libfreerdp-core: added check for certificate name against hostname
This commit is contained in:
parent
c422c7477a
commit
4695faae38
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user