diff --git a/certs/ca-cert.der b/certs/ca-cert.der
index 3c6964e2f..770131bd4 100644
Binary files a/certs/ca-cert.der and b/certs/ca-cert.der differ
diff --git a/certs/ca-cert.pem b/certs/ca-cert.pem
index bb4abe7bc..accf094cb 100644
--- a/certs/ca-cert.pem
+++ b/certs/ca-cert.pem
@@ -2,13 +2,13 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- 6b:9b:70:c6:f1:a3:94:65:19:a1:08:58:ef:a7:8d:2b:7a:83:c1:da
+ 67:19:d2:a8:7f:e3:2d:fa:75:7a:4f:e7:b2:02:d9:ad:c4:77:5e:f8
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:29 2024 GMT
- Not After : Sep 14 21:25:29 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:28 2026 GMT
+ Not After : Mar 7 21:44:28 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
@@ -37,8 +37,8 @@ Certificate:
27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -47,47 +47,47 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 77:3b:3d:66:74:bc:97:fe:40:16:e6:ba:a5:d5:d1:84:08:89:
- 69:4f:88:0d:57:a9:ef:8c:c3:97:52:c8:bd:8b:a2:49:3b:b7:
- f7:5d:1e:d6:14:7f:b2:80:33:da:a0:8a:d3:e1:2f:d5:bc:33:
- 9f:ea:5a:72:24:e5:f8:b8:4b:b3:df:62:90:3b:a8:21:ef:27:
- 42:75:bc:60:02:8e:37:35:99:eb:a3:28:f2:65:4c:ff:7a:f8:
- 8e:cc:23:6d:e5:6a:fe:22:5a:d9:b2:4f:47:c7:e0:ae:98:ef:
- 94:ac:b6:4f:61:81:29:8e:e1:79:2c:46:fc:e9:1a:c3:96:1f:
- 19:93:64:2e:9f:37:72:c5:e4:93:4e:61:5f:38:8e:ae:e8:39:
- 19:e6:97:a8:91:d4:23:7e:1e:d2:d0:53:ec:cc:ac:a0:1d:d0:
- b7:dd:b1:b7:01:2e:96:cd:85:27:e0:e7:47:e2:c1:c1:00:f6:
- 94:df:77:e7:fa:c6:ef:8a:c0:7c:67:bc:ff:a0:7c:94:3b:7d:
- 86:42:af:3d:83:31:ee:2a:3b:7b:f0:2c:9e:6f:e9:c4:07:81:
- 24:da:05:70:4d:dd:09:ae:9e:72:b8:21:0e:8c:b2:ab:aa:4c:
- 49:10:f7:76:f9:b5:0d:6c:20:d3:df:7a:06:32:8d:29:1f:28:
- 1d:8d:26:33
+ 5d:a4:7f:06:52:54:b2:56:a9:f8:8d:fb:c9:13:ab:9c:16:4e:
+ 72:a8:57:b2:8d:e7:b4:a9:3f:32:5c:21:08:ff:42:9f:41:47:
+ 12:27:b5:45:9e:61:6e:b6:94:fe:f6:01:46:96:3e:f7:3d:79:
+ 07:ac:a9:26:f5:77:f7:52:c3:ed:bd:5a:a0:17:4c:0e:9e:51:
+ 57:ac:e3:a1:ef:7d:a3:fa:7c:c6:a5:57:84:dd:d0:aa:77:ab:
+ 30:12:70:83:f9:41:ae:74:78:f0:54:73:ed:86:7f:66:a1:aa:
+ 01:cd:41:5f:95:c7:6e:ce:3b:ab:2e:70:ff:3a:34:11:43:df:
+ 4b:63:d5:3b:a5:9e:21:cb:9c:c8:a7:5c:a0:43:ec:73:98:c5:
+ 25:d9:d4:ad:cc:11:66:83:51:8a:bd:33:65:a0:a3:a8:93:1e:
+ 7b:b9:f7:6a:95:6a:a7:dd:ff:6f:3b:bb:24:5c:56:14:8d:b9:
+ 84:d3:97:bf:57:71:0c:1e:b1:68:93:31:d6:34:38:77:94:da:
+ e2:b0:fe:82:18:b2:bb:bf:83:cf:bb:fe:08:fa:2a:17:10:3e:
+ 06:b1:1c:b1:f9:12:97:87:cc:a8:4e:5e:0d:0c:26:3c:c2:e8:
+ be:2d:48:91:77:7f:1a:1d:ac:bf:c9:55:10:bf:2f:5f:60:53:
+ e7:b7:6a:72
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
diff --git a/certs/ech-public-cert.der b/certs/ech-public-cert.der
new file mode 100644
index 000000000..9d360437d
Binary files /dev/null and b/certs/ech-public-cert.der differ
diff --git a/certs/ech-public-cert.pem b/certs/ech-public-cert.pem
new file mode 100644
index 000000000..0821c35b5
--- /dev/null
+++ b/certs/ech-public-cert.pem
@@ -0,0 +1,91 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 35 (0x23)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
+ Validity
+ Not Before: Jul 10 20:54:16 2026 GMT
+ Not After : Apr 5 20:54:16 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL, OU=ECH, CN=public.com, emailAddress=info@wolfssl.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d1:42:85:b2:a7:81:6f:e7:1b:26:c6:f2:53:d1:
+ 42:ff:18:f1:0b:3f:75:a0:01:fa:5c:8f:b2:c7:b4:
+ 06:f5:a5:6e:e2:ae:cc:a5:5d:35:b4:56:28:21:d3:
+ 59:b1:6e:81:3f:69:7d:85:e9:33:0a:cd:7a:32:8a:
+ fc:41:5a:52:1e:23:9e:2a:22:d4:c9:20:7e:46:db:
+ 6c:4d:56:e8:18:aa:79:b7:e7:20:b9:f3:97:28:1d:
+ 63:44:03:b4:05:7b:03:93:4c:3f:83:8e:21:c4:4e:
+ f2:ee:28:8c:01:39:de:aa:64:57:34:9a:58:35:89:
+ c1:eb:4e:fc:8e:23:fd:10:ad:1e:ca:97:4e:a9:8f:
+ 5d:d7:f9:52:fd:3a:45:90:cd:21:97:bc:b4:e2:8e:
+ c2:60:16:43:51:b3:71:e6:54:ec:60:00:76:b7:f6:
+ 06:b1:0c:c9:93:d7:6c:c6:9e:ab:0d:4d:58:f9:d5:
+ c7:fc:d1:d9:53:66:b7:47:4b:4a:12:6b:37:23:b4:
+ df:f6:21:d4:23:6b:92:2d:f7:ca:e5:90:53:c7:84:
+ 29:c0:a0:ac:d5:31:73:72:05:27:55:f6:4d:1a:c9:
+ e5:da:d9:8e:54:37:77:9c:3b:7f:2a:b9:72:6f:ed:
+ 2e:a9:36:66:cf:f2:4f:29:6e:a0:92:10:05:6a:37:
+ 2c:79
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 6B:D8:10:65:C9:94:68:23:2A:1E:67:67:CE:90:1E:92:8D:90:52:29
+ 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=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:public.com
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 63:8a:f1:b3:a2:e4:e6:28:6a:63:c5:39:56:71:65:95:3d:08:
+ 86:f6:ee:aa:a2:61:9d:f3:77:31:f2:e1:61:a8:d7:47:7e:dc:
+ 2c:70:44:cd:b3:0a:ed:ae:5b:5b:bf:d6:4c:70:47:98:66:40:
+ 8f:f4:0e:4b:f4:7e:fa:45:87:9e:fb:70:fc:e4:7a:3b:ff:da:
+ 5f:57:8b:32:75:4f:ec:6b:ad:95:58:44:18:31:b7:45:77:76:
+ d4:e6:96:66:b1:63:42:df:86:c1:f4:0b:53:f8:51:8a:71:b0:
+ 99:ea:7a:16:27:0e:22:5a:ac:e9:c5:46:0b:06:16:e9:ba:85:
+ ae:2f:ae:56:f9:cc:de:69:8c:e1:0c:e6:38:93:f2:21:88:a9:
+ 0d:25:9b:5a:cc:45:f6:6a:e8:d5:d8:f6:69:2e:fa:b0:cc:09:
+ 76:3b:9a:fc:ab:4e:9a:a9:2a:28:a0:d5:3a:3c:f7:e2:cf:de:
+ 0c:18:40:34:65:cd:93:47:db:30:8f:6b:16:42:39:7e:ec:47:
+ bd:9a:3e:19:09:96:6a:88:b9:99:92:5d:de:af:f5:fb:69:b8:
+ 43:f0:27:2e:d5:5a:d9:c9:30:c4:f8:43:01:ea:41:04:eb:fd:
+ 5f:2c:0e:7c:28:11:41:4e:c9:d3:67:3c:48:89:02:2b:4c:e6:
+ 54:b7:00:0c
+-----BEGIN CERTIFICATE-----
+MIIEzTCCA7WgAwIBAgIBIzANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
+d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDcx
+MDIwNTQxNloXDTI5MDQwNTIwNTQxNlowgYcxCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRAwDgYDVQQKDAd3b2xmU1NMMQww
+CgYDVQQLDANFQ0gxEzARBgNVBAMMCnB1YmxpYy5jb20xHzAdBgkqhkiG9w0BCQEW
+EGluZm9Ad29sZnNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDRQoWyp4Fv5xsmxvJT0UL/GPELP3WgAfpcj7LHtAb1pW7irsylXTW0Vigh01mx
+boE/aX2F6TMKzXoyivxBWlIeI54qItTJIH5G22xNVugYqnm35yC585coHWNEA7QF
+ewOTTD+DjiHETvLuKIwBOd6qZFc0mlg1icHrTvyOI/0QrR7Kl06pj13X+VL9OkWQ
+zSGXvLTijsJgFkNRs3HmVOxgAHa39gaxDMmT12zGnqsNTVj51cf80dlTZrdHS0oS
+azcjtN/2IdQja5It98rlkFPHhCnAoKzVMXNyBSdV9k0ayeXa2Y5UN3ecO38quXJv
+7S6pNmbP8k8pbqCSEAVqNyx5AgMBAAGjggEyMIIBLjAdBgNVHQ4EFgQUa9gQZcmU
+aCMqHmdnzpAeko2QUikwgdUGA1UdIwSBzTCByoAUJ45nEXTDJh0/7TNjs6TYHTDl
+6NWhgZukgZgwgZUxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYD
+VQQHDAdCb3plbWFuMREwDwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3Vs
+dGluZzEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMSAwHgYJKoZIhvcNAQkBFhFm
+YWN0c0B3b2xmc3NsLmNvbYIUZxnSqH/jLfp1ek/nsgLZrcR3XvgwCQYDVR0TBAIw
+ADAVBgNVHREEDjAMggpwdWJsaWMuY29tMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0G
+CSqGSIb3DQEBCwUAA4IBAQBjivGzouTmKGpjxTlWcWWVPQiG9u6qomGd83cx8uFh
+qNdHftwscETNswrtrltbv9ZMcEeYZkCP9A5L9H76RYee+3D85Ho7/9pfV4sydU/s
+a62VWEQYMbdFd3bU5pZmsWNC34bB9AtT+FGKcbCZ6noWJw4iWqzpxUYLBhbpuoWu
+L65W+czeaYzhDOY4k/IhiKkNJZtazEX2aujV2PZpLvqwzAl2O5r8q06aqSoooNU6
+PPfiz94MGEA0Zc2TR9swj2sWQjl+7Ee9mj4ZCZZqiLmZkl3er/X7abhD8Ccu1VrZ
+yTDE+EMB6kEE6/1fLA58KBFBTsnTZzxIiQIrTOZUtwAM
+-----END CERTIFICATE-----
diff --git a/certs/ech-public-key.der b/certs/ech-public-key.der
new file mode 100644
index 000000000..c1aedd2f0
Binary files /dev/null and b/certs/ech-public-key.der differ
diff --git a/certs/ech-public-key.pem b/certs/ech-public-key.pem
new file mode 100644
index 000000000..26c797915
--- /dev/null
+++ b/certs/ech-public-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRQoWyp4Fv5xsm
+xvJT0UL/GPELP3WgAfpcj7LHtAb1pW7irsylXTW0Vigh01mxboE/aX2F6TMKzXoy
+ivxBWlIeI54qItTJIH5G22xNVugYqnm35yC585coHWNEA7QFewOTTD+DjiHETvLu
+KIwBOd6qZFc0mlg1icHrTvyOI/0QrR7Kl06pj13X+VL9OkWQzSGXvLTijsJgFkNR
+s3HmVOxgAHa39gaxDMmT12zGnqsNTVj51cf80dlTZrdHS0oSazcjtN/2IdQja5It
+98rlkFPHhCnAoKzVMXNyBSdV9k0ayeXa2Y5UN3ecO38quXJv7S6pNmbP8k8pbqCS
+EAVqNyx5AgMBAAECggEAZaAUVRCTRFisr3bTzc/lZQTkXy2I/tWnFFe3H9Q2wwp+
+IPl6Kl7ri3KCF/dP6mL7wuOE0clQgBENJMmpu0VVdwyeLeFvjGPK37eFT8QCgKQd
+66mEE7qQcKtg/3F69mRo9pqDh+y5SmB7Cx1G7PuBPyfuz/2bFBkcQ54++frRVkyT
+hZ8Zl74MUyNCWVunT9M43o5JbbcapLegxG9kWcQChUHVU5U7ZjiSG2eKOWbY7qY0
+8/lwNnr6X1x/SViS07p0tNy02cXBsVWItZb50LtpSdtMSfJkE8Ed6Z5wQWggDle9
+ll6dOUSUvK0zrzq1nk7X/iJ71837/A9ZTFzpEKOyHwKBgQD7J2QjP+u44v/Gn4PK
+5f6p3WMvIfqs2dzuXwLR1eq+uUs01H5fOeCe0+l8TuxIlkR9rOncR7iayRFtxing
+ccE0RD3UHivr7RCdTryA60CJ8CgVkN7U9x1wc7SJIWE3Oh1Plk8tfI+n16AI2ErF
+lVzGb9jEOzkvSOZWLAx7UDDpmwKBgQDVTDCbJfL/5c3pxtPR6egJNLdQ8pVwxgzC
+eloaxLAKZy7Jr2wgz+EC3/489+pY/nOTOfv+btmz9F+ytGuNBiQPybl6il2M0J33
+JKwlZygXHJSDj5vEChkQyz6rlS8evuXQ6C5ZdaUNfJRZVZQAa4vCeYo2KH47lQK3
+OCtFLHc9ewKBgGG9zcHOIY2dgg8pix/ObFJtHyl7ntPgIZP/E9jX2HiLIhKYU+n5
+W0pUjDxddqU1HciPH6AjpVtPvuGqyidX/em6WRmQ+GTjqKCfwMqnQ0GrXd4uuBnH
+ZgSacvsfK3dTvY54n63DGSEn0FdA3bCRVT7Azmpn5fRZ+ZI1qFHhPnfbAoGAJOXG
+LsCU1bGiOkOb1t84tYb6AzXDpjuMb4QM3D6UGWiaDmebM93iFcY7y74zOuvhgGFy
+dyQj4t5uQ5K0XDPovxZtUIZpAngAK4WbhejfZYgbJNsN3g7FIUOXdsUa3p21Ubso
+cW9JexjG7OFB9gSkq6KsxwugMpxnWNyNl6zGf8sCgYBS7BjgAf6yKbzSs6eZaD3N
+dq9Y5GLB/bg6EktrXYmdGZJAb44we3Yf3ssVh1u4SmUC0nUmHbwmuZw7NU+c+oKH
+IjBPCQNEdftHrJ5T3aHAQGTvaxgzt6dMaS50S+iwsNqVr1pfjUiZJ+QiB8peqlHU
+3klKawNgdytJZS1s6jl1/g==
+-----END PRIVATE KEY-----
diff --git a/certs/server-cert.der b/certs/server-cert.der
index 91c6fa74d..d7634dc68 100644
Binary files a/certs/server-cert.der and b/certs/server-cert.der differ
diff --git a/certs/server-cert.pem b/certs/server-cert.pem
index 6fc3db772..636030b32 100644
--- a/certs/server-cert.pem
+++ b/certs/server-cert.pem
@@ -3,11 +3,11 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:30 2024 GMT
- Not After : Sep 14 21:25:30 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = wolfSSL, OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:29 2026 GMT
+ Not After : Mar 7 21:44:29 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL, OU=Support, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
@@ -36,8 +36,8 @@ Certificate:
B3:11:32:C9:92:98:84:E2:C9:F8:D0:3B:6E:03:42:CA:1F:0E:8E:3C
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -46,61 +46,61 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 8a:f1:4e:e8:9f:59:b2:d9:13:ac:fc:42:c4:81:34:9f:6b:39:
- 57:9c:e9:92:5d:41:ac:05:35:b1:26:93:4d:4a:da:f8:51:82:
- d2:8d:7f:d3:5c:6e:29:80:8d:9b:02:10:2b:64:f5:d1:31:06:
- fa:85:2b:8f:63:32:14:76:7a:39:15:f3:4e:dd:fd:e2:2c:90:
- 15:d1:6f:73:87:ee:e6:c8:eb:ad:40:d5:e8:94:1f:a6:7e:26:
- 5b:87:ba:0f:06:5a:4d:55:7a:aa:c4:09:34:8b:f7:e5:cc:d6:
- b7:6c:46:6d:a1:e6:66:66:4c:4b:e5:12:31:37:54:49:64:a5:
- 66:eb:e0:c6:a1:49:f8:4d:c3:d3:55:a4:05:d2:ac:fb:e1:c8:
- 69:30:4b:98:fd:72:1a:ab:9f:86:eb:0d:bd:7c:a6:3d:81:d9:
- 01:a7:8a:79:ab:3c:ce:e5:b6:c3:1b:ef:7d:5e:37:7b:37:7c:
- 91:89:59:11:21:11:7c:05:80:e1:a8:d6:f9:35:da:1b:86:06:
- 5a:32:67:6c:a9:2b:e0:31:7b:89:53:37:42:af:34:a4:53:d2:
- 7c:91:50:63:3a:8e:4a:1f:a3:90:4e:7c:41:59:1d:eb:7b:a2:
- 14:87:ba:76:36:a4:77:46:34:f2:55:50:f0:24:9f:83:83:da:
- a6:aa:3c:c8
+ 88:7c:f7:57:61:57:5f:fc:da:3b:f8:1e:a3:20:54:3e:f4:2d:
+ f8:eb:05:14:8b:ba:1b:c8:55:f5:e5:48:09:2b:19:d3:36:88:
+ 64:6d:c2:61:65:6b:71:53:20:e7:c9:43:51:6d:c2:12:2b:78:
+ 4d:bc:f3:0d:88:ec:73:3d:db:8d:2f:1d:6f:31:d6:5b:ba:a5:
+ 9d:0a:fb:50:19:7c:9d:ae:f0:c4:9e:a0:23:91:dc:21:89:75:
+ 5c:00:0b:1b:4e:ff:08:c2:85:86:f0:e2:1b:4e:88:2c:cc:0b:
+ c5:c3:5d:0f:5f:5d:27:29:73:cd:95:08:40:67:bf:23:76:48:
+ fd:14:b2:61:e0:18:1a:83:57:4a:15:af:2f:63:10:d4:65:29:
+ b1:7f:41:37:d6:5e:0c:39:c7:c3:3d:36:f6:38:62:56:ed:5e:
+ 1c:4e:a9:fa:61:53:1c:9a:77:a4:40:f7:3c:ed:e4:86:60:68:
+ f2:39:5a:a0:b9:14:48:86:95:43:29:97:a8:e1:00:32:ad:ed:
+ 2b:2a:b5:ce:26:e9:86:5a:a2:4f:03:20:26:72:c9:6b:9d:4f:
+ f8:c1:09:0f:5a:16:d5:78:71:1d:20:a6:58:03:3b:6b:26:92:
+ 25:a2:f0:ce:d5:21:7c:db:15:60:a8:8e:04:8e:52:b7:e2:13:
+ cd:0e:0c:94
-----BEGIN CERTIFICATE-----
-MIIE6DCCA9CgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx
+MIIE6zCCA9OgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
-bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjQxMjE4
-MjEyNTMwWhcNMjcwOTE0MjEyNTMwWjCBkDELMAkGA1UEBhMCVVMxEDAOBgNVBAgM
-B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNVBAoMB3dvbGZTU0wxEDAO
-BgNVBAsMB1N1cHBvcnQxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG
-SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf+6hn
-f/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5Xz/X
-GQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ48bM
-QLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5ZMMq
-0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBpQkIJ
-6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCAUUwggFBMB0GA1UdDgQW
-BBSzETLJkpiE4sn40DtuA0LKHw6OPDCB1AYDVR0jBIHMMIHJgBQnjmcRdMMmHT/t
-M2OzpNgdMOXo1aGBmqSBlzCBlDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRh
-bmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYDVQQL
-DApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG
-9w0BCQEWEGluZm9Ad29sZnNzbC5jb22CFGubcMbxo5RlGaEIWO+njSt6g8HaMAwG
-A1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ILZXhhbXBsZS5jb22HBH8AAAEwHQYDVR0l
-BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCK8U7o
-n1my2ROs/ELEgTSfazlXnOmSXUGsBTWxJpNNStr4UYLSjX/TXG4pgI2bAhArZPXR
-MQb6hSuPYzIUdno5FfNO3f3iLJAV0W9zh+7myOutQNXolB+mfiZbh7oPBlpNVXqq
-xAk0i/flzNa3bEZtoeZmZkxL5RIxN1RJZKVm6+DGoUn4TcPTVaQF0qz74chpMEuY
-/XIaq5+G6w29fKY9gdkBp4p5qzzO5bbDG+99Xjd7N3yRiVkRIRF8BYDhqNb5Ndob
-hgZaMmdsqSvgMXuJUzdCrzSkU9J8kVBjOo5KH6OQTnxBWR3re6IUh7p2NqR3RjTy
-VVDwJJ+Dg9qmqjzI
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDYx
+MTIxNDQyOVoXDTI5MDMwNzIxNDQyOVowgZExCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRAwDgYDVQQKDAd3b2xmU1NMMRAw
+DgYDVQQLDAdTdXBwb3J0MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xIDAeBgkq
+hkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAwJUI4VdB8nFtt9JFQScBZcZFrvK8JDC4lc4vTtb2HIi8fJ/7
+qGd//lycUXX3isoH5zUvj+G9e8AvfKtkqBf8yl17uuAh5XIuby6G2JVz2qwbU7lf
+P9cZDSVP4WNjUYsLZD+tQ7ilHFw0s64AoGPF9n8LWWh4c6aMGKkCba/DGQEuuBDj
+xsxAtGmjRjNph27Euxem8+jdrXO8ey8htf1mUQy9VLPhbV8cvCNz0QkDiRTSELlk
+wyrQoZZKvOHUGlvHoMDBY3gPRDcwMpaAMiOVoXe6E9KXc+JdJclqDcM5YKS0sGlC
+Qgnp2Ai8MyCzWCKnquvE4eZhg8XSlt/Z0E+t1wIDAQABo4IBRjCCAUIwHQYDVR0O
+BBYEFLMRMsmSmITiyfjQO24DQsofDo48MIHVBgNVHSMEgc0wgcqAFCeOZxF0wyYd
+P+0zY7Ok2B0w5ejVoYGbpIGYMIGVMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9u
+dGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8GA1UECgwIU2F3dG9vdGgxEzARBgNV
+BAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEgMB4GCSqG
+SIb3DQEJARYRZmFjdHNAd29sZnNzbC5jb22CFGcZ0qh/4y36dXpP57IC2a3Ed174
+MAwGA1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ILZXhhbXBsZS5jb22HBH8AAAEwHQYD
+VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCI
+fPdXYVdf/No7+B6jIFQ+9C346wUUi7obyFX15UgJKxnTNohkbcJhZWtxUyDnyUNR
+bcISK3hNvPMNiOxzPduNLx1vMdZbuqWdCvtQGXydrvDEnqAjkdwhiXVcAAsbTv8I
+woWG8OIbTogszAvFw10PX10nKXPNlQhAZ78jdkj9FLJh4Bgag1dKFa8vYxDUZSmx
+f0E31l4MOcfDPTb2OGJW7V4cTqn6YVMcmnekQPc87eSGYGjyOVqguRRIhpVDKZeo
+4QAyre0rKrXOJumGWqJPAyAmcslrnU/4wQkPWhbVeHEdIKZYAztrJpIlovDO1SF8
+2xVgqI4EjlK34hPNDgyU
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- 6b:9b:70:c6:f1:a3:94:65:19:a1:08:58:ef:a7:8d:2b:7a:83:c1:da
+ 67:19:d2:a8:7f:e3:2d:fa:75:7a:4f:e7:b2:02:d9:ad:c4:77:5e:f8
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:29 2024 GMT
- Not After : Sep 14 21:25:29 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:28 2026 GMT
+ Not After : Mar 7 21:44:28 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
@@ -129,8 +129,8 @@ Certificate:
27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -139,47 +139,47 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 77:3b:3d:66:74:bc:97:fe:40:16:e6:ba:a5:d5:d1:84:08:89:
- 69:4f:88:0d:57:a9:ef:8c:c3:97:52:c8:bd:8b:a2:49:3b:b7:
- f7:5d:1e:d6:14:7f:b2:80:33:da:a0:8a:d3:e1:2f:d5:bc:33:
- 9f:ea:5a:72:24:e5:f8:b8:4b:b3:df:62:90:3b:a8:21:ef:27:
- 42:75:bc:60:02:8e:37:35:99:eb:a3:28:f2:65:4c:ff:7a:f8:
- 8e:cc:23:6d:e5:6a:fe:22:5a:d9:b2:4f:47:c7:e0:ae:98:ef:
- 94:ac:b6:4f:61:81:29:8e:e1:79:2c:46:fc:e9:1a:c3:96:1f:
- 19:93:64:2e:9f:37:72:c5:e4:93:4e:61:5f:38:8e:ae:e8:39:
- 19:e6:97:a8:91:d4:23:7e:1e:d2:d0:53:ec:cc:ac:a0:1d:d0:
- b7:dd:b1:b7:01:2e:96:cd:85:27:e0:e7:47:e2:c1:c1:00:f6:
- 94:df:77:e7:fa:c6:ef:8a:c0:7c:67:bc:ff:a0:7c:94:3b:7d:
- 86:42:af:3d:83:31:ee:2a:3b:7b:f0:2c:9e:6f:e9:c4:07:81:
- 24:da:05:70:4d:dd:09:ae:9e:72:b8:21:0e:8c:b2:ab:aa:4c:
- 49:10:f7:76:f9:b5:0d:6c:20:d3:df:7a:06:32:8d:29:1f:28:
- 1d:8d:26:33
+ 5d:a4:7f:06:52:54:b2:56:a9:f8:8d:fb:c9:13:ab:9c:16:4e:
+ 72:a8:57:b2:8d:e7:b4:a9:3f:32:5c:21:08:ff:42:9f:41:47:
+ 12:27:b5:45:9e:61:6e:b6:94:fe:f6:01:46:96:3e:f7:3d:79:
+ 07:ac:a9:26:f5:77:f7:52:c3:ed:bd:5a:a0:17:4c:0e:9e:51:
+ 57:ac:e3:a1:ef:7d:a3:fa:7c:c6:a5:57:84:dd:d0:aa:77:ab:
+ 30:12:70:83:f9:41:ae:74:78:f0:54:73:ed:86:7f:66:a1:aa:
+ 01:cd:41:5f:95:c7:6e:ce:3b:ab:2e:70:ff:3a:34:11:43:df:
+ 4b:63:d5:3b:a5:9e:21:cb:9c:c8:a7:5c:a0:43:ec:73:98:c5:
+ 25:d9:d4:ad:cc:11:66:83:51:8a:bd:33:65:a0:a3:a8:93:1e:
+ 7b:b9:f7:6a:95:6a:a7:dd:ff:6f:3b:bb:24:5c:56:14:8d:b9:
+ 84:d3:97:bf:57:71:0c:1e:b1:68:93:31:d6:34:38:77:94:da:
+ e2:b0:fe:82:18:b2:bb:bf:83:cf:bb:fe:08:fa:2a:17:10:3e:
+ 06:b1:1c:b1:f9:12:97:87:cc:a8:4e:5e:0d:0c:26:3c:c2:e8:
+ be:2d:48:91:77:7f:1a:1d:ac:bf:c9:55:10:bf:2f:5f:60:53:
+ e7:b7:6a:72
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-d3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29t
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwzKLRSyHoRCW804H0ry
-TXUQ8bY1n9/KfQOY06zeA2buKvHYsH1uB1QLEJghTYDLEiDnzE/eRX3Jcncy6sqQ
-u2lSEAMvqPOVxfGLYlYb72dvpBBBla0Km+OlwLDScHZQMFuo6AgsfO2nonqNOCkc
-rMft8nyVsJWCfUlcOM13Je+9gHVTlDw9ymNbnxW10x0TLxnRPNt2Osy4fcnlwtfa
-QG/YIdxzG0ItU5z+Gvx9q3o2P5jehHwFZ85qFDiHqfGMtWjLaH9xICv1oGP1Vi+j
-JtK3b7FaF9c4mQj+k1hv/sMTSQgWC6dNZwBSMWcjTpjtUUUduQTZC+zYKLNLve02
-eQIDAQABo4IBRTCCAUEwHQYDVR0OBBYEFCeOZxF0wyYdP+0zY7Ok2B0w5ejVMIHU
-BgNVHSMEgcwwgcmAFCeOZxF0wyYdP+0zY7Ok2B0w5ejVoYGapIGXMIGUMQswCQYD
-VQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8G
-A1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3
-dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIU
-a5twxvGjlGUZoQhY76eNK3qDwdowDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtl
-eGFtcGxlLmNvbYcEfwAAATAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
-DQYJKoZIhvcNAQELBQADggEBAHc7PWZ0vJf+QBbmuqXV0YQIiWlPiA1Xqe+Mw5dS
-yL2Lokk7t/ddHtYUf7KAM9qgitPhL9W8M5/qWnIk5fi4S7PfYpA7qCHvJ0J1vGAC
-jjc1meujKPJlTP96+I7MI23lav4iWtmyT0fH4K6Y75Sstk9hgSmO4XksRvzpGsOW
-HxmTZC6fN3LF5JNOYV84jq7oORnml6iR1CN+HtLQU+zMrKAd0LfdsbcBLpbNhSfg
-50fiwcEA9pTfd+f6xu+KwHxnvP+gfJQ7fYZCrz2DMe4qO3vwLJ5v6cQHgSTaBXBN
-3QmunnK4IQ6MsquqTEkQ93b5tQ1sINPfegYyjSkfKB2NJjM=
+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
-----END CERTIFICATE-----
diff --git a/certs/server-ecc-rsa.pem b/certs/server-ecc-rsa.pem
index 34e4e6f21..406905961 100644
--- a/certs/server-ecc-rsa.pem
+++ b/certs/server-ecc-rsa.pem
@@ -3,11 +3,11 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:30 2024 GMT
- Not After : Sep 14 21:25:30 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = Elliptic - RSAsig, OU = ECC-RSAsig, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:29 2026 GMT
+ Not After : Mar 7 21:44:29 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=Elliptic - RSAsig, OU=ECC-RSAsig, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
@@ -24,8 +24,8 @@ Certificate:
5D:5D:26:EF:AC:7E:36:F9:9B:76:15:2B:4A:25:02:23:EF:B2:89:30
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -34,43 +34,43 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 38:e8:66:c3:74:e0:5c:59:a9:12:46:ad:84:e3:b3:fa:3e:68:
- 90:d0:06:a4:2c:ab:f7:b3:b9:7c:89:62:fb:88:eb:88:04:d9:
- 4b:ac:7e:4b:4b:7c:7c:0f:e1:dd:73:ee:88:b3:e7:1e:00:7b:
- fe:aa:24:50:d7:3c:c4:03:f2:ba:fd:81:ce:7a:0c:1c:48:6a:
- 33:ad:a7:f8:f7:ca:f7:00:47:5c:fc:f8:05:98:5f:ec:c3:aa:
- 75:93:03:a1:4e:7a:37:ec:8b:a9:99:fa:76:85:cb:c3:99:29:
- 70:1e:9c:41:f1:49:fd:e8:c0:75:0a:dd:a0:e0:d3:6e:7f:93:
- 7e:4d:2e:ee:a1:c9:db:fc:98:86:bb:67:7d:2f:74:00:10:7c:
- 24:5b:58:f3:5a:ed:96:6e:8f:34:ee:47:46:be:3e:96:25:2b:
- 7c:90:5b:65:24:48:66:5a:79:a6:6a:f5:ed:31:cf:0b:29:c3:
- f1:ab:91:21:9c:79:99:c9:5c:4c:2b:ac:f1:21:5c:44:07:14:
- 45:e5:e0:84:ce:a3:49:59:8d:94:4a:9d:11:20:c3:d3:fc:ce:
- 8f:2c:38:5b:38:e7:b2:d0:71:9f:3f:de:4e:08:03:f9:11:58:
- 7c:46:04:0a:73:28:68:b8:17:17:02:45:9c:65:96:1a:b3:98:
- 4d:3b:fb:c7
+ b0:14:95:3b:d4:62:6f:36:45:82:20:27:3e:90:b2:4c:f7:f7:
+ be:1a:e3:a3:ea:13:f8:b9:4c:45:9b:11:2e:f7:f6:da:78:86:
+ d8:ce:0c:1a:d1:0a:5a:99:6d:46:79:c2:d7:59:bd:5a:b6:48:
+ e7:94:1e:7e:5d:dc:82:4a:0d:25:b4:f0:2c:e0:69:81:d5:f5:
+ d4:4d:97:5e:a9:87:36:bc:c9:14:80:39:5f:29:96:8e:5a:6d:
+ 65:b9:01:44:9a:bf:ca:7c:de:53:b9:ba:6b:02:9e:ce:03:17:
+ c7:d5:60:01:39:a5:c5:86:e1:cc:7c:49:a3:1c:e7:31:75:16:
+ 66:8d:a3:96:c2:ff:c4:fe:9b:13:83:44:a8:3c:41:bf:2c:af:
+ 3e:a1:da:ac:f6:76:08:6a:fd:2a:12:aa:f4:66:e6:05:92:1b:
+ 2c:48:18:91:b6:3f:e6:ff:6a:19:77:e7:f3:42:af:f4:35:f5:
+ 72:ac:8d:ec:cb:e9:92:ec:f2:89:a9:33:63:a4:da:1e:3e:f3:
+ c8:98:8f:e8:75:e1:7f:55:d4:29:20:9f:72:c5:bb:87:7d:fb:
+ 0f:b1:df:07:c2:bc:1c:db:16:29:3b:28:12:53:45:d1:cd:31:
+ 38:46:15:c2:5e:6b:60:a1:79:a5:cd:15:98:a4:e9:e4:1c:a9:
+ bb:f2:10:ae
-----BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx
+MIIELTCCAxWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
-bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjQxMjE4
-MjEyNTMwWhcNMjcwOTE0MjEyNTMwWjCBnTELMAkGA1UEBhMCVVMxEDAOBgNVBAgM
-B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xGjAYBgNVBAoMEUVsbGlwdGljIC0g
-UlNBc2lnMRMwEQYDVQQLDApFQ0MtUlNBc2lnMRgwFgYDVQQDDA93d3cud29sZnNz
-bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wWTATBgcqhkjO
-PQIBBggqhkjOPQMBBwNCAAS7M6xMJ1BKxkqlBMM83p8223ItzpTqK/rLIAk5LBbo
-YQLpr03TApOaMVuXkiF/8M8Y2pERAjSG6CBYMwuANInYo4IBRTCCAUEwHQYDVR0O
-BBYEFF1dJu+sfjb5m3YVK0olAiPvsokwMIHUBgNVHSMEgcwwgcmAFCeOZxF0wyYd
-P+0zY7Ok2B0w5ejVoYGapIGXMIGUMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9u
-dGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8GA1UECgwIU2F3dG9vdGgxEzARBgNV
-BAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG
-SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIUa5twxvGjlGUZoQhY76eNK3qDwdow
-DAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATAdBgNV
-HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBADjo
-ZsN04FxZqRJGrYTjs/o+aJDQBqQsq/ezuXyJYvuI64gE2UusfktLfHwP4d1z7oiz
-5x4Ae/6qJFDXPMQD8rr9gc56DBxIajOtp/j3yvcAR1z8+AWYX+zDqnWTA6FOejfs
-i6mZ+naFy8OZKXAenEHxSf3owHUK3aDg025/k35NLu6hydv8mIa7Z30vdAAQfCRb
-WPNa7ZZujzTuR0a+PpYlK3yQW2UkSGZaeaZq9e0xzwspw/GrkSGceZnJXEwrrPEh
-XEQHFEXl4ITOo0lZjZRKnREgw9P8zo8sOFs457LQcZ8/3k4IA/kRWHxGBApzKGi4
-FxcCRZxllhqzmE07+8c=
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDYx
+MTIxNDQyOVoXDTI5MDMwNzIxNDQyOVowgZ4xCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRowGAYDVQQKDBFFbGxpcHRpYyAt
+IFJTQXNpZzETMBEGA1UECwwKRUNDLVJTQXNpZzEYMBYGA1UEAwwPd3d3LndvbGZz
+c2wuY29tMSAwHgYJKoZIhvcNAQkBFhFmYWN0c0B3b2xmc3NsLmNvbTBZMBMGByqG
+SM49AgEGCCqGSM49AwEHA0IABLszrEwnUErGSqUEwzzenzbbci3OlOor+ssgCTks
+FuhhAumvTdMCk5oxW5eSIX/wzxjakRECNIboIFgzC4A0idijggFGMIIBQjAdBgNV
+HQ4EFgQUXV0m76x+NvmbdhUrSiUCI++yiTAwgdUGA1UdIwSBzTCByoAUJ45nEXTD
+Jh0/7TNjs6TYHTDl6NWhgZukgZgwgZUxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdN
+b250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREwDwYDVQQKDAhTYXd0b290aDETMBEG
+A1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMSAwHgYJ
+KoZIhvcNAQkBFhFmYWN0c0B3b2xmc3NsLmNvbYIUZxnSqH/jLfp1ek/nsgLZrcR3
+XvgwDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATAd
+BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEB
+ALAUlTvUYm82RYIgJz6Qskz3974a46PqE/i5TEWbES739tp4htjODBrRClqZbUZ5
+wtdZvVq2SOeUHn5d3IJKDSW08CzgaYHV9dRNl16phza8yRSAOV8plo5abWW5AUSa
+v8p83lO5umsCns4DF8fVYAE5pcWG4cx8SaMc5zF1FmaNo5bC/8T+mxODRKg8Qb8s
+rz6h2qz2dghq/SoSqvRm5gWSGyxIGJG2P+b/ahl35/NCr/Q19XKsjezL6ZLs8omp
+M2Ok2h4+88iYj+h14X9V1Ckgn3LFu4d9+w+x3wfCvBzbFik7KBJTRdHNMThGFcJe
+a2CheaXNFZik6eQcqbvyEK4=
-----END CERTIFICATE-----
diff --git a/certs/server-revoked-cert.pem b/certs/server-revoked-cert.pem
index 8bf60a03f..7fa8d2a2b 100644
--- a/certs/server-revoked-cert.pem
+++ b/certs/server-revoked-cert.pem
@@ -3,11 +3,11 @@ Certificate:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:30 2024 GMT
- Not After : Sep 14 21:25:30 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = wolfSSL_revoked, OU = Support_revoked, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:29 2026 GMT
+ Not After : Mar 7 21:44:29 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_revoked, OU=Support_revoked, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
@@ -36,8 +36,8 @@ Certificate:
D8:09:2B:59:E1:2A:EE:D9:EE:40:AA:9C:AB:F0:5D:28:09:4F:22:BB
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -46,61 +46,61 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 45:72:59:97:b2:67:b1:84:57:91:f4:fc:87:4b:18:ce:96:de:
- bc:90:30:81:f7:39:2a:7d:c2:56:e5:f5:ed:79:e5:7c:e0:81:
- f1:6d:bd:cf:96:30:f8:9e:57:d7:ab:a8:ab:2e:02:2c:4b:1f:
- 0e:47:50:db:3d:c7:01:3e:7d:3f:d9:ad:fa:97:76:74:9a:2d:
- 5b:67:91:65:27:6b:64:7b:f3:b1:6f:18:0b:ec:7f:fa:ee:8a:
- 26:5b:61:88:f9:08:be:08:c3:b6:fe:c7:b2:14:5c:95:41:31:
- 26:3e:47:be:ee:d7:b4:2d:54:15:be:36:5c:e0:1f:b4:9d:9c:
- 3c:8e:1d:70:8d:c9:5e:35:38:9a:9d:0a:62:d5:8c:30:aa:f5:
- e6:0e:eb:65:4e:77:cc:96:35:17:70:bb:3b:59:68:fe:4a:cf:
- d3:39:3e:70:50:ce:df:27:d4:6b:a7:30:a4:a0:55:fa:f5:f2:
- 12:5d:c8:3d:9b:31:ff:7b:2c:55:f1:f6:6f:49:0c:5f:b3:1e:
- 23:91:57:ca:68:88:80:2d:55:f3:4f:1a:d8:b3:81:03:da:f2:
- f8:01:27:01:c6:69:6e:67:cc:96:45:b5:2b:a5:ed:12:56:75:
- 8b:97:69:2a:7d:76:5a:5e:5a:7d:97:25:f6:94:15:9a:60:92:
- fd:d5:8e:fc
+ 23:1c:0e:3f:3d:fb:56:b8:db:9b:a9:d5:7f:d4:4b:68:8a:84:
+ fb:05:fc:a3:d5:9f:ba:df:18:a1:43:7b:49:f8:1a:73:a8:0f:
+ 90:dc:70:0d:72:26:13:bd:d1:61:a5:88:66:aa:b4:5b:0d:54:
+ a9:cb:94:90:aa:a1:04:63:79:5f:97:cc:db:0f:17:cf:c1:83:
+ 24:78:4b:ab:a1:b2:66:4b:c1:55:ad:61:a5:be:e7:0a:05:76:
+ da:32:c1:27:1c:39:cf:3c:5e:1b:cc:79:85:d9:00:6f:25:ff:
+ f2:bf:1c:4e:ce:e9:5a:96:d1:f7:af:b0:35:44:19:00:c2:93:
+ 1a:b2:7d:ba:3d:c7:e4:03:15:3e:03:ba:af:25:d2:32:65:60:
+ a8:e7:b9:b5:60:55:0a:07:ab:72:c0:ae:31:e0:83:74:3d:82:
+ 0d:77:ff:dd:1f:71:16:a0:b4:1d:86:33:55:21:97:d4:e2:50:
+ f8:22:bb:5f:d4:ac:8d:46:4e:36:6a:b5:eb:5e:74:ac:c6:45:
+ c7:eb:63:b1:ff:21:cb:a6:70:4f:aa:d3:f5:da:80:77:f7:b8:
+ 9c:f0:58:52:1d:d1:e8:74:4c:1e:b9:19:b1:71:f8:7e:7f:d6:
+ 68:34:8e:4e:b2:8b:49:2a:d9:94:2e:61:14:b5:17:c5:05:68:
+ d6:d9:ed:04
-----BEGIN CERTIFICATE-----
-MIIE+DCCA+CgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx
+MIIE+zCCA+OgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
-bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjQxMjE4
-MjEyNTMwWhcNMjcwOTE0MjEyNTMwWjCBoDELMAkGA1UEBhMCVVMxEDAOBgNVBAgM
-B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xGDAWBgNVBAoMD3dvbGZTU0xfcmV2
-b2tlZDEYMBYGA1UECwwPU3VwcG9ydF9yZXZva2VkMRgwFgYDVQQDDA93d3cud29s
-ZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwFBY6Q93hUEVPz4Cz3WaWx+n03N62
-ayQbdkisxiOlp+QFGb239t76/+1bPHmKqdXx++vIseSyq1JyiZMiXLrNijYqLNFA
-7KhmDsN2zeezowoe3UoHgheBut5XzrYygce9EbvpFSJO4has49TAaIhsEfzCvRvb
-Hf3mQ8cbM7j05RtZORI4TS2bZGiY/I1yEpHyJCVsTEpIV5IAzH7Y1D24HfKe6rIj
-D1EPEUEc9ScAGwh6EjoFWwMk/rF7IPrkqFjGys5/vpUBEp0F5jkTG8A+Vi4rn3Y3
-3t6b4A16Yw2nIljbMcf3tEZcurZLSLEYmmizY0f9rxJfL/4Qy1grM2iFAgMBAAGj
-ggFFMIIBQTAdBgNVHQ4EFgQU2AkrWeEq7tnuQKqcq/BdKAlPIrswgdQGA1UdIwSB
-zDCByYAUJ45nEXTDJh0/7TNjs6TYHTDl6NWhgZqkgZcwgZQxCzAJBgNVBAYTAlVT
-MRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREwDwYDVQQKDAhT
-YXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwPd3d3LndvbGZz
-c2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tghRrm3DG8aOU
-ZRmhCFjvp40reoPB2jAMBgNVHRMEBTADAQH/MBwGA1UdEQQVMBOCC2V4YW1wbGUu
-Y29thwR/AAABMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG
-9w0BAQsFAAOCAQEARXJZl7JnsYRXkfT8h0sYzpbevJAwgfc5Kn3CVuX17XnlfOCB
-8W29z5Yw+J5X16uoqy4CLEsfDkdQ2z3HAT59P9mt+pd2dJotW2eRZSdrZHvzsW8Y
-C+x/+u6KJlthiPkIvgjDtv7HshRclUExJj5Hvu7XtC1UFb42XOAftJ2cPI4dcI3J
-XjU4mp0KYtWMMKr15g7rZU53zJY1F3C7O1lo/krP0zk+cFDO3yfUa6cwpKBV+vXy
-El3IPZsx/3ssVfH2b0kMX7MeI5FXymiIgC1V808a2LOBA9ry+AEnAcZpbmfMlkW1
-K6XtElZ1i5dpKn12Wl5afZcl9pQVmmCS/dWO/A==
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDYx
+MTIxNDQyOVoXDTI5MDMwNzIxNDQyOVowgaExCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQKDA93b2xmU1NMX3Jl
+dm9rZWQxGDAWBgNVBAsMD1N1cHBvcnRfcmV2b2tlZDEYMBYGA1UEAwwPd3d3Lndv
+bGZzc2wuY29tMSAwHgYJKoZIhvcNAQkBFhFmYWN0c0B3b2xmc3NsLmNvbTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAUFjpD3eFQRU/PgLPdZpbH6fTc
+3rZrJBt2SKzGI6Wn5AUZvbf23vr/7Vs8eYqp1fH768ix5LKrUnKJkyJcus2KNios
+0UDsqGYOw3bN57OjCh7dSgeCF4G63lfOtjKBx70Ru+kVIk7iFqzj1MBoiGwR/MK9
+G9sd/eZDxxszuPTlG1k5EjhNLZtkaJj8jXISkfIkJWxMSkhXkgDMftjUPbgd8p7q
+siMPUQ8RQRz1JwAbCHoSOgVbAyT+sXsg+uSoWMbKzn++lQESnQXmORMbwD5WLiuf
+djfe3pvgDXpjDaciWNsxx/e0Rly6tktIsRiaaLNjR/2vEl8v/hDLWCszaIUCAwEA
+AaOCAUYwggFCMB0GA1UdDgQWBBTYCStZ4Sru2e5Aqpyr8F0oCU8iuzCB1QYDVR0j
+BIHNMIHKgBQnjmcRdMMmHT/tM2OzpNgdMOXo1aGBm6SBmDCBlTELMAkGA1UEBhMC
+VVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoM
+CFNhd3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29s
+ZnNzbC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tghRnGdKo
+f+Mt+nV6T+eyAtmtxHde+DAMBgNVHRMEBTADAQH/MBwGA1UdEQQVMBOCC2V4YW1w
+bGUuY29thwR/AAABMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkq
+hkiG9w0BAQsFAAOCAQEAIxwOPz37Vrjbm6nVf9RLaIqE+wX8o9Wfut8YoUN7Sfga
+c6gPkNxwDXImE73RYaWIZqq0Ww1UqcuUkKqhBGN5X5fM2w8Xz8GDJHhLq6GyZkvB
+Va1hpb7nCgV22jLBJxw5zzxeG8x5hdkAbyX/8r8cTs7pWpbR96+wNUQZAMKTGrJ9
+uj3H5AMVPgO6ryXSMmVgqOe5tWBVCgercsCuMeCDdD2CDXf/3R9xFqC0HYYzVSGX
+1OJQ+CK7X9SsjUZONmq16150rMZFx+tjsf8hy6ZwT6rT9dqAd/e4nPBYUh3R6HRM
+HrkZsXH4fn/WaDSOTrKLSSrZlC5hFLUXxQVo1tntBA==
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- 6b:9b:70:c6:f1:a3:94:65:19:a1:08:58:ef:a7:8d:2b:7a:83:c1:da
+ 67:19:d2:a8:7f:e3:2d:fa:75:7a:4f:e7:b2:02:d9:ad:c4:77:5e:f8
Signature Algorithm: sha256WithRSAEncryption
- Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Validity
- Not Before: Dec 18 21:25:29 2024 GMT
- Not After : Sep 14 21:25:29 2027 GMT
- Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
+ Not Before: Jun 11 21:44:28 2026 GMT
+ Not After : Mar 7 21:44:28 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
@@ -129,8 +129,8 @@ Certificate:
27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5
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:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA
+ DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Alternative Name:
@@ -139,47 +139,47 @@ Certificate:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
- 77:3b:3d:66:74:bc:97:fe:40:16:e6:ba:a5:d5:d1:84:08:89:
- 69:4f:88:0d:57:a9:ef:8c:c3:97:52:c8:bd:8b:a2:49:3b:b7:
- f7:5d:1e:d6:14:7f:b2:80:33:da:a0:8a:d3:e1:2f:d5:bc:33:
- 9f:ea:5a:72:24:e5:f8:b8:4b:b3:df:62:90:3b:a8:21:ef:27:
- 42:75:bc:60:02:8e:37:35:99:eb:a3:28:f2:65:4c:ff:7a:f8:
- 8e:cc:23:6d:e5:6a:fe:22:5a:d9:b2:4f:47:c7:e0:ae:98:ef:
- 94:ac:b6:4f:61:81:29:8e:e1:79:2c:46:fc:e9:1a:c3:96:1f:
- 19:93:64:2e:9f:37:72:c5:e4:93:4e:61:5f:38:8e:ae:e8:39:
- 19:e6:97:a8:91:d4:23:7e:1e:d2:d0:53:ec:cc:ac:a0:1d:d0:
- b7:dd:b1:b7:01:2e:96:cd:85:27:e0:e7:47:e2:c1:c1:00:f6:
- 94:df:77:e7:fa:c6:ef:8a:c0:7c:67:bc:ff:a0:7c:94:3b:7d:
- 86:42:af:3d:83:31:ee:2a:3b:7b:f0:2c:9e:6f:e9:c4:07:81:
- 24:da:05:70:4d:dd:09:ae:9e:72:b8:21:0e:8c:b2:ab:aa:4c:
- 49:10:f7:76:f9:b5:0d:6c:20:d3:df:7a:06:32:8d:29:1f:28:
- 1d:8d:26:33
+ 5d:a4:7f:06:52:54:b2:56:a9:f8:8d:fb:c9:13:ab:9c:16:4e:
+ 72:a8:57:b2:8d:e7:b4:a9:3f:32:5c:21:08:ff:42:9f:41:47:
+ 12:27:b5:45:9e:61:6e:b6:94:fe:f6:01:46:96:3e:f7:3d:79:
+ 07:ac:a9:26:f5:77:f7:52:c3:ed:bd:5a:a0:17:4c:0e:9e:51:
+ 57:ac:e3:a1:ef:7d:a3:fa:7c:c6:a5:57:84:dd:d0:aa:77:ab:
+ 30:12:70:83:f9:41:ae:74:78:f0:54:73:ed:86:7f:66:a1:aa:
+ 01:cd:41:5f:95:c7:6e:ce:3b:ab:2e:70:ff:3a:34:11:43:df:
+ 4b:63:d5:3b:a5:9e:21:cb:9c:c8:a7:5c:a0:43:ec:73:98:c5:
+ 25:d9:d4:ad:cc:11:66:83:51:8a:bd:33:65:a0:a3:a8:93:1e:
+ 7b:b9:f7:6a:95:6a:a7:dd:ff:6f:3b:bb:24:5c:56:14:8d:b9:
+ 84:d3:97:bf:57:71:0c:1e:b1:68:93:31:d6:34:38:77:94:da:
+ e2:b0:fe:82:18:b2:bb:bf:83:cf:bb:fe:08:fa:2a:17:10:3e:
+ 06:b1:1c:b1:f9:12:97:87:cc:a8:4e:5e:0d:0c:26:3c:c2:e8:
+ be:2d:48:91:77:7f:1a:1d:ac:bf:c9:55:10:bf:2f:5f:60:53:
+ e7:b7:6a:72
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
diff --git a/certs/tenant-a-cert.der b/certs/tenant-a-cert.der
new file mode 100644
index 000000000..1c72249c9
Binary files /dev/null and b/certs/tenant-a-cert.der differ
diff --git a/certs/tenant-a-cert.pem b/certs/tenant-a-cert.pem
new file mode 100644
index 000000000..a9739bad0
--- /dev/null
+++ b/certs/tenant-a-cert.pem
@@ -0,0 +1,92 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 33 (0x21)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
+ Validity
+ Not Before: Jul 10 20:54:16 2026 GMT
+ Not After : Apr 5 20:54:16 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL, OU=ECH demo, CN=tenant-a.example, emailAddress=info@wolfssl.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:95:08:e1:57:41:f2:71:6d:b7:d2:45:41:27:
+ 01:65:c6:45:ae:f2:bc:24:30:b8:95:ce:2f:4e:d6:
+ f6:1c:88:bc:7c:9f:fb:a8:67:7f:fe:5c:9c:51:75:
+ f7:8a:ca:07:e7:35:2f:8f:e1:bd:7b:c0:2f:7c:ab:
+ 64:a8:17:fc:ca:5d:7b:ba:e0:21:e5:72:2e:6f:2e:
+ 86:d8:95:73:da:ac:1b:53:b9:5f:3f:d7:19:0d:25:
+ 4f:e1:63:63:51:8b:0b:64:3f:ad:43:b8:a5:1c:5c:
+ 34:b3:ae:00:a0:63:c5:f6:7f:0b:59:68:78:73:a6:
+ 8c:18:a9:02:6d:af:c3:19:01:2e:b8:10:e3:c6:cc:
+ 40:b4:69:a3:46:33:69:87:6e:c4:bb:17:a6:f3:e8:
+ dd:ad:73:bc:7b:2f:21:b5:fd:66:51:0c:bd:54:b3:
+ e1:6d:5f:1c:bc:23:73:d1:09:03:89:14:d2:10:b9:
+ 64:c3:2a:d0:a1:96:4a:bc:e1:d4:1a:5b:c7:a0:c0:
+ c1:63:78:0f:44:37:30:32:96:80:32:23:95:a1:77:
+ ba:13:d2:97:73:e2:5d:25:c9:6a:0d:c3:39:60:a4:
+ b4:b0:69:42:42:09:e9:d8:08:bc:33:20:b3:58:22:
+ a7:aa:eb:c4:e1:e6:61:83:c5:d2:96:df:d9:d0:4f:
+ ad:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ B3:11:32:C9:92:98:84:E2:C9:F8:D0:3B:6E:03:42:CA:1F:0E:8E:3C
+ 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=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:tenant-a.example
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 8f:ba:a0:15:67:98:0d:08:88:5d:20:f3:e9:81:2c:dd:52:a5:
+ 63:15:7f:3f:e4:1b:5f:6a:c9:47:d5:60:a3:fb:0a:fa:00:3e:
+ ea:ee:40:3e:9a:6f:86:ee:fb:7e:2d:f2:6f:cb:e8:42:5f:b6:
+ 45:f9:be:b2:d9:3e:5a:d9:dc:ef:d6:ad:35:b4:a6:f9:82:61:
+ 9b:38:13:7d:69:01:0c:5c:b8:e1:bc:b5:29:20:53:c4:98:0e:
+ b3:cd:3e:64:b3:4e:e4:2c:c4:6f:f6:70:b6:cf:17:70:ef:5e:
+ 44:8d:80:e1:dd:58:ae:1e:85:22:76:c5:6f:87:77:64:64:45:
+ 58:75:fc:74:ba:96:ab:4c:e9:33:40:77:97:2b:a3:c7:92:d5:
+ 5e:92:db:fb:05:b0:4a:e5:a5:56:25:4d:2a:8d:ea:a7:03:da:
+ eb:cb:98:f1:19:03:cb:a2:95:05:7d:a6:a5:82:71:57:c8:64:
+ 3c:8b:ac:f9:79:c1:05:64:29:8f:2f:96:fa:13:bd:10:e9:52:
+ 9d:5a:47:d6:14:fa:d9:4c:e5:a1:01:e5:e1:70:77:8a:66:d4:
+ 4b:7b:37:76:c9:05:cf:22:63:c3:31:33:ac:67:db:ee:91:56:
+ d7:5d:35:d4:07:81:fd:fe:1b:d4:25:aa:99:72:49:d3:79:d7:
+ 98:dc:ac:19
+-----BEGIN CERTIFICATE-----
+MIIE3jCCA8agAwIBAgIBITANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
+d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDcx
+MDIwNTQxNloXDTI5MDQwNTIwNTQxNlowgZIxCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRAwDgYDVQQKDAd3b2xmU1NMMREw
+DwYDVQQLDAhFQ0ggZGVtbzEZMBcGA1UEAwwQdGVuYW50LWEuZXhhbXBsZTEfMB0G
+CSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf
++6hnf/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5
+Xz/XGQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ
+48bMQLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5
+ZMMq0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBp
+QkIJ6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCATgwggE0MB0GA1Ud
+DgQWBBSzETLJkpiE4sn40DtuA0LKHw6OPDCB1QYDVR0jBIHNMIHKgBQnjmcRdMMm
+HT/tM2OzpNgdMOXo1aGBm6SBmDCBlTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01v
+bnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYD
+VQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xIDAeBgkq
+hkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tghRnGdKof+Mt+nV6T+eyAtmtxHde
++DAJBgNVHRMEAjAAMBsGA1UdEQQUMBKCEHRlbmFudC1hLmV4YW1wbGUwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAI+6oBVnmA0IiF0g8+mB
+LN1SpWMVfz/kG19qyUfVYKP7CvoAPuruQD6ab4bu+34t8m/L6EJftkX5vrLZPlrZ
+3O/WrTW0pvmCYZs4E31pAQxcuOG8tSkgU8SYDrPNPmSzTuQsxG/2cLbPF3DvXkSN
+gOHdWK4ehSJ2xW+Hd2RkRVh1/HS6lqtM6TNAd5cro8eS1V6S2/sFsErlpVYlTSqN
+6qcD2uvLmPEZA8uilQV9pqWCcVfIZDyLrPl5wQVkKY8vlvoTvRDpUp1aR9YU+tlM
+5aEB5eFwd4pm1Et7N3bJBc8iY8MxM6xn2+6RVtddNdQHgf3+G9QlqplySdN515jc
+rBk=
+-----END CERTIFICATE-----
diff --git a/certs/tenant-b-cert.der b/certs/tenant-b-cert.der
new file mode 100644
index 000000000..b90e1c961
Binary files /dev/null and b/certs/tenant-b-cert.der differ
diff --git a/certs/tenant-b-cert.pem b/certs/tenant-b-cert.pem
new file mode 100644
index 000000000..b339adbfe
--- /dev/null
+++ b/certs/tenant-b-cert.pem
@@ -0,0 +1,92 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 34 (0x22)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=facts@wolfssl.com
+ Validity
+ Not Before: Jul 10 20:54:16 2026 GMT
+ Not After : Apr 5 20:54:16 2029 GMT
+ Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL, OU=ECH demo, CN=tenant-b.example, emailAddress=info@wolfssl.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:95:08:e1:57:41:f2:71:6d:b7:d2:45:41:27:
+ 01:65:c6:45:ae:f2:bc:24:30:b8:95:ce:2f:4e:d6:
+ f6:1c:88:bc:7c:9f:fb:a8:67:7f:fe:5c:9c:51:75:
+ f7:8a:ca:07:e7:35:2f:8f:e1:bd:7b:c0:2f:7c:ab:
+ 64:a8:17:fc:ca:5d:7b:ba:e0:21:e5:72:2e:6f:2e:
+ 86:d8:95:73:da:ac:1b:53:b9:5f:3f:d7:19:0d:25:
+ 4f:e1:63:63:51:8b:0b:64:3f:ad:43:b8:a5:1c:5c:
+ 34:b3:ae:00:a0:63:c5:f6:7f:0b:59:68:78:73:a6:
+ 8c:18:a9:02:6d:af:c3:19:01:2e:b8:10:e3:c6:cc:
+ 40:b4:69:a3:46:33:69:87:6e:c4:bb:17:a6:f3:e8:
+ dd:ad:73:bc:7b:2f:21:b5:fd:66:51:0c:bd:54:b3:
+ e1:6d:5f:1c:bc:23:73:d1:09:03:89:14:d2:10:b9:
+ 64:c3:2a:d0:a1:96:4a:bc:e1:d4:1a:5b:c7:a0:c0:
+ c1:63:78:0f:44:37:30:32:96:80:32:23:95:a1:77:
+ ba:13:d2:97:73:e2:5d:25:c9:6a:0d:c3:39:60:a4:
+ b4:b0:69:42:42:09:e9:d8:08:bc:33:20:b3:58:22:
+ a7:aa:eb:c4:e1:e6:61:83:c5:d2:96:df:d9:d0:4f:
+ ad:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ B3:11:32:C9:92:98:84:E2:C9:F8:D0:3B:6E:03:42:CA:1F:0E:8E:3C
+ 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=facts@wolfssl.com
+ serial:67:19:D2:A8:7F:E3:2D:FA:75:7A:4F:E7:B2:02:D9:AD:C4:77:5E:F8
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:tenant-b.example
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 22:58:5f:eb:66:9b:03:30:ca:04:59:94:7b:4f:07:0c:b1:04:
+ 13:50:d2:0c:c7:87:c4:d4:0b:e9:57:e9:0b:6e:58:8f:07:af:
+ 5b:8d:89:5c:1f:ce:17:77:82:d9:ed:6a:81:9e:92:a1:a3:0b:
+ 0a:8d:f5:5b:14:52:1b:b1:86:8e:b1:37:04:e9:f7:23:34:b5:
+ 00:d2:5d:6d:8d:da:11:1c:a5:02:d6:33:d0:39:a5:8c:d8:e7:
+ 81:a2:cb:f6:36:6e:da:fd:12:80:19:85:65:f2:5f:cd:21:68:
+ 3a:e4:7e:e3:2b:41:42:c3:ff:1f:8b:b4:dd:87:26:3e:a9:cc:
+ 4b:80:23:72:40:98:5a:2a:e3:af:d5:7c:71:7f:a6:85:ad:23:
+ b9:d6:d3:fc:bf:24:ee:71:7f:54:bc:a4:7b:69:d4:4c:ea:72:
+ 64:45:72:68:8f:08:ea:81:44:17:24:43:0a:70:5d:3d:19:15:
+ 8d:93:d2:c2:d2:95:2e:dd:ea:92:bc:27:ae:89:6e:ab:6d:4b:
+ 1b:f0:d5:b5:e7:f3:26:fe:64:8d:1b:08:ef:18:1e:a9:cf:54:
+ c5:25:14:d3:49:a6:81:78:f6:38:a4:a5:43:5e:a1:92:84:8c:
+ 2b:a4:e0:66:5e:ea:7c:d8:d1:e0:43:cf:fe:e7:c7:6a:fa:cf:
+ 7f:4a:c3:50
+-----BEGIN CERTIFICATE-----
+MIIE3jCCA8agAwIBAgIBIjANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
+d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
+bC5jb20xIDAeBgkqhkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tMB4XDTI2MDcx
+MDIwNTQxNloXDTI5MDQwNTIwNTQxNlowgZIxCzAJBgNVBAYTAlVTMRAwDgYDVQQI
+DAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRAwDgYDVQQKDAd3b2xmU1NMMREw
+DwYDVQQLDAhFQ0ggZGVtbzEZMBcGA1UEAwwQdGVuYW50LWIuZXhhbXBsZTEfMB0G
+CSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf
++6hnf/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5
+Xz/XGQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ
+48bMQLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5
+ZMMq0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBp
+QkIJ6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCATgwggE0MB0GA1Ud
+DgQWBBSzETLJkpiE4sn40DtuA0LKHw6OPDCB1QYDVR0jBIHNMIHKgBQnjmcRdMMm
+HT/tM2OzpNgdMOXo1aGBm6SBmDCBlTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01v
+bnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYD
+VQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xIDAeBgkq
+hkiG9w0BCQEWEWZhY3RzQHdvbGZzc2wuY29tghRnGdKof+Mt+nV6T+eyAtmtxHde
++DAJBgNVHRMEAjAAMBsGA1UdEQQUMBKCEHRlbmFudC1iLmV4YW1wbGUwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACJYX+tmmwMwygRZlHtP
+BwyxBBNQ0gzHh8TUC+lX6QtuWI8Hr1uNiVwfzhd3gtntaoGekqGjCwqN9VsUUhux
+ho6xNwTp9yM0tQDSXW2N2hEcpQLWM9A5pYzY54Giy/Y2btr9EoAZhWXyX80haDrk
+fuMrQULD/x+LtN2HJj6pzEuAI3JAmFoq46/VfHF/poWtI7nW0/y/JO5xf1S8pHtp
+1EzqcmRFcmiPCOqBRBckQwpwXT0ZFY2T0sLSlS7d6pK8J66JbqttSxvw1bXn8yb+
+ZI0bCO8YHqnPVMUlFNNJpoF49jikpUNeoZKEjCuk4GZe6nzY0eBDz/7nx2r6z39K
+w1A=
+-----END CERTIFICATE-----
diff --git a/tls/README.md b/tls/README.md
index 5b0513d6d..c4770ec01 100644
--- a/tls/README.md
+++ b/tls/README.md
@@ -118,7 +118,13 @@ into.
2. [Client](#client-ecc)
3. [Running](#run-ecc)
-6. [Encrypted Client Hello](#ech)
+7. [Encrypted Client Hello](#ech)
+
+ 1. [client-ech — Real-World ECH with Cloudflare](#ech-cloudflare)
+ 2. [Local ECH pair — server-ech-local and client-ech-local](#ech-local)
+ 3. [Multi-tenant ECH — server-ech-multi-sni and server-ech-multi-ctx](#ech-multi)
+
+ 1. [ECH rejection and retry configs](#ech-rejection)
@@ -1349,35 +1355,44 @@ To run these examples build wolfSSL with ECH support:
./configure --enable-ech && make && sudo make install
```
-There are four ECH example programs in this directory:
+The `server-ech-multi-ctx` example calls `wolfSSL_set_SSL_CTX()`, so it
+additionally needs `--enable-opensslextra`:
+
+```sh
+./configure --enable-ech --enable-opensslextra && make && sudo make install
+```
+
+This directory contains the following ECH example programs:
| Program | Description |
|---|---|
-| `client-ech` | Connects to Cloudflare to demonstrate real-world ECH |
-| `server-ech-local` | Local ECH server; generates its own ECH config at startup |
-| `client-ech-local` | Local ECH client; accepts a base64 ECH config as an argument |
-| `client-ech-grease` | GREASE ECH probe; retrieves retry configs from a local server |
+| `client-ech` | Connects to Cloudflare for real-world ECH; takes a base64 ECH config fetched from DNS |
+| `server-ech-local` | Minimal local ECH server: one `WOLFSSL_CTX`, a single private SNI |
+| `server-ech-multi-sni` | Multi-tenant ECH server: one `WOLFSSL_CTX`; an SNI callback installs each tenant's cert/key on the connection |
+| `server-ech-multi-ctx` | Multi-tenant ECH server: a per-tenant `WOLFSSL_CTX` swapped mid-handshake (needs `--enable-opensslextra`) |
+| `client-ech-local` | Local ECH client for every local server above: takes a base64 ECH config and a target SNI |
-### client-ech — Real-World ECH with Cloudflare
+### client-ech — Real-World ECH with Cloudflare
-`client-ech` demonstrates ECH against `crypto.cloudflare.com` in two phases:
+`client-ech` performs an ECH handshake against `crypto.cloudflare.com`. It takes
+the server's ECH config as a base64 command-line argument. Fetch it out of band
+from the DNS HTTPS record (the `ech=` value), e.g.:
-1. **GREASE phase**: Connects to Cloudflare's ECH endpoint
- (`cloudflare-ech.com`) without ECH configs set, which causes the library to
- send GREASE ECH. The server responds with its actual ECH configs as retry
- configs, which are collected via `wolfSSL_GetEchConfigs()`.
-2. **ECH phase**: Reconnects using the retrieved configs. The retrieved configs
- are set with `wolfSSL_SetEchConfigs()` which will set the public SNI to
- (`cloudflare-ech.com`) in addition to enabling encryption of the client
- hello. The private SNI is set via `wolfSSL_UseSNI()` to
- (`crypto.cloudflare.com`).
+```sh
+dig +tls @1.1.1.1 HTTPS crypto.cloudflare.com
+```
-The test succeeds when Cloudflare's `/cdn-cgi/trace` response shows
-`sni=encrypted`.
+`client-ech` then connects to Cloudflare's public IP on port 443, loads the
+config with `wolfSSL_SetEchConfigsBase64()`, and encrypts the private SNI
+`crypto.cloudflare.com` with `wolfSSL_UseSNI()` before sending an HTTP request
+for `/cdn-cgi/trace`. The handshake succeeds when the response shows
+`sni=encrypted` and `wolfSSL_GetEchStatus()` reports `Client: ECH successful`.
+If the connect fails (for example, a stale config), any retry configs the
+server returned are printed via `wolfSSL_GetEchRetryConfigs()`.
```sh
make client-ech
-./client-ech
+./client-ech
HTTP/1.1 200 OK
Date: Tue, 24 Feb 2026 17:42:20 GMT
Content-Type: text/plain
@@ -1410,21 +1425,27 @@ rbi=off
kex=X25519
0
+
+Client: ECH successful
```
-### Local ECH pair — server-ech-local and client-ech-local
+### Local ECH pair — server-ech-local and client-ech-local
`server-ech-local` and `client-ech-local` demonstrate ECH between two local
-processes without requiring internet access or DNS.
+processes without requiring internet access or DNS. This is the simplest
+starting point: a single `WOLFSSL_CTX` fronting a single private SNI.
`server-ech-local` generates its own ECH config at startup using
`wolfSSL_CTX_GenerateEchConfig()`, then encodes and prints it in base64. It
-listens on port 11111 and sets its private SNI to `ech-private-name.com`. The
-server loops accepting clients until it receives the message `shutdown`.
-
-`client-ech-local` takes the server's base64 ECH config as a command-line
-argument, loads it with `wolfSSL_SetEchConfigsBase64()`, and sets its private
-SNI to `ech-private-name.com` before connecting on port 11111. It then reads a
+listens on port 11111 with a public name of `public.com` and a private SNI of
+`example.com`, and loops accepting clients until it receives the message
+`shutdown`.
+
+`client-ech-local` takes the server's base64 ECH config and a target (private)
+SNI as command-line arguments. It loads the config with
+`wolfSSL_SetEchConfigsBase64()`, sets the SNI with `wolfSSL_UseSNI()`, and also
+checks the server certificate against that SNI with
+`wolfSSL_check_domain_name()` before connecting on port 11111. It then reads a
message from stdin and sends it to the server.
Build:
@@ -1433,18 +1454,21 @@ Build:
make server-ech-local client-ech-local
```
-Run the server in one terminal; it will print its ECH config:
+Run the server in one terminal; it will print its ECH config and private name:
```sh
./server-ech-local
ECH config:
+Private name: example.com
+
Waiting for a connection...
```
-Run the client in a second terminal, passing the base64 config the server printed:
+Run the client in a second terminal, passing the base64 config the server
+printed and the private SNI:
```sh
-./client-ech-local
+./client-ech-local example.com
Message for server: hello
Server: I hear ya fa shizzle!
Shutdown complete
@@ -1452,42 +1476,66 @@ Shutdown complete
Send `shutdown` as the message to stop the server.
-### client-ech-grease — GREASE Probe to Retrieve Server ECH Configs
+### Multi-tenant ECH — server-ech-multi-sni and server-ech-multi-ctx
-GREASE (Generate Random Extensions And Sustain Extensibility) provides several
-benefits to a user:
-1. Determines if a server supports ECH based on the response it gives.
-2. Retrieves ECH configs from the server if the client does not know any. It is
- an alternative to fetching them from DNS HTTPS records.
-3. Reduces the extent to which GREASE vs ECH connections stick out.
+These servers extend the local pair to a single front end that serves several
+tenants behind one public name. The client's true destination travels in the
+encrypted (inner) SNI; the server dispatches on it with a servername callback
+and selects that tenant's certificate. Both pair with `client-ech-local` — just
+pass a tenant name as the target SNI.
-`client-ech-grease` connects to a local server (such as `server-ech-local`) on
-port 11111 without valid ECH configs, which causes the library to send GREASE
-ECH. The server responds with its actual ECH configs as retry configs.
-`client-ech-grease` retrieves these via `wolfSSL_GetEchConfigs()` and prints
-them in base64. It takes the public SNI as a command-line argument.
+Both servers advertise the public name `public.com` and serve two tenants:
-Build:
+| Tenant SNI | Certificate |
+|---|---|
+| `tenant-a.example` | `../certs/tenant-a-cert.pem` |
+| `tenant-b.example` | `../certs/tenant-b-cert.pem` |
-```sh
-make client-ech-grease
-```
+They differ in *how* the tenant credentials are applied once the inner SNI is
+known:
-With `server-ech-local` already running in another terminal, probe for configs:
+- **`server-ech-multi-sni`** keeps a single `WOLFSSL_CTX`. Its SNI callback
+ installs the matched tenant's cert/key directly on the per-connection
+ `WOLFSSL` object with `wolfSSL_use_certificate_file()` /
+ `wolfSSL_use_PrivateKey_file()`.
+- **`server-ech-multi-ctx`** builds a separate `WOLFSSL_CTX` per tenant up
+ front and swaps the live connection onto the matching one with
+ `wolfSSL_set_SSL_CTX()`. This API needs wolfSSL built with
+ `--enable-opensslextra`.
+
+Build and run a server (either variant); it prints its ECH config and the
+tenants it serves:
```sh
-./client-ech-grease ech-public-name.com
+make server-ech-multi-sni client-ech-local
+./server-ech-multi-sni
ECH config:
+Tenants:
+ tenant-a.example
+ tenant-b.example
-Shutdown complete
+Waiting for a connection...
```
-The printed base64 config can then be passed directly to `client-ech-local`:
+Connect as one of the tenants, passing the printed config and the tenant SNI:
```sh
-./client-ech-local
+./client-ech-local tenant-a.example
+Message for server: hello
+Server: I hear ya fa shizzle!
+Shutdown complete
```
+#### ECH rejection and retry configs
+
+If a client offers a stale or wrong ECH config, the server cannot decrypt the
+inner ClientHello, so ECH is rejected. The handshake still completes under the
+public name (`public.com`) using the default cert, and the server returns fresh
+ECH configs as **retry configs** for the client to use on a later attempt. These
+example servers apply a strict ECH-only policy on that path: they report
+`Client ECH failed, sent retry configs` and close the connection without
+exchanging application data.
+
## TLS Example with Post-Handshake Authentication
See `client-tls-posthsauth.c` and `server-tls-posthsauth.c`. These server and client applications show how to do a handshake without the server authenticating the client. Then after the handshake is complete, the server requests authentication and the client authenticates itself to the server. This is mutual authentication with a faster handshake because the client authentication is done later. This can lead to a better user experience if there are conditions where the client need not be authenticated.
diff --git a/tls/client-ech-grease.c b/tls/client-ech-grease.c
deleted file mode 100644
index bd79dae77..000000000
--- a/tls/client-ech-grease.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* client-ech-grease.c
- *
- * Copyright (C) 2023 wolfSSL Inc.
- *
- * This file is part of wolfSSL. (formerly known as CyaSSL)
- *
- * wolfSSL is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * wolfSSL is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* the usual suspects */
-#include
-#include
-#include
-
-/* socket includes */
-#include
-#include
-#include
-#include
-
-/* wolfSSL */
-#include
-#include
-#include
-
-#define DEFAULT_PORT 11111
-
-#define CERT_FILE "../certs/ca-cert.pem"
-
-#ifdef HAVE_ECH
-int main(int argc, char **argv)
-{
- int sockfd;
- struct sockaddr_in servAddr;
- byte echConfig[512];
- word32 echConfigLen = 512;
- char echConfigBase64[512];
- word32 echConfigBase64Len = 512;
- int ret;
-
- /* declare wolfSSL objects */
- WOLFSSL_CTX* ctx;
- WOLFSSL* ssl;
-
- /* Check for proper calling convention */
- if (argc != 2) {
- printf("usage: %s \n", argv[0]);
- return 0;
- }
-
- /* Create a socket that uses an internet IPv4 address,
- * Sets the socket to be stream based (TCP),
- * 0 means choose the default protocol. */
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- fprintf(stderr, "ERROR: failed to create the socket\n");
- ret = -1;
- goto end;
- }
-
- /* Initialize the server address struct with zeros */
- memset(&servAddr, 0, sizeof(servAddr));
-
- /* Fill in the server address */
- servAddr.sin_family = AF_INET; /* using IPv4 */
- servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */
-
- /* set the ip to localhost */
- if (inet_pton(AF_INET, "127.0.0.1", &servAddr.sin_addr) != 1) {
- fprintf(stderr, "ERROR: invalid address\n");
- ret = -1;
- goto end;
- }
-
- /* Connect to the server */
- if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)))
- == -1) {
- fprintf(stderr, "ERROR: failed to connect\n");
- goto end;
- }
-
- /* Initialize wolfSSL */
- if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to initialize the library\n");
- goto socket_cleanup;
- }
-
- /* Create and initialize WOLFSSL_CTX */
- if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
- ret = -1;
- goto socket_cleanup;
- }
-
- /* Load client certificates into WOLFSSL_CTX */
- if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CERT_FILE, NULL))
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
- CERT_FILE);
- goto ctx_cleanup;
- }
-
- /* Create a WOLFSSL object */
- if ((ssl = wolfSSL_new(ctx)) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
- ret = -1;
- goto ctx_cleanup;
- }
-
- /* Set SNI to probe against */
- if (wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, argv[1], strlen(argv[1])) !=
- WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set public SNI\n");
- ret = -1;
- goto cleanup;
- }
-
- /* Attach wolfSSL to the socket */
- if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set the file descriptor\n");
- goto cleanup;
- }
-
- /* Connect to server */
- if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to connect to server\n");
- goto cleanup;
- }
-
- /* If the GREASE was successful then retry configs sent by the server
- * should be available */
- if(wolfSSL_GetEchConfigs(ssl, echConfig, &echConfigLen) !=
- WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to get GREASE configs\n");
- ret = -1;
- goto cleanup;
- }
-
- /* Print the retrieved configs in Base64 */
- if (Base64_Encode_NoNl(echConfig, echConfigLen, (byte*)echConfigBase64,
- &echConfigBase64Len) != 0) {
- fprintf(stderr, "ERROR: failed to encode ECH configs in Base64\n");
- ret = -1;
- goto cleanup;
- }
-
- printf("ECH config: %s\n\n", echConfigBase64);
-
- /* Bidirectional shutdown */
- while (wolfSSL_shutdown(ssl) == SSL_SHUTDOWN_NOT_DONE) {
- fprintf(stderr, "Shutdown not complete\n");
- }
- fprintf(stderr, "Shutdown complete\n");
-
- ret = 0;
-
- /* Cleanup and return */
-cleanup:
- wolfSSL_free(ssl); /* Free the wolfSSL object */
-ctx_cleanup:
- wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */
- wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */
-socket_cleanup:
- close(sockfd); /* Close the connection to the server */
-end:
- return ret; /* Return reporting a success */
-}
-#else
-int main(void)
-{
- printf("Please build wolfssl with ./configure --enable-ech\n");
- return 1;
-}
-#endif
diff --git a/tls/client-ech-local.c b/tls/client-ech-local.c
index 82611bdc5..475670be2 100644
--- a/tls/client-ech-local.c
+++ b/tls/client-ech-local.c
@@ -19,6 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+/* Local ECH client: Attempt to connect to a local ECH-enabled server. An ECH
+ * config must be provided as well as a target SNI.
+ *
+ * The associated ECH configs can be acquired from a locally run ECH server.
+ * Each of the example servers will print the possible target SNIs.
+ */
+
/* the usual suspects */
#include
#include
@@ -33,30 +40,56 @@
/* wolfSSL */
#include
#include
+#include
-#define DEFAULT_PORT 11111
-
-#define CERT_FILE "../certs/ca-cert.pem"
+#define DEFAULT_PORT 11111
+#define BUFF_LEN 256
+#define RETRY_CONFIGS_LEN 256
+#define CERT_FILE "../certs/ca-cert.pem"
#ifdef HAVE_ECH
+
+/* Log error, decoding err as a wolfSSL error code when possible */
+static void log_error(const char* function, int err)
+{
+ if (err != 0) {
+ char errStr[WOLFSSL_MAX_ERROR_SZ];
+ fprintf(stderr, "ERROR: %s returned %d (%s)\n", function, err,
+ wolfSSL_ERR_error_string(err, errStr));
+ }
+ else {
+ /* log WOLFSSL_FAILURE */
+ fprintf(stderr, "ERROR: %s failed\n", function);
+ }
+}
+
+#define LOG_ERROR(function, ret, label) \
+ do { \
+ log_error(function, (ret)); \
+ (ret) = -1; \
+ goto label; \
+ } while (0)
+
int main(int argc, char** argv)
{
- int sockfd;
+ int sockfd = SOCKET_INVALID;
struct sockaddr_in servAddr;
- char buff[256];
+ char buff[BUFF_LEN];
size_t len;
int ret;
- const char* privateName = "ech-private-name.com";
- int privateNameLen = strlen(privateName);
+ byte retryConfigs[RETRY_CONFIGS_LEN];
+ word32 retryConfigsLen = sizeof(retryConfigs);
+ char retryConfigsBase64[RETRY_CONFIGS_LEN];
+ word32 retryConfigsBase64Len = sizeof(retryConfigsBase64);
/* declare wolfSSL objects */
WOLFSSL_CTX* ctx;
WOLFSSL* ssl;
/* Check for proper calling convention */
- if (argc != 2) {
- printf("usage: %s \n", argv[0]);
- return 0;
+ if (argc != 3) {
+ printf("usage: %s \n", argv[0]);
+ return -1;
}
/* Create a socket that uses an internet IPv4 address,
@@ -79,14 +112,14 @@ int main(int argc, char** argv)
if (inet_pton(AF_INET, "127.0.0.1", &servAddr.sin_addr) != 1) {
fprintf(stderr, "ERROR: invalid address\n");
ret = -1;
- goto end;
+ goto socket_cleanup;
}
/* Connect to the server */
if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)))
- == -1) {
+ == -1) {
fprintf(stderr, "ERROR: failed to connect\n");
- goto end;
+ goto socket_cleanup;
}
/*---------------------------------------------------*/
@@ -95,58 +128,68 @@ int main(int argc, char** argv)
/* Initialize wolfSSL */
if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to initialize the library\n");
- goto socket_cleanup;
+ LOG_ERROR("wolfSSL_Init", ret, socket_cleanup);
}
/* Create and initialize WOLFSSL_CTX */
if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
- ret = -1;
- goto socket_cleanup;
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_CTX_new", ret, wolf_cleanup);
}
/* Load client certificates into WOLFSSL_CTX */
if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CERT_FILE, NULL))
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
- CERT_FILE);
- goto ctx_cleanup;
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_load_verify_locations(" CERT_FILE ")", ret,
+ ctx_cleanup);
}
/* Create a WOLFSSL object */
if ((ssl = wolfSSL_new(ctx)) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
- ret = -1;
- goto ctx_cleanup;
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_new", ret, ctx_cleanup);
}
/* Set ECH configs to those provided on the command line */
- if (wolfSSL_SetEchConfigsBase64(ssl, argv[1], strlen(argv[1])) !=
- WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set ECH configs\n");
- ret = -1;
- goto cleanup;
+ if ((ret = wolfSSL_SetEchConfigsBase64(ssl, argv[1], strlen(argv[1]))) !=
+ WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_SetEchConfigsBase64", ret, cleanup);
}
- /* Use privateName for private SNI */
- if (wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName,
- privateNameLen) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set private SNI\n");
- ret = -1;
- goto cleanup;
+ /* Use the private SNI provided on the command line */
+ if ((ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, argv[2],
+ strlen(argv[2]))) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_UseSNI", ret, cleanup);
+ }
+
+ /* Make sure the certificates are verified */
+ wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER, NULL);
+ /* and that the domain is checked */
+ if ((ret = wolfSSL_check_domain_name(ssl, argv[2])) !=
+ WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_check_domain_name", ret, cleanup);
}
/* Attach wolfSSL to the socket */
if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set the file descriptor\n");
- goto cleanup;
+ LOG_ERROR("wolfSSL_set_fd", ret, cleanup);
}
/* Connect to wolfSSL on the server side */
if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to connect to wolfSSL\n");
- goto cleanup;
+ ret = wolfSSL_get_error(ssl, ret);
+ if (wolfSSL_GetEchRetryConfigs(ssl, retryConfigs, &retryConfigsLen) ==
+ WOLFSSL_SUCCESS) {
+ if (Base64_Encode_NoNl(retryConfigs, retryConfigsLen,
+ (byte*)retryConfigsBase64, &retryConfigsBase64Len) != 0) {
+ fprintf(stderr, "ERROR: failed to encode retry configs "
+ "in Base64\n");
+ }
+ else {
+ printf("Received retry configs: %s\n", retryConfigsBase64);
+ }
+ }
+ LOG_ERROR("wolfSSL_connect", ret, cleanup);
}
/* Get a message for the server from stdin */
@@ -160,17 +203,17 @@ int main(int argc, char** argv)
len = strnlen(buff, sizeof(buff));
/* Send the message to the server */
- if ((ret = wolfSSL_write(ssl, buff, len)) != len) {
- fprintf(stderr, "ERROR: failed to write entire message\n");
- fprintf(stderr, "%d bytes of %d bytes were sent", ret, (int) len);
- goto cleanup;
+ if ((ret = wolfSSL_write(ssl, buff, len)) != (int)len) {
+ fprintf(stderr, "%d bytes of %d bytes were sent\n", ret, (int)len);
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_write", ret, cleanup);
}
/* Read the server data into our buff array */
memset(buff, 0, sizeof(buff));
if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) {
- fprintf(stderr, "ERROR: failed to read\n");
- goto cleanup;
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_read", ret, cleanup);
}
/* Print to stdout any data the server sends */
@@ -185,16 +228,24 @@ int main(int argc, char** argv)
ret = 0;
- /* Cleanup and return */
cleanup:
+ /* Cleanup and return */
+ if (ret == 0 && wolfSSL_GetEchStatus(ssl) == WOLFSSL_ECH_STATUS_ACCEPTED) {
+ fprintf(stdout, "\nClient: ECH successful\n");
+ }
+ else {
+ fprintf(stdout, "\nClient: ECH failed\n");
+ }
+
wolfSSL_free(ssl); /* Free the wolfSSL object */
ctx_cleanup:
wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */
+wolf_cleanup:
wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */
socket_cleanup:
close(sockfd); /* Close the connection to the server */
end:
- return ret; /* Return reporting a success */
+ return ret; /* Return reporting a success */
}
#else
int main(void)
diff --git a/tls/client-ech.c b/tls/client-ech.c
index 26fb43f76..538b2585f 100644
--- a/tls/client-ech.c
+++ b/tls/client-ech.c
@@ -19,6 +19,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+/* ECH client: Attempt to connect to a cloudflare server with ECH.
+ *
+ * The ECH configs needed for this can be retrieved via DNS, i.e.,
+ * $ dig +tls @1.1.1.1 HTTPS crypto.cloudflare.com
+ */
+
/* the usual suspects */
#include
#include
@@ -36,29 +42,51 @@
#include
#include
-#define SERV_PORT 443
-#define CERT_FILE "../certs/ech-client-cert.pem"
-#define RDBUFF_LEN 512
-#define ECHBUFF_LEN 256
+#define SERV_PORT 443
+#define RDBUFF_LEN 512
+#define RETRY_CONFIGS_LEN 512
+#define CERT_FILE "../certs/ech-client-cert.pem"
#ifdef HAVE_ECH
-int main(void)
+
+/* Log error, decoding err as a wolfSSL error code when possible */
+static void log_error(const char* function, int err)
+{
+ if (err != 0) {
+ char errStr[WOLFSSL_MAX_ERROR_SZ];
+ fprintf(stderr, "ERROR: %s returned %d (%s)\n", function, err,
+ wolfSSL_ERR_error_string(err, errStr));
+ }
+ else {
+ /* log WOLFSSL_FAILURE */
+ fprintf(stderr, "ERROR: %s failed\n", function);
+ }
+}
+
+#define LOG_ERROR(function, ret, label) \
+ do { \
+ log_error(function, (ret)); \
+ (ret) = -1; \
+ goto label; \
+ } while (0)
+
+int main(int argc, char** argv)
{
int ret = 0;
byte rd_buf[RDBUFF_LEN];
- int sockfd = -1;
+ int sockfd = SOCKET_INVALID;
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
struct sockaddr_in servAddr;
const char message[] =
- "GET /cdn-cgi/trace/ HTTP/1.1\r\n"
+ "GET /cdn-cgi/trace HTTP/1.1\r\n"
"Host: crypto.cloudflare.com\r\n"
"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.5\r\n"
"Referer: https://www.google.com/\r\n"
"DNT: 1\r\n"
- "Connection: keep-alive\r\n"
+ "Connection: close\r\n"
"Upgrade-Insecure-Requests: 1\r\n"
"Sec-Fetch-Dest: document\r\n"
"Sec-Fetch-Mode: navigate\r\n"
@@ -66,41 +94,31 @@ int main(void)
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"\r\n";
- const char publicIP[] = "104.18.11.118";
- const char publicSNI[] = "cloudflare-ech.com";
+ const char publicIP[] = "104.18.4.139";
const char privateSNI[] = "crypto.cloudflare.com";
- byte echConfigs[ECHBUFF_LEN];
- word32 echConfigsLen = ECHBUFF_LEN;
-
- /* Initialize wolfSSL */
- if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to initialize the library\n");
- goto cleanup;
- }
-
- /* Create and initialize WOLFSSL_CTX */
- if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
- ret = -1;
- goto cleanup;
+ byte retryConfigs[RETRY_CONFIGS_LEN];
+ word32 retryConfigsLen = sizeof(retryConfigs);
+ char retryConfigsBase64[RETRY_CONFIGS_LEN];
+ word32 retryConfigsBase64Len = sizeof(retryConfigsBase64);
+
+ /* The wolfSSL ECH client will connect to this server under the SNI given in
+ * the echConfig (which is likely cloudflare-ech.com), which will either
+ * serve or route the connection to crypto.cloudflare.com where it makes the
+ * HTTP request. */
+
+ /* Check for proper calling convention */
+ if (argc != 2) {
+ printf("usage: %s \n", argv[0]);
+ return -1;
}
- /*---------------------------------------------------*/
- /* Start of wolfSSL GREASE connection */
- /*---------------------------------------------------*/
-
- /* this first tls connection is only used to get the retry configs - these
- * configs can also be retrieved from DNS
- * i.e. `$ dig cloudflare-ech.com HTTPS` */
-
-
/* Create a socket that uses an internet IPv4 address,
* Sets the socket to be stream based (TCP),
* 0 means choose the default protocol. */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "ERROR: failed to create the socket\n");
ret = -1;
- goto cleanup;
+ goto end;
}
/* Initialize the server address struct with zeros */
@@ -117,132 +135,84 @@ int main(void)
if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)))
== -1) {
fprintf(stderr, "ERROR: failed to connect\n");
- goto cleanup;
- }
-
- /* Load client certificates into WOLFSSL_CTX */
- if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CERT_FILE, NULL))
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
- CERT_FILE);
- goto ctx_cleanup;
- }
-
- /* Create a WOLFSSL object */
- if ((ssl = wolfSSL_new(ctx)) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
- ret = -1;
- goto ctx_cleanup;
- }
-
- /* Set SNI to the ECH server
- * Take care not to set this to the private SNI because that would leak
- * information about it. The private SNI will only be encrypted once the ECH
- * configs are set. */
- if ((ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, publicSNI,
- strlen(publicSNI))) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set public SNI %d\n", ret);
- ret = -1;
- goto ssl_cleanup;
- }
-
- /* Attach wolfSSL to the socket */
- if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set the file descriptor %d\n", ret);
- goto ssl_cleanup;
- }
-
- /* Connect to Cloudflare ECH server */
- if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to connect to Cloudflare ECH server\n");
- fprintf(stderr, "%d %d\n", ret, wolfSSL_get_error(ssl, ret));
- goto ssl_cleanup;
- }
-
- /* If the GREASE was successful then retry configs sent by the server
- * should be available. Store these in echConfigs for encrypting the
- * upcoming ECH connection. */
- if ((ret = wolfSSL_GetEchConfigs(ssl, echConfigs, &echConfigsLen)) !=
- WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: unable to get GREASE configs %d\n", ret);
- goto ssl_cleanup;
+ goto socket_cleanup;
}
- while (wolfSSL_shutdown(ssl) == WOLFSSL_SHUTDOWN_NOT_DONE) {
- ; /* do nothing */
+ /* Initialize wolfSSL */
+ if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_Init", ret, socket_cleanup);
}
- /* frees all data before client termination */
- wolfSSL_free(ssl);
- close(sockfd);
-
- ssl = NULL;
- sockfd = -1;
-
- /*---------------------------------------------------*/
- /* Start of wolfSSL ECH connection */
- /*---------------------------------------------------*/
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- fprintf(stderr, "ERROR: failed to create the socket\n");
- ret = -1;
- goto ctx_cleanup;
+ /* Create and initialize WOLFSSL_CTX */
+ if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_CTX_new", ret, wolf_cleanup);
}
- memset(&servAddr, 0, sizeof(servAddr));
- servAddr.sin_family = AF_INET; /* using IPv4 */
- servAddr.sin_port = htons(SERV_PORT); /* on DEFAULT_PORT */
- servAddr.sin_addr.s_addr = inet_addr( publicIP );
- if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)))
- == -1) {
- fprintf(stderr, "ERROR: failed to connect\n");
- goto ctx_cleanup;
+ /* Load client certificates into WOLFSSL_CTX */
+ if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CERT_FILE, NULL))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_load_verify_locations(" CERT_FILE ")", ret,
+ ctx_cleanup);
}
/* Create a WOLFSSL object */
if ((ssl = wolfSSL_new(ctx)) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
- ret = -1;
- goto ctx_cleanup;
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_new", ret, ctx_cleanup);
}
- /* set the ECH configs with configs taken from the GREASE connection */
- if ((ret = wolfSSL_SetEchConfigs(ssl, echConfigs, echConfigsLen)) !=
+ /* ECH configs can be retrieved from DNS
+ * i.e. `$ dig +tls @1.1.1.1 HTTPS crypto.cloudflare.com` */
+
+ /* Set the ECH configs. This will setup the client to perform an ECH
+ * connection with the server.
+ * If these are not set then a GREASE ECH extension will be sent. When
+ * sending a GREASE ECH the connection will NOT hide any information - it is
+ * basically a normal TLSv13 connection. */
+ if ((ret = wolfSSL_SetEchConfigsBase64(ssl, argv[1], strlen(argv[1]))) !=
WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to set GREASE configs %d\n", ret);
- goto ssl_cleanup;
+ LOG_ERROR("wolfSSL_SetEchConfigsBase64", ret, cleanup);
}
- /* Now that ECH configs are set the private SNI will be encrypted, therefore
- * it is now fine (and correct) to set the private SNI here */
+ /* Now that ECH configs are set the private SNI will be encrypted */
if ((ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateSNI,
strlen(privateSNI))) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set private SNI %d\n", ret);
- ret = -1;
- goto ssl_cleanup;
+ LOG_ERROR("wolfSSL_UseSNI", ret, cleanup);
}
/* Attach wolfSSL to the socket */
if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: Failed to set the file descriptor %d\n", ret);
- goto ssl_cleanup;
+ LOG_ERROR("wolfSSL_set_fd", ret, cleanup);
}
/* Connect to Cloudflare */
if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to connect to Cloudflare\n");
- fprintf(stderr, "%d %d\n", ret, wolfSSL_get_error(ssl, ret));
- goto ssl_cleanup;
+ ret = wolfSSL_get_error(ssl, ret);
+
+ if (wolfSSL_GetEchRetryConfigs(ssl, retryConfigs, &retryConfigsLen) ==
+ WOLFSSL_SUCCESS) {
+ fprintf(stderr, "\n");
+ if (Base64_Encode_NoNl(retryConfigs, retryConfigsLen,
+ (byte*)retryConfigsBase64, &retryConfigsBase64Len) != 0) {
+ fprintf(stderr, "ERROR: failed to encode retry configs "
+ "in Base64\n");
+ }
+ else {
+ printf("Received retry configs: %s\n", retryConfigsBase64);
+ }
+ }
+ LOG_ERROR("wolfSSL_connect", ret, cleanup);
}
/* Write the message that will ask the server for information on the
* connection */
if ((ret = wolfSSL_write(ssl, message, strlen(message))) !=
- strlen(message)) {
- fprintf(stderr, "ERROR: failed to write entire message\n");
- fprintf(stderr, "%d bytes of %d bytes were sent",
+ (int)strlen(message)) {
+ fprintf(stderr, "%d bytes of %d bytes were sent\n",
ret, (int)strlen(message));
- goto ssl_cleanup;
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_write", ret, cleanup);
}
/* Retrieve the server's response:
@@ -258,22 +228,35 @@ int main(void)
/* read until the chunk size is 0 */
} while (rd_buf[0] != '0');
+ /* a clean close returns 0; anything negative is a real read error */
+ if (ret < 0) {
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_read", ret, cleanup);
+ }
+
while (wolfSSL_shutdown(ssl) == WOLFSSL_SHUTDOWN_NOT_DONE) {
; /* do nothing */
}
ret = 0;
-ssl_cleanup:
- wolfSSL_free(ssl);
- ssl = NULL;
-ctx_cleanup:
- wolfSSL_CTX_free(ctx);
cleanup:
- wolfSSL_Cleanup();
- close(sockfd);
- sockfd = -1;
+ /* Cleanup and return */
+ if (ret == 0 && wolfSSL_GetEchStatus(ssl) == WOLFSSL_ECH_STATUS_ACCEPTED) {
+ fprintf(stdout, "\nClient: ECH successful\n");
+ }
+ else {
+ fprintf(stdout, "\nClient: ECH failed\n");
+ }
+ wolfSSL_free(ssl); /* Free the wolfSSL object */
+ctx_cleanup:
+ wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */
+wolf_cleanup:
+ wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */
+socket_cleanup:
+ close(sockfd); /* Close the connection to the server */
+end:
return ret;
}
#else
diff --git a/tls/server-ech-local.c b/tls/server-ech-local.c
index bc2b4e745..e018ddbee 100644
--- a/tls/server-ech-local.c
+++ b/tls/server-ech-local.c
@@ -19,6 +19,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+/* ECH server: a single WOLFSSL_CTX with just a single private SNI. This is not
+ * an effective use of ECH, instead it is meant to showcase a minimal setup.
+ *
+ * This example should give a good understanding of the basic workflow needed
+ * for ECH before bringing in the systems needed for managing multiple SNIs.
+ *
+ * Pair with client-ech-local to connect.
+ */
+
/* the usual suspects */
#include
#include
@@ -30,17 +39,45 @@
#include
#include
+#define HAVE_SIGNAL
+#ifdef HAVE_SIGNAL
+#include
+#endif
+
/* wolfSSL */
#include
#include
#include
-#define DEFAULT_PORT 11111
-
-#define CERT_FILE "../certs/server-cert.pem"
-#define KEY_FILE "../certs/server-key.pem"
+#define DEFAULT_PORT 11111
+#define BUFF_LEN 256
+#define ECH_CONFIG_LEN 256
+#define CERT_FILE "../certs/server-cert.pem"
+#define KEY_FILE "../certs/server-key.pem"
#ifdef HAVE_ECH
+
+/* Log error, decoding err as a wolfSSL error code when possible */
+static void log_error(const char* function, int err)
+{
+ if (err != 0) {
+ char errStr[WOLFSSL_MAX_ERROR_SZ];
+ fprintf(stderr, "ERROR: %s returned %d (%s)\n", function, err,
+ wolfSSL_ERR_error_string(err, errStr));
+ }
+ else {
+ /* log WOLFSSL_FAILURE */
+ fprintf(stderr, "ERROR: %s failed\n", function);
+ }
+}
+
+#define LOG_ERROR(function, ret, label) \
+ do { \
+ log_error(function, (ret)); \
+ (ret) = -1; \
+ goto label; \
+ } while (0)
+
int main()
{
int sockfd = SOCKET_INVALID;
@@ -48,25 +85,35 @@ int main()
struct sockaddr_in servAddr;
struct sockaddr_in clientAddr;
socklen_t size = sizeof(clientAddr);
- char buff[256];
+ char buff[BUFF_LEN];
size_t len;
int shutdown = 0;
int ret;
+ int status;
const char* reply = "I hear ya fa shizzle!\n";
- const char* publicName = "ech-public-name.com";
- const char* privateName = "ech-private-name.com";
+ const char* publicName = "public.com";
+ const char* privateName = "example.com";
int privateNameLen = strlen(privateName);
- byte echConfig[512];
- word32 echConfigLen = 512;
- char echConfigBase64[512];
- word32 echConfigBase64Len = 512;
+ byte echConfig[ECH_CONFIG_LEN];
+ word32 echConfigLen = sizeof(echConfig);
+ char echConfigBase64[ECH_CONFIG_LEN];
+ word32 echConfigBase64Len = sizeof(echConfigBase64);
/* declare wolfSSL objects */
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
+#ifdef HAVE_SIGNAL
+ /* A client that resets the connection can make a later wolfSSL_write()
+ * raise SIGPIPE; ignore it so a misbehaving client cannot kill the
+ * server. */
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
/* Initialize wolfSSL */
- wolfSSL_Init();
+ if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_Init", ret, bad_init);
+ }
/* Create a socket that uses an internet IPv4 address,
* Sets the socket to be stream based (TCP),
@@ -79,57 +126,54 @@ int main()
/* Create and initialize WOLFSSL_CTX */
if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method())) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
- ret = -1;
- goto exit;
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_CTX_new", ret, exit);
}
/* Generate ech config */
- if (wolfSSL_CTX_GenerateEchConfig(ctx, publicName, 0, 0, 0)
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to generate ECH config\n");
- ret = -1;
- goto exit;
+ if ((ret = wolfSSL_CTX_GenerateEchConfig(ctx, publicName, 0, 0, 0))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GenerateEchConfig", ret, exit);
}
- if(wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen) !=
- WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to get ECH configs\n");
- ret = -1;
- goto exit;
+ if ((ret = wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GetEchConfigs", ret, exit);
}
- if (Base64_Encode_NoNl(echConfig, echConfigLen, (byte*)echConfigBase64,
- &echConfigBase64Len) != 0) {
- fprintf(stderr, "ERROR: failed to encode ECH configs in Base64\n");
- ret = -1;
- goto exit;
+ if ((ret = Base64_Encode_NoNl(echConfig, echConfigLen,
+ (byte*)echConfigBase64, &echConfigBase64Len)) != 0) {
+ LOG_ERROR("Base64_Encode_NoNl", ret, exit);
}
fprintf(stdout, "ECH config: %s\n", echConfigBase64);
- if(wolfSSL_CTX_UseSNI(ctx, WOLFSSL_SNI_HOST_NAME, privateName,
- privateNameLen) != WOLFSSL_SUCCESS) {
- fprintf(stderr,
- "ERROR: failed to set private SNI\n");
- ret = -1;
- goto exit;
+ fprintf(stdout, "Private name: %s\n\n", privateName);
+
+ if ((ret = wolfSSL_CTX_UseSNI(ctx, WOLFSSL_SNI_HOST_NAME, privateName,
+ privateNameLen)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_UseSNI", ret, exit);
}
+ /* For this example to truly work the certificate installed would need to
+ * have both the publicName and privateName in its certificate. This
+ * example is only here to show a very simple setup of ECH so this has not
+ * been done.
+ *
+ * The consequence of this is that checking the domain name when ECH is
+ * rejected will always return a failure since the publicName will
+ * not match. */
+
/* Load server certificates into WOLFSSL_CTX */
- if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM))
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
- CERT_FILE);
- goto exit;
+ if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_certificate_file(" CERT_FILE ")", ret,
+ exit);
}
-
/* Load server key into WOLFSSL_CTX */
- if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM))
- != WOLFSSL_SUCCESS) {
- fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
- KEY_FILE);
- goto exit;
+ if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_PrivateKey_file(" KEY_FILE ")", ret, exit);
}
/* Initialize the server address struct with zeros */
@@ -168,9 +212,8 @@ int main()
/* Create a WOLFSSL object */
if ((ssl = wolfSSL_new(ctx)) == NULL) {
- fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
- ret = -1;
- goto exit;
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_new", ret, exit);
}
/* Attach wolfSSL to the socket */
@@ -179,38 +222,52 @@ int main()
/* Establish TLS connection */
ret = wolfSSL_accept(ssl);
if (ret != WOLFSSL_SUCCESS) {
- fprintf(stderr, "wolfSSL_accept error = %d\n",
- wolfSSL_get_error(ssl, ret));
- goto exit;
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_accept", ret, restart_server);
}
printf("Client connected successfully\n");
- /* Read the client data into our buff array */
- memset(buff, 0, sizeof(buff));
- if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) {
- fprintf(stderr, "ERROR: failed to read\n");
- goto exit;
+ status = wolfSSL_GetEchStatus(ssl);
+ if (status == WOLFSSL_ECH_STATUS_ACCEPTED) {
+ printf("Client connected with ECH\n");
}
-
- /* Print to stdout any data the client sends */
- printf("Client: %s\n", buff);
-
- /* Check for server shutdown command */
- if (strncmp(buff, "shutdown", 8) == 0) {
- printf("Shutdown command issued!\n");
- shutdown = 1;
+ else if (status == WOLFSSL_ECH_STATUS_NOT_OFFERED) {
+ printf("Client did not send ECH\n");
+ }
+ else if (status == WOLFSSL_ECH_STATUS_REJECTED) {
+ printf("Client ECH failed, sent retry configs\n");
}
- /* Write our reply into buff */
+ /* When ECH is rejected the client may abort before sending anything, so
+ * handle the potential IO errors here */
memset(buff, 0, sizeof(buff));
- memcpy(buff, reply, strlen(reply));
- len = strnlen(buff, sizeof(buff));
-
- /* Reply back to the client */
- if ((ret = wolfSSL_write(ssl, buff, len)) != len) {
- fprintf(stderr, "ERROR: failed to write\n");
- goto exit;
+ ret = wolfSSL_read(ssl, buff, sizeof(buff)-1);
+ if (ret > 0) {
+ /* Print to stdout any data the client sends */
+ printf("Client: %s\n", buff);
+
+ /* Check for server shutdown command */
+ if (strncmp(buff, "shutdown", 8) == 0) {
+ printf("Shutdown command issued!\n");
+ shutdown = 1;
+ }
+
+ /* Write our reply into buff */
+ memset(buff, 0, sizeof(buff));
+ memcpy(buff, reply, strlen(reply));
+ len = strnlen(buff, sizeof(buff));
+
+ /* Reply back to the client; treat a bad write as non-fatal */
+ if (wolfSSL_write(ssl, buff, len) != (int)len)
+ fprintf(stderr, "ERROR: failed to write\n");
+ }
+ else {
+ int err = wolfSSL_get_error(ssl, ret);
+ if (err == WOLFSSL_ERROR_ZERO_RETURN)
+ printf("Client closed the connection\n");
+ else
+ fprintf(stderr, "wolfSSL_read error = %d\n", err);
}
/* Notify the client that the connection is ending */
@@ -218,9 +275,11 @@ int main()
printf("Shutdown complete\n");
/* Cleanup after this connection */
+restart_server:
wolfSSL_free(ssl); /* Free the wolfSSL object */
ssl = NULL;
close(connd); /* Close the connection to the client */
+ connd = SOCKET_INVALID;
}
ret = 0;
@@ -228,16 +287,17 @@ int main()
exit:
/* Cleanup and return */
if (ssl)
- wolfSSL_free(ssl); /* Free the wolfSSL object */
+ wolfSSL_free(ssl); /* Free the wolfSSL object */
if (connd != SOCKET_INVALID)
- close(connd); /* Close the connection to the client */
+ close(connd); /* Close the connection to the client */
if (sockfd != SOCKET_INVALID)
close(sockfd); /* Close the socket listening for clients */
if (ctx)
wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */
wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */
+bad_init:
- return ret; /* Return reporting a success */
+ return ret; /* Return reporting a success */
}
#else
int main(void)
diff --git a/tls/server-ech-multi-ctx.c b/tls/server-ech-multi-ctx.c
new file mode 100644
index 000000000..b9ce4cc16
--- /dev/null
+++ b/tls/server-ech-multi-ctx.c
@@ -0,0 +1,404 @@
+/* server-ech-multi-ctx.c
+ *
+ * Copyright (C) 2023 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* Multi-CTX ECH server: a public-facing WOLFSSL_CTX fronts multiple tenants,
+ * with a separate WOLFSSL_CTX (cert + key) prepared for each tenant. A
+ * servername callback dispatches on the inner/private SNI and swaps the live
+ * connection onto the matching tenant's CTX.
+ *
+ * Unlike `server-ech-multi-sni.c` (which installs the tenant cert/key directly
+ * on the per-connection WOLFSSL object) this swaps the whole CTX with
+ * wolfSSL_set_SSL_CTX midway through the handshake. This API requires wolfSSL
+ * built with --enable-opensslextra (or --enable-all).
+ *
+ * Pair with client-ech-local and use one of the tenant names as the
+ * inner/private SNI.
+ */
+
+/* the usual suspects */
+#include
+#include
+#include
+
+/* socket includes */
+#include
+#include
+#include
+#include
+
+#define HAVE_SIGNAL
+#ifdef HAVE_SIGNAL
+#include
+#endif
+
+/* wolfSSL */
+#include
+#include
+#include
+
+#define DEFAULT_PORT 11111
+#define BUFF_LEN 256
+#define ECH_CONFIG_LEN 256
+#define PUBLIC_NAME "public.com"
+#define ECH_CERT_FILE "../certs/ech-public-cert.pem"
+#define ECH_KEY_FILE "../certs/ech-public-key.pem"
+
+#define TENANT_A_NAME "tenant-a.example"
+#define TENANT_A_CERT_FILE "../certs/tenant-a-cert.pem"
+#define TENANT_A_KEY_FILE "../certs/server-key.pem"
+#define TENANT_B_NAME "tenant-b.example"
+#define TENANT_B_CERT_FILE "../certs/tenant-b-cert.pem"
+#define TENANT_B_KEY_FILE "../certs/server-key.pem"
+
+#if defined(HAVE_ECH) && (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA))
+
+/* Log error, decoding err as a wolfSSL error code when possible */
+static void log_error(const char* function, int err)
+{
+ if (err != 0) {
+ char errStr[WOLFSSL_MAX_ERROR_SZ];
+ fprintf(stderr, "ERROR: %s returned %d (%s)\n", function, err,
+ wolfSSL_ERR_error_string(err, errStr));
+ }
+ else {
+ /* log WOLFSSL_FAILURE */
+ fprintf(stderr, "ERROR: %s failed\n", function);
+ }
+}
+
+#define LOG_ERROR(function, ret, label) \
+ do { \
+ log_error(function, (ret)); \
+ (ret) = -1; \
+ goto label; \
+ } while (0)
+
+/* The SNI, cert, key, and per-tenant context */
+typedef struct ech_tenant {
+ const char* name;
+ const char* certFile;
+ const char* keyFile;
+ WOLFSSL_CTX* ctx;
+} ech_tenant;
+
+/* SNI dispatch callback. This is invoked for the SNI chosen by the server:
+ * ECH rejected / GREASE / no ECH -> outer (cleartext) SNI
+ * ECH accepted -> inner SNI
+ *
+ * On a tenant match the connection is swapped onto that tenant's CTX with
+ * wolfSSL_set_SSL_CTX, so the handshake uses its cert/key in place of the
+ * default (public) CTX.
+ *
+ * returns:
+ * 0 -> name match (ctx selected)
+ * unrecognized_name -> unknown name + aborts */
+static int sni_select_tenant(WOLFSSL* ssl, int* ad, void* arg)
+{
+ const ech_tenant* tenants = (const ech_tenant*)arg;
+ void* name = NULL;
+ word16 nameLen;
+
+ if (tenants == NULL)
+ return noack_return;
+
+ /* Access the received SNI */
+ nameLen = wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, &name);
+ if (nameLen == 0 || name == NULL) {
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+ }
+
+ fprintf(stdout, "Got client SNI: %.*s\n", (int)nameLen, (const char*)name);
+
+ /* public name -> CTX already in use */
+ if (strlen(PUBLIC_NAME) == nameLen &&
+ strncmp((const char*)name, PUBLIC_NAME, nameLen) == 0) {
+ return 0;
+ }
+
+ /* otherwise match one of the configured tenants and swap to its ctx */
+ for (; tenants->name != NULL; tenants++) {
+ if (strlen((const char*)tenants->name) == nameLen &&
+ strncmp((const char*)name, tenants->name, nameLen) == 0) {
+ if (wolfSSL_set_SSL_CTX(ssl, tenants->ctx) == NULL) {
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+ }
+ return 0;
+ }
+ }
+
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+}
+
+int main(void)
+{
+ int sockfd = SOCKET_INVALID;
+ int connd = SOCKET_INVALID;
+ struct sockaddr_in servAddr;
+ struct sockaddr_in clientAddr;
+ socklen_t size = sizeof(clientAddr);
+ char buff[BUFF_LEN];
+ size_t len;
+ int shutdown = 0;
+ int ret;
+ int status;
+ const char* reply = "I hear ya fa shizzle!\n";
+ byte echConfig[ECH_CONFIG_LEN];
+ word32 echConfigLen = sizeof(echConfig);
+ char echConfigBase64[ECH_CONFIG_LEN];
+ word32 echConfigBase64Len = sizeof(echConfigBase64);
+
+ /* declare wolfSSL objects */
+ WOLFSSL_CTX* ctx = NULL;
+ WOLFSSL* ssl = NULL;
+
+ ech_tenant tenants[] = {
+ { TENANT_A_NAME, TENANT_A_CERT_FILE, TENANT_A_KEY_FILE, NULL },
+ { TENANT_B_NAME, TENANT_B_CERT_FILE, TENANT_B_KEY_FILE, NULL },
+ { NULL, NULL, NULL, NULL }
+ };
+ ech_tenant* tenants_p;
+
+#ifdef HAVE_SIGNAL
+ /* A client that resets the connection can make a later wolfSSL_write()
+ * raise SIGPIPE; ignore it so a client cannot kill the server. */
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ /* Initialize wolfSSL */
+ if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_Init", ret, bad_init);
+ }
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ fprintf(stderr, "ERROR: failed to create the socket\n");
+ ret = -1;
+ goto exit;
+ }
+
+ /* Create and initialize WOLFSSL_CTX */
+ if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method())) == NULL) {
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_CTX_new", ret, exit);
+ }
+
+ /* Generate the ECH config */
+ if ((ret = wolfSSL_CTX_GenerateEchConfig(ctx, PUBLIC_NAME, 0, 0, 0))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GenerateEchConfig", ret, exit);
+ }
+
+ if ((ret = wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GetEchConfigs", ret, exit);
+ }
+
+ if ((ret = Base64_Encode_NoNl(echConfig, echConfigLen,
+ (byte*)echConfigBase64, &echConfigBase64Len)) != 0) {
+ LOG_ERROR("Base64_Encode_NoNl", ret, exit);
+ }
+
+ fprintf(stdout, "ECH config: %s\n", echConfigBase64);
+
+ tenants_p = tenants;
+ fprintf(stdout, "Tenants:\n");
+ for (; tenants_p->name != NULL; tenants_p++) {
+ fprintf(stdout, " %s\n", tenants_p->name);
+ }
+ fprintf(stdout, "\n");
+
+ /* Load a default cert/key on the CTX for the publicName / fallback path.
+ * Clients with ECH-rejected handshakes use these. */
+ if ((ret = wolfSSL_CTX_use_certificate_file(ctx, ECH_CERT_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_certificate_file(" ECH_CERT_FILE ")", ret,
+ exit);
+ }
+
+ if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, ECH_KEY_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_PrivateKey_file(" ECH_KEY_FILE ")", ret,
+ exit);
+ }
+
+ /* Build a CTX per tenant, each with its own cert and key. The servername
+ * callback swaps the live connection onto one of these (via
+ * wolfSSL_set_SSL_CTX) once ECH is accepted and the inner SNI is known. */
+ for (tenants_p = tenants; tenants_p->name != NULL; tenants_p++) {
+ if ((tenants_p->ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()))
+ == NULL) {
+ fprintf(stderr, "ERROR: failed to create CTX for tenant %s\n",
+ tenants_p->name);
+ ret = -1;
+ goto exit;
+ }
+
+ if (wolfSSL_CTX_use_certificate_file(tenants_p->ctx,
+ tenants_p->certFile, WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
+ fprintf(stderr, "ERROR: failed to load cert for tenant %s\n",
+ tenants_p->name);
+ ret = -1;
+ goto exit;
+ }
+
+ if (wolfSSL_CTX_use_PrivateKey_file(tenants_p->ctx,
+ tenants_p->keyFile, WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
+ fprintf(stderr, "ERROR: failed to load key for tenant %s\n",
+ tenants_p->name);
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ /* Register the dispatch callback */
+ wolfSSL_CTX_set_servername_callback(ctx, sni_select_tenant);
+ wolfSSL_CTX_set_servername_arg(ctx, (void*)tenants);
+
+ /* Initialize the server address struct with zeros */
+ memset(&servAddr, 0, sizeof(servAddr));
+
+ /* Fill in the server address */
+ servAddr.sin_family = AF_INET; /* using IPv4 */
+ servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */
+ servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */
+
+ /* Bind the server socket to our port */
+ if (bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) {
+ fprintf(stderr, "ERROR: failed to bind\n");
+ ret = -1;
+ goto exit;
+ }
+
+ if (listen(sockfd, 5) == -1) {
+ fprintf(stderr, "ERROR: failed to listen\n");
+ ret = -1;
+ goto exit;
+ }
+
+ while (!shutdown) {
+ fprintf(stdout, "\nWaiting for a connection...\n");
+
+ if ((connd = accept(sockfd, (struct sockaddr*)&clientAddr, &size))
+ == -1) {
+ fprintf(stderr, "ERROR: failed to accept the connection\n\n");
+ ret = -1;
+ goto exit;
+ }
+
+ if ((ssl = wolfSSL_new(ctx)) == NULL) {
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_new", ret, exit);
+ }
+
+ wolfSSL_set_fd(ssl, connd);
+
+ /* Attempt to receive a client: the SNI callback fires mid-handshake
+ * while parsing the inner ClientHello */
+ ret = wolfSSL_accept(ssl);
+ if (ret != WOLFSSL_SUCCESS) {
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_accept", ret, restart_server);
+ }
+
+ fprintf(stdout, "Client connected successfully\n");
+
+ status = wolfSSL_GetEchStatus(ssl);
+ if (status == WOLFSSL_ECH_STATUS_ACCEPTED) {
+ fprintf(stdout, "Client connected with ECH\n");
+ }
+ else if (status == WOLFSSL_ECH_STATUS_NOT_OFFERED) {
+ fprintf(stdout, "Client did not send ECH\n");
+ }
+ else if (status == WOLFSSL_ECH_STATUS_REJECTED) {
+ fprintf(stdout, "Client ECH failed, sent retry configs\n");
+ }
+
+ /* When ECH is rejected the client may abort before sending anything, so
+ * handle the potential IO errors here */
+ memset(buff, 0, sizeof(buff));
+ ret = wolfSSL_read(ssl, buff, sizeof(buff)-1);
+ if (ret > 0) {
+ fprintf(stdout, "Client: %s", buff);
+
+ if (strncmp(buff, "shutdown", 8) == 0) {
+ fprintf(stdout, "Shutdown command issued!\n");
+ shutdown = 1;
+ }
+
+ memset(buff, 0, sizeof(buff));
+ memcpy(buff, reply, strlen(reply));
+ len = strnlen(buff, sizeof(buff));
+
+ /* Treat a bad write as non-fatal too */
+ if (wolfSSL_write(ssl, buff, len) != (int)len)
+ fprintf(stderr, "ERROR: failed to write\n");
+ }
+ else {
+ int err = wolfSSL_get_error(ssl, ret);
+ if (err == WOLFSSL_ERROR_ZERO_RETURN)
+ fprintf(stdout, "Client closed the connection\n");
+ else
+ fprintf(stderr, "wolfSSL_read error = %d\n", err);
+ }
+
+ wolfSSL_shutdown(ssl);
+ fprintf(stdout, "Shutdown complete\n");
+
+restart_server:
+ wolfSSL_free(ssl);
+ ssl = NULL;
+ close(connd);
+ connd = SOCKET_INVALID;
+ }
+
+ ret = 0;
+
+exit:
+ if (ssl)
+ wolfSSL_free(ssl);
+ if (connd != SOCKET_INVALID)
+ close(connd);
+ if (sockfd != SOCKET_INVALID)
+ close(sockfd);
+ for (tenants_p = tenants; tenants_p->name != NULL; tenants_p++) {
+ if (tenants_p->ctx)
+ wolfSSL_CTX_free(tenants_p->ctx);
+ }
+ if (ctx)
+ wolfSSL_CTX_free(ctx);
+ wolfSSL_Cleanup();
+bad_init:
+
+ return ret;
+}
+#else
+int main(void)
+{
+ fprintf(stdout, "Please build wolfssl with ./configure --enable-ech "
+ "--enable-opensslextra\n");
+ return 1;
+}
+#endif
diff --git a/tls/server-ech-multi-sni.c b/tls/server-ech-multi-sni.c
new file mode 100644
index 000000000..e0a7471f5
--- /dev/null
+++ b/tls/server-ech-multi-sni.c
@@ -0,0 +1,366 @@
+/* server-ech-multi-sni.c
+ *
+ * Copyright (C) 2023 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* Multi-SNI ECH server: a single WOLFSSL_CTX fronts multiple tenants based on
+ * the inner/private SNI. A servername callback dispatches on the inner SNI and
+ * installs that tenant's certificate and private key on the per-connection
+ * WOLFSSL object.
+ *
+ * Pair with client-ech-local and use one of the tenant names as the
+ * inner/private SNI.
+ */
+
+/* the usual suspects */
+#include
+#include
+#include
+
+/* socket includes */
+#include
+#include
+#include
+#include
+
+#define HAVE_SIGNAL
+#ifdef HAVE_SIGNAL
+#include
+#endif
+
+/* wolfSSL */
+#include
+#include
+#include
+
+#define DEFAULT_PORT 11111
+#define BUFF_LEN 256
+#define ECH_CONFIG_LEN 256
+#define PUBLIC_NAME "public.com"
+#define ECH_CERT_FILE "../certs/ech-public-cert.pem"
+#define ECH_KEY_FILE "../certs/ech-public-key.pem"
+
+#define TENANT_A_NAME "tenant-a.example"
+#define TENANT_A_CERT_FILE "../certs/tenant-a-cert.pem"
+#define TENANT_A_KEY_FILE "../certs/server-key.pem"
+#define TENANT_B_NAME "tenant-b.example"
+#define TENANT_B_CERT_FILE "../certs/tenant-b-cert.pem"
+#define TENANT_B_KEY_FILE "../certs/server-key.pem"
+
+#ifdef HAVE_ECH
+
+/* Log error, decoding err as a wolfSSL error code when possible */
+static void log_error(const char* function, int err)
+{
+ if (err != 0) {
+ char errStr[WOLFSSL_MAX_ERROR_SZ];
+ fprintf(stderr, "ERROR: %s returned %d (%s)\n", function, err,
+ wolfSSL_ERR_error_string(err, errStr));
+ }
+ else {
+ /* log WOLFSSL_FAILURE */
+ fprintf(stderr, "ERROR: %s failed\n", function);
+ }
+}
+
+#define LOG_ERROR(function, ret, label) \
+ do { \
+ log_error(function, (ret)); \
+ (ret) = -1; \
+ goto label; \
+ } while (0)
+
+/* The SNI, cert, and key for a tenant */
+typedef struct ech_tenant {
+ const char* name;
+ const char* certFile;
+ const char* keyFile;
+} ech_tenant;
+
+/* SNI dispatch callback. This is invoked for the SNI chosen by the server:
+ * ECH rejected / GREASE / no ECH -> outer (cleartext) SNI
+ * ECH accepted -> inner SNI
+ *
+ * The selected cert/key are installed on the WOLFSSL object so the handshake
+ * uses them in place of the CTX defaults.
+ *
+ * returns:
+ * 0 -> name match (cert/key selected)
+ * unrecognized_name -> unknown name + aborts */
+static int sni_select_tenant(WOLFSSL* ssl, int* ad, void* arg)
+{
+ const ech_tenant* tenants = (const ech_tenant*)arg;
+ void* name = NULL;
+ word16 nameLen;
+
+ if (tenants == NULL)
+ return noack_return;
+
+ /* Access the received SNI */
+ nameLen = wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, &name);
+ if (nameLen == 0 || name == NULL) {
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+ }
+
+ fprintf(stdout, "Got client SNI: %.*s\n", (int)nameLen, (const char*)name);
+
+ /* public name -> default cert and key already installed on the CTX */
+ if (strlen(PUBLIC_NAME) == nameLen &&
+ strncmp((const char*)name, PUBLIC_NAME, nameLen) == 0) {
+ return 0;
+ }
+
+ /* otherwise match one of the configured tenants and install its cert/key */
+ for (; tenants->name != NULL; tenants++) {
+ if (strlen((const char*)tenants->name) == nameLen &&
+ strncmp((const char*)name, tenants->name, nameLen) == 0) {
+ if (wolfSSL_use_certificate_file(ssl, tenants->certFile,
+ WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS ||
+ wolfSSL_use_PrivateKey_file(ssl, tenants->keyFile,
+ WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+ }
+ return 0;
+ }
+ }
+
+ if (ad)
+ *ad = unrecognized_name;
+ return fatal_return;
+}
+
+int main(void)
+{
+ int sockfd = SOCKET_INVALID;
+ int connd = SOCKET_INVALID;
+ struct sockaddr_in servAddr;
+ struct sockaddr_in clientAddr;
+ socklen_t size = sizeof(clientAddr);
+ char buff[BUFF_LEN];
+ size_t len;
+ int shutdown = 0;
+ int ret;
+ int status;
+ const char* reply = "I hear ya fa shizzle!\n";
+ byte echConfig[ECH_CONFIG_LEN];
+ word32 echConfigLen = sizeof(echConfig);
+ char echConfigBase64[ECH_CONFIG_LEN];
+ word32 echConfigBase64Len = sizeof(echConfigBase64);
+
+ /* declare wolfSSL objects */
+ WOLFSSL_CTX* ctx = NULL;
+ WOLFSSL* ssl = NULL;
+
+ const ech_tenant tenants[] = {
+ { TENANT_A_NAME, TENANT_A_CERT_FILE, TENANT_A_KEY_FILE },
+ { TENANT_B_NAME, TENANT_B_CERT_FILE, TENANT_B_KEY_FILE },
+ { NULL, NULL, NULL }
+ };
+ const ech_tenant* tenants_p;
+
+#ifdef HAVE_SIGNAL
+ /* A client that resets the connection can make a later wolfSSL_write()
+ * raise SIGPIPE; ignore it so a client cannot kill the server. */
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ /* Initialize wolfSSL */
+ if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_Init", ret, bad_init);
+ }
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ fprintf(stderr, "ERROR: failed to create the socket\n");
+ ret = -1;
+ goto exit;
+ }
+
+ /* Create and initialize WOLFSSL_CTX */
+ if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method())) == NULL) {
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_CTX_new", ret, exit);
+ }
+
+ /* Generate the ECH config */
+ if ((ret = wolfSSL_CTX_GenerateEchConfig(ctx, PUBLIC_NAME, 0, 0, 0))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GenerateEchConfig", ret, exit);
+ }
+
+ if ((ret = wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen))
+ != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_GetEchConfigs", ret, exit);
+ }
+
+ if ((ret = Base64_Encode_NoNl(echConfig, echConfigLen,
+ (byte*)echConfigBase64, &echConfigBase64Len)) != 0) {
+ LOG_ERROR("Base64_Encode_NoNl", ret, exit);
+ }
+
+ fprintf(stdout, "ECH config: %s\n", echConfigBase64);
+
+ tenants_p = tenants;
+ fprintf(stdout, "Tenants:\n");
+ for (; tenants_p->name != NULL; tenants_p++) {
+ fprintf(stdout, " %s\n", tenants_p->name);
+ }
+ fprintf(stdout, "\n");
+
+ /* Load a default cert/key on the CTX for the publicName / fallback path.
+ * Clients with ECH-rejected handshakes use these. */
+ if ((ret = wolfSSL_CTX_use_certificate_file(ctx, ECH_CERT_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_certificate_file(" ECH_CERT_FILE ")", ret,
+ exit);
+ }
+
+ if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, ECH_KEY_FILE,
+ WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
+ LOG_ERROR("wolfSSL_CTX_use_PrivateKey_file(" ECH_KEY_FILE ")", ret,
+ exit);
+ }
+
+ /* Register the dispatch callback */
+ wolfSSL_CTX_set_servername_callback(ctx, sni_select_tenant);
+ wolfSSL_CTX_set_servername_arg(ctx, (void*)tenants);
+
+ /* Initialize the server address struct with zeros */
+ memset(&servAddr, 0, sizeof(servAddr));
+
+ /* Fill in the server address */
+ servAddr.sin_family = AF_INET; /* using IPv4 */
+ servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */
+ servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */
+
+ /* Bind the server socket to our port */
+ if (bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) {
+ fprintf(stderr, "ERROR: failed to bind\n");
+ ret = -1;
+ goto exit;
+ }
+
+ if (listen(sockfd, 5) == -1) {
+ fprintf(stderr, "ERROR: failed to listen\n");
+ ret = -1;
+ goto exit;
+ }
+
+ while (!shutdown) {
+ fprintf(stdout, "\nWaiting for a connection...\n");
+
+ if ((connd = accept(sockfd, (struct sockaddr*)&clientAddr, &size))
+ == -1) {
+ fprintf(stderr, "ERROR: failed to accept the connection\n\n");
+ ret = -1;
+ goto exit;
+ }
+
+ if ((ssl = wolfSSL_new(ctx)) == NULL) {
+ ret = WOLFSSL_FAILURE;
+ LOG_ERROR("wolfSSL_new", ret, exit);
+ }
+
+ wolfSSL_set_fd(ssl, connd);
+
+ /* Attempt to receive a client: the SNI callback fires mid-handshake
+ * while parsing the inner ClientHello */
+ ret = wolfSSL_accept(ssl);
+ if (ret != WOLFSSL_SUCCESS) {
+ ret = wolfSSL_get_error(ssl, ret);
+ LOG_ERROR("wolfSSL_accept", ret, restart_server);
+ }
+
+ fprintf(stdout, "Client connected successfully\n");
+
+ status = wolfSSL_GetEchStatus(ssl);
+ if (status == WOLFSSL_ECH_STATUS_ACCEPTED) {
+ fprintf(stdout, "Client connected with ECH\n");
+ }
+ else if (status == WOLFSSL_ECH_STATUS_NOT_OFFERED) {
+ fprintf(stdout, "Client did not send ECH\n");
+ }
+ else if (status == WOLFSSL_ECH_STATUS_REJECTED) {
+ fprintf(stdout, "Client ECH failed, sent retry configs\n");
+ }
+
+ /* When ECH is rejected the client may abort before sending anything, so
+ * handle the potential IO errors here */
+ memset(buff, 0, sizeof(buff));
+ ret = wolfSSL_read(ssl, buff, sizeof(buff)-1);
+ if (ret > 0) {
+ fprintf(stdout, "Client: %s", buff);
+
+ if (strncmp(buff, "shutdown", 8) == 0) {
+ fprintf(stdout, "Shutdown command issued!\n");
+ shutdown = 1;
+ }
+
+ memset(buff, 0, sizeof(buff));
+ memcpy(buff, reply, strlen(reply));
+ len = strnlen(buff, sizeof(buff));
+
+ /* Treat a bad write as non-fatal too */
+ if (wolfSSL_write(ssl, buff, len) != (int)len)
+ fprintf(stderr, "ERROR: failed to write\n");
+ }
+ else {
+ int err = wolfSSL_get_error(ssl, ret);
+ if (err == WOLFSSL_ERROR_ZERO_RETURN)
+ fprintf(stdout, "Client closed the connection\n");
+ else
+ fprintf(stderr, "wolfSSL_read error = %d\n", err);
+ }
+
+ wolfSSL_shutdown(ssl);
+ fprintf(stdout, "Shutdown complete\n");
+
+restart_server:
+ wolfSSL_free(ssl);
+ ssl = NULL;
+ close(connd);
+ connd = SOCKET_INVALID;
+ }
+
+ ret = 0;
+
+exit:
+ if (ssl)
+ wolfSSL_free(ssl);
+ if (connd != SOCKET_INVALID)
+ close(connd);
+ if (sockfd != SOCKET_INVALID)
+ close(sockfd);
+ if (ctx)
+ wolfSSL_CTX_free(ctx);
+ wolfSSL_Cleanup();
+bad_init:
+
+ return ret;
+}
+#else
+int main(void)
+{
+ fprintf(stdout, "Please build wolfssl with ./configure --enable-ech\n");
+ return 1;
+}
+#endif