unsigned int handshake_timeout_ms; /* timeout in milliseconds */
unsigned int record_timeout_ms; /* timeout in milliseconds */
+#define HSK_CRT_VRFY_EXPECTED 1
+#define HSK_CRT_SENT (1<<1)
+#define HSK_CRT_ASKED (1<<2)
+ unsigned hsk_flags; /* TLS1.3 only */
+
unsigned crt_requested; /* 1 if client auth was requested (i.e., client cert).
* In case of a server this holds 1 if we should wait
* for a client certificate verify
IMED_RET("send certificate", ret, 0);
/* fall through */
case STATE108:
- ret = _gnutls13_send_certificate_verify(session);
+ ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE108));
STATE = STATE108;
IMED_RET("send certificate verify", ret, 0);
/* fall through */
IMED_RET("send certificate", ret, 0);
/* fall through */
case STATE104:
- abort();
+ ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE104));
STATE = STATE104;
IMED_RET("send certificate verify", ret, 0);
/* fall through */
case STATE105:
- abort();
+ ret = _gnutls13_send_finished(session, AGAIN(STATE105));
STATE = STATE105;
IMED_RET("send finished", ret, 0);
/* fall through */
case STATE106:
- abort();
+ ret = _gnutls13_recv_certificate(session);
STATE = STATE106;
IMED_RET("recv certificate", ret, 0);
/* fall through */
case STATE107:
- abort();
+ ret = _gnutls13_recv_certificate_verify(session);
STATE = STATE107;
IMED_RET("recv certificate verify", ret, 0);
/* fall through */
case STATE108:
- ret = _gnutls_run_verify_callback(session, GNUTLS_SERVER);
+ ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT);
STATE = STATE108;
if (ret < 0)
return gnutls_assert_val(ret);
/* fall through */
case STATE109:
- abort();
+ ret = _gnutls13_recv_finished(session);
STATE = STATE109;
IMED_RET("recv finished", ret, 0);
/* fall through */
+ case STATE110:
+ ret =
+ generate_ap_traffic_keys(session);
+ STATE = STATE110;
+ IMED_RET("generate app keys", ret, 0);
STATE = STATE0;
break;
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
}
+ /* explicitly reset any false start flags */
+ session->internals.recv_state = RECV_STATE_0;
+ session->internals.initial_negotiation_completed = 1;
+
return 0;
}
}
/* Runs the certificate verification callback.
- * side is either GNUTLS_CLIENT or GNUTLS_SERVER.
+ * side is the side that we verify the certificate
+ * from (either GNUTLS_CLIENT or GNUTLS_SERVER).
*/
int _gnutls_run_verify_callback(gnutls_session_t session, unsigned int side)
{
return ret;
}
+
+int
+_gnutls13_handshake_sign_data(gnutls_session_t session,
+ gnutls_pcert_st * cert, gnutls_privkey_t pkey,
+ const gnutls_datum_t *context,
+ gnutls_datum_t * signature,
+ const gnutls_sign_entry_st *se)
+{
+ gnutls_datum_t p;
+ int ret;
+ gnutls_buffer_st buf;
+ uint8_t prefix[PREFIX_SIZE];
+
+ if (unlikely(se == NULL || se->hash == GNUTLS_DIG_SHA1 || se->pk == GNUTLS_PK_RSA))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ _gnutls_handshake_log
+ ("HSK[%p]: signing TLS 1.3 handshake data: using %s\n", session, se->name);
+
+ _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.length,
+ 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;
+
+ ret = gnutls_privkey_sign_data2(pkey, se->id, 0, &p, signature);
+ if (ret < 0) {
+ gnutls_assert();
+ }
+
+ ret = 0;
+ cleanup:
+ _gnutls_buffer_clear(&buf);
+
+ return ret;
+
+}
const gnutls_datum_t *signature,
const gnutls_sign_entry_st *se);
+int
+_gnutls13_handshake_sign_data(gnutls_session_t session,
+ gnutls_pcert_st * cert, gnutls_privkey_t pkey,
+ const gnutls_datum_t *context,
+ gnutls_datum_t * signature,
+ const gnutls_sign_entry_st *se);
+
#endif
{
int ret;
gnutls_buffer_st buf;
+ unsigned optional = 0;
- ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf);
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ /* if we didn't request a certificate, there will not be any */
+ if (session->internals.send_cert_req == 0)
+ return 0;
+
+ if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
+ optional = 1;
+ }
+
+ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, optional, &buf);
if (ret < 0)
return gnutls_assert_val(ret);
+ if (buf.length == 0 && optional) {
+ return 0;
+ }
+
if (buf.data[0] != 0) {
/* The context field must be empty during handshake */
gnutls_assert();
goto cleanup;
}
+ session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;
+
ret = 0;
cleanup:
if (ret < 0)
return gnutls_assert_val(ret);
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ /* if we didn't get a cert request there will not be any */
+ if (apr_cert_list_length == 0 ||
+ !(session->internals.hsk_flags & HSK_CRT_ASKED)) {
+ return 0;
+ }
+ }
+
ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
if (ret < 0)
return gnutls_assert_val(ret);
if (ret < 0)
return gnutls_assert_val(ret);
+ session->internals.hsk_flags |= HSK_CRT_ASKED;
+
return 0;
}
#include "ext/signature.h"
#include "algorithms.h"
#include "tls13-sig.h"
+#include "mbuffers.h"
#include "tls13/certificate_verify.h"
#define SRV_CTX "TLS 1.3, server CertificateVerify"
memset(&peer_cert, 0, sizeof(peer_cert));
+ /* this message is only expected if we have received
+ * a certificate message */
+ if (!(session->internals.hsk_flags & HSK_CRT_VRFY_EXPECTED))
+ return 0;
+
cred = (gnutls_certificate_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
if (unlikely(cred == NULL))
return ret;
}
-int _gnutls13_send_certificate_verify(gnutls_session_t session)
+int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again)
{
- return 0;
+ int ret;
+ gnutls_pcert_st *apr_cert_list;
+ gnutls_privkey_t apr_pkey;
+ int apr_cert_list_length;
+ mbuffer_st *bufel = NULL;
+ gnutls_buffer_st buf;
+ gnutls_datum_t sig = {NULL, 0};
+ gnutls_sign_algorithm_t algo;
+ const gnutls_sign_entry_st *se;
+
+ if (again == 0) {
+ _gnutls_buffer_init(&buf);
+
+ ret = _gnutls_get_selected_cert(session, &apr_cert_list,
+ &apr_cert_list_length, &apr_pkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (apr_cert_list_length == 0) {
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
+ } else {
+ /* if we didn't get a cert request there will not be any */
+ if (!(session->internals.hsk_flags & HSK_CRT_SENT))
+ return 0;
+ else
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
+ }
+
+ algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0);
+ if (algo == GNUTLS_SIGN_UNKNOWN)
+ return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ gnutls_sign_algorithm_set_server(session, algo);
+ else
+ gnutls_sign_algorithm_set_client(session, algo);
+
+ se = _gnutls_sign_to_entry(algo);
+
+ ret = _gnutls13_handshake_sign_data(session, &apr_cert_list[0], apr_pkey, &srv_ctx, &sig, se);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_buffer_append_data(&buf, se->aid.id, 2);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(&buf, 16, sig.data, sig.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ bufel = _gnutls_handshake_alloc(session, buf.length);
+ if (bufel == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ _mbuffer_set_udata_size(bufel, 0);
+ ret = _mbuffer_append_data(bufel, buf.data, buf.length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ _gnutls_buffer_clear(&buf);
+ gnutls_free(sig.data);
+ }
+
+ return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
+
+ cleanup:
+ gnutls_free(sig.data);
+ _gnutls_buffer_clear(&buf);
+ _mbuffer_xfree(&bufel);
+ return ret;
}
*/
int _gnutls13_recv_certificate_verify(gnutls_session_t session);
-int _gnutls13_send_certificate_verify(gnutls_session_t session);
+int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again);