diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index 28bc33134..c15a501af 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -735,6 +735,8 @@ boolean xf_authenticate(freerdp* instance, char** username, char** password, cha boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) { + char answer; + printf("Certificate details:\n"); printf("\tSubject: %s\n", subject); printf("\tIssuer: %s\n", issuer); @@ -743,7 +745,6 @@ boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, ch "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) "); @@ -757,6 +758,7 @@ boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, ch { break; } + printf("\n"); } return false; diff --git a/libfreerdp-core/certificate.c b/libfreerdp-core/certificate.c index 5eb877146..69fcf1da6 100644 --- a/libfreerdp-core/certificate.c +++ b/libfreerdp-core/certificate.c @@ -375,7 +375,8 @@ boolean certificate_read_server_proprietary_certificate(rdpCertificate* certific return false; } stream_read_uint16(s, wSignatureBlobLen); - if (wSignatureBlobLen != 72) { + if (wSignatureBlobLen != 72) + { printf("certificate_process_server_public_signature: invalid signature length (got %d, expected %d)\n", wSignatureBlobLen, 64); return false; } @@ -614,7 +615,9 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat return match; data = (char*) xmalloc(size + 2); - if (fread(data, size, 1, fp) != 1) { + + if (fread(data, size, 1, fp) != 1) + { xfree(data); return match; } diff --git a/libfreerdp-core/crypto.c b/libfreerdp-core/crypto.c index 1b1ada5fb..3fbe34ffb 100644 --- a/libfreerdp-core/crypto.c +++ b/libfreerdp-core/crypto.c @@ -355,7 +355,7 @@ 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) + if (X509_NAME_print_ex(outBIO, name, 0, XN_FLAG_ONELINE) > 0) { unsigned long size = BIO_number_written(outBIO); buffer = xzalloc(size + 1); @@ -373,6 +373,58 @@ char* crypto_cert_subject(X509* xcert) return crypto_print_name(X509_get_subject_name(xcert)); } +char* crypto_cert_subject_common_name(X509* xcert) +{ + int index; + int length; + uint8* common_name; + X509_NAME* subject_name; + X509_NAME_ENTRY* entry; + ASN1_STRING* entry_data; + + subject_name = X509_get_subject_name(xcert); + index = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1); + + entry = X509_NAME_get_entry(subject_name, index); + entry_data = X509_NAME_ENTRY_get_data(entry); + + length = ASN1_STRING_to_UTF8(&common_name, entry_data); + + return (char*) common_name; +} + +char** crypto_cert_subject_alt_name(X509* xcert, int* count) +{ + int index; + char** strings; + uint8* string; + int num_subject_alt_names; + GENERAL_NAMES* subject_alt_names; + GENERAL_NAME* subject_alt_name; + + *count = 0; + subject_alt_names = X509_get_ext_d2i(xcert, NID_subject_alt_name, 0, 0); + + if (!subject_alt_names) + return NULL; + + num_subject_alt_names = sk_GENERAL_NAME_num(subject_alt_names); + strings = malloc(sizeof(char*) * num_subject_alt_names); + + for (index = 0; index < num_subject_alt_names; ++index) + { + subject_alt_name = sk_GENERAL_NAME_value(subject_alt_names, index); + + if (subject_alt_name->type == GEN_DNS) + { + ASN1_STRING_to_UTF8(&string, subject_alt_name->d.dNSName); + strings[(*count)++] = (char*) string; + } + } + + return strings; +} + char* crypto_cert_issuer(X509* xcert) { return crypto_print_name(X509_get_issuer_name(xcert)); diff --git a/libfreerdp-core/crypto.h b/libfreerdp-core/crypto.h index 9253305ae..515399f0c 100644 --- a/libfreerdp-core/crypto.h +++ b/libfreerdp-core/crypto.h @@ -115,6 +115,8 @@ typedef struct crypto_cert_struct* CryptoCert; CryptoCert crypto_cert_read(uint8* data, uint32 length); char* crypto_cert_fingerprint(X509* xcert); char* crypto_cert_subject(X509* xcert); +char* crypto_cert_subject_common_name(X509* xcert); +char** crypto_cert_subject_alt_name(X509* xcert, int* count); char* crypto_cert_issuer(X509* xcert); void crypto_cert_print_info(X509* xcert); void crypto_cert_free(CryptoCert cert); diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index 22137b2de..882243733 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -230,7 +230,12 @@ CryptoCert tls_get_certificate(rdpTls* tls) int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) { int match; + int index; boolean status; + char* common_name; + char** alt_names; + int alt_names_count; + boolean hostname_match = false; status = x509_verify_certificate(cert, tls->certificate_store->path); @@ -245,8 +250,22 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) match = certificate_data_match(tls->certificate_store, certificate_data); - if (match == 0) + common_name = crypto_cert_subject_common_name(cert->px509); + alt_names = crypto_cert_subject_alt_name(cert->px509, &alt_names_count); + + if (strcmp(hostname, common_name) == 0) + hostname_match = true; + + for (index = 0; index < alt_names_count; index++) + { + if (strcmp(hostname, alt_names[index]) == 0) + hostname_match = true; + } + + if ((match == 0) && hostname_match) return 0; + else + tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count); issuer = crypto_cert_issuer(cert->px509); subject = crypto_cert_subject(cert->px509); @@ -299,6 +318,36 @@ void tls_print_certificate_error(char* hostname, char* fingerprint) printf("Host key verification failed.\n"); } +void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count) +{ + int index; + + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + printf("@ WARNING: CERTIFICATE NAME MISMATCH! @\n"); + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + printf("The hostname used for this connection (%s) \n", hostname); + + if (alt_names_count < 1) + { + printf("does not match the name given in the certificate:\n"); + printf("%s\n", common_name); + } + else + { + printf("does not match the names given in the certificate:\n"); + printf("%s", common_name); + + for (index = 0; index < alt_names_count; index++) + { + printf(", %s", alt_names[index]); + } + + printf("\n"); + } + + printf("A valid certificate for the wrong name should NOT be trusted!\n"); +} + rdpTls* tls_new(rdpSettings* settings) { rdpTls* tls; diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h index 06e565971..9657b3a27 100644 --- a/libfreerdp-core/tls.h +++ b/libfreerdp-core/tls.h @@ -49,7 +49,8 @@ int tls_write(rdpTls* tls, uint8* data, int length); CryptoCert tls_get_certificate(rdpTls* tls); int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname); -void tls_print_certificate_error(); +void tls_print_certificate_error(char* hostname, char* fingerprint); +void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count); boolean tls_print_error(char* func, SSL* connection, int value);