mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 12:20:52 +02:00
Merge pull request #10687 from rlm2002/zd-NameConstraints
Name Constraints cert chain walk
This commit is contained in:
@@ -104,3 +104,18 @@ EXTRA_DIST += \
|
||||
certs/test/expired/expired-ca.der \
|
||||
certs/test/expired/expired-cert.pem \
|
||||
certs/test/expired/expired-cert.der
|
||||
|
||||
EXTRA_DIST += \
|
||||
certs/test/nc-ancestor/gen-nc-ancestor.sh \
|
||||
certs/test/nc-ancestor/00-root-cert.pem \
|
||||
certs/test/nc-ancestor/00-root-key.pem \
|
||||
certs/test/nc-ancestor/00-uri-permit-ca-permissive-cert.pem \
|
||||
certs/test/nc-ancestor/00-uri-permit-ca-permissive-key.pem \
|
||||
certs/test/nc-ancestor/01-uri-permit-ca-cert.pem \
|
||||
certs/test/nc-ancestor/01-uri-permit-ca-key.pem \
|
||||
certs/test/nc-ancestor/02-benign-sub-ca-cert.pem \
|
||||
certs/test/nc-ancestor/02-benign-sub-ca-key.pem \
|
||||
certs/test/nc-ancestor/03-leaf-attacker-key.pem \
|
||||
certs/test/nc-ancestor/03-leaf-chain.pem \
|
||||
certs/test/nc-ancestor/03-valid-leaf-cert.pem \
|
||||
certs/test/nc-ancestor/03-valid-leaf-key.pem
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBnjCCAUWgAwIBAgIBEDAKBggqhkjOPQQDAjA3MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFTATBgNVBAMMDE5DIFRlc3QgUm9vdDAeFw0yNjA2MTcx
|
||||
NjQ5MTNaFw00NjA2MTIxNjQ5MTNaMDcxCzAJBgNVBAYTAlVTMREwDwYDVQQKDAhO
|
||||
QyBUZXN0czEVMBMGA1UEAwwMTkMgVGVzdCBSb290MFkwEwYHKoZIzj0CAQYIKoZI
|
||||
zj0DAQcDQgAEH8XA+HpY8YL8kkIzgHQKUudoe4ZACBd/d0stYnvyQDiko5rOjTEY
|
||||
Ayha6yaf1oYaZqGdE7LrEXN0+mNplh/fuKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||
BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFFgBv14PFBEmIEUkSYhOelfJG8QtMAoG
|
||||
CCqGSM49BAMCA0cAMEQCIFdTyWY40+eB0OfRni+daV3gSO0+57bwzqtbbIkR+UTS
|
||||
AiA91cFwnImuRN8cf/sfoow7u91f8YTW/3wzCwNBc4axnA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIIjlWhdRFLGgcr6mtVVFKs38XvU06zb7y0hS2wan70rkoAoGCCqGSM49
|
||||
AwEHoUQDQgAEH8XA+HpY8YL8kkIzgHQKUudoe4ZACBd/d0stYnvyQDiko5rOjTEY
|
||||
Ayha6yaf1oYaZqGdE7LrEXN0+mNplh/fuA==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBoDCCAUegAwIBAgIBEjAKBggqhkjOPQQDAjA4MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFjAUBgNVBAMMDVVSSSBQZXJtaXQgQ0EwHhcNMjYwNjE3
|
||||
MTY0OTEzWhcNNDYwNjEyMTY0OTEzWjA4MQswCQYDVQQGEwJVUzERMA8GA1UECgwI
|
||||
TkMgVGVzdHMxFjAUBgNVBAMMDVVSSSBQZXJtaXQgQ0EwWTATBgcqhkjOPQIBBggq
|
||||
hkjOPQMBBwNCAATo9NHaL2G3EUr/H8b80VjTMpaG6wYlwr0O12WJnhc2rbx5OXTj
|
||||
NCoHZiv1tP9LX4tzDNItcvtTQ4KqucauIVZao0IwQDAPBgNVHRMBAf8EBTADAQH/
|
||||
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUbRiM8y/EUI+f3CfZNVab5WsNQSQw
|
||||
CgYIKoZIzj0EAwIDRwAwRAIgVL6GP7rNVB9/TiHMvb65bMupvmS4D8QmOBTv5wJc
|
||||
JokCIHLUUM5jO2iequaJ0RW5phjkem74R+2J/KJgKVcUGS+x
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIDIvBXdwFSH5kRKKGmPAIfkBuiSDZtOzBQIxP8xz2gc4oAoGCCqGSM49
|
||||
AwEHoUQDQgAE6PTR2i9htxFK/x/G/NFY0zKWhusGJcK9DtdliZ4XNq28eTl04zQq
|
||||
B2Yr9bT/S1+LcwzSLXL7U0OCqrnGriFWWg==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,13 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB4zCCAYmgAwIBAgIBETAKBggqhkjOPQQDAjA3MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFTATBgNVBAMMDE5DIFRlc3QgUm9vdDAeFw0yNjA2MTcx
|
||||
NjQ5MTNaFw00NjA2MTIxNjQ5MTNaMDgxCzAJBgNVBAYTAlVTMREwDwYDVQQKDAhO
|
||||
QyBUZXN0czEWMBQGA1UEAwwNVVJJIFBlcm1pdCBDQTBZMBMGByqGSM49AgEGCCqG
|
||||
SM49AwEHA0IABFrlMrMGfsgCYAIrm6Txj6XX89Xij2nCextBHk3fb3UDhnnYlnY5
|
||||
0uwhnOGDbuyaoOWdd6xQOi/hLoFUERSArDOjgYQwgYEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNe8LgUsg1wiiv2LAqB+mHkWZc10
|
||||
MB8GA1UdIwQYMBaAFFgBv14PFBEmIEUkSYhOelfJG8QtMB4GA1UdHgEB/wQUMBKg
|
||||
EDAOhgwuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIgTxJPzS5x3CijTVJn
|
||||
hZVklkfJdHT/FZsUoq/c7p7Byl0CIQDixmRi8yTjmprhAu+nQCod1m6psWpw1irW
|
||||
UAdvBlM+EA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIEzfFkozUo56l+WktIla45isYf6tsAZZg5b1Ph7Ou9e3oAoGCCqGSM49
|
||||
AwEHoUQDQgAEWuUyswZ+yAJgAiubpPGPpdfz1eKPacJ7G0EeTd9vdQOGediWdjnS
|
||||
7CGc4YNu7Jqg5Z13rFA6L+EugVQRFICsMw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,12 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBwTCCAWigAwIBAgIBIDAKBggqhkjOPQQDAjA4MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFjAUBgNVBAMMDVVSSSBQZXJtaXQgQ0EwHhcNMjYwNjE3
|
||||
MTY0OTEzWhcNNDYwNjEyMTY0OTEzWjA4MQswCQYDVQQGEwJVUzERMA8GA1UECgwI
|
||||
TkMgVGVzdHMxFjAUBgNVBAMMDUJlbmlnbiBTdWIgQ0EwWTATBgcqhkjOPQIBBggq
|
||||
hkjOPQMBBwNCAASZKAPbUSJU9u4tTNkubWqSXWAPOhANvNoZ/prsWQWDLyWVKbbV
|
||||
Vbo3AdX+O/VZKUPEhPrAegWkGnAp+BIIwEMgo2MwYTAPBgNVHRMBAf8EBTADAQH/
|
||||
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUFYNbX112ryF4JdDlgMeqY0Uo6kkw
|
||||
HwYDVR0jBBgwFoAU17wuBSyDXCKK/YsCoH6YeRZlzXQwCgYIKoZIzj0EAwIDRwAw
|
||||
RAIgBfGaiofozmQUMuMo4pEW+hGMAONyTkKR6IXDVVIX5RUCIEXrIy0oDP/ETKfi
|
||||
+4VOsiMiEeOSBUOmdQpAaQfHf0hZ
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIESDNs2dwdV/XRjqhCbWYYrQqvWq9fDHf7Xzm0xIyj1IoAoGCCqGSM49
|
||||
AwEHoUQDQgAEmSgD21EiVPbuLUzZLm1qkl1gDzoQDbzaGf6a7FkFgy8llSm21VW6
|
||||
NwHV/jv1WSlDxIT6wHoFpBpwKfgSCMBDIA==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIAZeIz1p8VFPywN6Z6DMurHlIa3aQ1XrnGus1WMEYnk5oAoGCCqGSM49
|
||||
AwEHoUQDQgAE0DMqgWwITs3KxGRHGYd0jrUcQIdoyEietpnezW8auDJhFe+Z6wCP
|
||||
Nkh8KmbnySNEp0mlwokUvvi5ol4z8bOyXw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICBzCCAa2gAwIBAgIBMDAKBggqhkjOPQQDAjA4MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFjAUBgNVBAMMDUJlbmlnbiBTdWIgQ0EwHhcNMjYwNjE3
|
||||
MTY0OTEzWhcNNDYwNjEyMTY0OTEzWjBAMQswCQYDVQQGEwJVUzERMA8GA1UECgwI
|
||||
TkMgVGVzdHMxHjAcBgNVBAMMFU5DIFRlc3QgQXR0YWNrZXIgTGVhZjBZMBMGByqG
|
||||
SM49AgEGCCqGSM49AwEHA0IABNAzKoFsCE7NysRkRxmHdI61HECHaMhInraZ3s1v
|
||||
GrgyYRXvmesAjzZIfCpm58kjRKdJpcKJFL74uaJeM/Gzsl+jgZ8wgZwwDAYDVR0T
|
||||
AQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYD
|
||||
VR0OBBYEFO6GdfO6MvjzgDGAs71HPqOXaCtBMB8GA1UdIwQYMBaAFBWDW19ddq8h
|
||||
eCXQ5YDHqmNFKOpJMCcGA1UdEQEB/wQdMBuGGWh0dHBzOi8vYXR0YWNrZXIuY29t
|
||||
L2xlYWYwCgYIKoZIzj0EAwIDSAAwRQIhAL/dvlCeChSzMyecV6fV7ecfKccFY1RA
|
||||
NL/g+05/4lyiAiAO4PyaBBz5t/0U/TOInIzjtWqaO1cIL6IzE3xPoqj5KQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBwTCCAWigAwIBAgIBIDAKBggqhkjOPQQDAjA4MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFjAUBgNVBAMMDVVSSSBQZXJtaXQgQ0EwHhcNMjYwNjE3
|
||||
MTY0OTEzWhcNNDYwNjEyMTY0OTEzWjA4MQswCQYDVQQGEwJVUzERMA8GA1UECgwI
|
||||
TkMgVGVzdHMxFjAUBgNVBAMMDUJlbmlnbiBTdWIgQ0EwWTATBgcqhkjOPQIBBggq
|
||||
hkjOPQMBBwNCAASZKAPbUSJU9u4tTNkubWqSXWAPOhANvNoZ/prsWQWDLyWVKbbV
|
||||
Vbo3AdX+O/VZKUPEhPrAegWkGnAp+BIIwEMgo2MwYTAPBgNVHRMBAf8EBTADAQH/
|
||||
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUFYNbX112ryF4JdDlgMeqY0Uo6kkw
|
||||
HwYDVR0jBBgwFoAU17wuBSyDXCKK/YsCoH6YeRZlzXQwCgYIKoZIzj0EAwIDRwAw
|
||||
RAIgBfGaiofozmQUMuMo4pEW+hGMAONyTkKR6IXDVVIX5RUCIEXrIy0oDP/ETKfi
|
||||
+4VOsiMiEeOSBUOmdQpAaQfHf0hZ
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB4zCCAYmgAwIBAgIBETAKBggqhkjOPQQDAjA3MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFTATBgNVBAMMDE5DIFRlc3QgUm9vdDAeFw0yNjA2MTcx
|
||||
NjQ5MTNaFw00NjA2MTIxNjQ5MTNaMDgxCzAJBgNVBAYTAlVTMREwDwYDVQQKDAhO
|
||||
QyBUZXN0czEWMBQGA1UEAwwNVVJJIFBlcm1pdCBDQTBZMBMGByqGSM49AgEGCCqG
|
||||
SM49AwEHA0IABFrlMrMGfsgCYAIrm6Txj6XX89Xij2nCextBHk3fb3UDhnnYlnY5
|
||||
0uwhnOGDbuyaoOWdd6xQOi/hLoFUERSArDOjgYQwgYEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNe8LgUsg1wiiv2LAqB+mHkWZc10
|
||||
MB8GA1UdIwQYMBaAFFgBv14PFBEmIEUkSYhOelfJG8QtMB4GA1UdHgEB/wQUMBKg
|
||||
EDAOhgwuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIgTxJPzS5x3CijTVJn
|
||||
hZVklkfJdHT/FZsUoq/c7p7Byl0CIQDixmRi8yTjmprhAu+nQCod1m6psWpw1irW
|
||||
UAdvBlM+EA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,13 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICBTCCAaygAwIBAgIBMTAKBggqhkjOPQQDAjA4MQswCQYDVQQGEwJVUzERMA8G
|
||||
A1UECgwITkMgVGVzdHMxFjAUBgNVBAMMDUJlbmlnbiBTdWIgQ0EwHhcNMjYwNjE3
|
||||
MTY0OTEzWhcNNDYwNjEyMTY0OTEzWjA9MQswCQYDVQQGEwJVUzERMA8GA1UECgwI
|
||||
TkMgVGVzdHMxGzAZBgNVBAMMEk5DIFRlc3QgVmFsaWQgTGVhZjBZMBMGByqGSM49
|
||||
AgEGCCqGSM49AwEHA0IABNcVnczEUQaQMcxlrButtTd8HqQEoMLGBl8XLPdI/eZs
|
||||
42jj3B4l6txsi/zPG+9klJad5sPkp2Uqf9PiHowizW+jgaEwgZ4wDAYDVR0TAQH/
|
||||
BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0O
|
||||
BBYEFLG1JSabNebv3xs8ZTuMVceg4FmrMB8GA1UdIwQYMBaAFBWDW19ddq8heCXQ
|
||||
5YDHqmNFKOpJMCkGA1UdEQEB/wQfMB2GG2h0dHBzOi8vYmVuaWduLmV4YW1wbGUu
|
||||
Y29tLzAKBggqhkjOPQQDAgNHADBEAiBWs+jRkdeHkfw7XuJ/v7qEXHFEojWJFu9z
|
||||
Qhy+9ekdtwIgKRC5gM+FDlcDD2ULdCsHXtU9N/9801gx3gowxldxzA8=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIJKBX7gzH3pL3Cjgw5Z623D/6Jo/RrFZXKyu4IobX5DroAoGCCqGSM49
|
||||
AwEHoUQDQgAE1xWdzMRRBpAxzGWsG621N3wepASgwsYGXxcs90j95mzjaOPcHiXq
|
||||
3GyL/M8b72SUlp3mw+SnZSp/0+IejCLNbw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
Executable
+161
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# gen-nc-ancestor.sh
|
||||
# Re-sign the NameConstraints ancestor-walk test certs from committed
|
||||
# keys. Cert SKIDs are stable across runs; 01-uri-permit-ca and its
|
||||
# permissive sibling are pinned to satisfy the AKID-disambiguation test.
|
||||
|
||||
set -e
|
||||
|
||||
check_result(){
|
||||
if [ $1 -ne 0 ]; then
|
||||
echo "$2 Failed, Abort"
|
||||
exit 1
|
||||
else
|
||||
echo "$2 Succeeded!"
|
||||
fi
|
||||
}
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
# Issue a child cert from $issuer_cert/$issuer_key.
|
||||
# $1 child-key $2 subject-CN $3 out-cert $4 ext-file $5 ext-section $6 serial
|
||||
mkchild(){
|
||||
local child_key=$1 cn=$2 out=$3 extfile=$4 extsec=$5 serial=$6
|
||||
openssl req -new -key "$child_key" -out "$WORK/child.csr" \
|
||||
-subj "/C=US/O=NC Tests/CN=$cn" -config "$extfile"
|
||||
check_result $? "$(basename "$out"): csr"
|
||||
openssl x509 -req -in "$WORK/child.csr" \
|
||||
-CA "$issuer_cert" -CAkey "$issuer_key" \
|
||||
-set_serial "$serial" -out "$out" -days 7300 -sha256 \
|
||||
-extfile "$extfile" -extensions "$extsec"
|
||||
check_result $? "$(basename "$out"): sign"
|
||||
rm -f "$WORK/child.csr"
|
||||
}
|
||||
|
||||
# ---- ext configs ----
|
||||
|
||||
cat > "$WORK/root.cnf" <<'EOF'
|
||||
[req]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[dn]
|
||||
[v3_ca]
|
||||
basicConstraints = critical, CA:TRUE
|
||||
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
|
||||
subjectKeyIdentifier = hash
|
||||
EOF
|
||||
|
||||
cat > "$WORK/uri-permit-ca.cnf" <<'EOF'
|
||||
[req]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[dn]
|
||||
[v3_uri_permit]
|
||||
basicConstraints = critical, CA:TRUE
|
||||
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid
|
||||
nameConstraints = critical, permitted;URI:.example.com
|
||||
EOF
|
||||
|
||||
cat > "$WORK/sub-ca-nonc.cnf" <<'EOF'
|
||||
[req]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[dn]
|
||||
[v3_sub_ca]
|
||||
basicConstraints = critical, CA:TRUE
|
||||
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid
|
||||
EOF
|
||||
|
||||
cat > "$WORK/leaf-attacker.cnf" <<'EOF'
|
||||
[req]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[dn]
|
||||
[v3_leaf_attacker]
|
||||
basicConstraints = critical, CA:FALSE
|
||||
keyUsage = critical, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid
|
||||
subjectAltName = critical, URI:https://attacker.com/leaf
|
||||
EOF
|
||||
|
||||
cat > "$WORK/leaf-valid.cnf" <<'EOF'
|
||||
[req]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[dn]
|
||||
[v3_leaf_valid]
|
||||
basicConstraints = critical, CA:FALSE
|
||||
keyUsage = critical, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid
|
||||
subjectAltName = critical, URI:https://benign.example.com/
|
||||
EOF
|
||||
|
||||
# ---- 00 root (self-signed) ----
|
||||
|
||||
openssl req -new -x509 -key "$DIR/00-root-key.pem" \
|
||||
-out "$DIR/00-root-cert.pem" \
|
||||
-subj "/C=US/O=NC Tests/CN=NC Test Root" \
|
||||
-config "$WORK/root.cnf" -extensions v3_ca \
|
||||
-set_serial 0x10 -days 7300 -sha256
|
||||
check_result $? "00-root-cert.pem"
|
||||
|
||||
# ---- 01 uri-permit-ca (permits URI:.example.com), issued by root ----
|
||||
|
||||
issuer_cert="$DIR/00-root-cert.pem"
|
||||
issuer_key="$DIR/00-root-key.pem"
|
||||
mkchild "$DIR/01-uri-permit-ca-key.pem" "URI Permit CA" \
|
||||
"$DIR/01-uri-permit-ca-cert.pem" "$WORK/uri-permit-ca.cnf" \
|
||||
v3_uri_permit 0x11
|
||||
|
||||
# ---- 00 uri-permit-ca-permissive (same-DN distractor, self-signed) ----
|
||||
|
||||
openssl req -new -x509 -key "$DIR/00-uri-permit-ca-permissive-key.pem" \
|
||||
-out "$DIR/00-uri-permit-ca-permissive-cert.pem" \
|
||||
-subj "/C=US/O=NC Tests/CN=URI Permit CA" \
|
||||
-config "$WORK/root.cnf" -extensions v3_ca \
|
||||
-set_serial 0x12 -days 7300 -sha256
|
||||
check_result $? "00-uri-permit-ca-permissive-cert.pem"
|
||||
|
||||
# ---- 02 benign-sub-ca (no NC), issued by uri-permit-ca ----
|
||||
|
||||
issuer_cert="$DIR/01-uri-permit-ca-cert.pem"
|
||||
issuer_key="$DIR/01-uri-permit-ca-key.pem"
|
||||
mkchild "$DIR/02-benign-sub-ca-key.pem" "Benign Sub CA" \
|
||||
"$DIR/02-benign-sub-ca-cert.pem" "$WORK/sub-ca-nonc.cnf" \
|
||||
v3_sub_ca 0x20
|
||||
|
||||
# ---- 03 leaf-attacker (URI violates grandparent's permit), issued by sub-ca ----
|
||||
|
||||
issuer_cert="$DIR/02-benign-sub-ca-cert.pem"
|
||||
issuer_key="$DIR/02-benign-sub-ca-key.pem"
|
||||
mkchild "$DIR/03-leaf-attacker-key.pem" "NC Test Attacker Leaf" \
|
||||
"$WORK/03-leaf-cert.pem" "$WORK/leaf-attacker.cnf" \
|
||||
v3_leaf_attacker 0x30
|
||||
|
||||
# ---- 03 valid-leaf (URI inside permit), issued by sub-ca ----
|
||||
|
||||
mkchild "$DIR/03-valid-leaf-key.pem" "NC Test Valid Leaf" \
|
||||
"$DIR/03-valid-leaf-cert.pem" "$WORK/leaf-valid.cnf" \
|
||||
v3_leaf_valid 0x31
|
||||
|
||||
# ---- Concatenated bundle: attacker leaf + benign-sub-ca + uri-permit-ca ----
|
||||
|
||||
cat "$WORK/03-leaf-cert.pem" \
|
||||
"$DIR/02-benign-sub-ca-cert.pem" \
|
||||
"$DIR/01-uri-permit-ca-cert.pem" \
|
||||
> "$DIR/03-leaf-chain.pem"
|
||||
check_result $? "03-leaf-chain.pem"
|
||||
|
||||
echo "Generated chain in $DIR/"
|
||||
ls -la "$DIR/"
|
||||
@@ -3524,3 +3524,93 @@ int test_wolfSSL_X509_V_ERR_strings(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Leaf must satisfy a grandparent CA's NCs even when its direct issuer
|
||||
* carries no constraints. */
|
||||
int test_wolfSSL_CertManagerNameConstraint_valid_chain(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_WOLFSSL_CM_VERIFY) && defined(HAVE_ECC) && \
|
||||
!defined(IGNORE_NAME_CONSTRAINTS) && !defined(NO_SHA256) && \
|
||||
defined(WOLFSSL_ALT_NAMES) && \
|
||||
(defined(WOLFSSL_PEM_TO_DER) || defined(OPENSSL_EXTRA))
|
||||
WOLFSSL_CERT_MANAGER* cm = NULL;
|
||||
const char* root_cert =
|
||||
"./certs/test/nc-ancestor/00-root-cert.pem";
|
||||
const char* uri_permit_ca_cert =
|
||||
"./certs/test/nc-ancestor/01-uri-permit-ca-cert.pem";
|
||||
const char* benign_sub_ca_cert =
|
||||
"./certs/test/nc-ancestor/02-benign-sub-ca-cert.pem";
|
||||
const char* valid_leaf_cert =
|
||||
"./certs/test/nc-ancestor/03-valid-leaf-cert.pem";
|
||||
const char* attacker_leaf_chain =
|
||||
"./certs/test/nc-ancestor/03-leaf-chain.pem";
|
||||
|
||||
ExpectNotNull(cm = wolfSSL_CertManagerNew());
|
||||
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, root_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, uri_permit_ca_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, benign_sub_ca_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* Positive: leaf satisfies the grandparent permit. */
|
||||
ExpectIntEQ(wolfSSL_CertManagerVerify(cm, valid_leaf_cert,
|
||||
WOLFSSL_FILETYPE_PEM),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* Negative: leaf violates the grandparent permit. */
|
||||
ExpectIntEQ(wolfSSL_CertManagerVerify(cm, attacker_leaf_chain,
|
||||
WOLFSSL_FILETYPE_PEM),
|
||||
WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
|
||||
|
||||
wolfSSL_CertManagerFree(cm);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Same-DN sibling without NCs is loaded alongside the strict CA. The
|
||||
* walk must use AKID->SKID, not a name-only lookup, to find the real
|
||||
* signer. */
|
||||
int test_wolfSSL_CertManagerNameConstraint_skid_disambiguates(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_WOLFSSL_CM_VERIFY) && defined(HAVE_ECC) && \
|
||||
!defined(IGNORE_NAME_CONSTRAINTS) && !defined(NO_SHA256) && \
|
||||
!defined(NO_SKID) && defined(WOLFSSL_ALT_NAMES) && \
|
||||
(defined(WOLFSSL_PEM_TO_DER) || defined(OPENSSL_EXTRA))
|
||||
WOLFSSL_CERT_MANAGER* cm = NULL;
|
||||
const char* root_cert =
|
||||
"./certs/test/nc-ancestor/00-root-cert.pem";
|
||||
const char* permissive_cert =
|
||||
"./certs/test/nc-ancestor/00-uri-permit-ca-permissive-cert.pem";
|
||||
const char* strict_cert =
|
||||
"./certs/test/nc-ancestor/01-uri-permit-ca-cert.pem";
|
||||
const char* benign_sub_ca_cert =
|
||||
"./certs/test/nc-ancestor/02-benign-sub-ca-cert.pem";
|
||||
const char* attacker_leaf_chain =
|
||||
"./certs/test/nc-ancestor/03-leaf-chain.pem";
|
||||
|
||||
ExpectNotNull(cm = wolfSSL_CertManagerNew());
|
||||
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, root_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
/* Load permissive sibling first to favor a name-only lookup. */
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, permissive_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, strict_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, benign_sub_ca_cert, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_CertManagerVerify(cm, attacker_leaf_chain,
|
||||
WOLFSSL_FILETYPE_PEM),
|
||||
WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
|
||||
|
||||
wolfSSL_CertManagerFree(cm);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ int test_wolfSSL_CertManagerCheckOCSPResponse(void);
|
||||
int test_various_pathlen_chains(void);
|
||||
int test_wolfSSL_CertManagerRejectMD5Cert(void);
|
||||
int test_wolfSSL_X509_V_ERR_strings(void);
|
||||
int test_wolfSSL_CertManagerNameConstraint_valid_chain(void);
|
||||
int test_wolfSSL_CertManagerNameConstraint_skid_disambiguates(void);
|
||||
|
||||
#define TEST_CERTMAN_DECLS \
|
||||
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerAPI), \
|
||||
@@ -83,7 +85,11 @@ int test_wolfSSL_X509_V_ERR_strings(void);
|
||||
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCheckOCSPResponse), \
|
||||
TEST_DECL_GROUP("certman", test_various_pathlen_chains), \
|
||||
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerRejectMD5Cert), \
|
||||
TEST_DECL_GROUP("certman", test_wolfSSL_X509_V_ERR_strings)
|
||||
TEST_DECL_GROUP("certman", test_wolfSSL_X509_V_ERR_strings), \
|
||||
TEST_DECL_GROUP("certman", \
|
||||
test_wolfSSL_CertManagerNameConstraint_valid_chain), \
|
||||
TEST_DECL_GROUP("certman", \
|
||||
test_wolfSSL_CertManagerNameConstraint_skid_disambiguates)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_CERTMAN_H */
|
||||
|
||||
|
||||
+116
-16
@@ -18754,9 +18754,10 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
|
||||
case ASN_DNS_TYPE:
|
||||
name = cert->altNames;
|
||||
|
||||
/* When no SAN is present, apply DNS name constraints to the
|
||||
* Subject CN. */
|
||||
if (cert->subjectCN != NULL && cert->altNames == NULL) {
|
||||
/* Apply DNS constraints to leaf Subject CN when no SAN
|
||||
* (legacy hostname-in-CN). Skipped for CAs. */
|
||||
if (cert->subjectCN != NULL && cert->altNames == NULL &&
|
||||
!cert->isCA) {
|
||||
subjectDnsName.next = NULL;
|
||||
subjectDnsName.type = ASN_DNS_TYPE;
|
||||
subjectDnsName.len = cert->subjectCNLen;
|
||||
@@ -23323,6 +23324,71 @@ Signer* findSignerByName(Signer *list, byte *hash)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
/* Find a signer for cert in cm and extraCAList. Prefers AKID->SKID
|
||||
* with name-hash validation. Fall back to name-only when AKID is
|
||||
* absent. */
|
||||
static Signer* FindSignerByAkidOrName(void* cm, Signer* extraCAList,
|
||||
Signer* cert)
|
||||
{
|
||||
Signer* signer = NULL;
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
|
||||
#ifndef NO_SKID
|
||||
Signer* exCaSigner;
|
||||
#endif
|
||||
#else
|
||||
(void)extraCAList;
|
||||
#endif
|
||||
|
||||
#ifndef NO_SKID
|
||||
if (cert->authKeyIdSet) {
|
||||
signer = GetCA(cm, cert->authKeyIdHash);
|
||||
if (signer != NULL &&
|
||||
XMEMCMP(signer->subjectNameHash, cert->issuerNameHash,
|
||||
SIGNER_DIGEST_SIZE) != 0) {
|
||||
signer = NULL;
|
||||
}
|
||||
/* AKID is authoritative; do not fall back to name when AKID
|
||||
* is set (could substitute a same-DN sibling). */
|
||||
}
|
||||
else {
|
||||
signer = GetCAByName(cm, cert->issuerNameHash);
|
||||
}
|
||||
#else
|
||||
signer = GetCA(cm, cert->issuerNameHash);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
|
||||
if (signer == NULL && extraCAList != NULL) {
|
||||
#ifndef NO_SKID
|
||||
if (cert->authKeyIdSet) {
|
||||
for (exCaSigner = extraCAList; exCaSigner != NULL;
|
||||
exCaSigner = exCaSigner->next) {
|
||||
if (XMEMCMP(exCaSigner->subjectKeyIdHash,
|
||||
cert->authKeyIdHash,
|
||||
SIGNER_DIGEST_SIZE) == 0 &&
|
||||
XMEMCMP(exCaSigner->subjectNameHash,
|
||||
cert->issuerNameHash,
|
||||
SIGNER_DIGEST_SIZE) == 0) {
|
||||
signer = exCaSigner;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* AKID is authoritative; do not fall back to name. */
|
||||
}
|
||||
else {
|
||||
signer = findSignerByName(extraCAList, cert->issuerNameHash);
|
||||
}
|
||||
#else
|
||||
signer = findSignerByName(extraCAList, cert->issuerNameHash);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return signer;
|
||||
}
|
||||
#endif /* !IGNORE_NAME_CONSTRAINTS */
|
||||
|
||||
int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
Signer *extraCAList)
|
||||
{
|
||||
@@ -23337,6 +23403,12 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
int idx = 0;
|
||||
#endif
|
||||
byte* sce_tsip_encRsaKeyIdx;
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
int ncDepth = 0;
|
||||
Signer* ncSigner = NULL;
|
||||
Signer* ncParent = NULL;
|
||||
Signer* ncPrev = NULL;
|
||||
#endif
|
||||
(void)extraCAList;
|
||||
|
||||
if (cert == NULL) {
|
||||
@@ -23969,18 +24041,6 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
}
|
||||
#endif /* WOLFSSL_DUAL_ALG_CERTS */
|
||||
}
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
if (verify == VERIFY || verify == VERIFY_OCSP ||
|
||||
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) {
|
||||
/* check that this cert's name is permitted by the signer's
|
||||
* name constraints */
|
||||
if (!ConfirmNameConstraints(cert->ca, cert)) {
|
||||
WOLFSSL_MSG("Confirm name constraint failed");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
|
||||
return ASN_NAME_INVALID_E;
|
||||
}
|
||||
}
|
||||
#endif /* IGNORE_NAME_CONSTRAINTS */
|
||||
} /* cert->ca */
|
||||
#ifdef WOLFSSL_CERT_REQ
|
||||
else if (type == CERTREQ_TYPE) {
|
||||
@@ -24062,6 +24122,38 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
}
|
||||
} /* verify != NO_VERIFY && type != CA_TYPE && type != TRUSTED_PEER_TYPE */
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
/* Apply each ancestor CA's name constraints to this cert.
|
||||
* Signer pointers between lookups are not lock-protected
|
||||
* (see wolfssl_cm_get_certs_der). */
|
||||
if ((verify == VERIFY || verify == VERIFY_OCSP ||
|
||||
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) &&
|
||||
type != TRUSTED_PEER_TYPE && cert->ca != NULL) {
|
||||
ncSigner = cert->ca;
|
||||
while (ncSigner != NULL) {
|
||||
if (!ConfirmNameConstraints(ncSigner, cert)) {
|
||||
WOLFSSL_MSG("Confirm name constraint failed");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
|
||||
return ASN_NAME_INVALID_E;
|
||||
}
|
||||
/* Stop at trust anchor (self-issued). */
|
||||
if (ncSigner->selfSigned)
|
||||
break;
|
||||
ncParent = FindSignerByAkidOrName(cm, extraCAList, ncSigner);
|
||||
/* Stop on missing parent, self-loop, or A->B->A cycle. */
|
||||
if (ncParent == NULL || ncParent == ncSigner ||
|
||||
ncParent == ncPrev)
|
||||
break;
|
||||
if (++ncDepth >= WOLFSSL_MAX_CHAIN_DEPTH) {
|
||||
WOLFSSL_MSG("NC ancestor walk exceeded WOLFSSL_MAX_CHAIN_DEPTH");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
|
||||
return ASN_PATHLEN_SIZE_E;
|
||||
}
|
||||
ncPrev = ncSigner;
|
||||
ncSigner = ncParent;
|
||||
}
|
||||
}
|
||||
#endif /* IGNORE_NAME_CONSTRAINTS */
|
||||
#if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
|
||||
exit_pcr:
|
||||
#endif
|
||||
@@ -24140,10 +24232,18 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
|
||||
#ifndef NO_SKID
|
||||
XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
if (cert->extAuthKeyIdSet) {
|
||||
XMEMCPY(signer->authKeyIdHash, cert->extAuthKeyId,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
signer->authKeyIdSet = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
XMEMCPY(signer->subjectNameHash, cert->subjectHash,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || \
|
||||
defined(WOLFSSL_AKID_NAME) || !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XMEMCPY(signer->issuerNameHash, cert->issuerHash,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#endif
|
||||
|
||||
+18
-4
@@ -1736,6 +1736,11 @@ typedef struct EncodedName {
|
||||
#define WOLFSSL_MAX_PATH_LEN 127
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_MAX_CHAIN_DEPTH
|
||||
/* Max cert chain depth for ancestor walks. */
|
||||
#define WOLFSSL_MAX_CHAIN_DEPTH 20
|
||||
#endif
|
||||
|
||||
typedef struct DecodedName DecodedName;
|
||||
typedef struct DecodedCert DecodedCert;
|
||||
typedef struct Signer Signer;
|
||||
@@ -2207,6 +2212,10 @@ struct Signer {
|
||||
*/
|
||||
WC_BITFIELD extNameConstraintCrit:1;
|
||||
WC_BITFIELD extNameConstraintHasUnsupported:1;
|
||||
#ifndef NO_SKID
|
||||
WC_BITFIELD authKeyIdSet:1; /* true when authKeyIdHash holds the
|
||||
* AKID extension's keyId */
|
||||
#endif
|
||||
#endif
|
||||
const byte* publicKey;
|
||||
int nameLen;
|
||||
@@ -2218,15 +2227,20 @@ struct Signer {
|
||||
#endif
|
||||
byte subjectNameHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of names in certificate */
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME) || \
|
||||
!defined(IGNORE_NAME_CONSTRAINTS)
|
||||
byte issuerNameHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of issuer names in certificate.
|
||||
* Used in OCSP to check for authorized
|
||||
* responders. */
|
||||
/* sha hash of issuer names; used by
|
||||
* OCSP and name-constraint walk */
|
||||
#endif
|
||||
#ifndef NO_SKID
|
||||
byte subjectKeyIdHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of key in certificate */
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
byte authKeyIdHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of AKID; locates signer
|
||||
* during name-constraint walk */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_OCSP
|
||||
byte subjectKeyHash[KEYID_SIZE];
|
||||
|
||||
Reference in New Issue
Block a user