summaryrefslogtreecommitdiff
path: root/thirdparty/openssl/crypto/x509
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/openssl/crypto/x509')
-rw-r--r--thirdparty/openssl/crypto/x509/by_dir.c4
-rw-r--r--thirdparty/openssl/crypto/x509/x509_att.c12
-rw-r--r--thirdparty/openssl/crypto/x509/x509_err.c3
-rw-r--r--thirdparty/openssl/crypto/x509/x509_lu.c41
-rw-r--r--thirdparty/openssl/crypto/x509/x509_obj.c2
-rw-r--r--thirdparty/openssl/crypto/x509/x509_r2x.c14
-rw-r--r--thirdparty/openssl/crypto/x509/x509_txt.c7
-rw-r--r--thirdparty/openssl/crypto/x509/x509_vfy.c168
-rw-r--r--thirdparty/openssl/crypto/x509/x509spki.c2
9 files changed, 213 insertions, 40 deletions
diff --git a/thirdparty/openssl/crypto/x509/by_dir.c b/thirdparty/openssl/crypto/x509/by_dir.c
index 9ee8f8d859..bbc3189381 100644
--- a/thirdparty/openssl/crypto/x509/by_dir.c
+++ b/thirdparty/openssl/crypto/x509/by_dir.c
@@ -401,6 +401,10 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
}
if (!hent) {
hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
+ if (hent == NULL) {
+ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE);
+ goto finish;
+ }
hent->hash = h;
hent->suffix = k;
if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
diff --git a/thirdparty/openssl/crypto/x509/x509_att.c b/thirdparty/openssl/crypto/x509/x509_att.c
index bd59281f9d..2501075307 100644
--- a/thirdparty/openssl/crypto/x509/x509_att.c
+++ b/thirdparty/openssl/crypto/x509/x509_att.c
@@ -296,7 +296,7 @@ int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj)
int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
const void *data, int len)
{
- ASN1_TYPE *ttmp;
+ ASN1_TYPE *ttmp = NULL;
ASN1_STRING *stmp = NULL;
int atype = 0;
if (!attr)
@@ -324,20 +324,26 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
* least one value but some types use and zero length SET and require
* this.
*/
- if (attrtype == 0)
+ if (attrtype == 0) {
+ ASN1_STRING_free(stmp);
return 1;
+ }
if (!(ttmp = ASN1_TYPE_new()))
goto err;
if ((len == -1) && !(attrtype & MBSTRING_FLAG)) {
if (!ASN1_TYPE_set1(ttmp, attrtype, data))
goto err;
- } else
+ } else {
ASN1_TYPE_set(ttmp, atype, stmp);
+ stmp = NULL;
+ }
if (!sk_ASN1_TYPE_push(attr->value.set, ttmp))
goto err;
return 1;
err:
X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_MALLOC_FAILURE);
+ ASN1_TYPE_free(ttmp);
+ ASN1_STRING_free(stmp);
return 0;
}
diff --git a/thirdparty/openssl/crypto/x509/x509_err.c b/thirdparty/openssl/crypto/x509/x509_err.c
index 1e779fefd9..a2a8e1b08b 100644
--- a/thirdparty/openssl/crypto/x509/x509_err.c
+++ b/thirdparty/openssl/crypto/x509/x509_err.c
@@ -1,6 +1,6 @@
/* crypto/x509/x509_err.c */
/* ====================================================================
- * Copyright (c) 1999-2012 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1999-2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -72,6 +72,7 @@
static ERR_STRING_DATA X509_str_functs[] = {
{ERR_FUNC(X509_F_ADD_CERT_DIR), "ADD_CERT_DIR"},
{ERR_FUNC(X509_F_BY_FILE_CTRL), "BY_FILE_CTRL"},
+ {ERR_FUNC(X509_F_CHECK_NAME_CONSTRAINTS), "CHECK_NAME_CONSTRAINTS"},
{ERR_FUNC(X509_F_CHECK_POLICY), "CHECK_POLICY"},
{ERR_FUNC(X509_F_DIR_CTRL), "DIR_CTRL"},
{ERR_FUNC(X509_F_GET_CERT_BY_SUBJECT), "GET_CERT_BY_SUBJECT"},
diff --git a/thirdparty/openssl/crypto/x509/x509_lu.c b/thirdparty/openssl/crypto/x509/x509_lu.c
index 50120a4d70..b7424809fd 100644
--- a/thirdparty/openssl/crypto/x509/x509_lu.c
+++ b/thirdparty/openssl/crypto/x509/x509_lu.c
@@ -185,14 +185,16 @@ X509_STORE *X509_STORE_new(void)
if ((ret = (X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL)
return NULL;
- ret->objs = sk_X509_OBJECT_new(x509_object_cmp);
+ if ((ret->objs = sk_X509_OBJECT_new(x509_object_cmp)) == NULL)
+ goto err0;
ret->cache = 1;
- ret->get_cert_methods = sk_X509_LOOKUP_new_null();
+ if ((ret->get_cert_methods = sk_X509_LOOKUP_new_null()) == NULL)
+ goto err1;
ret->verify = 0;
ret->verify_cb = 0;
if ((ret->param = X509_VERIFY_PARAM_new()) == NULL)
- return NULL;
+ goto err2;
ret->get_issuer = 0;
ret->check_issued = 0;
@@ -204,14 +206,21 @@ X509_STORE *X509_STORE_new(void)
ret->lookup_crls = 0;
ret->cleanup = 0;
- if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data)) {
- sk_X509_OBJECT_free(ret->objs);
- OPENSSL_free(ret);
- return NULL;
- }
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data))
+ goto err3;
ret->references = 1;
return ret;
+
+ err3:
+ X509_VERIFY_PARAM_free(ret->param);
+ err2:
+ sk_X509_LOOKUP_free(ret->get_cert_methods);
+ err1:
+ sk_X509_OBJECT_free(ret->objs);
+ err0:
+ OPENSSL_free(ret);
+ return NULL;
}
static void cleanup(X509_OBJECT *a)
@@ -360,8 +369,12 @@ int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
X509err(X509_F_X509_STORE_ADD_CERT,
X509_R_CERT_ALREADY_IN_HASH_TABLE);
ret = 0;
- } else
- sk_X509_OBJECT_push(ctx->objs, obj);
+ } else if (!sk_X509_OBJECT_push(ctx->objs, obj)) {
+ X509_OBJECT_free_contents(obj);
+ OPENSSL_free(obj);
+ X509err(X509_F_X509_STORE_ADD_CERT, ERR_R_MALLOC_FAILURE);
+ ret = 0;
+ }
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
@@ -392,8 +405,12 @@ int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
OPENSSL_free(obj);
X509err(X509_F_X509_STORE_ADD_CRL, X509_R_CERT_ALREADY_IN_HASH_TABLE);
ret = 0;
- } else
- sk_X509_OBJECT_push(ctx->objs, obj);
+ } else if (!sk_X509_OBJECT_push(ctx->objs, obj)) {
+ X509_OBJECT_free_contents(obj);
+ OPENSSL_free(obj);
+ X509err(X509_F_X509_STORE_ADD_CRL, ERR_R_MALLOC_FAILURE);
+ ret = 0;
+ }
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
diff --git a/thirdparty/openssl/crypto/x509/x509_obj.c b/thirdparty/openssl/crypto/x509/x509_obj.c
index 3de3ac7204..0a839f3e54 100644
--- a/thirdparty/openssl/crypto/x509/x509_obj.c
+++ b/thirdparty/openssl/crypto/x509/x509_obj.c
@@ -129,7 +129,7 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
type == V_ASN1_VISIBLESTRING ||
type == V_ASN1_PRINTABLESTRING ||
type == V_ASN1_TELETEXSTRING ||
- type == V_ASN1_VISIBLESTRING || type == V_ASN1_IA5STRING) {
+ type == V_ASN1_IA5STRING) {
if (num > (int)sizeof(ebcdic_buf))
num = sizeof(ebcdic_buf);
ascii2ebcdic(ebcdic_buf, q, num);
diff --git a/thirdparty/openssl/crypto/x509/x509_r2x.c b/thirdparty/openssl/crypto/x509/x509_r2x.c
index 0ff439c99f..2879569ead 100644
--- a/thirdparty/openssl/crypto/x509/x509_r2x.c
+++ b/thirdparty/openssl/crypto/x509/x509_r2x.c
@@ -70,10 +70,12 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
X509 *ret = NULL;
X509_CINF *xi = NULL;
X509_NAME *xn;
+ EVP_PKEY *pubkey = NULL;
+ int res;
if ((ret = X509_new()) == NULL) {
X509err(X509_F_X509_REQ_TO_X509, ERR_R_MALLOC_FAILURE);
- goto err;
+ return NULL;
}
/* duplicate the request */
@@ -89,9 +91,9 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
}
xn = X509_REQ_get_subject_name(r);
- if (X509_set_subject_name(ret, X509_NAME_dup(xn)) == 0)
+ if (X509_set_subject_name(ret, xn) == 0)
goto err;
- if (X509_set_issuer_name(ret, X509_NAME_dup(xn)) == 0)
+ if (X509_set_issuer_name(ret, xn) == 0)
goto err;
if (X509_gmtime_adj(xi->validity->notBefore, 0) == NULL)
@@ -100,9 +102,11 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
NULL)
goto err;
- X509_set_pubkey(ret, X509_REQ_get_pubkey(r));
+ pubkey = X509_REQ_get_pubkey(r);
+ res = X509_set_pubkey(ret, pubkey);
+ EVP_PKEY_free(pubkey);
- if (!X509_sign(ret, pkey, EVP_md5()))
+ if (!res || !X509_sign(ret, pkey, EVP_md5()))
goto err;
if (0) {
err:
diff --git a/thirdparty/openssl/crypto/x509/x509_txt.c b/thirdparty/openssl/crypto/x509/x509_txt.c
index 3d46d3ff83..35db095591 100644
--- a/thirdparty/openssl/crypto/x509/x509_txt.c
+++ b/thirdparty/openssl/crypto/x509/x509_txt.c
@@ -204,6 +204,13 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_IP_ADDRESS_MISMATCH:
return ("IP address mismatch");
+ case X509_V_ERR_INVALID_CALL:
+ return ("Invalid certificate verification context");
+ case X509_V_ERR_STORE_LOOKUP:
+ return ("Issuer certificate lookup error");
+ case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION:
+ return ("proxy subject name violation");
+
default:
BIO_snprintf(buf, sizeof buf, "error number %ld", n);
return (buf);
diff --git a/thirdparty/openssl/crypto/x509/x509_vfy.c b/thirdparty/openssl/crypto/x509/x509_vfy.c
index 4d34dbac93..b1472018ba 100644
--- a/thirdparty/openssl/crypto/x509/x509_vfy.c
+++ b/thirdparty/openssl/crypto/x509/x509_vfy.c
@@ -199,6 +199,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (ctx->cert == NULL) {
X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
if (ctx->chain != NULL) {
@@ -207,6 +208,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* cannot do another one.
*/
X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
@@ -219,6 +221,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (((ctx->chain = sk_X509_new_null()) == NULL) ||
(!sk_X509_push(ctx->chain, ctx->cert))) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = -1;
goto err;
}
@@ -229,6 +232,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (ctx->untrusted != NULL
&& (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = -1;
goto err;
}
@@ -253,8 +257,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
*/
if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto err;
+ }
/*
* If successful for now free up cert so it will be picked up
* again later.
@@ -271,6 +277,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (xtmp != NULL) {
if (!sk_X509_push(ctx->chain, xtmp)) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = -1;
goto err;
}
@@ -352,14 +359,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
break;
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto err;
+ }
if (ok == 0)
break;
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = -1;
goto err;
}
@@ -386,8 +396,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
while (j-- > 1) {
xtmp2 = sk_X509_value(ctx->chain, j - 1);
ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto err;
+ }
/* Check if we found an alternate chain */
if (ok > 0) {
/*
@@ -515,6 +527,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
sk_X509_free(sktmp);
if (chain_ss != NULL)
X509_free(chain_ss);
+
+ /* Safety net, error returns must set ctx->error */
+ if (ok <= 0 && ctx->error == X509_V_OK)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
return ok;
}
@@ -697,13 +713,27 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
* the next certificate must be a CA certificate.
*/
if (x->ex_flags & EXFLAG_PROXY) {
- if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) {
- ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
- ctx->error_depth = i;
- ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ /*
+ * RFC3820, 4.1.3 (b)(1) stipulates that if pCPathLengthConstraint
+ * is less than max_path_length, the former should be copied to
+ * the latter, and 4.1.4 (a) stipulates that max_path_length
+ * should be verified to be larger than zero and decrement it.
+ *
+ * Because we're checking the certs in the reverse order, we start
+ * with verifying that proxy_path_length isn't larger than pcPLC,
+ * and copy the latter to the former if it is, and finally,
+ * increment proxy_path_length.
+ */
+ if (x->ex_pcpathlen != -1) {
+ if (proxy_path_length > x->ex_pcpathlen) {
+ ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok = cb(0, ctx);
+ if (!ok)
+ goto end;
+ }
+ proxy_path_length = x->ex_pcpathlen;
}
proxy_path_length++;
must_be_ca = 0;
@@ -726,6 +756,81 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
/* Ignore self issued certs unless last in chain */
if (i && (x->ex_flags & EXFLAG_SI))
continue;
+
+ /*
+ * Proxy certificates policy has an extra constraint, where the
+ * certificate subject MUST be the issuer with a single CN entry
+ * added.
+ * (RFC 3820: 3.4, 4.1.3 (a)(4))
+ */
+ if (x->ex_flags & EXFLAG_PROXY) {
+ X509_NAME *tmpsubject = X509_get_subject_name(x);
+ X509_NAME *tmpissuer = X509_get_issuer_name(x);
+ X509_NAME_ENTRY *tmpentry = NULL;
+ int last_object_nid = 0;
+ int err = X509_V_OK;
+ int last_object_loc = X509_NAME_entry_count(tmpsubject) - 1;
+
+ /* Check that there are at least two RDNs */
+ if (last_object_loc < 1) {
+ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
+ goto proxy_name_done;
+ }
+
+ /*
+ * Check that there is exactly one more RDN in subject as
+ * there is in issuer.
+ */
+ if (X509_NAME_entry_count(tmpsubject)
+ != X509_NAME_entry_count(tmpissuer) + 1) {
+ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
+ goto proxy_name_done;
+ }
+
+ /*
+ * Check that the last subject component isn't part of a
+ * multivalued RDN
+ */
+ if (X509_NAME_get_entry(tmpsubject, last_object_loc)->set
+ == X509_NAME_get_entry(tmpsubject, last_object_loc - 1)->set) {
+ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
+ goto proxy_name_done;
+ }
+
+ /*
+ * Check that the last subject RDN is a commonName, and that
+ * all the previous RDNs match the issuer exactly
+ */
+ tmpsubject = X509_NAME_dup(tmpsubject);
+ if (tmpsubject == NULL) {
+ X509err(X509_F_CHECK_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ return 0;
+ }
+
+ tmpentry =
+ X509_NAME_delete_entry(tmpsubject, last_object_loc);
+ last_object_nid =
+ OBJ_obj2nid(X509_NAME_ENTRY_get_object(tmpentry));
+
+ if (last_object_nid != NID_commonName
+ || X509_NAME_cmp(tmpsubject, tmpissuer) != 0) {
+ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION;
+ }
+
+ X509_NAME_ENTRY_free(tmpentry);
+ X509_NAME_free(tmpsubject);
+
+ proxy_name_done:
+ if (err != X509_V_OK) {
+ ctx->error = err;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+ }
+
/*
* Check against constraints for all certificates higher in chain
* including trust anchor. Trust anchor not strictly speaking needed
@@ -736,12 +841,19 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
if (nc) {
rv = NAME_CONSTRAINTS_check(x, nc);
- if (rv != X509_V_OK) {
+ switch (rv) {
+ case X509_V_OK:
+ continue;
+ case X509_V_ERR_OUT_OF_MEM:
+ ctx->error = rv;
+ return 0;
+ default:
ctx->error = rv;
ctx->error_depth = i;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
+ break;
}
}
}
@@ -880,6 +992,8 @@ static int check_cert(X509_STORE_CTX *ctx)
ctx->current_issuer = NULL;
ctx->current_crl_score = 0;
ctx->current_reasons = 0;
+ if (x->ex_flags & EXFLAG_PROXY)
+ return 1;
while (ctx->current_reasons != CRLDP_ALL_REASONS) {
last_reasons = ctx->current_reasons;
/* Try to retrieve relevant CRL */
@@ -1010,13 +1124,25 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
crl = sk_X509_CRL_value(crls, i);
reasons = *preasons;
crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x);
-
- if (crl_score > best_score) {
- best_crl = crl;
- best_crl_issuer = crl_issuer;
- best_score = crl_score;
- best_reasons = reasons;
+ if (crl_score < best_score || crl_score == 0)
+ continue;
+ /* If current CRL is equivalent use it if it is newer */
+ if (crl_score == best_score && best_crl != NULL) {
+ int day, sec;
+ if (ASN1_TIME_diff(&day, &sec, X509_CRL_get_lastUpdate(best_crl),
+ X509_CRL_get_lastUpdate(crl)) == 0)
+ continue;
+ /*
+ * ASN1_TIME_diff never returns inconsistent signs for |day|
+ * and |sec|.
+ */
+ if (day <= 0 && sec <= 0)
+ continue;
}
+ best_crl = crl;
+ best_crl_issuer = crl_issuer;
+ best_score = crl_score;
+ best_reasons = reasons;
}
if (best_crl) {
@@ -1630,6 +1756,7 @@ static int check_policy(X509_STORE_CTX *ctx)
ctx->param->policies, ctx->param->flags);
if (ret == 0) {
X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
return 0;
}
/* Invalid or inconsistent extensions */
@@ -1658,7 +1785,12 @@ static int check_policy(X509_STORE_CTX *ctx)
if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
ctx->current_cert = NULL;
- ctx->error = X509_V_OK;
+ /*
+ * Verification errors need to be "sticky", a callback may have allowed
+ * an SSL handshake to continue despite an error, and we must then
+ * remain in an error state. Therefore, we MUST NOT clear earlier
+ * verification errors by setting the error to X509_V_OK.
+ */
if (!ctx->verify_cb(2, ctx))
return 0;
}
diff --git a/thirdparty/openssl/crypto/x509/x509spki.c b/thirdparty/openssl/crypto/x509/x509spki.c
index 2df84ead9e..5ae5d30a35 100644
--- a/thirdparty/openssl/crypto/x509/x509spki.c
+++ b/thirdparty/openssl/crypto/x509/x509spki.c
@@ -112,6 +112,8 @@ char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki)
der_spki = OPENSSL_malloc(der_len);
b64_str = OPENSSL_malloc(der_len * 2);
if (!der_spki || !b64_str) {
+ OPENSSL_free(der_spki);
+ OPENSSL_free(b64_str);
X509err(X509_F_NETSCAPE_SPKI_B64_ENCODE, ERR_R_MALLOC_FAILURE);
return NULL;
}