Skip to content

Commit c059909

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

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
@@ -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+
19922074
template <class Base>
19932075
void 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

Comments
 (0)