@@ -2002,7 +2002,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
2002
2002
}
2003
2003
2004
2004
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
+
2006
2088
template <class Base >
2007
2089
void SSLWrap<Base>::GetPeerCertificate (
2008
2090
const FunctionCallbackInfo<Value>& args) {
@@ -2014,97 +2096,43 @@ void SSLWrap<Base>::GetPeerCertificate(
2014
2096
ClearErrorOnReturn clear_error_on_return;
2015
2097
2016
2098
Local<Object> result;
2017
- Local<Object> info;
2099
+ // Used to build the issuer certificate chain.
2100
+ Local<Object> issuer_chain;
2018
2101
2019
2102
// 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.
2021
2104
X509* cert = w->is_server () ? SSL_get_peer_certificate (w->ssl_ ) : nullptr ;
2022
2105
STACK_OF (X509)* ssl_certs = SSL_get_peer_cert_chain (w->ssl_ );
2023
2106
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 ) )
2025
2108
goto done;
2026
2109
2027
- if (cert == nullptr && sk_X509_num (ssl_certs) == 0 )
2028
- goto done;
2029
-
2030
- // Short result requested
2110
+ // Short result requested.
2031
2111
if (args.Length () < 1 || !args[0 ]->IsTrue ()) {
2032
2112
result = X509ToObject (env,
2033
2113
cert == nullptr ? sk_X509_value (ssl_certs, 0 ) : cert);
2034
2114
goto done;
2035
2115
}
2036
2116
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);
2089
2121
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 ();
2092
2129
2093
- // Delete cert and continue aggregating issuers
2094
- cert = ca;
2130
+ CHECK_NE (cert, nullptr );
2095
2131
}
2096
2132
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
-
2103
2133
done:
2104
2134
if (cert != nullptr )
2105
2135
X509_free (cert);
2106
- if (peer_certs != nullptr )
2107
- sk_X509_pop_free (peer_certs, X509_free);
2108
2136
if (result.IsEmpty ())
2109
2137
result = Object::New (env->isolate ());
2110
2138
args.GetReturnValue ().Set (result);
0 commit comments