Fix proxy certificate pathlength verification
authorRichard Levitte <levitte@openssl.org>
Sun, 19 Jun 2016 08:55:29 +0000 (10:55 +0200)
committerRichard Levitte <levitte@openssl.org>
Wed, 29 Jun 2016 23:00:26 +0000 (01:00 +0200)
While travelling up the certificate chain, the internal
proxy_path_length must be updated with the pCPathLengthConstraint
value, or verification will not work properly.  This corresponds to
RFC 3820, 4.1.4 (a).

Reviewed-by: Rich Salz <rsalz@openssl.org>
(cherry picked from commit 30aeb3128199c15760a785d88a4eda9e156d5af6)

crypto/x509/x509_vfy.c

index fdbbe8c5879d22ca71897e7f7791d8586dced0b1..f0fa7f4f07b43067bf9a6ce2ed631ff9d94f7a4a 100644 (file)
@@ -633,13 +633,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;