Blame lib/tls13/certificate_verify.c

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 "handshake.h"
Packit aea12f
#include "auth/cert.h"
Packit aea12f
#include "ext/signature.h"
Packit aea12f
#include "algorithms.h"
Packit aea12f
#include "tls13-sig.h"
Packit aea12f
#include "mbuffers.h"
Packit aea12f
#include "tls13/certificate_verify.h"
Packit aea12f
Packit aea12f
#define SRV_CTX "TLS 1.3, server CertificateVerify"
Packit aea12f
static const gnutls_datum_t srv_ctx = {
Packit aea12f
	(void*)SRV_CTX, sizeof(SRV_CTX)-1
Packit aea12f
};
Packit aea12f
Packit aea12f
#define CLI_CTX "TLS 1.3, client CertificateVerify"
Packit aea12f
static const gnutls_datum_t cli_ctx = {
Packit aea12f
	(void*)CLI_CTX, sizeof(CLI_CTX)-1
Packit aea12f
};
Packit aea12f
Packit aea12f
int _gnutls13_recv_certificate_verify(gnutls_session_t session)
Packit aea12f
{
Packit aea12f
	int ret;
Packit aea12f
	gnutls_buffer_st buf;
Packit aea12f
	const gnutls_sign_entry_st *se;
Packit aea12f
	gnutls_datum_t sig_data;
Packit aea12f
	gnutls_certificate_credentials_t cred;
Packit aea12f
	unsigned vflags;
Packit aea12f
	gnutls_pcert_st peer_cert;
Packit aea12f
	cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
Packit aea12f
	bool server = 0;
Packit aea12f
	gnutls_certificate_type_t cert_type;
Packit aea12f
Packit aea12f
	memset(&peer_cert, 0, sizeof(peer_cert));
Packit aea12f
Packit aea12f
	/* this message is only expected if we have received
Packit aea12f
	 * a certificate message */
Packit aea12f
	if (!(session->internals.hsk_flags & HSK_CRT_VRFY_EXPECTED))
Packit aea12f
		return 0;
Packit aea12f
Packit aea12f
	if (session->security_parameters.entity == GNUTLS_SERVER)
Packit aea12f
		server = 1;
Packit aea12f
Packit aea12f
	cred = (gnutls_certificate_credentials_t)
Packit aea12f
		_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit aea12f
	if (unlikely(cred == NULL))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit aea12f
	if (unlikely(info == NULL))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit aea12f
Packit aea12f
	ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, 0, &buf;;
Packit aea12f
	if (ret < 0)
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
	_gnutls_handshake_log("HSK[%p]: Parsing certificate verify\n", session);
Packit aea12f
Packit aea12f
	if (buf.length < 2) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	se = _gnutls_tls_aid_to_sign_entry(buf.data[0], buf.data[1], get_version(session));
Packit aea12f
	if (se == NULL) {
Packit aea12f
		_gnutls_handshake_log("Found unsupported signature (%d.%d)\n", (int)buf.data[0], (int)buf.data[1]);
Packit Service 991b93
		ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (server)
Packit aea12f
		gnutls_sign_algorithm_set_client(session, se->id);
Packit aea12f
	else
Packit aea12f
		gnutls_sign_algorithm_set_server(session, se->id);
Packit aea12f
Packit aea12f
	buf.data+=2;
Packit aea12f
	buf.length-=2;
Packit aea12f
Packit aea12f
	/* we check during verification whether the algorithm is enabled */
Packit aea12f
Packit aea12f
	ret = _gnutls_buffer_pop_datum_prefix16(&buf, &sig_data);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (sig_data.size == 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	/* We verify the certificate of the peer. Therefore we need to
Packit aea12f
	 * retrieve the negotiated certificate type for the peer. */
Packit aea12f
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_PEERS);
Packit aea12f
Packit aea12f
	/* Verify the signature */
Packit aea12f
	ret = _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	vflags = cred->verify_flags | session->internals.additional_verify_flags;
Packit aea12f
Packit aea12f
	ret = _gnutls13_handshake_verify_data(session, vflags, &peer_cert,
Packit aea12f
					      server?(&cli_ctx):(&srv_ctx),
Packit aea12f
					      &sig_data, se);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (buf.length > 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
Packit aea12f
		goto cleanup;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	ret = 0;
Packit aea12f
 cleanup:
Packit aea12f
	gnutls_pcert_deinit(&peer_cert);
Packit aea12f
	_gnutls_buffer_clear(&buf;;
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again)
Packit aea12f
{
Packit aea12f
	int ret;
Packit aea12f
	gnutls_pcert_st *apr_cert_list;
Packit aea12f
	gnutls_privkey_t apr_pkey;
Packit aea12f
	int apr_cert_list_length;
Packit aea12f
	mbuffer_st *bufel = NULL;
Packit aea12f
	gnutls_buffer_st buf;
Packit aea12f
	gnutls_datum_t sig = {NULL, 0};
Packit aea12f
	gnutls_sign_algorithm_t algo;
Packit aea12f
	const gnutls_sign_entry_st *se;
Packit aea12f
	bool server = 0;
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
		if (session->security_parameters.entity == GNUTLS_SERVER)
Packit aea12f
			server = 1;
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
		if (apr_cert_list_length == 0) {
Packit aea12f
			if (server) {
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit aea12f
			} else {
Packit aea12f
				/* for client, this means either we
Packit aea12f
				 * didn't get a cert request or we are
Packit aea12f
				 * declining authentication; in either
Packit aea12f
				 * case we don't send a cert verify */
Packit aea12f
				return 0;
Packit aea12f
			}
Packit aea12f
		}
Packit aea12f
Packit aea12f
		if (server) {
Packit Service 991b93
			algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0, GNUTLS_KX_UNKNOWN);
Packit aea12f
			if (algo == GNUTLS_SIGN_UNKNOWN)
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
Packit aea12f
Packit aea12f
			gnutls_sign_algorithm_set_server(session, algo);
Packit aea12f
		} else {
Packit aea12f
			/* for client, signature algorithm is already
Packit aea12f
			 * determined from Certificate Request */
Packit aea12f
			algo = gnutls_sign_algorithm_get_client(session);
Packit aea12f
			if (unlikely(algo == GNUTLS_SIGN_UNKNOWN))
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		se = _gnutls_sign_to_entry(algo);
Packit aea12f
Packit aea12f
		ret = _gnutls13_handshake_sign_data(session, &apr_cert_list[0], apr_pkey,
Packit aea12f
						    server?(&srv_ctx):(&cli_ctx),
Packit aea12f
						    &sig, se);
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
			gnutls_assert();
Packit aea12f
			goto cleanup;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = _gnutls_buffer_append_data(&buf, se->aid.id, 2);
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, 16, sig.data, sig.size);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			goto cleanup;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		bufel = _gnutls_buffer_to_mbuffer(&buf;;
Packit aea12f
Packit aea12f
		gnutls_free(sig.data);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
Packit aea12f
Packit aea12f
 cleanup:
Packit aea12f
	gnutls_free(sig.data);
Packit aea12f
	_gnutls_buffer_clear(&buf;;
Packit aea12f
	return ret;
Packit aea12f
}