Skip to content

Commit d00841b

Browse files
committed
src: refactor GetPeerCertificate
1 parent 2990429 commit d00841b

File tree

1 file changed

+100
-72
lines changed

1 file changed

+100
-72
lines changed

src/node_crypto.cc

Lines changed: 100 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,89 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
19691969
}
19701970

19711971

1972-
// TODO(indutny): Split it into multiple smaller functions
1972+
static Local<Object> AddIssuerChainToObject(X509** cert,
1973+
Local<Object> object,
1974+
STACK_OF(X509)* const peer_certs,
1975+
Environment* const env) {
1976+
Local<Context> context = env->isolate()->GetCurrentContext();
1977+
*cert = sk_X509_delete(peer_certs, 0);
1978+
for (;;) {
1979+
int i;
1980+
for (i = 0; i < sk_X509_num(peer_certs); i++) {
1981+
X509* ca = sk_X509_value(peer_certs, i);
1982+
if (X509_check_issued(ca, *cert) != X509_V_OK)
1983+
continue;
1984+
1985+
Local<Object> ca_info = X509ToObject(env, ca);
1986+
object->Set(context, env->issuercert_string(), ca_info).FromJust();
1987+
object = ca_info;
1988+
1989+
// NOTE: Intentionally freeing cert that is not used anymore.
1990+
X509_free(*cert);
1991+
1992+
// Delete cert and continue aggregating issuers.
1993+
*cert = sk_X509_delete(peer_certs, i);
1994+
break;
1995+
}
1996+
1997+
// Issuer not found, break out of the loop.
1998+
if (i == sk_X509_num(peer_certs))
1999+
break;
2000+
}
2001+
sk_X509_pop_free(peer_certs, X509_free);
2002+
return object;
2003+
}
2004+
2005+
2006+
static bool CloneSSLCerts(X509** cert,
2007+
const STACK_OF(X509)* const ssl_certs,
2008+
STACK_OF(X509)** peer_certs) {
2009+
*peer_certs = sk_X509_new(nullptr);
2010+
bool result = true;
2011+
if (*cert != nullptr)
2012+
sk_X509_push(*peer_certs, *cert);
2013+
for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
2014+
*cert = X509_dup(sk_X509_value(ssl_certs, i));
2015+
if (*cert == nullptr) {
2016+
result = false;
2017+
break;
2018+
}
2019+
if (!sk_X509_push(*peer_certs, *cert)) {
2020+
result = false;
2021+
break;
2022+
}
2023+
}
2024+
if (!result) {
2025+
sk_X509_pop_free(*peer_certs, X509_free);
2026+
}
2027+
return result;
2028+
}
2029+
2030+
2031+
static Local<Object> GetLastIssuedCert(X509** cert,
2032+
const SSL* const ssl,
2033+
Local<Object> issuer_chain,
2034+
Environment* const env) {
2035+
Local<Context> context = env->isolate()->GetCurrentContext();
2036+
while (X509_check_issued(*cert, *cert) != X509_V_OK) {
2037+
X509* ca;
2038+
if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl), *cert, &ca) <= 0)
2039+
break;
2040+
2041+
Local<Object> ca_info = X509ToObject(env, ca);
2042+
issuer_chain->Set(context, env->issuercert_string(), ca_info).FromJust();
2043+
issuer_chain = ca_info;
2044+
2045+
// NOTE: Intentionally freeing cert that is not used anymore.
2046+
X509_free(*cert);
2047+
2048+
// Delete cert and continue aggregating issuers.
2049+
*cert = ca;
2050+
}
2051+
return issuer_chain;
2052+
}
2053+
2054+
19732055
template <class Base>
19742056
void SSLWrap<Base>::GetPeerCertificate(
19752057
const FunctionCallbackInfo<Value>& args) {
@@ -1981,97 +2063,43 @@ void SSLWrap<Base>::GetPeerCertificate(
19812063
ClearErrorOnReturn clear_error_on_return;
19822064

19832065
Local<Object> result;
1984-
Local<Object> info;
2066+
// Used to build the issuer certificate chain.
2067+
Local<Object> issuer_chain;
19852068

19862069
// NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1987-
// contains the `peer_certificate`, but on server it doesn't
2070+
// contains the `peer_certificate`, but on server it doesn't.
19882071
X509* cert = w->is_server() ? SSL_get_peer_certificate(w->ssl_) : nullptr;
19892072
STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(w->ssl_);
19902073
STACK_OF(X509)* peer_certs = nullptr;
1991-
if (cert == nullptr && ssl_certs == nullptr)
2074+
if (cert == nullptr && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
19922075
goto done;
19932076

1994-
if (cert == nullptr && sk_X509_num(ssl_certs) == 0)
1995-
goto done;
1996-
1997-
// Short result requested
2077+
// Short result requested.
19982078
if (args.Length() < 1 || !args[0]->IsTrue()) {
19992079
result = X509ToObject(env,
20002080
cert == nullptr ? sk_X509_value(ssl_certs, 0) : cert);
20012081
goto done;
20022082
}
20032083

2004-
// Clone `ssl_certs`, because we are going to destruct it
2005-
peer_certs = sk_X509_new(nullptr);
2006-
if (cert != nullptr)
2007-
sk_X509_push(peer_certs, cert);
2008-
for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
2009-
cert = X509_dup(sk_X509_value(ssl_certs, i));
2010-
if (cert == nullptr)
2011-
goto done;
2012-
if (!sk_X509_push(peer_certs, cert))
2013-
goto done;
2014-
}
2015-
2016-
// First and main certificate
2017-
cert = sk_X509_value(peer_certs, 0);
2018-
result = X509ToObject(env, cert);
2019-
info = result;
2020-
2021-
// Put issuer inside the object
2022-
cert = sk_X509_delete(peer_certs, 0);
2023-
while (sk_X509_num(peer_certs) > 0) {
2024-
int i;
2025-
for (i = 0; i < sk_X509_num(peer_certs); i++) {
2026-
X509* ca = sk_X509_value(peer_certs, i);
2027-
if (X509_check_issued(ca, cert) != X509_V_OK)
2028-
continue;
2029-
2030-
Local<Object> ca_info = X509ToObject(env, ca);
2031-
info->Set(context, env->issuercert_string(), ca_info).FromJust();
2032-
info = ca_info;
2033-
2034-
// NOTE: Intentionally freeing cert that is not used anymore
2035-
X509_free(cert);
2036-
2037-
// Delete cert and continue aggregating issuers
2038-
cert = sk_X509_delete(peer_certs, i);
2039-
break;
2040-
}
2041-
2042-
// Issuer not found, break out of the loop
2043-
if (i == sk_X509_num(peer_certs))
2044-
break;
2045-
}
2046-
2047-
// Last certificate should be self-signed
2048-
while (X509_check_issued(cert, cert) != X509_V_OK) {
2049-
X509* ca;
2050-
if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(w->ssl_), cert, &ca) <= 0)
2051-
break;
2052-
2053-
Local<Object> ca_info = X509ToObject(env, ca);
2054-
info->Set(context, env->issuercert_string(), ca_info).FromJust();
2055-
info = ca_info;
2084+
if (CloneSSLCerts(&cert, ssl_certs, &peer_certs)) {
2085+
// First and main certificate.
2086+
cert = sk_X509_value(peer_certs, 0);
2087+
result = X509ToObject(env, cert);
20562088

2057-
// NOTE: Intentionally freeing cert that is not used anymore
2058-
X509_free(cert);
2089+
issuer_chain = AddIssuerChainToObject(&cert, result, peer_certs, env);
2090+
issuer_chain = GetLastIssuedCert(&cert, w->ssl_, issuer_chain, env);
2091+
// Last certificate should be self-signed.
2092+
if (X509_check_issued(cert, cert) == X509_V_OK)
2093+
issuer_chain->Set(env->context(),
2094+
env->issuercert_string(),
2095+
issuer_chain).FromJust();
20592096

2060-
// Delete cert and continue aggregating issuers
2061-
cert = ca;
2097+
CHECK_NE(cert, nullptr);
20622098
}
20632099

2064-
// Self-issued certificate
2065-
if (X509_check_issued(cert, cert) == X509_V_OK)
2066-
info->Set(context, env->issuercert_string(), info).FromJust();
2067-
2068-
CHECK_NE(cert, nullptr);
2069-
20702100
done:
20712101
if (cert != nullptr)
20722102
X509_free(cert);
2073-
if (peer_certs != nullptr)
2074-
sk_X509_pop_free(peer_certs, X509_free);
20752103
if (result.IsEmpty())
20762104
result = Object::New(env->isolate());
20772105
args.GetReturnValue().Set(result);

0 commit comments

Comments
 (0)