| Support for OCSP Verification in Serf |
| ===================================== |
| |
| Serf trunk currently supports OCSP stapling for verifying server |
| certificates. The purpose of this branch is to add minimal support |
| for issuing OCSP requests to responders from the client application. |
| |
| The idea is that the application decides when and where to send OCSP |
| requests and how to verify responses, and Serf provides some basic |
| utility functions for constructing the requests and parsing the |
| responses. |
| |
| These are the proposed changes: |
| |
| 1. serf_ssl_cert_certificate() |
| |
| Extract the OCSP responder locations from the certificate's x509v3 |
| extension field authorityInfoAccess:OCSP;URI and, if it is present, |
| insert the array into the returned hash table with key "OCSP". |
| |
| |
| 2. serf_ssl_cert_import() |
| |
| Add a new function that is the inverse of serf_ssl_cert_export(): |
| |
| serf_ssl_certificate_t *serf_ssl_cert_import( |
| const char *encoded_cert, |
| apr_pool_t *pool); |
| |
| Docstring: |
| |
| Imports certificate from a base64-encoded, zero-terminated |
| string. The returned certificate is allocated in @a pool. |
| Returns NULL on failure. |
| |
| Discussion: |
| |
| In order to create an OCSP request, the application needs both |
| the server certificate and its issuer certtificate. An |
| application may have to issue OCSP requests independently and |
| asynchronously of any other processing, so it's nice if it can |
| store the certificates in a form that's independent of pool |
| lifetimes. We provide this form with serf_ssl_cert_export(), but |
| there's no easy way to consume the exported form in existing Serf |
| APIs (writing it to a file in PEM format and reading it back |
| through serf_ssl_load_cert_file() is neither easy nor sane). |
| |
| |
| 3. serf_ssl_ocsp_request_create() |
| |
| Add a new function that can be used from within a request setup |
| handler to create an OCSP request: |
| |
| apr_status_t serf_ssl_ocsp_request_create( |
| const serf_ssl_certificate_t *server_cert, |
| const serf_ssl_certificate_t *issuer_cert, |
| const void **ocsp_request, |
| apr_size_t *ocsp_request_size, |
| const void **nonce, |
| apr_size_t *nonce_size, |
| apr_pool_t *pool); |
| |
| Docstring: |
| |
| Constructs an OCSP verification request for @a server_cert with |
| issuer certificate @a issuer_cert, Retyurns the DER encoded |
| request in @a ocsp_request and its size in @a ocsp_request_size. |
| |
| If @a nonce is not @c NULL, the request will contain a randomly |
| generated nonce, which will be returned in @a *nonce and its |
| size in @a nonce_size. If @a nonce is @c NULL, @a nonce_size |
| is ignored. |
| |
| The request and nonce will be allocated from @a pool. |
| |
| Discussion: |
| |
| HTTP OCSP requests can be sent using eithe the GET or POST |
| methods; see https://www.ietf.org/rfc/rfc2560.txt section A.1.1. |
| It's up to the application to decide which method to use, so we |
| don't provide a function to create the request body or set |
| request headers. |
| |
| |
| 4. serf_ssl_ocsp_response_verify() |
| |
| Add a new function that can be used from within a response handler |
| to verify an OCSP response: |
| |
| apr_status_t serf_ssl_ocsp_response_verify( |
| const void *ocsp_response, |
| apr_size_t ocsp_response_size, |
| const serf_ssl_certificate_t *server_cert, |
| const serf_ssl_certificate_t *issuer_cert, |
| const void *nonce, |
| apr_size_t nonce_size, |
| apr_time_t *this_update, |
| apr_time_t *next_update, |
| apr_time_t *produced_at, |
| apr_pool_t *pool); |
| |
| Docstring: |
| |
| Check if the given @a ocsp_response of size @a ocsp_response_size |
| is valid for the given @a server_cert, @a issuer_cert and @a nonce. |
| |
| If @a nonce is @c NULL, the response _must not_ contain a nonce. |
| Otherwise, it must contain an identical nonce with size @a nonce_size. |
| |
| The @a this_update, @a next_update and @a produced_at output arguments |
| are described in RFC 2560, section 2.4 and, when not @c NULL, will be |
| set from the parsed response. Any of these times that are not present |
| in the response will be set to the epoch, i.e., @c APR_TIME_C(0). |
| |
| Uses @a pool for temporary allocations. |
| |
| Discussion: |
| |
| Parses and verifies the OCSP response received in the HTTP response |
| body as per RFC 2560, section 3.2. |
| |
| |
| 5. New error codes and macros |
| |
| #define SERF_ERROR_SSL_OCSP_RESPONSE_CERT_REVOKED |
| #define SERF_ERROR_SSL_OCSP_RESPONSE_CERT_UNKNOWN |
| #define SERF_ERROR_SSL_OCSP_RESPONSE_INVALID |
| |
| #define SERF_OCSP_UNGOOD_ERROR(status) |
| |
| Discussion: |
| |
| These error codes are returned from serf_ssl_ocsp_response_verify(). |
| The SERF_OCSP_UNGOOD_ERROR() macro combines the _CERT_REVOKED |
| and _CERT_UNKNOWN error codes.. |