Allow NULL arg to OPENSSL_sk_{dup,deep_copy} returning empty stack
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Wed, 23 Dec 2020 18:33:03 +0000 (19:33 +0100)
committerDr. David von Oheimb <dev@ddvo.net>
Thu, 4 Feb 2021 06:28:11 +0000 (07:28 +0100)
This simplifies many usages

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14040)

crypto/cmp/cmp_ctx.c
crypto/ocsp/ocsp_vfy.c
crypto/stack/stack.c
crypto/ts/ts_rsp_sign.c
crypto/x509/x509_cmp.c
crypto/x509/x509_vfy.c
doc/man3/DEFINE_STACK_OF.pod
doc/man3/X509_new.pod
test/stack_test.c

index e1b4e50ea9dca135efcac571275547e1ccbc688a..ccca282721ee32e71f438becd8c5c2af14c84489 100644 (file)
@@ -462,8 +462,6 @@ STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx)
         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
         return NULL;
     }
-    if (ctx->newChain == NULL)
-        return sk_X509_new_null();
     return X509_chain_up_ref(ctx->newChain);
 }
 
@@ -477,10 +475,9 @@ int ossl_cmp_ctx_set1_newChain(OSSL_CMP_CTX *ctx, STACK_OF(X509) *newChain)
         return 0;
 
     sk_X509_pop_free(ctx->newChain, X509_free);
-    ctx->newChain= NULL;
-    if (newChain == NULL)
-        return 1;
-    return (ctx->newChain = X509_chain_up_ref(newChain)) != NULL;
+    ctx->newChain = NULL;
+    return newChain == NULL ||
+        (ctx->newChain = X509_chain_up_ref(newChain)) != NULL;
 }
 
 /* Returns the stack of extraCerts received in CertRepMessage, NULL on error */
@@ -490,8 +487,6 @@ STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx)
         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
         return NULL;
     }
-    if (ctx->extraCertsIn == NULL)
-        return sk_X509_new_null();
     return X509_chain_up_ref(ctx->extraCertsIn);
 }
 
@@ -507,9 +502,8 @@ int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx,
 
     sk_X509_pop_free(ctx->extraCertsIn, X509_free);
     ctx->extraCertsIn = NULL;
-    if (extraCertsIn == NULL)
-        return 1;
-    return (ctx->extraCertsIn = X509_chain_up_ref(extraCertsIn)) != NULL;
+    return extraCertsIn == NULL
+        || (ctx->extraCertsIn = X509_chain_up_ref(extraCertsIn)) != NULL;
 }
 
 /*
@@ -526,9 +520,8 @@ int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
 
     sk_X509_pop_free(ctx->extraCertsOut, X509_free);
     ctx->extraCertsOut = NULL;
-    if (extraCertsOut == NULL)
-        return 1;
-    return (ctx->extraCertsOut = X509_chain_up_ref(extraCertsOut)) != NULL;
+    return extraCertsOut == NULL
+        || (ctx->extraCertsOut = X509_chain_up_ref(extraCertsOut)) != NULL;
 }
 
 /*
@@ -580,8 +573,6 @@ STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx)
         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
         return NULL;
     }
-    if (ctx->caPubs == NULL)
-        return sk_X509_new_null();
     return X509_chain_up_ref(ctx->caPubs);
 }
 
@@ -596,9 +587,7 @@ int ossl_cmp_ctx_set1_caPubs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *caPubs)
 
     sk_X509_pop_free(ctx->caPubs, X509_free);
     ctx->caPubs = NULL;
-    if (caPubs == NULL)
-        return 1;
-    return (ctx->caPubs = X509_chain_up_ref(caPubs)) != NULL;
+    return caPubs == NULL || (ctx->caPubs = X509_chain_up_ref(caPubs)) != NULL;
 }
 
 #define char_dup OPENSSL_strdup
index f49f651007ec0df7e082d81c120710e02860e463..56b926164016b858ab9a1c80475f57c7a247fd87 100644 (file)
@@ -113,10 +113,9 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
         goto end;
     if ((flags & OCSP_NOVERIFY) == 0) {
         ret = -1;
-        if ((flags & OCSP_NOCHAIN) != 0) {
-            untrusted = NULL;
-        } else if (bs->certs != NULL && certs != NULL) {
-            untrusted = sk_X509_dup(bs->certs);
+        if ((flags & OCSP_NOCHAIN) == 0) {
+            if ((untrusted = sk_X509_dup(bs->certs)) == NULL)
+                goto end;
             if (!X509_add_certs(untrusted, certs, X509_ADD_FLAG_DEFAULT))
                 goto end;
         } else if (certs != NULL) {
@@ -159,8 +158,7 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
 
  end:
     sk_X509_pop_free(chain, X509_free);
-    if (bs->certs && certs)
-        sk_X509_free(untrusted);
+    sk_X509_free(untrusted);
     return ret;
 }
 
index e38efad022757aa9b14ec4a606ea2dfdf2be7e94..c50a55da141b0d74c65df77ebb7974d378eb747a 100644 (file)
@@ -45,26 +45,33 @@ OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
 {
     OPENSSL_STACK *ret;
 
-    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
-        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
+    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
+        goto err;
 
-    /* direct structure assignment */
-    *ret = *sk;
+    if (sk == NULL) {
+        ret->num = 0;
+        ret->sorted = 0;
+        ret->comp = NULL;
+    } else {
+        /* direct structure assignment */
+        *ret = *sk;
+    }
 
-    if (sk->num == 0) {
+    if (sk == NULL || sk->num == 0) {
         /* postpone |ret->data| allocation */
         ret->data = NULL;
         ret->num_alloc = 0;
         return ret;
     }
+
     /* duplicate |sk->data| content */
     if ((ret->data = OPENSSL_malloc(sizeof(*ret->data) * sk->num_alloc)) == NULL)
         goto err;
     memcpy(ret->data, sk->data, sizeof(void *) * sk->num);
     return ret;
+
  err:
+    ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
     OPENSSL_sk_free(ret);
     return NULL;
 }
@@ -76,15 +83,19 @@ OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
     OPENSSL_STACK *ret;
     int i;
 
-    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
-        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
+    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
+        goto err;
 
-    /* direct structure assignment */
-    *ret = *sk;
+    if (sk == NULL) {
+        ret->num = 0;
+        ret->sorted = 0;
+        ret->comp = NULL;
+    } else {
+        /* direct structure assignment */
+        *ret = *sk;
+    }
 
-    if (sk->num == 0) {
+    if (sk == NULL || sk->num == 0) {
         /* postpone |ret| data allocation */
         ret->data = NULL;
         ret->num_alloc = 0;
@@ -93,10 +104,8 @@ OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
 
     ret->num_alloc = sk->num > min_nodes ? sk->num : min_nodes;
     ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc);
-    if (ret->data == NULL) {
-        OPENSSL_free(ret);
-        return NULL;
-    }
+    if (ret->data == NULL)
+        goto err;
 
     for (i = 0; i < ret->num; ++i) {
         if (sk->data[i] == NULL)
@@ -105,11 +114,15 @@ OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
             while (--i >= 0)
                 if (ret->data[i] != NULL)
                     free_func((void *)ret->data[i]);
-            OPENSSL_sk_free(ret);
-            return NULL;
+            goto err;
         }
     }
     return ret;
+
+ err:
+    ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+    OPENSSL_sk_free(ret);
+    return NULL;
 }
 
 OPENSSL_STACK *OPENSSL_sk_new_null(void)
index 9ae584ff123f205148328f28ad91e11a2e53baf8..17024ea7bb380f7f3d0b4994b7beaaacf81575b9 100644 (file)
@@ -183,17 +183,10 @@ int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *def_policy)
 
 int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs)
 {
-
     sk_X509_pop_free(ctx->certs, X509_free);
     ctx->certs = NULL;
-    if (!certs)
-        return 1;
-    if ((ctx->certs = X509_chain_up_ref(certs)) == NULL) {
-        ERR_raise(ERR_LIB_TS, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
 
-    return 1;
+    return certs == NULL || (ctx->certs = X509_chain_up_ref(certs)) != NULL;
 }
 
 int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *policy)
index 1192527125d0549a81c3e608ccea0864f5e66e9e..8e525a38152858851a73cd9b0615e4d4dd38b08e 100644 (file)
@@ -531,6 +531,7 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
 }
 
 #endif
+
 /*
  * Not strictly speaking an "up_ref" as a STACK doesn't have a reference
  * count but it has the same effect by duping the STACK and upping the ref of
@@ -538,17 +539,19 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
  */
 STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain)
 {
-    STACK_OF(X509) *ret;
+    STACK_OF(X509) *ret = sk_X509_dup(chain);
     int i;
-    ret = sk_X509_dup(chain);
+
     if (ret == NULL)
         return NULL;
     for (i = 0; i < sk_X509_num(ret); i++) {
         X509 *x = sk_X509_value(ret, i);
+
         if (!X509_up_ref(x))
             goto err;
     }
     return ret;
+
  err:
     while (i-- > 0)
         X509_free(sk_X509_value(ret, i));
index 29ccc0ecb14b9fcb9fbe7bf1ded65e7beb5d9fc0..8e78c13b8e6ca0816d064d2f6138915bd7430fd7 100644 (file)
@@ -3004,7 +3004,7 @@ static int build_chain(X509_STORE_CTX *ctx)
      * typically the content of the peer's certificate message) so can make
      * multiple passes over it, while free to remove elements as we go.
      */
-    if (ctx->untrusted && (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
+    if ((sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
         ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
         ctx->error = X509_V_ERR_OUT_OF_MEM;
         return 0;
index 9088dc040b3fc3404c6d423d59548e29cdfea01d..b5908fead5efcc0994ca1716c1838709975aec4c 100644 (file)
@@ -182,12 +182,14 @@ B<sk_I<TYPE>_sort>() sorts I<sk> using the supplied comparison function.
 
 B<sk_I<TYPE>_is_sorted>() returns B<1> if I<sk> is sorted and B<0> otherwise.
 
-B<sk_I<TYPE>_dup>() returns a copy of I<sk>. Note the pointers in the copy
-are identical to the original.
+B<sk_I<TYPE>_dup>() returns a shallow copy of I<sk>
+or an empty stack if the passed stack is NULL.
+Note the pointers in the copy are identical to the original.
 
 B<sk_I<TYPE>_deep_copy>() returns a new stack where each element has been
-copied. Copying is performed by the supplied copyfunc() and freeing by
-freefunc(). The function freefunc() is only called if an error occurs.
+copied or an empty stack if the passed stack is NULL.
+Copying is performed by the supplied copyfunc() and freeing by freefunc().
+The function freefunc() is only called if an error occurs.
 
 =head1 NOTES
 
@@ -258,7 +260,7 @@ B<sk_I<TYPE>_is_sorted>() returns B<1> if the stack is sorted and B<0> if it is
 not.
 
 B<sk_I<TYPE>_dup>() and B<sk_I<TYPE>_deep_copy>() return a pointer to the copy
-of the stack.
+of the stack or NULL on error.
 
 =head1 HISTORY
 
index b40715bddfcd120bd4be7d4a551dd11b69b8d448..ab310bff577855c588ecb1b8e8f0a00c947a0b98 100644 (file)
@@ -2,9 +2,9 @@
 
 =head1 NAME
 
-X509_chain_up_ref,
 X509_new, X509_new_ex,
-X509_free, X509_up_ref - X509 certificate ASN1 allocation functions
+X509_free, X509_up_ref,
+X509_chain_up_ref - X509 certificate ASN1 allocation functions
 
 =head1 SYNOPSIS
 
@@ -37,7 +37,7 @@ frees it up if the reference count is zero. If B<a> is NULL nothing is done.
 X509_up_ref() increments the reference count of B<a>.
 
 X509_chain_up_ref() increases the reference count of all certificates in
-chain B<x> and returns a copy of the stack.
+chain B<x> and returns a copy of the stack, or an empty stack if B<a> is NULL.
 
 =head1 NOTES
 
@@ -46,20 +46,19 @@ used by several different operations each of which will free it up after
 use: this avoids the need to duplicate the entire certificate structure.
 
 The function X509_chain_up_ref() doesn't just up the reference count of
-each certificate it also returns a copy of the stack, using sk_X509_dup(),
+each certificate. It also returns a copy of the stack, using sk_X509_dup(),
 but it serves a similar purpose: the returned chain persists after the
 original has been freed.
 
 =head1 RETURN VALUES
 
-If the allocation fails, X509_new() returns B<NULL> and sets an error
+If the allocation fails, X509_new() returns NULL and sets an error
 code that can be obtained by L<ERR_get_error(3)>.
 Otherwise it returns a pointer to the newly allocated structure.
 
 X509_up_ref() returns 1 for success and 0 for failure.
 
-X509_chain_up_ref() returns a copy of the stack or B<NULL> if an error
-occurred.
+X509_chain_up_ref() returns a copy of the stack or NULL if an error occurred.
 
 =head1 SEE ALSO
 
index 0c1648da770fb76d1fb1da70874b80f1b2bc0d70..e59acd353b9bd9d1bd7c84c8e9cf0b85f6e65e8e 100644 (file)
@@ -195,6 +195,10 @@ static int test_uchar_stack(int reserve)
         goto end;
 
     /* dup */
+    r = sk_uchar_dup(NULL);
+    if (sk_uchar_num(r) != 0)
+        goto end;
+    sk_uchar_free(r);
     r = sk_uchar_dup(s);
     if (!TEST_int_eq(sk_uchar_num(r), n))
         goto end;
@@ -291,6 +295,10 @@ static int test_SS_stack(void)
         goto end;
 
     /* deepcopy */
+    r = sk_SS_deep_copy(NULL, &SS_copy, &SS_free);
+    if (sk_SS_num(r) != 0)
+        goto end;
+    sk_SS_free(r);
     r = sk_SS_deep_copy(s, &SS_copy, &SS_free);
     if (!TEST_ptr(r))
         goto end;