diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2020-07-14 18:27:29 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2020-07-14 18:27:29 +0000 |
commit | d6d1b9677130e7050d98626266a707ec00843340 (patch) | |
tree | d4051cc528e0f4f3c459aa4185bf049a553598ec /regress | |
parent | a847b703f2e49b63b3d32cf614b5f4bfa9ed76de (diff) |
Provide tools to build certificate changes for verify regress.
This provides a script that generates a variety of certificate chains
and assembles them into bundles containing various permutations, which
can be used to test our X.509 verification.
A Go program is included to verify each of these bundles.
ok beck@ tb@
Diffstat (limited to 'regress')
-rw-r--r-- | regress/lib/libcrypto/certs/Makefile | 21 | ||||
-rw-r--r-- | regress/lib/libcrypto/certs/README | 123 | ||||
-rw-r--r-- | regress/lib/libcrypto/certs/make-certs.sh | 381 | ||||
-rw-r--r-- | regress/lib/libcrypto/certs/verify_test.go | 111 |
4 files changed, 636 insertions, 0 deletions
diff --git a/regress/lib/libcrypto/certs/Makefile b/regress/lib/libcrypto/certs/Makefile new file mode 100644 index 00000000000..621c60907fb --- /dev/null +++ b/regress/lib/libcrypto/certs/Makefile @@ -0,0 +1,21 @@ +# $OpenBSD: Makefile,v 1.1 2020/07/14 18:27:28 jsing Exp $ + +.if ! (make(clean) || make(cleandir) || make(obj)) +GO_VERSION != sh -c "(go version) 2>/dev/null || true" +.endif + +.if empty(GO_VERSION) +regress: + @echo package go is required for this regress + @echo SKIPPED +.endif + +REGRESS_TARGETS=regress-go-verify + +certs: + cd ${.CURDIR} && sh ./make-certs.sh + +regress-go-verify: + cd ${.CURDIR} && go test -test.v . + +.include <bsd.regress.mk> diff --git a/regress/lib/libcrypto/certs/README b/regress/lib/libcrypto/certs/README new file mode 100644 index 00000000000..0d6fa7d48a2 --- /dev/null +++ b/regress/lib/libcrypto/certs/README @@ -0,0 +1,123 @@ +This directory contains tools for building certificate chains to +test verification. Each subdirectory contains a set of certificates +that test a particular scenario. The root certificate(s) are contained +in a roots.pem file, while the leaf certificate and any untrusted +intermediate certificates are contained in a bundle.pem file. + + 1a. A leaf certificate signed by the root certificate with no + intermediates (should verify). + + 2a. A leaf certificate signed by an intermediate, which is signed + by a root certificate (should verify). + + 2b. Same as (2a), however the intermediate is missing which should + prevent verification. + + 3a. A leaf certificate signed by three intermediates, the last of + which is signed by a root certificate (should verify). + + 3b. Same as (3a) however the first intermediate is missing which should + prevent verification. + + 3c. Same as (3a) however the second intermediate is missing which should + prevent verification. + + 3d. Same as (3a) however the third intermediate is missing which should + prevent verification. + + 3e. Same as (3a) however the order of the intermediates is reversed + (should verify). + + 4a. A leaf certificate signed by an intermediate, that is cross + signed by two root certificates (should verify with two chains). + + 4b. Same as (4a) but with one root missing (should verify with one chain). + + 4c. Same as (4b) but with the other root missing (should verify with one + chain). + + 4d. Same as (4a) but with one intermediate missing (should verify with one + chain). + + 4e. Same as (4d) but with the other intermediate missing (should verify + with one chain). + + 4f. Same as (4a) but with the intermediates reversed (should verify with + two chains). + + 4g. Same as (4b) but with the intermediates reversed (should verify with + one chain). + + 4h. Same as (4c) but with the intermediates reversed (should verify with + one chain). + + 5a. A leaf certificate signed by an intermediate, that is cross + signed by one root certificate and an intermediate, which in turn + is signed by a second root (should verify with two chains). + + 5b. Same as (5a) but missing the first root certificate (should verify + with one chain). + + 5c. Same as (5a) but missing the second root certificate (should verify + with one chain). + + 5d. Same as (5a) but missing the first intermediate (should verify with + one chain). + + 5e. Same as (5a) but missing the second intermediate (should verify + with one chain). + + 5f. Same as (5a) but missing the cross-signed intermediate (should verify + with one chain). + + 5g. Same as (5a) but order of intermediates is reversed (should verify + with two chains). + + 5h. Same as (5g) but missing the first root certificate (should verify + with two chains). + + 5i. Same as (5g) but missing the second root certificate (should verify + with two chains). + + 6a. A leaf certificate signed by an intermediate, that is cross + signed by an expired root certificate and an intermediate, which + in turn is signed by a second root (should verify with one chain). + + 6b. Same as (6a) but the order of the intermediates is reversed (should + verify with one chain). + + 7a. A leaf certificate signed by an intermediate, that is cross + signed by a root certificate and an intermediate, which in turn + is signed by a second root that has expired (should verify with one + chain). + + 7b. Same as (7a) but the order of the intermediates is reversed (should + verify with one chain). + + 8a. An expired leaf certificate signed by an intermediate that is then + signed by a root certificate (should fail to verify). + + 9a. A leaf certificate signed by an expired intermediate, which is + signed by a root certificate (should fail to verify). + +10a. A leaf certificate signed by an intermediate, that is cross + signed by two root certificates, with one of the cross signings + having expired (should verify with one chain). + +10b. Same as (10a) but order of intermediates is reversed (should verify + with one chain. + +11a. A leaf certificate signed by an intermediate, that is cross + signed by one root certificate and an expired intermediate, which + in turn is signed by a second root (should verify with one chain). + +11b. Same as (11a) but order of intermediates is reversed (should verify + with one chain. + +12a. A leaf certificate signed by an intermediate, that is signed by a + root certificate and cross signed as an expired intermediate, by a + second root (should verify with one chain). + +13a. A leaf certificate signed by an intermediate, that is signed by an + expired root certificate and cross signed as an intermediate, by a + second root (should verify with one chain). diff --git a/regress/lib/libcrypto/certs/make-certs.sh b/regress/lib/libcrypto/certs/make-certs.sh new file mode 100644 index 00000000000..b34a547ba25 --- /dev/null +++ b/regress/lib/libcrypto/certs/make-certs.sh @@ -0,0 +1,381 @@ +#!/bin/ksh + +# +# Copyright (c) 2020 Joel Sing <jsing@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +set -e +set -u +set -x + +readonly SUBJECT="/CN=LibreSSL Test" + +readonly TMPDIR=$(mktemp -d) + +cleanup() { + rm -rf "${TMPDIR}" +} + +trap cleanup EXIT INT + +reset() { + echo '100001' > ${TMPDIR}/certserial + cat /dev/null > ${TMPDIR}/certindex +} + +setup() { + reset + + cat > ${TMPDIR}/openssl.cnf <<EOF +[ca] +default_ca = test_ca + +[test_ca] +new_certs_dir = ${TMPDIR}/ +database = ${TMPDIR}/certindex +default_days = 365 +default_md = sha256 +policy = test_policy +serial = ${TMPDIR}/certserial + +[test_policy] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[v3_ca_root] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true +keyUsage = critical, cRLSign, keyCertSign + +[v3_ca_int] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true +keyUsage = critical, cRLSign, keyCertSign + +[v3_other] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:false +keyUsage = critical, digitalSignature + +[req] +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +EOF +} + +create_root() { + local name=$1 file=$2 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 -x509 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \ + -out "${TMPDIR}/${file}.crt" +} + +create_expired_root() { + local name=$1 file=$2 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \ + -out "${TMPDIR}/${file}.csr" + openssl ca -batch -notext -selfsign \ + -keyfile "${TMPDIR}/${file}.key" \ + -startdate 20100101000000Z -enddate 20200101000000Z \ + -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \ + -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_intermediate() { + local name=$1 file=$2 issuer_file=$3 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -out "${TMPDIR}/${file}.csr" + openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ + -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \ + -extfile ${TMPDIR}/openssl.cnf -extensions v3_ca_int \ + -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_expired_intermediate() { + local name=$1 file=$2 issuer_file=$3 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -out "${TMPDIR}/${file}.csr" + openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \ + -keyfile "${TMPDIR}/${issuer_file}.key" \ + -startdate 20100101000000Z -enddate 20200101000000Z \ + -config ${TMPDIR}/openssl.cnf -extensions v3_ca_int \ + -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_leaf() { + local name=$1 file=$2 issuer_file=$3 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -out "${TMPDIR}/${file}.csr" + openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ + -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \ + -extfile ${TMPDIR}/openssl.cnf -extensions v3_other \ + -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_expired_leaf() { + local name=$1 file=$2 issuer_file=$3 + + openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \ + -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ + -out "${TMPDIR}/${file}.csr" + openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \ + -keyfile "${TMPDIR}/${issuer_file}.key" \ + -config ${TMPDIR}/openssl.cnf -extensions v3_other \ + -startdate 20100101000000Z -enddate 20200101000000Z \ + -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_cross_signed() { + local file=$1 csr_file=$2 issuer_file=$3 + + openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ + -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \ + -extfile ${TMPDIR}/openssl.cnf -extensions v3_ca_int \ + -in "${TMPDIR}/${csr_file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_expired_cross_signed() { + local file=$1 csr_file=$2 issuer_file=$3 + + openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \ + -keyfile "${TMPDIR}/${issuer_file}.key" \ + -startdate 20100101000000Z -enddate 20200101000000Z \ + -config ${TMPDIR}/openssl.cnf -extensions v3_ca_int \ + -in "${TMPDIR}/${csr_file}.csr" -out "${TMPDIR}/${file}.crt" +} + +create_bundle() { + local bundle_file=$1 + shift + + mkdir -p $(dirname ${bundle_file}) + cat /dev/null > ${bundle_file} + + for _cert_file in $@; do + openssl x509 -nameopt oneline -subject -issuer -noout \ + -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} + done + for _cert_file in $@; do + cat "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} + done +} + +create_root_bundle() { + local bundle_file=$1 + shift + + mkdir -p $(dirname ${bundle_file}) + cat /dev/null > ${bundle_file} + + for _cert_file in $@; do + openssl x509 -nameopt oneline -subject -issuer \ + -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} + done +} + +setup + +# Scenario 1a. +reset +create_root "Root CA 1" "ca-root" +create_leaf "Server 1" "server-1" "ca-root" +create_root_bundle "./1a/roots.pem" "ca-root" +create_bundle "./1a/bundle.pem" "server-1" + +# Scenarios 2a and 2b. +reset +create_root "Root CA 1" "ca-root" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root" +create_leaf "Server 1" "server-1" "ca-int-1" +create_root_bundle "./2a/roots.pem" "ca-root" +create_bundle "./2a/bundle.pem" "server-1" "ca-int-1" +create_root_bundle "./2b/roots.pem" "ca-root" +create_bundle "./2b/bundle.pem" "server-1" + +# Scenarios 3a, 3b, 3c, 3d and 3e. +reset +create_root "Root CA 1" "ca-root" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_intermediate "Intermediate CA 3" "ca-int-3" "ca-int-2" +create_leaf "Server 1" "server-1" "ca-int-3" +create_root_bundle "./3a/roots.pem" "ca-root" +create_bundle "./3a/bundle.pem" "server-1" "ca-int-3" "ca-int-2" "ca-int-1" +create_root_bundle "./3b/roots.pem" "ca-root" +create_bundle "./3b/bundle.pem" "server-1" "ca-int-3" "ca-int-2" +create_root_bundle "./3c/roots.pem" "ca-root" +create_bundle "./3c/bundle.pem" "server-1" "ca-int-3" "ca-int-1" +create_root_bundle "./3d/roots.pem" "ca-root" +create_bundle "./3d/bundle.pem" "server-1" "ca-int-2" "ca-int-1" +create_root_bundle "./3e/roots.pem" "ca-root" +create_bundle "./3e/bundle.pem" "server-1" "ca-int-1" "ca-int-2" "ca-int-3" + +# Scenarios 4a, 4b, 4c, 4d, 4e, 4f, 4g and 4h. +reset +create_root "Root CA 1" "ca-root-1" +create_root "Root CA 2" "ca-root-2" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_cross_signed "ca-int-1-xs" "ca-int-1" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-1" +create_root_bundle "./4a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./4a/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs" +create_root_bundle "./4b/roots.pem" "ca-root-1" +create_bundle "./4b/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs" +create_root_bundle "./4c/roots.pem" "ca-root-2" +create_bundle "./4c/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs" +create_root_bundle "./4d/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./4d/bundle.pem" "server-1" "ca-int-1" +create_root_bundle "./4e/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./4e/bundle.pem" "server-1" "ca-int-1-xs" +create_root_bundle "./4f/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./4f/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1" +create_root_bundle "./4g/roots.pem" "ca-root-1" +create_bundle "./4g/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1" +create_root_bundle "./4h/roots.pem" "ca-root-2" +create_bundle "./4h/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1" + +# Scenario 5a, 5b, 5c, 5d, 5e, 5f, 5g, 5h and 5i. +reset +create_root "Root CA 1" "ca-root-1" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_root "Root CA 2" "ca-root-2" +create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./5a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./5a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./5b/roots.pem" "ca-root-2" +create_bundle "./5b/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./5c/roots.pem" "ca-root-1" +create_bundle "./5c/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./5d/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./5d/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./5e/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./5e/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" +create_root_bundle "./5f/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./5f/bundle.pem" "server-1" "ca-int-2" "ca-int-1" +create_root_bundle "./5g/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./5g/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" +create_root_bundle "./5h/roots.pem" "ca-root-2" +create_bundle "./5h/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" +create_root_bundle "./5i/roots.pem" "ca-root-1" +create_bundle "./5i/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" + +# Scenarios 6a and 6b. +reset +create_root "Root CA 1" "ca-root-1" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_expired_root "Root CA 2" "ca-root-2" +create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./6a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./6a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./6b/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./6b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" + +# Scenarios 7a and 7b. +reset +create_expired_root "Root CA 1" "ca-root-1" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_root "Root CA 2" "ca-root-2" +create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./7a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./7a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./7b/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./7b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" + +# Scenario 8a. +reset +create_root "Root CA 1" "ca-root" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root" +create_expired_leaf "Server 1" "server-1" "ca-int-1" +create_root_bundle "./8a/roots.pem" "ca-root" +create_bundle "./8a/bundle.pem" "server-1" "ca-int-1" + +# Scenario 9a. +reset +create_root "Root CA 1" "ca-root" +create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root" +create_leaf "Server 1" "server-1" "ca-int-1" +create_root_bundle "./9a/roots.pem" "ca-root" +create_bundle "./9a/bundle.pem" "server-1" "ca-int-1" + +# Scenarios 10a and 10b. +reset +create_root "Root CA 1" "ca-root-1" +create_root "Root CA 2" "ca-root-2" +create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_cross_signed "ca-int-1-xs" "ca-int-1" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-1" +create_root_bundle "./10a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./10a/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs" +create_root_bundle "./10b/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./10b/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1" + +# Scenarios 11a and 11b. +reset +create_root "Root CA 1" "ca-root-1" +create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_root "Root CA 2" "ca-root-2" +create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./11a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./11a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1" +create_root_bundle "./11b/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./11b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1" + +# Scenario 12a. +reset +create_root "Root CA 1" "ca-root-1" +create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_cross_signed "ca-root-2" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./12a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./12a/bundle.pem" "server-1" "ca-int-2" "ca-int-1" + +# Scenario 13a. +reset +create_root "Root CA 1" "ca-root-1" +create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1" +create_expired_cross_signed "ca-root-2" "ca-int-1" "ca-root-1" +create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1" +create_leaf "Server 1" "server-1" "ca-int-2" +create_root_bundle "./13a/roots.pem" "ca-root-1" "ca-root-2" +create_bundle "./13a/bundle.pem" "server-1" "ca-int-2" "ca-int-1" diff --git a/regress/lib/libcrypto/certs/verify_test.go b/regress/lib/libcrypto/certs/verify_test.go new file mode 100644 index 00000000000..25301109e4b --- /dev/null +++ b/regress/lib/libcrypto/certs/verify_test.go @@ -0,0 +1,111 @@ +package verify + +import ( + "crypto/x509" + "encoding/pem" + "io/ioutil" + "path/filepath" + "testing" +) + +func TestVerify(t *testing.T) { + tests := []struct { + id string + wantChains int + }{ + {"1a", 1}, + {"2a", 1}, + {"2b", 0}, + {"3a", 1}, + {"3b", 0}, + {"3c", 0}, + {"3d", 0}, + {"3e", 1}, + {"4a", 2}, + {"4b", 1}, + {"4c", 1}, + {"4d", 1}, + {"4e", 1}, + {"4f", 2}, + {"4g", 1}, + {"4h", 1}, + {"5a", 2}, + {"5b", 1}, + {"5c", 1}, + {"5d", 1}, + {"5e", 1}, + {"5f", 1}, + {"5g", 2}, + {"5h", 1}, + {"5i", 1}, + {"6a", 1}, // Expired root. + {"6b", 1}, // Expired root. + {"7a", 1}, // Expired root. + {"7b", 1}, // Expired root. + {"8a", 0}, // Expired leaf. + {"9a", 0}, // Expired intermediate. + {"10a", 1}, // Cross signed with expired intermediate. + {"10b", 1}, // Cross signed with expired intermediate. + {"11a", 1}, // Cross signed with expired intermediate. + {"11b", 1}, // Cross signed with expired intermediate. + {"12a", 1}, // Cross signed with expired intermediate. + {"13a", 1}, // Cross signed with expired root. + } + + for _, test := range tests { + t.Run(test.id, func(t *testing.T) { + rootsPEM, err := ioutil.ReadFile(filepath.Join(test.id, "roots.pem")) + if err != nil { + t.Fatalf("Failed to read roots PEM: %v", err) + } + bundlePEM, err := ioutil.ReadFile(filepath.Join(test.id, "bundle.pem")) + if err != nil { + t.Fatalf("Failed to read bundle PEM: %v", err) + } + + // Pull the leaf certificate off the top of the bundle. + block, intermediatesPEM := pem.Decode(bundlePEM) + if block == nil { + t.Fatal("Failed to parse leaf from bundle") + } + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + t.Fatalf("Failed to parse certificate: %v", err) + } + + roots := x509.NewCertPool() + if !roots.AppendCertsFromPEM(rootsPEM) { + t.Fatal("Failed to parse root certificates") + } + intermediates := x509.NewCertPool() + if len(intermediatesPEM) > 0 { + if !intermediates.AppendCertsFromPEM(intermediatesPEM) { + t.Fatal("Failed to parse intermediate certificates") + } + } + + opts := x509.VerifyOptions{ + Roots: roots, + Intermediates: intermediates, + } + + chains, err := cert.Verify(opts) + if err != nil { + if test.wantChains > 0 { + t.Errorf("Failed to verify certificate: %v", err) + } + return + } + t.Logf("Found %d chains", len(chains)) + if got, want := len(chains), test.wantChains; got != want { + t.Errorf("Got %d chains, want %d", got, want) + } + for i, chain := range chains { + t.Logf("Chain %d\n", i) + for _, cert := range chain { + t.Logf(" %v\n", cert.Subject) + } + } + }) + } +} |