@@ -1988,7 +1988,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
19881988}
19891989
19901990
1991- // TODO(indutny): Split it into multiple smaller functions
1991+ static Local<Object> AddIssuerChainToObject (X509** cert,
1992+ Local<Object> object,
1993+ STACK_OF (X509)* const peer_certs,
1994+ Environment* const env) {
1995+ Local<Context> context = env->isolate ()->GetCurrentContext ();
1996+ *cert = sk_X509_delete (peer_certs, 0 );
1997+ for (;;) {
1998+ int i;
1999+ for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
2000+ X509* ca = sk_X509_value (peer_certs, i);
2001+ if (X509_check_issued (ca, *cert) != X509_V_OK)
2002+ continue ;
2003+
2004+ Local<Object> ca_info = X509ToObject (env, ca);
2005+ object->Set (context, env->issuercert_string (), ca_info).FromJust ();
2006+ object = ca_info;
2007+
2008+ // NOTE: Intentionally freeing cert that is not used anymore.
2009+ X509_free (*cert);
2010+
2011+ // Delete cert and continue aggregating issuers.
2012+ *cert = sk_X509_delete (peer_certs, i);
2013+ break ;
2014+ }
2015+
2016+ // Issuer not found, break out of the loop.
2017+ if (i == sk_X509_num (peer_certs))
2018+ break ;
2019+ }
2020+ sk_X509_pop_free (peer_certs, X509_free);
2021+ return object;
2022+ }
2023+
2024+
2025+ static bool CloneSSLCerts (X509** cert,
2026+ const STACK_OF (X509)* const ssl_certs,
2027+ STACK_OF (X509)** peer_certs) {
2028+ *peer_certs = sk_X509_new (nullptr );
2029+ bool result = true ;
2030+ if (*cert != nullptr )
2031+ sk_X509_push (*peer_certs, *cert);
2032+ for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2033+ *cert = X509_dup (sk_X509_value (ssl_certs, i));
2034+ if (*cert == nullptr ) {
2035+ result = false ;
2036+ break ;
2037+ }
2038+ if (!sk_X509_push (*peer_certs, *cert)) {
2039+ result = false ;
2040+ break ;
2041+ }
2042+ }
2043+ if (!result) {
2044+ sk_X509_pop_free (*peer_certs, X509_free);
2045+ }
2046+ return result;
2047+ }
2048+
2049+
2050+ static Local<Object> GetLastIssuedCert (X509** cert,
2051+ const SSL* const ssl,
2052+ Local<Object> issuer_chain,
2053+ Environment* const env) {
2054+ Local<Context> context = env->isolate ()->GetCurrentContext ();
2055+ while (X509_check_issued (*cert, *cert) != X509_V_OK) {
2056+ X509* ca;
2057+ if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (ssl), *cert, &ca) <= 0 )
2058+ break ;
2059+
2060+ Local<Object> ca_info = X509ToObject (env, ca);
2061+ issuer_chain->Set (context, env->issuercert_string (), ca_info).FromJust ();
2062+ issuer_chain = ca_info;
2063+
2064+ // NOTE: Intentionally freeing cert that is not used anymore.
2065+ X509_free (*cert);
2066+
2067+ // Delete cert and continue aggregating issuers.
2068+ *cert = ca;
2069+ }
2070+ return issuer_chain;
2071+ }
2072+
2073+
19922074template <class Base >
19932075void SSLWrap<Base>::GetPeerCertificate (
19942076 const FunctionCallbackInfo<Value>& args) {
@@ -2000,97 +2082,43 @@ void SSLWrap<Base>::GetPeerCertificate(
20002082 ClearErrorOnReturn clear_error_on_return;
20012083
20022084 Local<Object> result;
2003- Local<Object> info;
2085+ // Used to build the issuer certificate chain.
2086+ Local<Object> issuer_chain;
20042087
20052088 // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
2006- // contains the `peer_certificate`, but on server it doesn't
2089+ // contains the `peer_certificate`, but on server it doesn't.
20072090 X509* cert = w->is_server () ? SSL_get_peer_certificate (w->ssl_ ) : nullptr ;
20082091 STACK_OF (X509)* ssl_certs = SSL_get_peer_cert_chain (w->ssl_ );
20092092 STACK_OF (X509)* peer_certs = nullptr ;
2010- if (cert == nullptr && ssl_certs == nullptr )
2093+ if (cert == nullptr && ( ssl_certs == nullptr || sk_X509_num (ssl_certs) == 0 ) )
20112094 goto done;
20122095
2013- if (cert == nullptr && sk_X509_num (ssl_certs) == 0 )
2014- goto done;
2015-
2016- // Short result requested
2096+ // Short result requested.
20172097 if (args.Length () < 1 || !args[0 ]->IsTrue ()) {
20182098 result = X509ToObject (env,
20192099 cert == nullptr ? sk_X509_value (ssl_certs, 0 ) : cert);
20202100 goto done;
20212101 }
20222102
2023- // Clone `ssl_certs`, because we are going to destruct it
2024- peer_certs = sk_X509_new (nullptr );
2025- if (cert != nullptr )
2026- sk_X509_push (peer_certs, cert);
2027- for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2028- cert = X509_dup (sk_X509_value (ssl_certs, i));
2029- if (cert == nullptr )
2030- goto done;
2031- if (!sk_X509_push (peer_certs, cert))
2032- goto done;
2033- }
2034-
2035- // First and main certificate
2036- cert = sk_X509_value (peer_certs, 0 );
2037- result = X509ToObject (env, cert);
2038- info = result;
2039-
2040- // Put issuer inside the object
2041- cert = sk_X509_delete (peer_certs, 0 );
2042- while (sk_X509_num (peer_certs) > 0 ) {
2043- int i;
2044- for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
2045- X509* ca = sk_X509_value (peer_certs, i);
2046- if (X509_check_issued (ca, cert) != X509_V_OK)
2047- continue ;
2048-
2049- Local<Object> ca_info = X509ToObject (env, ca);
2050- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2051- info = ca_info;
2052-
2053- // NOTE: Intentionally freeing cert that is not used anymore
2054- X509_free (cert);
2055-
2056- // Delete cert and continue aggregating issuers
2057- cert = sk_X509_delete (peer_certs, i);
2058- break ;
2059- }
2060-
2061- // Issuer not found, break out of the loop
2062- if (i == sk_X509_num (peer_certs))
2063- break ;
2064- }
2065-
2066- // Last certificate should be self-signed
2067- while (X509_check_issued (cert, cert) != X509_V_OK) {
2068- X509* ca;
2069- if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (w->ssl_ ), cert, &ca) <= 0 )
2070- break ;
2071-
2072- Local<Object> ca_info = X509ToObject (env, ca);
2073- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2074- info = ca_info;
2103+ if (CloneSSLCerts (&cert, ssl_certs, &peer_certs)) {
2104+ // First and main certificate.
2105+ cert = sk_X509_value (peer_certs, 0 );
2106+ result = X509ToObject (env, cert);
20752107
2076- // NOTE: Intentionally freeing cert that is not used anymore
2077- X509_free (cert);
2108+ issuer_chain = AddIssuerChainToObject (&cert, result, peer_certs, env);
2109+ issuer_chain = GetLastIssuedCert (&cert, w->ssl_ , issuer_chain, env);
2110+ // Last certificate should be self-signed.
2111+ if (X509_check_issued (cert, cert) == X509_V_OK)
2112+ issuer_chain->Set (env->context (),
2113+ env->issuercert_string (),
2114+ issuer_chain).FromJust ();
20782115
2079- // Delete cert and continue aggregating issuers
2080- cert = ca;
2116+ CHECK_NE (cert, nullptr );
20812117 }
20822118
2083- // Self-issued certificate
2084- if (X509_check_issued (cert, cert) == X509_V_OK)
2085- info->Set (context, env->issuercert_string (), info).FromJust ();
2086-
2087- CHECK_NE (cert, nullptr );
2088-
20892119 done:
20902120 if (cert != nullptr )
20912121 X509_free (cert);
2092- if (peer_certs != nullptr )
2093- sk_X509_pop_free (peer_certs, X509_free);
20942122 if (result.IsEmpty ())
20952123 result = Object::New (env->isolate ());
20962124 args.GetReturnValue ().Set (result);
0 commit comments