Skip to content

Commit d8a14a2

Browse files
tniessenbengl
authored andcommitted
src: fix static analysis warning and use smart ptr
Coverity issues a warning about `value_before_reset == ca`, where value_before_reset is a pointer that may not be valid. While comparing the pointer itself should still work, we should really be using smart pointers here so that this particular check can be simplified without running into a memory leak. Refactor SSL_CTX_get_issuer to return a smart pointer and update the call sites accordingly. Note that we might have to change that in the future once we improve error handling throughout crypto/tls. Refs: #37990 PR-URL: #43117 Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
1 parent 6f48dfb commit d8a14a2

File tree

3 files changed

+25
-22
lines changed

3 files changed

+25
-22
lines changed

src/crypto/crypto_common.cc

+18-15
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,18 @@ static constexpr int kX509NameFlagsRFC2253WithinUtf8JSON =
5252
~ASN1_STRFLGS_ESC_MSB &
5353
~ASN1_STRFLGS_ESC_CTRL;
5454

55-
bool SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) {
55+
X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert) {
5656
X509_STORE* store = SSL_CTX_get_cert_store(ctx);
5757
DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
5858
X509_STORE_CTX_new());
59-
return store_ctx.get() != nullptr &&
60-
X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
61-
X509_STORE_CTX_get1_issuer(issuer, store_ctx.get(), cert) == 1;
59+
X509Pointer result;
60+
X509* issuer;
61+
if (store_ctx.get() != nullptr &&
62+
X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
63+
X509_STORE_CTX_get1_issuer(&issuer, store_ctx.get(), cert) == 1) {
64+
result.reset(issuer);
65+
}
66+
return result;
6267
}
6368

6469
void LogSecret(
@@ -390,29 +395,27 @@ MaybeLocal<Object> GetLastIssuedCert(
390395
Environment* const env) {
391396
Local<Context> context = env->isolate()->GetCurrentContext();
392397
while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) {
393-
X509* ca;
394-
if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get(), &ca) <= 0)
398+
X509Pointer ca;
399+
if (!(ca = SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get())))
395400
break;
396401

397402
Local<Object> ca_info;
398-
MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca);
403+
MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca.get());
399404
if (!maybe_ca_info.ToLocal(&ca_info))
400405
return MaybeLocal<Object>();
401406

402407
if (!Set<Object>(context, issuer_chain, env->issuercert_string(), ca_info))
403408
return MaybeLocal<Object>();
404409
issuer_chain = ca_info;
405410

406-
// Take the value of cert->get() before the call to cert->reset()
407-
// in order to compare it to ca after and provide a way to exit this loop
408-
// in case it gets stuck.
409-
X509* value_before_reset = cert->get();
411+
// For self-signed certificates whose keyUsage field does not include
412+
// keyCertSign, X509_check_issued() will return false. Avoid going into an
413+
// infinite loop by checking if SSL_CTX_get_issuer() returned the same
414+
// certificate.
415+
if (cert->get() == ca.get()) break;
410416

411417
// Delete previous cert and continue aggregating issuers.
412-
cert->reset(ca);
413-
414-
if (value_before_reset == ca)
415-
break;
418+
*cert = std::move(ca);
416419
}
417420
return MaybeLocal<Object>(issuer_chain);
418421
}

src/crypto/crypto_common.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct StackOfXASN1Deleter {
2525
};
2626
using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>;
2727

28-
bool SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer);
28+
X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert);
2929

3030
void LogSecret(
3131
const SSLPointer& ssl,

src/crypto/crypto_context.cc

+6-6
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,21 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
110110
// Try getting issuer from a cert store
111111
if (ret) {
112112
if (issuer == nullptr) {
113-
ret = SSL_CTX_get_issuer(ctx, x.get(), &issuer);
114-
ret = ret < 0 ? 0 : 1;
113+
// TODO(tniessen): SSL_CTX_get_issuer does not allow the caller to
114+
// distinguish between a failed operation and an empty result. Fix that
115+
// and then handle the potential error properly here (set ret to 0).
116+
*issuer_ = SSL_CTX_get_issuer(ctx, x.get());
115117
// NOTE: get_cert_store doesn't increment reference count,
116118
// no need to free `store`
117119
} else {
118120
// Increment issuer reference count
119-
issuer = X509_dup(issuer);
120-
if (issuer == nullptr) {
121+
issuer_->reset(X509_dup(issuer));
122+
if (!*issuer_) {
121123
ret = 0;
122124
}
123125
}
124126
}
125127

126-
issuer_->reset(issuer);
127-
128128
if (ret && x != nullptr) {
129129
cert->reset(X509_dup(x.get()));
130130
if (!*cert)

0 commit comments

Comments
 (0)