|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Author: Nikos Mavrogiannopoulos
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This file is part of GnuTLS.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
aea12f |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
aea12f |
* the License, or (at your option) any later version.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
aea12f |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
aea12f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
aea12f |
* Lesser General Public License for more details.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#include "gnutls_int.h"
|
|
Packit |
aea12f |
#include "errors.h"
|
|
Packit |
aea12f |
#include "extv.h"
|
|
Packit |
aea12f |
#include "handshake.h"
|
|
Packit |
aea12f |
#include "tls13/certificate.h"
|
|
Packit |
aea12f |
#include "auth/cert.h"
|
|
Packit |
aea12f |
#include "mbuffers.h"
|
|
Packit |
aea12f |
#include "ext/status_request.h"
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int parse_cert_extension(void *ctx, unsigned tls_id, const uint8_t *data, unsigned data_size);
|
|
Packit |
aea12f |
static int parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
int _gnutls13_recv_certificate(gnutls_session_t session)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_buffer_st buf;
|
|
Packit |
aea12f |
unsigned optional = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!session->internals.initial_negotiation_completed &&
|
|
Packit |
aea12f |
session->internals.hsk_flags & HSK_PSK_SELECTED)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_SERVER) {
|
|
Packit |
aea12f |
/* if we didn't request a certificate, there will not be any */
|
|
Packit |
aea12f |
if (session->internals.send_cert_req == 0)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
|
|
Packit |
aea12f |
optional = 1;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf;;
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET && session->internals.send_cert_req)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (buf.length == 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.initial_negotiation_completed &&
|
|
Packit |
aea12f |
session->internals.post_handshake_cr_context.size > 0) {
|
|
Packit |
aea12f |
gnutls_datum_t context;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* verify whether the context matches */
|
|
Packit |
aea12f |
ret = _gnutls_buffer_pop_datum_prefix8(&buf, &context);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (context.size != session->internals.post_handshake_cr_context.size ||
|
|
Packit |
aea12f |
memcmp(context.data, session->internals.post_handshake_cr_context.data,
|
|
Packit |
aea12f |
context.size) != 0) {
|
|
Packit |
aea12f |
ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
if (buf.data[0] != 0) {
|
|
Packit |
aea12f |
/* The context field must be empty during handshake */
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* buf.length is positive */
|
|
Packit |
aea12f |
buf.data++;
|
|
Packit |
aea12f |
buf.length--;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log("HSK[%p]: parsing certificate message\n", session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = parse_cert_list(session, buf.data, buf.length);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
|
|
Packit |
aea12f |
if (optional)
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
else if (session->security_parameters.entity ==
|
|
Packit |
aea12f |
GNUTLS_SERVER)
|
|
Packit |
aea12f |
ret = GNUTLS_E_CERTIFICATE_REQUIRED;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_buffer_clear(&buf;;
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
struct ocsp_req_ctx_st {
|
|
Packit |
aea12f |
gnutls_pcert_st *pcert;
|
|
Packit |
aea12f |
unsigned cert_index;
|
|
Packit |
aea12f |
gnutls_session_t session;
|
|
Packit |
aea12f |
gnutls_certificate_credentials_t cred;
|
|
Packit |
aea12f |
};
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static
|
|
Packit |
aea12f |
int append_status_request(void *_ctx, gnutls_buffer_st *buf)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
struct ocsp_req_ctx_st *ctx = _ctx;
|
|
Packit |
aea12f |
gnutls_session_t session = ctx->session;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t resp;
|
|
Packit |
aea12f |
unsigned free_resp = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
assert(session->internals.selected_ocsp_func != NULL ||
|
|
Packit |
aea12f |
session->internals.selected_ocsp_length != 0);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* The global ocsp callback function can only be used to return
|
|
Packit |
aea12f |
* a single certificate request */
|
|
Packit |
aea12f |
if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.selected_ocsp_length > 0) {
|
|
Packit |
aea12f |
if (ctx->cert_index < session->internals.selected_ocsp_length) {
|
|
Packit |
aea12f |
if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 &&
|
|
Packit |
aea12f |
gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) ||
|
|
Packit |
aea12f |
session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) {
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data;
|
|
Packit |
aea12f |
resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size;
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else if (session->internals.selected_ocsp_func) {
|
|
Packit |
aea12f |
if (ctx->cert_index == 0) {
|
|
Packit |
aea12f |
ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
|
|
Packit |
aea12f |
free_resp = 1;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
} else if (ret < 0) {
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data(buf, "\x01", 1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
if (free_resp)
|
|
Packit |
aea12f |
gnutls_free(resp.data);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_pcert_st *apr_cert_list = NULL;
|
|
Packit |
aea12f |
gnutls_privkey_t apr_pkey = NULL;
|
|
Packit |
aea12f |
int apr_cert_list_length = 0;
|
|
Packit |
aea12f |
mbuffer_st *bufel = NULL;
|
|
Packit |
aea12f |
gnutls_buffer_st buf;
|
|
Packit |
aea12f |
unsigned pos_mark, ext_pos_mark;
|
|
Packit |
aea12f |
unsigned i;
|
|
Packit |
aea12f |
struct ocsp_req_ctx_st ctx;
|
|
Packit |
aea12f |
gnutls_certificate_credentials_t cred;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (again == 0) {
|
|
Packit |
aea12f |
if (!session->internals.initial_negotiation_completed &&
|
|
Packit |
aea12f |
session->internals.hsk_flags & HSK_PSK_SELECTED)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_SERVER &&
|
|
Packit |
aea12f |
session->internals.resumed)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cred = (gnutls_certificate_credentials_t)
|
|
Packit |
aea12f |
_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
|
|
Packit |
aea12f |
if (cred == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_CLIENT &&
|
|
Packit |
aea12f |
!(session->internals.hsk_flags & HSK_CRT_ASKED)) {
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_get_selected_cert(session, &apr_cert_list,
|
|
Packit |
aea12f |
&apr_cert_list_length, &apr_pkey);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_buffer_init_handshake_mbuffer(&buf;;
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_CLIENT) {
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data_prefix(&buf, 8,
|
|
Packit |
aea12f |
session->internals.post_handshake_cr_context.data,
|
|
Packit |
aea12f |
session->internals.post_handshake_cr_context.size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* mark total size */
|
|
Packit |
aea12f |
pos_mark = buf.length;
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(&buf, 24, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for (i=0;i<(unsigned)apr_cert_list_length;i++) {
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data_prefix(&buf, 24,
|
|
Packit |
aea12f |
apr_cert_list[i].cert.data,
|
|
Packit |
aea12f |
apr_cert_list[i].cert.size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#ifdef ENABLE_OCSP
|
|
Packit |
aea12f |
if ((session->internals.selected_ocsp_length > 0 ||
|
|
Packit |
aea12f |
session->internals.selected_ocsp_func) &&
|
|
Packit |
aea12f |
_gnutls_hello_ext_is_present(session, GNUTLS_EXTENSION_STATUS_REQUEST)) {
|
|
Packit |
aea12f |
/* append status response if available */
|
|
Packit |
aea12f |
ret = _gnutls_extv_append_init(&buf;;
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
ext_pos_mark = ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ctx.pcert = &apr_cert_list[i];
|
|
Packit |
aea12f |
ctx.cert_index = i;
|
|
Packit |
aea12f |
ctx.session = session;
|
|
Packit |
aea12f |
ctx.cred = cred;
|
|
Packit |
aea12f |
ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
|
|
Packit |
aea12f |
&ctx, append_status_request);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_extv_append_final(&buf, ext_pos_mark, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else
|
|
Packit |
aea12f |
#endif
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_write_uint24(buf.length-pos_mark-3, &buf.data[pos_mark]);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
bufel = _gnutls_buffer_to_mbuffer(&buf;;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
_gnutls_buffer_clear(&buf;;
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
typedef struct crt_cert_ctx_st {
|
|
Packit |
aea12f |
gnutls_session_t session;
|
|
Packit |
aea12f |
gnutls_datum_t *ocsp;
|
|
Packit |
aea12f |
unsigned idx;
|
|
Packit |
aea12f |
} crt_cert_ctx_st;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int parse_cert_extension(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned data_size)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
crt_cert_ctx_st *ctx = _ctx;
|
|
Packit |
aea12f |
gnutls_session_t session = ctx->session;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (tls_id == STATUS_REQUEST_TLS_ID) {
|
|
Packit |
aea12f |
#ifdef ENABLE_OCSP
|
|
Packit |
aea12f |
if (!_gnutls_hello_ext_is_present(session, ext_mod_status_request.gid)) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto unexpected;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log("Found OCSP response on cert %d\n", ctx->idx);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_parse_ocsp_response(session, data, data_size, ctx->ocsp);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
#endif
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
goto unexpected;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
unexpected:
|
|
Packit |
aea12f |
_gnutls_debug_log("received unexpected certificate extension (%d)\n", (int)tls_id);
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size)
|
|
Packit |
aea12f |
{
|
|
Packit |
5407aa |
int ret;
|
|
Packit |
5407aa |
size_t len;
|
|
Packit |
aea12f |
uint8_t *p = data;
|
|
Packit |
aea12f |
cert_auth_info_t info;
|
|
Packit |
aea12f |
gnutls_certificate_credentials_t cred;
|
|
Packit |
5407aa |
size_t size;
|
|
Packit |
aea12f |
int i;
|
|
Packit |
aea12f |
unsigned npeer_certs, npeer_ocsp, j;
|
|
Packit |
aea12f |
crt_cert_ctx_st ctx;
|
|
Packit |
aea12f |
gnutls_datum_t *peer_certs = NULL;
|
|
Packit |
aea12f |
gnutls_datum_t *peer_ocsp = NULL;
|
|
Packit |
aea12f |
unsigned nentries = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cred = (gnutls_certificate_credentials_t)
|
|
Packit |
aea12f |
_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
|
|
Packit |
aea12f |
if (cred == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((ret =
|
|
Packit |
aea12f |
_gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
|
|
Packit |
aea12f |
sizeof(cert_auth_info_st), 1)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (data == NULL || data_size == 0) {
|
|
Packit |
aea12f |
/* no certificate was sent */
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
|
|
Packit |
aea12f |
if (info == NULL)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
DECR_LEN(data_size, 3);
|
|
Packit |
aea12f |
size = _gnutls_read_uint24(p);
|
|
Packit |
aea12f |
p += 3;
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
if (size != data_size)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (size == 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
i = data_size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
while (i > 0) {
|
|
Packit |
5407aa |
DECR_LEN(data_size, 3);
|
|
Packit |
aea12f |
len = _gnutls_read_uint24(p);
|
|
Packit |
aea12f |
if (len == 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
DECR_LEN(data_size, len);
|
|
Packit |
aea12f |
p += len + 3;
|
|
Packit |
aea12f |
i -= len + 3;
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
DECR_LEN(data_size, 2);
|
|
Packit |
aea12f |
len = _gnutls_read_uint16(p);
|
|
Packit |
5407aa |
DECR_LEN(data_size, len);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
i -= len + 2;
|
|
Packit |
aea12f |
p += len + 2;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
nentries++;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
5407aa |
if (data_size != 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* this is unnecessary - keeping to avoid a regression due to a re-org
|
|
Packit |
aea12f |
* of the loop above */
|
|
Packit |
aea12f |
if (nentries == 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
npeer_ocsp = 0;
|
|
Packit |
aea12f |
npeer_certs = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Ok we now allocate the memory to hold the
|
|
Packit |
aea12f |
* certificate list
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
peer_certs = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
|
|
Packit |
aea12f |
if (peer_certs == NULL)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
peer_ocsp = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
|
|
Packit |
aea12f |
if (peer_ocsp == NULL) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
p = data+3;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Now we start parsing the list (again).
|
|
Packit |
aea12f |
* We don't use DECR_LEN since the list has
|
|
Packit |
aea12f |
* been parsed before.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ctx.session = session;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for (j = 0; j < nentries; j++) {
|
|
Packit |
aea12f |
len = _gnutls_read_uint24(p);
|
|
Packit |
aea12f |
p += 3;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_set_datum(&peer_certs[j], p, len);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_CERTIFICATE_ERROR;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
npeer_certs++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
p += len;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
len = _gnutls_read_uint16(p);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ctx.ocsp = &peer_ocsp[j];
|
|
Packit |
aea12f |
ctx.idx = j;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_extv_parse(&ctx, parse_cert_extension, p, len+2);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
p += len+2;
|
|
Packit |
aea12f |
npeer_ocsp++;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* The OCSP entries match the certificate entries, although
|
|
Packit |
aea12f |
* the contents of each OCSP entry may be NULL.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
for(j=0;j<info->ncerts;j++)
|
|
Packit |
aea12f |
gnutls_free(info->raw_certificate_list[j].data);
|
|
Packit |
aea12f |
gnutls_free(info->raw_certificate_list);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for(j=0;j<info->nocsp;j++)
|
|
Packit |
aea12f |
gnutls_free(info->raw_ocsp_list[j].data);
|
|
Packit |
aea12f |
gnutls_free(info->raw_ocsp_list);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
info->raw_certificate_list = peer_certs;
|
|
Packit |
aea12f |
info->ncerts = npeer_certs;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
info->raw_ocsp_list = peer_ocsp;
|
|
Packit |
aea12f |
info->nocsp = npeer_ocsp;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
for(j=0;j
|
|
Packit |
aea12f |
gnutls_free(peer_certs[j].data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for(j=0;j
|
|
Packit |
aea12f |
gnutls_free(peer_ocsp[j].data);
|
|
Packit |
aea12f |
gnutls_free(peer_certs);
|
|
Packit |
aea12f |
gnutls_free(peer_ocsp);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|