diff --git a/client/DirectFB/dfreerdp.c b/client/DirectFB/dfreerdp.c index 5690f009d..214ad4e05 100644 --- a/client/DirectFB/dfreerdp.c +++ b/client/DirectFB/dfreerdp.c @@ -218,6 +218,35 @@ static int df_process_plugin_args(rdpSettings* settings, const char* name, return 1; } +boolean df_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +{ + printf("Certificate details:\n"); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired." + "Please look at the documentation on how to create local certificate store for a private CA.\n"); + + char answer; + while (1) + { + printf("Do you trust the above certificate? (Y/N) "); + answer = fgetc(stdin); + + if (answer == 'y' || answer == 'Y') + { + return True; + } + else if (answer == 'n' || answer == 'N') + { + break; + } + } + + return False; +} + static int df_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size) { @@ -408,6 +437,7 @@ int main(int argc, char* argv[]) instance = freerdp_new(); instance->PreConnect = df_pre_connect; instance->PostConnect = df_post_connect; + instance->VerifyCertificate = df_verify_certificate; instance->ReceiveChannelData = df_receive_channel_data; instance->ContextSize = (pcContextSize) df_context_size; diff --git a/client/Windows/wfreerdp.c b/client/Windows/wfreerdp.c index 31ad0b80c..813693cd0 100644 --- a/client/Windows/wfreerdp.c +++ b/client/Windows/wfreerdp.c @@ -392,6 +392,12 @@ boolean wf_post_connect(freerdp* instance) return True; } +boolean wf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +{ + return True; +} + + int wf_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size) { return freerdp_channels_data(instance, channelId, data, size, flags, total_size); @@ -636,6 +642,7 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine instance = freerdp_new(); instance->PreConnect = wf_pre_connect; instance->PostConnect = wf_post_connect; + instance->VerifyCertificate = wf_verify_certificate; instance->ReceiveChannelData = wf_receive_channel_data; instance->ContextSize = (pcContextSize) wf_context_size; diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index f7f713a79..11e13dee1 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -771,6 +771,36 @@ boolean xf_authenticate(freerdp* instance, char** username, char** password, cha return True; } +boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +{ + printf("Certificate details:\n"); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired." + "Please look at the documentation on how to create local certificate store for a private CA.\n"); + + char answer; + while (1) + { + printf("Do you trust the above certificate? (Y/N) "); + answer = fgetc(stdin); + + if (answer == 'y' || answer == 'Y') + { + return True; + } + else if (answer == 'n' || answer == 'N') + { + break; + } + } + + return False; +} + + int xf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data) { int argc = 0; @@ -1049,6 +1079,7 @@ int main(int argc, char* argv[]) instance->PreConnect = xf_pre_connect; instance->PostConnect = xf_post_connect; instance->Authenticate = xf_authenticate; + instance->VerifyCertificate = xf_verify_certificate; instance->ReceiveChannelData = xf_receive_channel_data; instance->ContextSize = (pcContextSize) xf_context_size; diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 69baabd83..7f370257d 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -49,6 +49,7 @@ typedef void (*pcContextFree)(freerdp* instance, rdpContext* context); typedef boolean (*pcPreConnect)(freerdp* instance); typedef boolean (*pcPostConnect)(freerdp* instance); typedef boolean (*pcAuthenticate)(freerdp* instance, char** username, char** password, char** domain); +typedef boolean (*pcVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint); typedef int (*pcSendChannelData)(freerdp* instance, int channelId, uint8* data, int size); typedef int (*pcReceiveChannelData)(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size); @@ -85,6 +86,7 @@ struct rdp_freerdp pcPreConnect PreConnect; pcPostConnect PostConnect; pcAuthenticate Authenticate; + pcVerifyCertificate VerifyCertificate; pcSendChannelData SendChannelData; pcReceiveChannelData ReceiveChannelData; diff --git a/libfreerdp-core/crypto.c b/libfreerdp-core/crypto.c index 55ad46927..de7394c1d 100644 --- a/libfreerdp-core/crypto.c +++ b/libfreerdp-core/crypto.c @@ -279,6 +279,34 @@ char* crypto_cert_fingerprint(X509* xcert) return fp_buffer; } +char* crypto_print_name(X509_NAME* name) +{ + char* buffer = NULL; + BIO* outBIO = BIO_new(BIO_s_mem()); + + if(X509_NAME_print_ex(outBIO, name, 0, XN_FLAG_ONELINE) > 0) + { + unsigned long size = BIO_number_written(outBIO); + char* buffer = xzalloc(size); + memset(buffer, 0, size); + BIO_read(outBIO, buffer, size); + } + + BIO_free(outBIO); + return buffer; +} + + +char* crypto_cert_subject(X509* xcert) +{ + return crypto_print_name(X509_get_subject_name(xcert)); +} + +char* crypto_cert_issuer(X509* xcert) +{ + return crypto_print_name(X509_get_issuer_name(xcert)); +} + boolean x509_verify_cert(CryptoCert cert, rdpSettings* settings) { char* cert_loc; @@ -351,8 +379,8 @@ void crypto_cert_print_info(X509* xcert) char* issuer; char* subject; - subject = X509_NAME_oneline(X509_get_subject_name(xcert), NULL, 0); - issuer = X509_NAME_oneline(X509_get_issuer_name(xcert), NULL, 0); + subject = crypto_cert_subject(xcert); + issuer = crypto_cert_issuer(xcert); fp = crypto_cert_fingerprint(xcert); printf("Certificate details:\n"); @@ -363,5 +391,8 @@ void crypto_cert_print_info(X509* xcert) "the CA certificate in your certificate store, or the certificate has expired." "Please look at the documentation on how to create local certificate store for a private CA.\n"); + xfree(subject); + xfree(issuer); xfree(fp); } + diff --git a/libfreerdp-core/crypto.h b/libfreerdp-core/crypto.h index ce309ab92..42e6da50a 100644 --- a/libfreerdp-core/crypto.h +++ b/libfreerdp-core/crypto.h @@ -109,7 +109,9 @@ void crypto_hmac_free(CryptoHmac hmac); typedef struct crypto_cert_struct* CryptoCert; CryptoCert crypto_cert_read(uint8* data, uint32 length); -char* cypto_cert_fingerprint(X509* xcert); +char* crypto_cert_fingerprint(X509* xcert); +char* crypto_cert_subject(X509* xcert); +char* crypto_cert_issuer(X509* xcert); void crypto_cert_print_info(X509* xcert); void crypto_cert_free(CryptoCert cert); boolean x509_verify_cert(CryptoCert cert, rdpSettings* settings); diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index 940131d55..502a89b05 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -259,27 +259,22 @@ int tls_verify_certificate(CryptoCert cert, rdpSettings* settings, char* hostnam if (certstore->match == 1) { - char answer; - crypto_cert_print_info(cert->px509); + char* issuer = crypto_cert_issuer(cert->px509); + char* subject = crypto_cert_subject(cert->px509); + char* fingerprint = crypto_cert_fingerprint(cert->px509); -#ifndef _WIN32 - while (1) - { - printf("Do you trust the above certificate? (Y/N) "); - answer = fgetc(stdin); + boolean accept_certificate = False; + freerdp* instance = (freerdp*)settings->instance; - if (answer == 'y' || answer == 'Y') - { - cert_data_print(certstore); - break; - } - else if (answer == 'n' || answer == 'N') - { - certstore_free(certstore); - return 1; - } - } -#endif + if(instance->VerifyCertificate) + accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint); + + xfree(issuer); + xfree(subject); + xfree(fingerprint); + + if(!accept_certificate) + return 1; } else if (certstore->match == -1) {