@@ -1988,7 +1988,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
1988
1988
}
1989
1989
1990
1990
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
+
1992
2074
template <class Base >
1993
2075
void SSLWrap<Base>::GetPeerCertificate (
1994
2076
const FunctionCallbackInfo<Value>& args) {
@@ -2000,97 +2082,43 @@ void SSLWrap<Base>::GetPeerCertificate(
2000
2082
ClearErrorOnReturn clear_error_on_return;
2001
2083
2002
2084
Local<Object> result;
2003
- Local<Object> info;
2085
+ // Used to build the issuer certificate chain.
2086
+ Local<Object> issuer_chain;
2004
2087
2005
2088
// 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.
2007
2090
X509* cert = w->is_server () ? SSL_get_peer_certificate (w->ssl_ ) : nullptr ;
2008
2091
STACK_OF (X509)* ssl_certs = SSL_get_peer_cert_chain (w->ssl_ );
2009
2092
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 ) )
2011
2094
goto done;
2012
2095
2013
- if (cert == nullptr && sk_X509_num (ssl_certs) == 0 )
2014
- goto done;
2015
-
2016
- // Short result requested
2096
+ // Short result requested.
2017
2097
if (args.Length () < 1 || !args[0 ]->IsTrue ()) {
2018
2098
result = X509ToObject (env,
2019
2099
cert == nullptr ? sk_X509_value (ssl_certs, 0 ) : cert);
2020
2100
goto done;
2021
2101
}
2022
2102
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);
2075
2107
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 ();
2078
2115
2079
- // Delete cert and continue aggregating issuers
2080
- cert = ca;
2116
+ CHECK_NE (cert, nullptr );
2081
2117
}
2082
2118
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
-
2089
2119
done:
2090
2120
if (cert != nullptr )
2091
2121
X509_free (cert);
2092
- if (peer_certs != nullptr )
2093
- sk_X509_pop_free (peer_certs, X509_free);
2094
2122
if (result.IsEmpty ())
2095
2123
result = Object::New (env->isolate ());
2096
2124
args.GetReturnValue ().Set (result);
0 commit comments