@@ -438,6 +438,82 @@ _set_error_from_osstatus (OSStatus status,
438
438
CFRelease (err );
439
439
}
440
440
441
+ /* Always returns a string that must be freed. */
442
+ static char *
443
+ explain_trust_result (SecTrustRef trust , SecTrustResultType trust_result )
444
+ {
445
+ bson_string_t * reason ;
446
+ CFArrayRef cfprops = NULL ;
447
+ CFIndex count , i ;
448
+
449
+ reason = bson_string_new ("" );
450
+ switch (trust_result ) {
451
+ case kSecTrustResultDeny :
452
+ bson_string_append (reason , "Certificate trust denied" );
453
+ break ;
454
+ case kSecTrustResultRecoverableTrustFailure :
455
+ bson_string_append (reason , "Certificate trust failure" );
456
+ break ;
457
+ case kSecTrustResultFatalTrustFailure :
458
+ bson_string_append (reason , "Certificate trust fatal failure" );
459
+ break ;
460
+ case kSecTrustResultInvalid :
461
+ bson_string_append (reason , "Certificate trust evaluation failure" );
462
+ break ;
463
+ default :
464
+ bson_string_append_printf (
465
+ reason , "Certificate trust failure #%d" , (int ) trust_result );
466
+ break ;
467
+ }
468
+ bson_string_append (reason , ": " );
469
+
470
+ cfprops = SecTrustCopyProperties (trust );
471
+ /* This contains an array of dictionaries, each representing a cert in the
472
+ * chain. Append the first failure reason found. */
473
+ if (!cfprops ) {
474
+ bson_string_append (reason , "Unable to retreive cause for trust failure" );
475
+ goto done ;
476
+ }
477
+
478
+ count = CFArrayGetCount (cfprops );
479
+ for (i = 0 ; i < count ; ++ i ) {
480
+ const void * elem = NULL ;
481
+ const void * reason_elem = NULL ;
482
+ char * reason_str ;
483
+ CFDictionaryRef dict ;
484
+
485
+ elem = CFArrayGetValueAtIndex (cfprops , i );
486
+ if (CFGetTypeID (elem ) != CFDictionaryGetTypeID ()) {
487
+ bson_string_append (reason , "Unable to parse cause for trust failure" );
488
+ goto done ;
489
+ }
490
+
491
+ dict = (CFDictionaryRef ) elem ;
492
+ reason_elem = CFDictionaryGetValue (dict , kSecPropertyTypeError );
493
+ if (!reason_elem ) {
494
+ continue ;
495
+ }
496
+ if (CFGetTypeID (reason_elem ) != CFStringGetTypeID ()) {
497
+ bson_string_append (reason , "Unable to parse trust failure error" );
498
+ goto done ;
499
+ }
500
+ reason_str = _mongoc_cfstringref_to_cstring (reason_elem );
501
+ if (reason_str ) {
502
+ bson_string_append (reason , reason_str );
503
+ bson_free (reason_str );
504
+ goto done ;
505
+ } else {
506
+ bson_string_append (reason , "Unable to express trust failure error" );
507
+ goto done ;
508
+ }
509
+ }
510
+
511
+ bson_string_append (reason , "No trust failure reason available" );
512
+ done :
513
+ CFReleaseSafe (cfprops );
514
+ return bson_string_free (reason , false);
515
+ }
516
+
441
517
/* Returns a boolean indicating success. If false is returned, then an error is
442
518
* set.
443
519
*/
@@ -499,11 +575,13 @@ _verify_peer (mongoc_stream_t *stream, bson_error_t *error)
499
575
500
576
if (trust_result != kSecTrustResultProceed &&
501
577
trust_result != kSecTrustResultUnspecified ) {
578
+ char * reason = explain_trust_result (trust , trust_result );
502
579
bson_set_error (error ,
503
580
MONGOC_ERROR_STREAM ,
504
581
MONGOC_ERROR_STREAM_SOCKET ,
505
- "TLS handshake failed (%d)" ,
506
- trust_result );
582
+ "TLS handshake failed (%s)" ,
583
+ reason );
584
+ bson_free (reason );
507
585
goto fail ;
508
586
}
509
587
0 commit comments