Currently the OCSP_basic_verify() function fails with many apparently valid OCSP responses (e.g. all those sent by Cloudflare servers). Other libraries (GnuTLS, NSS) have no problem with them.
Essentially, in crypto/ocsp/ocsp_vfy.c in the OCSP_basic_verify() function, the X509_STORE_CTX_init() function is called like this: init_res = X509_STORE_CTX_init(&ctx, st, signer, bs->certs); where ctx is the X509_STORE_CTX to be initialized, st is the trust store passed by the user, signer is the signer of the OCSP response (which is what needs to be validated), and bs is the decoded OCSP basic response. The problem is the last argument. OpenSSL uses the cert list embedded in the OCSP response to build the trust chain, but it seems that in some cases this list is somewhat broken. Other libraries (e.g. GnuTLS), do the verification differently, without including those bs->certs that OpenSSL uses. I attached the patch and a simple test case. You can compile it with: $ cc ocsp_test.c -lcrypto -lssl To test the problem run: $ ./a.out digitalocean.com 443 OCSP response verification failed after the patch: $ ./a.out digitalocean.com 443 OK Cheers
>From 38ce9b993e9ffc76416ccdc26dee53b24b2cd33c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <alessan...@ghedini.me> Date: Tue, 20 Jan 2015 12:27:00 +0100 Subject: [PATCH] Don't use the cert list embedded in the OCSP response to build the trust chain Instead use the certificate stack passed by the user. This is required in some cases where the embedded chain is somewhat broken and causes the OCSP verification to fail, e.g. all DigiCert/Cloudflare sites. --- crypto/ocsp/ocsp_vfy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c index fc0d4cc..846971e 100644 --- a/crypto/ocsp/ocsp_vfy.c +++ b/crypto/ocsp/ocsp_vfy.c @@ -108,7 +108,7 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, if(flags & OCSP_NOCHAIN) init_res = X509_STORE_CTX_init(&ctx, st, signer, NULL); else - init_res = X509_STORE_CTX_init(&ctx, st, signer, bs->certs); + init_res = X509_STORE_CTX_init(&ctx, st, signer, certs); if(!init_res) { ret = -1; -- 2.1.4
#include <stdio.h> #include <netdb.h> #include <openssl/ssl.h> #include <openssl/ocsp.h> int main(int argc, char *argv[]) { int sd; SSL *ssl; BIO *sbio; SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs"); sd = tcp_connect(argv[1], argv[2]); ssl = SSL_new(ctx); SSL_set_fd(ssl, (int) sd); SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); if (SSL_connect(ssl) <= 0) { puts("SSL connect error"); exit(-1); } if (SSL_get_verify_result(ssl) != X509_V_OK) { puts("Certificate doesn't verify"); exit(-1); } /* ==== VERIFY OCSP RESPONSE ==== */ int i, ocsp_status; const unsigned char *p; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; long len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); if (!p) { puts("No OCSP response received"); exit(-1); } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (!rsp) { puts("Invalid OCSP response"); exit(-1); } ocsp_status = OCSP_response_status(rsp); if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { printf("Invalid OCSP response status: %s (%d)", OCSP_response_status_str(ocsp_status), ocsp_status); exit(-1); } br = OCSP_response_get1_basic(rsp); if (!br) { puts("Invalid OCSP response"); exit(-1); } ch = SSL_get_peer_cert_chain(ssl); st = SSL_CTX_get_cert_store(ctx); if (OCSP_basic_verify(br, ch, st, 0) <= 0) { puts("OCSP response verification failed"); exit(-1); } puts("OK"); return 0; } int tcp_connect(char *host, char *port) { int err, sd; struct addrinfo hints, *res, *r; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, port, &hints, &res); if (err != 0) { perror("getaddrinfo()"); exit(-1); } for (r = res; r != NULL; r = r->ai_next) { sd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if (sd == -1) continue; if (connect(sd, r->ai_addr, r->ai_addrlen) == 0) break; close(sd); } freeaddrinfo(res); return sd; }
_______________________________________________ openssl-dev mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev