Skip to content

Commit 06b34c8

Browse files
bnoordhuisMayaLekova
authored andcommitted
src: use std::unique_ptr for STACK_OF(X509)
Convert manual memory management of STACK_OF(X509) instances to std::unique_ptr with a custom deleter. Note the tasteful application of std::move() to indicate a function that consumes its argument. 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 c059909 commit 06b34c8

File tree

1 file changed

+44
-54
lines changed

1 file changed

+44
-54
lines changed

src/node_crypto.cc

+44-54
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@
4343
// StartComAndWoSignData.inc
4444
#include "StartComAndWoSignData.inc"
4545

46-
#include <algorithm>
4746
#include <errno.h>
4847
#include <limits.h> // INT_MAX
4948
#include <math.h>
5049
#include <stdlib.h>
5150
#include <string.h>
51+
52+
#include <algorithm>
53+
#include <memory>
5254
#include <vector>
5355

5456
#define THROW_AND_RETURN_IF_NOT_BUFFER(val, prefix) \
@@ -107,6 +109,12 @@ using v8::String;
107109
using v8::Value;
108110

109111

112+
struct StackOfX509Deleter {
113+
void operator()(STACK_OF(X509)* p) const { sk_X509_pop_free(p, X509_free); }
114+
};
115+
116+
using StackOfX509 = std::unique_ptr<STACK_OF(X509), StackOfX509Deleter>;
117+
110118
#if OPENSSL_VERSION_NUMBER < 0x10100000L
111119
static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e,
112120
const BIGNUM** d) {
@@ -829,17 +837,15 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
829837
int ret = 0;
830838
unsigned long err = 0; // NOLINT(runtime/int)
831839

832-
// Read extra certs
833-
STACK_OF(X509)* extra_certs = sk_X509_new_null();
834-
if (extra_certs == nullptr) {
840+
StackOfX509 extra_certs(sk_X509_new_null());
841+
if (!extra_certs)
835842
goto done;
836-
}
837843

838844
while ((extra = PEM_read_bio_X509(in,
839845
nullptr,
840846
NoPasswordCallback,
841847
nullptr))) {
842-
if (sk_X509_push(extra_certs, extra))
848+
if (sk_X509_push(extra_certs.get(), extra))
843849
continue;
844850

845851
// Failure, free all certs
@@ -857,13 +863,11 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
857863
goto done;
858864
}
859865

860-
ret = SSL_CTX_use_certificate_chain(ctx, x, extra_certs, cert, issuer);
866+
ret = SSL_CTX_use_certificate_chain(ctx, x, extra_certs.get(), cert, issuer);
861867
if (!ret)
862868
goto done;
863869

864870
done:
865-
if (extra_certs != nullptr)
866-
sk_X509_pop_free(extra_certs, X509_free);
867871
if (extra != nullptr)
868872
X509_free(extra);
869873
if (x != nullptr)
@@ -1990,14 +1994,14 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
19901994

19911995
static Local<Object> AddIssuerChainToObject(X509** cert,
19921996
Local<Object> object,
1993-
STACK_OF(X509)* const peer_certs,
1997+
StackOfX509 peer_certs,
19941998
Environment* const env) {
19951999
Local<Context> context = env->isolate()->GetCurrentContext();
1996-
*cert = sk_X509_delete(peer_certs, 0);
2000+
*cert = sk_X509_delete(peer_certs.get(), 0);
19972001
for (;;) {
19982002
int i;
1999-
for (i = 0; i < sk_X509_num(peer_certs); i++) {
2000-
X509* ca = sk_X509_value(peer_certs, i);
2003+
for (i = 0; i < sk_X509_num(peer_certs.get()); i++) {
2004+
X509* ca = sk_X509_value(peer_certs.get(), i);
20012005
if (X509_check_issued(ca, *cert) != X509_V_OK)
20022006
continue;
20032007

@@ -2009,41 +2013,31 @@ static Local<Object> AddIssuerChainToObject(X509** cert,
20092013
X509_free(*cert);
20102014

20112015
// Delete cert and continue aggregating issuers.
2012-
*cert = sk_X509_delete(peer_certs, i);
2016+
*cert = sk_X509_delete(peer_certs.get(), i);
20132017
break;
20142018
}
20152019

20162020
// Issuer not found, break out of the loop.
2017-
if (i == sk_X509_num(peer_certs))
2021+
if (i == sk_X509_num(peer_certs.get()))
20182022
break;
20192023
}
2020-
sk_X509_pop_free(peer_certs, X509_free);
20212024
return object;
20222025
}
20232026

20242027

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;
2028+
static StackOfX509 CloneSSLCerts(X509** cert,
2029+
const STACK_OF(X509)* const ssl_certs) {
2030+
StackOfX509 peer_certs(sk_X509_new(nullptr));
20302031
if (*cert != nullptr)
2031-
sk_X509_push(*peer_certs, *cert);
2032+
sk_X509_push(peer_certs.get(), *cert);
20322033
for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
20332034
*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);
2035+
if (*cert == nullptr)
2036+
return StackOfX509();
2037+
if (!sk_X509_push(peer_certs.get(), *cert))
2038+
return StackOfX509();
20452039
}
2046-
return result;
2040+
return peer_certs;
20472041
}
20482042

20492043

@@ -2077,7 +2071,6 @@ void SSLWrap<Base>::GetPeerCertificate(
20772071
Base* w;
20782072
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
20792073
Environment* env = w->ssl_env();
2080-
Local<Context> context = env->context();
20812074

20822075
ClearErrorOnReturn clear_error_on_return;
20832076

@@ -2089,23 +2082,25 @@ void SSLWrap<Base>::GetPeerCertificate(
20892082
// contains the `peer_certificate`, but on server it doesn't.
20902083
X509* cert = w->is_server() ? SSL_get_peer_certificate(w->ssl_) : nullptr;
20912084
STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(w->ssl_);
2092-
STACK_OF(X509)* peer_certs = nullptr;
20932085
if (cert == nullptr && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
20942086
goto done;
20952087

20962088
// Short result requested.
20972089
if (args.Length() < 1 || !args[0]->IsTrue()) {
2098-
result = X509ToObject(env,
2099-
cert == nullptr ? sk_X509_value(ssl_certs, 0) : cert);
2090+
X509* target_cert = cert;
2091+
if (target_cert == nullptr)
2092+
target_cert = sk_X509_value(ssl_certs, 0);
2093+
result = X509ToObject(env, target_cert);
21002094
goto done;
21012095
}
21022096

2103-
if (CloneSSLCerts(&cert, ssl_certs, &peer_certs)) {
2097+
if (auto peer_certs = CloneSSLCerts(&cert, ssl_certs)) {
21042098
// First and main certificate.
2105-
cert = sk_X509_value(peer_certs, 0);
2099+
cert = sk_X509_value(peer_certs.get(), 0);
21062100
result = X509ToObject(env, cert);
21072101

2108-
issuer_chain = AddIssuerChainToObject(&cert, result, peer_certs, env);
2102+
issuer_chain =
2103+
AddIssuerChainToObject(&cert, result, std::move(peer_certs), env);
21092104
issuer_chain = GetLastIssuedCert(&cert, w->ssl_, issuer_chain, env);
21102105
// Last certificate should be self-signed.
21112106
if (X509_check_issued(cert, cert) == X509_V_OK)
@@ -2959,25 +2954,23 @@ inline CheckResult CheckWhitelistedServerCert(X509_STORE_CTX* ctx) {
29592954
unsigned char hash[CNNIC_WHITELIST_HASH_LEN];
29602955
unsigned int hashlen = CNNIC_WHITELIST_HASH_LEN;
29612956

2962-
STACK_OF(X509)* chain = X509_STORE_CTX_get1_chain(ctx);
2963-
CHECK_NE(chain, nullptr);
2964-
CHECK_GT(sk_X509_num(chain), 0);
2957+
StackOfX509 chain(X509_STORE_CTX_get1_chain(ctx));
2958+
CHECK(chain);
2959+
CHECK_GT(sk_X509_num(chain.get()), 0);
29652960

29662961
// Take the last cert as root at the first time.
2967-
X509* root_cert = sk_X509_value(chain, sk_X509_num(chain)-1);
2962+
X509* root_cert = sk_X509_value(chain.get(), sk_X509_num(chain.get())-1);
29682963
X509_NAME* root_name = X509_get_subject_name(root_cert);
29692964

29702965
if (!IsSelfSigned(root_cert)) {
2971-
root_cert = FindRoot(chain);
2966+
root_cert = FindRoot(chain.get());
29722967
CHECK_NE(root_cert, nullptr);
29732968
root_name = X509_get_subject_name(root_cert);
29742969
}
29752970

2976-
X509* leaf_cert = sk_X509_value(chain, 0);
2977-
if (!CheckStartComOrWoSign(root_name, leaf_cert)) {
2978-
sk_X509_pop_free(chain, X509_free);
2971+
X509* leaf_cert = sk_X509_value(chain.get(), 0);
2972+
if (!CheckStartComOrWoSign(root_name, leaf_cert))
29792973
return CHECK_CERT_REVOKED;
2980-
}
29812974

29822975
// When the cert is issued from either CNNNIC ROOT CA or CNNNIC EV
29832976
// ROOT CA, check a hash of its leaf cert if it is in the whitelist.
@@ -2990,13 +2983,10 @@ inline CheckResult CheckWhitelistedServerCert(X509_STORE_CTX* ctx) {
29902983
void* result = bsearch(hash, WhitelistedCNNICHashes,
29912984
arraysize(WhitelistedCNNICHashes),
29922985
CNNIC_WHITELIST_HASH_LEN, compar);
2993-
if (result == nullptr) {
2994-
sk_X509_pop_free(chain, X509_free);
2986+
if (result == nullptr)
29952987
return CHECK_CERT_REVOKED;
2996-
}
29972988
}
29982989

2999-
sk_X509_pop_free(chain, X509_free);
30002990
return CHECK_OK;
30012991
}
30022992

0 commit comments

Comments
 (0)