@@ -453,7 +453,10 @@ namespace web { namespace http
453
453
454
454
private:
455
455
tcp::resolver m_resolver;
456
-
456
+ #if defined(__APPLE__)
457
+ bool m_openssl_failed;
458
+ #endif
459
+
457
460
static bool _check_streambuf (std::shared_ptr<linux_client_request_context> ctx, concurrency::streams::streambuf<uint8_t > rdbuf, const utility::char_t * msg)
458
461
{
459
462
if (!rdbuf.is_open ())
@@ -487,6 +490,7 @@ namespace web { namespace http
487
490
{
488
491
ctx->m_ssl_stream ->set_verify_mode (boost::asio::ssl::context::verify_peer);
489
492
ctx->m_ssl_stream ->set_verify_callback (boost::bind (&linux_client::handle_cert_verification, shared_from_this (), _1, _2));
493
+ m_openssl_failed = false ;
490
494
}
491
495
else
492
496
{
@@ -538,6 +542,7 @@ namespace web { namespace http
538
542
{
539
543
ctx->m_ssl_stream ->set_verify_mode (boost::asio::ssl::context::verify_peer);
540
544
ctx->m_ssl_stream ->set_verify_callback (boost::bind (&linux_client::handle_cert_verification, shared_from_this (), _1, _2));
545
+ m_openssl_failed = false ;
541
546
}
542
547
else
543
548
{
@@ -551,47 +556,66 @@ namespace web { namespace http
551
556
552
557
bool handle_cert_verification (bool preverified, boost::asio::ssl::verify_context &ctx)
553
558
{
554
- #if defined(__APPLE__)
555
- // The 'leaf', non-Certificate Authority (CA) certificate, i.e. actual server certificate
556
- // is at the '0' position in the certificate chain, the rest are optional intermediate
557
- // certificates, followed finally by the root CA self signed certificate.
558
-
559
559
// OpenSSL calls the verification callback once per certificate in the chain,
560
- // starting with the root CA certificate. We will be performing verification all
561
- // at once using the whole certificate chain so wait until the 'leaf' cert.
562
- X509_STORE_CTX *storeContext = ctx.native_handle ();
563
- int currentDepth = X509_STORE_CTX_get_error_depth (storeContext);
564
- if (currentDepth == 0 )
560
+ // starting with the root CA certificate. The 'leaf', non-Certificate Authority (CA)
561
+ // certificate, i.e. actual server certificate is at the '0' position in the
562
+ // certificate chain, the rest are optional intermediate certificates, followed
563
+ // finally by the root CA self signed certificate.
564
+
565
+ #if defined(__APPLE__)
566
+ if (!preverified)
567
+ {
568
+ m_openssl_failed = true ;
569
+ }
570
+ if (m_openssl_failed)
565
571
{
566
- // preverified false means OpenSSL falied to verify the certificate successfully.
567
- // On OS X, iOS, or Android, OpenSSL doesn't have access to where the OS stores keychains.
568
- // To work around this we fall back to the OS facilities to verify the server certificate.
569
- if (!preverified)
572
+ // On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS
573
+ // stores keychains. If OpenSSL fails we will doing verification at the
574
+ // end using the whole certificate chain so wait until the 'leaf' cert.
575
+ // For now return true so OpenSSL continues down the certificate chain.
576
+ X509_STORE_CTX *storeContext = ctx.native_handle ();
577
+ int currentDepth = X509_STORE_CTX_get_error_depth (storeContext);
578
+ if (currentDepth != 0 )
570
579
{
571
- STACK_OF (X509) *certStack = X509_STORE_CTX_get_chain (ctx. native_handle ()) ;
572
- const int numCerts = sk_X509_num (certStack);
573
- std::vector<std::string> certChain;
574
-
575
- for ( int i = 0 ; i < numCerts; ++i)
576
- {
577
- X509 *cert = sk_X509_value (certStack, i);
578
-
579
- // Encode into DER format into raw memory.
580
- unsigned char * buffer = nullptr ;
581
- const int len = i2d_X509 (cert, &buffer) ;
582
- if (len < 0 )
583
- {
584
- return false ;
585
- }
580
+ return true ;
581
+ }
582
+
583
+ STACK_OF (X509) *certStack = X509_STORE_CTX_get_chain (storeContext);
584
+ const int numCerts = sk_X509_num (certStack);
585
+ if (numCerts < 0 )
586
+ {
587
+ return false ;
588
+ }
589
+
590
+ std::vector<std::string> certChain ;
591
+ certChain. reserve (numCerts);
592
+ for ( int i = 0 ; i < numCerts; ++i)
593
+ {
594
+ X509 *cert = sk_X509_value (certStack, i);
586
595
587
- certChain.emplace_back (reinterpret_cast <char *>(buffer), len);
596
+ // Encode into DER format into raw memory.
597
+ int len = i2d_X509 (cert, nullptr );
598
+ if (len < 0 )
599
+ {
600
+ return false ;
588
601
}
589
-
590
- return verify_X509_cert_chain (certChain, m_uri.host ());
602
+
603
+ std::string certData;
604
+ certData.resize (len);
605
+ unsigned char * buffer = reinterpret_cast <unsigned char *>(&certData[0 ]);
606
+ len = i2d_X509 (cert, &buffer);
607
+ if (len < 0 )
608
+ {
609
+ return false ;
610
+ }
611
+
612
+ certChain.push_back (std::move (certData));
591
613
}
614
+
615
+ return verify_X509_cert_chain (certChain, m_uri.host ());
592
616
}
593
617
#endif
594
-
618
+
595
619
boost::asio::ssl::rfc2818_verification rfc2818 (m_uri.host ());
596
620
return rfc2818 (preverified, ctx);
597
621
}
@@ -604,7 +628,7 @@ namespace web { namespace http
604
628
}
605
629
else
606
630
{
607
- ctx->report_error (" Error code in handle_handshake is " , ec, httpclient_errorcode_context::handshake);
631
+ ctx->report_error (" Error in SSL handshake " , ec, httpclient_errorcode_context::handshake);
608
632
}
609
633
}
610
634
0 commit comments