COBJECTS += system/keys-dummy.c
endif
-COBJECTS += tls13/encrypted_extensions.c tls13/encrypted_extensions.h
+COBJECTS += tls13/encrypted_extensions.c tls13/encrypted_extensions.h \
+ tls13/certificate_request.c tls13/certificate_request.h \
+ tls13/certificate_verify.c tls13/certificate_verify.h \
+ tls13-sig.c tls13-sig.h \
+ tls13/finished.c tls13/finished.h \
+ tls13/certificate.c tls13/certificate.h
if ENABLE_PKCS11
COBJECTS += pkcs11.c pkcs11x.c pkcs11_privkey.c pkcs11_write.c pkcs11_secret.c \
const char *_gnutls_x509_sign_to_oid(gnutls_pk_algorithm_t,
gnutls_digest_algorithm_t mac);
+const gnutls_sign_entry_st *
+_gnutls_tls_aid_to_sign_entry(uint8_t id0, uint8_t id1, const version_entry_st *ver);
+
gnutls_sign_algorithm_t
_gnutls_tls_aid_to_sign(uint8_t id0, uint8_t id1, const version_entry_st *ver);
const sign_algorithm_st *_gnutls_sign_to_tls_aid(gnutls_sign_algorithm_t
return ret;
GNUTLS_SIGN_LOOP(
- if (p->aid.id[0] == id0 &&
+ if (p->aid.id[0] == id0 &&
p->aid.id[1] == id1 &&
((p->aid.tls_sem & ver->tls_sig_sem) != 0)) {
}
);
-
return ret;
}
return ret;
}
+
+const gnutls_sign_entry_st *
+_gnutls_tls_aid_to_sign_entry(uint8_t id0, uint8_t id1, const version_entry_st *ver)
+{
+ if (id0 == 255 && id1 == 255)
+ return NULL;
+
+ GNUTLS_SIGN_LOOP(
+ if (p->aid.id[0] == id0 &&
+ p->aid.id[1] == id1 &&
+ ((p->aid.tls_sem & ver->tls_sig_sem) != 0)) {
+
+ return p;
+ }
+ );
+
+ return NULL;
+}
/* Copies data from a internal certificate struct (gnutls_pcert_st) to
* exported certificate struct (cert_auth_info_t)
*/
-static int copy_certificate_auth_info(cert_auth_info_t info, gnutls_pcert_st * certs, size_t ncerts, /* openpgp only */
- void *keyid)
+int _gnutls_copy_certificate_auth_info(cert_auth_info_t info, gnutls_pcert_st * certs, size_t ncerts)
{
/* Copy peer's information to auth_info_t
*/
goto cleanup;
}
- if ((ret =
- copy_certificate_auth_info(info,
+ ret =
+ _gnutls_copy_certificate_auth_info(info,
peer_certificate_list,
- peer_certificate_list_size,
- NULL)) < 0) {
+ peer_certificate_list_size);
+ if (ret < 0) {
gnutls_assert();
goto cleanup;
}
int *apr_cert_list_length,
gnutls_privkey_t * apr_pkey);
+int _gnutls_copy_certificate_auth_info(cert_auth_info_t info, gnutls_pcert_st * certs, size_t ncerts);
+
int
_gnutls_server_select_cert(gnutls_session_t session, const gnutls_cipher_suite_entry_st *cs);
void _gnutls_selected_certs_deinit(gnutls_session_t session);
_tls13_set_keys(gnutls_session_t session, record_parameters_st * params,
unsigned iv_size, unsigned key_size)
{
- uint8_t hs_ckey[MAX_HASH_SIZE];
- uint8_t hs_skey[MAX_HASH_SIZE];
uint8_t ckey_block[MAX_CIPHER_KEY_SIZE];
uint8_t civ_block[MAX_CIPHER_IV_SIZE];
uint8_t skey_block[MAX_CIPHER_KEY_SIZE];
ret = _tls13_derive_secret(session, HANDSHAKE_CLIENT_TRAFFIC_LABEL, sizeof(HANDSHAKE_CLIENT_TRAFFIC_LABEL)-1,
session->internals.handshake_hash_buffer.data,
- session->internals.handshake_hash_buffer.length, hs_ckey);
+ session->internals.handshake_hash_buffer.length, session->key.hs_ckey);
if (ret < 0)
return gnutls_assert_val(ret);
/* client keys */
- ret = _tls13_expand_secret(session, "key", 3, NULL, 0, hs_ckey, key_size, ckey_block);
+ ret = _tls13_expand_secret(session, "key", 3, NULL, 0, session->key.hs_ckey, key_size, ckey_block);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, hs_ckey, iv_size, civ_block);
+ ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, session->key.hs_ckey, iv_size, civ_block);
if (ret < 0)
return gnutls_assert_val(ret);
/* server keys */
ret = _tls13_derive_secret(session, HANDSHAKE_SERVER_TRAFFIC_LABEL, sizeof(HANDSHAKE_SERVER_TRAFFIC_LABEL)-1,
session->internals.handshake_hash_buffer.data,
- session->internals.handshake_hash_buffer.length, hs_skey);
+ session->internals.handshake_hash_buffer.length, session->key.hs_skey);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _tls13_expand_secret(session, "key", 3, NULL, 0, hs_skey, key_size, skey_block);
+ ret = _tls13_expand_secret(session, "key", 3, NULL, 0, session->key.hs_skey, key_size, skey_block);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, hs_skey, iv_size, siv_block);
+ ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, session->key.hs_skey, iv_size, siv_block);
if (ret < 0)
return gnutls_assert_val(ret);
* early_secret, client_early_traffic_secret, ... */
uint8_t temp_secret[MAX_HASH_SIZE];
unsigned temp_secret_size; /* depends on negotiated PRF size */
+ uint8_t hs_ckey[MAX_HASH_SIZE]; /* client_handshake_traffic_secret */
+ uint8_t hs_skey[MAX_HASH_SIZE]; /* server_handshake_traffic_secret */
/* For ECDH KX */
gnutls_pk_params_st ecdh_params; /* private part */
#include <dtls.h>
#include "secrets.h"
#include "tls13/encrypted_extensions.h"
+#include "tls13/certificate_request.h"
+#include "tls13/certificate_verify.h"
+#include "tls13/certificate.h"
+#include "tls13/finished.h"
static int generate_hs_traffic_keys(gnutls_session_t session);
IMED_RET("recv encrypted extensions", ret, 0);
/* fall through */
case STATE102:
- abort();
+ ret = _gnutls13_recv_certificate_request(session);
STATE = STATE102;
IMED_RET("recv certificate request", ret, 0);
/* fall through */
case STATE103:
- abort();
+ ret = _gnutls13_recv_certificate(session);
STATE = STATE103;
IMED_RET("recv certificate", ret, 0);
/* fall through */
case STATE104:
- abort();
+ ret = _gnutls13_recv_certificate_verify(session);
STATE = STATE104;
IMED_RET("recv server certificate verify", ret, 0);
/* fall through */
return gnutls_assert_val(ret);
FALLTHROUGH;
case STATE106:
- abort();
+ ret = _gnutls13_recv_finished(session);
STATE = STATE106;
IMED_RET("recv finished", ret, 0);
/* fall through */
case STATE107:
- abort();
+ ret = _gnutls13_send_certificate(session);
STATE = STATE107;
IMED_RET("send certificate", ret, 0);
/* fall through */
case STATE108:
- abort();
+ ret = _gnutls13_send_certificate_verify(session);
STATE = STATE108;
IMED_RET("send certificate verify", ret, 0);
/* fall through */
case STATE109:
- abort();
+ ret = _gnutls13_send_finished(session, AGAIN(STATE109));
STATE = STATE109;
IMED_RET("send finished", ret, 0);
**/
void gnutls_pcert_deinit(gnutls_pcert_st * pcert)
{
- gnutls_pubkey_deinit(pcert->pubkey);
+ if (pcert->pubkey)
+ gnutls_pubkey_deinit(pcert->pubkey);
pcert->pubkey = NULL;
_gnutls_free_datum(&pcert->cert);
}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include <auth/cert.h>
+#include <algorithms.h>
+#include <ext/signature.h>
+#include <abstract_int.h>
+#include "tls13-sig.h"
+#include "hash_int.h"
+
+#undef PREFIX_SIZE
+#define PREFIX_SIZE 64
+#if PREFIX_SIZE < MAX_HASH_SIZE
+/* we assume later that prefix is sufficient to store hash output */
+# error Need to modify code
+#endif
+
+int
+_gnutls13_handshake_verify_data(gnutls_session_t session,
+ unsigned verify_flags,
+ gnutls_pcert_st *cert,
+ const gnutls_datum_t *context,
+ const gnutls_datum_t *signature,
+ const gnutls_sign_entry_st *se)
+{
+ int ret;
+ const version_entry_st *ver = get_version(session);
+ gnutls_buffer_st buf;
+ uint8_t prefix[PREFIX_SIZE];
+ gnutls_datum_t p;
+
+ _gnutls_handshake_log
+ ("HSK[%p]: verifying TLS 1.3 handshake data using %s\n", session,
+ se->name);
+
+ ret =
+ _gnutls_pubkey_compatible_with_sig(session,
+ cert->pubkey, ver,
+ se->id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_session_sign_algo_enabled(session, se->id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (se->hash == GNUTLS_DIG_SHA1) /* explicitly prohibited */
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ if (se->pk == GNUTLS_PK_RSA) /* explicitly prohibited */
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ _gnutls_buffer_init(&buf);
+
+ memset(prefix, 0x20, sizeof(prefix));
+ ret = _gnutls_buffer_append_data(&buf, prefix, sizeof(prefix));
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(&buf, context->data, context->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(&buf, "\x00", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_hash_fast(session->security_parameters.prf->id,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer_prev_len,
+ prefix);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(&buf, prefix, session->security_parameters.prf->output_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ p.data = buf.data;
+ p.size = buf.length;
+
+ /* Here we intentionally enable flag GNUTLS_VERIFY_ALLOW_BROKEN
+ * because we have checked whether the currently used signature
+ * algorithm is allowed in the session. */
+ ret = gnutls_pubkey_verify_data2(cert->pubkey, se->id,
+ verify_flags|GNUTLS_VERIFY_ALLOW_BROKEN,
+ &p, signature);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ _gnutls_buffer_clear(&buf);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef _TLS13_SIG_H
+# define _TLS13_SIG_H
+
+#include "gnutls_int.h"
+
+int
+_gnutls13_handshake_verify_data(gnutls_session_t session,
+ unsigned verify_flags,
+ gnutls_pcert_st *cert,
+ const gnutls_datum_t *context,
+ const gnutls_datum_t *signature,
+ const gnutls_sign_entry_st *se);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "extv.h"
+#include "handshake.h"
+#include "tls13/certificate.h"
+#include "auth/cert.h"
+
+static int parse_cert_extension(void *ctx, uint16_t tls_id, const uint8_t *data, int data_size);
+static int parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size);
+
+int _gnutls13_recv_certificate(gnutls_session_t session)
+{
+ int ret;
+ gnutls_buffer_st buf;
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (buf.data[0] != 0) {
+ /* The context field must be empty during handshake */
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto cleanup;
+ }
+
+ /* buf.length is positive */
+ buf.data++;
+ buf.length--;
+
+ _gnutls_handshake_log("HSK[%p]: parsing certificate message\n", session);
+
+ ret = parse_cert_list(session, buf.data, buf.length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+
+ _gnutls_buffer_clear(&buf);
+ return ret;
+}
+
+static int parse_cert_extension(void *ctx, uint16_t tls_id, const uint8_t *data, int data_size)
+{
+ /* ignore all extensions */
+ return 0;
+}
+
+static int
+parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size)
+{
+ int len, ret;
+ uint8_t *p = data;
+ cert_auth_info_t info;
+ gnutls_certificate_credentials_t cred;
+ ssize_t dsize = data_size, size;
+ int i;
+ gnutls_pcert_st *peer_certificate_list;
+ size_t peer_certificate_list_size = 0, j, x;
+ gnutls_datum_t tmp;
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ if ((ret =
+ _gnutls_auth_info_set(session, GNUTLS_CRD_CERTIFICATE,
+ sizeof(cert_auth_info_st), 1)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
+
+ if (data == NULL || data_size == 0) {
+ gnutls_assert();
+ /* no certificate was sent */
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ DECR_LEN(dsize, 3);
+ size = _gnutls_read_uint24(p);
+ p += 3;
+
+ if (size != dsize)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (size == 0) {
+ gnutls_assert();
+ /* no certificate was sent */
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ i = dsize;
+ while (i > 0) {
+ DECR_LEN(dsize, 3);
+ len = _gnutls_read_uint24(p);
+ p += 3;
+ DECR_LEN(dsize, len);
+ p += len;
+ i -= len + 3;
+
+ DECR_LEN(dsize, 2);
+ len = _gnutls_read_uint16(p);
+ DECR_LEN(dsize, len);
+
+ i -= len + 2;
+
+ peer_certificate_list_size++;
+ }
+
+ if (dsize != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (peer_certificate_list_size == 0) {
+ gnutls_assert();
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ /* Ok we now allocate the memory to hold the
+ * certificate list
+ */
+
+ peer_certificate_list =
+ gnutls_calloc(1,
+ sizeof(gnutls_pcert_st) *
+ (peer_certificate_list_size));
+ if (peer_certificate_list == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ p = data+3;
+
+ /* Now we start parsing the list (again).
+ * We don't use DECR_LEN since the list has
+ * been parsed before.
+ */
+
+ for (j = 0; j < peer_certificate_list_size; j++) {
+ len = _gnutls_read_uint24(p);
+ p += 3;
+
+ tmp.size = len;
+ tmp.data = p;
+
+ ret =
+ gnutls_pcert_import_x509_raw(&peer_certificate_list
+ [j], &tmp,
+ GNUTLS_X509_FMT_DER, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_debug_log("error importing certificate[%d]: %s\n", (int)j, gnutls_strerror(ret));
+ peer_certificate_list_size = j;
+ ret = GNUTLS_E_CERTIFICATE_ERROR;
+ goto cleanup;
+ }
+
+ p += len;
+
+ len = _gnutls_read_uint16(p);
+ p += 2;
+
+ /* FIXME: properly parse extensions */
+ ret = _gnutls_extv_parse(NULL, parse_cert_extension, p, len);
+ if (ret < 0) {
+ gnutls_assert();
+ peer_certificate_list_size = j+1;
+ goto cleanup;
+ }
+ }
+
+ ret =
+ _gnutls_copy_certificate_auth_info(info,
+ peer_certificate_list,
+ peer_certificate_list_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ for(x=0;x<peer_certificate_list_size;x++)
+ gnutls_pcert_deinit(&peer_certificate_list[x]);
+ gnutls_free(peer_certificate_list);
+ return ret;
+
+}
+
+int _gnutls13_send_certificate(gnutls_session_t session)
+{
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+int _gnutls13_recv_certificate(gnutls_session_t session);
+int _gnutls13_send_certificate(gnutls_session_t session);
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "extv.h"
+#include "handshake.h"
+#include "tls13/certificate_request.h"
+
+static
+int parse_cert_extension(void *ctx, uint16_t tls_id, const uint8_t *data, int data_size)
+{
+ /* ignore all exts */
+ return 0;
+}
+
+int _gnutls13_recv_certificate_request(gnutls_session_t session)
+{
+ int ret;
+ gnutls_buffer_st buf;
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST, 1, &buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* if not received */
+ if (buf.length == 0) {
+ _gnutls_buffer_clear(&buf);
+ return 0;
+ }
+
+ _gnutls_handshake_log("HSK[%p]: parsing certificate request\n", session);
+
+ if (buf.data[0] != 0) {
+ /* The context field must be empty during handshake */
+ gnutls_assert();
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+
+ /* buf.length is positive */
+ buf.data++;
+ buf.length--;
+
+ ret = _gnutls_extv_parse(NULL, parse_cert_extension, buf.data, buf.length);
+ _gnutls_buffer_clear(&buf);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+int _gnutls13_recv_certificate_request(gnutls_session_t session);
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "handshake.h"
+#include "auth/cert.h"
+#include "ext/signature.h"
+#include "algorithms.h"
+#include "tls13-sig.h"
+#include "tls13/certificate_verify.h"
+
+#define SRV_CTX "TLS 1.3, server CertificateVerify"
+static const gnutls_datum_t srv_ctx = {
+ (void*)SRV_CTX, sizeof(SRV_CTX)-1
+};
+
+int _gnutls13_recv_certificate_verify(gnutls_session_t session)
+{
+ int ret;
+ gnutls_buffer_st buf;
+ const gnutls_sign_entry_st *se;
+ gnutls_datum_t sig_data;
+ gnutls_certificate_credentials_t cred;
+ unsigned vflags;
+ gnutls_pcert_st peer_cert;
+ cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
+
+ memset(&peer_cert, 0, sizeof(peer_cert));
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (unlikely(cred == NULL))
+ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
+ if (unlikely(info == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, 0, &buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_handshake_log("HSK[%p]: parsing certificate verify\n", session);
+
+ if (buf.length < 2) {
+ gnutls_assert();
+ ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ goto cleanup;
+ }
+
+ se = _gnutls_tls_aid_to_sign_entry(buf.data[0], buf.data[1], get_version(session));
+ if (se == NULL) {
+ _gnutls_handshake_log("found unsupported signature (%d.%d)\n", (int)buf.data[0], (int)buf.data[1]);
+ ret = gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ goto cleanup;
+ }
+
+ gnutls_sign_algorithm_set_server(session, se->id);
+
+ buf.data+=2;
+ buf.length-=2;
+
+ /* we check during verification whether the algorithm is enabled */
+
+ ret = _gnutls_buffer_pop_datum_prefix16(&buf, &sig_data);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (sig_data.size == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Verify the signature */
+ ret = _gnutls_get_auth_info_pcert(&peer_cert, session->security_parameters.cert_type, info);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ vflags = cred->verify_flags | session->internals.additional_verify_flags;
+
+ ret = _gnutls13_handshake_verify_data(session, vflags, &peer_cert, &srv_ctx, &sig_data, se);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (buf.length > 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ gnutls_pcert_deinit(&peer_cert);
+ _gnutls_buffer_clear(&buf);
+ return ret;
+}
+
+int _gnutls13_send_certificate_verify(gnutls_session_t session)
+{
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+int _gnutls13_recv_certificate_verify(gnutls_session_t session);
+int _gnutls13_send_certificate_verify(gnutls_session_t session);
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "handshake.h"
+#include "tls13/finished.h"
+#include "mem.h"
+#include "mbuffers.h"
+#include "secrets.h"
+
+int _gnutls13_recv_finished(gnutls_session_t session)
+{
+ int ret;
+ gnutls_buffer_st buf;
+ uint8_t fkey[MAX_HASH_SIZE];
+ uint8_t ts_hash[MAX_HASH_SIZE];
+ uint8_t verifier[MAX_HASH_SIZE];
+ const uint8_t *base_key;
+ unsigned hash_size = session->security_parameters.prf->output_size;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ base_key = session->key.hs_skey;
+ else
+ base_key = session->key.hs_ckey;
+
+ ret = _tls13_expand_secret(session, "finished", 8, NULL, 0, base_key,
+ hash_size, fkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = gnutls_hash_fast(session->security_parameters.prf->id,
+ session->internals.handshake_hash_buffer.data,
+ /* we haven't yet processed the finished message */
+ session->internals.handshake_hash_buffer.length,
+ ts_hash);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_hmac_fast(session->security_parameters.prf->id,
+ fkey, hash_size,
+ ts_hash, hash_size,
+ verifier);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED, 0, &buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_handshake_log("HSK[%p]: parsing finished\n", session);
+
+ if (buf.length != hash_size)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+# warning This is unsafe for production builds
+#else
+ if (safe_memcmp(verifier, buf.data, buf.length) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_ERROR_IN_FINISHED_PACKET;
+ }
+#endif
+
+ ret = 0;
+cleanup:
+
+ _gnutls_buffer_clear(&buf);
+ return ret;
+}
+
+int _gnutls13_send_finished(gnutls_session_t session, unsigned again)
+{
+ int ret;
+ uint8_t fkey[MAX_HASH_SIZE];
+ uint8_t ts_hash[MAX_HASH_SIZE];
+ uint8_t verifier[MAX_HASH_SIZE];
+ mbuffer_st *bufel = NULL;
+ const uint8_t *base_key;
+ unsigned hash_size = session->security_parameters.prf->output_size;
+
+ if (again == 0) {
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ base_key = session->key.hs_ckey;
+ else
+ base_key = session->key.hs_skey;
+
+ ret = _tls13_expand_secret(session, "finished", 8, NULL, 0, base_key,
+ hash_size, fkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = gnutls_hash_fast(session->security_parameters.prf->id,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer.length,
+ ts_hash);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_hmac_fast(session->security_parameters.prf->id,
+ fkey, hash_size,
+ ts_hash, hash_size,
+ verifier);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ _gnutls_handshake_log("HSK[%p]: sending finished\n", session);
+
+ bufel = _gnutls_handshake_alloc(session, hash_size);
+ if (bufel == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _mbuffer_set_udata_size(bufel, 0);
+ ret = _mbuffer_append_data(bufel, verifier, hash_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_FINISHED);
+
+cleanup:
+ _mbuffer_xfree(&bufel);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+int _gnutls13_recv_finished(gnutls_session_t session);
+int _gnutls13_send_finished(gnutls_session_t session, unsigned again);