@@ -453,7 +453,10 @@ namespace web { namespace http
453453
454454 private:
455455 tcp::resolver m_resolver;
456-
456+ #if defined(__APPLE__)
457+ bool m_openssl_failed;
458+ #endif
459+
457460 static bool _check_streambuf (std::shared_ptr<linux_client_request_context> ctx, concurrency::streams::streambuf<uint8_t > rdbuf, const utility::char_t * msg)
458461 {
459462 if (!rdbuf.is_open ())
@@ -487,6 +490,7 @@ namespace web { namespace http
487490 {
488491 ctx->m_ssl_stream ->set_verify_mode (boost::asio::ssl::context::verify_peer);
489492 ctx->m_ssl_stream ->set_verify_callback (boost::bind (&linux_client::handle_cert_verification, shared_from_this (), _1, _2));
493+ m_openssl_failed = false ;
490494 }
491495 else
492496 {
@@ -538,6 +542,7 @@ namespace web { namespace http
538542 {
539543 ctx->m_ssl_stream ->set_verify_mode (boost::asio::ssl::context::verify_peer);
540544 ctx->m_ssl_stream ->set_verify_callback (boost::bind (&linux_client::handle_cert_verification, shared_from_this (), _1, _2));
545+ m_openssl_failed = false ;
541546 }
542547 else
543548 {
@@ -551,47 +556,66 @@ namespace web { namespace http
551556
552557 bool handle_cert_verification (bool preverified, boost::asio::ssl::verify_context &ctx)
553558 {
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-
559559 // 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)
565571 {
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 )
570579 {
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);
586595
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 ;
588601 }
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));
591613 }
614+
615+ return verify_X509_cert_chain (certChain, m_uri.host ());
592616 }
593617#endif
594-
618+
595619 boost::asio::ssl::rfc2818_verification rfc2818 (m_uri.host ());
596620 return rfc2818 (preverified, ctx);
597621 }
@@ -604,7 +628,7 @@ namespace web { namespace http
604628 }
605629 else
606630 {
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);
608632 }
609633 }
610634
0 commit comments