mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-28 00:22:22 +01:00
Merge pull request #9705 from cconlon/nameConstraints
Support for extracting and validating X.509 Name Constraints extensions
This commit is contained in:
BIN
certs/test/cert-ext-nc-combined.der
Normal file
BIN
certs/test/cert-ext-nc-combined.der
Normal file
Binary file not shown.
26
certs/test/cert-ext-nc-combined.pem
Normal file
26
certs/test/cert-ext-nc-combined.pem
Normal file
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCA0KgAwIBAgIUVxNILYrtvic5fahe1thKz5+9MBkwDQYJKoZIhvcNAQEL
|
||||
BQAwezELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0Jv
|
||||
emVtYW4xFDASBgNVBAoMC3dvbGZTU0wgSW5jMRgwFgYDVQQLDA9EZXYgYW5kIFRl
|
||||
c3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTAeFw0yNjAxMjIyMTE4MjJa
|
||||
Fw0yODEwMTgyMTE4MjJaMHsxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5h
|
||||
MRAwDgYDVQQHDAdCb3plbWFuMRQwEgYDVQQKDAt3b2xmU1NMIEluYzEYMBYGA1UE
|
||||
CwwPRGV2IGFuZCBUZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20wggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAlQjhV0HycW230kVBJwFlxkWu
|
||||
8rwkMLiVzi9O1vYciLx8n/uoZ3/+XJxRdfeKygfnNS+P4b17wC98q2SoF/zKXXu6
|
||||
4CHlci5vLobYlXParBtTuV8/1xkNJU/hY2NRiwtkP61DuKUcXDSzrgCgY8X2fwtZ
|
||||
aHhzpowYqQJtr8MZAS64EOPGzEC0aaNGM2mHbsS7F6bz6N2tc7x7LyG1/WZRDL1U
|
||||
s+FtXxy8I3PRCQOJFNIQuWTDKtChlkq84dQaW8egwMFjeA9ENzAyloAyI5Whd7oT
|
||||
0pdz4l0lyWoNwzlgpLSwaUJCCenYCLwzILNYIqeq68Th5mGDxdKW39nQT63XAgMB
|
||||
AAGjgdUwgdIwHQYDVR0OBBYEFLMRMsmSmITiyfjQO24DQsofDo48MB8GA1UdIwQY
|
||||
MBaAFLMRMsmSmITiyfjQO24DQsofDo48MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD
|
||||
VR0PAQH/BAQDAgGGMC4GA1UdHgEB/wQkMCKgIDAOhgwud29sZnNzbC5jb20wDoIM
|
||||
LndvbGZzc2wuY29tMDwGCWCGSAGG+EIBDQQvFi1UZXN0aW5nIGNvbWJpbmVkIFVS
|
||||
SSBhbmQgRE5TIG5hbWUgY29uc3RyYWludHMwDQYJKoZIhvcNAQELBQADggEBAKA5
|
||||
4xPLP6RVWnOSkHYi+Cr6KegUOQNxmPVoaAwph+QMR8Z2sdLKIWt9U1xL4lkH6L51
|
||||
S54kLMH/jnv2WD9bYvDe+CjWZEM97Nm+YURHDv5QAoqxY9gw9Y8TMGi8xOC5cubR
|
||||
JXpjN4U60N/mdHbxMQbcuHJLowjXSlCp3q6S+iz2Bh7TaP8w7EoTR6pQEK6nMo6L
|
||||
C/CRztvpaFgOZ4ia8O8C3EHBaBSECWWtPMyh6WappneKkT2p9wh8LdMB58AjKqoJ
|
||||
/Zg6lp0Qj+NOhpVYXiT2+RlxVkttZJmLv3DIYH9LMsS8jhnTriIXpx2DaS56dEVn
|
||||
aFzrG/ecf3YLPUrKgHw=
|
||||
-----END CERTIFICATE-----
|
||||
25
certs/test/cert-ext-ncdns.pem
Normal file
25
certs/test/cert-ext-ncdns.pem
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQzCCAyugAwIBAgIUBd10yS05H9xt7w0qR43nO7q47hUwDQYJKoZIhvcNAQEL
|
||||
BQAwezELMAkGA1UEBhMCQVUxEzARBgNVBAgMClF1ZWVuc2xhbmQxETAPBgNVBAcM
|
||||
CEJyaXNiYW5lMRQwEgYDVQQKDAt3b2xmU1NMIEluYzEUMBIGA1UECwwLRW5naW5l
|
||||
ZXJpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTAeFw0yNjAxMjIyMTE4MjJa
|
||||
Fw0yODEwMTgyMTE4MjJaMHsxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApRdWVlbnNs
|
||||
YW5kMREwDwYDVQQHDAhCcmlzYmFuZTEUMBIGA1UECgwLd29sZlNTTCBJbmMxFDAS
|
||||
BgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20wggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAlQjhV0HycW230kVBJwFlxkWu
|
||||
8rwkMLiVzi9O1vYciLx8n/uoZ3/+XJxRdfeKygfnNS+P4b17wC98q2SoF/zKXXu6
|
||||
4CHlci5vLobYlXParBtTuV8/1xkNJU/hY2NRiwtkP61DuKUcXDSzrgCgY8X2fwtZ
|
||||
aHhzpowYqQJtr8MZAS64EOPGzEC0aaNGM2mHbsS7F6bz6N2tc7x7LyG1/WZRDL1U
|
||||
s+FtXxy8I3PRCQOJFNIQuWTDKtChlkq84dQaW8egwMFjeA9ENzAyloAyI5Whd7oT
|
||||
0pdz4l0lyWoNwzlgpLSwaUJCCenYCLwzILNYIqeq68Th5mGDxdKW39nQT63XAgMB
|
||||
AAGjgb4wgbswHQYDVR0OBBYEFLMRMsmSmITiyfjQO24DQsofDo48MB8GA1UdIwQY
|
||||
MBaAFLMRMsmSmITiyfjQO24DQsofDo48MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD
|
||||
VR0PAQH/BAQDAgGGMCwGA1UdHgEB/wQiMCCgHjANggt3b2xmc3NsLmNvbTANggtl
|
||||
eGFtcGxlLmNvbTAnBglghkgBhvhCAQ0EGhYYVGVzdGluZyBuYW1lIGNvbnN0cmFp
|
||||
bnRzMA0GCSqGSIb3DQEBCwUAA4IBAQCkCFJl/uWp3JinCS01T3vxZF8UT71w165B
|
||||
Fqz49w4UScy3wStJ/fcP/+M1mxbClvGmfBhNW7l8BNixPU4L9OYs+5/rWsMh6No+
|
||||
ZbPjWfkkHRWlmGKVNmk+C9OD7vVOAGVuPhdQGZfs9rYD3AqPk+CYC7AE/o3T97C9
|
||||
tGzfpt4ccEjyFV5liDnxr2SvMuG2KBIJovX2+QYXsb4u4tinKyOyvA9PF8nGLYvA
|
||||
mQk0ZQy+vnYjWv3luU5ZEBBPrRlC9Ph5sOzNKBaKdZ+GAy6UCqMYlFHSzq+0GsnO
|
||||
I1zCNn1XgpvX6V/31AVYPgiAQj6qMHuYxJR0pQG5kTeN3v+FdXR3
|
||||
-----END CERTIFICATE-----
|
||||
BIN
certs/test/cert-ext-ncip.der
Normal file
BIN
certs/test/cert-ext-ncip.der
Normal file
Binary file not shown.
25
certs/test/cert-ext-ncip.pem
Normal file
25
certs/test/cert-ext-ncip.pem
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENDCCAxygAwIBAgIUNQdk2FntK/mSUrXLLySPJwId8FowDQYJKoZIhvcNAQEL
|
||||
BQAwezELMAkGA1UEBhMCQVUxEzARBgNVBAgMClF1ZWVuc2xhbmQxETAPBgNVBAcM
|
||||
CEJyaXNiYW5lMRQwEgYDVQQKDAt3b2xmU1NMIEluYzEUMBIGA1UECwwLRW5naW5l
|
||||
ZXJpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTAeFw0yNjAxMjAyMjQ2MTFa
|
||||
Fw0yODEwMTYyMjQ2MTFaMHsxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApRdWVlbnNs
|
||||
YW5kMREwDwYDVQQHDAhCcmlzYmFuZTEUMBIGA1UECgwLd29sZlNTTCBJbmMxFDAS
|
||||
BgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20wggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAlQjhV0HycW230kVBJwFlxkWu
|
||||
8rwkMLiVzi9O1vYciLx8n/uoZ3/+XJxRdfeKygfnNS+P4b17wC98q2SoF/zKXXu6
|
||||
4CHlci5vLobYlXParBtTuV8/1xkNJU/hY2NRiwtkP61DuKUcXDSzrgCgY8X2fwtZ
|
||||
aHhzpowYqQJtr8MZAS64EOPGzEC0aaNGM2mHbsS7F6bz6N2tc7x7LyG1/WZRDL1U
|
||||
s+FtXxy8I3PRCQOJFNIQuWTDKtChlkq84dQaW8egwMFjeA9ENzAyloAyI5Whd7oT
|
||||
0pdz4l0lyWoNwzlgpLSwaUJCCenYCLwzILNYIqeq68Th5mGDxdKW39nQT63XAgMB
|
||||
AAGjga8wgawwHQYDVR0OBBYEFLMRMsmSmITiyfjQO24DQsofDo48MB8GA1UdIwQY
|
||||
MBaAFLMRMsmSmITiyfjQO24DQsofDo48MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD
|
||||
VR0PAQH/BAQDAgGGMBoGA1UdHgEB/wQQMA6gDDAKhwjAqAEA////ADAqBglghkgB
|
||||
hvhCAQ0EHRYbVGVzdGluZyBJUCBuYW1lIGNvbnN0cmFpbnRzMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQCOpK6M3RK5jcp2E3CaH9bTQfbcbppXJwFHdUG85sjf/K5i6c3/hr3X
|
||||
eKihdD+h62KgiUZFPrGzEDCLD26EWwiJJCkxakhjtY45r9luLXj3kpUMXQ3aeqXC
|
||||
M5rtW80w+9Hz0WEkK4UkaKEultWX8mnrF7dH/MHctyyLDcy28qbH5SwAhVqE1XAZ
|
||||
0j/1Mw0MsQd8ycpbmONhQEgXTVlHspvn/vBcKvGS6oimeTlgO+Ghlnt9eeQfFRT0
|
||||
y7MacpE2kULmzy8qzXxqVvQI2V66wz7xC/8BYzj/KBYGwi7e2LeGKU5eEV4622sR
|
||||
QtT99fpv0XMKNPMTI5Iz9l/ZPWvZgXJE
|
||||
-----END CERTIFICATE-----
|
||||
BIN
certs/test/cert-ext-ncmulti.der
Normal file
BIN
certs/test/cert-ext-ncmulti.der
Normal file
Binary file not shown.
27
certs/test/cert-ext-ncmulti.pem
Normal file
27
certs/test/cert-ext-ncmulti.pem
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEljCCA36gAwIBAgIUL0V4sh34dBCPx7JGnW1VkkjOB4wwDQYJKoZIhvcNAQEL
|
||||
BQAwezELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0Jv
|
||||
emVtYW4xFDASBgNVBAoMC3dvbGZTU0wgSW5jMRgwFgYDVQQLDA9EZXYgYW5kIFRl
|
||||
c3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTAeFw0yNjAxMjIyMTE4MjJa
|
||||
Fw0yODEwMTgyMTE4MjJaMHsxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5h
|
||||
MRAwDgYDVQQHDAdCb3plbWFuMRQwEgYDVQQKDAt3b2xmU1NMIEluYzEYMBYGA1UE
|
||||
CwwPRGV2IGFuZCBUZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20wggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAlQjhV0HycW230kVBJwFlxkWu
|
||||
8rwkMLiVzi9O1vYciLx8n/uoZ3/+XJxRdfeKygfnNS+P4b17wC98q2SoF/zKXXu6
|
||||
4CHlci5vLobYlXParBtTuV8/1xkNJU/hY2NRiwtkP61DuKUcXDSzrgCgY8X2fwtZ
|
||||
aHhzpowYqQJtr8MZAS64EOPGzEC0aaNGM2mHbsS7F6bz6N2tc7x7LyG1/WZRDL1U
|
||||
s+FtXxy8I3PRCQOJFNIQuWTDKtChlkq84dQaW8egwMFjeA9ENzAyloAyI5Whd7oT
|
||||
0pdz4l0lyWoNwzlgpLSwaUJCCenYCLwzILNYIqeq68Th5mGDxdKW39nQT63XAgMB
|
||||
AAGjggEQMIIBDDAdBgNVHQ4EFgQUsxEyyZKYhOLJ+NA7bgNCyh8OjjwwHwYDVR0j
|
||||
BBgwFoAUsxEyyZKYhOLJ+NA7bgNCyh8OjjwwEgYDVR0TAQH/BAgwBgEB/wIBADAO
|
||||
BgNVHQ8BAf8EBAMCAYYwYAYDVR0eAQH/BFYwVKAgMA6CDC5leGFtcGxlLmNvbTAO
|
||||
gQwuZXhhbXBsZS5jb22hMDAWghQuYmxvY2tlZC5leGFtcGxlLmNvbTAWgRQuYmxv
|
||||
Y2tlZC5leGFtcGxlLmNvbTBEBglghkgBhvhCAQ0ENxY1VGVzdGluZyBtaXhlZCBw
|
||||
ZXJtaXR0ZWQgYW5kIGV4Y2x1ZGVkIG5hbWUgY29uc3RyYWludHMwDQYJKoZIhvcN
|
||||
AQELBQADggEBAEULvBMSjm5ENjZ7WNDnSPXwKm3ka1eK7AUCTmZdMl3Op1ge/yqq
|
||||
rdkG2xvX4cfAe8iPOUDMyvh/Jf9B8T2njOGnpUTueslRzDvOs7qBo/0VYRalkye9
|
||||
Qw0ysgKcvvnevMHMnErGCkLEvL0VmTTmSR9HA8YxRih962fBrv38GZytqmFw/TEm
|
||||
s0KMQRumxQWPHHAQ/AbWbzCIXZo0kOsZlIZV3geCf9M0klDhG/XLgFJqihwGDeT4
|
||||
Yvy1mtqJu87LduC03UKKqbMR0ltTOkoCm5xTjKQuTbHxPBw2q8UVZ7Ud2iE47UXi
|
||||
c4Zd4IxO9TTO5SCQaZLPq0dhp3SxjgtZ3tw=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -81,7 +81,7 @@ rm -f ./certs/test/cert-ext-mnc.pem
|
||||
|
||||
|
||||
OUT=certs/test/cert-ext-ncdns
|
||||
KEYFILE=certs/test/cert-ext-nc-key.der
|
||||
KEYFILE=certs/test/cert-ext-ncdns-key.der
|
||||
CONFIG=certs/test/cert-ext-ncdns.cfg
|
||||
tee >$CONFIG <<EOF
|
||||
[ req ]
|
||||
@@ -108,11 +108,68 @@ nsComment = "Testing name constraints"
|
||||
EOF
|
||||
gen_cert
|
||||
rm -f ./certs/test/cert-ext-ncdns.cfg
|
||||
rm -f ./certs/test/cert-ext-ncdns.pem
|
||||
|
||||
OUT=certs/test/cert-ext-ncmixed
|
||||
KEYFILE=certs/test/cert-ext-ncmixed-key.der
|
||||
CONFIG=certs/test/cert-ext-ncmixed.cfg
|
||||
OUT=certs/test/cert-ext-nc-combined
|
||||
KEYFILE=certs/test/cert-ext-nc-combined-key.der
|
||||
CONFIG=certs/test/cert-ext-nc-combined.cfg
|
||||
tee >$CONFIG <<EOF
|
||||
[ req ]
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = US
|
||||
ST = Montana
|
||||
L = Bozeman
|
||||
O = wolfSSL Inc
|
||||
OU = Dev and Testing
|
||||
CN = www.wolfssl.com
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
nameConstraints = critical,permitted;URI:.wolfssl.com,permitted;DNS:.wolfssl.com
|
||||
nsComment = "Testing combined URI and DNS name constraints"
|
||||
|
||||
EOF
|
||||
gen_cert
|
||||
rm -f ./certs/test/cert-ext-nc-combined.cfg
|
||||
|
||||
OUT=certs/test/cert-ext-ncmulti
|
||||
KEYFILE=certs/test/cert-ext-ncmulti-key.der
|
||||
CONFIG=certs/test/cert-ext-ncmulti.cfg
|
||||
tee >$CONFIG <<EOF
|
||||
[ req ]
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = US
|
||||
ST = Montana
|
||||
L = Bozeman
|
||||
O = wolfSSL Inc
|
||||
OU = Dev and Testing
|
||||
CN = www.wolfssl.com
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
nameConstraints = critical,permitted;DNS:.example.com,permitted;email:.example.com,excluded;DNS:.blocked.example.com,excluded;email:.blocked.example.com
|
||||
nsComment = "Testing mixed permitted and excluded name constraints"
|
||||
|
||||
EOF
|
||||
gen_cert
|
||||
rm -f ./certs/test/cert-ext-ncmulti.cfg
|
||||
|
||||
OUT=certs/test/cert-ext-ncip
|
||||
KEYFILE=certs/test/cert-ext-ncip-key.der
|
||||
CONFIG=certs/test/cert-ext-ncip.cfg
|
||||
tee >$CONFIG <<EOF
|
||||
[ req ]
|
||||
distinguished_name = req_distinguished_name
|
||||
@@ -132,13 +189,12 @@ subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
nameConstraints = critical,permitted;DNS:example, permitted;email:.wolfssl.com
|
||||
nsComment = "Testing name constraints"
|
||||
nameConstraints = critical,permitted;IP:192.168.1.0/255.255.255.0
|
||||
nsComment = "Testing IP name constraints"
|
||||
|
||||
EOF
|
||||
gen_cert
|
||||
rm -f ./certs/test/cert-ext-ncmixed.cfg
|
||||
rm -f ./certs/test/cert-ext-ncmixed.pem
|
||||
rm -f ./certs/test/cert-ext-ncip.cfg
|
||||
|
||||
OUT=certs/test/cert-ext-ia
|
||||
KEYFILE=certs/test/cert-ext-ia-key.der
|
||||
|
||||
@@ -9,7 +9,14 @@ EXTRA_DIST += \
|
||||
certs/test/cert-ext-nc.cfg \
|
||||
certs/test/cert-ext-nc.der \
|
||||
certs/test/cert-ext-nc.pem \
|
||||
certs/test/cert-ext-nc-combined.der \
|
||||
certs/test/cert-ext-nc-combined.pem \
|
||||
certs/test/cert-ext-ncip.der \
|
||||
certs/test/cert-ext-ncip.pem \
|
||||
certs/test/cert-ext-ncdns.der \
|
||||
certs/test/cert-ext-ncdns.pem \
|
||||
certs/test/cert-ext-ncmulti.der \
|
||||
certs/test/cert-ext-ncmulti.pem \
|
||||
certs/test/cert-ext-ncmixed.der \
|
||||
certs/test/cert-ext-mnc.der \
|
||||
certs/test/cert-ext-nct.cfg \
|
||||
|
||||
@@ -4894,6 +4894,16 @@ void FreeX509(WOLFSSL_X509* x509)
|
||||
FreeAltNames(x509->altNames, x509->heap);
|
||||
x509->altNames = NULL;
|
||||
}
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
if (x509->permittedNames) {
|
||||
FreeNameSubtrees(x509->permittedNames, x509->heap);
|
||||
x509->permittedNames = NULL;
|
||||
}
|
||||
if (x509->excludedNames) {
|
||||
FreeNameSubtrees(x509->excludedNames, x509->heap);
|
||||
x509->excludedNames = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DUAL_ALG_CERTS
|
||||
XFREE(x509->sapkiDer, x509->heap, DYNAMIC_TYPE_X509_EXT);
|
||||
@@ -13391,6 +13401,62 @@ static void AddSessionCertToChain(WOLFSSL_X509_CHAIN* chain,
|
||||
* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL ||
|
||||
* WOLFSSL_ACERT */
|
||||
|
||||
#if (defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \
|
||||
defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
|
||||
!defined(IGNORE_NAME_CONSTRAINTS)
|
||||
/* Duplicate a Base_entry */
|
||||
static Base_entry* BaseEntryDup(Base_entry* from, void* heap)
|
||||
{
|
||||
Base_entry* entry;
|
||||
|
||||
if (from == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry = (Base_entry*)XMALLOC(sizeof(Base_entry), heap,
|
||||
DYNAMIC_TYPE_ALTNAME);
|
||||
if (entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
XMEMSET(entry, 0, sizeof(Base_entry));
|
||||
|
||||
entry->name = (char*)XMALLOC((word32)from->nameSz + 1, heap,
|
||||
DYNAMIC_TYPE_ALTNAME);
|
||||
if (entry->name == NULL) {
|
||||
XFREE(entry, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
return NULL;
|
||||
}
|
||||
XMEMCPY(entry->name, from->name, (word32)from->nameSz);
|
||||
entry->name[from->nameSz] = '\0';
|
||||
entry->nameSz = from->nameSz;
|
||||
entry->type = from->type;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Copy a Base_entry list */
|
||||
static int CopyBaseEntry(Base_entry** to, Base_entry* from, void* heap)
|
||||
{
|
||||
Base_entry** next = to;
|
||||
|
||||
if (to == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
for (; from != NULL; from = from->next) {
|
||||
Base_entry* entry = BaseEntryDup(from, heap);
|
||||
if (entry == NULL) {
|
||||
WOLFSSL_MSG("BaseEntryDup failed");
|
||||
return MEMORY_E;
|
||||
}
|
||||
*next = entry;
|
||||
next = &entry->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* (KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA ||
|
||||
* OPENSSL_EXTRA_X509_SMALL) && !IGNORE_NAME_CONSTRAINTS */
|
||||
|
||||
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \
|
||||
defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
|
||||
@@ -13727,6 +13793,23 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
|
||||
#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
|
||||
x509->altNamesNext = x509->altNames; /* index hint */
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
/* copy name constraints from dCert to X509 */
|
||||
if (dCert->permittedNames != NULL) {
|
||||
if (CopyBaseEntry(&x509->permittedNames, dCert->permittedNames,
|
||||
x509->heap) != 0) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
}
|
||||
if (dCert->excludedNames != NULL) {
|
||||
if (CopyBaseEntry(&x509->excludedNames, dCert->excludedNames,
|
||||
x509->heap) != 0) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
}
|
||||
x509->nameConstraintCrit = dCert->extNameConstraintCrit;
|
||||
#endif /* !IGNORE_NAME_CONSTRAINTS */
|
||||
|
||||
x509->isCa = dCert->isCA;
|
||||
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
|
||||
x509->basicConstCrit = dCert->extBasicConstCrit;
|
||||
|
||||
10
src/ssl_sk.c
10
src/ssl_sk.c
@@ -168,6 +168,7 @@ static void* wolfssl_sk_node_get_data(WOLFSSL_STACK* node, int no_static)
|
||||
case STACK_TYPE_X509_OBJ:
|
||||
case STACK_TYPE_DIST_POINT:
|
||||
case STACK_TYPE_X509_CRL:
|
||||
case STACK_TYPE_GENERAL_SUBTREE:
|
||||
default:
|
||||
ret = node->data.generic;
|
||||
break;
|
||||
@@ -212,6 +213,7 @@ static void wolfssl_sk_node_set_data(WOLFSSL_STACK* node, WOLF_STACK_TYPE type,
|
||||
case STACK_TYPE_X509_OBJ:
|
||||
case STACK_TYPE_DIST_POINT:
|
||||
case STACK_TYPE_X509_CRL:
|
||||
case STACK_TYPE_GENERAL_SUBTREE:
|
||||
default:
|
||||
node->data.generic = (void*)data;
|
||||
#ifdef OPENSSL_ALL
|
||||
@@ -430,6 +432,7 @@ static int wolfssl_sk_dup_data(WOLFSSL_STACK* dst, WOLFSSL_STACK* src)
|
||||
case STACK_TYPE_BY_DIR_hash:
|
||||
case STACK_TYPE_DIST_POINT:
|
||||
case STACK_TYPE_X509_CRL:
|
||||
case STACK_TYPE_GENERAL_SUBTREE:
|
||||
default:
|
||||
WOLFSSL_MSG("Unsupported stack type");
|
||||
err = 1;
|
||||
@@ -622,6 +625,7 @@ void* wolfSSL_sk_value(const WOLFSSL_STACK* sk, int i)
|
||||
case STACK_TYPE_X509_OBJ:
|
||||
case STACK_TYPE_DIST_POINT:
|
||||
case STACK_TYPE_X509_CRL:
|
||||
case STACK_TYPE_GENERAL_SUBTREE:
|
||||
default:
|
||||
val = sk->data.generic;
|
||||
break;
|
||||
@@ -806,6 +810,12 @@ static wolfSSL_sk_freefunc wolfssl_sk_get_free_func(WOLF_STACK_TYPE type)
|
||||
case STACK_TYPE_GEN_NAME:
|
||||
func = (wolfSSL_sk_freefunc)wolfSSL_GENERAL_NAME_free;
|
||||
break;
|
||||
case STACK_TYPE_GENERAL_SUBTREE:
|
||||
#if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \
|
||||
!defined(WOLFSSL_LINUXKM)
|
||||
func = (wolfSSL_sk_freefunc)wolfSSL_GENERAL_SUBTREE_free;
|
||||
#endif
|
||||
break;
|
||||
case STACK_TYPE_STRING:
|
||||
#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
|
||||
defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
|
||||
|
||||
586
src/x509.c
586
src/x509.c
@@ -2218,6 +2218,160 @@ out:
|
||||
|
||||
#endif /* OPENSSL_ALL || OPENSSL_EXTRA */
|
||||
|
||||
#if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \
|
||||
!defined(WOLFSSL_LINUXKM)
|
||||
/*
|
||||
* Convert a Base_entry linked list to a STACK of GENERAL_SUBTREE.
|
||||
*
|
||||
* Base_entry stores name constraint data from DecodedCert. This function
|
||||
* converts it to GENERAL_SUBTREE format.
|
||||
*
|
||||
* Supported types: ASN_DNS_TYPE, ASN_RFC822_TYPE, ASN_DIR_TYPE, ASN_IP_TYPE,
|
||||
* ASN_URI_TYPE
|
||||
*
|
||||
* Returns 0 on success, negative on error.
|
||||
*/
|
||||
static int ConvertBaseEntryToSubtreeStack(Base_entry* list, WOLFSSL_STACK* sk,
|
||||
void* heap)
|
||||
{
|
||||
Base_entry* entry = list;
|
||||
WOLFSSL_GENERAL_SUBTREE* subtree = NULL;
|
||||
WOLFSSL_GENERAL_NAME* gn = NULL;
|
||||
(void)heap;
|
||||
|
||||
while (entry != NULL) {
|
||||
|
||||
if (entry->type != ASN_DNS_TYPE && entry->type != ASN_RFC822_TYPE &&
|
||||
entry->type != ASN_DIR_TYPE && entry->type != ASN_IP_TYPE &&
|
||||
entry->type != ASN_URI_TYPE) {
|
||||
entry = entry->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allocate subtree and general name */
|
||||
subtree = (WOLFSSL_GENERAL_SUBTREE*)XMALLOC(
|
||||
sizeof(WOLFSSL_GENERAL_SUBTREE), heap, DYNAMIC_TYPE_OPENSSL);
|
||||
if (subtree == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate GENERAL_SUBTREE");
|
||||
return MEMORY_E;
|
||||
}
|
||||
XMEMSET(subtree, 0, sizeof(WOLFSSL_GENERAL_SUBTREE));
|
||||
|
||||
gn = wolfSSL_GENERAL_NAME_new();
|
||||
if (gn == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate GENERAL_NAME");
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
/* Free default ia5 string allocated by GENERAL_NAME_new */
|
||||
wolfSSL_ASN1_STRING_free(gn->d.ia5);
|
||||
gn->d.ia5 = NULL;
|
||||
|
||||
switch (entry->type) {
|
||||
case ASN_DNS_TYPE:
|
||||
case ASN_RFC822_TYPE:
|
||||
case ASN_URI_TYPE:
|
||||
{
|
||||
if (entry->type == ASN_DNS_TYPE) {
|
||||
gn->type = WOLFSSL_GEN_DNS;
|
||||
}
|
||||
else if (entry->type == ASN_RFC822_TYPE) {
|
||||
gn->type = WOLFSSL_GEN_EMAIL;
|
||||
}
|
||||
else {
|
||||
gn->type = WOLFSSL_GEN_URI;
|
||||
}
|
||||
gn->d.ia5 = wolfSSL_ASN1_STRING_new();
|
||||
if (gn->d.ia5 == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate ASN1_STRING");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
if (wolfSSL_ASN1_STRING_set(gn->d.ia5, entry->name,
|
||||
entry->nameSz) != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("Failed to set ASN1_STRING");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
gn->d.ia5->type = WOLFSSL_V_ASN1_IA5STRING;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASN_DIR_TYPE:
|
||||
{
|
||||
byte* seqBuf = NULL;
|
||||
unsigned char* p = NULL;
|
||||
int seqLen = 0;
|
||||
|
||||
/* Wrap in SEQUENCE and parse as X509_NAME */
|
||||
gn->type = WOLFSSL_GEN_DIRNAME;
|
||||
seqBuf = (byte*)XMALLOC((word32)entry->nameSz + MAX_SEQ_SZ,
|
||||
heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (seqBuf == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate sequence buffer");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
seqLen = SetSequence(entry->nameSz, seqBuf);
|
||||
XMEMCPY(seqBuf + seqLen, entry->name, entry->nameSz);
|
||||
|
||||
p = seqBuf;
|
||||
gn->d.directoryName = wolfSSL_d2i_X509_NAME(NULL, &p,
|
||||
(long)entry->nameSz + seqLen);
|
||||
XFREE(seqBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
if (gn->d.directoryName == NULL) {
|
||||
WOLFSSL_MSG("Failed to parse directoryName");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASN_IP_TYPE:
|
||||
{
|
||||
/* For IP address, store raw bytes as OCTET_STRING. */
|
||||
gn->type = WOLFSSL_GEN_IPADD;
|
||||
gn->d.iPAddress = wolfSSL_ASN1_STRING_new();
|
||||
if (gn->d.iPAddress == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate ASN1_STRING for IP");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
if (wolfSSL_ASN1_STRING_set(gn->d.iPAddress, entry->name,
|
||||
entry->nameSz) != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("Failed to set IP ASN1_STRING");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
gn->d.iPAddress->type = WOLFSSL_V_ASN1_OCTET_STRING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
subtree->base = gn;
|
||||
|
||||
if (wolfSSL_sk_push(sk, subtree) <= 0) {
|
||||
WOLFSSL_MSG("Failed to push subtree onto stack");
|
||||
wolfSSL_GENERAL_NAME_free(gn);
|
||||
XFREE(subtree, heap, DYNAMIC_TYPE_OPENSSL);
|
||||
return MEMORY_E;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* OPENSSL_EXTRA && !IGNORE_NAME_CONSTRAINTS && !WOLFSSL_LINUXKM */
|
||||
|
||||
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
|
||||
/* Looks for the extension matching the passed in nid
|
||||
*
|
||||
@@ -2720,9 +2874,70 @@ void* wolfSSL_X509_get_ext_d2i(const WOLFSSL_X509* x509, int nid, int* c,
|
||||
}
|
||||
break;
|
||||
|
||||
#if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \
|
||||
!defined(WOLFSSL_LINUXKM)
|
||||
case NAME_CONS_OID:
|
||||
WOLFSSL_MSG("Name Constraint OID extension not supported");
|
||||
break;
|
||||
{
|
||||
WOLFSSL_NAME_CONSTRAINTS* nc = NULL;
|
||||
|
||||
/* Check if name constraints exist in stored X509 */
|
||||
if (x509->permittedNames == NULL && x509->excludedNames == NULL) {
|
||||
WOLFSSL_MSG("No Name Constraints set");
|
||||
break;
|
||||
}
|
||||
|
||||
if (c != NULL) {
|
||||
*c = x509->nameConstraintCrit;
|
||||
}
|
||||
|
||||
nc = (WOLFSSL_NAME_CONSTRAINTS*)XMALLOC(
|
||||
sizeof(WOLFSSL_NAME_CONSTRAINTS), x509->heap,
|
||||
DYNAMIC_TYPE_OPENSSL);
|
||||
if (nc == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate NAME_CONSTRAINTS");
|
||||
break;
|
||||
}
|
||||
XMEMSET(nc, 0, sizeof(WOLFSSL_NAME_CONSTRAINTS));
|
||||
|
||||
/* Convert permitted names */
|
||||
if (x509->permittedNames != NULL) {
|
||||
nc->permittedSubtrees = wolfSSL_sk_new_null();
|
||||
if (nc->permittedSubtrees == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate permitted stack");
|
||||
wolfSSL_NAME_CONSTRAINTS_free(nc);
|
||||
break;
|
||||
}
|
||||
nc->permittedSubtrees->type = STACK_TYPE_GENERAL_SUBTREE;
|
||||
|
||||
if (ConvertBaseEntryToSubtreeStack(x509->permittedNames,
|
||||
nc->permittedSubtrees, x509->heap) != 0) {
|
||||
WOLFSSL_MSG("Failed to convert permitted names");
|
||||
wolfSSL_NAME_CONSTRAINTS_free(nc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert excluded names */
|
||||
if (x509->excludedNames != NULL) {
|
||||
nc->excludedSubtrees = wolfSSL_sk_new_null();
|
||||
if (nc->excludedSubtrees == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate excluded stack");
|
||||
wolfSSL_NAME_CONSTRAINTS_free(nc);
|
||||
break;
|
||||
}
|
||||
nc->excludedSubtrees->type = STACK_TYPE_GENERAL_SUBTREE;
|
||||
|
||||
if (ConvertBaseEntryToSubtreeStack(x509->excludedNames,
|
||||
nc->excludedSubtrees, x509->heap) != 0) {
|
||||
WOLFSSL_MSG("Failed to convert excluded names");
|
||||
wolfSSL_NAME_CONSTRAINTS_free(nc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nc;
|
||||
}
|
||||
#endif /* OPENSSL_EXTRA && !IGNORE_NAME_CONSTRAINTS && !WOLFSSL_LINUXKM */
|
||||
|
||||
case PRIV_KEY_USAGE_PERIOD_OID:
|
||||
WOLFSSL_MSG("Private Key Usage Period extension not supported");
|
||||
@@ -5112,6 +5327,373 @@ void wolfSSL_EXTENDED_KEY_USAGE_free(WOLFSSL_STACK * sk)
|
||||
wolfSSL_sk_X509_pop_free(sk, NULL);
|
||||
}
|
||||
|
||||
#if !defined(IGNORE_NAME_CONSTRAINTS) && !defined(WOLFSSL_LINUXKM)
|
||||
/*
|
||||
* Allocate and initialize an empty GENERAL_SUBTREE structure.
|
||||
* Returns NULL on allocation failure.
|
||||
*/
|
||||
WOLFSSL_GENERAL_SUBTREE* wolfSSL_GENERAL_SUBTREE_new(void)
|
||||
{
|
||||
WOLFSSL_GENERAL_SUBTREE* subtree;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_GENERAL_SUBTREE_new");
|
||||
|
||||
subtree = (WOLFSSL_GENERAL_SUBTREE*)XMALLOC(sizeof(WOLFSSL_GENERAL_SUBTREE),
|
||||
NULL, DYNAMIC_TYPE_OPENSSL);
|
||||
if (subtree == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate GENERAL_SUBTREE");
|
||||
return NULL;
|
||||
}
|
||||
XMEMSET(subtree, 0, sizeof(WOLFSSL_GENERAL_SUBTREE));
|
||||
return subtree;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an empty NAME_CONSTRAINTS structure.
|
||||
* Returns NULL on allocation failure.
|
||||
*/
|
||||
WOLFSSL_NAME_CONSTRAINTS* wolfSSL_NAME_CONSTRAINTS_new(void)
|
||||
{
|
||||
WOLFSSL_NAME_CONSTRAINTS* nc;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_NAME_CONSTRAINTS_new");
|
||||
|
||||
nc = (WOLFSSL_NAME_CONSTRAINTS*)XMALLOC(sizeof(WOLFSSL_NAME_CONSTRAINTS),
|
||||
NULL, DYNAMIC_TYPE_OPENSSL);
|
||||
if (nc == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate NAME_CONSTRAINTS");
|
||||
return NULL;
|
||||
}
|
||||
XMEMSET(nc, 0, sizeof(WOLFSSL_NAME_CONSTRAINTS));
|
||||
return nc;
|
||||
}
|
||||
|
||||
/* Free a GENERAL_SUBTREE and its contents. */
|
||||
void wolfSSL_GENERAL_SUBTREE_free(WOLFSSL_GENERAL_SUBTREE* subtree)
|
||||
{
|
||||
if (subtree == NULL) {
|
||||
return;
|
||||
}
|
||||
wolfSSL_GENERAL_NAME_free(subtree->base);
|
||||
XFREE(subtree, NULL, DYNAMIC_TYPE_OPENSSL);
|
||||
}
|
||||
|
||||
/* Free a NAME_CONSTRAINTS structure and all its contents. */
|
||||
void wolfSSL_NAME_CONSTRAINTS_free(WOLFSSL_NAME_CONSTRAINTS* nc)
|
||||
{
|
||||
WOLFSSL_ENTER("wolfSSL_NAME_CONSTRAINTS_free");
|
||||
|
||||
if (nc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nc->permittedSubtrees != NULL) {
|
||||
wolfSSL_sk_pop_free(nc->permittedSubtrees,
|
||||
(wolfSSL_sk_freefunc)wolfSSL_GENERAL_SUBTREE_free);
|
||||
}
|
||||
|
||||
if (nc->excludedSubtrees != NULL) {
|
||||
wolfSSL_sk_pop_free(nc->excludedSubtrees,
|
||||
(wolfSSL_sk_freefunc)wolfSSL_GENERAL_SUBTREE_free);
|
||||
}
|
||||
|
||||
XFREE(nc, NULL, DYNAMIC_TYPE_OPENSSL);
|
||||
}
|
||||
|
||||
/* Get number of items in GENERAL_SUBTREE stack. */
|
||||
int wolfSSL_sk_GENERAL_SUBTREE_num(const WOLFSSL_STACK* sk)
|
||||
{
|
||||
WOLFSSL_ENTER("wolfSSL_sk_GENERAL_SUBTREE_num");
|
||||
|
||||
return wolfSSL_sk_num(sk);
|
||||
}
|
||||
|
||||
/* Get GENERAL_SUBTREE at index from stack. */
|
||||
WOLFSSL_GENERAL_SUBTREE* wolfSSL_sk_GENERAL_SUBTREE_value(
|
||||
const WOLFSSL_STACK* sk, int idx)
|
||||
{
|
||||
WOLFSSL_ENTER("wolfSSL_sk_GENERAL_SUBTREE_value");
|
||||
|
||||
return (WOLFSSL_GENERAL_SUBTREE*)wolfSSL_sk_value(sk, idx);
|
||||
}
|
||||
|
||||
/* Check IP address string matches constraint.
|
||||
*
|
||||
* name: IP address string (ex "192.168.1.50")
|
||||
* nameSz: length of name string
|
||||
* gn: GENERAL_NAME containing IP constraint (IP + mask bytes)
|
||||
*
|
||||
* Return 1 on match, otherwise 0
|
||||
*/
|
||||
static int MatchIpName(const char* name, int nameSz, WOLFSSL_GENERAL_NAME* gn)
|
||||
{
|
||||
int ipLen = 0;
|
||||
int constraintLen;
|
||||
char ipStr[WOLFSSL_MAX_IPSTR];
|
||||
unsigned char ipBytes[16]; /* Max 16 bytes for IPv6 */
|
||||
const unsigned char* constraintData;
|
||||
|
||||
if (name == NULL || nameSz <= 0 || gn == NULL || gn->d.iPAddress == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constraintData = wolfSSL_ASN1_STRING_get0_data(gn->d.iPAddress);
|
||||
constraintLen = wolfSSL_ASN1_STRING_length(gn->d.iPAddress);
|
||||
if (constraintData == NULL || constraintLen <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Null-terminate IP string */
|
||||
if (nameSz >= (int)sizeof(ipStr)) {
|
||||
return 0;
|
||||
}
|
||||
XMEMCPY(ipStr, name, nameSz);
|
||||
ipStr[nameSz] = '\0';
|
||||
|
||||
/* IPv4 constraint 8 bytes (IP + mask),
|
||||
* IPv6 constraint 32 bytes (IP + mask) */
|
||||
if (constraintLen == 8) {
|
||||
if (XINET_PTON(WOLFSSL_IP4, ipStr, ipBytes) == 1) {
|
||||
ipLen = 4;
|
||||
}
|
||||
}
|
||||
else if (constraintLen == 32) {
|
||||
if (XINET_PTON(WOLFSSL_IP6, ipStr, ipBytes) == 1) {
|
||||
ipLen = 16;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipLen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wolfssl_local_MatchIpSubnet(ipBytes, ipLen,
|
||||
constraintData, constraintLen);
|
||||
}
|
||||
|
||||
/* Extract host from URI for name constraint matching.
|
||||
* URI format: scheme://[userinfo@]host[:port][/path][?query][#fragment]
|
||||
* IPv6 literals are enclosed in brackets: scheme://[ipv6addr]:port/path
|
||||
* Returns pointer to host start and sets hostLen, or NULL on failure. */
|
||||
static const char* ExtractHostFromUri(const char* uri, int uriLen, int* hostLen)
|
||||
{
|
||||
const char* hostStart;
|
||||
const char* hostEnd;
|
||||
const char* p;
|
||||
const char* uriEnd = uri + uriLen;
|
||||
|
||||
if (uri == NULL || uriLen <= 0 || hostLen == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find "://" to skip scheme */
|
||||
hostStart = NULL;
|
||||
for (p = uri; p < uriEnd - 2; p++) {
|
||||
if (p[0] == ':' && p[1] == '/' && p[2] == '/') {
|
||||
hostStart = p + 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hostStart == NULL || hostStart >= uriEnd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Skip userinfo if present (look for @ before any /, ?, #)
|
||||
* userinfo can contain ':' (ex: user:pass@host), don't stop at ':'
|
||||
* For IPv6, also don't stop at '[' in userinfo */
|
||||
for (p = hostStart; p < uriEnd; p++) {
|
||||
if (*p == '@') {
|
||||
hostStart = p + 1;
|
||||
break;
|
||||
}
|
||||
if (*p == '/' || *p == '?' || *p == '#') {
|
||||
/* No userinfo found */
|
||||
break;
|
||||
}
|
||||
/* If '[' before '@', found IPv6 literal, not userinfo */
|
||||
if (*p == '[') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hostStart >= uriEnd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check for IPv6 literal */
|
||||
if (*hostStart == '[') {
|
||||
/* Find closing bracket, skip opening one */
|
||||
hostStart++;
|
||||
hostEnd = hostStart;
|
||||
while (hostEnd < uriEnd && *hostEnd != ']') {
|
||||
hostEnd++;
|
||||
}
|
||||
if (hostEnd >= uriEnd) {
|
||||
/* No closing bracket found, malformed */
|
||||
return NULL;
|
||||
}
|
||||
/* hostEnd points to closing bracket, extract content between */
|
||||
*hostLen = (int)(hostEnd - hostStart);
|
||||
if (*hostLen <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return hostStart;
|
||||
}
|
||||
|
||||
/* Regular hostname, find end */
|
||||
hostEnd = hostStart;
|
||||
while (hostEnd < uriEnd && *hostEnd != ':' && *hostEnd != '/' &&
|
||||
*hostEnd != '?' && *hostEnd != '#') {
|
||||
hostEnd++;
|
||||
}
|
||||
|
||||
*hostLen = (int)(hostEnd - hostStart);
|
||||
if (*hostLen <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hostStart;
|
||||
}
|
||||
|
||||
/* Helper to check if name string matches a single GENERAL_NAME constraint.
|
||||
* Returns 1 if matches, 0 if not. */
|
||||
static int MatchNameConstraint(int type, const char* name, int nameSz,
|
||||
WOLFSSL_GENERAL_NAME* gn)
|
||||
{
|
||||
const char* baseStr;
|
||||
int baseLen;
|
||||
|
||||
if (gn == NULL || gn->type != type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case WOLFSSL_GEN_IPADD:
|
||||
return MatchIpName(name, nameSz, gn);
|
||||
|
||||
case WOLFSSL_GEN_DNS:
|
||||
case WOLFSSL_GEN_EMAIL:
|
||||
case WOLFSSL_GEN_URI:
|
||||
if (gn->d.ia5 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
baseStr = (const char*)wolfSSL_ASN1_STRING_get0_data(gn->d.ia5);
|
||||
baseLen = wolfSSL_ASN1_STRING_length(gn->d.ia5);
|
||||
if (baseStr == NULL || baseLen <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type == WOLFSSL_GEN_EMAIL) {
|
||||
return wolfssl_local_MatchBaseName(ASN_RFC822_TYPE, name,
|
||||
nameSz, baseStr, baseLen);
|
||||
}
|
||||
else if (type == WOLFSSL_GEN_URI) {
|
||||
const char* host;
|
||||
int hostLen;
|
||||
|
||||
/* For URI, extract host and match against DNS-style */
|
||||
host = ExtractHostFromUri(name, nameSz, &hostLen);
|
||||
if (host == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return wolfssl_local_MatchBaseName(ASN_DNS_TYPE, host, hostLen,
|
||||
baseStr, baseLen);
|
||||
}
|
||||
else {
|
||||
/* WOLFSSL_GEN_DNS uses DNS-style matching */
|
||||
return wolfssl_local_MatchBaseName(ASN_DNS_TYPE, name, nameSz,
|
||||
baseStr, baseLen);
|
||||
}
|
||||
|
||||
default:
|
||||
/* Unsupported type */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a name string satisfies given name constraints.
|
||||
*
|
||||
* nc: NAME_CONSTRAINTS struct containing permitted/excluded subtrees
|
||||
* type: GeneralName type (WOLFSSL_GEN_DNS, WOLFSSL_GEN_EMAIL, etc.)
|
||||
* name: The name string to check
|
||||
* nameSz: Length of name string
|
||||
*
|
||||
* Returns 1 if name satisfies constraints (permitted and not excluded),
|
||||
* otherwise 0 if name does not satisfy constraints or on error
|
||||
*
|
||||
* A name satisfies constraints if permitted subtrees exist for the type,
|
||||
* name matches at least one, and name does not match any excluded subtree.
|
||||
*/
|
||||
int wolfSSL_NAME_CONSTRAINTS_check_name(WOLFSSL_NAME_CONSTRAINTS* nc,
|
||||
int type, const char* name, int nameSz)
|
||||
{
|
||||
int i, num;
|
||||
int hasPermittedType = 0;
|
||||
int matchedPermitted = 0;
|
||||
WOLFSSL_GENERAL_SUBTREE* subtree;
|
||||
WOLFSSL_GENERAL_NAME* gn;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_NAME_CONSTRAINTS_check_name");
|
||||
|
||||
if (nc == NULL || name == NULL || nameSz <= 0) {
|
||||
WOLFSSL_MSG("Bad argument to NAME_CONSTRAINTS_check_name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check permitted subtrees */
|
||||
if (nc->permittedSubtrees != NULL) {
|
||||
num = wolfSSL_sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
|
||||
for (i = 0; i < num; i++) {
|
||||
subtree = wolfSSL_sk_GENERAL_SUBTREE_value(
|
||||
nc->permittedSubtrees, i);
|
||||
if (subtree == NULL || subtree->base == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gn = subtree->base;
|
||||
if (gn->type != type) {
|
||||
continue;
|
||||
}
|
||||
hasPermittedType = 1;
|
||||
|
||||
if (MatchNameConstraint(type, name, nameSz, gn)) {
|
||||
matchedPermitted = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If permitted constraints exist for this type but none matched, fail */
|
||||
if (hasPermittedType && !matchedPermitted) {
|
||||
WOLFSSL_MSG("Name not in permitted subtrees");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check excluded subtrees */
|
||||
if (nc->excludedSubtrees != NULL) {
|
||||
num = wolfSSL_sk_GENERAL_SUBTREE_num(nc->excludedSubtrees);
|
||||
for (i = 0; i < num; i++) {
|
||||
subtree = wolfSSL_sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
|
||||
if (subtree == NULL || subtree->base == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gn = subtree->base;
|
||||
if (gn->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MatchNameConstraint(type, name, nameSz, gn)) {
|
||||
WOLFSSL_MSG("Name in excluded subtrees");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* !IGNORE_NAME_CONSTRAINTS && !WOLFSSL_LINUXKM */
|
||||
|
||||
#if defined(OPENSSL_ALL) && !defined(NO_BIO)
|
||||
/* Outputs name string of the given WOLFSSL_GENERAL_NAME_OBJECT to WOLFSSL_BIO.
|
||||
* Can handle following GENERAL_NAME_OBJECT types:
|
||||
|
||||
@@ -1549,3 +1549,727 @@ int test_wolfSSL_X509V3_EXT_print(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test retrieving Name Constraints extension via X509_get_ext_d2i.
|
||||
* Tests basic retrieval of permitted and excluded subtrees, stack operations
|
||||
* (num, value), GENERAL_NAME type and data extraction, free functions.
|
||||
*/
|
||||
int test_wolfSSL_X509_get_ext_d2i_name_constraints(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
GENERAL_SUBTREE* subtree = NULL;
|
||||
GENERAL_NAME* gn = NULL;
|
||||
int numPermitted = 0;
|
||||
int numExcluded = 0;
|
||||
int critical = -1;
|
||||
|
||||
/* Test NULL input handling */
|
||||
ExpectNull(X509_get_ext_d2i(NULL, NID_name_constraints, NULL, NULL));
|
||||
|
||||
/* Test certificate without name constraints
|
||||
* server-cert.pem does not have name constraints extension */
|
||||
ExpectTrue((f = XFOPEN("./certs/server-cert.pem", "rb")) != XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
/* Should return NULL for certificate without name constraints */
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
&critical, NULL);
|
||||
ExpectNull(nc);
|
||||
X509_free(x509);
|
||||
x509 = NULL;
|
||||
|
||||
/* Test certificate with permitted email name constraint.
|
||||
* cert-ext-nc.pem has nameConstraints with permitted email */
|
||||
ExpectTrue((f = XFOPEN("./certs/test/cert-ext-nc.pem", "rb")) != XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
critical = -1;
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
&critical, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
/* Verify critical flag is set (cert marks it critical) */
|
||||
ExpectIntEQ(critical, 1);
|
||||
|
||||
/* Check permitted subtrees */
|
||||
if (nc != NULL) {
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
if (nc->permittedSubtrees != NULL) {
|
||||
numPermitted = sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
|
||||
ExpectIntGT(numPermitted, 0);
|
||||
|
||||
/* Get first permitted subtree */
|
||||
subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 0);
|
||||
ExpectNotNull(subtree);
|
||||
if (subtree != NULL) {
|
||||
ExpectNotNull(subtree->base);
|
||||
if (subtree->base != NULL) {
|
||||
/* Check GENERAL_NAME type is GEN_EMAIL */
|
||||
gn = subtree->base;
|
||||
ExpectIntEQ(gn->type, GEN_EMAIL);
|
||||
|
||||
/* Verify email constraint value */
|
||||
ExpectNotNull(gn->d.ia5);
|
||||
if (gn->d.ia5 != NULL) {
|
||||
ExpectNotNull(gn->d.ia5->data);
|
||||
ExpectIntGT(gn->d.ia5->length, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check excluded subtrees, should be NULL or empty */
|
||||
if (nc->excludedSubtrees != NULL) {
|
||||
numExcluded = sk_GENERAL_SUBTREE_num(nc->excludedSubtrees);
|
||||
ExpectIntEQ(numExcluded, 0);
|
||||
}
|
||||
|
||||
/* Test out of bounds access */
|
||||
if (nc->permittedSubtrees != NULL) {
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 100));
|
||||
}
|
||||
}
|
||||
|
||||
/* Test NULL stack handling, wolfSSL returns 0 */
|
||||
ExpectIntEQ(sk_GENERAL_SUBTREE_num(NULL), 0);
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(NULL, 0));
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
nc = NULL;
|
||||
X509_free(x509);
|
||||
x509 = NULL;
|
||||
|
||||
/* Test free functions with NULL */
|
||||
NAME_CONSTRAINTS_free(NULL);
|
||||
wolfSSL_GENERAL_SUBTREE_free(NULL);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test sk_GENERAL_SUBTREE_num and sk_GENERAL_SUBTREE_value functions.
|
||||
*/
|
||||
int test_wolfSSL_sk_GENERAL_SUBTREE(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
GENERAL_SUBTREE* subtree = NULL;
|
||||
int num = 0;
|
||||
int i;
|
||||
|
||||
/* Load certificate with name constraints (cert-ext-nc.pem has 1 email) */
|
||||
ExpectTrue((f = XFOPEN("./certs/test/cert-ext-nc.pem", "rb")) != XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
if (nc != NULL) {
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
if (nc->permittedSubtrees != NULL) {
|
||||
/* Test sk_GENERAL_SUBTREE_num */
|
||||
num = sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
|
||||
ExpectIntGT(num, 0);
|
||||
|
||||
/* Test sk_GENERAL_SUBTREE_value with valid indices */
|
||||
for (i = 0; i < num && i < 10; i++) {
|
||||
subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
|
||||
ExpectNotNull(subtree);
|
||||
if (subtree != NULL) {
|
||||
ExpectNotNull(subtree->base);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test sk_GENERAL_SUBTREE_value at boundaries */
|
||||
ExpectNotNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 0));
|
||||
if (num > 0) {
|
||||
ExpectNotNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees,
|
||||
num - 1));
|
||||
}
|
||||
|
||||
/* Test invalid indices (out of bounds) */
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, num));
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees,
|
||||
num + 1));
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
/* Test NULL stack - wolfSSL returns 0 */
|
||||
ExpectIntEQ(sk_GENERAL_SUBTREE_num(NULL), 0);
|
||||
ExpectNull(sk_GENERAL_SUBTREE_value(NULL, 0));
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test GENERAL_NAME types in Name Constraints.
|
||||
* Verify that different GENERAL_NAME types (DNS, EMAIL, DIRNAME) are properly
|
||||
* extracted from name constraints.
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_types(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
GENERAL_SUBTREE* subtree = NULL;
|
||||
GENERAL_NAME* gn = NULL;
|
||||
|
||||
/* Test EMAIL type constraint from cert-ext-nc.pem */
|
||||
ExpectTrue((f = XFOPEN("./certs/test/cert-ext-nc.pem", "rb")) != XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 0);
|
||||
ExpectNotNull(subtree);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(subtree->base);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
gn = subtree->base;
|
||||
ExpectIntEQ(gn->type, GEN_EMAIL);
|
||||
ExpectNotNull(gn->d.ia5);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(gn->d.ia5->data);
|
||||
ExpectIntGT(gn->d.ia5->length, 0);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Constraint should contain "wolfssl.com" */
|
||||
ExpectNotNull(XSTRSTR((const char*)gn->d.ia5->data, "wolfssl.com"));
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test URI type in Name Constraints. Verifies that GEN_URI type name
|
||||
* constraints are properly extracted and stored as IA5STRING.
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_uri(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
GENERAL_SUBTREE* subtree = NULL;
|
||||
GENERAL_NAME* gn = NULL;
|
||||
int i;
|
||||
int numSubtrees;
|
||||
int foundUri = 0;
|
||||
|
||||
/* Test URI type constraint from cert-ext-nc-combined.pem
|
||||
* This cert has both URI and DNS constraints */
|
||||
ExpectTrue((f = XFOPEN("./certs/test/cert-ext-nc-combined.pem", "rb"))
|
||||
!= XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
}
|
||||
/* Find the URI constraint by iterating through subtrees
|
||||
* (wolfSSL may store them in a different order than in the cert) */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
numSubtrees = sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
|
||||
for (i = 0; i < numSubtrees; i++) {
|
||||
subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
|
||||
if (subtree != NULL && subtree->base != NULL &&
|
||||
subtree->base->type == GEN_URI) {
|
||||
gn = subtree->base;
|
||||
foundUri = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ExpectIntEQ(foundUri, 1);
|
||||
}
|
||||
if (EXPECT_SUCCESS() && foundUri) {
|
||||
ExpectNotNull(gn->d.ia5);
|
||||
}
|
||||
if (EXPECT_SUCCESS() && foundUri) {
|
||||
ExpectNotNull(gn->d.ia5->data);
|
||||
ExpectIntGT(gn->d.ia5->length, 0);
|
||||
}
|
||||
if (EXPECT_SUCCESS() && foundUri) {
|
||||
/* Constraint should contain "wolfssl.com" */
|
||||
ExpectNotNull(XSTRSTR((const char*)gn->d.ia5->data, "wolfssl.com"));
|
||||
}
|
||||
|
||||
/* Test URI constraint matching with NAME_CONSTRAINTS_check_name
|
||||
* Constraint is ".wolfssl.com" (leading dot), matches subdomains only */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Full URIs with subdomain hosts - should match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://www.wolfssl.com/path", 28), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"http://sub.wolfssl.com", 22), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://a.b.c.wolfssl.com:8080/path?q=1", 39), 1);
|
||||
|
||||
/* Exact domain, should not match .wolfssl.com per RFC 5280 */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://wolfssl.com/", 20), 0);
|
||||
|
||||
/* Different domains, should not match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://www.example.com/", 24), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://fakewolfssl.com/", 24), 0);
|
||||
|
||||
/* URI with userinfo, should extract host correctly */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://user@www.wolfssl.com/", 29), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://user:pass@www.wolfssl.com/path", 38), 1);
|
||||
|
||||
/* IPv6 literal URIs, host extracted without brackets.
|
||||
* These don't match .wolfssl.com constraint (different host type) */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://[::1]:8080/path", 23), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://[2001:db8::1]/", 22), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://[fe80::1%25eth0]:443/", 29), 0);
|
||||
|
||||
/* IPv6 with userinfo */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://user@[::1]:8080/", 24), 0);
|
||||
|
||||
/* Malformed IPv6 (missing closing bracket), should fail */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"https://[::1/path", 17), 0);
|
||||
|
||||
/* Invalid URIs, should fail */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"not-a-uri", 9), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
|
||||
"://no-scheme", 12), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test IP address type in Name Constraints.
|
||||
* Verifies that GEN_IPADD type name constraints are properly extracted
|
||||
* and contain the raw IP bytes in OCTET_STRING format.
|
||||
* Format: [IP bytes][subnet mask bytes] (8 bytes for IPv4, 32 for IPv6)
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_ipaddr(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
GENERAL_SUBTREE* subtree = NULL;
|
||||
GENERAL_NAME* gn = NULL;
|
||||
int numPermitted = 0;
|
||||
int critical = -1;
|
||||
|
||||
/* Test IP address type constraint from cert-ext-ncip.pem
|
||||
* This cert has permitted IP: 192.168.1.0/255.255.255.0 */
|
||||
if ((f = XFOPEN("./certs/test/cert-ext-ncip.pem", "rb")) == XBADFILE) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
x509 = PEM_read_X509(f, NULL, NULL, NULL);
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
|
||||
if (x509 == NULL) {
|
||||
/* Certificate may fail to load due to constraints, skip */
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
|
||||
critical = -1;
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
&critical, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
/* Verify critical flag is set */
|
||||
ExpectIntEQ(critical, 1);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
numPermitted = sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
|
||||
ExpectIntEQ(numPermitted, 1);
|
||||
subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 0);
|
||||
ExpectNotNull(subtree);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(subtree->base);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
gn = subtree->base;
|
||||
/* Verify GENERAL_NAME type is GEN_IPADD */
|
||||
ExpectIntEQ(gn->type, GEN_IPADD);
|
||||
/* Verify IP data is stored in d.ip as OCTET_STRING */
|
||||
ExpectNotNull(gn->d.ip);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNotNull(gn->d.ip->data);
|
||||
/* IPv4 constraint: 4 bytes IP + 4 bytes mask = 8 */
|
||||
ExpectIntEQ(gn->d.ip->length, 8);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Verify the IP address bytes (192.168.1.0) */
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[0], 192);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[1], 168);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[2], 1);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[3], 0);
|
||||
/* Verify the subnet mask bytes (255.255.255.0) */
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[4], 255);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[5], 255);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[6], 255);
|
||||
ExpectIntEQ((unsigned char)gn->d.ip->data[7], 0);
|
||||
}
|
||||
if (EXPECT_SUCCESS() && nc->excludedSubtrees != NULL) {
|
||||
/* Excluded subtrees should be empty */
|
||||
ExpectIntEQ(sk_GENERAL_SUBTREE_num(nc->excludedSubtrees), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test wolfSSL_NAME_CONSTRAINTS_check_name() function, checking individual
|
||||
* names against name constraints.
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_check_name(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
|
||||
/* Test email constraint checking with cert-ext-nc.pem
|
||||
* This cert has permitted email for .wolfssl.com (subdomains only) */
|
||||
ExpectTrue((f = XFOPEN("./certs/test/cert-ext-nc.pem", "rb")) != XBADFILE);
|
||||
ExpectNotNull(x509 = PEM_read_X509(f, NULL, NULL, NULL));
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Constraint is ".wolfssl.com" (leading dot). Per RFC 5280, this
|
||||
* matches emails where domain ends with ".wolfssl.com" (subdomains
|
||||
* only), not the exact domain. */
|
||||
|
||||
/* Subdomain emails, should match .wolfssl.com */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"test@sub.wolfssl.com", 20), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@mail.wolfssl.com", 21), 1);
|
||||
/* Deeper subdomain, should also match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"admin@a.b.c.wolfssl.com", 23), 1);
|
||||
|
||||
/* Exact domain, should not match .wolfssl.com per RFC */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@wolfssl.com", 16), 0);
|
||||
|
||||
/* Different domains, should not match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@other.com", 14), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@notwolfssl.com", 19), 0);
|
||||
/* Suffix that doesn't have dot boundary */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@fakewolfssl.com", 20), 0);
|
||||
|
||||
/* Test DNS names, no DNS constraint, so all should pass */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.example.com", 15), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"any.domain.org", 14), 1);
|
||||
|
||||
/* Test NULL/invalid arguments */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(NULL, GEN_EMAIL,
|
||||
"user@wolfssl.com", 16), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
NULL, 16), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@wolfssl.com", 0), 0);
|
||||
/* Invalid email format (no @) */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"invalid-email", 13), 0);
|
||||
/* @ at start */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"@wolfssl.com", 12), 0);
|
||||
/* @ at end */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@", 5), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
x509 = NULL;
|
||||
nc = NULL;
|
||||
|
||||
/* Test IP address constraint checking with cert-ext-ncip.pem
|
||||
* This cert has permitted IP 192.168.1.0/255.255.255.0 */
|
||||
if ((f = XFOPEN("./certs/test/cert-ext-ncip.pem", "rb")) == XBADFILE) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
x509 = PEM_read_X509(f, NULL, NULL, NULL);
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
|
||||
if (x509 == NULL) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Test permitted IPs, within 192.168.1.0/24 subnet */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"192.168.1.1", 11), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"192.168.1.50", 12), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"192.168.1.254", 13), 1);
|
||||
|
||||
/* Test non-permitted IPs, outside 192.168.1.0/24 subnet */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"192.168.2.1", 11), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"10.0.0.1", 8), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"8.8.8.8", 7), 0);
|
||||
|
||||
/* Test invalid IP format */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"invalid", 7), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_IPADD,
|
||||
"256.1.1.1", 9), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test DNS type name constraint checking with leading dot (subdomain matching).
|
||||
* Uses cert-ext-nc-combined.pem which has permitted;DNS:.wolfssl.com
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_dns(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
|
||||
/* Test DNS constraint checking with cert-ext-nc-combined.pem
|
||||
* This cert has permitted DNS for .wolfssl.com (subdomains only) */
|
||||
f = XFOPEN("./certs/test/cert-ext-nc-combined.pem", "rb");
|
||||
if (f == XBADFILE) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
x509 = PEM_read_X509(f, NULL, NULL, NULL);
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
|
||||
if (x509 == NULL) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Constraint is ".wolfssl.com" (leading dot). Per RFC 5280, this
|
||||
* matches DNS names that end with ".wolfssl.com" (subdomains only). */
|
||||
|
||||
/* Subdomain DNS names, should match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.wolfssl.com", 15), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"mail.wolfssl.com", 16), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"a.b.c.wolfssl.com", 17), 1);
|
||||
|
||||
/* Exact domain, should not match .wolfssl.com per RFC */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"wolfssl.com", 11), 0);
|
||||
|
||||
/* Different domains, should not match */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.example.com", 15), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"fakewolfssl.com", 15), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test excluded name constraints.
|
||||
* Uses cert-ext-ncmulti.pem which has:
|
||||
* permitted;DNS:.example.com, permitted;email:.example.com
|
||||
* excluded;DNS:.blocked.example.com, excluded;email:.blocked.example.com
|
||||
*/
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_excluded(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
||||
!defined(NO_RSA) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XFILE f = XBADFILE;
|
||||
X509* x509 = NULL;
|
||||
NAME_CONSTRAINTS* nc = NULL;
|
||||
|
||||
/* Test excluded constraint checking with cert-ext-ncmulti.pem
|
||||
* This cert permits .example.com but excludes .blocked.example.com */
|
||||
if ((f = XFOPEN("./certs/test/cert-ext-ncmulti.pem", "rb")) == XBADFILE) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
x509 = PEM_read_X509(f, NULL, NULL, NULL);
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
|
||||
if (x509 == NULL) {
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
|
||||
nc = (NAME_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_name_constraints,
|
||||
NULL, NULL);
|
||||
ExpectNotNull(nc);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Verify both permitted and excluded subtrees are populated */
|
||||
ExpectNotNull(nc->permittedSubtrees);
|
||||
ExpectNotNull(nc->excludedSubtrees);
|
||||
ExpectIntGT(sk_GENERAL_SUBTREE_num(nc->excludedSubtrees), 0);
|
||||
}
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Permitted .example.com subdomains should be allowed */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.example.com", 15), 1);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"mail.example.com", 16), 1);
|
||||
|
||||
/* Excluded .blocked.example.com, subdomains should be blocked */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.blocked.example.com", 23), 0);
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"sub.blocked.example.com", 23), 0);
|
||||
|
||||
/* blocked.example.com is permitted because
|
||||
* .blocked.example.com (with leading dot) only matches subdomains
|
||||
* per RFC 5280, and it still matches the permitted .example.com
|
||||
* constraint */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"blocked.example.com", 19), 1);
|
||||
|
||||
/* Domains outside permitted .example.com should not be allowed */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
|
||||
"www.wolfssl.com", 15), 0);
|
||||
|
||||
/* Permitted email .example.com subdomains should be allowed */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@www.example.com", 20), 1);
|
||||
|
||||
/* Excluded email .blocked.example.com, should be blocked */
|
||||
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
|
||||
"user@www.blocked.example.com", 28), 0);
|
||||
}
|
||||
|
||||
NAME_CONSTRAINTS_free(nc);
|
||||
X509_free(x509);
|
||||
|
||||
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_CERTS && !NO_RSA &&
|
||||
* !IGNORE_NAME_CONSTRAINTS */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,14 @@ int test_wolfSSL_X509V3_EXT_san(void);
|
||||
int test_wolfSSL_X509V3_EXT_aia(void);
|
||||
int test_wolfSSL_X509V3_EXT(void);
|
||||
int test_wolfSSL_X509V3_EXT_print(void);
|
||||
int test_wolfSSL_X509_get_ext_d2i_name_constraints(void);
|
||||
int test_wolfSSL_sk_GENERAL_SUBTREE(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_types(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_uri(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_ipaddr(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_check_name(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_dns(void);
|
||||
int test_wolfSSL_NAME_CONSTRAINTS_excluded(void);
|
||||
|
||||
#define TEST_OSSL_X509_EXT_DECLS \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509_get_extension_flags), \
|
||||
@@ -71,6 +79,15 @@ int test_wolfSSL_X509V3_EXT_print(void);
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509V3_EXT_san), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509V3_EXT_aia), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509V3_EXT), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509V3_EXT_print)
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_X509V3_EXT_print), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", \
|
||||
test_wolfSSL_X509_get_ext_d2i_name_constraints), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_sk_GENERAL_SUBTREE), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_types), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_uri), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_ipaddr), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_check_name),\
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_dns), \
|
||||
TEST_DECL_GROUP("ossl_x509_ext", test_wolfSSL_NAME_CONSTRAINTS_excluded)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_OSSL_X509_EXT_H */
|
||||
|
||||
@@ -19403,9 +19403,9 @@ int wolfssl_local_MatchBaseName(int type, const char* name, int nameSz,
|
||||
return 0;
|
||||
|
||||
while (nameSz > 0) {
|
||||
if (XTOLOWER((unsigned char)*name) !=
|
||||
XTOLOWER((unsigned char)*base))
|
||||
if (XTOLOWER((unsigned char)*name) != XTOLOWER((unsigned char)*base)) {
|
||||
return 0;
|
||||
}
|
||||
name++;
|
||||
base++;
|
||||
nameSz--;
|
||||
@@ -19414,6 +19414,42 @@ int wolfssl_local_MatchBaseName(int type, const char* name, int nameSz,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if IP address matches a name constraint.
|
||||
* IP name constraints contain IP address and subnet mask.
|
||||
* IPv4: ip is 4 bytes, constraint is 8 bytes (4 IP + 4 mask)
|
||||
* IPv6: ip is 16 bytes, constraint is 32 bytes (16 IP + 16 mask)
|
||||
*
|
||||
* ip: IP address bytes
|
||||
* ipSz: length of ip
|
||||
* constraint: constraint bytes (IP + mask)
|
||||
* constraintSz: length of constraint
|
||||
*
|
||||
* return 1 if IP matches constraint, otherwise 0
|
||||
*/
|
||||
int wolfssl_local_MatchIpSubnet(const byte* ip, int ipSz,
|
||||
const byte* constraint, int constraintSz)
|
||||
{
|
||||
int i;
|
||||
int match = 1;
|
||||
|
||||
if (ip == NULL || constraint == NULL || ipSz <= 0 || constraintSz <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Constraint should be 2x address length (IP + mask) */
|
||||
if (constraintSz != ipSz * 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ipSz; i++) {
|
||||
if ((ip[i] & constraint[ipSz + i]) !=
|
||||
(constraint[i] & constraint[ipSz + i])) {
|
||||
match = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Search through the list to find if the name is permitted.
|
||||
* name The DNS name to search for
|
||||
@@ -19432,7 +19468,16 @@ static int PermittedListOk(DNS_entry* name, Base_entry* dnsList, byte nameType)
|
||||
while (current != NULL) {
|
||||
if (current->type == nameType) {
|
||||
need = 1; /* restriction on permitted names is set for this type */
|
||||
if (name->len >= current->nameSz &&
|
||||
if (nameType == ASN_IP_TYPE) {
|
||||
/* IP address uses subnet matching (IP + mask) */
|
||||
if (wolfssl_local_MatchIpSubnet((const byte*)name->name,
|
||||
name->len, (const byte*)current->name,
|
||||
current->nameSz)) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (name->len >= current->nameSz &&
|
||||
wolfssl_local_MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
match = 1; /* found the current name in the permitted list*/
|
||||
@@ -19463,7 +19508,16 @@ static int IsInExcludedList(DNS_entry* name, Base_entry* dnsList, byte nameType)
|
||||
|
||||
while (current != NULL) {
|
||||
if (current->type == nameType) {
|
||||
if (name->len >= current->nameSz &&
|
||||
if (nameType == ASN_IP_TYPE) {
|
||||
/* IP address uses subnet matching (IP + mask) */
|
||||
if (wolfssl_local_MatchIpSubnet((const byte*)name->name,
|
||||
name->len, (const byte*)current->name,
|
||||
current->nameSz)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (name->len >= current->nameSz &&
|
||||
wolfssl_local_MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
ret = 1;
|
||||
@@ -19479,7 +19533,8 @@ static int IsInExcludedList(DNS_entry* name, Base_entry* dnsList, byte nameType)
|
||||
|
||||
static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
|
||||
{
|
||||
const byte nameTypes[] = {ASN_RFC822_TYPE, ASN_DNS_TYPE, ASN_DIR_TYPE};
|
||||
const byte nameTypes[] = {ASN_RFC822_TYPE, ASN_DNS_TYPE, ASN_DIR_TYPE,
|
||||
ASN_IP_TYPE};
|
||||
int i;
|
||||
|
||||
if (signer == NULL || cert == NULL)
|
||||
@@ -19500,6 +19555,10 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
|
||||
* subjectDnsName too */
|
||||
name = cert->altNames;
|
||||
break;
|
||||
case ASN_IP_TYPE:
|
||||
/* IP addresses are stored in altNames with type ASN_IP_TYPE */
|
||||
name = cert->altNames;
|
||||
break;
|
||||
case ASN_RFC822_TYPE:
|
||||
/* Shouldn't it validate E= in subject as well? */
|
||||
name = cert->altEmailNames;
|
||||
@@ -19544,15 +19603,20 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
|
||||
}
|
||||
|
||||
while (name != NULL) {
|
||||
if (IsInExcludedList(name, signer->excludedNames, nameType) == 1) {
|
||||
WOLFSSL_MSG("Excluded name was found!");
|
||||
return 0;
|
||||
}
|
||||
/* Only check entries that match the current nameType. */
|
||||
if (name->type == nameType) {
|
||||
if (IsInExcludedList(name, signer->excludedNames,
|
||||
nameType) == 1) {
|
||||
WOLFSSL_MSG("Excluded name was found!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check against the permitted list */
|
||||
if (PermittedListOk(name, signer->permittedNames, nameType) != 1) {
|
||||
WOLFSSL_MSG("Permitted name was not found!");
|
||||
return 0;
|
||||
/* Check against the permitted list */
|
||||
if (PermittedListOk(name, signer->permittedNames,
|
||||
nameType) != 1) {
|
||||
WOLFSSL_MSG("Permitted name was not found!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
name = name->next;
|
||||
@@ -22021,7 +22085,8 @@ static int DecodeSubtree(const byte* input, word32 sz, Base_entry** head,
|
||||
bType = (byte)(b & ASN_TYPE_MASK);
|
||||
|
||||
if (bType == ASN_DNS_TYPE || bType == ASN_RFC822_TYPE ||
|
||||
bType == ASN_DIR_TYPE) {
|
||||
bType == ASN_DIR_TYPE || bType == ASN_IP_TYPE ||
|
||||
bType == ASN_URI_TYPE) {
|
||||
Base_entry* entry;
|
||||
|
||||
/* if constructed has leading sequence */
|
||||
@@ -22099,7 +22164,9 @@ static int DecodeSubtree(const byte* input, word32 sz, Base_entry** head,
|
||||
/* Check GeneralName tag is one of the types we can handle. */
|
||||
if (t == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE) ||
|
||||
t == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE) ||
|
||||
t == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) {
|
||||
t == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE) ||
|
||||
t == (ASN_CONTEXT_SPECIFIC | ASN_IP_TYPE) ||
|
||||
t == (ASN_CONTEXT_SPECIFIC | ASN_URI_TYPE)) {
|
||||
/* Parse the general name and store a new entry. */
|
||||
ret = DecodeSubtreeGeneralName(input +
|
||||
GetASNItem_DataIdx(dataASN[SUBTREEASN_IDX_BASE], input),
|
||||
|
||||
@@ -5259,6 +5259,7 @@ typedef enum {
|
||||
STACK_TYPE_X509_CRL = 16,
|
||||
STACK_TYPE_X509_NAME_ENTRY = 17,
|
||||
STACK_TYPE_X509_REQ_ATTR = 18,
|
||||
STACK_TYPE_GENERAL_SUBTREE = 19,
|
||||
} WOLF_STACK_TYPE;
|
||||
|
||||
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
|
||||
@@ -5287,6 +5288,7 @@ struct WOLFSSL_STACK {
|
||||
void* generic;
|
||||
char* string;
|
||||
WOLFSSL_GENERAL_NAME* gn;
|
||||
WOLFSSL_GENERAL_SUBTREE* subtree;
|
||||
WOLFSSL_BY_DIR_entry* dir_entry;
|
||||
WOLFSSL_BY_DIR_HASH* dir_hash;
|
||||
WOLFSSL_X509_OBJECT* x509_obj;
|
||||
@@ -5327,6 +5329,9 @@ struct WOLFSSL_X509_NAME {
|
||||
|
||||
#ifdef NO_ASN
|
||||
typedef struct DNS_entry DNS_entry;
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
typedef struct Base_entry Base_entry;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct WOLFSSL_X509 {
|
||||
@@ -5355,6 +5360,11 @@ struct WOLFSSL_X509 {
|
||||
buffer sig;
|
||||
int sigOID;
|
||||
DNS_entry* altNames; /* alt names list */
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
Base_entry* permittedNames; /* name constraints */
|
||||
Base_entry* excludedNames;
|
||||
byte nameConstraintCrit:1;
|
||||
#endif
|
||||
buffer pubKey;
|
||||
int pubKeyOID;
|
||||
DNS_entry* altNamesNext; /* hint for retrieval */
|
||||
|
||||
@@ -199,8 +199,16 @@ typedef struct WOLFSSL_v3_ext_method X509V3_EXT_METHOD;
|
||||
typedef struct WOLFSSL_AUTHORITY_KEYID AUTHORITY_KEYID;
|
||||
typedef struct WOLFSSL_BASIC_CONSTRAINTS BASIC_CONSTRAINTS;
|
||||
typedef struct WOLFSSL_ACCESS_DESCRIPTION ACCESS_DESCRIPTION;
|
||||
typedef struct WOLFSSL_GENERAL_SUBTREE GENERAL_SUBTREE;
|
||||
typedef struct WOLFSSL_NAME_CONSTRAINTS NAME_CONSTRAINTS;
|
||||
|
||||
#define BASIC_CONSTRAINTS_free wolfSSL_BASIC_CONSTRAINTS_free
|
||||
#define NAME_CONSTRAINTS_new wolfSSL_NAME_CONSTRAINTS_new
|
||||
#define NAME_CONSTRAINTS_free wolfSSL_NAME_CONSTRAINTS_free
|
||||
#define GENERAL_SUBTREE_new wolfSSL_GENERAL_SUBTREE_new
|
||||
#define GENERAL_SUBTREE_free wolfSSL_GENERAL_SUBTREE_free
|
||||
#define sk_GENERAL_SUBTREE_num wolfSSL_sk_GENERAL_SUBTREE_num
|
||||
#define sk_GENERAL_SUBTREE_value wolfSSL_sk_GENERAL_SUBTREE_value
|
||||
#define AUTHORITY_KEYID_free wolfSSL_AUTHORITY_KEYID_free
|
||||
#define SSL_CTX_get_cert_store(x) wolfSSL_CTX_get_cert_store ((x))
|
||||
#define ASN1_INTEGER WOLFSSL_ASN1_INTEGER
|
||||
|
||||
@@ -343,6 +343,8 @@ typedef struct WOLFSSL_BASIC_CONSTRAINTS WOLFSSL_BASIC_CONSTRAINTS;
|
||||
typedef struct WOLFSSL_ACCESS_DESCRIPTION WOLFSSL_ACCESS_DESCRIPTION;
|
||||
typedef struct WOLFSSL_DIST_POINT_NAME WOLFSSL_DIST_POINT_NAME;
|
||||
typedef struct WOLFSSL_DIST_POINT WOLFSSL_DIST_POINT;
|
||||
typedef struct WOLFSSL_GENERAL_SUBTREE WOLFSSL_GENERAL_SUBTREE;
|
||||
typedef struct WOLFSSL_NAME_CONSTRAINTS WOLFSSL_NAME_CONSTRAINTS;
|
||||
|
||||
typedef struct WOLFSSL_CONF_CTX WOLFSSL_CONF_CTX;
|
||||
|
||||
@@ -483,6 +485,16 @@ struct WOLFSSL_GENERAL_NAME {
|
||||
} d; /* dereference */
|
||||
};
|
||||
|
||||
/* GeneralSubtree for Name Constraints extension (RFC 5280) */
|
||||
struct WOLFSSL_GENERAL_SUBTREE {
|
||||
WOLFSSL_GENERAL_NAME* base;
|
||||
};
|
||||
|
||||
struct WOLFSSL_NAME_CONSTRAINTS {
|
||||
WOLF_STACK_OF(WOLFSSL_GENERAL_SUBTREE)* permittedSubtrees;
|
||||
WOLF_STACK_OF(WOLFSSL_GENERAL_SUBTREE)* excludedSubtrees;
|
||||
};
|
||||
|
||||
struct WOLFSSL_DIST_POINT_NAME {
|
||||
int type;
|
||||
|
||||
@@ -1972,6 +1984,18 @@ WOLFSSL_API int wolfSSL_GENERAL_NAME_print(WOLFSSL_BIO* out,
|
||||
WOLFSSL_GENERAL_NAME* name);
|
||||
WOLFSSL_API void wolfSSL_EXTENDED_KEY_USAGE_free(WOLFSSL_STACK * sk);
|
||||
|
||||
#if !defined(IGNORE_NAME_CONSTRAINTS) && !defined(WOLFSSL_LINUXKM)
|
||||
WOLFSSL_API WOLFSSL_NAME_CONSTRAINTS* wolfSSL_NAME_CONSTRAINTS_new(void);
|
||||
WOLFSSL_API void wolfSSL_NAME_CONSTRAINTS_free(WOLFSSL_NAME_CONSTRAINTS* nc);
|
||||
WOLFSSL_API int wolfSSL_NAME_CONSTRAINTS_check_name(
|
||||
WOLFSSL_NAME_CONSTRAINTS* nc, int type, const char* name, int nameSz);
|
||||
WOLFSSL_API WOLFSSL_GENERAL_SUBTREE* wolfSSL_GENERAL_SUBTREE_new(void);
|
||||
WOLFSSL_API void wolfSSL_GENERAL_SUBTREE_free(WOLFSSL_GENERAL_SUBTREE* subtree);
|
||||
WOLFSSL_API int wolfSSL_sk_GENERAL_SUBTREE_num(const WOLFSSL_STACK* sk);
|
||||
WOLFSSL_API WOLFSSL_GENERAL_SUBTREE* wolfSSL_sk_GENERAL_SUBTREE_value(
|
||||
const WOLFSSL_STACK* sk, int idx);
|
||||
#endif /* !IGNORE_NAME_CONSTRAINTS && !WOLFSSL_LINUXKM */
|
||||
|
||||
WOLFSSL_API WOLFSSL_DIST_POINT* wolfSSL_DIST_POINT_new(void);
|
||||
WOLFSSL_API void wolfSSL_DIST_POINT_free(WOLFSSL_DIST_POINT* dp);
|
||||
WOLFSSL_API int wolfSSL_sk_DIST_POINT_push(WOLFSSL_DIST_POINTS* sk,
|
||||
|
||||
@@ -2925,6 +2925,9 @@ WOLFSSL_LOCAL int VerifyX509Acert(const byte* cert, word32 certSz,
|
||||
WOLFSSL_TEST_VIS int wolfssl_local_MatchBaseName(int type, const char* name,
|
||||
int nameSz, const char* base,
|
||||
int baseSz);
|
||||
WOLFSSL_TEST_VIS int wolfssl_local_MatchIpSubnet(const byte* ip, int ipSz,
|
||||
const byte* constraint,
|
||||
int constraintSz);
|
||||
#endif
|
||||
|
||||
#if ((defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)) \
|
||||
|
||||
Reference in New Issue
Block a user