Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f10470c

Browse filesBrowse files
danbevMylesBorins
authored andcommitted
src: refactor GetPeerCertificate
PR-URL: #19087 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
1 parent 6852461 commit f10470c
Copy full SHA for f10470c

File tree

Expand file treeCollapse file tree

1 file changed

+100
-72
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+100
-72
lines changed
Open diff view settings
Collapse file

‎src/node_crypto.cc‎

Copy file name to clipboardExpand all lines: src/node_crypto.cc
+100-72Lines changed: 100 additions & 72 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.