|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2012-2017 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Simon Josefsson, Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Status Request (OCSP) API.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "errors.h"
|
|
Packit Service |
4684c1 |
#include <auth.h>
|
|
Packit Service |
4684c1 |
#include <auth/cert.h>
|
|
Packit Service |
4684c1 |
#include <handshake.h>
|
|
Packit Service |
4684c1 |
#include <minmax.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <gnutls/ocsp.h>
|
|
Packit Service |
4684c1 |
#include "x509/ocsp.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_ocsp_status_request_get:
|
|
Packit Service |
4684c1 |
* @session: is a #gnutls_session_t type.
|
|
Packit Service |
4684c1 |
* @response: a #gnutls_datum_t with DER encoded OCSP response
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function returns the OCSP status response received
|
|
Packit Service |
4684c1 |
* from the TLS server. The @response should be treated as
|
|
Packit Service |
4684c1 |
* constant. If no OCSP response is available then
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.1.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_ocsp_status_request_get(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
gnutls_datum_t * response)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
return gnutls_ocsp_status_request_get2(session, 0, response);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_ocsp_status_request_get2:
|
|
Packit Service |
4684c1 |
* @session: is a #gnutls_session_t type.
|
|
Packit Service |
4684c1 |
* @idx: the index of peer's certificate
|
|
Packit Service |
4684c1 |
* @response: a #gnutls_datum_t with DER encoded OCSP response
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function returns the OCSP status response received
|
|
Packit Service |
4684c1 |
* from the TLS server for the certificate index provided.
|
|
Packit Service |
4684c1 |
* The index corresponds to certificates as returned by
|
|
Packit Service |
4684c1 |
* gnutls_certificate_get_peers. When index is zero this
|
|
Packit Service |
4684c1 |
* function operates identically to gnutls_ocsp_status_request_get().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The returned @response should be treated as
|
|
Packit Service |
4684c1 |
* constant. If no OCSP response is available for the
|
|
Packit Service |
4684c1 |
* given index then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
|
|
Packit Service |
4684c1 |
* is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.6.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_ocsp_status_request_get2(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
unsigned idx,
|
|
Packit Service |
4684c1 |
gnutls_datum_t * response)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const version_entry_st *ver = get_version(session);
|
|
Packit Service |
4684c1 |
cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!ver->tls13_sem && session->security_parameters.entity == GNUTLS_SERVER)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (info == NULL || info->raw_ocsp_list == NULL ||
|
|
Packit Service |
4684c1 |
info->nocsp <= idx || info->raw_ocsp_list[idx].size == 0)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
response->data = info->raw_ocsp_list[idx].data;
|
|
Packit Service |
4684c1 |
response->size = info->raw_ocsp_list[idx].size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_set_ocsp_status_request_function:
|
|
Packit Service |
4684c1 |
* @sc: is a #gnutls_certificate_credentials_t type.
|
|
Packit Service |
4684c1 |
* @ocsp_func: function pointer to OCSP status request callback.
|
|
Packit Service |
4684c1 |
* @ptr: opaque pointer passed to callback function
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function is to be used by server to register a callback to
|
|
Packit Service |
4684c1 |
* handle OCSP status requests from the client. The callback will be
|
|
Packit Service |
4684c1 |
* invoked if the client supplied a status-request OCSP extension.
|
|
Packit Service |
4684c1 |
* The callback function prototype is:
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* typedef int (*gnutls_status_request_ocsp_func)
|
|
Packit Service |
4684c1 |
* (gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response);
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The callback will be invoked if the client requests an OCSP certificate
|
|
Packit Service |
4684c1 |
* status. The callback may return %GNUTLS_E_NO_CERTIFICATE_STATUS, if
|
|
Packit Service |
4684c1 |
* there is no recent OCSP response. If the callback returns %GNUTLS_E_SUCCESS,
|
|
Packit Service |
4684c1 |
* it is expected to have the @ocsp_response field set with a valid (DER-encoded)
|
|
Packit Service |
4684c1 |
* OCSP response. The response must be a value allocated using gnutls_malloc(),
|
|
Packit Service |
4684c1 |
* and will be deinitialized by the caller.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* It is possible to set a specific callback for each provided certificate
|
|
Packit Service |
4684c1 |
* using gnutls_certificate_set_ocsp_status_request_function2().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.1.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
void
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_ocsp_status_request_function
|
|
Packit Service |
4684c1 |
(gnutls_certificate_credentials_t sc,
|
|
Packit Service |
4684c1 |
gnutls_status_request_ocsp_func ocsp_func, void *ptr)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sc->glob_ocsp_func = ocsp_func;
|
|
Packit Service |
4684c1 |
sc->glob_ocsp_func_ptr = ptr;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_set_ocsp_status_request_function2:
|
|
Packit Service |
4684c1 |
* @sc: is a #gnutls_certificate_credentials_t type.
|
|
Packit Service |
4684c1 |
* @idx: is a certificate index as returned by gnutls_certificate_set_key() and friends
|
|
Packit Service |
4684c1 |
* @ocsp_func: function pointer to OCSP status request callback.
|
|
Packit Service |
4684c1 |
* @ptr: opaque pointer passed to callback function
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function is to be used by server to register a callback to
|
|
Packit Service |
4684c1 |
* provide OCSP status requests that correspond to the indexed certificate chain
|
|
Packit Service |
4684c1 |
* from the client. The callback will be invoked if the client supplied a
|
|
Packit Service |
4684c1 |
* status-request OCSP extension.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The callback function prototype is:
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* typedef int (*gnutls_status_request_ocsp_func)
|
|
Packit Service |
4684c1 |
* (gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response);
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The callback will be invoked if the client requests an OCSP certificate
|
|
Packit Service |
4684c1 |
* status. The callback may return %GNUTLS_E_NO_CERTIFICATE_STATUS, if
|
|
Packit Service |
4684c1 |
* there is no recent OCSP response. If the callback returns %GNUTLS_E_SUCCESS,
|
|
Packit Service |
4684c1 |
* it is expected to have the @ocsp_response field set with a valid (DER-encoded)
|
|
Packit Service |
4684c1 |
* OCSP response. The response must be a value allocated using gnutls_malloc(),
|
|
Packit Service |
4684c1 |
* and will be deinitialized by the caller.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Note: the ability to set multiple OCSP responses per credential
|
|
Packit Service |
4684c1 |
* structure via the index @idx was added in version 3.5.6. To keep
|
|
Packit Service |
4684c1 |
* backwards compatibility, it requires using gnutls_certificate_set_flags()
|
|
Packit Service |
4684c1 |
* with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate
|
|
Packit Service |
4684c1 |
* functions return an index usable by this function.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.5.5
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_ocsp_status_request_function2
|
|
Packit Service |
4684c1 |
(gnutls_certificate_credentials_t sc, unsigned idx, gnutls_status_request_ocsp_func ocsp_func, void *ptr)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (idx >= sc->ncerts)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_func = ocsp_func;
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_func_ptr = ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
unsigned resp_matches_pcert(gnutls_ocsp_resp_t resp, const gnutls_pcert_st *cert)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t crt;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned retval;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_init(&crt;;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_import(crt, &cert->cert, GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
retval = 0;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_check_crt(resp, 0, crt);
|
|
Packit Service |
4684c1 |
if (ret == 0)
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
retval = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(crt);
|
|
Packit Service |
4684c1 |
return retval;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_set_ocsp_status_request_file:
|
|
Packit Service |
4684c1 |
* @sc: is a credentials structure.
|
|
Packit Service |
4684c1 |
* @response_file: a filename of the OCSP response
|
|
Packit Service |
4684c1 |
* @idx: is a certificate index as returned by gnutls_certificate_set_key() and friends
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function loads the provided OCSP response. It will be
|
|
Packit Service |
4684c1 |
* sent to the client if requests an OCSP certificate status for
|
|
Packit Service |
4684c1 |
* the certificate chain specified by @idx.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Note: the ability to set multiple OCSP responses per credential
|
|
Packit Service |
4684c1 |
* structure via the index @idx was added in version 3.5.6. To keep
|
|
Packit Service |
4684c1 |
* backwards compatibility, it requires using gnutls_certificate_set_flags()
|
|
Packit Service |
4684c1 |
* with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate
|
|
Packit Service |
4684c1 |
* functions return an index usable by this function.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function can be called multiple times since GnuTLS 3.6.3
|
|
Packit Service |
4684c1 |
* when multiple responses which apply to the chain are available.
|
|
Packit Service |
4684c1 |
* If the response provided does not match any certificates present
|
|
Packit Service |
4684c1 |
* in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
|
|
Packit Service |
4684c1 |
* To revert to the previous behavior set the flag %GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK
|
|
Packit Service |
4684c1 |
* in the certificate credentials structure. In that case, only the
|
|
Packit Service |
4684c1 |
* end-certificate's OCSP response can be set.
|
|
Packit Service |
4684c1 |
* If the response is already expired at the time of loading the code
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_EXPIRED is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* To revert to the previous behavior of this function which does not return
|
|
Packit Service |
4684c1 |
* any errors, set the flag %GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.1.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_ocsp_status_request_file(gnutls_certificate_credentials_t sc,
|
|
Packit Service |
4684c1 |
const char *response_file,
|
|
Packit Service |
4684c1 |
unsigned idx)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_ocsp_status_request_file2(sc, response_file,
|
|
Packit Service |
4684c1 |
idx, GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret >= 0)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int append_response(gnutls_certificate_credentials_t sc, unsigned idx,
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_t resp, const gnutls_datum_t *der)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned i, found = 0;
|
|
Packit Service |
4684c1 |
unsigned try_already_set = 0;
|
|
Packit Service |
4684c1 |
time_t t;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
retry:
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* iterate through all certificates in chain, and add the response
|
|
Packit Service |
4684c1 |
* to the certificate that it matches with.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
for (i=0;i<MIN(sc->certs[idx].cert_list_length, MAX_OCSP_RESPONSES);i++) {
|
|
Packit Service |
4684c1 |
if (!try_already_set && sc->certs[idx].ocsp_data[i].response.data)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!resp_matches_pcert(resp, &sc->certs[idx].cert_list[i]))
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
t = _gnutls_ocsp_get_validity(resp);
|
|
Packit Service |
4684c1 |
/* if already invalid */
|
|
Packit Service |
4684c1 |
if (t == (time_t)-1) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("the OCSP response associated with chain %d on pos %d, is invalid/expired\n", idx, i);
|
|
Packit Service |
4684c1 |
return GNUTLS_E_EXPIRED;
|
|
Packit Service |
4684c1 |
} else if (t == (time_t)-2) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("the OCSP response associated with chain %d on pos %d, is too old (ignoring)\n", idx, i);
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (t >= 0)
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[i].exptime = t;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[i].exptime = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("associating OCSP response with chain %d on pos %d\n", idx, i);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(sc->certs[idx].ocsp_data[i].response.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_set_datum(&sc->certs[idx].ocsp_data[i].response,
|
|
Packit Service |
4684c1 |
der->data,
|
|
Packit Service |
4684c1 |
der->size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[i].response.data = NULL;
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[i].response.size = 0;
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sc->certs[idx].ocsp_data_length <= i)
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data_length = i+1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
found = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!found) {
|
|
Packit Service |
4684c1 |
/* slow path; if we found no matching certificate for the OCSP
|
|
Packit Service |
4684c1 |
* response, try all the existing, even if a response is already
|
|
Packit Service |
4684c1 |
* given. */
|
|
Packit Service |
4684c1 |
if (!try_already_set) {
|
|
Packit Service |
4684c1 |
try_already_set = 1;
|
|
Packit Service |
4684c1 |
goto retry;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_OCSP_MISMATCH_WITH_CERTS;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_set_ocsp_status_request_file2:
|
|
Packit Service |
4684c1 |
* @sc: is a credentials structure.
|
|
Packit Service |
4684c1 |
* @response_file: a filename of the OCSP response
|
|
Packit Service |
4684c1 |
* @idx: is a certificate index as returned by gnutls_certificate_set_key() and friends
|
|
Packit Service |
4684c1 |
* @fmt: is PEM or DER
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function loads the OCSP responses to be sent to the
|
|
Packit Service |
4684c1 |
* peer for the certificate chain specified by @idx. When @fmt is
|
|
Packit Service |
4684c1 |
* set to PEM, multiple responses can be loaded.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function must be called after setting any certificates, and
|
|
Packit Service |
4684c1 |
* cannot be used for certificates that are provided via a callback --
|
|
Packit Service |
4684c1 |
* that is when gnutls_certificate_set_retrieve_function() is used. In
|
|
Packit Service |
4684c1 |
* that case consider using gnutls_certificate_set_retrieve_function3().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function can be called multiple times when multiple responses
|
|
Packit Service |
4684c1 |
* applicable to the certificate chain are available.
|
|
Packit Service |
4684c1 |
* If the response provided does not match any certificates present
|
|
Packit Service |
4684c1 |
* in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
|
|
Packit Service |
4684c1 |
* If the response is already expired at the time of loading the code
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_EXPIRED is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, the number of loaded responses is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.1.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_ocsp_status_request_file2(gnutls_certificate_credentials_t sc,
|
|
Packit Service |
4684c1 |
const char *response_file,
|
|
Packit Service |
4684c1 |
unsigned idx,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_fmt_t fmt)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t raw = {NULL, 0};
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (idx >= sc->ncerts)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_load_file(response_file, &raw;;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_ocsp_status_request_mem(sc, &raw, idx, fmt);
|
|
Packit Service |
4684c1 |
gnutls_free(raw.data);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define PEM_OCSP_RESPONSE "OCSP RESPONSE"
|
|
Packit Service |
4684c1 |
#define FULL_PEM_OCSP_RESPONSE "-----BEGIN OCSP RESPONSE"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_set_ocsp_status_request_mem:
|
|
Packit Service |
4684c1 |
* @sc: is a credentials structure.
|
|
Packit Service |
4684c1 |
* @resp_data: a memory buffer holding an OCSP response
|
|
Packit Service |
4684c1 |
* @idx: is a certificate index as returned by gnutls_certificate_set_key() and friends
|
|
Packit Service |
4684c1 |
* @fmt: is PEM or DER
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function sets the OCSP responses to be sent to the
|
|
Packit Service |
4684c1 |
* peer for the certificate chain specified by @idx. When @fmt is set
|
|
Packit Service |
4684c1 |
* to PEM, multiple responses can be loaded.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Note: the ability to set multiple OCSP responses per credential
|
|
Packit Service |
4684c1 |
* structure via the index @idx was added in version 3.5.6. To keep
|
|
Packit Service |
4684c1 |
* backwards compatibility, it requires using gnutls_certificate_set_flags()
|
|
Packit Service |
4684c1 |
* with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate
|
|
Packit Service |
4684c1 |
* functions return an index usable by this function.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function must be called after setting any certificates, and
|
|
Packit Service |
4684c1 |
* cannot be used for certificates that are provided via a callback --
|
|
Packit Service |
4684c1 |
* that is when gnutls_certificate_set_retrieve_function() is used.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function can be called multiple times when multiple responses which
|
|
Packit Service |
4684c1 |
* apply to the certificate chain are available.
|
|
Packit Service |
4684c1 |
* If the response provided does not match any certificates present
|
|
Packit Service |
4684c1 |
* in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
|
|
Packit Service |
4684c1 |
* If the response is already expired at the time of loading the code
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_EXPIRED is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, the number of loaded responses is returned,
|
|
Packit Service |
4684c1 |
* otherwise a negative error code.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.6.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_ocsp_status_request_mem(gnutls_certificate_credentials_t sc,
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *resp_data,
|
|
Packit Service |
4684c1 |
unsigned idx,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_fmt_t fmt)
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t der = {NULL, 0};
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_t resp = NULL;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned int nresp = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_init(&resp);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (fmt == GNUTLS_X509_FMT_PEM) {
|
|
Packit Service |
4684c1 |
/* load multiple responses */
|
|
Packit Service |
4684c1 |
gnutls_datum_t p = {resp_data->data, resp_data->size};
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
p.data = memmem(p.data, p.size, FULL_PEM_OCSP_RESPONSE,
|
|
Packit Service |
4684c1 |
sizeof(FULL_PEM_OCSP_RESPONSE)-1);
|
|
Packit Service |
4684c1 |
if (p.data == NULL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
p.size -= p.data - resp_data->data;
|
|
Packit Service |
4684c1 |
if (p.size <= 0) {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_pem_base64_decode2(PEM_OCSP_RESPONSE, &p, &der;;
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_ocsp_status_request_mem(sc, &der, idx,
|
|
Packit Service |
4684c1 |
GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
nresp++;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(der.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
p.data++;
|
|
Packit Service |
4684c1 |
p.size--;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
p.data = memmem(p.data, p.size, FULL_PEM_OCSP_RESPONSE,
|
|
Packit Service |
4684c1 |
sizeof(FULL_PEM_OCSP_RESPONSE)-1);
|
|
Packit Service |
4684c1 |
if (p.data == NULL)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
p.size = resp_data->size - (p.data - resp_data->data);
|
|
Packit Service |
4684c1 |
} while(p.size > 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = nresp;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* DER: load a single response */
|
|
Packit Service |
4684c1 |
if (sc->flags & GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK) {
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_import2(resp, resp_data, GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret >= 0) {
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[0].exptime = _gnutls_ocsp_get_validity(resp);
|
|
Packit Service |
4684c1 |
if (sc->certs[idx].ocsp_data[0].exptime <= 0)
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data[0].exptime = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* quick load of first response */
|
|
Packit Service |
4684c1 |
gnutls_free(sc->certs[idx].ocsp_data[0].response.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_set_datum(&sc->certs[idx].ocsp_data[0].response,
|
|
Packit Service |
4684c1 |
resp_data->data,
|
|
Packit Service |
4684c1 |
resp_data->size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sc->certs[idx].ocsp_data_length = 1;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_import2(resp, resp_data, GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = append_response(sc, idx, resp, resp_data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
gnutls_free(der.data);
|
|
Packit Service |
4684c1 |
if (resp)
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_deinit(resp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_certificate_get_ocsp_expiration:
|
|
Packit Service |
4684c1 |
* @sc: is a credentials structure.
|
|
Packit Service |
4684c1 |
* @idx: is a certificate chain index as returned by gnutls_certificate_set_key() and friends
|
|
Packit Service |
4684c1 |
* @oidx: is an OCSP response index
|
|
Packit Service |
4684c1 |
* @flags: should be zero
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function returns the validity of the loaded OCSP responses,
|
|
Packit Service |
4684c1 |
* to provide information on when to reload/refresh them.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Note that the credentials structure should be read-only when in
|
|
Packit Service |
4684c1 |
* use, thus when reloading, either the credentials structure must not
|
|
Packit Service |
4684c1 |
* be in use by any sessions, or a new credentials structure should be
|
|
Packit Service |
4684c1 |
* allocated for new sessions.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* When @oidx is (-1) then the minimum refresh time for all responses
|
|
Packit Service |
4684c1 |
* is returned. Otherwise the index specifies the response corresponding
|
|
Packit Service |
4684c1 |
* to the @odix certificate in the certificate chain.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, the expiration time of the OCSP response. Otherwise
|
|
Packit Service |
4684c1 |
* (time_t)(-1) on error, or (time_t)-2 on out of bounds.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.6.3
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
time_t
|
|
Packit Service |
4684c1 |
gnutls_certificate_get_ocsp_expiration(gnutls_certificate_credentials_t sc,
|
|
Packit Service |
4684c1 |
unsigned idx,
|
|
Packit Service |
4684c1 |
int oidx,
|
|
Packit Service |
4684c1 |
unsigned flags)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned j;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (idx >= sc->ncerts)
|
|
Packit Service |
4684c1 |
return (time_t)-2;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (oidx == -1) {
|
|
Packit Service |
4684c1 |
time_t min = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (j=0;j<MIN(sc->certs[idx].cert_list_length, MAX_OCSP_RESPONSES);j++) {
|
|
Packit Service |
4684c1 |
if (min <= 0)
|
|
Packit Service |
4684c1 |
min = sc->certs[idx].ocsp_data[j].exptime;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
if (sc->certs[idx].ocsp_data[j].exptime > 0 &&
|
|
Packit Service |
4684c1 |
min >= sc->certs[idx].ocsp_data[j].exptime)
|
|
Packit Service |
4684c1 |
min = sc->certs[idx].ocsp_data[j].exptime;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return min;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (oidx >= MAX_OCSP_RESPONSES || (unsigned)oidx >= sc->certs[idx].cert_list_length)
|
|
Packit Service |
4684c1 |
return (time_t)-2;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sc->certs[idx].ocsp_data[oidx].response.data == NULL)
|
|
Packit Service |
4684c1 |
return (time_t)-1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return sc->certs[idx].ocsp_data[oidx].exptime;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_ocsp_status_request_is_checked:
|
|
Packit Service |
4684c1 |
* @session: is a gnutls session
|
|
Packit Service |
4684c1 |
* @flags: should be zero or %GNUTLS_OCSP_SR_IS_AVAIL
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* When flags are zero this function returns non-zero if a valid OCSP status
|
|
Packit Service |
4684c1 |
* response was included in the TLS handshake. That is, an OCSP status response
|
|
Packit Service |
4684c1 |
* which is not too old, superseded or marks the certificate as revoked.
|
|
Packit Service |
4684c1 |
* It returns zero otherwise.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* When the flag %GNUTLS_OCSP_SR_IS_AVAIL is specified, the function
|
|
Packit Service |
4684c1 |
* returns non-zero if an OCSP status response was included in the handshake
|
|
Packit Service |
4684c1 |
* even if it was invalid. Otherwise, if no OCSP status response was included,
|
|
Packit Service |
4684c1 |
* it returns zero. The %GNUTLS_OCSP_SR_IS_AVAIL flag was introduced in GnuTLS 3.4.0.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This is a helper function when needing to decide whether to perform an
|
|
Packit Service |
4684c1 |
* explicit OCSP validity check on the peer's certificate. Should be called after
|
|
Packit Service |
4684c1 |
* any of gnutls_certificate_verify_peers*() are called.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function is always usable on client side, but on server side only
|
|
Packit Service |
4684c1 |
* under TLS 1.3, which is the first version of TLS that allows cliend-side OCSP
|
|
Packit Service |
4684c1 |
* responses.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Non-zero if the response was valid, or a zero if it wasn't sent,
|
|
Packit Service |
4684c1 |
* or sent and was invalid.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.1.4
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
unsigned
|
|
Packit Service |
4684c1 |
gnutls_ocsp_status_request_is_checked(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
unsigned int flags)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum_t data;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (flags & GNUTLS_OCSP_SR_IS_AVAIL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_status_request_get(session, &data);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (data.data == NULL)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(0);
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return session->internals.ocsp_check_ok;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#endif
|