Skip to content

Commit f10470c

Browse files
danbevMylesBorins
authored andcommitted
src: refactor GetPeerCertificate
PR-URL: #19087 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]>
1 parent 6852461 commit f10470c

File tree

1 file changed

+100
-72
lines changed

1 file changed

+100
-72
lines changed

src/node_crypto.cc

+100-72
Original file line numberDiff line numberDiff line change
@@ -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+
20062088
template <class Base>
20072089
void 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

Comments
 (0)