Added subject and issuer to saved data.
When a certificate has changed, display not only the fingerprint but also subject and issuer of old certificate.
This commit is contained in:
parent
7786cf1376
commit
7fc1c65165
@ -36,6 +36,8 @@ struct rdp_certificate_data
|
||||
{
|
||||
char* hostname;
|
||||
UINT16 port;
|
||||
char* subject;
|
||||
char* issuer;
|
||||
char* fingerprint;
|
||||
};
|
||||
|
||||
@ -52,15 +54,29 @@ struct rdp_certificate_store
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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 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 BOOL certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data);
|
||||
FREERDP_API BOOL certificate_get_fingerprint(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data, char** fingerprint);
|
||||
FREERDP_API rdpCertificateData* certificate_data_new(
|
||||
char* hostname, UINT16 port, char*subject,
|
||||
char*issuer, char* fingerprint);
|
||||
FREERDP_API void certificate_data_free(
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API rdpCertificateStore* certificate_store_new(
|
||||
rdpSettings* settings);
|
||||
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 BOOL certificate_data_print(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API BOOL certificate_get_stored_data(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data,
|
||||
char** subject, char** issuer,
|
||||
char** fingerprint);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -67,7 +67,10 @@ typedef BOOL (*pPostConnect)(freerdp* instance);
|
||||
typedef void (*pPostDisconnect)(freerdp* instance);
|
||||
typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain);
|
||||
typedef BOOL (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint);
|
||||
typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject, char* issuer, char* new_fingerprint, char* old_fingerprint);
|
||||
typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject,
|
||||
char* issuer, char* new_fingerprint,
|
||||
char* old_subject, char* old_issuer,
|
||||
char* old_fingerprint);
|
||||
typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data, int length, const char* hostname, int port, DWORD flags);
|
||||
|
||||
typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type);
|
||||
@ -207,7 +210,7 @@ struct rdp_freerdp
|
||||
Callback for certificate validation.
|
||||
Used to verify that an unknown certificate is trusted. */
|
||||
ALIGN64 pVerifyChangedCertificate VerifyChangedCertificate; /**< (offset 52)
|
||||
Callback for changed certificate validation.
|
||||
Callback for changed certificate validation.
|
||||
Used when a certificate differs from stored fingerprint.
|
||||
If returns TRUE, the new fingerprint will be trusted and old thrown out. */
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/path.h>
|
||||
@ -43,8 +44,9 @@ static const char certificate_legacy_hosts_file[] = "known_hosts";
|
||||
|
||||
#define TAG FREERDP_TAG("crypto")
|
||||
|
||||
static BOOL certificate_split_line(char* line, char** host,
|
||||
UINT16* port, char** fingerprint);
|
||||
static BOOL certificate_split_line(char* line, char** host, UINT16* port,
|
||||
char**subject, char**issuer,
|
||||
char** fingerprint);
|
||||
|
||||
BOOL certificate_store_init(rdpCertificateStore* certificate_store)
|
||||
{
|
||||
@ -184,7 +186,8 @@ static int certificate_data_match_legacy(rdpCertificateStore* certificate_store,
|
||||
{
|
||||
rdpCertificateData* data = certificate_data_new(hostname,
|
||||
certificate_data->port,
|
||||
pline);
|
||||
NULL, NULL,
|
||||
pline);
|
||||
if (data)
|
||||
match = certificate_data_print(certificate_store, data) ? 0 : 1;
|
||||
certificate_data_free(data);
|
||||
@ -195,7 +198,9 @@ static int certificate_data_match_legacy(rdpCertificateStore* certificate_store,
|
||||
}
|
||||
|
||||
static int certificate_data_match_raw(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data, char** fprint)
|
||||
rdpCertificateData* certificate_data,
|
||||
char** psubject, char** pissuer,
|
||||
char** fprint)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
FILE* fp;
|
||||
@ -206,6 +211,8 @@ static int certificate_data_match_raw(rdpCertificateStore* certificate_store,
|
||||
int match = 1;
|
||||
long int size;
|
||||
char* hostname = NULL;
|
||||
char* subject = NULL;
|
||||
char* issuer = NULL;
|
||||
char* fingerprint = NULL;
|
||||
unsigned short port = 0;
|
||||
|
||||
@ -250,16 +257,24 @@ static int certificate_data_match_raw(rdpCertificateStore* certificate_store,
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (!certificate_split_line(pline, &hostname, &port, &fingerprint))
|
||||
WLog_WARN(TAG, "Invalid %s entry %s!", certificate_known_hosts_file, pline);
|
||||
if (!certificate_split_line(pline, &hostname, &port,
|
||||
&subject, &issuer, &fingerprint))
|
||||
WLog_WARN(TAG, "Invalid %s entry %s!",
|
||||
certificate_known_hosts_file, pline);
|
||||
else if (strcmp(pline, certificate_data->hostname) == 0)
|
||||
{
|
||||
int outLen;
|
||||
|
||||
if (port == certificate_data->port)
|
||||
{
|
||||
found = TRUE;
|
||||
match = strcmp(certificate_data->fingerprint, fingerprint);
|
||||
if (fingerprint && fprint)
|
||||
*fprint = _strdup(fingerprint);
|
||||
if (subject && psubject)
|
||||
crypto_base64_decode(subject, strlen(subject), psubject, &outLen);
|
||||
if (issuer && pissuer)
|
||||
crypto_base64_decode(issuer, strlen(issuer), pissuer, &outLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -275,22 +290,28 @@ static int certificate_data_match_raw(rdpCertificateStore* certificate_store,
|
||||
return match;
|
||||
}
|
||||
|
||||
BOOL certificate_get_fingerprint(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data, char** fingerprint)
|
||||
BOOL certificate_get_stored_data(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data,
|
||||
char** subject, char** issuer,
|
||||
char** fingerprint)
|
||||
{
|
||||
int rc = certificate_data_match_raw(certificate_store, certificate_data, fingerprint);
|
||||
int rc = certificate_data_match_raw(certificate_store, certificate_data,
|
||||
subject, issuer, fingerprint);
|
||||
|
||||
if ((rc == 0) || (rc == -1))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
|
||||
int certificate_data_match(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data)
|
||||
{
|
||||
return certificate_data_match_raw(certificate_store, certificate_data, NULL);
|
||||
return certificate_data_match_raw(certificate_store, certificate_data,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
|
||||
BOOL certificate_data_replace(rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data)
|
||||
{
|
||||
FILE* fp;
|
||||
BOOL rc = FALSE;
|
||||
@ -353,9 +374,12 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertifi
|
||||
if (length > 0)
|
||||
{
|
||||
UINT16 port = 0;
|
||||
char* hostname = NULL, *fingerprint;
|
||||
char* hostname = NULL;
|
||||
char* fingerprint = NULL;
|
||||
char* subject = NULL;
|
||||
char* issuer = NULL;
|
||||
|
||||
if (!certificate_split_line(pline, &hostname, &port, &fingerprint))
|
||||
if (!certificate_split_line(pline, &hostname, &port, &subject, &issuer, &fingerprint))
|
||||
WLog_WARN(TAG, "Skipping invalid %s entry %s!",
|
||||
certificate_known_hosts_file, pline);
|
||||
else
|
||||
@ -367,7 +391,7 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertifi
|
||||
fingerprint = certificate_data->fingerprint;
|
||||
rc = TRUE;
|
||||
}
|
||||
fprintf(fp, "%s %hu %s\n", hostname, port, fingerprint);
|
||||
fprintf(fp, "%s %hu %s %s %s\n", hostname, port, fingerprint, subject, issuer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +404,8 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertifi
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL certificate_split_line(char* line, char** host, UINT16* port, char** fingerprint)
|
||||
BOOL certificate_split_line(char* line, char** host, UINT16* port, char** subject,
|
||||
char** issuer, char** fingerprint)
|
||||
{
|
||||
char* cur;
|
||||
size_t length = strlen(line);
|
||||
@ -406,6 +431,18 @@ BOOL certificate_split_line(char* line, char** host, UINT16* port, char** finger
|
||||
|
||||
*fingerprint = cur;
|
||||
|
||||
cur = StrSep(&line, " \t");
|
||||
if (!cur)
|
||||
return FALSE;
|
||||
|
||||
*subject = cur;
|
||||
|
||||
cur = StrSep(&line, " \t");
|
||||
if (!cur)
|
||||
return FALSE;
|
||||
|
||||
*issuer = cur;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -419,15 +456,16 @@ BOOL certificate_data_print(rdpCertificateStore* certificate_store, rdpCertifica
|
||||
if (!fp)
|
||||
return FALSE;
|
||||
|
||||
fprintf(fp, "%s %hu %s\n", certificate_data->hostname, certificate_data->port,
|
||||
certificate_data->fingerprint);
|
||||
fprintf(fp, "%s %hu %s %s %s\n", certificate_data->hostname, certificate_data->port,
|
||||
certificate_data->fingerprint, certificate_data->subject,
|
||||
certificate_data->issuer);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rdpCertificateData* certificate_data_new(char* hostname, UINT16 port, char* fingerprint)
|
||||
rdpCertificateData* certificate_data_new(char* hostname, UINT16 port, char* subject, char* issuer, char* fingerprint)
|
||||
{
|
||||
rdpCertificateData* certdata;
|
||||
|
||||
@ -437,16 +475,21 @@ rdpCertificateData* certificate_data_new(char* hostname, UINT16 port, char* fing
|
||||
|
||||
certdata->port = port;
|
||||
certdata->hostname = _strdup(hostname);
|
||||
if (!certdata->hostname)
|
||||
goto out_free;
|
||||
certdata->subject = crypto_base64_encode(subject, strlen(subject));
|
||||
certdata->issuer = crypto_base64_encode(issuer, strlen(subject));
|
||||
certdata->fingerprint = _strdup(fingerprint);
|
||||
if (!certdata->fingerprint)
|
||||
goto out_free_hostname;
|
||||
|
||||
if (!certdata->hostname || !certdata->subject ||
|
||||
!certdata->issuer || !certdata->fingerprint)
|
||||
goto fail;
|
||||
|
||||
return certdata;
|
||||
|
||||
out_free_hostname:
|
||||
fail:
|
||||
free(certdata->hostname);
|
||||
out_free:
|
||||
free(certdata->subject);
|
||||
free(certdata->issuer);
|
||||
free(certdata->fingerprint);
|
||||
free(certdata);
|
||||
return NULL;
|
||||
}
|
||||
@ -456,6 +499,8 @@ void certificate_data_free(rdpCertificateData* certificate_data)
|
||||
if (certificate_data != NULL)
|
||||
{
|
||||
free(certificate_data->hostname);
|
||||
free(certificate_data->subject);
|
||||
free(certificate_data->issuer);
|
||||
free(certificate_data->fingerprint);
|
||||
free(certificate_data);
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, c
|
||||
BN_free(&mod);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
out_free_input_reverse:
|
||||
out_free_input_reverse:
|
||||
free(input_reverse);
|
||||
|
||||
return output_length;
|
||||
@ -376,7 +376,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)
|
||||
{
|
||||
unsigned long size = BIO_number_written(outBIO);
|
||||
@ -433,7 +433,7 @@ char* crypto_cert_subject_common_name(X509* xcert, int* length)
|
||||
}
|
||||
|
||||
FREERDP_API void crypto_cert_subject_alt_name_free(int count, int *lengths,
|
||||
char** alt_name)
|
||||
char** alt_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -557,6 +557,8 @@ end:
|
||||
|
||||
rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UINT16 port)
|
||||
{
|
||||
char* issuer;
|
||||
char* subject;
|
||||
char* fp;
|
||||
rdpCertificateData* certdata;
|
||||
|
||||
@ -564,7 +566,13 @@ rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UIN
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
certdata = certificate_data_new(hostname, port, fp);
|
||||
issuer = crypto_cert_issuer(xcert);
|
||||
subject = crypto_cert_subject(xcert);
|
||||
|
||||
certdata = certificate_data_new(hostname, port, issuer, subject, fp);
|
||||
|
||||
free(subject);
|
||||
free(issuer);
|
||||
free(fp);
|
||||
|
||||
return certdata;
|
||||
@ -590,8 +598,8 @@ void crypto_cert_print_info(X509* xcert)
|
||||
WLog_INFO(TAG, "\tIssuer: %s", issuer);
|
||||
WLog_INFO(TAG, "\tThumbprint: %s", fp);
|
||||
WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"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.");
|
||||
"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.");
|
||||
free(fp);
|
||||
out_free_issuer:
|
||||
free(issuer);
|
||||
|
@ -83,6 +83,8 @@ int TestKnownHosts(int argc, char* argv[])
|
||||
char* currentFileV2 = NULL;
|
||||
char* legacyFileV2 = NULL;
|
||||
char* legacyFile = NULL;
|
||||
char* subject = NULL;
|
||||
char* issuer = NULL;
|
||||
char* fp = NULL;
|
||||
|
||||
current.ConfigPath = GetKnownSubPath(KNOWN_PATH_TEMP, "TestKnownHostsCurrent");
|
||||
@ -152,13 +154,17 @@ int TestKnownHosts(int argc, char* argv[])
|
||||
}
|
||||
|
||||
/* Test if we can read out the old fingerprint. */
|
||||
if (!certificate_get_fingerprint(store, data, &fp))
|
||||
if (!certificate_get_stored_data(store, data, &subject, &issuer, &fp))
|
||||
{
|
||||
fprintf(stderr, "Could not read old fingerprint!\n");
|
||||
goto finish;
|
||||
}
|
||||
printf("Got '%s'\n", fp);
|
||||
printf("Got %s, %s '%s'\n", subject, issuer, fp);
|
||||
free(subject);
|
||||
free(issuer);
|
||||
free(fp);
|
||||
subject = NULL;
|
||||
issuer = NULL;
|
||||
fp = NULL;
|
||||
certificate_data_free(data);
|
||||
|
||||
@ -177,7 +183,7 @@ int TestKnownHosts(int argc, char* argv[])
|
||||
}
|
||||
|
||||
/* Test if we read out the old fingerprint fails. */
|
||||
if (certificate_get_fingerprint(store, data, &fp))
|
||||
if (certificate_get_stored_data(store, data, &subject, &issuer, &fp))
|
||||
{
|
||||
fprintf(stderr, "Read out not existing old fingerprint succeeded?!\n");
|
||||
goto finish;
|
||||
@ -308,6 +314,8 @@ finish:
|
||||
free (currentFileV2);
|
||||
free (legacyFileV2);
|
||||
free (legacyFile);
|
||||
free(subject);
|
||||
free(issuer);
|
||||
free(fp);
|
||||
|
||||
return rc;
|
||||
|
@ -761,7 +761,7 @@ int tls_connect(rdpTls* tls, BIO* underlying)
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static void tls_openssl_tlsext_debug_callback(SSL *s, int client_server,
|
||||
int type, unsigned char *data, int len, void *arg)
|
||||
int type, unsigned char *data, int len, void *arg)
|
||||
{
|
||||
/* see code comment in tls_accept() below */
|
||||
|
||||
@ -1172,14 +1172,17 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por
|
||||
}
|
||||
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_fingerprint(tls->certificate_store,
|
||||
certificate_data, &old_fingerprint))
|
||||
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:hu",
|
||||
hostname, port);
|
||||
|
||||
@ -1187,7 +1190,8 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por
|
||||
{
|
||||
accept_certificate = instance->VerifyChangedCertificate(
|
||||
instance, subject, issuer,
|
||||
fingerprint, old_fingerprint);
|
||||
fingerprint, old_subject, old_issuer,
|
||||
old_fingerprint);
|
||||
}
|
||||
|
||||
free(old_fingerprint);
|
||||
@ -1226,7 +1230,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por
|
||||
|
||||
if (alt_names)
|
||||
crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths,
|
||||
alt_names);
|
||||
alt_names);
|
||||
|
||||
return (verification_status == 0) ? 0 : 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user