Add libtls functionality for OCSP, and OCSP stapling support - take 2
On Tue, Jul 05, 2016 at 09:11:37PM -0600, Bob Beck wrote: > Ok, so this work was done by Marko Kreen, all as the result of a very long > discussion in: > > https://github.com/libressl-portable/openbsd/pull/47 > > In a nutshell, I threw down a glove that libtls could have functions to > support OCSP, and > make it where a client could write ocsp stuff, but I would resist making > libtls be > and http library that does that for you. I challenged him to add the > necessary support > functions so it was possible to write a client. > > He delivered, and I've cleaned a few things up in it. (after a long delay > which > I apologize for) > > Attached to this message is marko's test program, which uses libcurl - The > diff is > for our libtls, and I've been able to compile and use his test program with > it: Ok, here's a revised diff for this to handle the recent libtls changes. Included in this diff (but would be committed separately) are modifications to nc so that nc will show both the OCSP URL in a connected certificate, and the OCSP stapling informaiton if it is there in a similar manner to marko kreen's test program: # nc -c -v www.openbsd.org 443 Connection to www.openbsd.org 443 port [tcp/https] succeeded! TLS handshake negotiated TLSv1.2/ECDHE-RSA-CHACHA20-POLY1305 with host www.openbsd.org Peer name: www.openbsd.org Subject: /CN=www.openbsd.org Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 Valid From: Sat Aug 6 16:41:00 2016 Valid Until: Fri Nov 4 16:41:00 2016 Cert Hash: SHA256:76a8ebf241afca46ebb3a88a2f28d0d3b31650b479a27eeae0a67eb53195437c OCSP URL: http://ocsp.int-x3.letsencrypt.org/ OCSP Stapling: no-ocsp # nc -c -v cloudflare.com 443 Connection to cloudflare.com 443 port [tcp/https] succeeded! TLS handshake negotiated TLSv1.2/ECDHE-ECDSA-AES128-GCM-SHA256 with host cloudflare.com Peer name: cloudflare.com Subject: /serialNumber=4710875/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/C=US/postalCode=94107/ST=California/L=San Francisco/street=655 Third Street, Suite 200/O=CloudFlare, Inc./OU=COMODO EV Multi-Domain SSL Issuer: /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Extended Validation Secure Server CA Valid From: Mon Nov 30 17:00:00 2015 Valid Until: Wed Nov 30 16:59:59 2016 Cert Hash: SHA256:e5554e6a21828b6f17546c2b77227f37003c7a092693beb394beeff80a735880 OCSP URL: http://ocsp.comodoca.com OCSP Stapling: good req_status=0 cert_status=0 crl_reason=0 this update Sun Aug 21 23:34:02 2016 next update Thu Aug 25 23:34:02 2016 revocation N/A marko's test program is in the attachment (It uses libcurl to retrieve the OCSP info from the URL - nc does not do this). Looking to get this in and polish in tree. I'll add man pages once I get feedback on the API. Index: lib/libtls/Makefile === RCS file: /cvs/src/lib/libtls/Makefile,v retrieving revision 1.23 diff -u -p -u -p -r1.23 Makefile --- lib/libtls/Makefile 30 Mar 2016 06:38:43 - 1.23 +++ lib/libtls/Makefile 23 Aug 2016 02:06:17 - @@ -19,6 +19,7 @@ SRCS= tls.c \ tls_peer.c \ tls_server.c \ tls_util.c \ + tls_ocsp.c \ tls_verify.c MAN= tls_init.3 Index: lib/libtls/tls.h === RCS file: /cvs/src/lib/libtls/tls.h,v retrieving revision 1.35 diff -u -p -u -p -r1.35 tls.h --- lib/libtls/tls.h22 Aug 2016 14:58:26 - 1.35 +++ lib/libtls/tls.h23 Aug 2016 02:41:30 - @@ -40,6 +40,29 @@ extern "C" { #define TLS_WANT_POLLIN-2 #define TLS_WANT_POLLOUT -3 +#define TLS_NO_OCSP-4 + +#define TLS_OCSP_RESPONSE_SUCCESSFUL 0 +#define TLS_OCSP_RESPONSE_MALFORMED1 +#define TLS_OCSP_RESPONSE_INTERNALERR 2 +#define TLS_OCSP_RESPONSE_TRYLATER 3 +#define TLS_OCSP_RESPONSE_SIGREQUIRED 5 +#define TLS_OCSP_RESPONSE_UNAUTHORIZED 6 + +#define TLS_OCSP_CERT_GOOD 0 +#define TLS_OCSP_CERT_REVOKED 1 +#define TLS_OCSP_CERT_UNKNOWN 2 + +#define TLS_CRL_REASON_UNPSECIFIED 0 +#define TLS_CRL_REASON_KEY_COMPROMISE 1 +#define TLS_CRL_REASON_CA_COMPROMISE 2 +#define TLS_CRL_REASON_AFFILIATION_CHANGED 3 +#define TLS_CRL_REASON_SUPERSEDED 4 +#define TLS_CRL_REASON_CESSATION_OF_OPERATION 5 +#define TLS_CRL_REASON_CERTIFICATE_HOLD6 +#define TLS_CRL_REASON_REMOVE_FROM_CRL 8 +#define TLS_CRL_REASON_PRIVILEGE_WITH_DRAWN9 +#define TLS_CRL_REASON_AA_COMPROMISE 10 struct tls; struct tls_config; @@ -76,6 +99,8 @@ int tls_config_set_keypair_file(struct t const char *_cert_file, const char *_key_file); int tls_config_set_keypair_mem(struct tls_config *_config, const uint8_t *_cert,
Re: Add libtls functionality for OCSP, and OCSP stapling support
On Fri, Jul 08, 2016 at 07:20:32PM -0600, Bob Beck wrote: > One thing I am considering here (and for y'all to know, this is a > major API addition and won't > go in until after the soon upcoming openbsd release cycle happens). is > that the way > we have done this in the past with libtls is to just - do the thing in > the handshake and keep > the data hidden in the (private) conn_info stucture and then > accessible to the user via a > tls_ funciton call. > > What strikes me as the most sensible thing to do for staping is to > just do it in the handshake, > and then record the status is the conn_info.. So if stapling is > provided the handshake succeeds > if the stapled response checks out, fails if it does not with a > reason, and if it is not present or > the certifiacat status is indeterminate we then have any designated > ocsp responders from the > certificate available to the application to then go make their own > ocsp calls directly. That is what the patch is about - after handshake client can call tls_get_ocsp_info() to see if OCSP stapling was in use. The responder request stuff is mainly necessary for server to update it's stapled response. But it's also possible to check peer cert via OCSP as it's basically same code. -- marko
Re: Add libtls functionality for OCSP, and OCSP stapling support
One thing I am considering here (and for y'all to know, this is a major API addition and won't go in until after the soon upcoming openbsd release cycle happens). is that the way we have done this in the past with libtls is to just - do the thing in the handshake and keep the data hidden in the (private) conn_info stucture and then accessible to the user via a tls_ funciton call. What strikes me as the most sensible thing to do for staping is to just do it in the handshake, and then record the status is the conn_info.. So if stapling is provided the handshake succeeds if the stapled response checks out, fails if it does not with a reason, and if it is not present or the certifiacat status is indeterminate we then have any designated ocsp responders from the certificate available to the application to then go make their own ocsp calls directly. On Fri, Jul 8, 2016 at 2:40 PM, Marko Kreenwrote: > On Wed, Jul 06, 2016 at 08:30:23PM +0900, kinichiro inoguchi wrote: >> Hi, I have 2 questions about this implementation. >> >> 1) Can the OCSP client put multiple certificates to check in the request ? >>like this. >> >> $ openssl ocsp -reqin ocsp_req.der -req_text >> OCSP Request Data: >> Version: 1 (0x0) >> Requestor List: >> Certificate ID: >> Hash Algorithm: sha1 >> Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A >> Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 >> Serial Number: 03 >> Certificate ID: >> Hash Algorithm: sha1 >> Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A >> Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 >> Serial Number: D0F00ED53778C7C5 >> Request Extensions: >> OCSP Nonce: >> 04104C65A6FA1D4839916C3B8C18A4EF2E5D >> > > No. Current goal is to get stapling working, which deals with > one cert at a time. > > Requesting multiple certs with one request seems dubious even > in general (rfc6961) case as each cert may potentially have > different responder. The API needs to export multiple > (ocsp_url, request_blob) pairs then. But there is option > to embed multiple certs into one request_blob if they > use same responder, as optimization. > >> 2) Is it available signing to OCSP request by client ? >>I indicate this https://tools.ietf.org/html/rfc6960#section-4.1.2 >>"The requestor MAY choose to sign the OCSP request." >> >> These 2 functionality might NOT need when we're doing OCSP stapling. >> (server cert to verify by OCSP stapling will be always single ...) > > No. It's possible to expose it as option, but why? > > Btw, I tried to use OCSP_request_add1_nonce() to add unique nonce to > reqests, for replay protection. Common OCSP responders reject such > requests. I guess both on performace and security grounds, > to have dumb responders that do not have access to signing keys. > > So I doubt requiring signed requests is common. > > -- > marko >
Re: Add libtls functionality for OCSP, and OCSP stapling support
On Wed, Jul 06, 2016 at 08:30:23PM +0900, kinichiro inoguchi wrote: > Hi, I have 2 questions about this implementation. > > 1) Can the OCSP client put multiple certificates to check in the request ? >like this. > > $ openssl ocsp -reqin ocsp_req.der -req_text > OCSP Request Data: > Version: 1 (0x0) > Requestor List: > Certificate ID: > Hash Algorithm: sha1 > Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A > Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 > Serial Number: 03 > Certificate ID: > Hash Algorithm: sha1 > Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A > Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 > Serial Number: D0F00ED53778C7C5 > Request Extensions: > OCSP Nonce: > 04104C65A6FA1D4839916C3B8C18A4EF2E5D > No. Current goal is to get stapling working, which deals with one cert at a time. Requesting multiple certs with one request seems dubious even in general (rfc6961) case as each cert may potentially have different responder. The API needs to export multiple (ocsp_url, request_blob) pairs then. But there is option to embed multiple certs into one request_blob if they use same responder, as optimization. > 2) Is it available signing to OCSP request by client ? >I indicate this https://tools.ietf.org/html/rfc6960#section-4.1.2 >"The requestor MAY choose to sign the OCSP request." > > These 2 functionality might NOT need when we're doing OCSP stapling. > (server cert to verify by OCSP stapling will be always single ...) No. It's possible to expose it as option, but why? Btw, I tried to use OCSP_request_add1_nonce() to add unique nonce to reqests, for replay protection. Common OCSP responders reject such requests. I guess both on performace and security grounds, to have dumb responders that do not have access to signing keys. So I doubt requiring signed requests is common. -- marko
Re: Add libtls functionality for OCSP, and OCSP stapling support
Hi, I have 2 questions about this implementation. 1) Can the OCSP client put multiple certificates to check in the request ? like this. $ openssl ocsp -reqin ocsp_req.der -req_text OCSP Request Data: Version: 1 (0x0) Requestor List: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 Serial Number: 03 Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 3429CF3BC59A76F61C3296E597B1F9D5F4A52B3A Issuer Key Hash: 68DBFBB578936A6704433C981F7ECE61819838C7 Serial Number: D0F00ED53778C7C5 Request Extensions: OCSP Nonce: 04104C65A6FA1D4839916C3B8C18A4EF2E5D 2) Is it available signing to OCSP request by client ? I indicate this https://tools.ietf.org/html/rfc6960#section-4.1.2 "The requestor MAY choose to sign the OCSP request." These 2 functionality might NOT need when we're doing OCSP stapling. (server cert to verify by OCSP stapling will be always single ...) Best regards, Kinichiro Inoguchi
Add libtls functionality for OCSP, and OCSP stapling support
Ok, so this work was done by Marko Kreen, all as the result of a very long discussion in: https://github.com/libressl-portable/openbsd/pull/47 In a nutshell, I threw down a glove that libtls could have functions to support OCSP, and make it where a client could write ocsp stuff, but I would resist making libtls be and http library that does that for you. I challenged him to add the necessary support functions so it was possible to write a client. He delivered, and I've cleaned a few things up in it. (after a long delay which I apologize for) Attached to this message is marko's test program, which uses libcurl - The diff is for our libtls, and I've been able to compile and use his test program with it: $ ./oc amazon.com libssl: LibreSSL 2.4.1 OCSP stapling: good req_status=0 cert_status=0 crl_reason=0 this update: Mon Jul 4 08:17:21 2016 next update: Mon Jul 11 08:17:21 2016 revocation: -- OCSP URL: http://ss.symcd.com OCSP responder: good req_status=0 cert_status=0 crl_reason=0 this update: Mon Jul 4 08:17:21 2016 next update: Mon Jul 11 08:17:21 2016 revocation: -- $ ./oc google.com libssl: LibreSSL 2.4.1 OCSP stapling: no-ocsp OCSP URL: http://clients1.google.com/ocsp OCSP responder: good req_status=0 cert_status=0 crl_reason=0 this update: Tue Jul 5 13:00:28 2016 next update: Tue Jul 12 13:00:28 2016 revocation: -- $ Discussion, OK's diff --git lib/libtls/Makefile lib/libtls/Makefile index ca2f00b..461bf44 100644 --- lib/libtls/Makefile +++ lib/libtls/Makefile @@ -19,6 +19,7 @@ SRCS= tls.c \ tls_peer.c \ tls_server.c \ tls_util.c \ + tls_ocsp.c \ tls_verify.c MAN= tls_init.3 diff --git lib/libtls/tls.c lib/libtls/tls.c index 76d00e5..b00bea8 100644 --- lib/libtls/tls.c +++ lib/libtls/tls.c @@ -393,6 +393,13 @@ tls_reset(struct tls *ctx) tls_free_conninfo(ctx->conninfo); free(ctx->conninfo); ctx->conninfo = NULL; + + tls_ocsp_info_free(ctx->ocsp_info); + ctx->ocsp_info = NULL; + ctx->ocsp_result = NULL; + + if (ctx->flags & TLS_OCSP_CLIENT) + tls_ocsp_client_free(ctx); } int diff --git lib/libtls/tls.h lib/libtls/tls.h index 75c46c1..da6cd69 100644 --- lib/libtls/tls.h +++ lib/libtls/tls.h @@ -40,6 +40,29 @@ extern "C" { #define TLS_WANT_POLLIN-2 #define TLS_WANT_POLLOUT -3 +#define TLS_NO_OCSP-4 + +#define TLS_OCSP_RESPONSE_SUCCESSFUL 0 +#define TLS_OCSP_RESPONSE_MALFORMED1 +#define TLS_OCSP_RESPONSE_INTERNALERR 2 +#define TLS_OCSP_RESPONSE_TRYLATER 3 +#define TLS_OCSP_RESPONSE_SIGREQUIRED 5 +#define TLS_OCSP_RESPONSE_UNAUTHORIZED 6 + +#define TLS_OCSP_CERT_GOOD 0 +#define TLS_OCSP_CERT_REVOKED 1 +#define TLS_OCSP_CERT_UNKNOWN 2 + +#define TLS_CRL_REASON_UNPSECIFIED 0 +#define TLS_CRL_REASON_KEY_COMPROMISE 1 +#define TLS_CRL_REASON_CA_COMPROMISE 2 +#define TLS_CRL_REASON_AFFILIATION_CHANGED 3 +#define TLS_CRL_REASON_SUPERSEDED 4 +#define TLS_CRL_REASON_CESSATION_OF_OPERATION 5 +#define TLS_CRL_REASON_CERTIFICATE_HOLD6 +#define TLS_CRL_REASON_REMOVE_FROM_CRL 8 +#define TLS_CRL_REASON_PRIVILEGE_WITH_DRAWN9 +#define TLS_CRL_REASON_AA_COMPROMISE 10 struct tls; struct tls_config; @@ -70,6 +93,8 @@ int tls_config_set_keypair_file(struct tls_config *_config, const char *_cert_file, const char *_key_file); int tls_config_set_keypair_mem(struct tls_config *_config, const uint8_t *_cert, size_t _cert_len, const uint8_t *_key, size_t _key_len); +int tls_config_set_ocsp_stapling_file(struct tls_config *_config, const char *_blob_file); +int tls_config_set_ocsp_stapling_mem(struct tls_config *_config, const uint8_t *_blob, size_t _len); void tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); void tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); @@ -121,6 +146,18 @@ const char *tls_conn_cipher(struct tls *_ctx); uint8_t *tls_load_file(const char *_file, size_t *_len, char *_password); +int tls_get_ocsp_info(struct tls *ctx, int *response_status, int *cert_status, int *crl_reason, + time_t *this_update, time_t *next_update, time_t *revoction_time, + const char **result_text); + +int tls_ocsp_check_peer_request(struct tls **ocsp_ctx_p, struct tls *target, + char **ocsp_url, void **request_blob, size_t *request_size); + +int tls_ocsp_refresh_stapling_request(struct tls **ocsp_ctx_p, struct tls_config *config, + char **ocsp_url, void **request_blob, size_t *request_size); + +int tls_ocsp_process_response(struct tls *ctx, const void *response_blob, size_t size); + #ifdef __cplusplus } #endif diff --git lib/libtls/tls_client.c lib/libtls/tls_client.c index 3847f4c..86dd9a8