diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 5132d25a5..bb43fa64c 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -56,6 +56,8 @@ extern "C" FREERDP_API CryptoCert crypto_cert_read(BYTE* data, UINT32 length); FREERDP_API BYTE* crypto_cert_hash(X509* xcert, const char* hash, UINT32* length); FREERDP_API char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash); + FREERDP_API char* crypto_cert_fingerprint_by_hash_ex(X509* xcert, const char* hash, + BOOL separator); FREERDP_API char* crypto_cert_fingerprint(X509* xcert); FREERDP_API BYTE* crypto_cert_pem(X509* xcert, STACK_OF(X509) * chain, size_t* length); FREERDP_API X509* crypto_cert_from_pem(const char* data, size_t length, BOOL fromFile); diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index a78e38423..2dca1a74e 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -275,11 +275,16 @@ BYTE* crypto_cert_hash(X509* xcert, const char* hash, UINT32* length) } char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash) +{ + return crypto_cert_fingerprint_by_hash_ex(xcert, hash, 0); +} + +char* crypto_cert_fingerprint_by_hash_ex(X509* xcert, const char* hash, BOOL separator) { UINT32 fp_len, i; + size_t pos, size; BYTE* fp; - char* p; - char* fp_buffer; + char* fp_buffer = NULL; if (!xcert) { WLog_ERR(TAG, "Invalid certificate %p", xcert); @@ -294,23 +299,35 @@ char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash) if (!fp) return NULL; - fp_buffer = calloc(fp_len * 3 + 1, sizeof(char)); + size = fp_len * 3 + 1; + fp_buffer = calloc(size, sizeof(char)); if (!fp_buffer) goto fail; - p = fp_buffer; + pos = 0; for (i = 0; i < (fp_len - 1); i++) { - sprintf_s(p, (fp_len - i) * 3, "%02" PRIx8 ":", fp[i]); - p = &fp_buffer[(i + 1) * 3]; + int rc; + char* p = &fp_buffer[pos]; + if (separator) + rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]); + else + rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]); + if (rc <= 0) + goto fail; + pos += (size_t)rc; } - sprintf_s(p, (fp_len - i) * 3, "%02" PRIx8 "", fp[i]); -fail: + sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]); + free(fp); return fp_buffer; +fail: + free(fp); + free(fp_buffer); + return NULL; } static char* crypto_print_name(X509_NAME* name) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 1023ae712..4c350fd60 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -1176,6 +1176,33 @@ static BOOL is_accepted(rdpTls* tls, const BYTE* pem, size_t length) return FALSE; } +static BOOL compare_fingerprint(const char* fp, const char* hash, CryptoCert cert, BOOL separator) +{ + BOOL equal; + char* strhash; + + WINPR_ASSERT(fp); + WINPR_ASSERT(hash); + WINPR_ASSERT(cert); + + strhash = crypto_cert_fingerprint_by_hash_ex(cert->px509, hash, separator); + if (!strhash) + return FALSE; + + equal = (_stricmp(strhash, fp) == 0); + free(strhash); + return equal; +} + +static BOOL compare_fingerprint_all(const char* fp, const char* hash, CryptoCert cert) +{ + if (compare_fingerprint(fp, hash, cert, FALSE)) + return TRUE; + if (compare_fingerprint(fp, hash, cert, TRUE)) + return TRUE; + return FALSE; +} + static BOOL is_accepted_fingerprint(CryptoCert cert, const char* CertificateAcceptedFingerprints) { BOOL rc = FALSE; @@ -1187,30 +1214,22 @@ static BOOL is_accepted_fingerprint(CryptoCert cert, const char* CertificateAcce while (cur) { char* subcontext = NULL; - BOOL equal; - char* strhash; const char* h = strtok_s(cur, ":", &subcontext); const char* fp; if (!h) - continue; + goto next; fp = h + strlen(h) + 1; if (!fp) - continue; + goto next; - strhash = crypto_cert_fingerprint_by_hash(cert->px509, h); - if (!strhash) - continue; - - equal = (_stricmp(strhash, fp) == 0); - free(strhash); - if (equal) + if (compare_fingerprint_all(fp, h, cert)) { rc = TRUE; break; } - + next: cur = strtok_s(NULL, ",", &context); } free(copy);