234
tls = (rdpTls*) xzalloc(sizeof(rdpTls));
238
SSL_load_error_strings();
245
int tls_verify_certificate(CryptoCert cert, rdpSettings* settings, char* hostname)
248
rdpCertStore* certstore;
249
status = x509_verify_cert(cert, settings);
230
boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
235
int common_name_length;
238
int* alt_names_lengths;
239
boolean certificate_status;
240
boolean hostname_match = false;
241
rdpCertificateData* certificate_data;
243
/* ignore certificate verification if user explicitly required it (discouraged) */
244
if (tls->settings->ignore_certificate)
245
return true; /* success! */
247
/* if user explicitly specified a certificate name, use it instead of the hostname */
248
if (tls->settings->certificate_name)
249
hostname = tls->settings->certificate_name;
251
/* attempt verification using OpenSSL and the ~/.freerdp/certs certificate store */
252
certificate_status = x509_verify_certificate(cert, tls->certificate_store->path);
254
/* verify certificate name match */
255
certificate_data = crypto_get_certificate_data(cert->px509, hostname);
257
/* extra common name and alternative names */
258
common_name = crypto_cert_subject_common_name(cert->px509, &common_name_length);
259
alt_names = crypto_cert_subject_alt_name(cert->px509, &alt_names_count, &alt_names_lengths);
261
/* compare against common name */
263
if (common_name != NULL)
265
if (strlen(hostname) == common_name_length)
267
if (memcmp((void*) hostname, (void*) common_name, common_name_length) == 0)
268
hostname_match = true;
272
/* compare against alternative names */
274
if (alt_names != NULL)
276
for (index = 0; index < alt_names_count; index++)
278
if (strlen(hostname) == alt_names_lengths[index])
280
if (memcmp((void*) hostname, (void*) alt_names[index], alt_names_lengths[index]) == 0)
281
hostname_match = true;
286
/* if the certificate is valid and the certificate name matches, verification succeeds */
287
if (certificate_status && hostname_match)
288
return true; /* success! */
290
/* if the certificate is valid but the certificate name does not match, warn user, do not accept */
291
if (certificate_status && !hostname_match)
292
tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count);
294
/* verification could not succeed with OpenSSL, use known_hosts file and prompt user for manual verification */
296
if (!certificate_status)
255
300
char* fingerprint;
256
rdpCertData* certdata;
258
certdata = crypto_get_cert_data(cert->px509, hostname);
259
certstore = certstore_new(certdata, settings->home_path);
261
if (cert_data_match(certstore) == 0)
301
boolean accept_certificate = false;
302
boolean verification_status = false;
264
304
issuer = crypto_cert_issuer(cert->px509);
265
305
subject = crypto_cert_subject(cert->px509);
266
306
fingerprint = crypto_cert_fingerprint(cert->px509);
268
if (certstore->match == 1)
270
boolean accept_certificate = settings->ignore_certificate;
272
if (!accept_certificate)
274
freerdp* instance = (freerdp*) settings->instance;
276
if (instance->VerifyCertificate)
277
accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint);
284
if (!accept_certificate)
287
cert_data_print(certstore);
289
else if (certstore->match == -1)
291
tls_print_cert_error(hostname, fingerprint);
292
certstore_free(certstore);
297
certstore_free(certstore);
308
/* search for matching entry in known_hosts file */
309
match = certificate_data_match(tls->certificate_store, certificate_data);
313
/* no entry was found in known_hosts file, prompt user for manual verification */
315
freerdp* instance = (freerdp*) tls->settings->instance;
318
tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count);
320
if (instance->VerifyCertificate)
321
accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint);
323
if (!accept_certificate)
325
/* user did not accept, abort and do not add entry in known_hosts file */
326
verification_status = false; /* failure! */
330
/* user accepted certificate, add entry in known_hosts file */
331
certificate_data_print(tls->certificate_store, certificate_data);
332
verification_status = true; /* success! */
335
else if (match == -1)
337
/* entry was found in known_hosts file, but fingerprint does not match */
338
tls_print_certificate_error(hostname, fingerprint);
339
verification_status = false; /* failure! */
343
verification_status = true; /* success! */
350
return verification_status;
303
void tls_print_cert_error(char* hostname, char* fingerprint)
356
void tls_print_certificate_error(char* hostname, char* fingerprint)
305
358
printf("The host key for %s has changed\n", hostname);
306
359
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
316
369
printf("Host key verification failed.\n");
372
void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count)
376
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
377
printf("@ WARNING: CERTIFICATE NAME MISMATCH! @\n");
378
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
379
printf("The hostname used for this connection (%s) \n", hostname);
381
if (alt_names_count < 1)
383
printf("does not match the name given in the certificate:\n");
384
printf("%s\n", common_name);
388
printf("does not match the names given in the certificate:\n");
389
printf("%s", common_name);
391
for (index = 0; index < alt_names_count; index++)
393
printf(", %s", alt_names[index]);
399
printf("A valid certificate for the wrong name should NOT be trusted!\n");
402
rdpTls* tls_new(rdpSettings* settings)
406
tls = (rdpTls*) xzalloc(sizeof(rdpTls));
410
SSL_load_error_strings();
413
tls->settings = settings;
414
tls->certificate_store = certificate_store_new(settings);
319
420
void tls_free(rdpTls* tls)
324
425
SSL_free(tls->ssl);
326
428
SSL_CTX_free(tls->ctx);
430
certificate_store_free(tls->certificate_store);