@@ -2002,7 +2002,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
20022002}
20032003
20042004
2005- // TODO(indutny): Split it into multiple smaller functions
2005+ static Local<Object> AddIssuerChainToObject (X509** cert,
2006+ Local<Object> object,
2007+ STACK_OF (X509)* const peer_certs,
2008+ Environment* const env) {
2009+ Local<Context> context = env->isolate ()->GetCurrentContext ();
2010+ *cert = sk_X509_delete (peer_certs, 0 );
2011+ for (;;) {
2012+ int i;
2013+ for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
2014+ X509* ca = sk_X509_value (peer_certs, i);
2015+ if (X509_check_issued (ca, *cert) != X509_V_OK)
2016+ continue ;
2017+
2018+ Local<Object> ca_info = X509ToObject (env, ca);
2019+ object->Set (context, env->issuercert_string (), ca_info).FromJust ();
2020+ object = ca_info;
2021+
2022+ // NOTE: Intentionally freeing cert that is not used anymore.
2023+ X509_free (*cert);
2024+
2025+ // Delete cert and continue aggregating issuers.
2026+ *cert = sk_X509_delete (peer_certs, i);
2027+ break ;
2028+ }
2029+
2030+ // Issuer not found, break out of the loop.
2031+ if (i == sk_X509_num (peer_certs))
2032+ break ;
2033+ }
2034+ sk_X509_pop_free (peer_certs, X509_free);
2035+ return object;
2036+ }
2037+
2038+
2039+ static bool CloneSSLCerts (X509** cert,
2040+ const STACK_OF (X509)* const ssl_certs,
2041+ STACK_OF (X509)** peer_certs) {
2042+ *peer_certs = sk_X509_new (nullptr );
2043+ bool result = true ;
2044+ if (*cert != nullptr )
2045+ sk_X509_push (*peer_certs, *cert);
2046+ for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2047+ *cert = X509_dup (sk_X509_value (ssl_certs, i));
2048+ if (*cert == nullptr ) {
2049+ result = false ;
2050+ break ;
2051+ }
2052+ if (!sk_X509_push (*peer_certs, *cert)) {
2053+ result = false ;
2054+ break ;
2055+ }
2056+ }
2057+ if (!result) {
2058+ sk_X509_pop_free (*peer_certs, X509_free);
2059+ }
2060+ return result;
2061+ }
2062+
2063+
2064+ static Local<Object> GetLastIssuedCert (X509** cert,
2065+ const SSL* const ssl,
2066+ Local<Object> issuer_chain,
2067+ Environment* const env) {
2068+ Local<Context> context = env->isolate ()->GetCurrentContext ();
2069+ while (X509_check_issued (*cert, *cert) != X509_V_OK) {
2070+ X509* ca;
2071+ if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (ssl), *cert, &ca) <= 0 )
2072+ break ;
2073+
2074+ Local<Object> ca_info = X509ToObject (env, ca);
2075+ issuer_chain->Set (context, env->issuercert_string (), ca_info).FromJust ();
2076+ issuer_chain = ca_info;
2077+
2078+ // NOTE: Intentionally freeing cert that is not used anymore.
2079+ X509_free (*cert);
2080+
2081+ // Delete cert and continue aggregating issuers.
2082+ *cert = ca;
2083+ }
2084+ return issuer_chain;
2085+ }
2086+
2087+
20062088template <class Base >
20072089void SSLWrap<Base>::GetPeerCertificate (
20082090 const FunctionCallbackInfo<Value>& args) {
@@ -2014,97 +2096,43 @@ void SSLWrap<Base>::GetPeerCertificate(
20142096 ClearErrorOnReturn clear_error_on_return;
20152097
20162098 Local<Object> result;
2017- Local<Object> info;
2099+ // Used to build the issuer certificate chain.
2100+ Local<Object> issuer_chain;
20182101
20192102 // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
2020- // contains the `peer_certificate`, but on server it doesn't
2103+ // contains the `peer_certificate`, but on server it doesn't.
20212104 X509* cert = w->is_server () ? SSL_get_peer_certificate (w->ssl_ ) : nullptr ;
20222105 STACK_OF (X509)* ssl_certs = SSL_get_peer_cert_chain (w->ssl_ );
20232106 STACK_OF (X509)* peer_certs = nullptr ;
2024- if (cert == nullptr && ssl_certs == nullptr )
2107+ if (cert == nullptr && ( ssl_certs == nullptr || sk_X509_num (ssl_certs) == 0 ) )
20252108 goto done;
20262109
2027- if (cert == nullptr && sk_X509_num (ssl_certs) == 0 )
2028- goto done;
2029-
2030- // Short result requested
2110+ // Short result requested.
20312111 if (args.Length () < 1 || !args[0 ]->IsTrue ()) {
20322112 result = X509ToObject (env,
20332113 cert == nullptr ? sk_X509_value (ssl_certs, 0 ) : cert);
20342114 goto done;
20352115 }
20362116
2037- // Clone `ssl_certs`, because we are going to destruct it
2038- peer_certs = sk_X509_new (nullptr );
2039- if (cert != nullptr )
2040- sk_X509_push (peer_certs, cert);
2041- for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2042- cert = X509_dup (sk_X509_value (ssl_certs, i));
2043- if (cert == nullptr )
2044- goto done;
2045- if (!sk_X509_push (peer_certs, cert))
2046- goto done;
2047- }
2048-
2049- // First and main certificate
2050- cert = sk_X509_value (peer_certs, 0 );
2051- result = X509ToObject (env, cert);
2052- info = result;
2053-
2054- // Put issuer inside the object
2055- cert = sk_X509_delete (peer_certs, 0 );
2056- while (sk_X509_num (peer_certs) > 0 ) {
2057- int i;
2058- for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
2059- X509* ca = sk_X509_value (peer_certs, i);
2060- if (X509_check_issued (ca, cert) != X509_V_OK)
2061- continue ;
2062-
2063- Local<Object> ca_info = X509ToObject (env, ca);
2064- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2065- info = ca_info;
2066-
2067- // NOTE: Intentionally freeing cert that is not used anymore
2068- X509_free (cert);
2069-
2070- // Delete cert and continue aggregating issuers
2071- cert = sk_X509_delete (peer_certs, i);
2072- break ;
2073- }
2074-
2075- // Issuer not found, break out of the loop
2076- if (i == sk_X509_num (peer_certs))
2077- break ;
2078- }
2079-
2080- // Last certificate should be self-signed
2081- while (X509_check_issued (cert, cert) != X509_V_OK) {
2082- X509* ca;
2083- if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (w->ssl_ ), cert, &ca) <= 0 )
2084- break ;
2085-
2086- Local<Object> ca_info = X509ToObject (env, ca);
2087- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2088- info = ca_info;
2117+ if (CloneSSLCerts (&cert, ssl_certs, &peer_certs)) {
2118+ // First and main certificate.
2119+ cert = sk_X509_value (peer_certs, 0 );
2120+ result = X509ToObject (env, cert);
20892121
2090- // NOTE: Intentionally freeing cert that is not used anymore
2091- X509_free (cert);
2122+ issuer_chain = AddIssuerChainToObject (&cert, result, peer_certs, env);
2123+ issuer_chain = GetLastIssuedCert (&cert, w->ssl_ , issuer_chain, env);
2124+ // Last certificate should be self-signed.
2125+ if (X509_check_issued (cert, cert) == X509_V_OK)
2126+ issuer_chain->Set (env->context (),
2127+ env->issuercert_string (),
2128+ issuer_chain).FromJust ();
20922129
2093- // Delete cert and continue aggregating issuers
2094- cert = ca;
2130+ CHECK_NE (cert, nullptr );
20952131 }
20962132
2097- // Self-issued certificate
2098- if (X509_check_issued (cert, cert) == X509_V_OK)
2099- info->Set (context, env->issuercert_string (), info).FromJust ();
2100-
2101- CHECK_NE (cert, nullptr );
2102-
21032133 done:
21042134 if (cert != nullptr )
21052135 X509_free (cert);
2106- if (peer_certs != nullptr )
2107- sk_X509_pop_free (peer_certs, X509_free);
21082136 if (result.IsEmpty ())
21092137 result = Object::New (env->isolate ());
21102138 args.GetReturnValue ().Set (result);
0 commit comments