static BOOL is_accepted(rdpTls* tls, const BYTE* pem, size_t length) { rdpSettings* settings = tls->settings; char* AccpetedKey; UINT32 AcceptedKeyLength; if (tls->isGatewayTransport) { AccpetedKey = settings->GatewayAcceptedCert; AcceptedKeyLength = settings->GatewayAcceptedCertLength; } else if (is_redirected(tls)) { AccpetedKey = settings->RedirectionAcceptedCert; AcceptedKeyLength = settings->RedirectionAcceptedCertLength; } else { AccpetedKey = settings->AcceptedCert; AcceptedKeyLength = settings->AcceptedCertLength; } if (AcceptedKeyLength > 0) { if (AcceptedKeyLength == length) { if (memcmp(AccpetedKey, pem, AcceptedKeyLength) == 0) return TRUE; } } if (tls->isGatewayTransport) { free(settings->GatewayAcceptedCert); settings->GatewayAcceptedCert = NULL; settings->GatewayAcceptedCertLength = 0; } else if (is_redirected(tls)) { free(settings->RedirectionAcceptedCert); settings->RedirectionAcceptedCert = NULL; settings->RedirectionAcceptedCertLength = 0; } else { free(settings->AcceptedCert); settings->AcceptedCert = NULL; settings->AcceptedCertLength = 0; } return FALSE; }
static BOOL accept_cert(rdpTls* tls, BYTE* pem, UINT32 length) { rdpSettings* settings = tls->settings; if (tls->isGatewayTransport) { settings->GatewayAcceptedCert = (char*)pem; settings->GatewayAcceptedCertLength = length; } else if (is_redirected(tls)) { settings->RedirectionAcceptedCert = (char*)pem; settings->RedirectionAcceptedCertLength = length; } else { settings->AcceptedCert = (char*)pem; settings->AcceptedCertLength = length; } return TRUE; }
int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port) { int match; int index; char* common_name = NULL; int common_name_length = 0; char** dns_names = 0; int dns_names_count = 0; int* dns_names_lengths = NULL; BOOL certificate_status; BOOL hostname_match = FALSE; BOOL verification_status = FALSE; rdpCertificateData* certificate_data; freerdp* instance = (freerdp*) tls->settings->instance; DWORD length; BYTE* pemCert; if (!tls_extract_pem(cert, &pemCert, &length)) return -1; /* Check, if we already accepted this key. */ if (is_accepted(tls, pemCert, length)) { free(pemCert); return 1; } if (tls->settings->ExternalCertificateManagement) { int status = -1; if (instance->VerifyX509Certificate) status = instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, tls->isGatewayTransport | is_redirected(tls) ? 2 : 0); else WLog_ERR(TAG, "No VerifyX509Certificate callback registered!"); if (status > 0) { accept_cert(tls, pemCert, length); } else if (status < 0) { WLog_ERR(TAG, "VerifyX509Certificate failed: (length = %d) status: [%d] %s", length, status, pemCert); free(pemCert); return -1; } else free(pemCert); return (status == 0) ? 0 : 1; } /* ignore certificate verification if user explicitly required it (discouraged) */ if (tls->settings->IgnoreCertificate) { free(pemCert); return 1; /* success! */ } if (!tls->isGatewayTransport && tls->settings->AuthenticationLevel == 0) { free(pemCert); return 1; /* success! */ } /* if user explicitly specified a certificate name, use it instead of the hostname */ if (!tls->isGatewayTransport && tls->settings->CertificateName) hostname = tls->settings->CertificateName; /* attempt verification using OpenSSL and the ~/.freerdp/certs certificate store */ certificate_status = x509_verify_certificate(cert, tls->certificate_store->path); /* verify certificate name match */ certificate_data = crypto_get_certificate_data(cert->px509, hostname, port); /* extra common name and alternative names */ common_name = crypto_cert_subject_common_name(cert->px509, &common_name_length); dns_names = crypto_cert_get_dns_names(cert->px509, &dns_names_count, &dns_names_lengths); /* compare against common name */ if (common_name) { if (tls_match_hostname(common_name, common_name_length, hostname)) hostname_match = TRUE; } /* compare against alternative names */ if (dns_names) { for (index = 0; index < dns_names_count; index++) { if (tls_match_hostname(dns_names[index], dns_names_lengths[index], hostname)) { hostname_match = TRUE; break; } } } /* if the certificate is valid and the certificate name matches, verification succeeds */ if (certificate_status && hostname_match) verification_status = TRUE; /* success! */ /* verification could not succeed with OpenSSL, use known_hosts file and prompt user for manual verification */ if (!certificate_status || !hostname_match) { char* issuer; char* subject; char* fingerprint; DWORD accept_certificate = 0; issuer = crypto_cert_issuer(cert->px509); subject = crypto_cert_subject(cert->px509); fingerprint = crypto_cert_fingerprint(cert->px509); /* search for matching entry in known_hosts file */ match = certificate_data_match(tls->certificate_store, certificate_data); if (match == 1) { /* no entry was found in known_hosts file, prompt user for manual verification */ if (!hostname_match) tls_print_certificate_name_mismatch_error( hostname, port, common_name, dns_names, dns_names_count); /* Automatically accept certificate on first use */ if (tls->settings->AutoAcceptCertificate) { WLog_INFO(TAG, "No certificate stored, automatically accepting."); accept_certificate = 1; } else if (instance->VerifyCertificate) { accept_certificate = instance->VerifyCertificate( instance, common_name, subject, issuer, fingerprint, !hostname_match); } switch (accept_certificate) { case 1: /* user accepted certificate, add entry in known_hosts file */ verification_status = certificate_data_print(tls->certificate_store, certificate_data); break; case 2: /* user did accept temporaty, do not add to known hosts file */ verification_status = TRUE; break; default: /* user did not accept, abort and do not add entry in known_hosts file */ verification_status = FALSE; /* failure! */ break; } } else if (match == -1) { char* old_subject = NULL; char* old_issuer = NULL; char* old_fingerprint = NULL; /* entry was found in known_hosts file, but fingerprint does not match. ask user to use it */ tls_print_certificate_error(hostname, port, fingerprint, tls->certificate_store->file); if (!certificate_get_stored_data(tls->certificate_store, certificate_data, &old_subject, &old_issuer, &old_fingerprint)) WLog_WARN(TAG, "Failed to get certificate entry for %s:%d", hostname, port); if (instance->VerifyChangedCertificate) { accept_certificate = instance->VerifyChangedCertificate( instance, common_name, subject, issuer, fingerprint, old_subject, old_issuer, old_fingerprint); } free(old_subject); free(old_issuer); free(old_fingerprint); switch (accept_certificate) { case 1: /* user accepted certificate, add entry in known_hosts file */ verification_status = certificate_data_replace(tls->certificate_store, certificate_data); break; case 2: /* user did accept temporaty, do not add to known hosts file */ verification_status = TRUE; break; default: /* user did not accept, abort and do not add entry in known_hosts file */ verification_status = FALSE; /* failure! */ break; } } else if (match == 0) verification_status = TRUE; /* success! */ free(issuer); free(subject); free(fingerprint); } certificate_data_free(certificate_data); free(common_name); if (dns_names) crypto_cert_dns_names_free(dns_names_count, dns_names_lengths, dns_names); if (verification_status > 0) { accept_cert(tls, pemCert, length); } else { free(pemCert); } return (verification_status == 0) ? 0 : 1; }
int main(int argc, char *argv[]) { int i; DWORD dwBase = 0xFFFFFFFFL; /* First address to dump */ DWORD dwLength = 0xFFFFFFFFL; /* Number of bytes to dump */ BYTE table[16]; /* 16 bytes table */ DWORD ul; WORD u; char *pszName = NULL; /* File name */ FILE *f; #ifndef __unix__ /* Force stdin and stdout to untranslated */ _setmode( _fileno( stdin ), _O_BINARY ); #endif for (i=1; i<argc; i++) { if (IsSwitch(argv[i])) { if ( streq(argv[i]+1, "?") || streq(argv[i]+1, "h") || streq(argv[i]+1, "-help")) { usage(); } if (streq(argv[i]+1, "p")) { paginate = GetScreenRows() - 1; /* Pause once per screen */ continue; } if (streq(argv[i]+1, "V")) { /* -V: Display the version */ printf("%s\n", PROGRAM_VERSION " " PROGRAM_DATE " " OS_NAME); exit(0); } printf("Unrecognized switch %s. Ignored.\n", argv[i]); continue; } if (!pszName) { pszName = argv[i]; continue; } if (dwBase == 0xFFFFFFFFL) { if (sscanf(argv[i], "%lX", &ul)) dwBase = ul; continue; } if (dwLength == 0xFFFFFFFFL) { if (sscanf(argv[i], "%lX", &ul)) dwLength = ul; continue; } printf("Unexpected argument: %s\nIgnored.\n", argv[i]); break; /* Ignore other arguments */ } if (pszName) { f = fopen(pszName, "rb"); if (!f) { printf("Cannot open file %s.\n", pszName); exit(1); } } else { if (!is_redirected(stdin)) usage(); f = stdin; paginate = FALSE; /* Avoid waiting forever */ } printf("\n\ Offset 00 04 08 0C 0 4 8 C \n\ -------- ----------- ----------- ----------- ----------- -------- --------\n\ "); if (dwBase == 0xFFFFFFFFL) dwBase = 0; fseek(f, dwBase & 0xFFFFFFF0L, SEEK_SET); for (ul = dwBase & 0xFFFFFFF0L; between(dwBase & 0xFFFFFFF0L, ul, dwBase+dwLength); ul += 16) { size_t nRead; nRead = fread(table, 1, 16, f); if (!nRead) break; printf("%08lX ", ul); /* Display the hex dump */ for (u=0; u<nRead; u++) { if (!(u&3)) printf(" "); if (between(dwBase, ul+u, dwBase+dwLength)) printf("%02X ", (WORD)table[u]); else printf(" "); } for ( ; u<16; u++) { if (!(u&3)) printf(" "); printf(" "); } /* Display the character dump */ for (u=0; u<nRead; u++) { if (!(u&7)) printf(" "); #ifdef __unix__ if ( (table[u] & 0x7F) < 0x20) table[u] = ' '; #else switch (table[u]) { case '\x07': table[u] = ' '; break; case '\x08': table[u] = ' '; break; /* Backspace */ case '\x09': table[u] = ' '; break; /* Tab */ case '\x0A': table[u] = ' '; break; /* Line feed */ case '\x0D': table[u] = ' '; break; /* Carrier return */ case '\x1A': table[u] = ' '; break; default: break; } #endif if (between(dwBase, ul+u, dwBase+dwLength) && (table[u]>' ')) printf("%c", table[u]); else printf(" "); } for ( ; u<16; u++) { if (!(u&7)) printf(" "); printf(" "); } printflf(); } printflf(); return 0; }