@@ -1969,7 +1969,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
19691969}
19701970
19711971
1972- // TODO(indutny): Split it into multiple smaller functions
1972+ static Local<Object> AddIssuerChainToObject (X509** cert,
1973+ Local<Object> object,
1974+ STACK_OF (X509)* const peer_certs,
1975+ Environment* const env) {
1976+ Local<Context> context = env->isolate ()->GetCurrentContext ();
1977+ *cert = sk_X509_delete (peer_certs, 0 );
1978+ for (;;) {
1979+ int i;
1980+ for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
1981+ X509* ca = sk_X509_value (peer_certs, i);
1982+ if (X509_check_issued (ca, *cert) != X509_V_OK)
1983+ continue ;
1984+
1985+ Local<Object> ca_info = X509ToObject (env, ca);
1986+ object->Set (context, env->issuercert_string (), ca_info).FromJust ();
1987+ object = ca_info;
1988+
1989+ // NOTE: Intentionally freeing cert that is not used anymore.
1990+ X509_free (*cert);
1991+
1992+ // Delete cert and continue aggregating issuers.
1993+ *cert = sk_X509_delete (peer_certs, i);
1994+ break ;
1995+ }
1996+
1997+ // Issuer not found, break out of the loop.
1998+ if (i == sk_X509_num (peer_certs))
1999+ break ;
2000+ }
2001+ sk_X509_pop_free (peer_certs, X509_free);
2002+ return object;
2003+ }
2004+
2005+
2006+ static bool CloneSSLCerts (X509** cert,
2007+ const STACK_OF (X509)* const ssl_certs,
2008+ STACK_OF (X509)** peer_certs) {
2009+ *peer_certs = sk_X509_new (nullptr );
2010+ bool result = true ;
2011+ if (*cert != nullptr )
2012+ sk_X509_push (*peer_certs, *cert);
2013+ for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2014+ *cert = X509_dup (sk_X509_value (ssl_certs, i));
2015+ if (*cert == nullptr ) {
2016+ result = false ;
2017+ break ;
2018+ }
2019+ if (!sk_X509_push (*peer_certs, *cert)) {
2020+ result = false ;
2021+ break ;
2022+ }
2023+ }
2024+ if (!result) {
2025+ sk_X509_pop_free (*peer_certs, X509_free);
2026+ }
2027+ return result;
2028+ }
2029+
2030+
2031+ static Local<Object> GetLastIssuedCert (X509** cert,
2032+ const SSL* const ssl,
2033+ Local<Object> issuer_chain,
2034+ Environment* const env) {
2035+ Local<Context> context = env->isolate ()->GetCurrentContext ();
2036+ while (X509_check_issued (*cert, *cert) != X509_V_OK) {
2037+ X509* ca;
2038+ if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (ssl), *cert, &ca) <= 0 )
2039+ break ;
2040+
2041+ Local<Object> ca_info = X509ToObject (env, ca);
2042+ issuer_chain->Set (context, env->issuercert_string (), ca_info).FromJust ();
2043+ issuer_chain = ca_info;
2044+
2045+ // NOTE: Intentionally freeing cert that is not used anymore.
2046+ X509_free (*cert);
2047+
2048+ // Delete cert and continue aggregating issuers.
2049+ *cert = ca;
2050+ }
2051+ return issuer_chain;
2052+ }
2053+
2054+
19732055template <class Base >
19742056void SSLWrap<Base>::GetPeerCertificate (
19752057 const FunctionCallbackInfo<Value>& args) {
@@ -1981,97 +2063,43 @@ void SSLWrap<Base>::GetPeerCertificate(
19812063 ClearErrorOnReturn clear_error_on_return;
19822064
19832065 Local<Object> result;
1984- Local<Object> info;
2066+ // Used to build the issuer certificate chain.
2067+ Local<Object> issuer_chain;
19852068
19862069 // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1987- // contains the `peer_certificate`, but on server it doesn't
2070+ // contains the `peer_certificate`, but on server it doesn't.
19882071 X509* cert = w->is_server () ? SSL_get_peer_certificate (w->ssl_ ) : nullptr ;
19892072 STACK_OF (X509)* ssl_certs = SSL_get_peer_cert_chain (w->ssl_ );
19902073 STACK_OF (X509)* peer_certs = nullptr ;
1991- if (cert == nullptr && ssl_certs == nullptr )
2074+ if (cert == nullptr && ( ssl_certs == nullptr || sk_X509_num (ssl_certs) == 0 ) )
19922075 goto done;
19932076
1994- if (cert == nullptr && sk_X509_num (ssl_certs) == 0 )
1995- goto done;
1996-
1997- // Short result requested
2077+ // Short result requested.
19982078 if (args.Length () < 1 || !args[0 ]->IsTrue ()) {
19992079 result = X509ToObject (env,
20002080 cert == nullptr ? sk_X509_value (ssl_certs, 0 ) : cert);
20012081 goto done;
20022082 }
20032083
2004- // Clone `ssl_certs`, because we are going to destruct it
2005- peer_certs = sk_X509_new (nullptr );
2006- if (cert != nullptr )
2007- sk_X509_push (peer_certs, cert);
2008- for (int i = 0 ; i < sk_X509_num (ssl_certs); i++) {
2009- cert = X509_dup (sk_X509_value (ssl_certs, i));
2010- if (cert == nullptr )
2011- goto done;
2012- if (!sk_X509_push (peer_certs, cert))
2013- goto done;
2014- }
2015-
2016- // First and main certificate
2017- cert = sk_X509_value (peer_certs, 0 );
2018- result = X509ToObject (env, cert);
2019- info = result;
2020-
2021- // Put issuer inside the object
2022- cert = sk_X509_delete (peer_certs, 0 );
2023- while (sk_X509_num (peer_certs) > 0 ) {
2024- int i;
2025- for (i = 0 ; i < sk_X509_num (peer_certs); i++) {
2026- X509* ca = sk_X509_value (peer_certs, i);
2027- if (X509_check_issued (ca, cert) != X509_V_OK)
2028- continue ;
2029-
2030- Local<Object> ca_info = X509ToObject (env, ca);
2031- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2032- info = ca_info;
2033-
2034- // NOTE: Intentionally freeing cert that is not used anymore
2035- X509_free (cert);
2036-
2037- // Delete cert and continue aggregating issuers
2038- cert = sk_X509_delete (peer_certs, i);
2039- break ;
2040- }
2041-
2042- // Issuer not found, break out of the loop
2043- if (i == sk_X509_num (peer_certs))
2044- break ;
2045- }
2046-
2047- // Last certificate should be self-signed
2048- while (X509_check_issued (cert, cert) != X509_V_OK) {
2049- X509* ca;
2050- if (SSL_CTX_get_issuer (SSL_get_SSL_CTX (w->ssl_ ), cert, &ca) <= 0 )
2051- break ;
2052-
2053- Local<Object> ca_info = X509ToObject (env, ca);
2054- info->Set (context, env->issuercert_string (), ca_info).FromJust ();
2055- info = ca_info;
2084+ if (CloneSSLCerts (&cert, ssl_certs, &peer_certs)) {
2085+ // First and main certificate.
2086+ cert = sk_X509_value (peer_certs, 0 );
2087+ result = X509ToObject (env, cert);
20562088
2057- // NOTE: Intentionally freeing cert that is not used anymore
2058- X509_free (cert);
2089+ issuer_chain = AddIssuerChainToObject (&cert, result, peer_certs, env);
2090+ issuer_chain = GetLastIssuedCert (&cert, w->ssl_ , issuer_chain, env);
2091+ // Last certificate should be self-signed.
2092+ if (X509_check_issued (cert, cert) == X509_V_OK)
2093+ issuer_chain->Set (env->context (),
2094+ env->issuercert_string (),
2095+ issuer_chain).FromJust ();
20592096
2060- // Delete cert and continue aggregating issuers
2061- cert = ca;
2097+ CHECK_NE (cert, nullptr );
20622098 }
20632099
2064- // Self-issued certificate
2065- if (X509_check_issued (cert, cert) == X509_V_OK)
2066- info->Set (context, env->issuercert_string (), info).FromJust ();
2067-
2068- CHECK_NE (cert, nullptr );
2069-
20702100 done:
20712101 if (cert != nullptr )
20722102 X509_free (cert);
2073- if (peer_certs != nullptr )
2074- sk_X509_pop_free (peer_certs, X509_free);
20752103 if (result.IsEmpty ())
20762104 result = Object::New (env->isolate ());
20772105 args.GetReturnValue ().Set (result);
0 commit comments