|
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 |
}
|