Initialize potentially uninitialized local variables
[openssl.git] / crypto / x509 / x509_vfy.c
index f5da926a12567cebac2127d79c222a87a1b31e2f..4538b8b83ee1eedbc0cc7d956b1fa4be1a5bc51d 100644 (file)
@@ -145,12 +145,6 @@ static int null_callback(int ok, X509_STORE_CTX *e)
     return ok;
 }
 
-#if 0
-static int x509_subject_cmp(X509 **a, X509 **b)
-{
-    return X509_subject_name_cmp(*a, *b);
-}
-#endif
 /* Return 1 is a certificate is self signed */
 static int cert_self_signed(X509 *x)
 {
@@ -188,11 +182,11 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
 
 int X509_verify_cert(X509_STORE_CTX *ctx)
 {
-    X509 *x, *xtmp, *chain_ss = NULL;
+    X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
     int bad_chain = 0;
     X509_VERIFY_PARAM *param = ctx->param;
     int depth, i, ok = 0;
-    int num;
+    int num, j, retry;
     int (*cb) (int xok, X509_STORE_CTX *xctx);
     STACK_OF(X509) *sktmp = NULL;
     if (ctx->cert == NULL) {
@@ -277,91 +271,136 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
         break;
     }
 
+    /* Remember how many untrusted certs we have */
+    j = num;
     /*
      * at this point, chain should contain a list of untrusted certificates.
      * We now need to add at least one trusted one, if possible, otherwise we
      * complain.
      */
 
-    /*
-     * Examine last certificate in chain and see if it is self signed.
-     */
-
-    i = sk_X509_num(ctx->chain);
-    x = sk_X509_value(ctx->chain, i - 1);
-    if (cert_self_signed(x)) {
-        /* we have a self signed certificate */
-        if (sk_X509_num(ctx->chain) == 1) {
-            /*
-             * We have a single self signed certificate: see if we can find
-             * it in the store. We must have an exact match to avoid possible
-             * impersonation.
-             */
-            ok = ctx->get_issuer(&xtmp, ctx, x);
-            if ((ok <= 0) || X509_cmp(x, xtmp)) {
-                ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
-                ctx->current_cert = x;
-                ctx->error_depth = i - 1;
-                if (ok == 1)
-                    X509_free(xtmp);
-                bad_chain = 1;
-                ok = cb(0, ctx);
-                if (!ok)
-                    goto end;
+    do {
+        /*
+         * Examine last certificate in chain and see if it is self signed.
+         */
+        i = sk_X509_num(ctx->chain);
+        x = sk_X509_value(ctx->chain, i - 1);
+        if (cert_self_signed(x)) {
+            /* we have a self signed certificate */
+            if (sk_X509_num(ctx->chain) == 1) {
+                /*
+                 * We have a single self signed certificate: see if we can
+                 * find it in the store. We must have an exact match to avoid
+                 * possible impersonation.
+                 */
+                ok = ctx->get_issuer(&xtmp, ctx, x);
+                if ((ok <= 0) || X509_cmp(x, xtmp)) {
+                    ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
+                    ctx->current_cert = x;
+                    ctx->error_depth = i - 1;
+                    if (ok == 1)
+                        X509_free(xtmp);
+                    bad_chain = 1;
+                    ok = cb(0, ctx);
+                    if (!ok)
+                        goto end;
+                } else {
+                    /*
+                     * We have a match: replace certificate with store
+                     * version so we get any trust settings.
+                     */
+                    X509_free(x);
+                    x = xtmp;
+                    (void)sk_X509_set(ctx->chain, i - 1, x);
+                    ctx->last_untrusted = 0;
+                }
             } else {
                 /*
-                 * We have a match: replace certificate with store version so
-                 * we get any trust settings.
+                 * extract and save self signed certificate for later use
                  */
-                X509_free(x);
-                x = xtmp;
-                (void)sk_X509_set(ctx->chain, i - 1, x);
-                ctx->last_untrusted = 0;
+                chain_ss = sk_X509_pop(ctx->chain);
+                ctx->last_untrusted--;
+                num--;
+                j--;
+                x = sk_X509_value(ctx->chain, num - 1);
             }
-        } else {
-            /*
-             * extract and save self signed certificate for later use
-             */
-            chain_ss = sk_X509_pop(ctx->chain);
-            ctx->last_untrusted--;
-            num--;
-            x = sk_X509_value(ctx->chain, num - 1);
         }
-    }
-
-    /* We now lookup certs from the certificate store */
-    for (;;) {
-        /* If we have enough, we break */
-        if (depth < num)
-            break;
+        /* We now lookup certs from the certificate store */
+        for (;;) {
+            /* If we have enough, we break */
+            if (depth < num)
+                break;
+            /* If we are self signed, we break */
+            if (cert_self_signed(x))
+                break;
+            ok = ctx->get_issuer(&xtmp, ctx, x);
 
-        /* If we are self signed, we break */
-        if (cert_self_signed(x))
-            break;
+            if (ok < 0)
+                return ok;
+            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);
+                return 0;
+            }
+            num++;
+        }
 
-        ok = ctx->get_issuer(&xtmp, ctx, x);
+        /* we now have our chain, lets check it... */
+        i = check_trust(ctx);
 
-        if (ok < 0)
-            return ok;
-        if (ok == 0)
-            break;
+        /* If explicitly rejected error */
+        if (i == X509_TRUST_REJECTED)
+            goto end;
+        /*
+         * If it's not explicitly trusted then check if there is an alternative
+         * chain that could be used. We only do this if we haven't already
+         * checked via TRUSTED_FIRST and the user hasn't switched off alternate
+         * chain checking
+         */
+        retry = 0;
+        if (i != X509_TRUST_TRUSTED
+            && !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
+            && !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
+            while (j-- > 1) {
+                STACK_OF(X509) *chtmp = ctx->chain;
+                xtmp2 = sk_X509_value(ctx->chain, j - 1);
+                /*
+                 * Temporarily set chain to NULL so we don't discount
+                 * duplicates: the same certificate could be an untrusted
+                 * CA found in the trusted store.
+                 */
+                ctx->chain = NULL;
+                ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
+                ctx->chain = chtmp;
+                if (ok < 0)
+                    goto end;
+                /* Check if we found an alternate chain */
+                if (ok > 0) {
+                    /*
+                     * Free up the found cert we'll add it again later
+                     */
+                    X509_free(xtmp);
 
-        x = xtmp;
-        if (!sk_X509_push(ctx->chain, x)) {
-            X509_free(xtmp);
-            X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
-            return 0;
+                    /*
+                     * Dump all the certs above this point - we've found an
+                     * alternate chain
+                     */
+                    while (num > j) {
+                        xtmp = sk_X509_pop(ctx->chain);
+                        X509_free(xtmp);
+                        num--;
+                        ctx->last_untrusted--;
+                    }
+                    retry = 1;
+                    break;
+                }
+            }
         }
-        num++;
-    }
+    } while (retry);
 
-    /* we now have our chain, lets check it... */
-
-    i = check_trust(ctx);
-
-    /* If explicitly rejected error */
-    if (i == X509_TRUST_REJECTED)
-        goto end;
     /*
      * If not explicitly trusted then indicate error unless it's a single
      * self signed certificate in which case we've indicated an error already
@@ -439,7 +478,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
     if (!ok)
         goto end;
 
-#ifndef OPENSSL_NO_RFC3779
     /* RFC 3779 path validation, now that CRL check has been done */
     ok = v3_asid_validate_path(ctx);
     if (!ok)
@@ -447,21 +485,18 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
     ok = v3_addr_validate_path(ctx);
     if (!ok)
         goto end;
-#endif
 
     /* If we get this far evaluate policies */
     if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK))
         ok = ctx->check_policy(ctx);
-    if (!ok)
-        goto end;
-    if (0) {
+    if (ok)
+        goto done;
+
  end:
-        X509_get_pubkey_parameters(NULL, ctx->chain);
-    }
-    if (sktmp != NULL)
-        sk_X509_free(sktmp);
-    if (chain_ss != NULL)
-        X509_free(chain_ss);
+    X509_get_pubkey_parameters(NULL, ctx->chain);
+ done:
+    sk_X509_free(sktmp);
+    X509_free(chain_ss);
     return ok;
 }
 
@@ -538,9 +573,6 @@ static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
 
 static int check_chain_extensions(X509_STORE_CTX *ctx)
 {
-#ifdef OPENSSL_NO_CHAIN_VERIFY
-    return 1;
-#else
     int i, ok = 0, must_be_ca, plen = 0;
     X509 *x;
     int (*cb) (int xok, X509_STORE_CTX *xctx);
@@ -680,7 +712,6 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
     ok = 1;
  end:
     return ok;
-#endif
 }
 
 static int check_name_constraints(X509_STORE_CTX *ctx)
@@ -811,7 +842,7 @@ static int check_trust(X509_STORE_CTX *ctx)
 
 static int check_revocation(X509_STORE_CTX *ctx)
 {
-    int i, last, ok;
+    int i = 0, last = 0, ok = 0;
     if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK))
         return 1;
     if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL)
@@ -834,9 +865,9 @@ static int check_revocation(X509_STORE_CTX *ctx)
 static int check_cert(X509_STORE_CTX *ctx)
 {
     X509_CRL *crl = NULL, *dcrl = NULL;
-    X509 *x;
-    int ok, cnum;
-    unsigned int last_reasons;
+    X509 *x = NULL;
+    int ok = 0, cnum = 0;
+    unsigned int last_reasons = 0;
     cnum = ctx->error_depth;
     x = sk_X509_value(ctx->chain, cnum);
     ctx->current_cert = x;
@@ -983,17 +1014,14 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
     }
 
     if (best_crl) {
-        if (*pcrl)
-            X509_CRL_free(*pcrl);
+        X509_CRL_free(*pcrl);
         *pcrl = best_crl;
         *pissuer = best_crl_issuer;
         *pscore = best_score;
         *preasons = best_reasons;
         CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509_CRL);
-        if (*pdcrl) {
-            X509_CRL_free(*pdcrl);
-            *pdcrl = NULL;
-        }
+        X509_CRL_free(*pdcrl);
+        *pdcrl = NULL;
         get_delta_sk(ctx, pdcrl, pscore, best_crl, crls);
     }
 
@@ -1900,10 +1928,8 @@ int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain)
         }
         if (!EVP_PKEY_missing_parameters(ktmp))
             break;
-        else {
-            EVP_PKEY_free(ktmp);
-            ktmp = NULL;
-        }
+        EVP_PKEY_free(ktmp);
+        ktmp = NULL;
     }
     if (ktmp == NULL) {
         X509err(X509_F_X509_GET_PUBKEY_PARAMETERS,
@@ -2027,8 +2053,7 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
 
  memerr:
     X509err(X509_F_X509_CRL_DIFF, ERR_R_MALLOC_FAILURE);
-    if (crl)
-        X509_CRL_free(crl);
+    X509_CRL_free(crl);
     return NULL;
 }
 
@@ -2186,18 +2211,20 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
 
 X509_STORE_CTX *X509_STORE_CTX_new(void)
 {
-    X509_STORE_CTX *ctx;
-    ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
+    X509_STORE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
+
     if (!ctx) {
         X509err(X509_F_X509_STORE_CTX_NEW, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
-    memset(ctx, 0, sizeof(X509_STORE_CTX));
+    memset(ctx, 0, sizeof(*ctx));
     return ctx;
 }
 
 void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
 {
+    if (!ctx)
+        return;
     X509_STORE_CTX_cleanup(ctx);
     OPENSSL_free(ctx);
 }
@@ -2310,11 +2337,9 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
     ctx->check_policy = check_policy;
 
     /*
-     * This memset() can't make any sense anyway, so it's removed. As
-     * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a
-     * corresponding "new" here and remove this bogus initialisation.
+     * Since X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we
+     * put a corresponding "new" here.
      */
-    /* memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); */
     if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
                             &(ctx->ex_data))) {
         OPENSSL_free(ctx);
@@ -2344,16 +2369,12 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
             X509_VERIFY_PARAM_free(ctx->param);
         ctx->param = NULL;
     }
-    if (ctx->tree != NULL) {
-        X509_policy_tree_free(ctx->tree);
-        ctx->tree = NULL;
-    }
-    if (ctx->chain != NULL) {
-        sk_X509_pop_free(ctx->chain, X509_free);
-        ctx->chain = NULL;
-    }
+    X509_policy_tree_free(ctx->tree);
+    ctx->tree = NULL;
+    sk_X509_pop_free(ctx->chain, X509_free);
+    ctx->chain = NULL;
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, &(ctx->ex_data));
-    memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA));
+    memset(&ctx->ex_data, 0, sizeof(ctx->ex_data));
 }
 
 void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth)
@@ -2404,17 +2425,6 @@ X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx)
 
 void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param)
 {
-    if (ctx->param)
-        X509_VERIFY_PARAM_free(ctx->param);
+    X509_VERIFY_PARAM_free(ctx->param);
     ctx->param = param;
 }
-
-IMPLEMENT_STACK_OF(X509)
-
-IMPLEMENT_ASN1_SET_OF(X509)
-
-IMPLEMENT_STACK_OF(X509_NAME)
-
-IMPLEMENT_STACK_OF(X509_ATTRIBUTE)
-
-IMPLEMENT_ASN1_SET_OF(X509_ATTRIBUTE)