Merge 49cf1b5376 into dfc84f3d13
commit
f5119857c2
|
|
@ -204,6 +204,19 @@ profiles:
|
|||
--enable-ocsp-responder --enable-cert-setup-cb --enable-sessioncerts
|
||||
--enable-tls13 --enable-static --enable-shared
|
||||
|
||||
ocsp-nonblock:
|
||||
# ocsp/ocsp_nonblock: two clients that fetch a live cert and check OCSP
|
||||
# non-blocking. The plain one needs opensslextra+sni and KEEP_PEER_CERT
|
||||
# (it calls wolfSSL_get_peer_certificate/X509_get_der); the async one adds
|
||||
# asynccrypt, alpn and stapling. This profile mirrors the two README
|
||||
# configure lines and adds tls13 to exercise the TLS 1.3 path against the
|
||||
# live server -- neither client requires it (both still allow TLS 1.2).
|
||||
flags: >-
|
||||
--enable-ocsp --enable-ocspstapling --enable-ocspstapling2
|
||||
--enable-asynccrypt --enable-opensslextra --enable-sni --enable-alpn
|
||||
--enable-tls13 --enable-static --enable-shared
|
||||
cflags: "-DWOLFSSL_NONBLOCK_OCSP -DHAVE_IO_TIMEOUT -DKEEP_PEER_CERT -DWOLFSSL_OCSP_SCREEN_RESPONDER"
|
||||
|
||||
pkcs11:
|
||||
flags: "--enable-pkcs11 --enable-cryptocb --enable-static --enable-shared"
|
||||
|
||||
|
|
@ -635,9 +648,9 @@ examples:
|
|||
|
||||
- id: ocsp-nonblock
|
||||
path: ocsp/ocsp_nonblock
|
||||
profile: ocsp
|
||||
profile: ocsp-nonblock
|
||||
mode: build-only
|
||||
reason: "ocsp_nonblock_async connects to an external responder on :443"
|
||||
reason: "both clients connect to a live OCSP responder on :443"
|
||||
|
||||
- id: ocsp-responder
|
||||
path: ocsp/responder
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ on:
|
|||
branches: [master]
|
||||
paths:
|
||||
- 'certs/**'
|
||||
- 'ocsp/ocsp_nonblock/ca_certs/**'
|
||||
- '.github/workflows/cert-expiry.yml'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
paths:
|
||||
- 'certs/**'
|
||||
- 'ocsp/ocsp_nonblock/ca_certs/**'
|
||||
- '.github/workflows/cert-expiry.yml'
|
||||
# No cron: nightly.yml calls this, so the nightly stays one run and one triage writer
|
||||
workflow_call:
|
||||
|
|
@ -38,3 +40,5 @@ jobs:
|
|||
- uses: actions/checkout@v5
|
||||
- name: Warn on certs nearing expiry
|
||||
run: ./certs/check-expiry.sh certs
|
||||
- name: Warn on example CA certs nearing expiry
|
||||
run: ./certs/check-expiry.sh ocsp/ocsp_nonblock/ca_certs
|
||||
|
|
|
|||
|
|
@ -5,14 +5,20 @@ Online Certificate Status Protocol (OCSP) is used for obtaining the revocation s
|
|||
|
||||
## OCSP non-blocking example
|
||||
|
||||
This uses a google.com certificate chain to demonstrate validating revocation status using an OCSP server.
|
||||
This connects to a public server, fetches its leaf certificate, and checks that
|
||||
certificate's revocation status with a non-blocking OCSP lookup. The certificate
|
||||
is fetched live so nothing static can expire.
|
||||
|
||||
The Google.com certificate defines OCSP in the X509v3 extension "Authority Information Access" section.
|
||||
It uses `www.digicert.com` because that certificate still has an OCSP responder
|
||||
(many CAs, including Google, have dropped OCSP). The bundled `ca_certs` hold the
|
||||
DigiCert CAs used to verify it.
|
||||
|
||||
Example usage:
|
||||
|
||||
```sh
|
||||
$ ./configure --enable-ocsp CFLAGS="-DHAVE_IO_TIMEOUT -DWOLFSSL_NONBLOCK_OCSP"
|
||||
$ ./configure --enable-ocsp --enable-opensslextra --enable-sni \
|
||||
CFLAGS="-DHAVE_IO_TIMEOUT -DWOLFSSL_NONBLOCK_OCSP -DKEEP_PEER_CERT \
|
||||
-DWOLFSSL_OCSP_SCREEN_RESPONDER"
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
|
|
@ -20,35 +26,56 @@ $ sudo make install
|
|||
gcc -o ocsp_nonblock ocsp_nonblock.c -Wall -I/usr/local/include -Os -L/usr/local/lib -lwolfssl
|
||||
|
||||
% ./ocsp_nonblock
|
||||
Fetched www.digicert.com certificate (1777 bytes)
|
||||
Loaded Trusted CA dir ca_certs (ret 1)
|
||||
Convert Google.com PEM cert to DER (ret 1)
|
||||
Verify Google.com cert: 1
|
||||
Verify www.digicert.com cert: 1
|
||||
OCSP Lookup:
|
||||
URL: http://ocsp.pki.goog/gts1c3
|
||||
Domain: ocsp.pki.goog
|
||||
Path: /gts1c3
|
||||
URL: http://ocsp.digicert.com
|
||||
Domain: ocsp.digicert.com
|
||||
Path: /
|
||||
Port: 80
|
||||
OCSP Response: ret 471, nonblock count 409421
|
||||
Check OCSP for Google.com (ret 1)
|
||||
OCSP Response: ret 471, nonblock count 1
|
||||
Resp ret: 471
|
||||
Check OCSP for www.digicert.com (ret 1)
|
||||
Ret = 1: success
|
||||
```
|
||||
|
||||
The `Ret = 1` line is wolfSSL's success code, not the exit status: the program
|
||||
exits `0` on success and a non-zero error code on failure, so it works in scripts.
|
||||
|
||||
If DigiCert's chain changes, pass an alternate CA directory as an argument, e.g.
|
||||
`./ocsp_nonblock /etc/ssl/certs`.
|
||||
|
||||
The certificate fetch (TCP connect plus TLS handshake) and the OCSP responder
|
||||
connect each time out after 10 seconds. On a slow network, raise it at build
|
||||
time with `CFLAGS="-DDEFAULT_TIMEOUT_SEC=30 ..."`.
|
||||
|
||||
With `WOLFSSL_OCSP_SCREEN_RESPONDER` both clients refuse OCSP responder
|
||||
addresses in loopback, private and link-local ranges, so a certificate cannot
|
||||
point the lookup at an internal host. They resolve the responder once and
|
||||
connect to the address they checked, so a changing DNS answer cannot get
|
||||
around it. Leave the define out if your responder runs on such an address.
|
||||
|
||||
## OCSP non-blocking Async example
|
||||
|
||||
This uses your system certificate chain to demonstrate validating revocation status using an OCSP
|
||||
public server with wolfSSL's Asynchronous cryptography support.
|
||||
This demonstrates validating revocation status using an OCSP public server with wolfSSL's
|
||||
Asynchronous cryptography support.
|
||||
|
||||
**NOTE:** Before building this example the asynchronous support must be obtained from
|
||||
(https://github.com/wolfSSL/wolfAsyncCrypt) and installed into wolfSSL by following the
|
||||
instructions in the *README* file contained in the wolfAsyncCrypt repository.
|
||||
The example uses `www.digicert.com`, whose certificate still has an OCSP
|
||||
responder (many CAs, including Google, have dropped OCSP).
|
||||
|
||||
The example uses youtube.com as the public server.
|
||||
The name lookups, the TCP connects, the TLS handshake and the OCSP lookup
|
||||
inside it share one 15 second deadline (`HANDSHAKE_TIMEOUT_SEC` in the source).
|
||||
The OCSP lookup is done with wolfSSL's HTTP helpers on a non-blocking socket so
|
||||
it can be held to that deadline too. Name lookups use glibc's `getaddrinfo_a()`,
|
||||
so this client builds on Linux.
|
||||
|
||||
Example usage:
|
||||
|
||||
```sh
|
||||
$ ./configure --enable-ocsp --enable-asynccrypt --enable-sni --enable-alpn --enable-ocspstapling
|
||||
--enable-ocspstapling2 --enable-opensslextra --enable-curve25519 CFLAGS="-DWOLFSSL_NONBLOCK_OCSP"
|
||||
--enable-ocspstapling2 --enable-opensslextra \
|
||||
CFLAGS="-DWOLFSSL_NONBLOCK_OCSP -DHAVE_IO_TIMEOUT -DWOLFSSL_OCSP_SCREEN_RESPONDER"
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
|
|
@ -59,70 +86,48 @@ gcc -o ocsp_nonblock_async ocsp_nonblock_async.c -Wall -I/usr/local/include -Os
|
|||
WolfSSL AsyncCrypt Enabled
|
||||
WolfSSL AsyncCrypt with Simulation Mode
|
||||
Connecting...
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gsr1
|
||||
simulate 'want read'
|
||||
wolfSSL_connect() returned -1 (error code -408)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gsr1
|
||||
Running command:
|
||||
curl -s --data-binary '@ocsp.req' -o 'ocsp.resp' -X POST -H 'Cache-Control: no-cache' -H 'Content-Type: application/ocsp-request' 'http://ocsp.pki.goog/gsr1'
|
||||
Reading OCSP response from file...
|
||||
Read 1447 bytes.
|
||||
*response is (nil)
|
||||
Allocating 1447 bytes...
|
||||
*response is now 0x55ef7fdcb4e0
|
||||
Copying bytes...
|
||||
Bytes copied.
|
||||
verify_cb()
|
||||
preverify_ok = 1
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gtsr1
|
||||
ocsp_cb(): http://ocsp.digicert.com
|
||||
simulate 'want read'
|
||||
wolfSSL_connect() returned -1 (error code -408)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gtsr1
|
||||
Running command:
|
||||
curl -s --data-binary '@ocsp.req' -o 'ocsp.resp' -X POST -H 'Cache-Control: no-cache' -H 'Content-Type: application/ocsp-request' 'http://ocsp.pki.goog/gtsr1'
|
||||
Reading OCSP response from file...
|
||||
Read 724 bytes.
|
||||
*response is (nil)
|
||||
Allocating 724 bytes...
|
||||
*response is now 0x55ef7fdaf030
|
||||
Copying bytes...
|
||||
Bytes copied.
|
||||
ocsp_cb(): http://ocsp.digicert.com
|
||||
verify_cb()
|
||||
preverify_ok = 1
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gts1c3
|
||||
simulate 'want read'
|
||||
wolfSSL_connect() returned -1 (error code -408)
|
||||
ocsp_cb(): http://ocsp.pki.goog/gts1c3
|
||||
Running command:
|
||||
curl -s --data-binary '@ocsp.req' -o 'ocsp.resp' -X POST -H 'Cache-Control: no-cache' -H 'Content-Type: application/ocsp-request' 'http://ocsp.pki.goog/gts1c3'
|
||||
Reading OCSP response from file...
|
||||
Read 472 bytes.
|
||||
*response is (nil)
|
||||
Allocating 472 bytes...
|
||||
*response is now 0x55ef7fdac4b0
|
||||
Copying bytes...
|
||||
Bytes copied.
|
||||
verify_cb()
|
||||
preverify_ok = 1
|
||||
wolfSSL_connect() returned -1 (error code -108)
|
||||
CONNECTED
|
||||
Closing connection...
|
||||
wolfSSL_shutdown() failed with code 2 (error 0)
|
||||
CLOSED
|
||||
test_connect() failed
|
||||
CONNECT FAILED
|
||||
CONNECT PASSED
|
||||
|
||||
DONE
|
||||
```
|
||||
|
||||
The example uses `/etc/ssl/certs/ca-certificates.crt` as the system certs file by default. If your
|
||||
system doesn't have this file, just run the executable with the path to your own cert file.
|
||||
If you already have wolfSSL installed and do not want to change it, build a
|
||||
local wolfSSL copy but skip `make install`, then compile the example straight
|
||||
against that build (this leaves your existing install untouched):
|
||||
|
||||
```sh
|
||||
# In your local wolfSSL source directory, build only (no install):
|
||||
$ ./configure --enable-ocsp --enable-asynccrypt --enable-sni --enable-alpn \
|
||||
--enable-ocspstapling --enable-ocspstapling2 --enable-opensslextra \
|
||||
CFLAGS="-DWOLFSSL_NONBLOCK_OCSP -DHAVE_IO_TIMEOUT -DWOLFSSL_OCSP_SCREEN_RESPONDER"
|
||||
$ make
|
||||
|
||||
# Back in this example directory, point the compiler at that build:
|
||||
$ WOLFSSL=/path/to/wolfssl
|
||||
$ gcc -o ocsp_nonblock_async ocsp_nonblock_async.c -Wall -Os \
|
||||
-I$WOLFSSL -L$WOLFSSL/src/.libs -lwolfssl
|
||||
$ LD_LIBRARY_PATH=$WOLFSSL/src/.libs ./ocsp_nonblock_async
|
||||
```
|
||||
|
||||
By default it loads the bundled `ca_certs/DigiCert_Global_Root_G2.pem` to check
|
||||
digicert.com's certificate, so it runs on its own. digicert.com is a real server,
|
||||
so its certificate can change. If the check fails, pass another cert file, such as
|
||||
your system CA bundle:
|
||||
|
||||
```
|
||||
./ocsp_nonblock_asynccrypt ../../mycerts/ca.crt
|
||||
./ocsp_nonblock_async /etc/ssl/certs/ca-certificates.crt
|
||||
```
|
||||
|
||||
On success it prints `CONNECTED` and, at the end, `CONNECT PASSED`. The
|
||||
`verify_cb` and `ocsp_cb` lines show the certificate check and OCSP lookup
|
||||
running.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFPDCCBCSgAwIBAgIQAWePH++IIlXYsKcOa3uyIDANBgkqhkiG9w0BAQsFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||
MjAeFw0yMDA3MDIxMjQyNTBaFw0zMDA3MDIxMjQyNTBaMEQxCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEVWIFJT
|
||||
QSBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0eZsx/neTr
|
||||
f4MXJz0R2fJTIDfN8AwUAu7hy4gI0vp7O8LAAHx2h3bbf8wl+pGMSxaJK9ffDDCD
|
||||
63FqqFBqE9eTmo3RkgQhlu55a04LsXRLcK6crkBOO0djdonybmhrfGrtBqYvbRat
|
||||
xenkv0Sg4frhRl4wYh4dnW0LOVRGhbt1G5Q19zm9CqMlq7LlUdAE+6d3a5++ppfG
|
||||
cnWLmbEVEcLHPAnbl+/iKauQpQlU1Mi+wEBnjE5tK8Q778naXnF+DsedQJ7NEi+b
|
||||
QoonTHEz9ryeEcUHuQTv7nApa/zCqes5lXn1pMs4LZJ3SVgbkTLj+RbBov/uiwTX
|
||||
tkBEWawvZH8CAwEAAaOCAgswggIHMB0GA1UdDgQWBBRqTlC/mGidW3sgddRZAXlI
|
||||
ZpIyBjAfBgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8E
|
||||
BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI
|
||||
MAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
|
||||
cC5kaWdpY2VydC5jb20wewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGln
|
||||
aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA3oDWgM4YxaHR0cDov
|
||||
L2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDCBzgYD
|
||||
VR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
|
||||
aWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMg
|
||||
Q2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWlu
|
||||
ZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2Vy
|
||||
dC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQBSMgrCdY2+O9spnYNvwHiG
|
||||
+9lCJbyELR0UsoLwpzGpSdkHD7pVDDFJm3//B8Es+17T1o5Hat+HRDsvRr7d3MEy
|
||||
o9iXkkxLhKEgApA2Ft2eZfPrTolc95PwSWnn3FZ8BhdGO4brTA4+zkPSKoMXi/X+
|
||||
WLBNN29Z/nbCS7H/qLGt7gViEvTIdU8x+H4l/XigZMUDaVmJ+B5d7cwSK7yOoQdf
|
||||
oIBGmA5Mp4LhMzo52rf//kXPfE3wYIZVHqVuxxlnTkFYmffCX9/Lon7SWaGdg6Rc
|
||||
k4RHhHLWtmz2lTZ5CEo2ljDsGzCFGJP7oT4q6Q8oFC38irvdKIJ95cUxYzj4tnOI
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
|
||||
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
|
||||
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
|
||||
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
|
||||
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
|
||||
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
|
||||
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
|
||||
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
|
||||
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
|
||||
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
|
||||
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
|
||||
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
|
||||
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
|
||||
MrY=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
|
||||
MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
|
||||
kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
|
||||
lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
|
||||
BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
|
||||
gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
|
||||
tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
|
||||
DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
|
||||
VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
|
||||
CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
|
||||
AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
|
||||
MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
|
||||
A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
|
||||
aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
|
||||
AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
|
||||
cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
|
||||
RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
|
||||
+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
|
||||
PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
|
||||
lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
|
||||
Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
|
||||
z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
|
||||
AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
|
||||
juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
|
||||
1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX
|
||||
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
|
||||
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx
|
||||
OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
|
||||
GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63
|
||||
ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS
|
||||
iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k
|
||||
KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ
|
||||
DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk
|
||||
j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5
|
||||
cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW
|
||||
CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499
|
||||
iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei
|
||||
Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap
|
||||
sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b
|
||||
9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP
|
||||
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf
|
||||
BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw
|
||||
JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH
|
||||
MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al
|
||||
oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy
|
||||
MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF
|
||||
AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9
|
||||
NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9
|
||||
WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw
|
||||
9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy
|
||||
+qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi
|
||||
d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEhzCCA2+gAwIBAgIQOzdfWX2DYt0J79PlD6I4NTANBgkqhkiG9w0BAQsFADBG
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzA0MjQxMjAxMTZaFw0yMzA3MTcx
|
||||
MjAxMTVaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYI
|
||||
KoZIzj0DAQcDQgAEjjE+XIQeTp+HYC7t1oTblWTyWA3fy8AdbKLYDxYvyCBhtU3o
|
||||
hNe8xFj2yLkNzjjG5r/e+9pssNIL7///gh53JaOCAmcwggJjMA4GA1UdDwEB/wQE
|
||||
AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW
|
||||
BBRqOTqTkUjbMDNo/o2cnpSNng1IATAfBgNVHSMEGDAWgBSKdH+vhc3ulc09nNDi
|
||||
RhTzcTUdJzBqBggrBgEFBQcBAQReMFwwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3Nw
|
||||
LnBraS5nb29nL2d0czFjMzAxBggrBgEFBQcwAoYlaHR0cDovL3BraS5nb29nL3Jl
|
||||
cG8vY2VydHMvZ3RzMWMzLmRlcjAZBgNVHREEEjAQgg53d3cuZ29vZ2xlLmNvbTAh
|
||||
BgNVHSAEGjAYMAgGBmeBDAECATAMBgorBgEEAdZ5AgUDMDwGA1UdHwQ1MDMwMaAv
|
||||
oC2GK2h0dHA6Ly9jcmxzLnBraS5nb29nL2d0czFjMy9RT3ZKME4xc1QyQS5jcmww
|
||||
ggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgB6MoxU2LcttiDqOOBSHumEFnAyE4VN
|
||||
O9IrwTpXo1LrUgAAAYezWq9QAAAEAwBHMEUCID7E4i4X0sXFwbQSmgi+aDvZw5Zc
|
||||
D6hTicrkqA/3XlmrAiEA8qCimh33lfyW6879dtRbxZ2HTu7mZwD9BaitE2y9m44A
|
||||
dgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYezWq8cAAAEAwBH
|
||||
MEUCIQDt0g6qUANO5pRDTWlqVUlGvYHAavpVy1oTzaH54v2lnAIgLP5A/29sPUZX
|
||||
/7txQxZyeUgnzoXidMvpvrjMkjHqL/IwDQYJKoZIhvcNAQELBQADggEBANalC0GR
|
||||
lmC+Yt6aB1IG9WZn+i9lYmaoIhz1WbDF+GkX6WwMWCJZOd3P7Ul4of3DU8Ql1jhG
|
||||
fpPvCtXa66Iuc9Ujzhs29Mbrunq7zdYjlB+X8yacFkUHBDkvXtr7em53BfHDHnwb
|
||||
Sb5CIVm/E/HrfHeCBeK6JQJ4C8m25hUYYv5+Z2s6vDutnX+L0vwMFgE2dNX3Sh45
|
||||
rtjoG2AHUIkxR/ovAMPIy8hKuhag7yaFZO08us1cNlGXda448O3OTcVSZ+yuyHlu
|
||||
cI4gZ5/W1Kem0gx3uvjnCttxZ4hR+mknD0dS+XK4sp5LNuc8pi1K40GzL3kHVK5M
|
||||
suHVECOecBARAJ4=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -20,6 +20,15 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
**/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/wolfio.h>
|
||||
|
|
@ -27,8 +36,11 @@
|
|||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#include <wolfssl/wolfcrypt/logging.h>
|
||||
|
||||
/* Requires wolfSSL: --enable-ocsp --enable-opensslextra --enable-sni,
|
||||
* CFLAGS -DWOLFSSL_NONBLOCK_OCSP -DHAVE_IO_TIMEOUT -DKEEP_PEER_CERT. */
|
||||
static const char* kCACertsDir = "ca_certs"; /* put CA certs into this directory */
|
||||
static const char* kGoogleCom = "google.pem"; /* www.google.com */
|
||||
static const char* kServerHost = "www.digicert.com";
|
||||
static const word16 kServerPort = 443;
|
||||
|
||||
#ifndef HTTP_SCRATCH_BUFFER_SIZE
|
||||
#define HTTP_SCRATCH_BUFFER_SIZE 512
|
||||
|
|
@ -37,7 +49,7 @@ static const char* kGoogleCom = "google.pem"; /* www.google.com */
|
|||
#define MAX_URL_ITEM_SIZE 80
|
||||
#endif
|
||||
#ifndef DEFAULT_TIMEOUT_SEC
|
||||
#define DEFAULT_TIMEOUT_SEC 0 /* no timeout */
|
||||
#define DEFAULT_TIMEOUT_SEC 10 /* cert fetch / OCSP connect limit (sec) */
|
||||
#endif
|
||||
|
||||
static int io_timeout_sec = DEFAULT_TIMEOUT_SEC;
|
||||
|
|
@ -50,6 +62,120 @@ static char domainName[MAX_URL_ITEM_SIZE];
|
|||
static int nonBlockCnt = 0;
|
||||
static byte* httpBuf;
|
||||
|
||||
/* Switch fd to non-blocking so I/O on it can be driven against a deadline.
|
||||
* Returns 0 on success, -1 on error. */
|
||||
static int set_nonblocking(SOCKET_T fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
|
||||
if (flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait until fd is ready for the direction the caller needs, or until the
|
||||
* deadline passes. Returns 0 when ready, -1 on timeout or error. */
|
||||
static int wait_for_socket(SOCKET_T fd, int wantWrite, time_t deadline)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
time_t now = time(NULL);
|
||||
int ret;
|
||||
|
||||
if (now >= deadline) {
|
||||
return -1;
|
||||
}
|
||||
pfd.fd = fd;
|
||||
pfd.events = wantWrite ? POLLOUT : POLLIN;
|
||||
pfd.revents = 0;
|
||||
ret = poll(&pfd, 1, (int)(deadline - now) * 1000);
|
||||
return (ret > 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_OCSP_SCREEN_RESPONDER
|
||||
/* 1 if the IPv4 address is in a loopback, private, link-local or reserved
|
||||
* range that an OCSP responder must not live in, else 0. */
|
||||
static int ipv4_blocked(const struct in_addr* in)
|
||||
{
|
||||
const unsigned char* a = (const unsigned char*)&in->s_addr;
|
||||
|
||||
return (a[0] == 0) || /* 0.0.0.0/8 */
|
||||
(a[0] == 127) || /* loopback */
|
||||
(a[0] == 10) || /* 10/8 */
|
||||
(a[0] == 172 && (a[1] & 0xF0) == 16) || /* 172.16/12 */
|
||||
(a[0] == 192 && a[1] == 168) || /* 192.168/16 */
|
||||
(a[0] == 169 && a[1] == 254) || /* link-local */
|
||||
(a[0] == 100 && (a[1] & 0xC0) == 64) || /* 100.64/10 */
|
||||
(a[0] >= 224); /* multicast, reserved */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve host once, screen every address it returned, then connect straight
|
||||
* to an accepted address within timeoutSec. Connecting to the address rather
|
||||
* than the name again means a changing DNS answer cannot slip a blocked
|
||||
* address past the screen. Returns 0 with *fd set, -1 on failure. */
|
||||
static int connect_responder(const char* host, word16 port, int timeoutSec,
|
||||
SOCKET_T* fd)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo* res = NULL;
|
||||
struct addrinfo* ai;
|
||||
char portStr[6];
|
||||
time_t deadline = time(NULL) + timeoutSec;
|
||||
int s = -1;
|
||||
|
||||
snprintf(portStr, sizeof(portStr), "%u", (unsigned int)port);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (getaddrinfo(host, portStr, &hints, &res) != 0) {
|
||||
printf("Unable to resolve OCSP responder %s\n", host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_OCSP_SCREEN_RESPONDER
|
||||
/* Reject the responder if any of its addresses is off limits. */
|
||||
for (ai = res; ai != NULL; ai = ai->ai_next) {
|
||||
if (ipv4_blocked(&((struct sockaddr_in*)ai->ai_addr)->sin_addr)) {
|
||||
printf("OCSP responder %s not permitted\n", host);
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (ai = res; ai != NULL && s == -1; ai = ai->ai_next) {
|
||||
int err = 0;
|
||||
socklen_t errLen = sizeof(err);
|
||||
|
||||
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (s == -1) {
|
||||
continue;
|
||||
}
|
||||
if (set_nonblocking(s) == 0 &&
|
||||
(connect(s, ai->ai_addr, ai->ai_addrlen) == 0 ||
|
||||
(errno == EINPROGRESS &&
|
||||
wait_for_socket(s, 1, deadline) == 0 &&
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &errLen) == 0 &&
|
||||
err == 0))) {
|
||||
break;
|
||||
}
|
||||
close(s);
|
||||
s = -1;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
|
||||
if (s == -1) {
|
||||
printf("OCSP responder connection failed\n");
|
||||
return -1;
|
||||
}
|
||||
*fd = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return size of the OCSP response or negative for error */
|
||||
static int OcspLookupNonBlockCb(void* ctx, const char* url, int urlSz,
|
||||
byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
|
||||
|
|
@ -96,12 +222,10 @@ static int OcspLookupNonBlockCb(void* ctx, const char* url, int urlSz,
|
|||
httpBufSz = wolfIO_HttpBuildRequestOcsp(domainName, path, ocspReqSz,
|
||||
httpBuf, httpBufSz);
|
||||
|
||||
ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec);
|
||||
/* The socket comes back non-blocking, which the response read
|
||||
* below relies on to report OCSP_WANT_READ. */
|
||||
ret = connect_responder(domainName, port, io_timeout_sec, &sfd);
|
||||
if (ret == 0) {
|
||||
#if defined(WOLFSSL_NONBLOCK_OCSP) && defined(HAVE_IO_TIMEOUT)
|
||||
wolfIO_SetBlockingMode(sfd, 1); /* non-blocking */
|
||||
#endif
|
||||
|
||||
if (wolfIO_Send(sfd, (char*)httpBuf, httpBufSz, 0) !=
|
||||
httpBufSz) {
|
||||
printf("OCSP http request failed\n");
|
||||
|
|
@ -112,13 +236,13 @@ static int OcspLookupNonBlockCb(void* ctx, const char* url, int urlSz,
|
|||
}
|
||||
else {
|
||||
do {
|
||||
ret = wolfIO_HttpProcessResponseOcsp(sfd, ocspRespBuf,
|
||||
ret = wolfIO_HttpProcessResponseOcsp(sfd, ocspRespBuf,
|
||||
httpBuf, HTTP_SCRATCH_BUFFER_SIZE, NULL);
|
||||
nonBlockCnt++;
|
||||
if (ret == OCSP_WANT_READ)
|
||||
return WOLFSSL_CBIO_ERR_WANT_READ;
|
||||
} while (ret == OCSP_WANT_READ);
|
||||
printf("OCSP Response: ret %d, nonblock count %d\n",
|
||||
printf("OCSP Response: ret %d, nonblock count %d\n",
|
||||
ret, nonBlockCnt);
|
||||
}
|
||||
}
|
||||
|
|
@ -145,92 +269,257 @@ static void OcspRespFreeCb(void* ctx, byte *resp)
|
|||
(void)ctx;
|
||||
}
|
||||
|
||||
/* Duplicate an X509's DER encoding into a newly allocated buffer sized to the
|
||||
* cert. Returns it (caller XFREEs) and sets *derSz, or NULL on error. */
|
||||
static byte* dup_x509_der(WOLFSSL_X509* x509, int* derSz)
|
||||
{
|
||||
int sz = 0;
|
||||
const byte* d = wolfSSL_X509_get_der(x509, &sz);
|
||||
byte* copy;
|
||||
|
||||
if (d == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (sz <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
copy = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
XMEMCPY(copy, d, sz);
|
||||
*derSz = sz;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Drive wolfSSL_connect() on a non-blocking socket until it finishes or the
|
||||
* deadline passes. wolfIO_TcpConnect() only times out the TCP connect, and
|
||||
* per-call socket timeouts can be kept alive by a peer that trickles data, so
|
||||
* the whole handshake is held to one absolute deadline instead. Returns
|
||||
* WOLFSSL_SUCCESS, or the wolfSSL_connect() result with *timedOut set when the
|
||||
* deadline passed. */
|
||||
static int connect_with_deadline(WOLFSSL* ssl, SOCKET_T fd, int timeoutSec,
|
||||
int* timedOut)
|
||||
{
|
||||
time_t deadline = time(NULL) + timeoutSec;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
*timedOut = 0;
|
||||
for (;;) {
|
||||
ret = wolfSSL_connect(ssl);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
err = wolfSSL_get_error(ssl, ret);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
break;
|
||||
}
|
||||
if (wait_for_socket(fd, err == WOLFSSL_ERROR_WANT_WRITE, deadline)
|
||||
!= 0) {
|
||||
*timedOut = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Open a TLS connection to host:tlsPort and return the peer's leaf certificate
|
||||
* DER in a newly allocated buffer (caller XFREEs), or NULL on error. */
|
||||
static byte* fetch_leaf_der(const char* host, word16 tlsPort, const char* caDir,
|
||||
int* derSz)
|
||||
{
|
||||
WOLFSSL_CTX* ctx;
|
||||
WOLFSSL* ssl;
|
||||
WOLFSSL_X509* peer;
|
||||
SOCKET_T fd = SOCKET_INVALID;
|
||||
byte* der;
|
||||
int ret;
|
||||
int timedOut;
|
||||
|
||||
ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
|
||||
if (ctx == NULL) {
|
||||
printf("Unable to create client context\n");
|
||||
return NULL;
|
||||
}
|
||||
/* Verify the peer during this fetch so we get the genuine host cert; an
|
||||
* unverified fetch would let an attacker swap in any CA-issued cert. */
|
||||
wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||
if (wolfSSL_CTX_load_verify_locations(ctx, NULL, caDir)
|
||||
!= WOLFSSL_SUCCESS) {
|
||||
printf("Unable to load CA certs from %s\n", caDir);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wolfIO_TcpConnect(&fd, host, tlsPort, io_timeout_sec) != 0) {
|
||||
printf("TCP connect to %s failed\n", host);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
if (set_nonblocking(fd) != 0) {
|
||||
printf("Unable to make socket non-blocking\n");
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
printf("Unable to create SSL object\n");
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
wolfSSL_set_fd(ssl, fd);
|
||||
|
||||
if (wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host,
|
||||
(word16)XSTRLEN(host)) != WOLFSSL_SUCCESS) {
|
||||
printf("wolfSSL_UseSNI failed\n");
|
||||
wolfSSL_free(ssl);
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Bind the cert to the hostname; a chain check alone is not enough. */
|
||||
if (wolfSSL_check_domain_name(ssl, host) != WOLFSSL_SUCCESS) {
|
||||
printf("wolfSSL_check_domain_name failed\n");
|
||||
wolfSSL_free(ssl);
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = connect_with_deadline(ssl, fd, io_timeout_sec, &timedOut);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
if (timedOut) {
|
||||
printf("TLS connect to %s timed out after %d seconds\n", host,
|
||||
io_timeout_sec);
|
||||
}
|
||||
else {
|
||||
printf("TLS connect to %s failed (%d)\n", host,
|
||||
wolfSSL_get_error(ssl, ret));
|
||||
}
|
||||
wolfSSL_free(ssl);
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peer = wolfSSL_get_peer_certificate(ssl);
|
||||
if (peer == NULL) {
|
||||
printf("No peer certificate\n");
|
||||
wolfSSL_free(ssl);
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
der = dup_x509_der(peer, derSz);
|
||||
if (der == NULL) {
|
||||
printf("Peer certificate DER unavailable\n");
|
||||
}
|
||||
|
||||
wolfSSL_shutdown(ssl); /* clean TLS close before teardown */
|
||||
wolfSSL_FreeX509(peer);
|
||||
wolfSSL_free(ssl);
|
||||
CloseSocket(fd);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return der;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret;
|
||||
WOLFSSL_CERT_MANAGER* pCm;
|
||||
char pem[2048];
|
||||
int pemSz = 0;
|
||||
byte der[2000];
|
||||
/* Allocated by fetch_leaf_der to the exact cert size; freed below. */
|
||||
byte* der = NULL;
|
||||
int derSz = 0;
|
||||
FILE* file;
|
||||
const char* certFile = kGoogleCom;
|
||||
const char* caDir = kCACertsDir;
|
||||
|
||||
#if 0
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
|
||||
/* Optional argv[1] overrides the CA directory if the chain changes. */
|
||||
if (argc > 1) {
|
||||
certFile = argv[1];
|
||||
caDir = argv[1];
|
||||
}
|
||||
|
||||
ret = wolfSSL_Init();
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
printf("wolfSSL_Init failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Fetch the live leaf certificate so nothing static can expire. */
|
||||
der = fetch_leaf_der(kServerHost, kServerPort, caDir, &derSz);
|
||||
if (der == NULL) {
|
||||
printf("Could not fetch %s certificate\n", kServerHost);
|
||||
wolfSSL_Cleanup();
|
||||
return -1;
|
||||
}
|
||||
printf("Fetched %s certificate (%d bytes)\n", kServerHost, derSz);
|
||||
|
||||
/* Create certificate manager context */
|
||||
pCm = wolfSSL_CertManagerNew();
|
||||
if (pCm) {
|
||||
#ifdef HAVE_OCSP
|
||||
/* Enable OCSP */
|
||||
ret = wolfSSL_CertManagerEnableOCSP(pCm, 0);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Setup callbacks for OCSP */
|
||||
ret = wolfSSL_CertManagerSetOCSP_Cb(pCm,
|
||||
OcspLookupNonBlockCb,
|
||||
OcspRespFreeCb,
|
||||
NULL /* optional context */
|
||||
);
|
||||
}
|
||||
#else
|
||||
ret = WOLFSSL_SUCCESS;
|
||||
#endif
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Load root CAs into Certificate Manager */
|
||||
ret = wolfSSL_CertManagerLoadCA(pCm, NULL, kCACertsDir);
|
||||
printf("Loaded Trusted CA dir %s (ret %d)\n", kCACertsDir, ret);
|
||||
}
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Load PEM to buffer */
|
||||
file = fopen(certFile, "rb");
|
||||
if (file != NULL) {
|
||||
pemSz = fread(pem, 1, sizeof(pem), file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Convert certificate to DER/ASN.1 */
|
||||
ret = wc_CertPemToDer(
|
||||
(byte*)pem, pemSz,
|
||||
der, sizeof(der), CERT_TYPE);
|
||||
if (ret >= 0) {
|
||||
derSz = ret;
|
||||
ret = WOLFSSL_SUCCESS;
|
||||
}
|
||||
printf("Convert Google.com PEM cert to DER (ret %d)\n", ret);
|
||||
}
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Load and verify certificate */
|
||||
ret = wolfSSL_CertManagerVerifyBuffer(pCm,
|
||||
der, derSz, WOLFSSL_FILETYPE_ASN1);
|
||||
printf("Verify Google.com cert: %d\n", ret);
|
||||
}
|
||||
#ifdef HAVE_OCSP
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Check OCSP for certificate */
|
||||
do {
|
||||
ret = wolfSSL_CertManagerCheckOCSP(pCm,
|
||||
der, derSz);
|
||||
} while (ret == OCSP_WANT_READ);
|
||||
printf("Check OCSP for Google.com (ret %d)\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
wolfSSL_CertManagerFree(pCm);
|
||||
}
|
||||
else {
|
||||
ret = MEMORY_E;
|
||||
if (pCm == NULL) {
|
||||
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_Cleanup();
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
printf("Ret = %d: %s\n",
|
||||
ret, (ret == WOLFSSL_SUCCESS) ?
|
||||
"success" :
|
||||
#ifdef HAVE_OCSP
|
||||
/* Enable OCSP */
|
||||
ret = wolfSSL_CertManagerEnableOCSP(pCm, 0);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Setup callbacks for OCSP */
|
||||
ret = wolfSSL_CertManagerSetOCSP_Cb(pCm,
|
||||
OcspLookupNonBlockCb,
|
||||
OcspRespFreeCb,
|
||||
NULL /* optional context */
|
||||
);
|
||||
}
|
||||
#else
|
||||
ret = WOLFSSL_SUCCESS;
|
||||
#endif
|
||||
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Load root CAs into Certificate Manager */
|
||||
ret = wolfSSL_CertManagerLoadCA(pCm, NULL, caDir);
|
||||
printf("Loaded Trusted CA dir %s (ret %d)\n", caDir, ret);
|
||||
}
|
||||
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Verify the fetched certificate against the loaded CAs */
|
||||
ret = wolfSSL_CertManagerVerifyBuffer(pCm, der, derSz,
|
||||
WOLFSSL_FILETYPE_ASN1);
|
||||
printf("Verify %s cert: %d\n", kServerHost, ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OCSP
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
/* Check OCSP for the certificate */
|
||||
do {
|
||||
ret = wolfSSL_CertManagerCheckOCSP(pCm, der, derSz);
|
||||
} while (ret == OCSP_WANT_READ);
|
||||
printf("Check OCSP for %s (ret %d)\n", kServerHost, ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
wolfSSL_CertManagerFree(pCm);
|
||||
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
printf("Ret = %d: %s\n",
|
||||
ret, (ret == WOLFSSL_SUCCESS) ?
|
||||
"success" :
|
||||
wc_GetErrorString(ret));
|
||||
|
||||
/* Exit 0 on success so scripts and CI can tell pass from fail. */
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue