diff --git a/.gitignore b/.gitignore index 0ef9644175..591b9d4230 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,10 @@ ecc-key.der ecc-key.pem certreq.der certreq.pem +crlRsaOut.pem +crlRsaOut.der +crlEccOut.pem +crlEccOut.der pkcs7cert.der pkcs7authEnvelopedDataAES128GCM.der pkcs7authEnvelopedDataAES128GCM_ECDH_SHA1KDF.der @@ -470,3 +474,6 @@ wolfssl/debug-trace-error-codes.h wolfssl/debug-untrace-error-codes.h AGENTS.md + +# Code navigation files +compile_commands.json diff --git a/certs/client-ca-cert.der b/certs/client-ca-cert.der new file mode 100644 index 0000000000..8b5ba8ddea Binary files /dev/null and b/certs/client-ca-cert.der differ diff --git a/certs/client-ca-cert.pem b/certs/client-ca-cert.pem new file mode 100644 index 0000000000..b7eea645de --- /dev/null +++ b/certs/client-ca-cert.pem @@ -0,0 +1,92 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4661 (0x1235) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Validity + Not Before: Jan 24 20:31:13 2026 GMT + Not After : Oct 20 20:31:13 2028 GMT + Subject: C = US, ST = Montana, L = Bozeman, O = wolfSSL_2048, OU = Programming-2048, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c3:03:d1:2b:fe:39:a4:32:45:3b:53:c8:84:2b: + 2a:7c:74:9a:bd:aa:2a:52:07:47:d6:a6:36:b2:07: + 32:8e:d0:ba:69:7b:c6:c3:44:9e:d4:81:48:fd:2d: + 68:a2:8b:67:bb:a1:75:c8:36:2c:4a:d2:1b:f7:8b: + ba:cf:0d:f9:ef:ec:f1:81:1e:7b:9b:03:47:9a:bf: + 65:cc:7f:65:24:69:a6:e8:14:89:5b:e4:34:f7:c5: + b0:14:93:f5:67:7b:3a:7a:78:e1:01:56:56:91:a6: + 13:42:8d:d2:3c:40:9c:4c:ef:d1:86:df:37:51:1b: + 0c:a1:3b:f5:f1:a3:4a:35:e4:e1:ce:96:df:1b:7e: + bf:4e:97:d0:10:e8:a8:08:30:81:af:20:0b:43:14: + c5:74:67:b4:32:82:6f:8d:86:c2:88:40:99:36:83: + ba:1e:40:72:22:17:d7:52:65:24:73:b0:ce:ef:19: + cd:ae:ff:78:6c:7b:c0:12:03:d4:4e:72:0d:50:6d: + 3b:a3:3b:a3:99:5e:9d:c8:d9:0c:85:b3:d9:8a:d9: + 54:26:db:6d:fa:ac:bb:ff:25:4c:c4:d1:79:f4:71: + d3:86:40:18:13:b0:63:b5:72:4e:30:c4:97:84:86: + 2d:56:2f:d7:15:f7:7f:c0:ae:f5:fc:5b:e5:fb:a1: + ba:d3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Subject Key Identifier: + 33:D8:45:66:D7:68:87:18:7E:54:0D:70:27:91:C7:26:D7:85:65:C0 + X509v3 Authority Key Identifier: + keyid:27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + serial:3F:29:11:20:57:71:E7:8E:F9:18:0D:CA:70:4D:5B:15:2A:43:D6:24 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 7f:71:41:b2:72:c1:a9:ba:c9:52:40:ea:6d:3d:3d:c0:ae:1e: + 44:cd:f9:a5:d6:ac:34:5f:8b:ed:cd:91:81:0f:05:0f:5e:4b: + b3:18:bf:33:7a:61:a5:25:f1:91:55:c1:12:66:b7:26:3b:9c: + bb:21:1a:0c:72:78:88:57:fa:49:22:e7:80:2f:c1:40:01:66: + 3d:20:63:e7:e3:38:a9:54:39:52:42:d2:b6:38:6b:08:7d:45: + 49:1a:de:b5:64:70:c9:65:ce:0b:94:24:ee:b4:46:67:3c:74: + f0:2a:61:4d:b2:fc:6e:ca:c0:36:a9:b0:d3:5a:e2:15:72:f5: + a4:90:73:b2:37:58:b4:10:39:d3:85:5f:56:91:7e:cf:54:5d: + c6:a7:40:36:bd:ed:f2:af:e5:ce:b6:ea:38:be:47:32:6f:ed: + d2:ba:9d:70:e1:74:2e:f0:27:e4:72:53:75:43:ce:0a:07:b4: + 7e:74:17:00:55:b5:d1:92:e4:42:39:ca:84:51:84:f8:23:a6: + 41:27:fb:20:e2:43:e3:74:d3:ce:95:4e:1f:06:de:65:5e:e3: + 38:e2:eb:f1:a6:ca:6b:7c:56:51:c0:02:1e:6e:3f:51:c1:d5: + 04:c0:3d:57:56:15:65:76:a4:f4:eb:43:27:2c:c3:58:29:5c: + 18:da:e8:fd +-----BEGIN CERTIFICATE----- +MIIE3zCCA8egAwIBAgICEjUwDQYJKoZIhvcNAQELBQAwgZQxCzAJBgNVBAYTAlVT +MRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREwDwYDVQQKDAhT +YXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwPd3d3LndvbGZz +c2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTI2MDEy +NDIwMzExM1oXDTI4MTAyMDIwMzExM1owgZ4xCzAJBgNVBAYTAlVTMRAwDgYDVQQI +DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRUwEwYDVQQKDAx3b2xmU1NMXzIw +NDgxGTAXBgNVBAsMEFByb2dyYW1taW5nLTIwNDgxGDAWBgNVBAMMD3d3dy53b2xm +c3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMD0Sv+OaQyRTtTyIQrKnx0mr2qKlIH +R9amNrIHMo7Quml7xsNEntSBSP0taKKLZ7uhdcg2LErSG/eLus8N+e/s8YEee5sD +R5q/Zcx/ZSRppugUiVvkNPfFsBST9Wd7Onp44QFWVpGmE0KN0jxAnEzv0YbfN1Eb +DKE79fGjSjXk4c6W3xt+v06X0BDoqAgwga8gC0MUxXRntDKCb42GwohAmTaDuh5A +ciIX11JlJHOwzu8Zza7/eGx7wBID1E5yDVBtO6M7o5lencjZDIWz2YrZVCbbbfqs +u/8lTMTRefRx04ZAGBOwY7VyTjDEl4SGLVYv1xX3f8Cu9fxb5fuhutMCAwEAAaOC +AS0wggEpMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG +CCsGAQUFBwMCMB0GA1UdDgQWBBQz2EVm12iHGH5UDXAnkccm14VlwDCB1AYDVR0j +BIHMMIHJgBQnjmcRdMMmHT/tM2OzpNgdMOXo1aGBmqSBlzCBlDELMAkGA1UEBhMC +VVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoM +CFNhd3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29s +ZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb22CFD8pESBX +ceeO+RgNynBNWxUqQ9YkMA0GCSqGSIb3DQEBCwUAA4IBAQB/cUGycsGpuslSQOpt +PT3Arh5Ezfml1qw0X4vtzZGBDwUPXkuzGL8zemGlJfGRVcESZrcmO5y7IRoMcniI +V/pJIueAL8FAAWY9IGPn4zipVDlSQtK2OGsIfUVJGt61ZHDJZc4LlCTutEZnPHTw +KmFNsvxuysA2qbDTWuIVcvWkkHOyN1i0EDnThV9WkX7PVF3Gp0A2ve3yr+XOtuo4 +vkcyb+3Sup1w4XQu8CfkclN1Q84KB7R+dBcAVbXRkuRCOcqEUYT4I6ZBJ/sg4kPj +dNPOlU4fBt5lXuM44uvxpsprfFZRwAIebj9RwdUEwD1XVhVldqT060MnLMNYKVwY +2uj9 +-----END CERTIFICATE----- diff --git a/certs/client-ecc-ca-cert.der b/certs/client-ecc-ca-cert.der new file mode 100644 index 0000000000..5fa80d3c07 Binary files /dev/null and b/certs/client-ecc-ca-cert.der differ diff --git a/certs/client-ecc-ca-cert.pem b/certs/client-ecc-ca-cert.pem new file mode 100644 index 0000000000..9059e12507 --- /dev/null +++ b/certs/client-ecc-ca-cert.pem @@ -0,0 +1,54 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4660 (0x1234) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C = US, ST = Washington, L = Seattle, O = wolfSSL, OU = Development, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Validity + Not Before: Jan 24 20:12:22 2026 GMT + Not After : Oct 20 20:12:22 2028 GMT + Subject: C = US, ST = Oregon, L = Salem, O = Client ECC, OU = Fast, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:55:bf:f4:0f:44:50:9a:3d:ce:9b:b7:f0:c5:4d: + f5:70:7b:d4:ec:24:8e:19:80:ec:5a:4c:a2:24:03: + 62:2c:9b:da:ef:a2:35:12:43:84:76:16:c6:56:95: + 06:cc:01:a9:bd:f6:75:1a:42:f7:bd:a9:b2:36:22: + 5f:c7:5d:7f:b4 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + EB:D4:4B:59:6B:95:61:3F:51:57:B6:04:4D:89:41:88:44:5C:AB:F2 + X509v3 Authority Key Identifier: + 56:8E:9A:C3:F0:42:DE:18:B9:45:55:6E:F9:93:CF:EA:C3:F3:A5:21 + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Client Authentication + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:9d:4d:72:4a:fb:f7:19:96:e3:d3:c2:75:ed: + b5:39:18:44:e7:61:7d:5e:31:d0:3c:eb:45:b3:6f:38:68:f9: + 1d:02:20:57:c1:19:e8:c8:8a:14:e7:37:d1:93:b3:46:f5:eb: + 8f:24:31:6c:78:d7:cd:b7:c9:8e:09:54:6e:4d:3b:7b:7b +-----BEGIN CERTIFICATE----- +MIICizCCAjGgAwIBAgICEjQwCgYIKoZIzj0EAwIwgZcxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAd3 +b2xmU1NMMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEYMBYGA1UEAwwPd3d3LndvbGZz +c2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTI2MDEy +NDIwMTIyMloXDTI4MTAyMDIwMTIyMlowgY0xCzAJBgNVBAYTAlVTMQ8wDQYDVQQI +DAZPcmVnb24xDjAMBgNVBAcMBVNhbGVtMRMwEQYDVQQKDApDbGllbnQgRUNDMQ0w +CwYDVQQLDARGYXN0MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG +9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC +AARVv/QPRFCaPc6bt/DFTfVwe9TsJI4ZgOxaTKIkA2Ism9rvojUSQ4R2FsZWlQbM +Aam99nUaQve9qbI2Il/HXX+0o3UwczAdBgNVHQ4EFgQU69RLWWuVYT9RV7YETYlB +iERcq/IwHwYDVR0jBBgwFoAUVo6aw/BC3hi5RVVu+ZPP6sPzpSEwDAYDVR0TAQH/ +BAIwADAOBgNVHQ8BAf8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCgYIKoZI +zj0EAwIDSAAwRQIhAJ1Nckr79xmW49PCde21ORhE52F9XjHQPOtFs284aPkdAiBX +wRnoyIoU5zfRk7NG9euPJDFseNfNt8mOCVRuTTt7ew== +-----END CERTIFICATE----- diff --git a/certs/include.am b/certs/include.am index 68fcd1e2ea..a4c85eb69d 100644 --- a/certs/include.am +++ b/certs/include.am @@ -32,7 +32,9 @@ EXTRA_DIST += \ certs/ecc-client-keyPub.pem \ certs/empty-issuer-cert.pem \ certs/client-ecc-cert.pem \ + certs/client-ecc-ca-cert.pem \ certs/client-ca.pem \ + certs/client-ca-cert.pem \ certs/dh2048.pem \ certs/server-cert.pem \ certs/server-ecc.pem \ @@ -91,6 +93,8 @@ EXTRA_DIST += \ certs/client-cert.der \ certs/client-key.der \ certs/client-ecc-cert.der \ + certs/client-ecc-ca-cert.der \ + certs/client-ca-cert.der \ certs/client-keyPub.der \ certs/client-keyPub.pem \ certs/dh2048.der \ @@ -154,4 +158,3 @@ include certs/sphincs/include.am include certs/rpk/include.am include certs/acert/include.am include certs/mldsa/include.am - diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 5aed648817..d98eb28cd0 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -21,6 +21,10 @@ # 1024/client-cert.pem # server-ecc-comp.pem # client-ca.pem +# client-ca-cert.der +# client-ca-cert.pem +# client-ecc-ca-cert.der +# client-ecc-ca-cert.pem # test/digsigku.pem # ecc-privOnlyCert.pem # client-uri-cert.pem @@ -896,6 +900,61 @@ run_renewcerts(){ echo "End of section" echo "---------------------------------------------------------------------" + ############################################################ + ########## update and sign client-ca-cert.pem ############## + ############################################################ + echo "Updating client-ca-cert.pem" + echo "" + cat > client-ca-ext.cnf <<'EOF' +[ client_ca ] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints=critical, CA:FALSE +keyUsage=critical, digitalSignature, keyEncipherment +extendedKeyUsage=clientAuth +EOF + check_result $? "Step 1" + + #pipe the following arguments to openssl req... + echo -e "US\\nMontana\\nBozeman\\nwolfSSL_2048\\nProgramming-2048\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n.\\n.\\n" | openssl req -new -key client-key.pem -config ./wolfssl.cnf -nodes > client-ca-cert-req.pem + check_result $? "Step 2" + + openssl x509 -req -in client-ca-cert-req.pem -extfile client-ca-ext.cnf -extensions client_ca -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 0x1235 > client-ca-cert.pem + check_result $? "Step 3" + rm client-ca-cert-req.pem + + openssl x509 -in client-ca-cert.pem -text > tmp.pem + check_result $? "Step 4" + mv tmp.pem client-ca-cert.pem + + openssl x509 -inform PEM -in client-ca-cert.pem -outform DER -out client-ca-cert.der + check_result $? "Step 5" + rm client-ca-ext.cnf + echo "End of section" + echo "---------------------------------------------------------------------" + + ############################################################ + ####### update and sign client-ecc-ca-cert.pem ############# + ############################################################ + echo "Updating client-ecc-ca-cert.pem" + echo "" + #pipe the following arguments to openssl req... + echo -e "US\\nOregon\\nSalem\\nClient ECC\\nFast\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n.\\n.\\n" | openssl req -new -key ecc-client-key.pem -config ./wolfssl.cnf -nodes > client-ecc-ca-cert-req.pem + check_result $? "Step 1" + + openssl x509 -req -in client-ecc-ca-cert-req.pem -extfile wolfssl.cnf -extensions client_ecc -days 1000 -CA ca-ecc-cert.pem -CAkey ca-ecc-key.pem -set_serial 0x1234 > client-ecc-ca-cert.pem + check_result $? "Step 2" + rm client-ecc-ca-cert-req.pem + + openssl x509 -in client-ecc-ca-cert.pem -text > tmp.pem + check_result $? "Step 3" + mv tmp.pem client-ecc-ca-cert.pem + + openssl x509 -inform PEM -in client-ecc-ca-cert.pem -outform DER -out client-ecc-ca-cert.der + check_result $? "Step 4" + echo "End of section" + echo "---------------------------------------------------------------------" + #cleanup the file system now that we're done echo "Performing final steps, cleaning up the file system..." echo "" diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index bb9dd03a76..558ad2baf9 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -46,6 +46,7 @@ #endif #include + #include #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) #error Unsupported kernel. diff --git a/scripts/crl-gen-openssl.test b/scripts/crl-gen-openssl.test new file mode 100755 index 0000000000..df11465da4 --- /dev/null +++ b/scripts/crl-gen-openssl.test @@ -0,0 +1,112 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Verifies CRLs generated by the C API unit tests (tests/api.c). +# Uses OpenSSL to validate CRL structure, signature, and revocation behavior. +# RSA: ca-cert.pem + server-cert.pem (revoked) + client-ca-cert.pem (good). +# ECC: ca-ecc-cert.pem + server-ecc.pem (revoked) + client-ecc-ca-cert.pem (good). + +OPENSSL=${OPENSSL:-openssl} + +if ! command -v "$OPENSSL" >/dev/null 2>&1; then + echo "skipping crl-gen-openssl.test: openssl not found" + exit 77 +fi + +normalize_dn() { + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \ + -e 's/^issuer=//' -e 's/^subject=//' \ + -e 's/[[:space:]]*=[[:space:]]*/=/g' \ + -e 's/[[:space:]]*,[[:space:]]*/,/g' +} + +check_crl() { + local crl="$1" + local ca_cert="$2" + local revoked_cert="$3" + local good_cert="$4" + local label="$5" + + echo "Checking $label CRL: $crl" + + local issuer subject + issuer=$("$OPENSSL" crl -in "$crl" -noout -issuer | normalize_dn) + subject=$("$OPENSSL" x509 -in "$ca_cert" -noout -subject | normalize_dn) + if [ "$issuer" != "$subject" ]; then + echo "issuer mismatch for $label CRL" + echo "issuer : $issuer" + echo "subject: $subject" + return 1 + fi + + local last_update next_update + last_update=$("$OPENSSL" crl -in "$crl" -noout -lastupdate) + next_update=$("$OPENSSL" crl -in "$crl" -noout -nextupdate) + if [ -z "$last_update" ] || [ -z "$next_update" ]; then + echo "missing lastUpdate/nextUpdate for $label CRL" + return 1 + fi + + if ! "$OPENSSL" crl -in "$crl" -noout -verify -CAfile "$ca_cert" >/dev/null 2>&1; then + echo "CRL signature verification failed for $label" + return 1 + fi + + local revoked_count + revoked_count=$("$OPENSSL" crl -in "$crl" -text -noout | grep -c "Serial Number" || true) + if [ "$revoked_count" -ne 4 ]; then + echo "unexpected revoked count for $label CRL: $revoked_count (expected 4)" + return 1 + fi + + local serial crl_text + serial=$("$OPENSSL" x509 -in "$revoked_cert" -noout -serial | cut -d= -f2 | tr 'A-F' 'a-f') + crl_text=$("$OPENSSL" crl -in "$crl" -text -noout | tr 'A-F' 'a-f') + if ! echo "$crl_text" | grep -q "$serial"; then + echo "revoked serial not found in $label CRL: $serial" + return 1 + fi + + local verify_out verify_rc + verify_out=$("$OPENSSL" verify -CAfile "$ca_cert" -crl_check -CRLfile "$crl" \ + "$revoked_cert" 2>&1) || verify_rc=$? + verify_rc=${verify_rc:-0} + if [ "$verify_rc" -eq 0 ] || ! echo "$verify_out" | grep -qi "certificate revoked"; then + echo "expected revoked verification failure for $label CRL" + echo "$verify_out" + return 1 + fi + + if [ -n "$good_cert" ]; then + if ! "$OPENSSL" verify -CAfile "$ca_cert" -crl_check -CRLfile "$crl" \ + "$good_cert" >/dev/null 2>&1; then + echo "expected successful verification for $label CRL with $good_cert" + return 1 + fi + fi +} + +crl_rsa="certs/crl/crlRsaOut.pem" +crl_ecc="certs/crl/crlEccOut.pem" + +if [ ! -f "$crl_rsa" ] && [ ! -f "$crl_ecc" ]; then + echo "skipping crl-gen-openssl.test: CRL outputs not found" + exit 77 +fi + +if [ -f "$crl_rsa" ]; then + ca_rsa="certs/ca-cert.pem" + revoked_rsa="certs/server-cert.pem" + good_rsa="certs/client-ca-cert.pem" + check_crl "$crl_rsa" "$ca_rsa" "$revoked_rsa" "$good_rsa" "RSA" +fi + +if [ -f "$crl_ecc" ]; then + ca_ecc="certs/ca-ecc-cert.pem" + revoked_ecc="certs/server-ecc.pem" + good_ecc="certs/client-ecc-ca-cert.pem" + check_crl "$crl_ecc" "$ca_ecc" "$revoked_ecc" "${good_ecc:-}" "ECC" +fi + +echo "crl-gen-openssl.test: OK" diff --git a/scripts/include.am b/scripts/include.am index 7325d3b668..b2dd157ea8 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -18,7 +18,9 @@ if BUILD_RSA if BUILD_CRL # make revoked test rely on completion of resume test dist_noinst_SCRIPTS+= scripts/crl-revoked.test +dist_noinst_SCRIPTS+= scripts/crl-gen-openssl.test scripts/crl-revoked.log: scripts/resume.log +scripts/crl-gen-openssl.log: scripts/crl-revoked.log endif # arrange to serialize ocsp.test, ocsp-stapling.test, ocsp-stapling-with-ca-as-responder.test, ocsp-stapling2.test, and testsuite, diff --git a/src/crl.c b/src/crl.c index 17f1fb30e3..b729b2f41d 100644 --- a/src/crl.c +++ b/src/crl.c @@ -40,6 +40,8 @@ CRL Options: #include #include #include +#include +#include #ifndef NO_STRING_H #include @@ -235,6 +237,14 @@ static void CRL_Entry_free(CRL_Entry* crle, void* heap) XFREE(crle->sigParams, heap, DYNAMIC_TYPE_CRL_ENTRY); #endif #if defined(OPENSSL_EXTRA) + if (crle->sigBits != NULL) { + wolfSSL_ASN1_BIT_STRING_free(crle->sigBits); + crle->sigBits = NULL; + } + if (crle->sigAlgor != NULL) { + wolfSSL_X509_ALGOR_free(crle->sigAlgor); + crle->sigAlgor = NULL; + } if (crle->issuer != NULL) { FreeX509Name(crle->issuer); XFREE(crle->issuer, heap, DYNAMIC_TYPE_X509); @@ -816,6 +826,227 @@ int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, return ret ? ret : WOLFSSL_SUCCESS; /* convert 0 to WOLFSSL_SUCCESS */ } +/* Store CRL into a buffer in DER or PEM format. + * If buff is NULL, updates inOutSz with required size and returns success. + * Returns WOLFSSL_SUCCESS on success, negative on failure. + */ +int BufferStoreCRL(WOLFSSL_CRL* crl, byte* buff, long* inOutSz, int type) +{ + CRL_Entry* ent = NULL; + const byte* tbs = NULL; + word32 tbsSz = 0; + const byte* sig = NULL; + word32 sigSz = 0; + word32 sigOID = 0; +#ifdef WC_RSA_PSS + const byte* sigParams = NULL; + word32 sigParamsSz = 0; +#endif + word32 algoLen = 0; + word32 bitHdrLen = 0; + word32 totalContentLen = 0; + word32 outerHdrLen = 0; + word32 derNeeded = 0; + long outSz = 0; + + WOLFSSL_ENTER("BufferStoreCRL"); + + if (crl == NULL || inOutSz == NULL) { + return BAD_FUNC_ARG; + } + + outSz = *inOutSz; + + /* Access the first CRL entry. */ + if (wc_LockRwLock_Rd(&crl->crlLock) != 0) { + WOLFSSL_MSG("wc_LockRwLock_Rd failed"); + return BAD_MUTEX_E; + } + ent = crl->crlList; + if (ent != NULL) { + tbs = ent->toBeSigned; + tbsSz = ent->tbsSz; + sig = ent->signature; + sigSz = ent->signatureSz; + sigOID = ent->signatureOID; +#ifdef WC_RSA_PSS + sigParams = ent->sigParams; + sigParamsSz = ent->sigParamsSz; +#endif + } + wc_UnLockRwLock(&crl->crlLock); + + if (ent == NULL || tbs == NULL || tbsSz == 0 || sig == NULL || sigSz == 0) { + WOLFSSL_MSG("CRL entry missing toBeSigned/signature data"); + return BAD_FUNC_ARG; + } + + /* Calculate encoded lengths for AlgorithmIdentifier. */ +#ifdef WC_RSA_PSS + if (sigParams != NULL && sigParamsSz > 0) { + /* OID + explicit parameters inside SEQUENCE */ + word32 oidSz = 0; + word32 idLen; + const byte* oid = OidFromId(sigOID, oidSigType, &oidSz); + if (oid == NULL) { + WOLFSSL_MSG("Unknown signature OID for CRL"); + return WOLFSSL_FATAL_ERROR; + } + /* OBJECT IDENTIFIER header */ + idLen = (word32)SetObjectId((int)oidSz, NULL); + algoLen = SetSequence(idLen + oidSz + sigParamsSz, NULL) + + idLen + oidSz + sigParamsSz; + } + else +#endif + { + algoLen = SetAlgoID((int)sigOID, NULL, oidSigType, 0); + if (algoLen == 0) { + WOLFSSL_MSG("SetAlgoID failed"); + return WOLFSSL_FATAL_ERROR; + } + } + + /* BIT STRING header for signature */ + bitHdrLen = SetBitString(sigSz, 0, NULL); + + /* Compute total DER size. */ + totalContentLen = tbsSz + algoLen + bitHdrLen + sigSz; + outerHdrLen = SetSequence(totalContentLen, NULL); + derNeeded = outerHdrLen + totalContentLen; + + if (type == WOLFSSL_FILETYPE_ASN1) { + if (buff == NULL) { + *inOutSz = (long)derNeeded; + return WOLFSSL_SUCCESS; + } + if ((long)derNeeded > outSz) { + WOLFSSL_MSG("Output buffer too small for DER CRL"); + return BUFFER_E; + } + + /* Encode DER CRL directly into caller buffer. */ + { + word32 pos = 0; +#ifdef WC_RSA_PSS + word32 oidSz = 0; + const byte* oid = NULL; +#endif + /* Outer SEQUENCE header */ + pos += SetSequence(totalContentLen, buff + pos); + /* tbsCertList */ + XMEMCPY(buff + pos, tbs, tbsSz); + pos += tbsSz; + + /* signatureAlgorithm AlgorithmIdentifier */ +#ifdef WC_RSA_PSS + if (sigParams != NULL && sigParamsSz > 0) { + /* Lookup OID bytes for signature algorithm. */ + oid = OidFromId(sigOID, oidSigType, &oidSz); + if (oid == NULL) { + WOLFSSL_MSG("Unknown signature OID for CRL"); + return WOLFSSL_FATAL_ERROR; + } + /* SEQUENCE header for AlgorithmIdentifier */ + pos += SetSequence((word32)SetObjectId((int)oidSz, NULL) + + oidSz + sigParamsSz, buff + pos); + /* OBJECT IDENTIFIER header and content */ + pos += (word32)SetObjectId((int)oidSz, buff + pos); + XMEMCPY(buff + pos, oid, oidSz); + pos += oidSz; + /* Parameters as captured (already DER encoded) */ + XMEMCPY(buff + pos, sigParams, sigParamsSz); + pos += sigParamsSz; + } + else +#endif + { + pos += SetAlgoID((int)sigOID, buff + pos, oidSigType, 0); + } + + /* signature BIT STRING and bytes */ + pos += SetBitString(sigSz, 0, buff + pos); + XMEMCPY(buff + pos, sig, sigSz); + (void)pos; /* pos not used after this point */ + } + + *inOutSz = (long)derNeeded; + return WOLFSSL_SUCCESS; + } +#ifdef WOLFSSL_DER_TO_PEM + else if (type == WOLFSSL_FILETYPE_PEM) { + byte* derTmp = NULL; + int pemSz; + /* Build DER first in a temporary buffer. */ + derTmp = (byte*)XMALLOC(derNeeded, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (derTmp == NULL) { + return MEMORY_E; + } + /* Encode DER CRL into temporary buffer. */ + { + word32 pos = 0; +#ifdef WC_RSA_PSS + word32 oidSz = 0; + const byte* oid = NULL; +#endif + pos += SetSequence(totalContentLen, derTmp + pos); + XMEMCPY(derTmp + pos, tbs, tbsSz); + pos += tbsSz; +#ifdef WC_RSA_PSS + if (sigParams != NULL && sigParamsSz > 0) { + oid = OidFromId(sigOID, oidSigType, &oidSz); + if (oid == NULL) { + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FATAL_ERROR; + } + pos += SetSequence((word32)SetObjectId((int)oidSz, NULL) + + oidSz + sigParamsSz, derTmp + pos); + pos += (word32)SetObjectId((int)oidSz, derTmp + pos); + XMEMCPY(derTmp + pos, oid, oidSz); + pos += oidSz; + XMEMCPY(derTmp + pos, sigParams, sigParamsSz); + pos += sigParamsSz; + } + else +#endif + { + pos += SetAlgoID((int)sigOID, derTmp + pos, oidSigType, 0); + } + pos += SetBitString(sigSz, 0, derTmp + pos); + XMEMCPY(derTmp + pos, sig, sigSz); + (void)pos; /* pos not used after this point */ + } + + /* Determine required PEM size. */ + pemSz = wc_DerToPemEx(derTmp, derNeeded, NULL, 0, NULL, CRL_TYPE); + if (pemSz < 0) { + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FATAL_ERROR; + } + if (buff == NULL) { + *inOutSz = pemSz; + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } + if (outSz < pemSz) { + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_MSG("Output buffer too small for PEM CRL"); + return BUFFER_E; + } + if (wc_DerToPemEx(derTmp, derNeeded, buff, (word32)pemSz, NULL, + CRL_TYPE) < 0) { + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FATAL_ERROR; + } + *inOutSz = pemSz; + XFREE(derTmp, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_DER_TO_PEM */ + else { + return BAD_FUNC_ARG; + } +} #ifdef HAVE_CRL_UPDATE_CB /* Fill out CRL info structure, WOLFSSL_SUCCESS on ok */ @@ -1893,5 +2124,636 @@ int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor) } #endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */ +#ifndef NO_FILESYSTEM +/* Store CRL to a file in DER or PEM format. + * Returns WOLFSSL_SUCCESS on success, negative on failure. + * @param [in] crl CRL object. + * @param [in] path Path to the file to store the CRL. + * @param [in] type Format of encoding. Valid values: + * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. + * @return WOLFSSL_SUCCESS on success, or negative on failure. + */ +int StoreCRL(WOLFSSL_CRL* crl, const char* path, int type) +{ + XFILE fp = XBADFILE; + int ret = WOLFSSL_SUCCESS; + long sz = 0; + byte* mem = NULL; + + WOLFSSL_ENTER("StoreCRL"); + + if (crl == NULL || path == NULL) + return BAD_FUNC_ARG; + + /* Determine required size. */ + ret = BufferStoreCRL(crl, NULL, &sz, type); + if (ret != WOLFSSL_SUCCESS) { + return ret; + } + + /* Allocate temporary buffer. */ + mem = (byte*)XMALLOC((size_t)sz, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + return MEMORY_E; + } + + /* Encode CRL into buffer. */ + ret = BufferStoreCRL(crl, mem, &sz, type); + if (ret == WOLFSSL_SUCCESS) { + /* Open destination file for writing. */ + fp = XFOPEN(path, "wb"); + if (fp == XBADFILE) { + ret = WOLFSSL_BAD_FILE; + } + else { + size_t wrote = XFWRITE(mem, 1, (size_t)sz, fp); + if (wrote != (size_t)sz) { + WOLFSSL_MSG("CRL file write failed"); + ret = FWRITE_ERROR; + } + XFCLOSE(fp); + } + } + + XFREE(mem, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#else +int StoreCRL(WOLFSSL_CRL* crl, const char* file, int type) +{ + (void)crl; + (void)file; + (void)type; + return NOT_COMPILED_IN; +} +#endif /* NO_FILESYSTEM */ + +#if defined(OPENSSL_EXTRA) +/* Create a new empty CRL object for generation. + * Version is set to 2 by default. Use wolfSSL_X509_CRL_set_version() to change it. + * lastUpdate set to current time, nextUpdate set to 500 days from now. + * Returns a new CRL or NULL on failure. + */ +WOLFSSL_X509_CRL* wolfSSL_X509_CRL_new(void) +{ + WOLFSSL_X509_CRL* crl; + CRL_Entry* entry; + WOLFSSL_ASN1_TIME asnTime; + + WOLFSSL_ENTER("wolfSSL_X509_CRL_new"); + + crl = (WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), NULL, + DYNAMIC_TYPE_CRL); + if (crl == NULL) { + WOLFSSL_MSG("Memory allocation failed for CRL"); + return NULL; + } + + if (InitCRL(crl, NULL) < 0) { + WOLFSSL_MSG("Init CRL failed"); + XFREE(crl, NULL, DYNAMIC_TYPE_CRL); + return NULL; + } + + /* Allocate empty CRL entry for setting fields */ + entry = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY); + if (entry == NULL) { + WOLFSSL_MSG("Memory allocation failed for CRL entry"); + FreeCRL(crl, 1); + return NULL; + } + XMEMSET(entry, 0, sizeof(CRL_Entry)); + + if (wc_InitMutex(&entry->verifyMutex) != 0) { + XFREE(entry, NULL, DYNAMIC_TYPE_CRL_ENTRY); + FreeCRL(crl, 1); + return NULL; + } + + crl->crlList = entry; + + /* Set thisUpdate to current time */ + if (wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 0, 0) == NULL) { + WOLFSSL_MSG("Failed to get current time"); + wc_FreeMutex(&entry->verifyMutex); + XFREE(entry, NULL, DYNAMIC_TYPE_CRL_ENTRY); + FreeCRL(crl, 1); + return NULL; + } + if (wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to set last update"); + wc_FreeMutex(&entry->verifyMutex); + XFREE(entry, NULL, DYNAMIC_TYPE_CRL_ENTRY); + FreeCRL(crl, 1); + return NULL; + } + + /* Set next update date to 500 days from now, + * following convention from wc_InitCert() */ + if (wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 500, 0) == NULL) { + WOLFSSL_MSG("Failed to get next update time"); + wc_FreeMutex(&entry->verifyMutex); + XFREE(entry, NULL, DYNAMIC_TYPE_CRL_ENTRY); + FreeCRL(crl, 1); + return NULL; + } + if (wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to set next update"); + wc_FreeMutex(&entry->verifyMutex); + XFREE(entry, NULL, DYNAMIC_TYPE_CRL_ENTRY); + FreeCRL(crl, 1); + return NULL; + } + + /* Set default version to v2 (required for extensions) */ + entry->version = 2; + + return crl; +} + +#ifdef WOLFSSL_CERT_GEN +/* Add a revoked certificate entry to CRL. + * crl: target CRL + * rev: serial number of revoked certificate + * Returns WOLFSSL_SUCCESS on success. + * TODO: support other fields for OpenSSL compatibility: revocationDate, + * extensions, issuer, etc. + */ +int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl, + WOLFSSL_X509_REVOKED* rev) +{ + CRL_Entry* entry; + RevokedCert* rc; + RevokedCert* curr; + WOLFSSL_ASN1_TIME revDate = {0}; + + WOLFSSL_ENTER("wolfSSL_X509_CRL_add_revoked"); + + if (crl == NULL || rev == NULL || rev->serialNumber == NULL) { + return BAD_FUNC_ARG; + } + + entry = crl->crlList; + if (entry == NULL) { + return BAD_FUNC_ARG; + } + + /* Set the revocation date to the current time */ + if (wolfSSL_ASN1_TIME_adj(&revDate, XTIME(NULL), 0, 0) == NULL) { + WOLFSSL_MSG("Failed to get current time"); + return BAD_STATE_E; + } + + { + const byte* serial = rev->serialNumber->data; + int serialSz = rev->serialNumber->length; + + if (serial == NULL || serialSz <= 0) { + return BAD_FUNC_ARG; + } + + /* If the serial is DER-encoded ASN.1 INTEGER, strip tag/length. */ + if (serialSz >= 3 && serial[0] == ASN_INTEGER && + serial[1] == serialSz - 2) { + serial += 2; + serialSz -= 2; + } + + if (serialSz <= 0 || serialSz > EXTERNAL_SERIAL_SIZE) { + return BAD_FUNC_ARG; + } + + /* All zero serial numbers are invalid per rfc5280 and not supported */ + rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), crl->heap, + DYNAMIC_TYPE_REVOKED); + if (rc == NULL) { + return MEMORY_E; + } + XMEMSET(rc, 0, sizeof(RevokedCert)); + + XMEMCPY(rc->serialNumber, serial, (size_t)serialSz); + rc->serialSz = serialSz; + } + + XMEMCPY(rc->revDate, revDate.data, revDate.length); + rc->revDateFormat = (byte)revDate.type; + rc->next = NULL; + + /* Add to end of list */ + if (entry->certs == NULL) { + entry->certs = rc; + } + else { + for (curr = entry->certs; curr->next != NULL; curr = curr->next) + ; + curr->next = rc; + } + entry->totalCerts++; + + WOLFSSL_LEAVE("wolfSSL_X509_CRL_add_revoked", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} + +/* Add a revoked certificate entry to CRL by parsing a certificate buffer. + * crl: target CRL + * certBuf: DER-encoded certificate buffer + * certSz: size of certificate buffer + * revDate: revocation date (ASN.1 format), or NULL for + * current time + * revDateFmt: date format (ASN_UTC_TIME or ASN_GENERALIZED_TIME), ignored if + * revDate is NULL + * Returns WOLFSSL_SUCCESS on success. + * Note: this function is only available when WOLFSSL_CERT_GEN is defined. + */ +int wolfSSL_X509_CRL_add_revoked_cert(WOLFSSL_X509_CRL* crl, + const unsigned char* certBuf, int certSz) +{ + int ret; + DecodedCert cert[1]; + WOLFSSL_X509_REVOKED revoked; + WOLFSSL_ASN1_INTEGER* serialInt = NULL; + int i = 0; + + WOLFSSL_ENTER("wolfSSL_X509_CRL_add_revoked_cert"); + + if (crl == NULL || certBuf == NULL || certSz <= 0) { + return BAD_FUNC_ARG; + } + + /* Initialize and parse the certificate */ + InitDecodedCert(cert, certBuf, (word32)certSz, NULL); + ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, NULL, NULL); + if (ret != 0) { + WOLFSSL_MSG("Failed to parse certificate"); + FreeDecodedCert(cert); + return ret; + } + + serialInt = wolfSSL_ASN1_INTEGER_new(); + if (serialInt == NULL) { + FreeDecodedCert(cert); + return MEMORY_E; + } + + if (cert->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) { + serialInt->data = (unsigned char*)XMALLOC(cert->serialSz + 2, NULL, + DYNAMIC_TYPE_OPENSSL); + if (serialInt->data == NULL) { + wolfSSL_ASN1_INTEGER_free(serialInt); + FreeDecodedCert(cert); + return MEMORY_E; + } + serialInt->dataMax = (unsigned int)cert->serialSz + 2; + serialInt->isDynamic = 1; + } + else { + serialInt->data = serialInt->intData; + serialInt->dataMax = WOLFSSL_ASN1_INTEGER_MAX; + } + + serialInt->data[i++] = ASN_INTEGER; + i += SetLength(cert->serialSz, serialInt->data + i); + XMEMCPY(&serialInt->data[i], cert->serial, cert->serialSz); + serialInt->length = cert->serialSz + 2; + + revoked.serialNumber = serialInt; + + /* Add the revoked certificate entry */ + ret = wolfSSL_X509_CRL_add_revoked(crl, &revoked); + + FreeDecodedCert(cert); + wolfSSL_ASN1_INTEGER_free(serialInt); + + return ret; +} + +/* Unified cleanup macro to avoid use of goto */ +#define SIGN_CRL_CLEANUP() \ + do { \ + if (issuerDer) \ + XFREE(issuerDer, NULL, DYNAMIC_TYPE_OPENSSL); \ + if (buf) \ + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); \ + if (rngInit) \ + wc_FreeRng(&rng); \ + } while(0) + +static int GetCrlSignBufSz(int tbsSz, int sigType, RsaKey* rsaKey, + ecc_key* eccKey) +{ + int sigSz = 0; + int ret; + byte sigDummy = 0; + + if (tbsSz <= 0) + return BAD_FUNC_ARG; + +#ifndef NO_RSA + if (rsaKey != NULL) { + sigSz = wc_RsaEncryptSize(rsaKey); + } +#endif +#ifdef HAVE_ECC + if (sigSz <= 0 && eccKey != NULL) { + sigSz = wc_ecc_sig_size(eccKey); + } +#endif + if (sigSz <= 0) { + /* Fallback for unexpected key sizes */ + sigSz = 1024; + } + + ret = AddSignature(NULL, tbsSz, &sigDummy, sigSz, sigType); + if (ret < 0) { + ret = tbsSz + sigSz + 64; + } + return ret; +} + +/* Sign a CRL with a private key, rebuilding TBS from fields. + * crl: CRL with fields set via setter functions + * pkey: private key for signing + * md: digest algorithm (e.g., EVP_sha256()) + * Note: only one entry is supported in the CRL list. + * Returns WOLFSSL_SUCCESS on success. + */ +int wolfSSL_X509_CRL_sign(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_MD* md) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + CRL_Entry* entry; + byte* issuerDer = NULL; + int issuerSz = 0; + int sigType; + int tbsSz; + int totalSz = 0; + byte* buf = NULL; + int bufSz; + RsaKey* rsaKey = NULL; + ecc_key* eccKey = NULL; + WC_RNG rng; + int rngInit = 0; + + WOLFSSL_ENTER("wolfSSL_X509_CRL_sign"); + + if (crl == NULL || pkey == NULL || md == NULL) { + return BAD_FUNC_ARG; + } + + /* Fetch only the first entry in the CRL list */ + entry = crl->crlList; + if (entry == NULL) { + WOLFSSL_MSG("CRL has no entry"); + return BAD_FUNC_ARG; + } + + /* Determine signature type from digest and key type */ +#ifndef NO_RSA + if (pkey->type == WC_EVP_PKEY_RSA) { + if (md == wolfSSL_EVP_sha256()) { + sigType = CTC_SHA256wRSA; + } + #ifdef WOLFSSL_SHA384 + else if (md == wolfSSL_EVP_sha384()) { + sigType = CTC_SHA384wRSA; + } + #endif + #ifdef WOLFSSL_SHA512 + else if (md == wolfSSL_EVP_sha512()) { + sigType = CTC_SHA512wRSA; + } + #endif + else if (md == wolfSSL_EVP_sha1()) { + sigType = CTC_SHAwRSA; + } + else { + WOLFSSL_MSG("Unsupported digest for RSA"); + return BAD_FUNC_ARG; + } + rsaKey = (RsaKey*)pkey->rsa->internal; + } + else +#endif +#ifdef HAVE_ECC + if (pkey->type == WC_EVP_PKEY_EC) { + if (md == wolfSSL_EVP_sha256()) { + sigType = CTC_SHA256wECDSA; + } + #ifdef WOLFSSL_SHA384 + else if (md == wolfSSL_EVP_sha384()) { + sigType = CTC_SHA384wECDSA; + } + #endif + #ifdef WOLFSSL_SHA512 + else if (md == wolfSSL_EVP_sha512()) { + sigType = CTC_SHA512wECDSA; + } + #endif + else if (md == wolfSSL_EVP_sha1()) { + sigType = CTC_SHAwECDSA; + } + else { + WOLFSSL_MSG("Unsupported digest for ECDSA"); + return BAD_FUNC_ARG; + } + eccKey = (ecc_key*)pkey->ecc->internal; + } + else +#endif + { + WOLFSSL_MSG("Unsupported key type"); + return BAD_FUNC_ARG; + } + + /* Get issuer name DER */ + if (entry->issuer != NULL) { + issuerSz = wolfSSL_i2d_X509_NAME(entry->issuer, &issuerDer); + if (issuerSz <= 0) { + WOLFSSL_MSG("Failed to encode issuer name"); + return WOLFSSL_FAILURE; + } + } + else { + WOLFSSL_MSG("CRL has no issuer set"); + return BAD_FUNC_ARG; + } + + /* Copy dates from ASN1 time structures to raw fields if needed */ + if (entry->lastDateAsn1.length > 0 && entry->lastDateFormat == 0) { + XMEMCPY(entry->lastDate, entry->lastDateAsn1.data, + (size_t)entry->lastDateAsn1.length); + entry->lastDateFormat = (byte)entry->lastDateAsn1.type; + } + if (entry->nextDateAsn1.length > 0 && entry->nextDateFormat == 0) { + XMEMCPY(entry->nextDate, entry->nextDateAsn1.data, + (size_t)entry->nextDateAsn1.length); + entry->nextDateFormat = (byte)entry->nextDateAsn1.type; + } + + /* Verify we have valid dates */ + if (entry->lastDateFormat == 0) { + WOLFSSL_MSG("CRL has no lastUpdate date set"); + XFREE(issuerDer, NULL, DYNAMIC_TYPE_OPENSSL); + return BAD_FUNC_ARG; + } + + /* Initialize RNG */ + if (wc_InitRng(&rng) != 0) { + WOLFSSL_MSG("RNG init failed"); + XFREE(issuerDer, NULL, DYNAMIC_TYPE_OPENSSL); + return WOLFSSL_FAILURE; + } + rngInit = 1; + + bufSz = wc_MakeCRL_ex(issuerDer, (word32)issuerSz, + entry->lastDate, entry->lastDateFormat, + entry->nextDate, entry->nextDateFormat, + entry->certs, entry->totalCerts, + entry->crlNumberSet ? (const byte*)entry->crlNumber : NULL, + entry->crlNumberSet ? CRL_MAX_NUM_SZ : 0, + sigType, entry->version, + NULL, 0); + if (bufSz < 0) { + WOLFSSL_MSG("wc_MakeCRL_ex size check failed"); + SIGN_CRL_CLEANUP(); + return bufSz; + } + + bufSz = GetCrlSignBufSz(bufSz, sigType, rsaKey, eccKey); + if (bufSz <= 0) { + WOLFSSL_MSG("CRL buffer size calc failed"); + SIGN_CRL_CLEANUP(); + return bufSz; + } + + /* Allocate working buffer for TBS + signature */ + buf = (byte*)XMALLOC(bufSz, crl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + SIGN_CRL_CLEANUP(); + return MEMORY_E; + } + + /* Build to-be-signed (TBS) portion of the CRL buffer. + * Note that we pass the fields rather than the CRL_entry struct so + * wolfcrypt need not know about the openSSL-compatible CRL_entry struct. */ + tbsSz = wc_MakeCRL_ex(issuerDer, (word32)issuerSz, + entry->lastDate, entry->lastDateFormat, + entry->nextDate, entry->nextDateFormat, + entry->certs, entry->totalCerts, + entry->crlNumberSet ? (const byte*)entry->crlNumber : NULL, + entry->crlNumberSet ? CRL_MAX_NUM_SZ : 0, + sigType, entry->version, + buf, bufSz); + if (tbsSz < 0) { + WOLFSSL_MSG("wc_MakeCRL_ex failed"); + SIGN_CRL_CLEANUP(); + return tbsSz; + } + + /* Sign and complete CRL. Note that the output buffer is the same as the input buffer. + * The signature is added to the end of the buffer. */ + totalSz = wc_SignCRL_ex(buf, tbsSz, sigType, buf, bufSz, + rsaKey, eccKey, &rng); + if (totalSz < 0) { + WOLFSSL_MSG("wc_SignCRL_ex failed"); + SIGN_CRL_CLEANUP(); + return totalSz; + } + + /* Update CRL entry with new toBeSigned and signature */ + /* Free old buffers if present */ + if (entry->toBeSigned != NULL) { + XFREE(entry->toBeSigned, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + } + if (entry->signature != NULL) { + XFREE(entry->signature, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + } + + /* Extract TBS and signature from the complete CRL buffer. + * This bookkeeping ensures the CRL_entry is updated with the results + * from the complete CRL buffer. + * After AddSignature, the buffer layout is: + * [outer SEQUENCE header][TBS][AlgorithmIdentifier][BIT STRING signature] + */ + { + word32 idx = 0; + int len; + word32 tbsStart, tbsLen; + int sigLen; + + /* Parse outer SEQUENCE */ + if (GetSequence(buf, &idx, &len, (word32)totalSz) < 0) { + SIGN_CRL_CLEANUP(); + return ASN_PARSE_E; + } + + /* TBS starts here */ + tbsStart = idx; + + /* Parse TBS SEQUENCE to get its length */ + if (GetSequence(buf, &idx, &len, (word32)totalSz) < 0) { + SIGN_CRL_CLEANUP(); + return ASN_PARSE_E; + } + tbsLen = idx + (word32)len - tbsStart; + idx = tbsStart + tbsLen; /* Move past TBS */ + + /* Allocate and copy TBS */ + entry->toBeSigned = (byte*)XMALLOC(tbsLen, crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (entry->toBeSigned == NULL) { + SIGN_CRL_CLEANUP(); + return MEMORY_E; + } + XMEMCPY(entry->toBeSigned, buf + tbsStart, tbsLen); + entry->tbsSz = tbsLen; + + /* Skip AlgorithmIdentifier */ + if (GetAlgoId(buf, &idx, (word32*)&len, oidSigType, (word32)totalSz) < 0) { + XFREE(entry->toBeSigned, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + SIGN_CRL_CLEANUP(); + return ASN_PARSE_E; + } + + /* Get BIT STRING */ + if (GetASNHeader(buf, ASN_BIT_STRING, &idx, &sigLen, (word32)totalSz) < 0) { + XFREE(entry->toBeSigned, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + SIGN_CRL_CLEANUP(); + return ASN_PARSE_E; + } + + /* Skip unused bits byte */ + if (buf[idx] != 0) { + XFREE(entry->toBeSigned, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + SIGN_CRL_CLEANUP(); + return ASN_PARSE_E; + } + idx++; + sigLen--; + + entry->signature = (byte*)XMALLOC((word32)sigLen, crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (entry->signature == NULL) { + XFREE(entry->toBeSigned, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + SIGN_CRL_CLEANUP(); + return MEMORY_E; + } + XMEMCPY(entry->signature, buf + idx, (size_t)sigLen); + entry->signatureSz = (word32)sigLen; + entry->signatureOID = (word32)sigType; + } + + /* Mark the CRL as verified/signed for future reference. */ + entry->verified = 1; + ret = WOLFSSL_SUCCESS; + + SIGN_CRL_CLEANUP(); + + return ret; +} +#endif /* WOLFSSL_CERT_GEN */ + +#endif /* OPENSSL_EXTRA */ + #endif /* HAVE_CRL */ #endif /* !WOLFCRYPT_ONLY */ diff --git a/src/pk.c b/src/pk.c index 8f07a679c1..e1b1884e7d 100644 --- a/src/pk.c +++ b/src/pk.c @@ -63,7 +63,7 @@ #define ASN_LEN_SIZE(l) \ (((l) < 128) ? 1 : (((l) < 256) ? 2 : 3)) -#if defined(OPENSSL_EXTRA) +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #ifndef NO_ASN @@ -16721,4 +16721,3 @@ int wolfSSL_PEM_write_PKCS8PrivateKey(XFILE f, WOLFSSL_EVP_PKEY* pkey, ******************************************************************************/ #endif /* !WOLFSSL_PK_INCLUDED */ - diff --git a/src/ssl.c b/src/ssl.c index 160af7fe0c..dd8b9468b7 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -16265,7 +16265,7 @@ void wolfSSL_set_dynlock_destroy_callback( #endif /* OPENSSL_EXTRA */ -#ifdef OPENSSL_EXTRA +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #ifndef NO_CERTS #if !defined(NO_ASN) && !defined(NO_PWDBASED) @@ -16454,7 +16454,7 @@ int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) #endif /* !NO_ASN && !NO_PWDBASED */ #endif /* !NO_CERTS */ -#endif /* OPENSSL_EXTRA */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef OPENSSL_EXTRA @@ -22924,6 +22924,10 @@ int wolfSSL_set_alpn_protos(WOLFSSL* ssl, #include "src/bio.c" #endif +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + word32 nid2oid(int nid, int grp) { /* get OID type */ @@ -23691,6 +23695,10 @@ int oid2nid(word32 oid, int grp) return WOLFSSL_FATAL_ERROR; } +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) + /* frees all nodes in the current threads error queue * * id thread id. ERR_remove_state is depreciated and id is ignored. The diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 2fe3cab470..c4894b5a0e 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -722,7 +722,8 @@ void* wolfSSL_ASN1_item_d2i(void** dst, const byte **src, long len, * ASN1_BIT_STRING APIs ******************************************************************************/ -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(WOLFSSL_WPAS_SMALL) /* Create a new ASN.1 BIT_STRING object. * * @return ASN.1 BIT_STRING object on success. @@ -4658,9 +4659,10 @@ int wolfSSL_i2d_ASN1_TYPE(WOLFSSL_ASN1_TYPE* at, unsigned char** pp) return ret; } -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || WOLFSSL_WPAS_SMALL */ -#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS) || \ +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_WPAS) || \ defined(WOLFSSL_WPAS_SMALL) /** * Set ASN.1 TYPE object with a type and value. @@ -4723,9 +4725,8 @@ int wolfSSL_ASN1_TYPE_get(const WOLFSSL_ASN1_TYPE *a) return 0; } -#endif /* OPENSSL_ALL || OPENSSL_EXTRA || WOLFSSL_WPAS */ +#endif /* OPENSSL_ALL || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || WOLFSSL_WPAS */ #endif /* !NO_ASN */ #endif /* !WOLFSSL_SSL_ASN1_INCLUDED */ - diff --git a/src/x509.c b/src/x509.c index 7594b0dae8..bb876407c1 100644 --- a/src/x509.c +++ b/src/x509.c @@ -34,6 +34,9 @@ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #include #endif +#ifdef OPENSSL_EXTRA + #include +#endif #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) unsigned int wolfSSL_X509_get_extension_flags(WOLFSSL_X509* x509) @@ -2840,8 +2843,31 @@ int wolfSSL_X509_add_altname(WOLFSSL_X509* x509, const char* name, int type) return WOLFSSL_SUCCESS; if (type == ASN_IP_TYPE) { - WOLFSSL_MSG("Type not supported, use wolfSSL_X509_add_altname_ex"); +#ifdef WOLFSSL_IP_ALT_NAME + byte ip4[4]; + byte ip6[16]; + int ptonRet; + + /* Check if this is an ip4 address */ + ptonRet = XINET_PTON(WOLFSSL_IP4, name, ip4); + if (ptonRet == 1) { + return wolfSSL_X509_add_altname_ex(x509, (const char*)ip4, 4, + type); + } + + /* Check for ip6 */ + ptonRet = XINET_PTON(WOLFSSL_IP6, name, ip6); + if (ptonRet == 1) { + return wolfSSL_X509_add_altname_ex(x509, (const char*)ip6, 16, + type); + } + + WOLFSSL_MSG("IP address parse failed"); return WOLFSSL_FAILURE; +#else + WOLFSSL_MSG("WOLFSSL_IP_ALT_NAME not enabled"); + return WOLFSSL_FAILURE; +#endif } return wolfSSL_X509_add_altname_ex(x509, name, nameSz, type); @@ -8710,7 +8736,7 @@ WOLFSSL_X509_CRL* wolfSSL_d2i_X509_CRL(WOLFSSL_X509_CRL** crl, * return X509_NAME* on success * return NULL on failure */ -WOLFSSL_X509_NAME* wolfSSL_X509_CRL_get_issuer_name(WOLFSSL_X509_CRL* crl) +WOLFSSL_X509_NAME* wolfSSL_X509_CRL_get_issuer_name(const WOLFSSL_X509_CRL* crl) { if (crl == NULL || crl->crlList == NULL) return NULL; @@ -8718,6 +8744,30 @@ WOLFSSL_X509_NAME* wolfSSL_X509_CRL_get_issuer_name(WOLFSSL_X509_CRL* crl) return crl->crlList->issuer; } +/* Set issuer name of CRL + * return WOLFSSL_SUCCESS on success + * return WOLFSSL_FAILURE on failure + */ +int wolfSSL_X509_CRL_set_issuer_name(WOLFSSL_X509_CRL* crl, const WOLFSSL_X509_NAME* name) +{ + WOLFSSL_X509_NAME* newName; + + if (crl == NULL || crl->crlList == NULL || name == NULL) + return WOLFSSL_FAILURE; + + newName = wolfSSL_X509_NAME_dup(name); + if (newName == NULL) + return WOLFSSL_FAILURE; + + if (crl->crlList->issuer != NULL) { + FreeX509Name(crl->crlList->issuer); + XFREE(crl->crlList->issuer, crl->heap, DYNAMIC_TYPE_X509); + } + crl->crlList->issuer = newName; + + return WOLFSSL_SUCCESS; +} + /* Retrieve version from CRL * return version on success * return 0 on failure @@ -8730,6 +8780,20 @@ int wolfSSL_X509_CRL_version(WOLFSSL_X509_CRL* crl) return crl->crlList->version; } +/* Set version of CRL + * RFC 5280: 5.2.1. CRL version is 0 for v1, 1 for v2, etc + * return WOLFSSL_SUCCESS on success + * return WOLFSSL_FAILURE on failure + */ +int wolfSSL_X509_CRL_set_version(WOLFSSL_X509_CRL* crl, long version) +{ + if (crl == NULL || crl->crlList == NULL) + return WOLFSSL_FAILURE; + + crl->crlList->version = (int)version; + return WOLFSSL_SUCCESS; +} + /* Retrieve sig OID from CRL * return OID on success * return 0 on failure @@ -8742,6 +8806,19 @@ int wolfSSL_X509_CRL_get_signature_type(WOLFSSL_X509_CRL* crl) return crl->crlList->signatureOID; } +/* Set signature type of CRL + * return WOLFSSL_SUCCESS on success + * return WOLFSSL_FAILURE on failure + */ +int wolfSSL_X509_CRL_set_signature_type(WOLFSSL_X509_CRL* crl, int signatureType) +{ + if (crl == NULL || crl->crlList == NULL) + return WOLFSSL_FAILURE; + + crl->crlList->signatureOID = signatureType; + return WOLFSSL_SUCCESS; +} + /* Retrieve sig NID from CRL * return NID on success * return 0 on failure @@ -8754,29 +8831,132 @@ int wolfSSL_X509_CRL_get_signature_nid(const WOLFSSL_X509_CRL* crl) return oid2nid(crl->crlList->signatureOID, oidSigType); } +/* Set signature NID of CRL + * return OID on success + * return negative value on failure + */ +int wolfSSL_X509_CRL_set_signature_nid(WOLFSSL_X509_CRL* crl, int nid) +{ + if (crl == NULL || crl->crlList == NULL || nid <= 0) + return BAD_FUNC_ARG; + + crl->crlList->signatureOID = nid2oid(nid, oidSigType); + return WOLFSSL_SUCCESS; +} + /* Retrieve signature from CRL * return WOLFSSL_SUCCESS on success and negative values on failure */ -int wolfSSL_X509_CRL_get_signature(WOLFSSL_X509_CRL* crl, - unsigned char* buf, int* bufSz) +void wolfSSL_X509_CRL_get_signature(const WOLFSSL_X509_CRL* crl, + const WOLFSSL_ASN1_BIT_STRING **psig, const WOLFSSL_X509_ALGOR **palg) { + CRL_Entry* entry; + WOLFSSL_ASN1_BIT_STRING* bitStr; + WOLFSSL_X509_ALGOR* algor; + int nid; + WOLFSSL_ENTER("wolfSSL_X509_CRL_get_signature"); + if (psig) { + *psig = NULL; + } + if (palg) { + *palg = NULL; + } + if (crl == NULL || crl->crlList == NULL || - crl->crlList->signature == NULL || bufSz == NULL) + crl->crlList->signature == NULL || crl->crlList->signatureSz == 0) { + return; + } + + entry = ((WOLFSSL_X509_CRL*)crl)->crlList; + + if (psig) { + bitStr = entry->sigBits; + if (bitStr == NULL) { + bitStr = wolfSSL_ASN1_BIT_STRING_new(); + if (bitStr == NULL) { + return; + } + entry->sigBits = bitStr; + } + + if (bitStr->data == NULL || bitStr->length != (int)entry->signatureSz) { + XFREE(bitStr->data, NULL, DYNAMIC_TYPE_OPENSSL); + bitStr->data = (byte*)XMALLOC(entry->signatureSz, NULL, + DYNAMIC_TYPE_OPENSSL); + if (bitStr->data == NULL) { + bitStr->length = 0; + return; + } + } + XMEMCPY(bitStr->data, entry->signature, entry->signatureSz); + bitStr->length = (int)entry->signatureSz; + bitStr->type = WOLFSSL_V_ASN1_BIT_STRING; + bitStr->flags = 0; + + *psig = bitStr; + } + + if (palg) { + nid = oid2nid(entry->signatureOID, oidSigType); + algor = entry->sigAlgor; + if (algor == NULL || + (algor->algorithm != NULL && + wolfSSL_OBJ_obj2nid(algor->algorithm) != nid)) { + if (algor != NULL) { + wolfSSL_X509_ALGOR_free(algor); + } + algor = wolfSSL_X509_ALGOR_new(); + if (algor == NULL) { + return; + } + if (wolfSSL_X509_ALGOR_set0(algor, wolfSSL_OBJ_nid2obj(nid), + WOLFSSL_V_ASN1_NULL, NULL) != WOLFSSL_SUCCESS) { + wolfSSL_X509_ALGOR_free(algor); + return; + } + entry->sigAlgor = algor; + } + *palg = algor; + } +} + +int wolfSSL_X509_CRL_set_signature(WOLFSSL_X509_CRL* crl, + unsigned char* buf, int bufSz) +{ + byte* newSig; + + if (crl == NULL || crl->crlList == NULL || buf == NULL || bufSz <= 0) return BAD_FUNC_ARG; - if (buf != NULL) { - if (*bufSz < (int)crl->crlList->signatureSz) { - WOLFSSL_MSG("Signature buffer too small"); - return BUFFER_E; + /* Ensure signature buffer is allocated and large enough. */ + if (crl->crlList->signature == NULL) { + crl->crlList->signature = (byte*)XMALLOC((word32)bufSz, crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (crl->crlList->signature == NULL) { + return MEMORY_E; } - else { - XMEMCPY(buf, crl->crlList->signature, crl->crlList->signatureSz); + crl->crlList->signatureSz = (word32)bufSz; + } + else if ((word32)bufSz > crl->crlList->signatureSz) { + newSig = (byte*)XMALLOC((word32)bufSz, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + if (newSig == NULL) { + return MEMORY_E; } + XFREE(crl->crlList->signature, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + crl->crlList->signature = newSig; + crl->crlList->signatureSz = (word32)bufSz; } - *bufSz = (int)crl->crlList->signatureSz; + XMEMCPY(crl->crlList->signature, buf, bufSz); + crl->crlList->signatureSz = (word32)bufSz; +#if defined(OPENSSL_EXTRA) + if (crl->crlList->sigBits != NULL) { + wolfSSL_ASN1_BIT_STRING_free(crl->crlList->sigBits); + crl->crlList->sigBits = NULL; + } +#endif return WOLFSSL_SUCCESS; } @@ -8856,34 +9036,17 @@ static int X509RevokedPrintSerial(WOLFSSL_BIO* bio, RevokedCert* rev, static int X509CRLPrintSignature(WOLFSSL_BIO* bio, WOLFSSL_X509_CRL* crl, int algOnly, int indent) { - int sigSz = 0; + const WOLFSSL_ASN1_BIT_STRING* sig = NULL; + int sigNid = wolfSSL_X509_CRL_get_signature_nid(crl); - if (wolfSSL_X509_CRL_get_signature(crl, NULL, &sigSz) <= 0) { + wolfSSL_X509_CRL_get_signature(crl, &sig, NULL); + if (sig == NULL || sig->data == NULL || sig->length <= 0) { return WOLFSSL_FAILURE; } - if (sigSz > 0) { - unsigned char* sig; - int sigNid = wolfSSL_X509_CRL_get_signature_nid(crl); - - sig = (unsigned char*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (sig == NULL) { - return WOLFSSL_FAILURE; - } - - if (wolfSSL_X509_CRL_get_signature(crl, sig, &sigSz) <= 0) { - XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - - if (X509PrintSignature_ex(bio, sig, sigSz, sigNid, algOnly, indent) - != WOLFSSL_SUCCESS) { - XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - - XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - + if (X509PrintSignature_ex(bio, sig->data, sig->length, sigNid, + algOnly, indent) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; @@ -9261,8 +9424,16 @@ WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl) (crl->crlList->lastDateAsn1.data[0] != 0)) { return &crl->crlList->lastDateAsn1; } - else - return NULL; + return NULL; +} + +int wolfSSL_X509_CRL_set_lastUpdate(WOLFSSL_X509_CRL* crl, const WOLFSSL_ASN1_TIME* time) +{ + if (crl != NULL && crl->crlList != NULL && time != NULL) { + crl->crlList->lastDateAsn1 = *time; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; } WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl) @@ -9271,8 +9442,16 @@ WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl) (crl->crlList->nextDateAsn1.data[0] != 0)) { return &crl->crlList->nextDateAsn1; } - else - return NULL; + return NULL; +} + +int wolfSSL_X509_CRL_set_nextUpdate(WOLFSSL_X509_CRL* crl, const WOLFSSL_ASN1_TIME* time) +{ + if (crl != NULL && crl->crlList != NULL && time != NULL) { + crl->crlList->nextDateAsn1 = *time; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; } #ifndef NO_WOLFSSL_STUB @@ -9284,8 +9463,222 @@ int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* key) return 0; } #endif + +/* Encode CRL to DER format in memory. + * + * If *out is NULL, allocates memory and returns it via *out. + * If *out is not NULL, writes DER data starting at *out. + * + * @param crl CRL to encode + * @param out Pointer to output buffer pointer + * @return Size of DER encoding on success, negative on failure + */ +int wolfSSL_i2d_X509_CRL(WOLFSSL_X509_CRL* crl, unsigned char** out) +{ + int ret; + long derSz = 0; + byte* der = NULL; + int alloced = 0; + + WOLFSSL_ENTER("wolfSSL_i2d_X509_CRL"); + + if (crl == NULL) { + return BAD_FUNC_ARG; + } + + /* Get required size */ + ret = BufferStoreCRL(crl, NULL, &derSz, WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS || derSz <= 0) { + WOLFSSL_MSG("BufferStoreCRL failed to get size"); + return WOLFSSL_FAILURE; + } + + if (out == NULL) { + /* Just return size */ + return (int)derSz; + } + + if (*out == NULL) { + /* Allocate output buffer */ + der = (byte*)XMALLOC((size_t)derSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (der == NULL) { + WOLFSSL_MSG("Memory allocation failed"); + return MEMORY_E; + } + alloced = 1; + } + else { + der = *out; + } + + /* Encode CRL to DER */ + ret = BufferStoreCRL(crl, der, &derSz, WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("BufferStoreCRL failed to encode"); + if (alloced) { + XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL); + } + return WOLFSSL_FAILURE; + } + + if (alloced) { + *out = der; + } + + return (int)derSz; +} #endif /* HAVE_CRL && OPENSSL_EXTRA */ +#if defined(WOLFSSL_CERT_EXT) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +/* Set CRL Distribution Points from pre-encoded DER. + * + * x509 - Certificate to modify + * der - Pre-encoded CRLDistributionPoints DER + * derSz - Size of DER in bytes + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_CRL_set_dist_points(WOLFSSL_X509* x509, + const unsigned char* der, int derSz) +{ + WOLFSSL_ENTER("wolfSSL_X509_CRL_set_dist_points"); + + if (x509 == NULL || der == NULL || derSz <= 0) { + return WOLFSSL_FAILURE; + } + + if (x509->rawCRLInfo != NULL) { + XFREE(x509->rawCRLInfo, x509->heap, DYNAMIC_TYPE_X509_EXT); + } + x509->rawCRLInfo = (byte*)XMALLOC((word32)derSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->rawCRLInfo == NULL) { + return WOLFSSL_FAILURE; + } + + XMEMCPY(x509->rawCRLInfo, der, (word32)derSz); + x509->rawCRLInfoSz = derSz; + x509->CRLdistSet = 1; + + return WOLFSSL_SUCCESS; +} + +/* Add CRL Distribution Point URI. + * Encodes URI into proper CRLDistributionPoints DER format. + * + * x509 - Certificate to modify + * uri - URI string (e.g., "http://crl.example.com/ca.crl") + * critical - Whether extension is critical + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_CRL_add_dist_point(WOLFSSL_X509* x509, + const char* uri, int critical) +{ + int uriLen; + byte* derBuf = NULL; + int derSz; + int idx; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_X509_CRL_add_dist_point"); + + if (x509 == NULL || uri == NULL) { + return WOLFSSL_FAILURE; + } + + uriLen = (int)XSTRLEN(uri); + if (uriLen == 0 || uriLen >= 128) { + /* Current implementation limited to URIs < 128 bytes */ + WOLFSSL_MSG("URI too long or empty"); + return WOLFSSL_FAILURE; + } + + /* + * Encode CRL Distribution Points in DER format: + * CRLDistributionPoints ::= SEQUENCE OF DistributionPoint + * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] EXPLICIT DistributionPointName OPTIONAL + * } + * DistributionPointName ::= CHOICE { + * fullName [0] IMPLICIT GeneralNames + * } + * GeneralNames ::= SEQUENCE OF GeneralName + * GeneralName ::= [6] IMPLICIT IA5String (uniformResourceIdentifier) + */ + + /* Allocate buffer for DER encoding */ + derSz = uriLen + 20; /* URI + tags + length bytes */ + derBuf = (byte*)XMALLOC((word32)derSz, x509->heap, DYNAMIC_TYPE_X509_EXT); + if (derBuf == NULL) { + return WOLFSSL_FAILURE; + } + + /* Build from inside out, starting from end of buffer */ + idx = derSz; + + /* Copy URI string */ + idx -= uriLen; + XMEMCPY(derBuf + idx, uri, (word32)uriLen); + + /* [6] IMPLICIT IA5String tag for URI (context-specific, primitive) */ + idx--; + derBuf[idx] = (byte)uriLen; + idx--; + derBuf[idx] = (ASN_CONTEXT_SPECIFIC | 6); /* [6] tag */ + + /* [0] IMPLICIT wrapper for GeneralNames (constructed) */ + { + int innerLen = derSz - idx; + idx--; + derBuf[idx] = (byte)innerLen; + idx--; + derBuf[idx] = (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED); + } + + /* [0] EXPLICIT wrapper for distributionPoint */ + { + int innerLen = derSz - idx; + idx--; + derBuf[idx] = (byte)innerLen; + idx--; + derBuf[idx] = (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED); + } + + /* SEQUENCE for DistributionPoint */ + { + int innerLen = derSz - idx; + idx--; + derBuf[idx] = (byte)innerLen; + idx--; + derBuf[idx] = (ASN_SEQUENCE | ASN_CONSTRUCTED); + } + + /* SEQUENCE for CRLDistributionPoints (outer) */ + { + int innerLen = derSz - idx; + idx--; + derBuf[idx] = (byte)innerLen; + idx--; + derBuf[idx] = (ASN_SEQUENCE | ASN_CONSTRUCTED); + } + + /* Store the encoded CRL info in x509 */ + { + int finalSz = derSz - idx; + ret = wolfSSL_X509_CRL_set_dist_points(x509, derBuf + idx, finalSz); + if (ret == WOLFSSL_SUCCESS && critical) { + x509->CRLdistCrit = 1; + } + } + + XFREE(derBuf, x509->heap, DYNAMIC_TYPE_X509_EXT); + + return ret; +} +#endif /* WOLFSSL_CERT_EXT && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ + #ifdef OPENSSL_EXTRA @@ -9864,10 +10257,11 @@ WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509) #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ -#ifdef OPENSSL_EXTRA +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -#if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD) \ - || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_APACHE_HTTPD) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) WOLFSSL_X509_ALGOR* wolfSSL_X509_ALGOR_new(void) { WOLFSSL_X509_ALGOR* ret; @@ -10448,7 +10842,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_sk_X509_OBJECT_deep_copy( /* Creates a duplicate of a WOLFSSL_X509_NAME structure. Returns a new WOLFSSL_X509_NAME structure or NULL on failure */ - WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(WOLFSSL_X509_NAME *name) + WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(const WOLFSSL_X509_NAME *name) { WOLFSSL_X509_NAME* copy = NULL; @@ -12327,6 +12721,19 @@ WOLFSSL_X509_CRL* wolfSSL_PEM_read_X509_CRL(XFILE fp, return (WOLFSSL_X509_CRL* )wolfSSL_PEM_read_X509_ex(fp, (void **)crl, cb, u, CRL_TYPE); } + +/* Convert CRL to DER or PEM format. + * Returns WOLFSSL_SUCCESS on success, negative on failure. + * The caller is responsible for freeing the buffer using XFREE. + */ +int wolfSSL_write_X509_CRL(WOLFSSL_X509_CRL* crl, const char* path, int type) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_write_X509_CRL"); + ret = StoreCRL(crl, path, type); + WOLFSSL_LEAVE("wolfSSL_write_X509_CRL", ret); + return ret; +} #endif #ifdef WOLFSSL_CERT_GEN @@ -13011,7 +13418,7 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_X509_NAME_ENTRY_get_object( else { /* iterate through and find first open spot */ for (i = 0; i < MAX_NAME_ENTRIES; i++) { - if (name->entry[i].set != 1) { /* not set so overwritten */ + if (name->entry[i].set == 0) { /* not set so overwritten */ WOLFSSL_MSG("Found place for name entry"); break; } @@ -13054,6 +13461,15 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_X509_NAME_ENTRY_get_object( return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_PYTHON + /* Set name index for OpenSSL stack index position and so Python can + * generate tuples/sets from the list. */ + for (i = 0; i < MAX_NAME_ENTRIES; i++) { + if (name->entry[i].set != 0) + name->entry[i].set = i + 1; + } +#endif + if (RebuildFullName(name) != 0) return WOLFSSL_FAILURE; @@ -13125,6 +13541,17 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_X509_NAME_ENTRY_get_object( return NULL; } name->entry[loc].set = 0; +#ifdef WOLFSSL_PYTHON + { + int i; + /* Set name index for OpenSSL stack index position and so Python can + * generate tuples/sets from the list. */ + for (i = 0; i < MAX_NAME_ENTRIES; i++) { + if (name->entry[i].set != 0) + name->entry[i].set = i + 1; + } + } +#endif return ret; } @@ -13175,7 +13602,7 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_X509_NAME_ENTRY_get_object( /* returns a pointer to the internal entry at location 'loc' on success, * a null pointer is returned in fail cases */ WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry( - WOLFSSL_X509_NAME *name, int loc) + const WOLFSSL_X509_NAME *name, int loc) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_X509_NAME_get_entry"); @@ -13191,15 +13618,7 @@ WOLFSSL_ASN1_OBJECT* wolfSSL_X509_NAME_ENTRY_get_object( } if (name->entry[loc].set) { -#ifdef WOLFSSL_PYTHON - /* "set" is not only flag use, but also stack index position use in - * OpenSSL. Python makes tuple based on this number. Therefore, - * updating "set" by position + 1. "plus 1" means to avoid "not set" - * zero. - */ - name->entry[loc].set = loc + 1; -#endif - return &name->entry[loc]; + return (WOLFSSL_X509_NAME_ENTRY*)&name->entry[loc]; } else { return NULL; @@ -14597,7 +15016,7 @@ int wolfSSL_sk_X509_OBJECT_push(WOLFSSL_STACK* sk, WOLFSSL_X509_OBJECT* obj) /* unlike wolfSSL_X509_NAME_dup this does not malloc a duplicate, only deep * copy. "to" is expected to be a fresh blank name, if not pointers could be * lost */ -int wolfSSL_X509_NAME_copy(WOLFSSL_X509_NAME* from, WOLFSSL_X509_NAME* to) +int wolfSSL_X509_NAME_copy(const WOLFSSL_X509_NAME* from, WOLFSSL_X509_NAME* to) { int i; @@ -14849,6 +15268,183 @@ int wolfSSL_X509_set_version(WOLFSSL_X509* x509, long v) return WOLFSSL_SUCCESS; } +#ifdef WOLFSSL_CERT_EXT +/* Set Subject Key Identifier from raw bytes. + * + * x509 - Certificate to modify + * skid - Raw SKID bytes + * skidSz - Size of SKID in bytes + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_set_subject_key_id(WOLFSSL_X509* x509, + const unsigned char* skid, int skidSz) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_subject_key_id"); + + if (x509 == NULL || skid == NULL || skidSz <= 0) { + return WOLFSSL_FAILURE; + } + + /* Allocate/reallocate memory for subjKeyId */ + if (x509->subjKeyId == NULL || (int)x509->subjKeyIdSz < skidSz) { + if (x509->subjKeyId != NULL) { + XFREE(x509->subjKeyId, x509->heap, DYNAMIC_TYPE_X509_EXT); + } + x509->subjKeyId = (byte*)XMALLOC((word32)skidSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->subjKeyId == NULL) { + return WOLFSSL_FAILURE; + } + } + + XMEMCPY(x509->subjKeyId, skid, (word32)skidSz); + x509->subjKeyIdSz = (word32)skidSz; + x509->subjKeyIdSet = 1; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_SHA +/* Set Subject Key Identifier by computing SHA-1 hash of the public key. + * + * x509 - Certificate to modify (must have public key set) + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_set_subject_key_id_ex(WOLFSSL_X509* x509) +{ + byte hash[WC_SHA_DIGEST_SIZE]; + int ret; + + WOLFSSL_ENTER("wolfSSL_X509_set_subject_key_id_ex"); + + if (x509 == NULL) { + return WOLFSSL_FAILURE; + } + + /* Check if public key has been set */ + if (x509->pubKey.buffer == NULL || x509->pubKey.length == 0) { + WOLFSSL_MSG("Public key not set"); + return WOLFSSL_FAILURE; + } + + /* Compute SHA-1 hash of the public key */ + ret = wc_ShaHash(x509->pubKey.buffer, x509->pubKey.length, hash); + if (ret != 0) { + WOLFSSL_MSG("wc_ShaHash failed"); + return WOLFSSL_FAILURE; + } + + return wolfSSL_X509_set_subject_key_id(x509, hash, WC_SHA_DIGEST_SIZE); +} +#endif /* !NO_SHA */ + +/* Set Authority Key Identifier from raw bytes. + * + * x509 - Certificate to modify + * akid - Raw AKID bytes + * akidSz - Size of AKID in bytes + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_set_authority_key_id(WOLFSSL_X509* x509, + const unsigned char* akid, int akidSz) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_authority_key_id"); + + if (x509 == NULL || akid == NULL || akidSz <= 0) { + return WOLFSSL_FAILURE; + } + + /* Allocate/reallocate memory for authKeyIdSrc */ + if (x509->authKeyIdSrc == NULL || (int)x509->authKeyIdSrcSz < akidSz) { + if (x509->authKeyIdSrc != NULL) { + XFREE(x509->authKeyIdSrc, x509->heap, DYNAMIC_TYPE_X509_EXT); + } + x509->authKeyIdSrc = (byte*)XMALLOC((word32)akidSz, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->authKeyIdSrc == NULL) { + return WOLFSSL_FAILURE; + } + } + + XMEMCPY(x509->authKeyIdSrc, akid, (word32)akidSz); + x509->authKeyIdSrcSz = (word32)akidSz; + x509->authKeyId = x509->authKeyIdSrc; + x509->authKeyIdSz = (word32)akidSz; + x509->authKeyIdSet = 1; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_SHA +/* Set Authority Key Identifier from issuer certificate. + * Extracts SKID from issuer (or computes from issuer's public key). + * + * x509 - Certificate to modify + * issuer - Issuer certificate + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_set_authority_key_id_ex(WOLFSSL_X509* x509, + WOLFSSL_X509* issuer) +{ + byte hash[WC_SHA_DIGEST_SIZE]; + int ret; + + WOLFSSL_ENTER("wolfSSL_X509_set_authority_key_id_ex"); + + if (x509 == NULL || issuer == NULL) { + return WOLFSSL_FAILURE; + } + + /* First try to use issuer's SKID if it's set */ + if (issuer->subjKeyIdSet && issuer->subjKeyId != NULL && + issuer->subjKeyIdSz > 0) { + return wolfSSL_X509_set_authority_key_id(x509, issuer->subjKeyId, + (int)issuer->subjKeyIdSz); + } + + /* Otherwise compute from issuer's public key */ + if (issuer->pubKey.buffer == NULL || issuer->pubKey.length == 0) { + WOLFSSL_MSG("Issuer public key not available"); + return WOLFSSL_FAILURE; + } + + ret = wc_ShaHash(issuer->pubKey.buffer, issuer->pubKey.length, hash); + if (ret != 0) { + WOLFSSL_MSG("wc_ShaHash failed"); + return WOLFSSL_FAILURE; + } + + return wolfSSL_X509_set_authority_key_id(x509, hash, WC_SHA_DIGEST_SIZE); +} +#endif /* !NO_SHA */ +#endif /* WOLFSSL_CERT_EXT */ + +#ifndef IGNORE_NETSCAPE_CERT_TYPE +/* Set Netscape Certificate Type extension. + * + * x509 - Certificate to modify + * nsCertType - Bitwise OR of NS_SSL_CLIENT, NS_SSL_SERVER, etc. + * + * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE + */ +int wolfSSL_X509_set_ns_cert_type(WOLFSSL_X509* x509, int nsCertType) +{ + WOLFSSL_ENTER("wolfSSL_X509_set_ns_cert_type"); + + if (x509 == NULL) { + return WOLFSSL_FAILURE; + } + + x509->nsCertType = (byte)nsCertType; + + return WOLFSSL_SUCCESS; +} +#endif /* !IGNORE_NETSCAPE_CERT_TYPE */ + #endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) && WOLFSSL_CERT_GEN */ #if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \ diff --git a/tests/api.c b/tests/api.c index 4f257c5dc6..bc6efd03a6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -17674,6 +17674,88 @@ static int test_wolfSSL_X509_SEP(void) return EXPECT_RESULT(); } +/* Test wolfSSL_X509_set_* extension functions */ +static int test_wolfSSL_X509_set_extensions(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) + WOLFSSL_X509* x509 = NULL; +#ifdef WOLFSSL_CERT_EXT + byte skid[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; + byte akid[20] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; +#endif +#ifndef IGNORE_NETSCAPE_CERT_TYPE + int nsCertType = 0; +#endif + + ExpectNotNull(x509 = wolfSSL_X509_new()); + +#ifdef WOLFSSL_CERT_EXT + /* Test wolfSSL_X509_set_subject_key_id */ + ExpectIntEQ(wolfSSL_X509_set_subject_key_id(NULL, skid, sizeof(skid)), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, NULL, sizeof(skid)), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, skid, 0), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_subject_key_id(x509, skid, sizeof(skid)), + WOLFSSL_SUCCESS); + + /* Test wolfSSL_X509_set_authority_key_id */ + ExpectIntEQ(wolfSSL_X509_set_authority_key_id(NULL, akid, sizeof(akid)), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, NULL, sizeof(akid)), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, akid, 0), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_authority_key_id(x509, akid, sizeof(akid)), + WOLFSSL_SUCCESS); + + /* Test wolfSSL_X509_CRL_add_dist_point */ + ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(NULL, + "http://crl.example.com/ca.crl", 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(x509, NULL, 0), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_CRL_add_dist_point(x509, + "http://crl.example.com/ca.crl", 0), WOLFSSL_SUCCESS); + + /* Test wolfSSL_X509_CRL_set_dist_points with raw DER */ + { + /* Simple CRL DP DER encoding for "http://example.com/crl" */ + byte crlDer[] = { + 0x30, 0x1d, /* SEQUENCE (outer) */ + 0x30, 0x1b, /* SEQUENCE (DistributionPoint) */ + 0xa0, 0x19, /* [0] EXPLICIT */ + 0xa0, 0x17, /* [0] IMPLICIT GeneralNames */ + 0x86, 0x15, /* [6] URI */ + 'h','t','t','p',':','/','/','e','x','a','m','p','l','e','.','c', + 'o','m','/','c','r','l' + }; + ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(NULL, crlDer, + sizeof(crlDer)), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, NULL, + sizeof(crlDer)), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, crlDer, 0), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_CRL_set_dist_points(x509, crlDer, + sizeof(crlDer)), WOLFSSL_SUCCESS); + } +#endif /* WOLFSSL_CERT_EXT */ + +#ifndef IGNORE_NETSCAPE_CERT_TYPE + /* Test wolfSSL_X509_set_ns_cert_type */ + nsCertType = WC_NS_SSL_CLIENT | WC_NS_SSL_SERVER; + ExpectIntEQ(wolfSSL_X509_set_ns_cert_type(NULL, nsCertType), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_X509_set_ns_cert_type(x509, nsCertType), + WOLFSSL_SUCCESS); +#endif + + wolfSSL_X509_free(x509); +#endif /* OPENSSL_EXTRA && !NO_CERTS */ + return EXPECT_RESULT(); +} + static int test_wolfSSL_OpenSSL_add_all_algorithms(void) { EXPECT_DECLS; @@ -19837,10 +19919,10 @@ static int test_sk_X509(void) return EXPECT_RESULT(); } -static int test_sk_X509_CRL(void) +static int test_sk_X509_CRL_decode(void) { EXPECT_DECLS; -#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && defined(HAVE_CRL) && \ +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && defined(HAVE_CRL) && \ !defined(NO_RSA) X509_CRL* crl = NULL; XFILE fp = XBADFILE; @@ -19933,11 +20015,18 @@ static int test_sk_X509_CRL(void) ExpectIntEQ(wolfSSL_X509_CRL_get_signature_type(&empty), 0); ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(NULL), 0); ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(&empty), 0); - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(NULL, NULL, NULL), BAD_FUNC_ARG); - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl , NULL, NULL), BAD_FUNC_ARG); - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(NULL, NULL, &len), BAD_FUNC_ARG); - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(&empty, NULL, &len), - BAD_FUNC_ARG); + { + const WOLFSSL_ASN1_BIT_STRING* sig = NULL; + const WOLFSSL_X509_ALGOR* sigAlg = NULL; + wolfSSL_X509_CRL_get_signature(NULL, NULL, NULL); + wolfSSL_X509_CRL_get_signature(crl, NULL, NULL); + wolfSSL_X509_CRL_get_signature(NULL, &sig, &sigAlg); + ExpectNull(sig); + ExpectNull(sigAlg); + wolfSSL_X509_CRL_get_signature(&empty, &sig, &sigAlg); + ExpectNull(sig); + ExpectNull(sigAlg); + } ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(NULL, NULL, NULL), BAD_FUNC_ARG); ExpectIntEQ(wolfSSL_X509_REVOKED_get_serial_number(rev , NULL, NULL), @@ -19954,15 +20043,15 @@ static int test_sk_X509_CRL(void) ExpectIntEQ(wolfSSL_X509_CRL_get_signature_type(crl), CTC_SHA256wRSA); ExpectIntEQ(wolfSSL_X509_CRL_get_signature_nid(crl), WC_NID_sha256WithRSAEncryption); - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl, NULL, &len), - WOLFSSL_SUCCESS); - ExpectIntEQ(len, 256); - len--; - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl, buff, &len), BUFFER_E); - len += 2; - ExpectIntEQ(wolfSSL_X509_CRL_get_signature(crl, buff, &len), - WOLFSSL_SUCCESS); - ExpectIntEQ(len, 256); + { + const WOLFSSL_ASN1_BIT_STRING* sig = NULL; + const WOLFSSL_X509_ALGOR* sigAlg = NULL; + wolfSSL_X509_CRL_get_signature(crl, &sig, &sigAlg); + ExpectNotNull(sig); + ExpectNotNull(sig->data); + ExpectIntEQ(sig->length, 256); + ExpectNotNull(sigAlg); + } ExpectNotNull(wolfSSL_X509_CRL_get_lastUpdate(crl)); ExpectNotNull(wolfSSL_X509_CRL_get_nextUpdate(crl)); @@ -20032,6 +20121,300 @@ static int test_sk_X509_CRL(void) return EXPECT_RESULT(); } +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ + defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) +/* Helper function to create, sign, and write a CRL */ +static int generate_crl_test(const char* keyFile, const char* certFile, + const char* derFile, const char* pemFile, + const char* certToRevokePath) +{ + EXPECT_DECLS; + X509_NAME* issuer = NULL; + X509_NAME* decodedIssuer = NULL; + WOLFSSL_X509* cert = NULL; + WOLFSSL_ASN1_TIME asnTime = {0}; + XFILE fp = XBADFILE; + WOLFSSL_X509_CRL* crl = NULL; + WOLFSSL_X509_CRL* decodedCrl = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + int i = 0; + int revokedCount = 0; + byte serialsToRevokeBytes[][1] = { { 0x02 }, { 0x03 }, { 0x04 } }; + static const int numSerials = (int)(sizeof(serialsToRevokeBytes) / sizeof(serialsToRevokeBytes[0])); + WOLFSSL_ASN1_INTEGER serialsToRevoke[3] = { + { .data = serialsToRevokeBytes[0], .length = sizeof(serialsToRevokeBytes[0]) }, + { .data = serialsToRevokeBytes[1], .length = sizeof(serialsToRevokeBytes[1]) }, + { .data = serialsToRevokeBytes[2], .length = sizeof(serialsToRevokeBytes[2]) } + }; + WOLFSSL_X509_REVOKED revoked[3] = { + { .serialNumber = &serialsToRevoke[0] }, + { .serialNumber = &serialsToRevoke[1] }, + { .serialNumber = &serialsToRevoke[2] } + }; + WOLFSSL_X509* certToRevoke = NULL; + + /* Load certificate to get issuer name (CRL issuer = cert subject) */ + ExpectTrue((fp = XFOPEN(certFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(cert = PEM_read_X509(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + /* Create a new empty CRL */ + ExpectNotNull(crl = wolfSSL_X509_CRL_new()); + ExpectIntEQ(wolfSSL_X509_CRL_version(crl), 2); + + /* Set issuer name, must match certificate subject for verification */ + ExpectNotNull(issuer = X509_get_subject_name(cert)); + ExpectIntEQ(wolfSSL_X509_CRL_set_issuer_name(crl, issuer), WOLFSSL_SUCCESS); + + /* Set thisUpdate to current time */ + ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 0, 0)); + ExpectIntEQ(wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime), WOLFSSL_SUCCESS); + + /* Set nextUpdate to 30 days from now */ + ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 30, 0)); + ExpectIntEQ(wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime), WOLFSSL_SUCCESS); + + /* Add revoked certificates based on serial numbers */ + for (i = 0; i < numSerials; i++) { + ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked[i]), + WOLFSSL_SUCCESS); + } + + /* Add a revoked certificate entry to CRL by parsing a different certificate buffer */ + ExpectTrue((fp = XFOPEN(certToRevokePath, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(certToRevoke = PEM_read_X509(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + { + const byte* certDer = NULL; + int certDerSz = 0; + + ExpectNotNull(certDer = wolfSSL_X509_get_der(certToRevoke, &certDerSz)); + ExpectIntEQ(wolfSSL_X509_CRL_add_revoked_cert(crl, certDer, certDerSz), + WOLFSSL_SUCCESS); + } + wolfSSL_X509_free(certToRevoke); + certToRevoke = NULL; + + /* Count revoked certificates - should be 'numSerials' + 1 */ + revokedCount = 0; + if (EXPECT_SUCCESS() && crl != NULL && crl->crlList != NULL) { + RevokedCert* rev = crl->crlList->certs; + while (rev != NULL) { + revokedCount++; + rev = rev->next; + } + } + ExpectIntEQ(revokedCount, numSerials + 1); + + /* Load private key for signing */ + ExpectTrue((fp = XFOPEN(keyFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + /* Sign the CRL */ + ExpectIntEQ(wolfSSL_X509_CRL_sign(crl, pkey, wolfSSL_EVP_sha256()), + WOLFSSL_SUCCESS); + + /* Encode CRL to DER */ + ExpectIntEQ(wolfSSL_write_X509_CRL(crl, derFile, WOLFSSL_FILETYPE_ASN1), + WOLFSSL_SUCCESS); + + /* Encode CRL to PEM */ + ExpectIntEQ(wolfSSL_write_X509_CRL(crl, pemFile, WOLFSSL_FILETYPE_PEM), + WOLFSSL_SUCCESS); + + /* ===== Validate encoded DER CRL by decoding and checking contents ===== */ + ExpectTrue((fp = XFOPEN(derFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(decodedCrl = d2i_X509_CRL_fp(fp, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + /* Verify CRL version is v2 */ + ExpectIntEQ(wolfSSL_X509_CRL_version(decodedCrl), 2); + + /* Verify issuer name matches */ + ExpectNotNull(decodedIssuer = wolfSSL_X509_CRL_get_issuer_name(decodedCrl)); + ExpectIntEQ(X509_NAME_cmp(issuer, decodedIssuer), 0); + + /* Verify signature type is SHA256 with RSA or ECDSA */ + ExpectIntNE(wolfSSL_X509_CRL_get_signature_type(decodedCrl), 0); + + /* Verify lastUpdate and nextUpdate are set */ + ExpectNotNull(wolfSSL_X509_CRL_get_lastUpdate(decodedCrl)); + ExpectNotNull(wolfSSL_X509_CRL_get_nextUpdate(decodedCrl)); + + /* Count revoked certificates - should be 'numSerials' */ + revokedCount = 0; + if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) { + RevokedCert* rev = decodedCrl->crlList->certs; + while (rev != NULL) { + revokedCount++; + rev = rev->next; + } + } + ExpectIntEQ(revokedCount, numSerials + 1); + + wolfSSL_X509_CRL_free(decodedCrl); + decodedCrl = NULL; + + /* ===== Validate encoded PEM CRL by decoding and checking contents ===== */ + ExpectTrue((fp = XFOPEN(pemFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(decodedCrl = (X509_CRL*)PEM_read_X509_CRL(fp, NULL, + NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + /* Verify CRL version is v2 */ + ExpectIntEQ(wolfSSL_X509_CRL_version(decodedCrl), 2); + + /* Verify issuer name matches */ + ExpectNotNull(decodedIssuer = wolfSSL_X509_CRL_get_issuer_name(decodedCrl)); + ExpectIntEQ(X509_NAME_cmp(issuer, decodedIssuer), 0); + + /* Count revoked certificates from PEM - should also be 'numSerials' */ + revokedCount = 0; + if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) { + RevokedCert* rev = decodedCrl->crlList->certs; + while (rev != NULL) { + revokedCount++; + rev = rev->next; + } + } + ExpectIntEQ(revokedCount, numSerials + 1); + + wolfSSL_X509_CRL_free(decodedCrl); + + wolfSSL_EVP_PKEY_free(pkey); + wolfSSL_X509_CRL_free(crl); + wolfSSL_X509_free(cert); + + return EXPECT_RESULT(); +} +#endif + +static int test_sk_X509_CRL_encode(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ + defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) +#ifndef NO_RSA + static const char* crlRsaPemFile = "./certs/crl/crlRsaOut.pem"; + static const char* crlRsaDerFile = "./certs/crl/crlRsaOut.der"; + static const char* testRsaKeyFile = "./certs/ca-key.pem"; + /* Use ca-cert.pem to match ca-key.pem for proper CRL verification */ + static const char* testRsaCertFile = "./certs/ca-cert.pem"; + static const char* revokeRsaCertFile = "./certs/server-cert.pem"; +#endif +#ifdef HAVE_ECC + static const char* crlEccPemFile = "./certs/crl/crlEccOut.pem"; + static const char* crlEccDerFile = "./certs/crl/crlEccOut.der"; + static const char* testEccKeyFile = "./certs/ca-ecc-key.pem"; + /* Use ca-ecc-cert.pem to match ca-ecc-key.pem for proper CRL verification */ + static const char* testEccCertFile = "./certs/ca-ecc-cert.pem"; + static const char* revokeEccCertFile = "./certs/server-ecc.pem"; +#endif + +#ifndef NO_RSA + /* Generate RSA-signed CRL (PEM and DER) */ + ExpectIntEQ(generate_crl_test(testRsaKeyFile, testRsaCertFile, + crlRsaDerFile, crlRsaPemFile, revokeRsaCertFile), TEST_SUCCESS); +#endif + +#ifdef HAVE_ECC + /* Generate ECC-signed CRL (PEM and DER) */ + ExpectIntEQ(generate_crl_test(testEccKeyFile, testEccCertFile, + crlEccDerFile, crlEccPemFile, revokeEccCertFile), TEST_SUCCESS); +#endif +#endif + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_CRL_sign_large(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ + defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) +#ifndef NO_RSA + static const char* testRsaKeyFile = "./certs/ca-key.pem"; + static const char* testRsaCertFile = "./certs/ca-cert.pem"; + X509_NAME* issuer = NULL; + WOLFSSL_X509* cert = NULL; + WOLFSSL_X509_CRL* crl = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_ASN1_TIME asnTime = {0}; + WOLFSSL_X509_REVOKED revoked; + XFILE fp = XBADFILE; + int i; + byte serial[4]; + + ExpectTrue((fp = XFOPEN(testRsaCertFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(cert = PEM_read_X509(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectNotNull(crl = wolfSSL_X509_CRL_new()); + ExpectNotNull(issuer = X509_get_subject_name(cert)); + ExpectIntEQ(wolfSSL_X509_CRL_set_issuer_name(crl, issuer), WOLFSSL_SUCCESS); + + ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 0, 0)); + ExpectIntEQ(wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime), WOLFSSL_SUCCESS); + + ExpectNotNull(wolfSSL_ASN1_TIME_adj(&asnTime, XTIME(NULL), 30, 0)); + ExpectIntEQ(wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime), WOLFSSL_SUCCESS); + + revoked.serialNumber = wolfSSL_ASN1_INTEGER_new(); + revoked.serialNumber->data = serial; + revoked.serialNumber->length = (int)sizeof(serial); + + for (i = 0; i < 1024; i++) { + serial[0] = (byte)(i & 0xff); + serial[1] = (byte)((i >> 8) & 0xff); + serial[2] = (byte)((i >> 16) & 0xff); + serial[3] = (byte)((i >> 24) & 0xff); + ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked), + WOLFSSL_SUCCESS); + } + + ExpectTrue((fp = XFOPEN(testRsaKeyFile, "rb")) != XBADFILE); + if (fp != XBADFILE) { + ExpectNotNull(pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)); + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectIntEQ(wolfSSL_X509_CRL_sign(crl, pkey, wolfSSL_EVP_sha256()), + WOLFSSL_SUCCESS); + + revoked.serialNumber->data = NULL; + wolfSSL_ASN1_INTEGER_free(revoked.serialNumber); + revoked.serialNumber = NULL; + + wolfSSL_EVP_PKEY_free(pkey); + wolfSSL_X509_CRL_free(crl); + wolfSSL_X509_free(cert); +#endif /* !NO_RSA */ +#endif + return EXPECT_RESULT(); +} + static int test_X509_REQ(void) { EXPECT_DECLS; @@ -31298,6 +31681,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_X509_ALGOR_get0), TEST_DECL(test_wolfSSL_X509_SEP), + TEST_DECL(test_wolfSSL_X509_set_extensions), TEST_DECL(test_wolfSSL_X509_CRL), #ifndef NO_BIO TEST_DECL(test_wolfSSL_X509_print), @@ -31316,7 +31700,9 @@ TEST_CASE testCases[] = { /* OpenSSL sk_X509 API test */ TEST_DECL(test_sk_X509), /* OpenSSL sk_X509_CRL API test */ - TEST_DECL(test_sk_X509_CRL), + TEST_DECL(test_sk_X509_CRL_decode), + TEST_DECL(test_sk_X509_CRL_encode), + TEST_DECL(test_wolfSSL_X509_CRL_sign_large), /* OpenSSL X509 REQ API test */ TEST_DECL(test_wolfSSL_d2i_X509_REQ), diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c index a2ff33373b..02d47bfe91 100644 --- a/tests/api/test_certman.c +++ b/tests/api/test_certman.c @@ -946,9 +946,14 @@ int test_wolfSSL_CertManagerNameConstraint2(void) WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_X509_add_altname(x509, "", ASN_DIR_TYPE), WOLFSSL_SUCCESS); - /* IP not supported. */ + /* IP not supported unless WOLFSSL_IP_ALT_NAME is enabled. */ +#ifdef WOLFSSL_IP_ALT_NAME + ExpectIntEQ(wolfSSL_X509_add_altname(x509, "127.0.0.1", ASN_IP_TYPE), + WOLFSSL_SUCCESS); +#else ExpectIntEQ(wolfSSL_X509_add_altname(x509, "127.0.0.1", ASN_IP_TYPE), WOLFSSL_FAILURE); +#endif /* add in matching DIR alt name and resign */ wolfSSL_X509_add_altname_ex(x509, altName, sizeof(altName), ASN_DIR_TYPE); @@ -2367,4 +2372,3 @@ int test_various_pathlen_chains(void) #endif return EXPECT_RESULT(); } - diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 31466ca846..cdd9a80cf6 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -631,6 +631,7 @@ static word32 SizeASNLength(word32 length) #define ASNIntMSBSet(asn, data_a, i) \ (((asn)[i].tag == ASN_INTEGER) && \ ((data_a)[i].data.buffer.data != NULL && \ + ((data_a)[i].data.buffer.length > 0) && \ ((data_a)[i].data.buffer.data[0] & 0x80) == 0x80)) @@ -3131,11 +3132,10 @@ const char* GetSigName(int oid) { #if !defined(WOLFSSL_ASN_TEMPLATE) || defined(HAVE_PKCS7) || \ - defined(OPENSSL_EXTRA) + defined(OPENSSL_EXTRA) || defined(WOLFSSL_CERT_GEN) #if !defined(NO_DSA) || defined(HAVE_ECC) || !defined(NO_CERTS) || \ - (!defined(NO_RSA) && \ - (defined(WOLFSSL_CERT_GEN) || \ - ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA))))) + defined(WOLFSSL_CERT_GEN) || \ + (!defined(NO_RSA) && (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA))) /* Set the DER/BER encoding of the ASN.1 INTEGER header. * * When output is NULL, calculate the header length only. @@ -41397,6 +41397,423 @@ int ParseCRL(RevokedCert* rcert, DecodedCRL* dcrl, const byte* buff, word32 sz, #endif /* WOLFSSL_ASN_TEMPLATE */ } +#ifdef WOLFSSL_CERT_GEN +/* Encode a date as ASN.1 (UTC or GeneralizedTime). + * Returns length written to output (including tag and length bytes). + * If output is NULL, just returns the required size. + */ +static word32 EncodeCrlDate(byte* output, const byte* date, byte format) +{ + word32 idx = 0; + word32 dateLen; + + /* Determine date length based on format */ + if (format == ASN_UTC_TIME) { + dateLen = ASN_UTC_TIME_SIZE - 1; /* exclude null terminator */ + } + else if (format == ASN_GENERALIZED_TIME) { + dateLen = ASN_GENERALIZED_TIME_SIZE - 1; + } + else { + return 0; /* unsupported format */ + } + + if (output != NULL) { + output[idx] = format; + } + idx++; + + if (output != NULL) { + idx += SetLength(dateLen, output + idx); + XMEMCPY(output + idx, date, dateLen); + } + else { + idx += SetLength(dateLen, NULL); + } + idx += dateLen; + + return idx; +} + +/* Encode a serial number as ASN.1 INTEGER. + * Similar to SetSerialNumber but always available. + */ +static int EncodeCrlSerial(const byte* sn, word32 snSz, byte* output, + word32 outputSz) +{ + int i; + int snSzInt = (int)snSz; + const byte* snPtr = sn; + + if (sn == NULL || snSzInt < 0) + return BAD_FUNC_ARG; + + /* remove leading zeros */ + while (snSzInt > 0 && snPtr[0] == 0) { + snSzInt--; + snPtr++; + } + /* Serial numbers must be non-negative; allow zero for tolerance */ + if (snSzInt == 0) { + i = SetASNInt(1, 0x00, output); + if (1 > (int)outputSz - i) { + return BUFFER_E; + } + if (output != NULL) { + output[i] = 0x00; + } + return i + 1; + } + + i = SetASNInt(snSzInt, snPtr[0], NULL); + /* sanity check number of bytes to copy */ + if (snSzInt > (int)outputSz - i || snSzInt <= 0) { + return BUFFER_E; + } + + if (output != NULL) { + /* write out ASN.1 Integer */ + (void)SetASNInt(snSzInt, snPtr[0], output); + XMEMCPY(output + i, snPtr, (size_t)snSzInt); + } + + return i + snSzInt; +} + +/* Encode a single revoked certificate entry. + * Returns length written to output. + */ +static word32 EncodeRevokedCert(byte* output, const RevokedCert* rc) +{ + word32 idx = 0; + word32 snSz, dateSz, seqSz; + byte snBuf[MAX_SN_SZ]; + byte dateBuf[MAX_DATE_SIZE + 2]; /* tag + length + data */ + byte seqBuf[MAX_SEQ_SZ]; + + /* Encode serial number */ + snSz = (word32)EncodeCrlSerial(rc->serialNumber, (word32)rc->serialSz, + snBuf, sizeof(snBuf)); + if ((int)snSz < 0) + return 0; + + /* Encode revocation date */ + dateSz = EncodeCrlDate(dateBuf, rc->revDate, rc->revDateFormat); + if (dateSz == 0) + return 0; + + /* Wrap in SEQUENCE */ + seqSz = SetSequence(snSz + dateSz, seqBuf); + + if (output != NULL) { + XMEMCPY(output + idx, seqBuf, seqSz); + idx += seqSz; + XMEMCPY(output + idx, snBuf, snSz); + idx += snSz; + XMEMCPY(output + idx, dateBuf, dateSz); + idx += dateSz; + } + else { + idx = seqSz + snSz + dateSz; + } + + return idx; +} + +/* Encode the CRL Number extension. + * Returns length written to output. + */ +static word32 EncodeCrlNumberExt(byte* output, const byte* crlNum, + word32 crlNumSz) +{ + word32 idx = 0; + word32 oidSz, intSz, octetSz, seqSz; + byte seqBuf[MAX_SEQ_SZ]; + byte octetBuf[MAX_OCTET_STR_SZ]; + byte intBuf[MAX_SN_SZ]; + + /* CRL Number OID: 2.5.29.20 */ + static const byte crlNumOid[] = { 0x06, 0x03, 0x55, 0x1d, 0x14 }; + oidSz = sizeof(crlNumOid); + + /* Encode the INTEGER for CRL number */ + intSz = (word32)EncodeCrlSerial(crlNum, crlNumSz, intBuf, sizeof(intBuf)); + if ((int)intSz < 0) + return 0; + + /* Wrap INTEGER in OCTET STRING */ + octetSz = SetOctetString(intSz, octetBuf); + + /* Wrap in extension SEQUENCE */ + seqSz = SetSequence(oidSz + octetSz + intSz, seqBuf); + + if (output != NULL) { + XMEMCPY(output + idx, seqBuf, seqSz); + idx += seqSz; + XMEMCPY(output + idx, crlNumOid, oidSz); + idx += oidSz; + XMEMCPY(output + idx, octetBuf, octetSz); + idx += octetSz; + XMEMCPY(output + idx, intBuf, intSz); + idx += intSz; + } + else { + idx = seqSz + oidSz + octetSz + intSz; + } + + return idx; +} + +/* Build CRL TBSCertList from fields. + * issuerDer: DER-encoded issuer Name + * issuerSz: size of issuer DER + * lastDate/lastDateFmt: thisUpdate time and format + * nextDate/nextDateFmt: nextUpdate time and format + * certs: linked list of revoked certificates (may be NULL) + * crlNumber/crlNumberSz: CRL number extension data (may be NULL) + * sigType: signature algorithm type (e.g., CTC_SHA256wRSA) + * version: CRL version (1 or 2; 2 required for extensions) + * output: buffer to write TBS (NULL to calculate size) + * outputSz: size of output buffer + * + * Returns: size of TBS on success, negative error code on failure + */ +int wc_MakeCRL_ex(const byte* issuerDer, word32 issuerSz, + const byte* lastDate, byte lastDateFmt, + const byte* nextDate, byte nextDateFmt, + RevokedCert* certs, int totalCerts, + const byte* crlNumber, word32 crlNumberSz, + int sigType, int version, + byte* output, word32 outputSz) +{ + word32 idx = 0; + word32 tbsContentSz = 0; + word32 versionSz = 0, algoSz = 0, lastDateSz = 0, nextDateSz = 0; + word32 revokedSz = 0, extSz = 0, extSeqSz = 0, extCtxSz = 0; + word32 tbsSeqSz; + byte tbsSeqBuf[MAX_SEQ_SZ]; + byte versionBuf[MAX_VERSION_SZ]; + byte algoBuf[MAX_ALGO_SZ]; + byte lastDateBuf[MAX_DATE_SIZE + 2]; + byte nextDateBuf[MAX_DATE_SIZE + 2]; + byte revokedSeqBuf[MAX_SEQ_SZ]; + byte extSeqBuf[MAX_SEQ_SZ]; + byte extCtxBuf[MAX_SEQ_SZ + 1]; /* context tag + length */ + RevokedCert* rc; + int i; + + (void)totalCerts; + + if (issuerDer == NULL || issuerSz == 0 || lastDate == NULL) + return BAD_FUNC_ARG; + + /* Version: only include if v2 (version = 2 means value 1 in ASN.1) */ + if (version >= 2) { + versionSz = (word32)SetMyVersion(version - 1, versionBuf, FALSE); + } + + /* Signature AlgorithmIdentifier */ + algoSz = SetAlgoID(sigType, algoBuf, oidSigType, 0); + if (algoSz == 0) + return ALGO_ID_E; + + /* thisUpdate */ + lastDateSz = EncodeCrlDate(lastDateBuf, lastDate, lastDateFmt); + if (lastDateSz == 0) + return ASN_DATE_SZ_E; + + /* nextUpdate (optional) */ + if (nextDate != NULL && nextDateFmt != 0) { + nextDateSz = EncodeCrlDate(nextDateBuf, nextDate, nextDateFmt); + } + + /* revokedCertificates (optional) */ + if (certs != NULL) { + word32 contentSz = 0; + /* First pass: calculate size */ + for (rc = certs; rc != NULL; rc = rc->next) { + word32 entrySz = EncodeRevokedCert(NULL, rc); + if (entrySz == 0) + return ASN_PARSE_E; + contentSz += entrySz; + } + revokedSz = SetSequence(contentSz, revokedSeqBuf) + contentSz; + } + + /* crlExtensions (optional) - CRL Number */ + if (crlNumber != NULL && crlNumberSz > 0 && version >= 2) { + word32 crlNumExtSz = EncodeCrlNumberExt(NULL, crlNumber, crlNumberSz); + if (crlNumExtSz > 0) { + extSeqSz = SetSequence(crlNumExtSz, extSeqBuf); + /* Context tag [0] EXPLICIT */ + extCtxBuf[0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0); + extCtxSz = 1 + SetLength(extSeqSz + crlNumExtSz, extCtxBuf + 1); + extSz = extCtxSz + extSeqSz + crlNumExtSz; + } + } + + /* Calculate total TBS content size */ + tbsContentSz = versionSz + algoSz + issuerSz + lastDateSz + nextDateSz + + revokedSz + extSz; + + /* TBS SEQUENCE header */ + tbsSeqSz = SetSequence(tbsContentSz, tbsSeqBuf); + + /* Check buffer size */ + if (output != NULL && (tbsSeqSz + tbsContentSz > outputSz)) + return BUFFER_E; + + /* If output is NULL, just return required size */ + if (output == NULL) + return (int)(tbsSeqSz + tbsContentSz); + + /* Encode TBS */ + idx = 0; + + /* TBS SEQUENCE header */ + XMEMCPY(output + idx, tbsSeqBuf, tbsSeqSz); + idx += tbsSeqSz; + + /* Version (optional) */ + if (versionSz > 0) { + XMEMCPY(output + idx, versionBuf, versionSz); + idx += versionSz; + } + + /* Signature AlgorithmIdentifier */ + XMEMCPY(output + idx, algoBuf, algoSz); + idx += algoSz; + + /* Issuer Name */ + XMEMCPY(output + idx, issuerDer, issuerSz); + idx += issuerSz; + + /* thisUpdate */ + XMEMCPY(output + idx, lastDateBuf, lastDateSz); + idx += lastDateSz; + + /* nextUpdate (optional) */ + if (nextDateSz > 0) { + XMEMCPY(output + idx, nextDateBuf, nextDateSz); + idx += nextDateSz; + } + + /* revokedCertificates (optional) */ + if (revokedSz > 0) { + word32 contentSz = 0; + for (rc = certs; rc != NULL; rc = rc->next) { + contentSz += EncodeRevokedCert(NULL, rc); + } + idx += SetSequence(contentSz, output + idx); + for (rc = certs, i = 0; rc != NULL; rc = rc->next, i++) { + idx += EncodeRevokedCert(output + idx, rc); + } + } + + /* crlExtensions (optional) */ + if (extSz > 0) { + word32 crlNumExtSz = EncodeCrlNumberExt(NULL, crlNumber, crlNumberSz); + /* Context tag [0] */ + output[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0); + idx += SetLength(extSeqSz + crlNumExtSz, output + idx); + /* Extensions SEQUENCE */ + idx += SetSequence(crlNumExtSz, output + idx); + /* CRL Number extension */ + idx += EncodeCrlNumberExt(output + idx, crlNumber, crlNumberSz); + } + + return (int)idx; +} + +/* Sign a CRL TBS and produce complete CRL DER. + * tbsBuf: contains the TBS at the beginning + * tbsSz: size of TBS in tbsBuf + * sType: signature type (e.g., CTC_SHA256wRSA) + * buf: output buffer for complete CRL + * bufSz: size of output buffer + * rsaKey/eccKey: signing key (one must be non-NULL) + * rng: random number generator + * + * Returns: size of complete CRL on success, negative error on failure + */ +int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, + byte* buf, word32 bufSz, + RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) +{ + int ret; + int sigSz; + CertSignCtx certSignCtx_lcl; + CertSignCtx* certSignCtx = &certSignCtx_lcl; + void* heap = NULL; + + if (tbsBuf == NULL || tbsSz <= 0 || buf == NULL || rng == NULL) + return BAD_FUNC_ARG; + if (rsaKey == NULL && eccKey == NULL) + return BAD_FUNC_ARG; + + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); + + if (rsaKey != NULL) { + heap = rsaKey->heap; + } +#ifdef HAVE_ECC + else if (eccKey != NULL) { + heap = eccKey->heap; + } +#endif + + /* Copy TBS to output buffer first */ + if ((word32)tbsSz > bufSz) + return BUFFER_E; + XMEMCPY(buf, tbsBuf, (size_t)tbsSz); + +#ifndef WOLFSSL_NO_MALLOC + certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certSignCtx->sig == NULL) + return MEMORY_E; + /* Initialize first byte to avoid static analysis warnings about using + * uninitialized memory if MakeSignature fails before writing sig. */ + certSignCtx->sig[0] = 0; +#endif + + /* Create signature */ + sigSz = MakeSignature(certSignCtx, buf, (word32)tbsSz, certSignCtx->sig, + MAX_ENCODED_SIG_SZ, rsaKey, eccKey, NULL, NULL, NULL, + NULL, NULL, rng, (word32)sType, heap); + if (sigSz < 0) { +#ifndef WOLFSSL_NO_MALLOC + XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return sigSz; + } + + /* Ensure output buffer is large enough for signature wrapper */ + ret = AddSignature(NULL, tbsSz, certSignCtx->sig, sigSz, sType); + if (ret < 0) { +#ifndef WOLFSSL_NO_MALLOC + XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + if ((word32)ret > bufSz) { +#ifndef WOLFSSL_NO_MALLOC + XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return BUFFER_E; + } + + /* Add signature algorithm and signature to buffer */ + ret = AddSignature(buf, tbsSz, certSignCtx->sig, sigSz, sType); + +#ifndef WOLFSSL_NO_MALLOC + XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} +#endif /* WOLFSSL_CERT_GEN */ + #endif /* HAVE_CRL */ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 1912b2eb47..d74a2c9a57 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -28,7 +28,8 @@ #elif defined(WOLFCRYPT_ONLY) #else -#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(HAVE_CURL) #if !defined(HAVE_PKCS7) && \ ((defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ diff --git a/wolfssl/crl.h b/wolfssl/crl.h index 059edeef84..774f9361c2 100644 --- a/wolfssl/crl.h +++ b/wolfssl/crl.h @@ -39,8 +39,11 @@ WOLFSSL_LOCAL void FreeCRL(WOLFSSL_CRL* crl, int dynamic); WOLFSSL_LOCAL int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor); +WOLFSSL_LOCAL int StoreCRL(WOLFSSL_CRL* crl, const char* file, int type); WOLFSSL_LOCAL int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, int verify); +WOLFSSL_LOCAL int BufferStoreCRL(WOLFSSL_CRL* crl, byte* buff, long* inOutSz, + int type); WOLFSSL_LOCAL int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert); WOLFSSL_LOCAL int CheckCertCRL_ex(WOLFSSL_CRL* crl, byte* issuerHash, byte* serial, int serialSz, byte* serialHash, const byte* extCrlInfo, diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 00fd901e83..f7f6d51d70 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2503,6 +2503,8 @@ struct CRL_Entry { byte* signature; #if defined(OPENSSL_EXTRA) WOLFSSL_X509_NAME* issuer; /* X509_NAME type issuer */ + WOLFSSL_ASN1_BIT_STRING* sigBits; /* cached signature bit string */ + WOLFSSL_X509_ALGOR* sigAlgor; /* cached signature algorithm */ #endif CRL_Entry* next; /* next entry */ wolfSSL_Mutex verifyMutex; @@ -5453,7 +5455,9 @@ struct WOLFSSL_X509 { #endif /* WOLFSSL_CERT_REQ || WOLFSSL_CERT_GEN */ WOLFSSL_X509_NAME issuer; WOLFSSL_X509_NAME subject; -#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_APACHE_HTTPD) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) WOLFSSL_X509_ALGOR algor; WOLFSSL_X509_PUBKEY key; #endif diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 5b8175564e..11bdc03a71 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -576,6 +576,17 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define X509_set1_notBefore wolfSSL_X509_set1_notBefore #define X509_set_serialNumber wolfSSL_X509_set_serialNumber #define X509_set_version wolfSSL_X509_set_version +#ifdef WOLFSSL_CERT_EXT +#define X509_set_subject_key_id wolfSSL_X509_set_subject_key_id +#define X509_set_subject_key_id_ex wolfSSL_X509_set_subject_key_id_ex +#define X509_set_authority_key_id wolfSSL_X509_set_authority_key_id +#define X509_set_authority_key_id_ex wolfSSL_X509_set_authority_key_id_ex +#define X509_CRL_set_dist_points wolfSSL_X509_CRL_set_dist_points +#define X509_CRL_add_dist_point wolfSSL_X509_CRL_add_dist_point +#endif +#ifndef IGNORE_NETSCAPE_CERT_TYPE +#define X509_set_ns_cert_type wolfSSL_X509_set_ns_cert_type +#endif #define X509_REQ_set_version wolfSSL_X509_REQ_set_version #define X509_REQ_get_version wolfSSL_X509_REQ_get_version #define X509_sign wolfSSL_X509_sign @@ -804,10 +815,13 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define d2i_X509_CRL wolfSSL_d2i_X509_CRL #define d2i_X509_CRL_fp wolfSSL_d2i_X509_CRL_fp +#define i2d_X509_CRL wolfSSL_i2d_X509_CRL #define PEM_read_X509_CRL wolfSSL_PEM_read_X509_CRL +#define X509_CRL_new wolfSSL_X509_CRL_new #define X509_CRL_dup wolfSSL_X509_CRL_dup #define X509_CRL_free wolfSSL_X509_CRL_free +#define X509_CRL_sign wolfSSL_X509_CRL_sign #define X509_CRL_get_lastUpdate wolfSSL_X509_CRL_get_lastUpdate #define X509_CRL_get0_lastUpdate wolfSSL_X509_CRL_get_lastUpdate #define X509_CRL_get_nextUpdate wolfSSL_X509_CRL_get_nextUpdate @@ -817,6 +831,14 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define X509_CRL_get_issuer wolfSSL_X509_CRL_get_issuer_name #define X509_CRL_get_signature_nid wolfSSL_X509_CRL_get_signature_nid #define X509_CRL_get_version wolfSSL_X509_CRL_version +#define X509_CRL_set_lastUpdate wolfSSL_X509_CRL_set_lastUpdate +#define X509_CRL_set1_lastUpdate wolfSSL_X509_CRL_set_lastUpdate +#define X509_CRL_set_nextUpdate wolfSSL_X509_CRL_set_nextUpdate +#define X509_CRL_set1_nextUpdate wolfSSL_X509_CRL_set_nextUpdate +#define X509_CRL_set_issuer_name wolfSSL_X509_CRL_set_issuer_name +#define X509_CRL_set_version wolfSSL_X509_CRL_set_version +#define X509_CRL_get0_signature wolfSSL_X509_CRL_get_signature +#define X509_CRL_get_signature_nid wolfSSL_X509_CRL_get_signature_nid #define X509_load_crl_file wolfSSL_X509_load_crl_file #define X509_ACERT_new wolfSSL_X509_ACERT_new diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 7b5b76d062..b75b3625ee 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -874,6 +874,9 @@ struct WOLFSSL_X509_VERIFY_PARAM { typedef struct WOLFSSL_X509_REVOKED { WOLFSSL_ASN1_INTEGER* serialNumber; /* stunnel dereference */ + /* TODO: add other fields to match OpenSSL's X509_REVOKED + * (struct x509_revoked_st) such as revocationDate, extensions, etc. + * Then update wolfSSL_X509_CRL_add_revoked to handle those fields. */ } WOLFSSL_X509_REVOKED; typedef enum { @@ -2278,6 +2281,22 @@ WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_get_notAfter(const WOLFSSL_X509* x50 WOLFSSL_API int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s); WOLFSSL_API int wolfSSL_X509_set_version(WOLFSSL_X509* x509, long v); +#ifdef WOLFSSL_CERT_EXT +WOLFSSL_API int wolfSSL_X509_set_subject_key_id(WOLFSSL_X509* x509, + const unsigned char* skid, int skidSz); +#ifndef NO_SHA +WOLFSSL_API int wolfSSL_X509_set_subject_key_id_ex(WOLFSSL_X509* x509); +#endif +WOLFSSL_API int wolfSSL_X509_set_authority_key_id(WOLFSSL_X509* x509, + const unsigned char* akid, int akidSz); +#ifndef NO_SHA +WOLFSSL_API int wolfSSL_X509_set_authority_key_id_ex(WOLFSSL_X509* x509, + WOLFSSL_X509* issuer); +#endif +#endif /* WOLFSSL_CERT_EXT */ +#ifndef IGNORE_NETSCAPE_CERT_TYPE +WOLFSSL_API int wolfSSL_X509_set_ns_cert_type(WOLFSSL_X509* x509, int nsCertType); +#endif WOLFSSL_API int wolfSSL_X509_sign(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_MD* md); WOLFSSL_API int wolfSSL_X509_sign_ctx(WOLFSSL_X509 *x509, WOLFSSL_EVP_MD_CTX *ctx); @@ -2347,8 +2366,9 @@ WOLFSSL_API void wolfSSL_X509_STORE_CTX_trusted_stack(WOLFSSL_X509_STORE_CTX *ct WOLF_STACK_OF(WOLFSSL_X509) *sk); WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl); +WOLFSSL_API int wolfSSL_X509_CRL_set_lastUpdate(WOLFSSL_X509_CRL* crl, const WOLFSSL_ASN1_TIME* time); WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl); - +WOLFSSL_API int wolfSSL_X509_CRL_set_nextUpdate(WOLFSSL_X509_CRL* crl, const WOLFSSL_ASN1_TIME* time); WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* pkey); WOLFSSL_API void wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT* obj); @@ -3443,15 +3463,22 @@ WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL_fp(XFILE file, WOLFSSL_X509_C WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL_bio(WOLFSSL_BIO *bp, WOLFSSL_X509_CRL **crl); WOLFSSL_API int wolfSSL_X509_CRL_version(WOLFSSL_X509_CRL *crl); +WOLFSSL_API int wolfSSL_X509_CRL_set_version(WOLFSSL_X509_CRL* crl, long version); WOLFSSL_API int wolfSSL_X509_CRL_get_signature_type(WOLFSSL_X509_CRL* crl); +WOLFSSL_API int wolfSSL_X509_CRL_set_signature_type(WOLFSSL_X509_CRL* crl, int signatureType); WOLFSSL_API int wolfSSL_X509_CRL_get_signature_nid( const WOLFSSL_X509_CRL* crl); -WOLFSSL_API int wolfSSL_X509_CRL_get_signature(WOLFSSL_X509_CRL* crl, - unsigned char* buf, int* bufSz); +WOLFSSL_API int wolfSSL_X509_CRL_set_signature_nid(WOLFSSL_X509_CRL* crl, int nid); +WOLFSSL_API void wolfSSL_X509_CRL_get_signature(const WOLFSSL_X509_CRL* crl, + const WOLFSSL_ASN1_BIT_STRING **psig, + const WOLFSSL_X509_ALGOR **palg); +WOLFSSL_API int wolfSSL_X509_CRL_set_signature(WOLFSSL_X509_CRL* crl, + unsigned char* buf, int bufSz); WOLFSSL_API int wolfSSL_X509_CRL_print(WOLFSSL_BIO* bio, WOLFSSL_X509_CRL* crl); WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_CRL_get_issuer_name( - WOLFSSL_X509_CRL *crl); + const WOLFSSL_X509_CRL *crl); +WOLFSSL_API int wolfSSL_X509_CRL_set_issuer_name(WOLFSSL_X509_CRL* crl, const WOLFSSL_X509_NAME* name); WOLFSSL_API int wolfSSL_X509_REVOKED_get_serial_number(RevokedCert* rev, byte* in, int* inOutSz); #endif @@ -3459,6 +3486,26 @@ WOLFSSL_API int wolfSSL_X509_REVOKED_get_serial_number(RevokedCert* rev, WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_X509_CRL_dup(const WOLFSSL_X509_CRL* crl); WOLFSSL_API void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl); #endif +#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) +WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_X509_CRL_new(void); +#ifdef WOLFSSL_CERT_GEN +WOLFSSL_API int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl, + WOLFSSL_X509_REVOKED* revoked); +WOLFSSL_API int wolfSSL_X509_CRL_add_revoked_cert(WOLFSSL_X509_CRL* crl, + const unsigned char* certBuf, int certSz); +WOLFSSL_API int wolfSSL_X509_CRL_sign(WOLFSSL_X509_CRL* crl, + WOLFSSL_EVP_PKEY* pkey, + const WOLFSSL_EVP_MD* md); +#endif /* WOLFSSL_CERT_GEN */ +WOLFSSL_API int wolfSSL_i2d_X509_CRL(WOLFSSL_X509_CRL* crl, unsigned char** out); +#endif /* HAVE_CRL && OPENSSL_EXTRA */ +#if defined(WOLFSSL_CERT_EXT) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) +WOLFSSL_API int wolfSSL_X509_CRL_set_dist_points(WOLFSSL_X509* x509, + const unsigned char* der, int derSz); +WOLFSSL_API int wolfSSL_X509_CRL_add_dist_point(WOLFSSL_X509* x509, + const char* uri, int critical); +#endif /* WOLFSSL_CERT_EXT && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ #if defined(WOLFSSL_ACERT) && \ (defined(OPENSSL_EXTRA_X509_SMALL) || defined(OPENSSL_EXTRA)) @@ -5023,8 +5070,8 @@ WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_new(void); #ifndef wolfSSL_X509_NAME_new_ex WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_new_ex(void *heap); #endif -WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(WOLFSSL_X509_NAME* name); -WOLFSSL_API int wolfSSL_X509_NAME_copy(WOLFSSL_X509_NAME* from, WOLFSSL_X509_NAME* to); +WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(const WOLFSSL_X509_NAME* name); +WOLFSSL_API int wolfSSL_X509_NAME_copy(const WOLFSSL_X509_NAME* from, WOLFSSL_X509_NAME* to); WOLFSSL_API int wolfSSL_check_private_key(const WOLFSSL* ssl); #endif /* !NO_CERTS */ #endif /* OPENSSL_ALL || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ @@ -5199,6 +5246,7 @@ WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509_INFO)* wolfSSL_PEM_X509_INFO_read_bio( #ifndef NO_FILESYSTEM WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_PEM_read_X509_CRL(XFILE fp, WOLFSSL_X509_CRL **x, wc_pem_password_cb *cb, void *u); +WOLFSSL_API int wolfSSL_write_X509_CRL(WOLFSSL_X509_CRL* crl, const char* path, int type); #endif WOLFSSL_API int wolfSSL_PEM_get_EVP_CIPHER_INFO(const char* header, EncryptedInfo* cipher); @@ -5224,7 +5272,7 @@ struct WOLFSSL_CONF_CTX { WOLFSSL* ssl; }; -WOLFSSL_API WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(WOLFSSL_X509_NAME *name, int loc); +WOLFSSL_API WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(const WOLFSSL_X509_NAME *name, int loc); WOLFSSL_API int wolfSSL_X509_NAME_ENTRY_set(const WOLFSSL_X509_NAME_ENTRY *ne); #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 685f806996..3c6ab6da9c 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -593,6 +593,21 @@ WOLFSSL_API int wc_SetCustomExtension(Cert *cert, int critical, const char *oid, #endif /* WOLFSSL_CERT_EXT */ +#if defined(WOLFSSL_CERT_GEN) && defined(HAVE_CRL) +/* CRL Generation functions */ +struct RevokedCert; /* forward declaration */ +WOLFSSL_API int wc_MakeCRL_ex(const byte* issuerDer, word32 issuerSz, + const byte* lastDate, byte lastDateFmt, + const byte* nextDate, byte nextDateFmt, + struct RevokedCert* certs, int totalCerts, + const byte* crlNumber, word32 crlNumberSz, + int sigType, int version, + byte* output, word32 outputSz); +WOLFSSL_API int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, + byte* buf, word32 bufSz, + RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng); +#endif /* WOLFSSL_CERT_GEN && HAVE_CRL */ + WOLFSSL_API int wc_GetDateInfo(const byte* certDate, int certDateSz, const byte** date, byte* format, int* length); #ifndef NO_ASN_TIME diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index abfdbe5534..6a6e5dd38d 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -1012,6 +1012,10 @@ WOLFSSL_API void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags); #define XINET_PTON(a,b,c,d) inet_pton((a),(b),(c),(d)) #elif defined(WOLFSSL_ZEPHYR) #define XINET_PTON(a,b,c) zsock_inet_pton((a),(b),(c)) + #elif defined(WOLFSSL_LINUXKM) + #define XINET_PTON(a,b,c) \ + (((a) == WOLFSSL_IP4) ? in4_pton((b), -1, (u8*)(c), -1, NULL) : \ + ((a) == WOLFSSL_IP6) ? in6_pton((b), -1, (u8*)(c), -1, NULL) : 0) #else #define XINET_PTON(a,b,c) inet_pton((a),(b),(c)) #endif