Blob Blame History Raw
diff -up openssl-1.0.2a/apps/apps.c.alt-chains openssl-1.0.2a/apps/apps.c
--- openssl-1.0.2a/apps/apps.c.alt-chains	2015-03-19 14:30:36.000000000 +0100
+++ openssl-1.0.2a/apps/apps.c	2015-04-28 16:49:50.124558770 +0200
@@ -2371,6 +2371,8 @@ int args_verify(char ***pargs, int *parg
         flags |= X509_V_FLAG_SUITEB_192_LOS;
     else if (!strcmp(arg, "-partial_chain"))
         flags |= X509_V_FLAG_PARTIAL_CHAIN;
+    else if (!strcmp(arg, "-no_alt_chains"))
+        flags |= X509_V_FLAG_NO_ALT_CHAINS;
     else
         return 0;
 
diff -up openssl-1.0.2a/apps/cms.c.alt-chains openssl-1.0.2a/apps/cms.c
--- openssl-1.0.2a/apps/cms.c.alt-chains	2015-04-23 10:22:56.225685251 +0200
+++ openssl-1.0.2a/apps/cms.c	2015-04-28 16:49:50.125558793 +0200
@@ -648,6 +648,8 @@ int MAIN(int argc, char **argv)
         BIO_printf(bio_err,
                    "-trusted_first use trusted certificates first when building the trust chain\n");
         BIO_printf(bio_err,
+                   "-no_alt_chains only ever use the first certificate chain found\n");
+        BIO_printf(bio_err,
                    "-crl_check     check revocation status of signer's certificate using CRLs\n");
         BIO_printf(bio_err,
                    "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
diff -up openssl-1.0.2a/apps/ocsp.c.alt-chains openssl-1.0.2a/apps/ocsp.c
--- openssl-1.0.2a/apps/ocsp.c.alt-chains	2015-04-23 10:22:56.225685251 +0200
+++ openssl-1.0.2a/apps/ocsp.c	2015-04-28 16:49:50.125558793 +0200
@@ -538,6 +538,8 @@ int MAIN(int argc, char **argv)
         BIO_printf(bio_err,
                    "-trusted_first       use trusted certificates first when building the trust chain\n");
         BIO_printf(bio_err,
+                   "-no_alt_chains       only ever use the first certificate chain found\n");
+        BIO_printf(bio_err,
                    "-VAfile file         validator certificates file\n");
         BIO_printf(bio_err,
                    "-validity_period n   maximum validity discrepancy in seconds\n");
diff -up openssl-1.0.2a/apps/s_client.c.alt-chains openssl-1.0.2a/apps/s_client.c
--- openssl-1.0.2a/apps/s_client.c.alt-chains	2015-04-23 10:22:56.225685251 +0200
+++ openssl-1.0.2a/apps/s_client.c	2015-04-28 16:49:50.126558815 +0200
@@ -335,6 +335,8 @@ static void sc_usage(void)
     BIO_printf(bio_err,
                " -trusted_first - Use trusted CA's first when building the trust chain\n");
     BIO_printf(bio_err,
+               " -no_alt_chains - only ever use the first certificate chain found\n");
+    BIO_printf(bio_err,
                " -reconnect    - Drop and re-make the connection with the same Session-ID\n");
     BIO_printf(bio_err,
                " -pause        - sleep(1) after each read(2) and write(2) system call\n");
diff -up openssl-1.0.2a/apps/smime.c.alt-chains openssl-1.0.2a/apps/smime.c
--- openssl-1.0.2a/apps/smime.c.alt-chains	2015-04-23 10:22:56.226685277 +0200
+++ openssl-1.0.2a/apps/smime.c	2015-04-28 16:49:50.128558861 +0200
@@ -444,6 +444,8 @@ int MAIN(int argc, char **argv)
         BIO_printf(bio_err,
                    "-trusted_first use trusted certificates first when building the trust chain\n");
         BIO_printf(bio_err,
+                   "-no_alt_chains only ever use the first certificate chain found\n");
+        BIO_printf(bio_err,
                    "-crl_check     check revocation status of signer's certificate using CRLs\n");
         BIO_printf(bio_err,
                    "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
diff -up openssl-1.0.2a/apps/s_server.c.alt-chains openssl-1.0.2a/apps/s_server.c
--- openssl-1.0.2a/apps/s_server.c.alt-chains	2015-04-23 10:22:56.226685277 +0200
+++ openssl-1.0.2a/apps/s_server.c	2015-04-28 16:49:50.128558861 +0200
@@ -571,6 +571,8 @@ static void sv_usage(void)
     BIO_printf(bio_err,
                " -trusted_first - Use trusted CA's first when building the trust chain\n");
     BIO_printf(bio_err,
+               " -no_alt_chains - only ever use the first certificate chain found\n");
+    BIO_printf(bio_err,
                " -nocert       - Don't use any certificates (Anon-DH)\n");
     BIO_printf(bio_err,
                " -cipher arg   - play with 'openssl ciphers' to see what goes here\n");
diff -up openssl-1.0.2a/apps/verify.c.alt-chains openssl-1.0.2a/apps/verify.c
--- openssl-1.0.2a/apps/verify.c.alt-chains	2015-04-28 16:49:50.128558861 +0200
+++ openssl-1.0.2a/apps/verify.c	2015-04-28 16:50:52.210974346 +0200
@@ -232,7 +232,7 @@ int MAIN(int argc, char **argv)
     if (ret == 1) {
         BIO_printf(bio_err,
                    "usage: verify [-verbose] [-CApath path] [-CAfile file] [-trusted_first] [-purpose purpose] [-crl_check]");
-        BIO_printf(bio_err, " [-attime timestamp]");
+        BIO_printf(bio_err, " [-no_alt_chains] [-attime timestamp]");
 #ifndef OPENSSL_NO_ENGINE
         BIO_printf(bio_err, " [-engine e]");
 #endif
diff -up openssl-1.0.2a/crypto/x509/x509_vfy.c.alt-chains openssl-1.0.2a/crypto/x509/x509_vfy.c
--- openssl-1.0.2a/crypto/x509/x509_vfy.c.alt-chains	2015-04-23 10:22:56.188684277 +0200
+++ openssl-1.0.2a/crypto/x509/x509_vfy.c	2015-04-28 17:03:40.478786778 +0200
@@ -189,11 +189,11 @@ static X509 *lookup_cert_match(X509_STOR
 
 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) {
@@ -278,91 +278,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
diff -up openssl-1.0.2a/crypto/x509/x509_vfy.h.alt-chains openssl-1.0.2a/crypto/x509/x509_vfy.h
--- openssl-1.0.2a/crypto/x509/x509_vfy.h.alt-chains	2015-04-23 10:22:56.016679751 +0200
+++ openssl-1.0.2a/crypto/x509/x509_vfy.h	2015-04-28 16:49:18.551838908 +0200
@@ -432,6 +432,12 @@ void X509_STORE_CTX_set_depth(X509_STORE
 
 /* Allow partial chains if at least one certificate is in trusted store */
 # define X509_V_FLAG_PARTIAL_CHAIN               0x80000
+/*
+ * If the initial chain is not trusted, do not attempt to build an alternative
+ * chain. Alternate chain checking was introduced in 1.0.2b. Setting this flag
+ * will force the behaviour to match that of previous versions.
+ */
+# define X509_V_FLAG_NO_ALT_CHAINS               0x100000
 
 # define X509_VP_FLAG_DEFAULT                    0x1
 # define X509_VP_FLAG_OVERWRITE                  0x2
diff -up openssl-1.0.2a/doc/apps/cms.pod.alt-chains openssl-1.0.2a/doc/apps/cms.pod
--- openssl-1.0.2a/doc/apps/cms.pod.alt-chains	2015-04-23 10:22:56.227685303 +0200
+++ openssl-1.0.2a/doc/apps/cms.pod	2015-04-28 16:54:17.537682406 +0200
@@ -36,6 +36,7 @@ B<openssl> B<cms>
 [B<-CAfile file>]
 [B<-CApath dir>]
 [B<-trusted_first>]
+[B<-no_alt_chains>]
 [B<-md digest>]
 [B<-[cipher]>]
 [B<-nointern>]
@@ -426,7 +427,7 @@ portion of a message so they may be incl
 then many S/MIME mail clients check the signers certificate's email
 address matches that specified in the From: address.
 
-=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig>
+=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig -no_alt_chains>
 
 Set various certificate chain valiadition option. See the
 L<B<verify>|verify(1)> manual page for details.
@@ -662,4 +663,6 @@ Support for RSA-OAEP and RSA-PSS was fir
 The use of non-RSA keys with B<-encrypt> and B<-decrypt> was first added
 to OpenSSL 1.1.0.
 
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
+
 =cut
diff -up openssl-1.0.2a/doc/apps/ocsp.pod.alt-chains openssl-1.0.2a/doc/apps/ocsp.pod
--- openssl-1.0.2a/doc/apps/ocsp.pod.alt-chains	2015-04-23 10:22:56.227685303 +0200
+++ openssl-1.0.2a/doc/apps/ocsp.pod	2015-04-28 16:53:44.564914852 +0200
@@ -30,6 +30,7 @@ B<openssl> B<ocsp>
 [B<-CApath dir>]
 [B<-CAfile file>]
 [B<-trusted_first>]
+[B<-no_alt_chains>]
 [B<-VAfile file>]
 [B<-validity_period n>]
 [B<-status_age n>]
@@ -151,6 +152,10 @@ in the response or residing in other cer
 chain to verify responder certificate.
 This is mainly useful in environments with Bridge CA or Cross-Certified CAs.
 
+=item B<-no_alt_chains>
+
+See L<B<verify>|verify(1)> manual page for details.
+
 =item B<-verify_other file>
 
 file containing additional certificates to search when attempting to locate
@@ -388,3 +393,9 @@ second file.
 
  openssl ocsp -index demoCA/index.txt -rsigner rcert.pem -CA demoCA/cacert.pem
      -reqin req.der -respout resp.der
+
+=head1 HISTORY
+
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
+
+=cut
diff -up openssl-1.0.2a/doc/apps/s_client.pod.alt-chains openssl-1.0.2a/doc/apps/s_client.pod
--- openssl-1.0.2a/doc/apps/s_client.pod.alt-chains	2015-04-23 10:22:56.227685303 +0200
+++ openssl-1.0.2a/doc/apps/s_client.pod	2015-04-28 16:55:24.812248450 +0200
@@ -20,6 +20,7 @@ B<openssl> B<s_client>
 [B<-CApath directory>]
 [B<-CAfile filename>]
 [B<-trusted_first>]
+[B<-no_alt_chains>]
 [B<-reconnect>]
 [B<-pause>]
 [B<-showcerts>]
@@ -124,7 +125,7 @@ also used when building the client certi
 A file containing trusted certificates to use during server authentication
 and to use when attempting to build the client certificate chain.
 
-=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig, -trusted_first>
+=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig, -trusted_first -no_alt_chains>
 
 Set various certificate chain valiadition option. See the
 L<B<verify>|verify(1)> manual page for details.
@@ -365,4 +366,8 @@ information whenever a session is renego
 
 L<sess_id(1)|sess_id(1)>, L<s_server(1)|s_server(1)>, L<ciphers(1)|ciphers(1)>
 
+=head1 HISTORY
+
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
+
 =cut
diff -up openssl-1.0.2a/doc/apps/smime.pod.alt-chains openssl-1.0.2a/doc/apps/smime.pod
--- openssl-1.0.2a/doc/apps/smime.pod.alt-chains	2015-04-23 10:22:56.227685303 +0200
+++ openssl-1.0.2a/doc/apps/smime.pod	2015-04-28 16:57:33.598246384 +0200
@@ -18,6 +18,7 @@ B<openssl> B<smime>
 [B<-CAfile file>]
 [B<-CApath dir>]
 [B<-trusted_first>]
+[B<-no_alt_chains>]
 [B<-certfile file>]
 [B<-signer file>]
 [B<-recip  file>]
@@ -268,7 +269,7 @@ portion of a message so they may be incl
 then many S/MIME mail clients check the signers certificate's email
 address matches that specified in the From: address.
 
-=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig>
+=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig -no_alt_chains>
 
 Set various options of certificate chain verification. See
 L<B<verify>|verify(1)> manual page for details.
@@ -450,5 +451,6 @@ structures may cause parsing errors.
 The use of multiple B<-signer> options and the B<-resign> command were first
 added in OpenSSL 1.0.0
 
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
 
 =cut
diff -up openssl-1.0.2a/doc/apps/s_server.pod.alt-chains openssl-1.0.2a/doc/apps/s_server.pod
--- openssl-1.0.2a/doc/apps/s_server.pod.alt-chains	2015-04-23 10:22:56.227685303 +0200
+++ openssl-1.0.2a/doc/apps/s_server.pod	2015-04-28 16:56:27.494707598 +0200
@@ -34,6 +34,7 @@ B<openssl> B<s_server>
 [B<-CApath directory>]
 [B<-CAfile filename>]
 [B<-trusted_first>]
+[B<-no_alt_chains>]
 [B<-nocert>]
 [B<-cipher cipherlist>]
 [B<-serverpref>]
@@ -181,6 +182,10 @@ Use certificates in CA file or CA direct
 when building the trust chain to verify client certificates.
 This is mainly useful in environments with Bridge CA or Cross-Certified CAs.
 
+=item B<-no_alt_chains>
+
+See the L<B<verify>|verify(1)> manual page for details.
+
 =item B<-state>
 
 prints out the SSL session states.
@@ -413,4 +418,8 @@ unknown cipher suites a client says it s
 
 L<sess_id(1)|sess_id(1)>, L<s_client(1)|s_client(1)>, L<ciphers(1)|ciphers(1)>
 
+=head1 HISTORY
+
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
+
 =cut
diff -up openssl-1.0.2a/doc/apps/verify.pod.alt-chains openssl-1.0.2a/doc/apps/verify.pod
--- openssl-1.0.2a/doc/apps/verify.pod.alt-chains	2015-04-23 10:22:56.228685330 +0200
+++ openssl-1.0.2a/doc/apps/verify.pod	2015-04-28 16:52:22.544033948 +0200
@@ -26,6 +26,7 @@ B<openssl> B<verify>
 [B<-extended_crl>]
 [B<-use_deltas>]
 [B<-policy_print>]
+[B<-no_alt_chains>]
 [B<-untrusted file>]
 [B<-help>]
 [B<-issuer_checks>]
@@ -131,6 +132,14 @@ Set policy variable inhibit-any-policy (
 
 Set policy variable inhibit-policy-mapping (see RFC5280).
 
+=item B<-no_alt_chains>
+
+When building a certificate chain, if the first certificate chain found is not
+trusted, then OpenSSL will continue to check to see if an alternative chain can
+be found that is trusted. With this option that behaviour is suppressed so that
+only the first chain found is ever used. Using this option will force the
+behaviour to match that of previous OpenSSL versions.
+
 =item B<-policy_print>
 
 Print out diagnostics related to policy processing.
@@ -432,4 +441,8 @@ B<20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CER
 
 L<x509(1)|x509(1)>
 
+=head1 HISTORY
+
+The -no_alt_chains options was first added to OpenSSL 1.0.2b.
+
 =cut
diff -up openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod
--- openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains	2015-03-19 14:30:36.000000000 +0100
+++ openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod	2015-04-28 16:52:22.544033948 +0200
@@ -197,6 +197,12 @@ verification. If this flag is set then a
 to the verification callback and it B<must> be prepared to handle such cases
 without assuming they are hard errors.
 
+The B<X509_V_FLAG_NO_ALT_CHAINS> flag suppresses checking for alternative
+chains. By default, when building a certificate chain, if the first certificate
+chain found is not trusted, then OpenSSL will continue to check to see if an
+alternative chain can be found that is trusted. With this flag set the behaviour
+will match that of OpenSSL versions prior to 1.0.2b.
+
 =head1 NOTES
 
 The above functions should be used to manipulate verification parameters
@@ -233,6 +239,6 @@ L<X509_check_ip(3)|X509_check_ip(3)>
 
 =head1 HISTORY
 
-TBA
+The B<X509_V_FLAG_NO_ALT_CHAINS> flag was added in OpenSSL 1.0.2b
 
 =cut