Blame lib/auth/cert.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
Packit Service 4684c1
 * Copyright (C) 2017 Red Hat, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Author: 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
/* The certificate authentication functions which are needed in the handshake,
Packit Service 4684c1
 * and are common to RSA and DHE key exchange, are in this file.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include "gnutls_int.h"
Packit Service 4684c1
#include "auth.h"
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
#include <auth/cert.h>
Packit Service 4684c1
#include "dh.h"
Packit Service 4684c1
#include "num.h"
Packit Service 4684c1
#include "libtasn1.h"
Packit Service 4684c1
#include "datum.h"
Packit Service 4684c1
#include "ext/signature.h"
Packit Service 4684c1
#include <pk.h>
Packit Service 4684c1
#include <algorithms.h>
Packit Service 4684c1
#include <global.h>
Packit Service 4684c1
#include <record.h>
Packit Service 4684c1
#include <tls-sig.h>
Packit Service 4684c1
#include <state.h>
Packit Service 4684c1
#include <pk.h>
Packit Service 4684c1
#include <x509.h>
Packit Service 4684c1
#include <x509/verify-high.h>
Packit Service 4684c1
#include <gnutls/abstract.h>
Packit Service 4684c1
#include "abstract_int.h"
Packit Service 4684c1
#include "debug.h"
Packit Service 4684c1
Packit Service 4684c1
static void
Packit Service 4684c1
selected_certs_set(gnutls_session_t session,
Packit Service 4684c1
		   gnutls_pcert_st * certs, int ncerts,
Packit Service 4684c1
		   gnutls_ocsp_data_st *ocsp, unsigned nocsp,
Packit Service 4684c1
		   gnutls_privkey_t key, int need_free,
Packit Service 4684c1
		   gnutls_status_request_ocsp_func ocsp_func,
Packit Service 4684c1
		   void *ocsp_func_ptr);
Packit Service 4684c1
Packit Service 4684c1
#define MAX_CLIENT_SIGN_ALGOS 5
Packit Service 4684c1
#define CERTTYPE_SIZE (MAX_CLIENT_SIGN_ALGOS+1)
Packit Service 4684c1
typedef enum CertificateSigType { RSA_SIGN = 1, DSA_SIGN = 2, ECDSA_SIGN = 64,
Packit Service 4684c1
#ifdef ENABLE_GOST
Packit Service 4684c1
	GOSTR34102012_256_SIGN = 67,
Packit Service 4684c1
	GOSTR34102012_512_SIGN = 68
Packit Service 4684c1
#endif
Packit Service 4684c1
} CertificateSigType;
Packit Service 4684c1
Packit Service 4684c1
/* Moves data from an internal certificate struct (gnutls_pcert_st) to
Packit Service 4684c1
 * another internal certificate struct (cert_auth_info_t), and deinitializes
Packit Service 4684c1
 * the former.
Packit Service 4684c1
 */
Packit Service 4684c1
int _gnutls_pcert_to_auth_info(cert_auth_info_t info, gnutls_pcert_st * certs, size_t ncerts)
Packit Service 4684c1
{
Packit Service 4684c1
	size_t i, j;
Packit Service 4684c1
Packit Service 4684c1
	if (info->raw_certificate_list != NULL) {
Packit Service 4684c1
		for (j = 0; j < info->ncerts; j++)
Packit Service 4684c1
			_gnutls_free_datum(&info->raw_certificate_list[j]);
Packit Service 4684c1
		gnutls_free(info->raw_certificate_list);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (ncerts == 0) {
Packit Service 4684c1
		info->raw_certificate_list = NULL;
Packit Service 4684c1
		info->ncerts = 0;
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	info->raw_certificate_list =
Packit Service 4684c1
	    gnutls_calloc(ncerts, sizeof(gnutls_datum_t));
Packit Service 4684c1
	if (info->raw_certificate_list == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_MEMORY_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	info->cert_type = certs[0].type;
Packit Service 4684c1
	info->ncerts = ncerts;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < ncerts; i++) {
Packit Service 4684c1
		info->raw_certificate_list[i].data = certs[i].cert.data;
Packit Service 4684c1
		info->raw_certificate_list[i].size = certs[i].cert.size;
Packit Service 4684c1
		certs[i].cert.data = NULL;
Packit Service 4684c1
		gnutls_pcert_deinit(&certs[i]);
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_free(certs);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* returns 0 if the algo_to-check exists in the pk_algos list,
Packit Service 4684c1
 * -1 otherwise.
Packit Service 4684c1
 */
Packit Service 4684c1
inline static int
Packit Service 4684c1
check_pk_algo_in_list(const gnutls_pk_algorithm_t *
Packit Service 4684c1
		      pk_algos, int pk_algos_length,
Packit Service 4684c1
		      gnutls_pk_algorithm_t algo_to_check)
Packit Service 4684c1
{
Packit Service 4684c1
	int i;
Packit Service 4684c1
	for (i = 0; i < pk_algos_length; i++) {
Packit Service 4684c1
		if (algo_to_check == pk_algos[i]) {
Packit Service 4684c1
			return 0;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
	return -1;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Returns the issuer's Distinguished name in odn, of the certificate
Packit Service 4684c1
 * specified in cert.
Packit Service 4684c1
 */
Packit Service 4684c1
static int cert_get_issuer_dn(gnutls_pcert_st * cert, gnutls_datum_t * odn)
Packit Service 4684c1
{
Packit Service 4684c1
	ASN1_TYPE dn;
Packit Service 4684c1
	int len, result;
Packit Service 4684c1
	int start, end;
Packit Service 4684c1
Packit Service 4684c1
	if ((result = asn1_create_element
Packit Service 4684c1
	     (_gnutls_get_pkix(), "PKIX1.Certificate", &dn)) != ASN1_SUCCESS) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return _gnutls_asn2err(result);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	result = asn1_der_decoding(&dn, cert->cert.data, cert->cert.size, NULL);
Packit Service 4684c1
	if (result != ASN1_SUCCESS) {
Packit Service 4684c1
		/* couldn't decode DER */
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		asn1_delete_structure(&dn;;
Packit Service 4684c1
		return _gnutls_asn2err(result);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	result =
Packit Service 4684c1
	    asn1_der_decoding_startEnd(dn, cert->cert.data,
Packit Service 4684c1
				       cert->cert.size,
Packit Service 4684c1
				       "tbsCertificate.issuer", &start, &end;;
Packit Service 4684c1
Packit Service 4684c1
	if (result != ASN1_SUCCESS) {
Packit Service 4684c1
		/* couldn't decode DER */
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		asn1_delete_structure(&dn;;
Packit Service 4684c1
		return _gnutls_asn2err(result);
Packit Service 4684c1
	}
Packit Service 4684c1
	asn1_delete_structure(&dn;;
Packit Service 4684c1
Packit Service 4684c1
	len = end - start + 1;
Packit Service 4684c1
Packit Service 4684c1
	odn->size = len;
Packit Service 4684c1
	odn->data = &cert->cert.data[start];
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Locates the most appropriate x509 certificate using the
Packit Service 4684c1
 * given DN. If indx == -1 then no certificate was found.
Packit Service 4684c1
 *
Packit Service 4684c1
 * That is to guess which certificate to use, based on the
Packit Service 4684c1
 * CAs and sign algorithms supported by the peer server.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
find_x509_client_cert(gnutls_session_t session,
Packit Service 4684c1
	       const gnutls_certificate_credentials_t cred,
Packit Service 4684c1
	       const uint8_t * _data, size_t _data_size,
Packit Service 4684c1
	       const gnutls_pk_algorithm_t * pk_algos,
Packit Service 4684c1
	       int pk_algos_length, int *indx)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned size;
Packit Service 4684c1
	gnutls_datum_t odn = { NULL, 0 }, asked_dn;
Packit Service 4684c1
	const uint8_t *data = _data;
Packit Service 4684c1
	ssize_t data_size = _data_size;
Packit Service 4684c1
	unsigned i, j;
Packit Service 4684c1
	int result, cert_pk;
Packit Service 4684c1
	unsigned key_usage;
Packit Service 4684c1
Packit Service 4684c1
	*indx = -1;
Packit Service 4684c1
Packit Service 4684c1
	/* If peer doesn't send any issuers and we have a single certificate
Packit Service 4684c1
	 * then send that one.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (cred->ncerts == 1 &&
Packit Service 4684c1
	    (data_size == 0
Packit Service 4684c1
	     || (session->internals.flags & GNUTLS_FORCE_CLIENT_CERT))) {
Packit Service 4684c1
		if (cred->certs[0].cert_list[0].type == GNUTLS_CRT_X509) {
Packit Service 4684c1
Packit Service 4684c1
			key_usage = get_key_usage(session, cred->certs[0].cert_list[0].pubkey);
Packit Service 4684c1
Packit Service 4684c1
			/* For client certificates we require signatures */
Packit Service 4684c1
			result = _gnutls_check_key_usage_for_sig(session, key_usage, 1);
Packit Service 4684c1
			if (result < 0) {
Packit Service 4684c1
				_gnutls_debug_log("Client certificate is not suitable for signing\n");
Packit Service 4684c1
				return gnutls_assert_val(result);
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			*indx = 0;
Packit Service 4684c1
			return 0;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	do {
Packit Service 4684c1
		DECR_LENGTH_RET(data_size, 2, 0);
Packit Service 4684c1
		size = _gnutls_read_uint16(data);
Packit Service 4684c1
		DECR_LENGTH_RET(data_size, size, 0);
Packit Service 4684c1
		data += 2;
Packit Service 4684c1
Packit Service 4684c1
		asked_dn.data = (void*)data;
Packit Service 4684c1
		asked_dn.size = size;
Packit Service 4684c1
		_gnutls_dn_log("Peer requested CA", &asked_dn);
Packit Service 4684c1
Packit Service 4684c1
		for (i = 0; i < cred->ncerts; i++) {
Packit Service 4684c1
			for (j = 0; j < cred->certs[i].cert_list_length; j++) {
Packit Service 4684c1
				if ((result =
Packit Service 4684c1
				     cert_get_issuer_dn(&cred->certs
Packit Service 4684c1
							[i].cert_list
Packit Service 4684c1
							[j], &odn)) < 0) {
Packit Service 4684c1
					gnutls_assert();
Packit Service 4684c1
					return result;
Packit Service 4684c1
				}
Packit Service 4684c1
Packit Service 4684c1
				if (odn.size == 0 || odn.size != asked_dn.size)
Packit Service 4684c1
					continue;
Packit Service 4684c1
Packit Service 4684c1
				key_usage = get_key_usage(session, cred->certs[i].cert_list[0].pubkey);
Packit Service 4684c1
Packit Service 4684c1
				/* For client certificates we require signatures */
Packit Service 4684c1
				if (_gnutls_check_key_usage_for_sig(session, key_usage, 1) < 0) {
Packit Service 4684c1
					_gnutls_debug_log("Client certificate is not suitable for signing\n");
Packit Service 4684c1
					continue;
Packit Service 4684c1
				}
Packit Service 4684c1
Packit Service 4684c1
				/* If the DN matches and
Packit Service 4684c1
				 * the *_SIGN algorithm matches
Packit Service 4684c1
				 * the cert is our cert!
Packit Service 4684c1
				 */
Packit Service 4684c1
				cert_pk =
Packit Service 4684c1
				    gnutls_pubkey_get_pk_algorithm(cred->certs
Packit Service 4684c1
								   [i].cert_list
Packit Service 4684c1
								   [0].pubkey,
Packit Service 4684c1
								   NULL);
Packit Service 4684c1
Packit Service 4684c1
				if ((memcmp(odn.data, asked_dn.data, asked_dn.size) == 0) &&
Packit Service 4684c1
				    (check_pk_algo_in_list
Packit Service 4684c1
				     (pk_algos, pk_algos_length,
Packit Service 4684c1
				      cert_pk) == 0)) {
Packit Service 4684c1
					*indx = i;
Packit Service 4684c1
					break;
Packit Service 4684c1
				}
Packit Service 4684c1
			}
Packit Service 4684c1
			if (*indx != -1)
Packit Service 4684c1
				break;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (*indx != -1)
Packit Service 4684c1
			break;
Packit Service 4684c1
Packit Service 4684c1
		/* move to next record */
Packit Service 4684c1
		data += size;
Packit Service 4684c1
	}
Packit Service 4684c1
	while (1);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
/* Locates the first raw public-key.
Packit Service 4684c1
 * Currently it only makes sense to associate one raw pubkey per session.
Packit Service 4684c1
 * Associating more raw pubkeys with a session has no use because we
Packit Service 4684c1
 * don't know how to select the correct one.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
find_rawpk_client_cert(gnutls_session_t session,
Packit Service 4684c1
			const gnutls_certificate_credentials_t cred,
Packit Service 4684c1
			const gnutls_pk_algorithm_t* pk_algos,
Packit Service 4684c1
			int pk_algos_length, int* indx)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned i;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_pk_algorithm_t pk;
Packit Service 4684c1
Packit Service 4684c1
	*indx = -1;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < cred->ncerts; i++) {
Packit Service 4684c1
		/* We know that our list length will be 1, therefore we can
Packit Service 4684c1
		 * ignore the rest.
Packit Service 4684c1
		 */
Packit Service 4684c1
		if (cred->certs[i].cert_list_length == 1 && cred->certs[i].cert_list[0].type == GNUTLS_CRT_RAWPK) {
Packit Service 4684c1
			pk = gnutls_pubkey_get_pk_algorithm(cred->certs[i].cert_list[0].pubkey, NULL);
Packit Service 4684c1
Packit Service 4684c1
			/* For client certificates we require signatures */
Packit Service 4684c1
			ret = _gnutls_check_key_usage_for_sig(session, get_key_usage(session, cred->certs[i].cert_list[0].pubkey), 1);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				/* we return an error instead of skipping so that the user is notified about
Packit Service 4684c1
				 * the key incompatibility */
Packit Service 4684c1
				_gnutls_debug_log("Client certificate is not suitable for signing\n");
Packit Service 4684c1
				return gnutls_assert_val(ret);
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			/* Check whether the public-key algorithm of our credential is in
Packit Service 4684c1
			 * the list with supported public-key algorithms and whether the
Packit Service 4684c1
			 * cert type matches. */
Packit Service 4684c1
			if ((check_pk_algo_in_list(pk_algos, pk_algos_length, pk) == 0)) {
Packit Service 4684c1
				// We found a compatible credential
Packit Service 4684c1
				*indx = i;
Packit Service 4684c1
				break;
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
/* Returns the number of issuers in the server's
Packit Service 4684c1
 * certificate request packet.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
get_issuers_num(gnutls_session_t session, const uint8_t * data, ssize_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int issuers_dn_len = 0;
Packit Service 4684c1
	unsigned size;
Packit Service 4684c1
Packit Service 4684c1
	/* Count the number of the given issuers;
Packit Service 4684c1
	 * This is used to allocate the issuers_dn without
Packit Service 4684c1
	 * using realloc().
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	if (data_size == 0 || data == NULL)
Packit Service 4684c1
		return 0;
Packit Service 4684c1
Packit Service 4684c1
	while (data_size > 0) {
Packit Service 4684c1
		/* This works like DECR_LEN()
Packit Service 4684c1
		 */
Packit Service 4684c1
		DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit Service 4684c1
		size = _gnutls_read_uint16(data);
Packit Service 4684c1
Packit Service 4684c1
		DECR_LENGTH_RET(data_size, size, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit Service 4684c1
Packit Service 4684c1
		data += 2;
Packit Service 4684c1
Packit Service 4684c1
		if (size > 0) {
Packit Service 4684c1
			issuers_dn_len++;
Packit Service 4684c1
			data += size;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return issuers_dn_len;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Returns the issuers in the server's certificate request
Packit Service 4684c1
 * packet.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
get_issuers(gnutls_session_t session,
Packit Service 4684c1
	    gnutls_datum_t * issuers_dn, int issuers_len,
Packit Service 4684c1
	    const uint8_t * data, size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int i;
Packit Service 4684c1
	unsigned size;
Packit Service 4684c1
Packit Service 4684c1
	if (get_certificate_type(session, GNUTLS_CTYPE_CLIENT) != GNUTLS_CRT_X509)
Packit Service 4684c1
		return 0;
Packit Service 4684c1
Packit Service 4684c1
	/* put the requested DNs to req_dn, only in case
Packit Service 4684c1
	 * of X509 certificates.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (issuers_len > 0) {
Packit Service 4684c1
Packit Service 4684c1
		for (i = 0; i < issuers_len; i++) {
Packit Service 4684c1
			/* The checks here for the buffer boundaries
Packit Service 4684c1
			 * are not needed since the buffer has been
Packit Service 4684c1
			 * parsed above.
Packit Service 4684c1
			 */
Packit Service 4684c1
			data_size -= 2;
Packit Service 4684c1
Packit Service 4684c1
			size = _gnutls_read_uint16(data);
Packit Service 4684c1
Packit Service 4684c1
			data += 2;
Packit Service 4684c1
Packit Service 4684c1
			issuers_dn[i].data = (void*)data;
Packit Service 4684c1
			issuers_dn[i].size = size;
Packit Service 4684c1
Packit Service 4684c1
			_gnutls_dn_log("Peer requested CA", &issuers_dn[i]);
Packit Service 4684c1
Packit Service 4684c1
			data += size;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Calls the client or server certificate get callback.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
call_get_cert_callback(gnutls_session_t session,
Packit Service 4684c1
		       const gnutls_datum_t * issuers_dn,
Packit Service 4684c1
		       int issuers_dn_length,
Packit Service 4684c1
		       gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_privkey_t local_key = NULL;
Packit Service 4684c1
	int ret = GNUTLS_E_INTERNAL_ERROR;
Packit Service 4684c1
	gnutls_certificate_type_t type;
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	gnutls_pcert_st *pcert = NULL;
Packit Service 4684c1
	gnutls_ocsp_data_st *ocsp = NULL;
Packit Service 4684c1
	unsigned int ocsp_length = 0;
Packit Service 4684c1
	unsigned int pcert_length = 0;
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* Correctly set the certificate type for ourselves */
Packit Service 4684c1
	type = get_certificate_type(session, GNUTLS_CTYPE_OURS);
Packit Service 4684c1
Packit Service 4684c1
	/* Check whether a callback is set and call it */
Packit Service 4684c1
	if (cred->get_cert_callback3) {
Packit Service 4684c1
		struct gnutls_cert_retr_st info;
Packit Service 4684c1
		unsigned int flags = 0;
Packit Service 4684c1
Packit Service 4684c1
		memset(&info, 0, sizeof(info));
Packit Service 4684c1
		info.req_ca_rdn = issuers_dn;
Packit Service 4684c1
		info.nreqs = issuers_dn_length;
Packit Service 4684c1
		info.pk_algos = pk_algos;
Packit Service 4684c1
		info.pk_algos_length = pk_algos_length;
Packit Service 4684c1
		info.cred = cred;
Packit Service 4684c1
Packit Service 4684c1
		/* we avoid all allocations and transformations */
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    cred->get_cert_callback3(session, &info,
Packit Service 4684c1
					     &pcert, &pcert_length,
Packit Service 4684c1
					     &ocsp, &ocsp_length,
Packit Service 4684c1
					     &local_key, &flags);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_USER_ERROR);
Packit Service 4684c1
Packit Service 4684c1
		if (pcert_length > 0 && type != pcert[0].type)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit Service 4684c1
Packit Service 4684c1
		if (pcert_length == 0) {
Packit Service 4684c1
			pcert = NULL;
Packit Service 4684c1
			local_key = NULL;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		selected_certs_set(session, pcert, pcert_length,
Packit Service 4684c1
				   ocsp, ocsp_length,
Packit Service 4684c1
				   local_key, (flags&GNUTLS_CERT_RETR_DEINIT_ALL)?1:0,
Packit Service 4684c1
				   cred->glob_ocsp_func, cred->glob_ocsp_func_ptr);
Packit Service 4684c1
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	} else {
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
	}
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Finds the appropriate certificate depending on the cA Distinguished name
Packit Service 4684c1
 * advertized by the server. If none matches then returns 0 and -1 as index.
Packit Service 4684c1
 * In case of an error a negative error code, is returned.
Packit Service 4684c1
 *
Packit Service 4684c1
 * 20020128: added ability to select a certificate depending on the SIGN
Packit Service 4684c1
 * algorithm (only in automatic mode).
Packit Service 4684c1
 */
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_select_client_cert(gnutls_session_t session,
Packit Service 4684c1
			   const uint8_t * _data, size_t _data_size,
Packit Service 4684c1
			   gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
Packit Service 4684c1
{
Packit Service 4684c1
	int result;
Packit Service 4684c1
	int indx = -1;
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	const uint8_t *data = _data;
Packit Service 4684c1
	ssize_t data_size = _data_size;
Packit Service 4684c1
	int issuers_dn_length;
Packit Service 4684c1
	gnutls_datum_t *issuers_dn = NULL;
Packit Service 4684c1
	gnutls_certificate_type_t cert_type;
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_CLIENT);
Packit Service 4684c1
Packit Service 4684c1
	if (cred->get_cert_callback3 != NULL) {
Packit Service 4684c1
Packit Service 4684c1
		/* use a callback to get certificate
Packit Service 4684c1
		 */
Packit Service 4684c1
		if (cert_type == GNUTLS_CRT_X509) {
Packit Service 4684c1
			issuers_dn_length =
Packit Service 4684c1
			    get_issuers_num(session, data, data_size);
Packit Service 4684c1
			if (issuers_dn_length < 0) {
Packit Service 4684c1
				gnutls_assert();
Packit Service 4684c1
				return issuers_dn_length;
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			if (issuers_dn_length > 0) {
Packit Service 4684c1
				issuers_dn =
Packit Service 4684c1
				    gnutls_malloc(sizeof(gnutls_datum_t) *
Packit Service 4684c1
						  issuers_dn_length);
Packit Service 4684c1
				if (issuers_dn == NULL) {
Packit Service 4684c1
					gnutls_assert();
Packit Service 4684c1
					return GNUTLS_E_MEMORY_ERROR;
Packit Service 4684c1
				}
Packit Service 4684c1
Packit Service 4684c1
				result =
Packit Service 4684c1
				    get_issuers(session, issuers_dn,
Packit Service 4684c1
						issuers_dn_length, data,
Packit Service 4684c1
						data_size);
Packit Service 4684c1
				if (result < 0) {
Packit Service 4684c1
					gnutls_assert();
Packit Service 4684c1
					goto cleanup;
Packit Service 4684c1
				}
Packit Service 4684c1
			}
Packit Service 4684c1
		} else {
Packit Service 4684c1
			issuers_dn_length = 0;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		result =
Packit Service 4684c1
		    call_get_cert_callback(session, issuers_dn,
Packit Service 4684c1
					   issuers_dn_length, pk_algos,
Packit Service 4684c1
					   pk_algos_length);
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
Packit Service 4684c1
	} else {
Packit Service 4684c1
		/* If we have no callbacks, try to guess.
Packit Service 4684c1
		 */
Packit Service 4684c1
		switch (cert_type) {
Packit Service 4684c1
			case GNUTLS_CRT_X509:
Packit Service 4684c1
				result = find_x509_client_cert(session, cred, _data,
Packit Service 4684c1
										_data_size, pk_algos,
Packit Service 4684c1
										pk_algos_length, &indx);
Packit Service 4684c1
				break;
Packit Service 4684c1
			case GNUTLS_CRT_RAWPK:
Packit Service 4684c1
				result = find_rawpk_client_cert(session, cred,
Packit Service 4684c1
							pk_algos, pk_algos_length, &indx);
Packit Service 4684c1
				break;
Packit Service 4684c1
			default:
Packit Service 4684c1
				result = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
Packit Service 4684c1
				break;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (result < 0) {
Packit Service 4684c1
			return gnutls_assert_val(result);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (indx >= 0) {
Packit Service 4684c1
			selected_certs_set(session,
Packit Service 4684c1
					   &cred->certs[indx].
Packit Service 4684c1
					   cert_list[0],
Packit Service 4684c1
					   cred->certs[indx].
Packit Service 4684c1
					   cert_list_length,
Packit Service 4684c1
					   cred->certs[indx].ocsp_data,
Packit Service 4684c1
					   cred->certs[indx].ocsp_data_length,
Packit Service 4684c1
					   cred->certs[indx].pkey, 0,
Packit Service 4684c1
					   NULL, NULL);
Packit Service 4684c1
		} else {
Packit Service 4684c1
			selected_certs_set(session, NULL, 0, NULL, 0,
Packit Service 4684c1
					   NULL, 0, NULL, NULL);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		result = 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	gnutls_free(issuers_dn);
Packit Service 4684c1
	return result;
Packit Service 4684c1
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Generate certificate message
Packit Service 4684c1
 */
Packit Service 4684c1
static int gen_x509_crt(gnutls_session_t session, gnutls_buffer_st * data)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret, i;
Packit Service 4684c1
	gnutls_pcert_st *apr_cert_list;
Packit Service 4684c1
	gnutls_privkey_t apr_pkey;
Packit Service 4684c1
	int apr_cert_list_length;
Packit Service 4684c1
	unsigned init_pos = data->length;
Packit Service 4684c1
Packit Service 4684c1
	/* find the appropriate certificate
Packit Service 4684c1
	 */
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_get_selected_cert(session, &apr_cert_list,
Packit Service 4684c1
				       &apr_cert_list_length, &apr_pkey)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = 3;
Packit Service 4684c1
	for (i = 0; i < apr_cert_list_length; i++) {
Packit Service 4684c1
		ret += apr_cert_list[i].cert.size + 3;
Packit Service 4684c1
		/* hold size
Packit Service 4684c1
		 * for uint24 */
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* if no certificates were found then send:
Packit Service 4684c1
	 * 0B 00 00 03 00 00 00    // Certificate with no certs
Packit Service 4684c1
	 * instead of:
Packit Service 4684c1
	 * 0B 00 00 00	  // empty certificate handshake
Packit Service 4684c1
	 *
Packit Service 4684c1
	 * ( the above is the whole handshake message, not
Packit Service 4684c1
	 * the one produced here )
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_buffer_append_prefix(data, 24, ret - 3);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < apr_cert_list_length; i++) {
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    _gnutls_buffer_append_data_prefix(data, 24,
Packit Service 4684c1
						      apr_cert_list[i].
Packit Service 4684c1
						      cert.data,
Packit Service 4684c1
						      apr_cert_list[i].
Packit Service 4684c1
						      cert.size);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return data->length - init_pos;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
/* Generates a Raw Public Key certificate message that holds only the
Packit Service 4684c1
 * SubjectPublicKeyInfo part of a regular certificate message.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns the number of bytes sent or a negative error code.
Packit Service 4684c1
 */
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_rawpk_crt(gnutls_session_t session, gnutls_buffer_st* data)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_pcert_st *apr_cert_list;
Packit Service 4684c1
	gnutls_privkey_t apr_pkey;
Packit Service 4684c1
	int apr_cert_list_length;
Packit Service 4684c1
Packit Service 4684c1
	if((ret = _gnutls_get_selected_cert(session, &apr_cert_list,
Packit Service 4684c1
				       &apr_cert_list_length, &apr_pkey)) < 0)	{
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* Since we are transmitting a raw public key with no additional
Packit Service 4684c1
	 * certificate credentials attached to it, it doesn't make sense to
Packit Service 4684c1
	 * have more than one certificate set (i.e. to have a certificate chain).
Packit Service 4684c1
	 */
Packit Service 4684c1
	assert(apr_cert_list_length <= 1);
Packit Service 4684c1
Packit Service 4684c1
	/* Write our certificate containing only the SubjectPublicKeyInfo to
Packit Service 4684c1
	 * the output buffer. We always have exactly one certificate that
Packit Service 4684c1
	 * contains our raw public key. Our message looks like:
Packit Service 4684c1
	 * <length++certificate> where
Packit Service 4684c1
	 * length = 3 bytes (or 24 bits) and
Packit Service 4684c1
	 * certificate = length bytes.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (apr_cert_list_length == 0) {
Packit Service 4684c1
		ret = _gnutls_buffer_append_prefix(data, 24, 0);
Packit Service 4684c1
	} else {
Packit Service 4684c1
		ret = _gnutls_buffer_append_data_prefix(data, 24,
Packit Service 4684c1
							apr_cert_list[0].cert.data,
Packit Service 4684c1
							apr_cert_list[0].cert.size);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
	if (ret < 0) return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	return data->length;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_cert_client_crt(gnutls_session_t session, gnutls_buffer_st * data)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_certificate_type_t cert_type;
Packit Service 4684c1
Packit Service 4684c1
	// Retrieve the (negotiated) certificate type for the client
Packit Service 4684c1
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_CLIENT);
Packit Service 4684c1
Packit Service 4684c1
	switch (cert_type) {
Packit Service 4684c1
		case GNUTLS_CRT_X509:
Packit Service 4684c1
			return gen_x509_crt(session, data);
Packit Service 4684c1
		case GNUTLS_CRT_RAWPK:
Packit Service 4684c1
			return _gnutls_gen_rawpk_crt(session, data);
Packit Service 4684c1
		default:
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
	}
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_cert_server_crt(gnutls_session_t session, gnutls_buffer_st * data)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_certificate_type_t cert_type;
Packit Service 4684c1
Packit Service 4684c1
	// Retrieve the (negotiated) certificate type for the server
Packit Service 4684c1
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_SERVER);
Packit Service 4684c1
Packit Service 4684c1
	switch (cert_type) {
Packit Service 4684c1
		case GNUTLS_CRT_X509:
Packit Service 4684c1
			return gen_x509_crt(session, data);
Packit Service 4684c1
		case GNUTLS_CRT_RAWPK:
Packit Service 4684c1
			return _gnutls_gen_rawpk_crt(session, data);
Packit Service 4684c1
		default:
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
	}
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static
Packit Service 4684c1
int check_pk_compat(gnutls_session_t session, gnutls_pubkey_t pubkey)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned cert_pk;
Packit Service 4684c1
	unsigned kx;
Packit Service 4684c1
Packit Service 4684c1
	if (session->security_parameters.entity != GNUTLS_CLIENT)
Packit Service 4684c1
		return 0;
Packit Service 4684c1
Packit Service 4684c1
	cert_pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL);
Packit Service 4684c1
	if (cert_pk == GNUTLS_PK_UNKNOWN) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	kx = session->security_parameters.cs->kx_algorithm;
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_map_kx_get_cred(kx, 1) == GNUTLS_CRD_CERTIFICATE &&
Packit Service 4684c1
	    !_gnutls_kx_supports_pk(kx, cert_pk)) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Process server certificate
Packit Service 4684c1
 */
Packit Service 4684c1
#define CLEAR_CERTS for(x=0;x
Packit Service 4684c1
static int
Packit Service 4684c1
_gnutls_proc_x509_crt(gnutls_session_t session,
Packit Service 4684c1
			     uint8_t * data, size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int size, len, ret;
Packit Service 4684c1
	uint8_t *p = data;
Packit Service 4684c1
	cert_auth_info_t info;
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	ssize_t dsize = data_size;
Packit Service 4684c1
	int i;
Packit Service 4684c1
	gnutls_pcert_st *peer_certificate_list;
Packit Service 4684c1
	size_t peer_certificate_list_size = 0, j, x;
Packit Service 4684c1
	gnutls_datum_t tmp;
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
Packit Service 4684c1
				   sizeof(cert_auth_info_st), 1)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
Packit Service 4684c1
	if (data == NULL || data_size == 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		/* no certificate was sent */
Packit Service 4684c1
		return GNUTLS_E_NO_CERTIFICATE_FOUND;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN(dsize, 3);
Packit Service 4684c1
	size = _gnutls_read_uint24(p);
Packit Service 4684c1
	p += 3;
Packit Service 4684c1
Packit Service 4684c1
	/* ensure no discrepancy in data */
Packit Service 4684c1
	if (size != dsize)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit Service 4684c1
Packit Service 4684c1
	/* some implementations send 0B 00 00 06 00 00 03 00 00 00
Packit Service 4684c1
	 * instead of just 0B 00 00 03 00 00 00 as an empty certificate message.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (size == 0 || (size == 3 && memcmp(p, "\x00\x00\x00", 3) == 0)) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		/* no certificate was sent */
Packit Service 4684c1
		return GNUTLS_E_NO_CERTIFICATE_FOUND;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	i = dsize;
Packit Service 4684c1
	while (i > 0) {
Packit Service 4684c1
		DECR_LEN(dsize, 3);
Packit Service 4684c1
		len = _gnutls_read_uint24(p);
Packit Service 4684c1
		p += 3;
Packit Service 4684c1
		DECR_LEN(dsize, len);
Packit Service 4684c1
		peer_certificate_list_size++;
Packit Service 4684c1
		p += len;
Packit Service 4684c1
		i -= len + 3;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (dsize != 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit Service 4684c1
Packit Service 4684c1
	if (peer_certificate_list_size == 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_NO_CERTIFICATE_FOUND;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* Ok we now allocate the memory to hold the
Packit Service 4684c1
	 * certificate list
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	peer_certificate_list =
Packit Service 4684c1
	    gnutls_calloc(1,
Packit Service 4684c1
			  sizeof(gnutls_pcert_st) *
Packit Service 4684c1
			  (peer_certificate_list_size));
Packit Service 4684c1
	if (peer_certificate_list == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_MEMORY_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	p = data + 3;
Packit Service 4684c1
Packit Service 4684c1
	/* Now we start parsing the list (again).
Packit Service 4684c1
	 * We don't use DECR_LEN since the list has
Packit Service 4684c1
	 * been parsed before.
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	for (j = 0; j < peer_certificate_list_size; j++) {
Packit Service 4684c1
		len = _gnutls_read_uint24(p);
Packit Service 4684c1
		p += 3;
Packit Service 4684c1
Packit Service 4684c1
		tmp.size = len;
Packit Service 4684c1
		tmp.data = p;
Packit Service 4684c1
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    gnutls_pcert_import_x509_raw(&peer_certificate_list
Packit Service 4684c1
						 [j], &tmp,
Packit Service 4684c1
						 GNUTLS_X509_FMT_DER, 0);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			peer_certificate_list_size = j;
Packit Service 4684c1
			ret = GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		p += len;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = check_pk_compat(session, peer_certificate_list[0].pubkey);
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 =
Packit Service 4684c1
	     _gnutls_pcert_to_auth_info(info,
Packit Service 4684c1
					peer_certificate_list,
Packit Service 4684c1
					peer_certificate_list_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
	return 0;
Packit Service 4684c1
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	CLEAR_CERTS;
Packit Service 4684c1
	gnutls_free(peer_certificate_list);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
int _gnutls_proc_rawpk_crt(gnutls_session_t session,
Packit Service 4684c1
				uint8_t * data, size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int cert_size, ret;
Packit Service 4684c1
	cert_auth_info_t info;
Packit Service 4684c1
	gnutls_pcert_st* peer_certificate;
Packit Service 4684c1
	gnutls_datum_t tmp_cert;
Packit Service 4684c1
Packit Service 4684c1
	uint8_t *p = data;
Packit Service 4684c1
	ssize_t dsize = data_size;
Packit Service 4684c1
Packit Service 4684c1
	/* We assume data != null and data_size > 0 because
Packit Service 4684c1
	 * the caller checks this for us. */
Packit Service 4684c1
Packit Service 4684c1
	/* Read the length of our certificate. We always have exactly
Packit Service 4684c1
	 * one certificate that contains our raw public key. Our message
Packit Service 4684c1
	 * looks like:
Packit Service 4684c1
	 * <length++certificate> where
Packit Service 4684c1
	 * length = 3 bytes and
Packit Service 4684c1
	 * certificate = length bytes.
Packit Service 4684c1
	 */
Packit Service 4684c1
	DECR_LEN(dsize, 3);
Packit Service 4684c1
	cert_size = _gnutls_read_uint24(p);
Packit Service 4684c1
	p += 3;
Packit Service 4684c1
Packit Service 4684c1
	/* Ensure no discrepancy in data */
Packit Service 4684c1
	if (cert_size != dsize)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
	if (cert_size == 0)	{
Packit Service 4684c1
		// No certificate was sent. This is not OK.
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN_FINAL(dsize, cert_size);
Packit Service 4684c1
Packit Service 4684c1
	/* We are now going to read our certificate and store it into
Packit Service 4684c1
	 * the authentication info structure.
Packit Service 4684c1
	 */
Packit Service 4684c1
	tmp_cert.size = cert_size;
Packit Service 4684c1
	tmp_cert.data = p;
Packit Service 4684c1
Packit Service 4684c1
	peer_certificate = gnutls_calloc(1, sizeof(*peer_certificate));
Packit Service 4684c1
	if (peer_certificate == NULL) {
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	// Import our raw certificate holding only a raw public key into this pcert
Packit Service 4684c1
	ret = gnutls_pcert_import_rawpk_raw(peer_certificate, &tmp_cert, GNUTLS_X509_FMT_DER, 0, 0);
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
	// Check whether the PK algo is compatible with the negotiated KX
Packit Service 4684c1
	ret = check_pk_compat(session, peer_certificate->pubkey);
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_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
Packit Service 4684c1
															sizeof(cert_auth_info_st), 1);
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
	info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
Packit Service 4684c1
	/* Copy our imported certificate into the auth info structure
Packit Service 4684c1
	 * and free our temporary cert storage peer_certificate.
Packit Service 4684c1
	 */
Packit Service 4684c1
	ret = _gnutls_pcert_to_auth_info(info, peer_certificate, 1);
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
	return GNUTLS_E_SUCCESS;
Packit Service 4684c1
Packit Service 4684c1
cleanup:
Packit Service 4684c1
	if (peer_certificate != NULL) {
Packit Service 4684c1
		gnutls_pcert_deinit(peer_certificate);
Packit Service 4684c1
		gnutls_free(peer_certificate);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
int _gnutls_proc_crt(gnutls_session_t session, uint8_t * data, size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	gnutls_certificate_type_t cert_type;
Packit Service 4684c1
Packit Service 4684c1
	cred =
Packit Service 4684c1
	    (gnutls_certificate_credentials_t) _gnutls_get_cred(session,
Packit Service 4684c1
								GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* Determine what certificate type we need to process.
Packit Service 4684c1
	 * We need to process the certificate of the peer. */
Packit Service 4684c1
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_PEERS);
Packit Service 4684c1
Packit Service 4684c1
	switch (cert_type) {
Packit Service 4684c1
		case GNUTLS_CRT_X509:
Packit Service 4684c1
			return _gnutls_proc_x509_crt(session, data, data_size);
Packit Service 4684c1
		case GNUTLS_CRT_RAWPK:
Packit Service 4684c1
			return _gnutls_proc_rawpk_crt(session, data, data_size);
Packit Service 4684c1
		default:
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
	}
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Checks if we support the given signature algorithm
Packit Service 4684c1
 * (RSA or DSA). Returns the corresponding gnutls_pk_algorithm_t
Packit Service 4684c1
 * if true;
Packit Service 4684c1
 */
Packit Service 4684c1
inline static int _gnutls_check_supported_sign_algo(CertificateSigType algo)
Packit Service 4684c1
{
Packit Service 4684c1
	switch (algo) {
Packit Service 4684c1
	case RSA_SIGN:
Packit Service 4684c1
		return GNUTLS_PK_RSA;
Packit Service 4684c1
	case DSA_SIGN:
Packit Service 4684c1
		return GNUTLS_PK_DSA;
Packit Service 4684c1
	case ECDSA_SIGN:
Packit Service 4684c1
		return GNUTLS_PK_EC;
Packit Service 4684c1
#ifdef ENABLE_GOST
Packit Service 4684c1
	case GOSTR34102012_256_SIGN:
Packit Service 4684c1
		return GNUTLS_PK_GOST_12_256;
Packit Service 4684c1
	case GOSTR34102012_512_SIGN:
Packit Service 4684c1
		return GNUTLS_PK_GOST_12_512;
Packit Service 4684c1
#endif
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return -1;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_proc_cert_cert_req(gnutls_session_t session, uint8_t * data,
Packit Service 4684c1
			   size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int size, ret;
Packit Service 4684c1
	uint8_t *p;
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	ssize_t dsize;
Packit Service 4684c1
	int i;
Packit Service 4684c1
	gnutls_pk_algorithm_t pk_algos[MAX_CLIENT_SIGN_ALGOS];
Packit Service 4684c1
	int pk_algos_length;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(ver == NULL))
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
Packit Service 4684c1
				   sizeof(cert_auth_info_st), 0)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	p = data;
Packit Service 4684c1
	dsize = data_size;
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN(dsize, 1);
Packit Service 4684c1
	size = p[0];
Packit Service 4684c1
	p++;
Packit Service 4684c1
	/* check if the sign algorithm is supported.
Packit Service 4684c1
	 */
Packit Service 4684c1
	pk_algos_length = 0;
Packit Service 4684c1
	for (i = 0; i < size; i++, p++) {
Packit Service 4684c1
		DECR_LEN(dsize, 1);
Packit Service 4684c1
		if ((ret = _gnutls_check_supported_sign_algo(*p)) > 0) {
Packit Service 4684c1
			if (pk_algos_length < MAX_CLIENT_SIGN_ALGOS) {
Packit Service 4684c1
				pk_algos[pk_algos_length++] = ret;
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (pk_algos_length == 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		/* read supported hashes */
Packit Service 4684c1
		int hash_num;
Packit Service 4684c1
		DECR_LEN(dsize, 2);
Packit Service 4684c1
		hash_num = _gnutls_read_uint16(p);
Packit Service 4684c1
		p += 2;
Packit Service 4684c1
		DECR_LEN(dsize, hash_num);
Packit Service 4684c1
Packit Service 4684c1
		ret = _gnutls_sign_algorithm_parse_data(session, p, hash_num);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return ret;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		p += hash_num;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* read the certificate authorities */
Packit Service 4684c1
	DECR_LEN(dsize, 2);
Packit Service 4684c1
	size = _gnutls_read_uint16(p);
Packit Service 4684c1
	p += 2;
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN_FINAL(dsize, size);
Packit Service 4684c1
Packit Service 4684c1
	/* We should reply with a certificate message,
Packit Service 4684c1
	 * even if we have no certificate to send.
Packit Service 4684c1
	 */
Packit Service 4684c1
	session->internals.hsk_flags |= HSK_CRT_ASKED;
Packit Service 4684c1
Packit Service 4684c1
	/* now we ask the user to tell which one
Packit Service 4684c1
	 * he wants to use.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_select_client_cert(session, p, size, pk_algos,
Packit Service 4684c1
					pk_algos_length)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_cert_client_crt_vrfy(gnutls_session_t session,
Packit Service 4684c1
				 gnutls_buffer_st * data)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_pcert_st *apr_cert_list;
Packit Service 4684c1
	gnutls_privkey_t apr_pkey;
Packit Service 4684c1
	int apr_cert_list_length;
Packit Service 4684c1
	gnutls_datum_t signature = { NULL, 0 };
Packit Service 4684c1
	gnutls_sign_algorithm_t sign_algo;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	unsigned init_pos = data->length;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(ver == NULL))
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	/* find the appropriate certificate */
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_get_selected_cert(session, &apr_cert_list,
Packit Service 4684c1
				       &apr_cert_list_length, &apr_pkey)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (apr_cert_list_length > 0) {
Packit Service 4684c1
		if ((ret =
Packit Service 4684c1
		     _gnutls_handshake_sign_crt_vrfy(session,
Packit Service 4684c1
						     &apr_cert_list[0],
Packit Service 4684c1
						     apr_pkey,
Packit Service 4684c1
						     &signature)) < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return ret;
Packit Service 4684c1
		}
Packit Service 4684c1
		sign_algo = ret;
Packit Service 4684c1
	} else {
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		const sign_algorithm_st *aid;
Packit Service 4684c1
		uint8_t p[2];
Packit Service 4684c1
		/* error checking is not needed here since we have used those algorithms */
Packit Service 4684c1
		aid = _gnutls_sign_to_tls_aid(sign_algo);
Packit Service 4684c1
		if (aid == NULL)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
Packit Service 4684c1
Packit Service 4684c1
		p[0] = aid->id[0];
Packit Service 4684c1
		p[1] = aid->id[1];
Packit Service 4684c1
		ret = _gnutls_buffer_append_data(data, p, 2);
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
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    _gnutls_buffer_append_data_prefix(data, 16, signature.data,
Packit Service 4684c1
					      signature.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
	ret = data->length - init_pos;
Packit Service 4684c1
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	_gnutls_free_datum(&signature);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_proc_cert_client_crt_vrfy(gnutls_session_t session,
Packit Service 4684c1
				  uint8_t * data, size_t data_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int size, ret;
Packit Service 4684c1
	ssize_t dsize = data_size;
Packit Service 4684c1
	uint8_t *pdata = data;
Packit Service 4684c1
	gnutls_datum_t sig;
Packit Service 4684c1
	cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	gnutls_pcert_st peer_cert;
Packit Service 4684c1
	gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	unsigned vflags;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(info == NULL || info->ncerts == 0 || ver == NULL)) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		/* we need this in order to get peer's certificate */
Packit Service 4684c1
		return GNUTLS_E_INTERNAL_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	vflags = cred->verify_flags | session->internals.additional_verify_flags;
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		DECR_LEN(dsize, 2);
Packit Service 4684c1
Packit Service 4684c1
		sign_algo = _gnutls_tls_aid_to_sign(pdata[0], pdata[1], ver);
Packit Service 4684c1
		if (sign_algo == GNUTLS_SIGN_UNKNOWN) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
Packit Service 4684c1
		}
Packit Service 4684c1
		pdata += 2;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_session_sign_algo_enabled(session, sign_algo);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN(dsize, 2);
Packit Service 4684c1
	size = _gnutls_read_uint16(pdata);
Packit Service 4684c1
	pdata += 2;
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN_FINAL(dsize, size);
Packit Service 4684c1
Packit Service 4684c1
	sig.data = pdata;
Packit Service 4684c1
	sig.size = size;
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_get_auth_info_pcert(&peer_cert,
Packit Service 4684c1
					  session->security_parameters.
Packit Service 4684c1
					  client_ctype, info);
Packit Service 4684c1
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_handshake_verify_crt_vrfy(session, vflags, &peer_cert, &sig,
Packit Service 4684c1
					       sign_algo)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		gnutls_pcert_deinit(&peer_cert);
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_pcert_deinit(&peer_cert);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_cert_server_cert_req(gnutls_session_t session,
Packit Service 4684c1
				 gnutls_buffer_st * data)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	int ret, i;
Packit Service 4684c1
	uint8_t tmp_data[CERTTYPE_SIZE];
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	unsigned init_pos = data->length;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(ver == NULL))
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	/* Now we need to generate the RDN sequence. This is
Packit Service 4684c1
	 * already in the CERTIFICATE_CRED structure, to improve
Packit Service 4684c1
	 * performance.
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	i = 1;
Packit Service 4684c1
#ifdef ENABLE_GOST
Packit Service 4684c1
	if (_gnutls_kx_is_vko_gost(session->security_parameters.cs->kx_algorithm)) {
Packit Service 4684c1
		tmp_data[i++] = GOSTR34102012_256_SIGN;
Packit Service 4684c1
		tmp_data[i++] = GOSTR34102012_512_SIGN;
Packit Service 4684c1
	} else
Packit Service 4684c1
#endif
Packit Service 4684c1
	{
Packit Service 4684c1
		tmp_data[i++] = RSA_SIGN;
Packit Service 4684c1
		tmp_data[i++] = DSA_SIGN;
Packit Service 4684c1
		tmp_data[i++] = ECDSA_SIGN;
Packit Service 4684c1
	}
Packit Service 4684c1
	tmp_data[0] = i - 1;
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_buffer_append_data(data, tmp_data, i);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    _gnutls_sign_algorithm_write_params(session, data);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return ret;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (session->security_parameters.client_ctype == GNUTLS_CRT_X509 &&
Packit Service 4684c1
	    session->internals.ignore_rdn_sequence == 0) {
Packit Service 4684c1
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    _gnutls_buffer_append_data_prefix(data, 16,
Packit Service 4684c1
						      cred->
Packit Service 4684c1
						      tlist->x509_rdn_sequence.
Packit Service 4684c1
						      data,
Packit Service 4684c1
						      cred->
Packit Service 4684c1
						      tlist->x509_rdn_sequence.
Packit Service 4684c1
						      size);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	} else {
Packit Service 4684c1
		ret = _gnutls_buffer_append_prefix(data, 16, 0);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return data->length - init_pos;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* This function will return the appropriate certificate to use.
Packit Service 4684c1
 * Fills in the apr_cert_list, apr_cert_list_length and apr_pkey.
Packit Service 4684c1
 * The return value is a negative error code on error.
Packit Service 4684c1
 *
Packit Service 4684c1
 * It is normal to return 0 with no certificates in client side.
Packit Service 4684c1
 *
Packit Service 4684c1
 */
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_get_selected_cert(gnutls_session_t session,
Packit Service 4684c1
			  gnutls_pcert_st ** apr_cert_list,
Packit Service 4684c1
			  int *apr_cert_list_length,
Packit Service 4684c1
			  gnutls_privkey_t * apr_pkey)
Packit Service 4684c1
{
Packit Service 4684c1
	if (session->security_parameters.entity == GNUTLS_SERVER) {
Packit Service 4684c1
Packit Service 4684c1
		*apr_cert_list = session->internals.selected_cert_list;
Packit Service 4684c1
		*apr_pkey = session->internals.selected_key;
Packit Service 4684c1
		*apr_cert_list_length =
Packit Service 4684c1
		    session->internals.selected_cert_list_length;
Packit Service 4684c1
Packit Service 4684c1
		if (*apr_cert_list_length == 0 || *apr_cert_list == NULL) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
	} else {		/* CLIENT SIDE */
Packit Service 4684c1
		/* _gnutls_select_client_cert() must have been called before.
Packit Service 4684c1
		 */
Packit Service 4684c1
		*apr_cert_list = session->internals.selected_cert_list;
Packit Service 4684c1
		*apr_cert_list_length =
Packit Service 4684c1
		    session->internals.selected_cert_list_length;
Packit Service 4684c1
		*apr_pkey = session->internals.selected_key;
Packit Service 4684c1
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
void _gnutls_selected_certs_deinit(gnutls_session_t session)
Packit Service 4684c1
{
Packit Service 4684c1
	if (session->internals.selected_need_free != 0) {
Packit Service 4684c1
		int i;
Packit Service 4684c1
Packit Service 4684c1
		for (i = 0;
Packit Service 4684c1
		     i < session->internals.selected_cert_list_length; i++) {
Packit Service 4684c1
			gnutls_pcert_deinit(&session->internals.
Packit Service 4684c1
					    selected_cert_list[i]);
Packit Service 4684c1
		}
Packit Service 4684c1
		gnutls_free(session->internals.selected_cert_list);
Packit Service 4684c1
Packit Service 4684c1
		for (i = 0;
Packit Service 4684c1
		     i < session->internals.selected_ocsp_length; i++) {
Packit Service 4684c1
			_gnutls_free_datum(&session->internals.
Packit Service 4684c1
					   selected_ocsp[i].response);
Packit Service 4684c1
		}
Packit Service 4684c1
		gnutls_free(session->internals.selected_ocsp);
Packit Service 4684c1
Packit Service 4684c1
		gnutls_privkey_deinit(session->internals.selected_key);
Packit Service 4684c1
	}
Packit Service 4684c1
	session->internals.selected_ocsp_func = NULL;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_cert_list = NULL;
Packit Service 4684c1
	session->internals.selected_cert_list_length = 0;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_key = NULL;
Packit Service 4684c1
Packit Service 4684c1
	return;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void
Packit Service 4684c1
selected_certs_set(gnutls_session_t session,
Packit Service 4684c1
		   gnutls_pcert_st * certs, int ncerts,
Packit Service 4684c1
		   gnutls_ocsp_data_st *ocsp, unsigned nocsp,
Packit Service 4684c1
		   gnutls_privkey_t key, int need_free,
Packit Service 4684c1
		   gnutls_status_request_ocsp_func ocsp_func,
Packit Service 4684c1
		   void *ocsp_func_ptr)
Packit Service 4684c1
{
Packit Service 4684c1
	_gnutls_selected_certs_deinit(session);
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_cert_list = certs;
Packit Service 4684c1
	session->internals.selected_cert_list_length = ncerts;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_ocsp = ocsp;
Packit Service 4684c1
	session->internals.selected_ocsp_length = nocsp;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_key = key;
Packit Service 4684c1
	session->internals.selected_need_free = need_free;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.selected_ocsp_func = ocsp_func;
Packit Service 4684c1
	session->internals.selected_ocsp_func_ptr = ocsp_func_ptr;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void get_server_name(gnutls_session_t session, uint8_t * name,
Packit Service 4684c1
			    size_t max_name_size)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret, i;
Packit Service 4684c1
	size_t max_name;
Packit Service 4684c1
	unsigned int type;
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
	for (i = 0; !(ret < 0); i++) {
Packit Service 4684c1
		max_name = max_name_size;
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    gnutls_server_name_get(session, name, &max_name, &type, i);
Packit Service 4684c1
		if (ret >= 0 && type == GNUTLS_NAME_DNS)
Packit Service 4684c1
			return;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	name[0] = 0;
Packit Service 4684c1
Packit Service 4684c1
	return;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Checks the compatibility of the pubkey in the certificate with the
Packit Service 4684c1
 * ciphersuite and selects a signature algorithm (if required by the
Packit Service 4684c1
 * ciphersuite and TLS version) appropriate for the certificate. If none
Packit Service 4684c1
 * can be selected returns an error.
Packit Service 4684c1
 *
Packit Service 4684c1
 * IMPORTANT
Packit Service 4684c1
 * Currently this function is only called from _gnutls_select_server_cert,
Packit Service 4684c1
 * i.e. it is only called at the server. We therefore retrieve the
Packit Service 4684c1
 * negotiated server certificate type within this function.
Packit Service 4684c1
 * If, in the future, this routine is called at the client then we
Packit Service 4684c1
 * need to adapt the implementation accordingly.
Packit Service 4684c1
 */
Packit Service 4684c1
static
Packit Service 4684c1
int cert_select_sign_algorithm(gnutls_session_t session,
Packit Service 4684c1
			       gnutls_pcert_st * cert,
Packit Service 4684c1
			       gnutls_privkey_t pkey,
Packit Service 4684c1
			       const gnutls_cipher_suite_entry_st *cs)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_pubkey_t pubkey = cert->pubkey;
Packit Service 4684c1
	gnutls_certificate_type_t cert_type = cert->type;
Packit Service 4684c1
	unsigned pk = pubkey->params.algo;
Packit Service 4684c1
	unsigned key_usage;
Packit Service 4684c1
	gnutls_sign_algorithm_t algo;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	gnutls_certificate_type_t ctype;
Packit Service 4684c1
Packit Service 4684c1
	assert(IS_SERVER(session));
Packit Service 4684c1
Packit Service 4684c1
	/* Retrieve the server certificate type */
Packit Service 4684c1
	ctype = get_certificate_type(session, GNUTLS_CTYPE_SERVER);
Packit Service 4684c1
Packit Service 4684c1
	if (ctype != cert_type) {
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	key_usage = get_key_usage(session, pubkey);
Packit Service 4684c1
Packit Service 4684c1
	/* In TLS1.3 we support only signatures; ensure the selected key supports them */
Packit Service 4684c1
	if (ver->tls13_sem && _gnutls_check_key_usage_for_sig(session, key_usage, 1) < 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit Service 4684c1
Packit Service 4684c1
	if (!ver->tls13_sem && !_gnutls_kx_supports_pk_usage(cs->kx_algorithm, pk, key_usage)) {
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (!ver->tls13_sem && _gnutls_kx_encipher_type(cs->kx_algorithm) != CIPHER_SIGN)
Packit Service 4684c1
		return 0;
Packit Service 4684c1
Packit Service 4684c1
	if (!_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		/* For SSL3.0 and TLS1.0 we lie as we cannot express md5-sha1 as
Packit Service 4684c1
		 * signature algorithm. */
Packit Service 4684c1
		algo = gnutls_pk_to_sign(cert->pubkey->params.algo, GNUTLS_DIG_SHA1);
Packit Service 4684c1
		gnutls_sign_algorithm_set_server(session, algo);
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	algo = _gnutls_session_get_sign_algo(session, cert, pkey, 0, cs->kx_algorithm);
Packit Service 4684c1
	if (algo == GNUTLS_SIGN_UNKNOWN)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_sign_algorithm_set_server(session, algo);
Packit Service 4684c1
	_gnutls_handshake_log("Selected signature algorithm: %s\n", gnutls_sign_algorithm_get_name(algo));
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* finds the most appropriate certificate in the cert list.
Packit Service 4684c1
 * The 'appropriate' is defined by the user.
Packit Service 4684c1
 *
Packit Service 4684c1
 * requested_algo holds the parameters required by the peer (RSA, DSA
Packit Service 4684c1
 * or -1 for any).
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns 0 on success and a negative error code on error. The
Packit Service 4684c1
 * selected certificate will be in session->internals.selected_*.
Packit Service 4684c1
 *
Packit Service 4684c1
 */
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_select_server_cert(gnutls_session_t session, const gnutls_cipher_suite_entry_st *cs)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned i, j;
Packit Service 4684c1
	int idx, ret;
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	char server_name[MAX_CN];
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert(); /* we don't need to select a cert */
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* When a callback is set, we call it once to get the
Packit Service 4684c1
	 * certificate and then check its compatibility with
Packit Service 4684c1
	 * the ciphersuites.
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (cred->get_cert_callback3) {
Packit Service 4684c1
		if (session->internals.selected_cert_list_length == 0) {
Packit Service 4684c1
			ret = call_get_cert_callback(session, NULL, 0, NULL, 0);
Packit Service 4684c1
			if (ret < 0)
Packit Service 4684c1
				return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
			if (session->internals.selected_cert_list_length == 0)
Packit Service 4684c1
				return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit Service 4684c1
Packit Service 4684c1
			_gnutls_debug_log("Selected (%s) cert\n",
Packit Service 4684c1
					  gnutls_pk_get_name(session->internals.selected_cert_list[0].pubkey->params.algo));
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		ret = cert_select_sign_algorithm(session,
Packit Service 4684c1
						 &session->internals.selected_cert_list[0],
Packit Service 4684c1
						 session->internals.selected_key,
Packit Service 4684c1
						 cs);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* Otherwise... we check the compatibility of the ciphersuite
Packit Service 4684c1
	 * with all the certificates available. */
Packit Service 4684c1
Packit Service 4684c1
	get_server_name(session, (unsigned char *)server_name,
Packit Service 4684c1
			sizeof(server_name));
Packit Service 4684c1
Packit Service 4684c1
	_gnutls_handshake_log ("HSK[%p]: Requested server name: '%s'\n",
Packit Service 4684c1
				     session, server_name);
Packit Service 4684c1
	idx = -1;		/* default is use no certificate */
Packit Service 4684c1
Packit Service 4684c1
	/* find certificates that match the requested server_name
Packit Service 4684c1
	 */
Packit Service 4684c1
Packit Service 4684c1
	if (server_name[0] != 0) {
Packit Service 4684c1
		for (j = 0; j < cred->ncerts; j++) {
Packit Service 4684c1
			i = cred->sorted_cert_idx[j];
Packit Service 4684c1
Packit Service 4684c1
			if (cred->certs[i].names != NULL
Packit Service 4684c1
			    && _gnutls_str_array_match(cred->certs[i].names,
Packit Service 4684c1
						       server_name) != 0) {
Packit Service 4684c1
				/* if requested algorithms are also compatible select it */
Packit Service 4684c1
Packit Service 4684c1
				ret = cert_select_sign_algorithm(session,
Packit Service 4684c1
								 &cred->certs[i].cert_list[0],
Packit Service 4684c1
								 cred->certs[i].pkey,
Packit Service 4684c1
								 cs);
Packit Service 4684c1
				if (ret >= 0) {
Packit Service 4684c1
					idx = i;
Packit Service 4684c1
					_gnutls_debug_log("Selected (%s) cert based on ciphersuite %x.%x: %s\n",
Packit Service 4684c1
						  gnutls_pk_get_name(cred->certs[i].cert_list[0].pubkey->params.algo),
Packit Service 4684c1
						  (unsigned)cs->id[0],
Packit Service 4684c1
						  (unsigned)cs->id[1],
Packit Service 4684c1
						  cs->name);
Packit Service 4684c1
					/* found */
Packit Service 4684c1
					goto finished;
Packit Service 4684c1
				}
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* no name match */
Packit Service 4684c1
	for (j = 0; j < cred->ncerts; j++) {
Packit Service 4684c1
		i = cred->sorted_cert_idx[j];
Packit Service 4684c1
Packit Service 4684c1
		_gnutls_handshake_log
Packit Service 4684c1
		    ("HSK[%p]: checking compat of %s with certificate[%d] (%s/%s)\n",
Packit Service 4684c1
		     session, cs->name, i,
Packit Service 4684c1
		     gnutls_pk_get_name(cred->certs[i].cert_list[0].pubkey->
Packit Service 4684c1
					params.algo),
Packit Service 4684c1
		     gnutls_certificate_type_get_name(cred->certs[i].
Packit Service 4684c1
						      cert_list[0].type));
Packit Service 4684c1
Packit Service 4684c1
		ret = cert_select_sign_algorithm(session,
Packit Service 4684c1
						 &cred->certs[i].cert_list[0],
Packit Service 4684c1
						 cred->certs[i].pkey,
Packit Service 4684c1
						 cs);
Packit Service 4684c1
		if (ret >= 0) {
Packit Service 4684c1
			idx = i;
Packit Service 4684c1
			_gnutls_debug_log("Selected (%s) cert based on ciphersuite %x.%x: %s\n",
Packit Service 4684c1
					  gnutls_pk_get_name(cred->certs[i].cert_list[0].pubkey->params.algo),
Packit Service 4684c1
					  (unsigned)cs->id[0],
Packit Service 4684c1
					  (unsigned)cs->id[1],
Packit Service 4684c1
					  cs->name);
Packit Service 4684c1
			/* found */
Packit Service 4684c1
			goto finished;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* store the certificate pointer for future use, in the handshake.
Packit Service 4684c1
	 * (This will allow not calling this callback again.)
Packit Service 4684c1
	 */
Packit Service 4684c1
 finished:
Packit Service 4684c1
	if (idx >= 0) {
Packit Service 4684c1
		gnutls_status_request_ocsp_func ocsp_func = NULL;
Packit Service 4684c1
		void *ocsp_ptr = NULL;
Packit Service 4684c1
		gnutls_ocsp_data_st *ocsp = NULL;
Packit Service 4684c1
		unsigned nocsp = 0;
Packit Service 4684c1
Packit Service 4684c1
		if (cred->certs[idx].ocsp_data_length > 0) {
Packit Service 4684c1
			ocsp = &cred->certs[idx].ocsp_data[0];
Packit Service 4684c1
			nocsp = cred->certs[idx].ocsp_data_length;
Packit Service 4684c1
		} else if (cred->glob_ocsp_func != NULL) {
Packit Service 4684c1
			ocsp_func = cred->glob_ocsp_func;
Packit Service 4684c1
			ocsp_ptr = cred->glob_ocsp_func_ptr;
Packit Service 4684c1
		} else if (cred->certs[idx].ocsp_func != NULL) {
Packit Service 4684c1
			ocsp_func = cred->certs[idx].ocsp_func;
Packit Service 4684c1
			ocsp_ptr = cred->certs[idx].ocsp_func_ptr;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		selected_certs_set(session,
Packit Service 4684c1
				   &cred->certs[idx].cert_list[0],
Packit Service 4684c1
				   cred->certs[idx].cert_list_length,
Packit Service 4684c1
				   ocsp, nocsp,
Packit Service 4684c1
				   cred->certs[idx].pkey, 0,
Packit Service 4684c1
				   ocsp_func,
Packit Service 4684c1
				   ocsp_ptr);
Packit Service 4684c1
	} else {
Packit Service 4684c1
		/* Certificate does not support REQUESTED_ALGO.  */
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int _gnutls_gen_dhe_signature(gnutls_session_t session,
Packit Service 4684c1
			      gnutls_buffer_st * data, uint8_t * plain,
Packit Service 4684c1
			      unsigned plain_size)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_pcert_st *apr_cert_list;
Packit Service 4684c1
	gnutls_privkey_t apr_pkey;
Packit Service 4684c1
	int apr_cert_list_length;
Packit Service 4684c1
	gnutls_datum_t signature = { NULL, 0 }, ddata;
Packit Service 4684c1
	gnutls_sign_algorithm_t sign_algo;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(ver == NULL))
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	ddata.data = plain;
Packit Service 4684c1
	ddata.size = plain_size;
Packit Service 4684c1
Packit Service 4684c1
	/* find the appropriate certificate */
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_get_selected_cert(session, &apr_cert_list,
Packit Service 4684c1
				       &apr_cert_list_length, &apr_pkey)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (apr_cert_list_length > 0) {
Packit Service 4684c1
		if ((ret =
Packit Service 4684c1
		     _gnutls_handshake_sign_data(session,
Packit Service 4684c1
						 &apr_cert_list[0],
Packit Service 4684c1
						 apr_pkey, &ddata,
Packit Service 4684c1
						 &signature, &sign_algo)) < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
	} else {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		ret = 0;	/* ANON-DH, do not put a signature - ILLEGAL! */
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		const sign_algorithm_st *aid;
Packit Service 4684c1
		uint8_t p[2];
Packit Service 4684c1
Packit Service 4684c1
		if (sign_algo == GNUTLS_SIGN_UNKNOWN) {
Packit Service 4684c1
			ret = GNUTLS_E_UNKNOWN_ALGORITHM;
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		aid = _gnutls_sign_to_tls_aid(sign_algo);
Packit Service 4684c1
		if (aid == NULL) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			ret = GNUTLS_E_UNKNOWN_ALGORITHM;
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		p[0] = aid->id[0];
Packit Service 4684c1
		p[1] = aid->id[1];
Packit Service 4684c1
Packit Service 4684c1
		ret = _gnutls_buffer_append_data(data, p, 2);
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
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    _gnutls_buffer_append_data_prefix(data, 16, signature.data,
Packit Service 4684c1
					      signature.size);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	_gnutls_free_datum(&signature);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data,
Packit Service 4684c1
			   size_t _data_size, gnutls_datum_t * vparams)
Packit Service 4684c1
{
Packit Service 4684c1
	int sigsize;
Packit Service 4684c1
	gnutls_datum_t signature;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	ssize_t data_size = _data_size;
Packit Service 4684c1
	gnutls_pcert_st peer_cert;
Packit Service 4684c1
	gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
Packit Service 4684c1
	const version_entry_st *ver = get_version(session);
Packit Service 4684c1
	gnutls_certificate_credentials_t cred;
Packit Service 4684c1
	unsigned vflags;
Packit Service 4684c1
	gnutls_certificate_type_t cert_type;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(info == NULL || info->ncerts == 0 || ver == NULL)) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		/* we need this in order to get peer's certificate */
Packit Service 4684c1
		return GNUTLS_E_INTERNAL_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	cred = (gnutls_certificate_credentials_t)
Packit Service 4684c1
	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
Packit Service 4684c1
	if (cred == NULL) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	vflags = cred->verify_flags | session->internals.additional_verify_flags;
Packit Service 4684c1
Packit Service 4684c1
	/* VERIFY SIGNATURE */
Packit Service 4684c1
	if (_gnutls_version_has_selectable_sighash(ver)) {
Packit Service 4684c1
		uint8_t id[2];
Packit Service 4684c1
Packit Service 4684c1
		DECR_LEN(data_size, 1);
Packit Service 4684c1
		id[0] = *data++;
Packit Service 4684c1
		DECR_LEN(data_size, 1);
Packit Service 4684c1
		id[1] = *data++;
Packit Service 4684c1
Packit Service 4684c1
		sign_algo = _gnutls_tls_aid_to_sign(id[0], id[1], ver);
Packit Service 4684c1
		if (sign_algo == GNUTLS_SIGN_UNKNOWN) {
Packit Service 4684c1
			_gnutls_debug_log("unknown signature %d.%d\n",
Packit Service 4684c1
					  (int)id[0], (int)id[1]);
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
	DECR_LEN(data_size, 2);
Packit Service 4684c1
	sigsize = _gnutls_read_uint16(data);
Packit Service 4684c1
	data += 2;
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN_FINAL(data_size, sigsize);
Packit Service 4684c1
	signature.data = data;
Packit Service 4684c1
	signature.size = sigsize;
Packit Service 4684c1
Packit Service 4684c1
	// Retrieve the negotiated certificate type
Packit Service 4684c1
	cert_type = get_certificate_type(session, GNUTLS_CTYPE_SERVER);
Packit Service 4684c1
Packit Service 4684c1
	if ((ret =
Packit Service 4684c1
	     _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info)) < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    _gnutls_handshake_verify_data(session, vflags, &peer_cert, vparams,
Packit Service 4684c1
					  &signature, sign_algo);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_pcert_deinit(&peer_cert);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}