From 48b95e56b86394e0a2bbd556f951e7f98e867fb3 Mon Sep 17 00:00:00 2001 From: night1rider Date: Tue, 25 Aug 2026 13:19:48 -0600 Subject: [PATCH 1/2] ocsp_nonblock: fix OCSP-URL command injection and modernize the examples Replace the system("curl ... ") OCSP fetch in the async example with wolfSSL's EmbedOcspLookup, so the certificate-supplied URL is fetched as data over a socket instead of executed. Both examples now target www.digicert.com (Google dropped OCSP): ocsp_nonblock fetches the leaf live over TLS rather than a bundled cert that expires, and the async example uses wolfSSL's native async API. Bundle the DigiCert CAs and drop the expired google.pem and stale GTS certs. --- ocsp/ocsp_nonblock/README.md | 119 ++-- .../ca_certs/DigiCert_EV_RSA_CA_G2.pem | 30 + .../ca_certs/DigiCert_Global_Root_G2.pem | 22 + ocsp/ocsp_nonblock/ca_certs/GTS_CA_1C3.pem | 32 - ocsp/ocsp_nonblock/ca_certs/GTS_Root_R1.pem | 31 - ocsp/ocsp_nonblock/google.pem | 27 - ocsp/ocsp_nonblock/ocsp_nonblock.c | 232 +++++-- ocsp/ocsp_nonblock/ocsp_nonblock_async.c | 591 +++++++++--------- 8 files changed, 569 insertions(+), 515 deletions(-) create mode 100644 ocsp/ocsp_nonblock/ca_certs/DigiCert_EV_RSA_CA_G2.pem create mode 100644 ocsp/ocsp_nonblock/ca_certs/DigiCert_Global_Root_G2.pem delete mode 100644 ocsp/ocsp_nonblock/ca_certs/GTS_CA_1C3.pem delete mode 100644 ocsp/ocsp_nonblock/ca_certs/GTS_Root_R1.pem delete mode 100644 ocsp/ocsp_nonblock/google.pem diff --git a/ocsp/ocsp_nonblock/README.md b/ocsp/ocsp_nonblock/README.md index e0a4fd0f5..3b18d3843 100644 --- a/ocsp/ocsp_nonblock/README.md +++ b/ocsp/ocsp_nonblock/README.md @@ -5,14 +5,19 @@ 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" $ make $ sudo make install @@ -20,29 +25,27 @@ $ 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 ``` ## 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 youtube.com as the public server. +The example uses `www.digicert.com`, whose certificate still has an OCSP +responder (many CAs, including Google, have dropped OCSP). Example usage: @@ -59,70 +62,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 - 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. verify_cb() preverify_ok = 1 -wolfSSL_connect() returned -1 (error code -108) -ocsp_cb(): http://ocsp.pki.goog/gts1c3 +ocsp_cb(): http://ocsp.digicert.com 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. +ocsp_cb(): http://ocsp.digicert.com 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 \ + --enable-curve25519 CFLAGS="-DWOLFSSL_NONBLOCK_OCSP" +$ 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. diff --git a/ocsp/ocsp_nonblock/ca_certs/DigiCert_EV_RSA_CA_G2.pem b/ocsp/ocsp_nonblock/ca_certs/DigiCert_EV_RSA_CA_G2.pem new file mode 100644 index 000000000..5a38769b1 --- /dev/null +++ b/ocsp/ocsp_nonblock/ca_certs/DigiCert_EV_RSA_CA_G2.pem @@ -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----- diff --git a/ocsp/ocsp_nonblock/ca_certs/DigiCert_Global_Root_G2.pem b/ocsp/ocsp_nonblock/ca_certs/DigiCert_Global_Root_G2.pem new file mode 100644 index 000000000..798e00275 --- /dev/null +++ b/ocsp/ocsp_nonblock/ca_certs/DigiCert_Global_Root_G2.pem @@ -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----- diff --git a/ocsp/ocsp_nonblock/ca_certs/GTS_CA_1C3.pem b/ocsp/ocsp_nonblock/ca_certs/GTS_CA_1C3.pem deleted file mode 100644 index 2acab7259..000000000 --- a/ocsp/ocsp_nonblock/ca_certs/GTS_CA_1C3.pem +++ /dev/null @@ -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----- \ No newline at end of file diff --git a/ocsp/ocsp_nonblock/ca_certs/GTS_Root_R1.pem b/ocsp/ocsp_nonblock/ca_certs/GTS_Root_R1.pem deleted file mode 100644 index e5aa68147..000000000 --- a/ocsp/ocsp_nonblock/ca_certs/GTS_Root_R1.pem +++ /dev/null @@ -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----- \ No newline at end of file diff --git a/ocsp/ocsp_nonblock/google.pem b/ocsp/ocsp_nonblock/google.pem deleted file mode 100644 index 8d158776c..000000000 --- a/ocsp/ocsp_nonblock/google.pem +++ /dev/null @@ -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----- diff --git a/ocsp/ocsp_nonblock/ocsp_nonblock.c b/ocsp/ocsp_nonblock/ocsp_nonblock.c index ba5c5ba22..5600e5719 100644 --- a/ocsp/ocsp_nonblock/ocsp_nonblock.c +++ b/ocsp/ocsp_nonblock/ocsp_nonblock.c @@ -28,7 +28,8 @@ #include 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 @@ -112,13 +113,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 +146,187 @@ static void OcspRespFreeCb(void* ctx, byte *resp) (void)ctx; } +/* Copy an X509's DER encoding into der. Returns 0 on success, -1 otherwise. */ +static int copy_x509_der(WOLFSSL_X509* x509, byte* der, int derCap, int* derSz) +{ + int sz = 0; + const byte* d = wolfSSL_X509_get_der(x509, &sz); + + if (d == NULL) { + return -1; + } + if (sz <= 0) { + return -1; + } + if (sz > derCap) { + return -1; + } + XMEMCPY(der, d, sz); + *derSz = sz; + return 0; +} + +/* Open a TLS connection to host:tlsPort and copy the peer's leaf certificate + * (DER) into der. Returns 0 on success, -1 on error. */ +static int fetch_leaf_der(const char* host, word16 tlsPort, byte* der, + int derCap, int* derSz) +{ + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + WOLFSSL_X509* peer; + SOCKET_T fd = SOCKET_INVALID; + int result; + int ret; + + ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + if (ctx == NULL) { + printf("Unable to create client context\n"); + return -1; + } + /* 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, kCACertsDir) + != WOLFSSL_SUCCESS) { + printf("Unable to load CA certs from %s\n", kCACertsDir); + wolfSSL_CTX_free(ctx); + return -1; + } + + if (wolfIO_TcpConnect(&fd, host, tlsPort, io_timeout_sec) != 0) { + printf("TCP connect to %s failed\n", host); + wolfSSL_CTX_free(ctx); + return -1; + } + + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + printf("Unable to create SSL object\n"); + CloseSocket(fd); + wolfSSL_CTX_free(ctx); + return -1; + } + wolfSSL_set_fd(ssl, fd); + wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host, (word16)XSTRLEN(host)); + /* Bind the cert to the hostname; a chain check alone is not enough. */ + wolfSSL_check_domain_name(ssl, host); + + ret = wolfSSL_connect(ssl); + if (ret != WOLFSSL_SUCCESS) { + printf("TLS connect to %s failed (%d)\n", host, + wolfSSL_get_error(ssl, ret)); + wolfSSL_free(ssl); + CloseSocket(fd); + wolfSSL_CTX_free(ctx); + return -1; + } + + peer = wolfSSL_get_peer_certificate(ssl); + if (peer == NULL) { + printf("No peer certificate\n"); + wolfSSL_free(ssl); + CloseSocket(fd); + wolfSSL_CTX_free(ctx); + return -1; + } + + result = copy_x509_der(peer, der, derCap, derSz); + if (result != 0) { + printf("Peer certificate DER unavailable\n"); + } + + wolfSSL_FreeX509(peer); + wolfSSL_free(ssl); + CloseSocket(fd); + wolfSSL_CTX_free(ctx); + return result; +} + int main(int argc, char** argv) { int ret; WOLFSSL_CERT_MANAGER* pCm; - char pem[2048]; - int pemSz = 0; byte der[2000]; int derSz = 0; - FILE* file; - const char* certFile = kGoogleCom; #if 0 wolfSSL_Debugging_ON(); #endif - if (argc > 1) { - certFile = argv[1]; + (void)argc; + (void)argv; + + 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. */ + ret = fetch_leaf_der(kServerHost, kServerPort, der, sizeof(der), &derSz); + if (ret != 0) { + printf("Could not fetch %s certificate\n", kServerHost); + wolfSSL_Cleanup(); + return ret; } + 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); - } + if (pCm == NULL) { + wolfSSL_Cleanup(); + return MEMORY_E; + } - /* 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 +#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 - wolfSSL_CertManagerFree(pCm); + 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); } - else { - ret = MEMORY_E; + + 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); } - printf("Ret = %d: %s\n", - ret, (ret == WOLFSSL_SUCCESS) ? - "success" : +#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); + 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; } diff --git a/ocsp/ocsp_nonblock/ocsp_nonblock_async.c b/ocsp/ocsp_nonblock/ocsp_nonblock_async.c index 2a363f4ad..7f9db0e0e 100644 --- a/ocsp/ocsp_nonblock/ocsp_nonblock_async.c +++ b/ocsp/ocsp_nonblock/ocsp_nonblock_async.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -30,10 +30,8 @@ #include #include -#include -#define SERVER_NAME "www.youtube.com" -#define SERVER_IP "172.217.18.14" +#define SERVER_NAME "www.digicert.com" #define SERVER_PORT 443 #define ALPN_PROTOS "http/1.1" @@ -42,24 +40,9 @@ && defined(WOLFSSL_NONBLOCK_OCSP) && defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ && defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) -static const char* sys_certs_file = "/etc/ssl/certs/ca-certificates.crt"; - -#if defined(WOLFSSL_ASYNC_CRYPT) -static int wait_async(WOLFSSL_CTX* ctx, WOLFSSL* ssl) -{ - WOLF_EVENT* wolfEvent; - int n = 0; - do { - if (wolfSSL_CTX_AsyncPoll(ctx, &wolfEvent, 1, WOLF_POLL_FLAG_CHECK_HW, &n) != 0) { - fprintf(stderr, "error calling wolfSSL_CTX_AsyncPoll()\n"); - return -1; - } - } while (n == 0); - assert(n == 1); - assert(ssl == (WOLFSSL*)wolfEvent->context); - return 0; -} -#endif +/* Bundled root for digicert.com so the demo runs standalone. Pass a cert + * file as argv[1] if that chain changes. */ +static const char* sys_certs_file = "ca_certs/DigiCert_Global_Root_G2.pem"; static int verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX* store) { @@ -76,199 +59,199 @@ static int verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX* store) static int ocsp_cb(void* ctx, const char* url, int urlSz, unsigned char* request, int requestSz, unsigned char** response) { - printf("ocsp_cb(): %s\n", url); + /* Return "want read" once per request, then look up on retry. A static + * flag holds the state, so no marker file is needed. */ + static int wantReadPending = 0; - if (access("ocsp.req", F_OK) == 0) { - /* file exists, delete it and return (in order to simulate that it needs read I/O) */ - if (remove("ocsp.req") != 0) { - return -1; - } + printf("ocsp_cb(): %.*s\n", urlSz, url); + + if (!wantReadPending) { + wantReadPending = 1; printf(" simulate 'want read'\n"); return WOLFSSL_CBIO_ERR_WANT_READ; - } else { - /* file doesn't exist, proceed */ } + wantReadPending = 0; - FILE *frq = fopen("ocsp.req", "wb"); - if (frq != NULL) { - size_t nbytes = fwrite(request, 1, requestSz, frq); - if (requestSz != nbytes) { - printf("Failed to write all data. Wrote only %zu bytes.\n", nbytes); - } - fclose(frq); - frq = NULL; - } else { - return -1; - } - - char cmd[1024]; - snprintf(cmd, sizeof(cmd), "curl -s --data-binary '@ocsp.req' -o 'ocsp.resp' -X POST -H 'Cache-Control: no-cache' -H 'Content-Type: application/ocsp-request' '%s'", url); - printf("Running command:\n%s\n", cmd); - int ret = system(cmd); - if (ret == 0) { - FILE *frsp = fopen("ocsp.resp", "rb"); - if (frsp != NULL) { - printf("Reading OCSP response from file...\n"); - char resp[4096]; - size_t nbytes = fread(resp, 1, sizeof(resp), frsp); - printf("Read %zu bytes.\n", nbytes); - fclose(frsp); - frsp = NULL; - - printf("*response is %p\n", *response); - printf("Allocating %zu bytes...\n", nbytes); - *response = malloc(nbytes); - if (*response == NULL) { - printf("malloc() failed\n"); - return -1; - } - printf("*response is now %p\n", *response); - printf("Copying bytes...\n"); - memcpy(*response, resp, nbytes); - printf("Bytes copied.\n"); - - return nbytes; - } - return -1; - } else { - printf("Command failed with error code '%d'.\n", ret); - } - - return -1; + /* Use wolfSSL's built-in OCSP HTTP lookup, which parses the URL and + * fetches the response over a socket. */ + return EmbedOcspLookup(ctx, url, urlSz, request, requestSz, response); } static void ocsp_free(void* ctx, unsigned char* response) { - (void)ctx; - if (response) { - free(response); - } + /* Pair with EmbedOcspLookup's allocator. */ + EmbedOcspRespFree(ctx, response); } -int test_connect(WOLFSSL_CTX* ctx) +/* Resolve SERVER_NAME, connect, and switch the socket to non-blocking. + * Returns the connected socket, or -1 on failure. */ +static int open_socket(void) { + struct addrinfo hints; + struct addrinfo* res = NULL; + struct addrinfo* ai; + char portStr[6]; + int sockfd = -1; + int flags; int ret; - int errCode; - char errBuff[WOLFSSL_MAX_ERROR_SZ]; - - int sockfd; - struct sockaddr_in servAddr; - - int result = 0; - memset(&servAddr, 0, sizeof(servAddr)); + ret = snprintf(portStr, sizeof(portStr), "%d", SERVER_PORT); + if (ret < 0) { + fprintf(stderr, "failed to format port %d\n", SERVER_PORT); + return -1; + } + if ((size_t)ret >= sizeof(portStr)) { + fprintf(stderr, "failed to format port %d\n", SERVER_PORT); + return -1; + } - servAddr.sin_family = AF_INET; - servAddr.sin_port = htons(SERVER_PORT); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; - if (inet_pton(AF_INET, SERVER_IP, &servAddr.sin_addr) != 1) { - fprintf(stderr, "invalid address\n"); - result = -1; - goto exit; + /* Resolve the server by name so it keeps working as the IP changes. */ + if (getaddrinfo(SERVER_NAME, portStr, &hints, &res) != 0) { + fprintf(stderr, "failed to resolve %s\n", SERVER_NAME); + return -1; } - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - fprintf(stderr, "failed to create socket\n"); - result = -1; - goto exit; + for (ai = res; ai != NULL; ai = ai->ai_next) { + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockfd == -1) { + continue; + } + if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 0) { + break; + } + if (close(sockfd) != 0) { + fprintf(stderr, "warning: failed to close socket\n"); + } + sockfd = -1; } + freeaddrinfo(res); - if (connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)) == -1) { - fprintf(stderr, "failed to connect socket\n"); - result = -1; - goto exit; + if (sockfd == -1) { + fprintf(stderr, "failed to connect to %s:%d\n", SERVER_NAME, + SERVER_PORT); + return -1; } - // set non-block socket - int flags = fcntl(sockfd, F_GETFL, 0); + flags = fcntl(sockfd, F_GETFL, 0); if (flags == -1) { fprintf(stderr, "fcntl(F_GETFL) failed\n"); - result = -1; - goto exit_closefd; + close(sockfd); + return -1; } if ((flags & O_NONBLOCK) == 0) { - flags |= O_NONBLOCK; - if (fcntl(sockfd, F_SETFL, flags) != 0) { + if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) != 0) { fprintf(stderr, "fcntl(F_SETFL) failed\n"); - result = -1; - goto exit_closefd; + close(sockfd); + return -1; } } - WOLFSSL *ssl = wolfSSL_new(ctx); - if (ssl == NULL) { - fprintf(stderr, "wolfSSL_new() failed\n"); - result = -1; - goto exit_closefd; - } - - wolfSSL_set_fd(ssl, sockfd); + return sockfd; +} - wolfSSL_set_using_nonblock(ssl, 1); +/* Apply the OCSP callback, TLS version policy, SNI, and ALPN. + * Returns 0 on success, -1 on failure. */ +static int configure_ssl(WOLFSSL* ssl) +{ + const long verMask = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | + SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; + long opt; + int ret; ret = wolfSSL_SetOCSP_Cb(ssl, ocsp_cb, ocsp_free, NULL); if (ret != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_SetOCSP_Cb() failed with code %d\n", ret); - result = -1; - goto exit_freessl; + return -1; } - long opt = wolfSSL_get_options(ssl); - const long ver_opt_mask = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; - opt = (opt & ~ver_opt_mask) | SSL_OP_NO_SSLv3; + opt = wolfSSL_get_options(ssl); + opt = (opt & ~verMask) | SSL_OP_NO_SSLv3; if (opt != wolfSSL_set_options(ssl, opt)) { fprintf(stderr, "Could not configure TLS versions on client stub\n"); - result = -1; - goto exit_freessl; + return -1; } - if ((ret = wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_X25519)) != SSL_SUCCESS || - (ret = wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP256R1)) != SSL_SUCCESS || - (ret = wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP384R1)) != SSL_SUCCESS || - (ret = wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP521R1)) != SSL_SUCCESS) { - fprintf(stderr, "Could not set SSL supported groups on client stub\n"); - result = -1; - goto exit_freessl; + ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, SERVER_NAME, + strlen(SERVER_NAME)); + if (ret != SSL_SUCCESS) { + fprintf(stderr, "wolfSSL_UseSNI() failed with code %d\n", ret); + return -1; } - ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, SERVER_NAME, strlen(SERVER_NAME)); + /* Match the peer certificate name against SERVER_NAME; verifying the + * chain alone would accept any cert issued under the loaded root. */ + ret = wolfSSL_check_domain_name(ssl, SERVER_NAME); if (ret != SSL_SUCCESS) { - fprintf(stderr, "wolfSSL_UseSNI() failed with code %d\n", ret); - result = -1; - goto exit_freessl; + fprintf(stderr, "wolfSSL_check_domain_name() failed with code %d\n", + ret); + return -1; } - ret = wolfSSL_UseALPN(ssl, ALPN_PROTOS, strlen(ALPN_PROTOS), WOLFSSL_ALPN_FAILED_ON_MISMATCH); + ret = wolfSSL_UseALPN(ssl, ALPN_PROTOS, strlen(ALPN_PROTOS), + WOLFSSL_ALPN_FAILED_ON_MISMATCH); if (ret != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_UseALPN() failed with code %d\n", ret); - result = -1; - goto exit_freessl; + return -1; } + return 0; +} + +/* Whether a failed wolfSSL_connect() should be retried. */ +static int is_retryable(int errCode) +{ + if (errCode == SSL_ERROR_WANT_READ) { + return 1; + } + if (errCode == OCSP_WANT_READ) { + return 1; + } + if (errCode == WC_PENDING_E) { + return 1; + } + return 0; +} + +/* Drive the non-blocking handshake to completion, then shut down. + * Returns 0 on success, -1 on failure. */ +static int do_handshake(WOLFSSL* ssl) +{ + char errBuff[WOLFSSL_MAX_ERROR_SZ]; + int ret; + int errCode; + printf("Connecting...\n"); - do { + for (;;) { ret = wolfSSL_connect(ssl); - errCode = 0; - if (ret != SSL_SUCCESS) { - errCode = wolfSSL_get_error(ssl, ret); + if (ret == SSL_SUCCESS) { + break; + } - if (errCode != WOLFSSL_ERROR_WANT_READ) { - printf("wolfSSL_connect() returned %d (error code %d)\n", ret, errCode); - } + errCode = wolfSSL_get_error(ssl, ret); + /* Only report genuine errors; the want-read/pending codes are normal + * non-blocking progress. */ + if (!is_retryable(errCode)) { + printf("wolfSSL_connect() returned %d (error code %d)\n", ret, + errCode); + } -#if defined(WOLFSSL_ASYNC_CRYPT) - if (errCode == WC_PENDING_E) { - if (wait_async(ctx, ssl) != 0) { - fprintf(stderr, "wait_async() failed\n"); - result = -1; - goto exit_freessl; - } + if (errCode == WC_PENDING_E) { + /* Native async: finish the pending crypto op, then retry. */ + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + fprintf(stderr, "wolfSSL_AsyncPoll() failed\n"); + return -1; } -#endif } - } while (ret != SSL_SUCCESS && (errCode == SSL_ERROR_WANT_READ || errCode == OCSP_WANT_READ || errCode == WC_PENDING_E)); + if (!is_retryable(errCode)) { + break; + } + } if (ret != SSL_SUCCESS) { errCode = wolfSSL_get_error(ssl, ret); @@ -277,197 +260,229 @@ int test_connect(WOLFSSL_CTX* ctx) wolfSSL_ERR_error_string((unsigned long) errCode, errBuff)); if (errCode == FATAL_ERROR) { WOLFSSL_ALERT_HISTORY hist; + const char* alertType; wolfSSL_get_alert_history(ssl, &hist); - int last_alert_code = hist.last_rx.code; - const char* last_alert_type = wolfSSL_alert_type_string_long(last_alert_code); - fprintf(stderr, "Last alert received: %d - %s\n", last_alert_code, last_alert_type); + alertType = wolfSSL_alert_type_string_long(hist.last_rx.code); + fprintf(stderr, "Last alert received: %d - %s\n", + hist.last_rx.code, alertType); } - result = -1; - goto exit_freessl; + return -1; } printf("CONNECTED\n"); - if (wolfSSL_get_error(ssl, ret) != SOCKET_PEER_CLOSED_E) { - printf(" Closing connection...\n"); - ret = wolfSSL_shutdown(ssl); - if (ret == SSL_SHUTDOWN_NOT_DONE) { - ret = wolfSSL_shutdown(ssl); - } - if (ret != SSL_SUCCESS) { - fprintf(stderr, "wolfSSL_shutdown() failed with code %d (error %d)\n", ret, wolfSSL_get_error(ssl, ret)); - result = -1; - goto exit_freessl; - } + if (wolfSSL_get_error(ssl, ret) == SOCKET_PEER_CLOSED_E) { + return 0; } -exit_freessl: - wolfSSL_free(ssl); - -exit_closefd: - close(sockfd); - printf(" CLOSED\n"); - -exit: - return result; -} -#endif - -int main(int argc, char** argv) -{ - #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SNI) && defined(HAVE_ALPN) \ - && defined(WOLFSSL_NONBLOCK_OCSP) && defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - && defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) - - int err; - int result = 0; - WC_RNG rng; - int asyncCryptDevId = INVALID_DEVID; - pthread_t current_thread; - WOLFSSL_METHOD *method = NULL; - WOLFSSL_CTX *ctx = NULL; - - /* Check presence of sys_certs_file */ - if (access (sys_certs_file, F_OK) == -1 && argc == 1) { - fprintf(stderr, "Default system cert file /etc/ssl/certs/ca-certificates.crt doesn't exist." - " Please provide cert file path as show below.\n"); - fprintf(stderr, "./ocsp_nonblock_asynccrypt ../../mycerts/ca.crt\n"); - return -1; + printf(" Closing connection...\n"); + ret = wolfSSL_shutdown(ssl); + if (ret == WOLFSSL_SUCCESS) { + return 0; } - /* Handle user provided certs file */ - else if (argc == 2) { - if (access (argv[1], F_OK) == -1) { - fprintf(stderr, "Provided cert file %s doesn't exist." - " Please provide a valid path.\n", argv[1]); - return -1; - } - else { - sys_certs_file = argv[1]; - } + /* Our close_notify was sent; on a non-blocking socket the peer's reply may + * still be in flight, which is fine for this demo. */ + if (ret == WOLFSSL_SHUTDOWN_NOT_DONE) { + return 0; } - - wolfSSL_Debugging_ON(); - - err = wolfSSL_Init(); - if (err != SSL_SUCCESS) { - fprintf(stderr, "wolfSSL_Init() failed with code %d\n", err); - return -1; + errCode = wolfSSL_get_error(ssl, ret); + if (errCode == WOLFSSL_ERROR_WANT_READ) { + return 0; } - - wolfSSL_load_error_strings(); - -#if defined(WOLFSSL_ASYNC_CRYPT) - wolfAsync_HardwareStart(); - printf("WolfSSL AsyncCrypt Enabled\n"); -#if defined(HAVE_INTEL_QA) - printf("WolfSSL AsyncCrypt with IntelQA Mode\n"); -#elif defined(WOLFSSL_ASYNC_CRYPT_SW) - printf("WolfSSL AsyncCrypt with Simulation Mode\n"); -#else - #error Unknown HW Acceleration device -#endif - - current_thread = pthread_self(); - if (wolfAsync_DevOpenThread(&asyncCryptDevId, ¤t_thread) < 0) { - fprintf(stderr, "Could not initialize AsyncCrypt device\n"); - return -1; + if (errCode == WOLFSSL_ERROR_WANT_WRITE) { + return 0; } + fprintf(stderr, "wolfSSL_shutdown() failed with code %d (error %d)\n", + ret, errCode); + return -1; +} -#endif - - err = wc_InitRng(&rng); - if (err != 0) { - fprintf(stderr, "wc_InitRng() failed with code %d\n", err); - result = -1; - goto exit; - } +/* Create and configure the client CTX (verify, OCSP stapling, CA, async). + * Returns the CTX, or NULL on failure. */ +static WOLFSSL_CTX* create_ctx(int devId) +{ + WOLFSSL_METHOD* method; + WOLFSSL_CTX* ctx; + int err; method = wolfSSLv23_client_method(); if (method == NULL) { fprintf(stderr, "failed to get client method\n"); - result = -1; - goto exit; + return NULL; } ctx = wolfSSL_CTX_new(method); if (ctx == NULL) { fprintf(stderr, "failed to create context object\n"); - result = -1; - goto exit; + return NULL; } wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); - err = wolfSSL_CTX_UseOCSPStapling(ctx, WOLFSSL_CSR_OCSP, WOLFSSL_CSR_OCSP_USE_NONCE); + err = wolfSSL_CTX_UseOCSPStapling(ctx, WOLFSSL_CSR_OCSP, + WOLFSSL_CSR_OCSP_USE_NONCE); if (err != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_CTX_UseOCSPStapling() returned %d\n", err); - result = -1; - goto exit; + wolfSSL_CTX_free(ctx); + return NULL; } - err = wolfSSL_CTX_UseOCSPStaplingV2(ctx, WOLFSSL_CSR2_OCSP_MULTI, WOLFSSL_CSR2_OCSP_USE_NONCE); + err = wolfSSL_CTX_UseOCSPStaplingV2(ctx, WOLFSSL_CSR2_OCSP_MULTI, + WOLFSSL_CSR2_OCSP_USE_NONCE); if (err != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_CTX_UseOCSPStaplingV2() returned %d\n", err); - result = -1; - goto exit; + wolfSSL_CTX_free(ctx); + return NULL; } - err = wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_CHECKALL | WOLFSSL_OCSP_NO_NONCE); + err = wolfSSL_CTX_EnableOCSP(ctx, + WOLFSSL_OCSP_CHECKALL | WOLFSSL_OCSP_NO_NONCE); if (err != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_CTX_EnableOCSP() returned %d\n", err); - result = -1; - goto exit; + wolfSSL_CTX_free(ctx); + return NULL; } err = wolfSSL_CTX_UnloadCAs(ctx); if (err != SSL_SUCCESS) { fprintf(stderr, "wolfSSL_CTX_UnloadCAs() returned %d\n", err); - result = -1; - goto exit; + wolfSSL_CTX_free(ctx); + return NULL; } err = wolfSSL_CTX_load_verify_locations(ctx, sys_certs_file, NULL); if (err != SSL_SUCCESS) { - fprintf(stderr, "wolfSSL_CTX_load_verify_locations() returned %d\n", err); - result = -1; - goto exit; + fprintf(stderr, "wolfSSL_CTX_load_verify_locations() returned %d\n", + err); + wolfSSL_CTX_free(ctx); + return NULL; } -#if defined(WOLFSSL_ASYNC_CRYPT) - if (wolfSSL_CTX_UseAsync(ctx, asyncCryptDevId) != SSL_SUCCESS ) { - fprintf(stderr, "Could not enable AsyncCrypt device on TLS context\n"); - result = -1; - goto exit; + if (wolfSSL_CTX_SetDevId(ctx, devId) != SSL_SUCCESS) { + fprintf(stderr, "Could not set AsyncCrypt device on TLS context\n"); + wolfSSL_CTX_free(ctx); + return NULL; } -#endif - err = test_connect(ctx); - if (err != 0) { - fprintf(stderr, "test_connect() failed\n"); - fprintf(stderr, "CONNECT FAILED\n"); + return ctx; +} + +int test_connect(WOLFSSL_CTX* ctx) +{ + WOLFSSL* ssl; + int sockfd; + int result; + + sockfd = open_socket(); + if (sockfd == -1) { + return -1; } - else { - fprintf(stderr, "CONNECT PASSED\n"); + + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + fprintf(stderr, "wolfSSL_new() failed\n"); + close(sockfd); + printf(" CLOSED\n"); + return -1; + } + + wolfSSL_set_fd(ssl, sockfd); + wolfSSL_set_using_nonblock(ssl, 1); + + result = configure_ssl(ssl); + if (result == 0) { + result = do_handshake(ssl); } - wolfSSL_CTX_free(ctx); - ctx = NULL; + wolfSSL_free(ssl); + close(sockfd); + printf(" CLOSED\n"); -exit: + return result; +} +#endif - printf("\nDONE\n\n"); +int main(int argc, char** argv) +{ + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SNI) && defined(HAVE_ALPN) \ + && defined(WOLFSSL_NONBLOCK_OCSP) && defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + && defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + int result = 0; + WC_RNG rng; + int asyncCryptDevId = INVALID_DEVID; + WOLFSSL_CTX* ctx; + + /* Use a caller-supplied cert file, else the bundled default. */ + if (argc == 2) { + if (access(argv[1], F_OK) == -1) { + fprintf(stderr, "Provided cert file %s doesn't exist." + " Please provide a valid path.\n", argv[1]); + return -1; + } + sys_certs_file = argv[1]; + } + else if (access(sys_certs_file, F_OK) == -1) { + fprintf(stderr, "Default cert file %s doesn't exist." + " Please provide a cert file path as shown below.\n", + sys_certs_file); + fprintf(stderr, + "./ocsp_nonblock_async /etc/ssl/certs/ca-certificates.crt\n"); + return -1; + } - wc_FreeRng(&rng); + wolfSSL_Debugging_ON(); -#if defined(WOLFSSL_ASYNC_CRYPT) - if (asyncCryptDevId != INVALID_DEVID) { - wolfAsync_DevClose(&asyncCryptDevId); + if (wolfSSL_Init() != SSL_SUCCESS) { + fprintf(stderr, "wolfSSL_Init() failed\n"); + return -1; } - wolfAsync_HardwareStop(); + wolfSSL_load_error_strings(); + + printf("WolfSSL AsyncCrypt Enabled\n"); +#if defined(HAVE_INTEL_QA) + printf("WolfSSL AsyncCrypt with IntelQA Mode\n"); +#elif defined(WOLFSSL_ASYNC_CRYPT_SW) + printf("WolfSSL AsyncCrypt with Simulation Mode\n"); +#else + #error Unknown HW Acceleration device #endif + if (wolfAsync_DevOpen(&asyncCryptDevId) < 0) { + fprintf(stderr, "Could not open AsyncCrypt device\n"); + wolfSSL_Cleanup(); + return -1; + } + + if (wc_InitRng(&rng) != 0) { + fprintf(stderr, "wc_InitRng() failed\n"); + result = -1; + } + else { + ctx = create_ctx(asyncCryptDevId); + if (ctx == NULL) { + result = -1; + } + else { + if (test_connect(ctx) != 0) { + fprintf(stderr, "test_connect() failed\n"); + fprintf(stderr, "CONNECT FAILED\n"); + result = -1; + } + else { + fprintf(stderr, "CONNECT PASSED\n"); + } + wolfSSL_CTX_free(ctx); + } + wc_FreeRng(&rng); + } + + printf("\nDONE\n\n"); + + if (asyncCryptDevId != INVALID_DEVID) { + wolfAsync_DevClose(&asyncCryptDevId); + } wolfSSL_Cleanup(); return result; @@ -475,7 +490,7 @@ int main(int argc, char** argv) (void)argc; (void)argv; - printf("Please compile wolfSSL with ./configure --enable-asynccrypt --enable-sni" + printf("Please compile wolfSSL with ./configure --enable-asynccrypt --enable-sni" " --enable-alpn --enable-ocspstapling --enable-ocspstapling2 --enable-opensslextra" " --enable-curve25519 CFLAGS=-DWOLFSSL_NONBLOCK_OCSP"); return -1; From 25ff2ff3b9fd669171f7ba4f0521b00f01efb983 Mon Sep 17 00:00:00 2001 From: night1rider Date: Wed, 26 Aug 2026 21:55:42 -0600 Subject: [PATCH 2/2] CI: build ocsp_nonblock with its own profile The rewritten clients need asynccrypt/opensslextra/sni/alpn and WOLFSSL_NONBLOCK_OCSP, which the shared ocsp profile lacks; add a dedicated ocsp-nonblock profile. --- .github/examples-manifest.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/examples-manifest.yml b/.github/examples-manifest.yml index 1f0950d82..93eff27da 100644 --- a/.github/examples-manifest.yml +++ b/.github/examples-manifest.yml @@ -204,6 +204,16 @@ 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; the async one adds + # asynccrypt, alpn and stapling. + flags: >- + --enable-ocsp --enable-ocspstapling --enable-ocspstapling2 + --enable-asynccrypt --enable-opensslextra --enable-sni --enable-alpn + --enable-curve25519 --enable-tls13 --enable-static --enable-shared + cflags: "-DWOLFSSL_NONBLOCK_OCSP -DHAVE_IO_TIMEOUT" + pkcs11: flags: "--enable-pkcs11 --enable-cryptocb --enable-static --enable-shared" @@ -635,9 +645,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