From 6da4a5aaf0bbf45ea3caa8e8f2e9f64df6cc9f30 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 9 Jun 2015 15:33:13 +0200 Subject: [PATCH] Using ' ' format for known hosts. --- include/freerdp/crypto/certificate.h | 7 +- include/freerdp/crypto/crypto.h | 2 +- libfreerdp/crypto/certificate.c | 151 ++++++++++++++++++--------- libfreerdp/crypto/crypto.c | 4 +- libfreerdp/crypto/tls.c | 10 +- 5 files changed, 114 insertions(+), 60 deletions(-) diff --git a/include/freerdp/crypto/certificate.h b/include/freerdp/crypto/certificate.h index 537829615..83fc3a753 100644 --- a/include/freerdp/crypto/certificate.h +++ b/include/freerdp/crypto/certificate.h @@ -35,6 +35,7 @@ typedef struct rdp_certificate_store rdpCertificateStore; struct rdp_certificate_data { char* hostname; + UINT16 port; char* fingerprint; }; @@ -51,13 +52,13 @@ struct rdp_certificate_store extern "C" { #endif -FREERDP_API rdpCertificateData* certificate_data_new(char* hostname, char* fingerprint); +FREERDP_API rdpCertificateData* certificate_data_new(char* hostname, UINT16 port, char* fingerprint); FREERDP_API void certificate_data_free(rdpCertificateData* certificate_data); FREERDP_API rdpCertificateStore* certificate_store_new(rdpSettings* settings); -FREERDP_API void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data); +FREERDP_API BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data); FREERDP_API void certificate_store_free(rdpCertificateStore* certificate_store); FREERDP_API int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data); -FREERDP_API void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data); +FREERDP_API BOOL certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data); #ifdef __cplusplus } diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 44c8eef38..25d98bde3 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -133,7 +133,7 @@ FREERDP_API void crypto_cert_print_info(X509* xcert); FREERDP_API void crypto_cert_free(CryptoCert cert); FREERDP_API BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path); -FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname); +FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UINT16 port); FREERDP_API BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* PublicKeyLength); #define TSSK_KEY_LENGTH 64 diff --git a/libfreerdp/crypto/certificate.c b/libfreerdp/crypto/certificate.c index fbe804d00..0e7d0dc74 100644 --- a/libfreerdp/crypto/certificate.c +++ b/libfreerdp/crypto/certificate.c @@ -35,13 +35,16 @@ static const char certificate_store_dir[] = "certs"; static const char certificate_server_dir[] = "server"; -static const char certificate_known_hosts_file[] = "known_hosts"; +static const char certificate_known_hosts_file[] = "known_hosts.v2"; #include #include #define TAG FREERDP_TAG("crypto") +static BOOL certificate_split_line(char* line, char** host, + UINT16* port, char** fingerprint); + BOOL certificate_store_init(rdpCertificateStore* certificate_store) { char* server_path = NULL; @@ -53,10 +56,10 @@ BOOL certificate_store_init(rdpCertificateStore* certificate_store) { if (!CreateDirectoryA(settings->ConfigPath, 0)) { - WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath); + WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath); goto fail; } - WLog_INFO(TAG, "creating directory %s", settings->ConfigPath); + WLog_INFO(TAG, "creating directory %s", settings->ConfigPath); } if (!(certificate_store->path = GetCombinedPath(settings->ConfigPath, (char*) certificate_store_dir))) @@ -66,10 +69,10 @@ BOOL certificate_store_init(rdpCertificateStore* certificate_store) { if (!CreateDirectoryA(certificate_store->path, 0)) { - WLog_ERR(TAG, "error creating directory [%s]", certificate_store->path); + WLog_ERR(TAG, "error creating directory [%s]", certificate_store->path); goto fail; } - WLog_INFO(TAG, "creating directory [%s]", certificate_store->path); + WLog_INFO(TAG, "creating directory [%s]", certificate_store->path); } if (!(server_path = GetCombinedPath(settings->ConfigPath, (char*) certificate_server_dir))) @@ -79,10 +82,10 @@ BOOL certificate_store_init(rdpCertificateStore* certificate_store) { if (!CreateDirectoryA(server_path, 0)) { - WLog_ERR(TAG, "error creating directory [%s]", server_path); + WLog_ERR(TAG, "error creating directory [%s]", server_path); goto fail; } - WLog_INFO(TAG, "created directory [%s]", server_path); + WLog_INFO(TAG, "created directory [%s]", server_path); } if (!(certificate_store->file = GetCombinedPath(settings->ConfigPath, (char*) certificate_known_hosts_file))) @@ -95,7 +98,7 @@ BOOL certificate_store_init(rdpCertificateStore* certificate_store) if (!certificate_store->fp) { - WLog_ERR(TAG, "error opening [%s]", certificate_store->file); + WLog_ERR(TAG, "error opening [%s]", certificate_store->file); goto fail; } @@ -104,7 +107,7 @@ BOOL certificate_store_init(rdpCertificateStore* certificate_store) return TRUE; fail: - WLog_ERR(TAG, "certificate store initialization failed"); + WLog_ERR(TAG, "certificate store initialization failed"); free(server_path); free(certificate_store->path); free(certificate_store->file); @@ -118,9 +121,13 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat FILE* fp; int length; char* data; + char* mdata; char* pline; int match = 1; long int size; + char* hostname = NULL; + char* fingerprint = NULL; + unsigned short port = 0; fp = certificate_store->fp; @@ -134,8 +141,11 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat if (size < 1) return match; - data = (char*) malloc(size + 2); + mdata = (char*) malloc(size + 2); + if (!mdata) + return match; + data = mdata; if (fread(data, size, 1, fp) != 1) { free(data); @@ -144,7 +154,7 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat data[size] = '\n'; data[size + 1] = '\0'; - pline = strtok(data, "\n"); + pline = StrSep(&data, "\r\n"); while (pline != NULL) { @@ -152,62 +162,69 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat if (length > 0) { - length = strcspn(pline, " \t"); - pline[length] = '\0'; - - if (strcmp(pline, certificate_data->hostname) == 0) + if (!certificate_split_line(pline, &hostname, &port, &fingerprint)) + WLog_WARN(TAG, "Invalid %s entry %s!", certificate_known_hosts_file, pline); + else if (strcmp(pline, certificate_data->hostname) == 0) { - pline = &pline[length + 1]; - - if (strcmp(pline, certificate_data->fingerprint) == 0) - match = 0; - else - match = -1; - break; + if (port == certificate_data->port) + { + match = strcmp(fingerprint, certificate_data->fingerprint); + break; + } } } - pline = strtok(NULL, "\n"); + pline = StrSep(&data, "\r\n"); } - free(data); + free(mdata); return match; } -void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) +BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) { FILE* fp; int length; char* data; + char* sdata; char* pline; long int size; fp = certificate_store->fp; if (!fp) - return; - + return FALSE; + /* Read the current contents of the file. */ fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); if (size < 1) - return; + return FALSE; data = (char*) malloc(size + 2); + if (!data) + return FALSE; if (fread(data, size, 1, fp) != 1) { free(data); - return; + return FALSE; } - + /* Write the file back out, with appropriate fingerprint substitutions */ fp = fopen(certificate_store->file, "w+"); + if (!fp) + { + free(data); + return FALSE; + } + data[size] = '\n'; data[size + 1] = '\0'; - pline = strtok(data, "\n"); // xxx: use strsep + sdata = data; + pline = StrSep(&sdata, "\r\n"); while (pline != NULL) { @@ -215,28 +232,61 @@ void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertifi if (length > 0) { - char* hostname = pline, *fingerprint; - - length = strcspn(pline, " \t"); - hostname[length] = '\0'; + UINT16 port = 0; + char* hostname = NULL, *fingerprint; - /* If this is the replaced hostname, use the updated fingerprint. */ - if (strcmp(hostname, certificate_data->hostname) == 0) - fingerprint = certificate_data->fingerprint; + if (!certificate_split_line(pline, &hostname, &port, &fingerprint)) + WLog_WARN(TAG, "Skipping invalid %s entry %s!", certificate_known_hosts_file, pline); else - fingerprint = &hostname[length + 1]; - - fprintf(fp, "%s %s\n", hostname, fingerprint); + { + /* If this is the replaced hostname, use the updated fingerprint. */ + if ((strcmp(hostname, certificate_data->hostname) == 0) && (port == certificate_data->port)) + fingerprint = certificate_data->fingerprint; + else + fingerprint = &hostname[length + 1]; + fprintf(fp, "%s %hu %s\n", hostname, port, fingerprint); + } } - pline = strtok(NULL, "\n"); + pline = StrSep(&sdata, "\r\n"); } - + fclose(fp); - free(data); + free(data); + + return TRUE; } -void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) +BOOL certificate_split_line(char* line, char** host, UINT16* port, char** fingerprint) +{ + char* cur; + size_t length = strlen(line); + + if (length <= 0) + return FALSE; + + cur = StrSep(&line, " \t"); + if (!cur) + return FALSE; + *host = cur; + + cur = StrSep(&line, " \t"); + if (!cur) + return FALSE; + + if(sscanf(cur, "%hu", port) != 1) + return FALSE; + + cur = StrSep(&line, " \t"); + if (!cur) + return FALSE; + + *fingerprint = cur; + + return TRUE; +} + +BOOL certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) { FILE* fp; @@ -244,13 +294,17 @@ void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertifica fp = fopen(certificate_store->file, "a"); if (!fp) - return; + return FALSE; + + fprintf(fp, "%s %hu %s\n", certificate_data->hostname, certificate_data->port, + certificate_data->fingerprint); - fprintf(fp, "%s %s\n", certificate_data->hostname, certificate_data->fingerprint); fclose(fp); + + return TRUE; } -rdpCertificateData* certificate_data_new(char* hostname, char* fingerprint) +rdpCertificateData* certificate_data_new(char* hostname, UINT16 port, char* fingerprint) { rdpCertificateData* certdata; @@ -258,6 +312,7 @@ rdpCertificateData* certificate_data_new(char* hostname, char* fingerprint) if (!certdata) return NULL; + certdata->port = port; certdata->hostname = _strdup(hostname); if (!certdata->hostname) goto out_free; diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 3c54c2c3b..031e9734e 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -555,7 +555,7 @@ end: return status; } -rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname) +rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UINT16 port) { char* fp; rdpCertificateData* certdata; @@ -564,7 +564,7 @@ rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname) if (!fp) return NULL; - certdata = certificate_data_new(hostname, fp); + certdata = certificate_data_new(hostname, port, fp); free(fp); return certdata; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index c5025cadc..af2c796d8 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -1082,7 +1082,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por certificate_status = x509_verify_certificate(cert, tls->certificate_store->path); /* verify certificate name match */ - certificate_data = crypto_get_certificate_data(cert->px509, hostname); + 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); @@ -1162,15 +1162,14 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por else { /* user accepted certificate, add entry in known_hosts file */ - certificate_data_print(tls->certificate_store, certificate_data); - verification_status = TRUE; /* success! */ + verification_status = certificate_data_print(tls->certificate_store, certificate_data); } } else if (match == -1) { /* entry was found in known_hosts file, but fingerprint does not match. ask user to use it */ tls_print_certificate_error(hostname, fingerprint, tls->certificate_store->file); - + if (instance->VerifyChangedCertificate) { accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, ""); @@ -1184,8 +1183,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por else { /* user accepted new certificate, add replace fingerprint for this host in known_hosts file */ - certificate_data_replace(tls->certificate_store, certificate_data); - verification_status = TRUE; /* success! */ + verification_status = certificate_data_replace(tls->certificate_store, certificate_data); } } else if (match == 0)