Fix some error-handling in i2v functions.
See upstream commits:
32f3b98d1302d4c0950dc1bf94b50269b6edbd95
432f8688bb72e21939845ac7a69359ca718c6676
7bb50cbc4af78a0c8d36fdf2c141ad1330125e2f
8c74c9d1ade0fbdab5b815ddb747351b8b839641
Change-Id: Iff614260c1b1582856edb4ae7a226f2e07537698
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/49045
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/x509v3/v3_akey.c b/crypto/x509v3/v3_akey.c
index 1037673..0aba20e 100644
--- a/crypto/x509v3/v3_akey.c
+++ b/crypto/x509v3/v3_akey.c
@@ -93,20 +93,39 @@
STACK_OF(CONF_VALUE)
*extlist)
{
- char *tmp;
+ char *tmp = NULL;
+ int extlist_was_null = extlist == NULL;
if (akeyid->keyid) {
tmp = x509v3_bytes_to_hex(akeyid->keyid->data, akeyid->keyid->length);
- X509V3_add_value("keyid", tmp, &extlist);
+ int ok = tmp != NULL && X509V3_add_value("keyid", tmp, &extlist);
OPENSSL_free(tmp);
+ if (!ok) {
+ goto err;
+ }
}
- if (akeyid->issuer)
- extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
+ if (akeyid->issuer) {
+ STACK_OF(CONF_VALUE) *tmpextlist =
+ i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
+ if (tmpextlist == NULL) {
+ goto err;
+ }
+ extlist = tmpextlist;
+ }
if (akeyid->serial) {
tmp = x509v3_bytes_to_hex(akeyid->serial->data, akeyid->serial->length);
- X509V3_add_value("serial", tmp, &extlist);
+ int ok = tmp != NULL && X509V3_add_value("serial", tmp, &extlist);
OPENSSL_free(tmp);
+ if (!ok) {
+ goto err;
+ }
}
return extlist;
+
+err:
+ if (extlist_was_null) {
+ sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free);
+ }
+ return NULL;
}
/*
diff --git a/crypto/x509v3/v3_alt.c b/crypto/x509v3/v3_alt.c
index 9ea3ed0..0c55816 100644
--- a/crypto/x509v3/v3_alt.c
+++ b/crypto/x509v3/v3_alt.c
@@ -104,11 +104,17 @@
GENERAL_NAMES *gens,
STACK_OF(CONF_VALUE) *ret)
{
- size_t i;
- GENERAL_NAME *gen;
- for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
- gen = sk_GENERAL_NAME_value(gens, i);
- ret = i2v_GENERAL_NAME(method, gen, ret);
+ int ret_was_null = ret == NULL;
+ for (size_t i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i);
+ STACK_OF(CONF_VALUE) *tmp = i2v_GENERAL_NAME(method, gen, ret);
+ if (tmp == NULL) {
+ if (ret_was_null) {
+ sk_CONF_VALUE_pop_free(ret, X509V3_conf_free);
+ }
+ return NULL;
+ }
+ ret = tmp;
}
if (!ret)
return sk_CONF_VALUE_new_null();
@@ -119,6 +125,9 @@
GENERAL_NAME *gen,
STACK_OF(CONF_VALUE) *ret)
{
+ /* Note the error-handling for this function relies on there being at most
+ * one |X509V3_add_value| call. If there were two and the second failed, we
+ * would need to sometimes free the first call's result. */
unsigned char *p;
char oline[256], htmp[5];
int i;
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index d404013..5d91aed 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -94,6 +94,7 @@
{
CONF_VALUE *vtmp = NULL;
char *tname = NULL, *tvalue = NULL;
+ int extlist_was_null = *extlist == NULL;
if (name && !(tname = OPENSSL_strdup(name)))
goto malloc_err;
if (!omit_value) {
@@ -120,12 +121,13 @@
malloc_err:
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
err:
- if (vtmp)
- OPENSSL_free(vtmp);
- if (tname)
- OPENSSL_free(tname);
- if (tvalue)
- OPENSSL_free(tvalue);
+ if (extlist_was_null) {
+ sk_CONF_VALUE_free(*extlist);
+ *extlist = NULL;
+ }
+ OPENSSL_free(vtmp);
+ OPENSSL_free(tname);
+ OPENSSL_free(tvalue);
return 0;
}
@@ -293,7 +295,7 @@
return aint;
}
-int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint,
STACK_OF(CONF_VALUE) **extlist)
{
char *strtmp;
diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h
index 5dcb894..8e4a511 100644
--- a/include/openssl/x509v3.h
+++ b/include/openssl/x509v3.h
@@ -483,12 +483,30 @@
X509V3_EXT_METHOD *method, ASN1_BIT_STRING *bits,
STACK_OF(CONF_VALUE) *extlist);
+// i2v_GENERAL_NAME serializes |gen| as a |CONF_VALUE|. If |ret| is non-NULL, it
+// appends the value to |ret| and returns |ret| on success or NULL on error. If
+// it returns NULL, the caller is still responsible for freeing |ret|. If |ret|
+// is NULL, it returns a newly-allocated |STACK_OF(CONF_VALUE)| containing the
+// result. |method| is ignored.
+//
+// Do not use this function. This is an internal implementation detail of the
+// human-readable print functions. If extracting a SAN list from a certificate,
+// look at |gen| directly.
OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(
X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret);
OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen);
DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES)
+// i2v_GENERAL_NAMES serializes |gen| as a list of |CONF_VALUE|s. If |ret| is
+// non-NULL, it appends the values to |ret| and returns |ret| on success or NULL
+// on error. If it returns NULL, the caller is still responsible for freeing
+// |ret|. If |ret| is NULL, it returns a newly-allocated |STACK_OF(CONF_VALUE)|
+// containing the results. |method| is ignored.
+//
+// Do not use this function. This is an internal implementation detail of the
+// human-readable print functions. If extracting a SAN list from a certificate,
+// look at |gen| directly.
OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(
X509V3_EXT_METHOD *method, GENERAL_NAMES *gen,
STACK_OF(CONF_VALUE) *extlist);
@@ -602,15 +620,35 @@
OPENSSL_EXPORT void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
X509_REQ *req, X509_CRL *crl, int flags);
+// X509V3_add_value appends a |CONF_VALUE| containing |name| and |value| to
+// |*extlist|. It returns one on success and zero on error. If |*extlist| is
+// NULL, it sets |*extlist| to a newly-allocated |STACK_OF(CONF_VALUE)|
+// containing the result. Either |name| or |value| may be NULL to omit the
+// field.
+//
+// On failure, if |*extlist| was NULL, |*extlist| will remain NULL when the
+// function returns.
OPENSSL_EXPORT int X509V3_add_value(const char *name, const char *value,
STACK_OF(CONF_VALUE) **extlist);
+
+// X509V3_add_value_uchar behaves like |X509V3_add_value| but takes an
+// |unsigned char| pointer.
OPENSSL_EXPORT int X509V3_add_value_uchar(const char *name,
const unsigned char *value,
STACK_OF(CONF_VALUE) **extlist);
+
+// X509V3_add_value_bool behaves like |X509V3_add_value| but stores the value
+// "TRUE" if |asn1_bool| is non-zero and "FALSE" otherwise.
OPENSSL_EXPORT int X509V3_add_value_bool(const char *name, int asn1_bool,
STACK_OF(CONF_VALUE) **extlist);
-OPENSSL_EXPORT int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+
+// X509V3_add_value_bool behaves like |X509V3_add_value| but stores a string
+// representation of |aint|. Note this string representation may be decimal or
+// hexadecimal, depending on the size of |aint|.
+OPENSSL_EXPORT int X509V3_add_value_int(const char *name,
+ const ASN1_INTEGER *aint,
STACK_OF(CONF_VALUE) **extlist);
+
OPENSSL_EXPORT char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth,
const ASN1_INTEGER *aint);
OPENSSL_EXPORT ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth,