/* * Copyright (C) 2000-2012 Free Software Foundation, Inc. * 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 * */ /* Contains functions that are supposed to pack and unpack session data, * before and after they are sent to the database backend. */ #include "gnutls_int.h" #ifdef ENABLE_SRP #include #endif #ifdef ENABLE_PSK #include #endif #include #include #include "errors.h" #include #include #include #include #include #include #include #include #include #include "tls13/session_ticket.h" static int pack_certificate_auth_info(gnutls_session_t, gnutls_buffer_st * packed_session); static int unpack_certificate_auth_info(gnutls_session_t, gnutls_buffer_st * packed_session); static int unpack_srp_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int pack_srp_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int unpack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int pack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int unpack_anon_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int pack_anon_auth_info(gnutls_session_t session, gnutls_buffer_st * packed_session); static int unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * packed_session); static int pack_security_parameters(gnutls_session_t session, gnutls_buffer_st * packed_session); static int tls13_unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * packed_session); static int tls13_pack_security_parameters(gnutls_session_t session, gnutls_buffer_st * packed_session); /* Since auth_info structures contain malloced data, this function * is required in order to pack these structures in a vector in * order to store them to the DB. * * packed_session will contain the session data. * * The data will be in a platform independent format. */ int _gnutls_session_pack(gnutls_session_t session, gnutls_datum_t * packed_session) { int ret; gnutls_buffer_st sb; uint8_t id; if (packed_session == NULL) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } _gnutls_buffer_init(&sb); id = gnutls_auth_get_type(session); BUFFER_APPEND_NUM(&sb, PACKED_SESSION_MAGIC); BUFFER_APPEND_NUM(&sb, session->security_parameters.timestamp); BUFFER_APPEND_NUM(&sb, session->internals.expire_time); BUFFER_APPEND(&sb, &id, 1); switch (id) { #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: ret = pack_srp_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: ret = pack_psk_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } break; #endif #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: ret = pack_anon_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } break; #endif case GNUTLS_CRD_CERTIFICATE: ret = pack_certificate_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } break; default: ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); goto fail; } /* Auth_info structures copied. Now copy security_parameters_st. * packed_session must have allocated space for the security parameters. */ ret = pack_security_parameters(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } if (session->security_parameters.pversion->tls13_sem) { ret = tls13_pack_security_parameters(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } } /* Extensions are re-negotiated in a resumed session under TLS 1.3 */ if (!session->security_parameters.pversion->tls13_sem) { ret = _gnutls_hello_ext_pack(session, &sb); if (ret < 0) { gnutls_assert(); goto fail; } } return _gnutls_buffer_to_datum(&sb, packed_session, 0); fail: _gnutls_buffer_clear(&sb); return ret; } /* Load session data from a buffer. */ int _gnutls_session_unpack(gnutls_session_t session, const gnutls_datum_t * packed_session) { int ret; gnutls_buffer_st sb; uint32_t magic; uint32_t expire_time; uint8_t id; _gnutls_buffer_init(&sb); if (packed_session == NULL || packed_session->size == 0) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_buffer_append_data(&sb, packed_session->data, packed_session->size); if (ret < 0) { gnutls_assert(); return ret; } if (session->key.auth_info != NULL) { _gnutls_free_auth_info(session); } BUFFER_POP_NUM(&sb, magic); if (magic != PACKED_SESSION_MAGIC) { ret = gnutls_assert_val(GNUTLS_E_DB_ERROR); goto error; } BUFFER_POP_NUM(&sb, session->internals.resumed_security_parameters. timestamp); BUFFER_POP_NUM(&sb, expire_time); (void) expire_time; BUFFER_POP(&sb, &id, 1); switch (id) { #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: ret = unpack_srp_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: ret = unpack_psk_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } break; #endif #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: ret = unpack_anon_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); return ret; } break; #endif case GNUTLS_CRD_CERTIFICATE: ret = unpack_certificate_auth_info(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } break; default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; goto error; } /* Auth_info structures copied. Now copy security_parameters_st. * packed_session must have allocated space for the security parameters. */ ret = unpack_security_parameters(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } if (session->internals.resumed_security_parameters.pversion->tls13_sem) { /* 'prf' will not be NULL at this point, else unpack_security_parameters() would have failed */ ret = tls13_unpack_security_parameters(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } } if (!session->internals.resumed_security_parameters.pversion->tls13_sem) { ret = _gnutls_hello_ext_unpack(session, &sb); if (ret < 0) { gnutls_assert(); goto error; } } ret = 0; error: _gnutls_buffer_clear(&sb); return ret; } /* * If we're using TLS 1.3 semantics, we might have TLS 1.3-specific data. * Format: * 4 bytes the total length * 4 bytes the ticket lifetime * 4 bytes the ticket age add value * 1 byte the ticket nonce length * x bytes the ticket nonce * 4 bytes the ticket length * x bytes the ticket * 1 bytes the resumption master secret length * x bytes the resumption master secret * 12 bytes the ticket arrival time * 4 bytes the max early data size * * We only store that info if we received a TLS 1.3 NewSessionTicket at some point. * If we didn't receive any NST then we cannot resume a TLS 1.3 session and hence * its nonsense to store all that info. */ static int tls13_pack_security_parameters(gnutls_session_t session, gnutls_buffer_st *ps) { int ret = 0; uint32_t length = 0; size_t length_pos; tls13_ticket_st *ticket = &session->internals.tls13_ticket; length_pos = ps->length; BUFFER_APPEND_NUM(ps, 0); if (ticket->ticket.data != NULL) { BUFFER_APPEND_NUM(ps, ticket->lifetime); length += 4; BUFFER_APPEND_NUM(ps, ticket->age_add); length += 4; BUFFER_APPEND_PFX1(ps, ticket->nonce, ticket->nonce_size); length += (1 + ticket->nonce_size); BUFFER_APPEND_PFX4(ps, ticket->ticket.data, ticket->ticket.size); length += (4 + ticket->ticket.size); BUFFER_APPEND_PFX1(ps, ticket->resumption_master_secret, ticket->prf->output_size); length += (1 + ticket->prf->output_size); BUFFER_APPEND_TS(ps, ticket->arrival_time); length += 12; BUFFER_APPEND_NUM(ps, session->security_parameters. max_early_data_size); length += 4; /* Overwrite the length field */ _gnutls_write_uint32(length, ps->data + length_pos); } return ret; } static int tls13_unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st *ps) { uint32_t ttl_len; tls13_ticket_st *ticket = &session->internals.tls13_ticket; gnutls_datum_t t; int ret = 0; BUFFER_POP_NUM(ps, ttl_len); if (ttl_len > 0) { BUFFER_POP_NUM(ps, ticket->lifetime); BUFFER_POP_NUM(ps, ticket->age_add); ret = _gnutls_buffer_pop_datum_prefix8(ps, &t); if (ret < 0 || t.size > sizeof(ticket->nonce)) { ret = GNUTLS_E_PARSING_ERROR; gnutls_assert(); goto error; } ticket->nonce_size = t.size; memcpy(ticket->nonce, t.data, t.size); BUFFER_POP_DATUM(ps, &ticket->ticket); ret = _gnutls_buffer_pop_datum_prefix8(ps, &t); if (ret < 0 || t.size > sizeof(ticket->resumption_master_secret)) { ret = GNUTLS_E_PARSING_ERROR; gnutls_assert(); goto error; } memcpy(ticket->resumption_master_secret, t.data, t.size); if (unlikely(session->internals.resumed_security_parameters.prf == NULL || session->internals.resumed_security_parameters.prf->output_size != t.size)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ticket->prf = session->internals.resumed_security_parameters.prf; BUFFER_POP_TS(ps, ticket->arrival_time); BUFFER_POP_NUM(ps, session->security_parameters. max_early_data_size); } error: return ret; } /* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * DH stuff * 2 bytes the size of secret key in bits * 4 bytes the size of the prime * x bytes the prime * 4 bytes the size of the generator * x bytes the generator * 4 bytes the size of the public key * x bytes the public key * RSA stuff * 4 bytes the size of the modulus * x bytes the modulus * 4 bytes the size of the exponent * x bytes the exponent * CERTIFICATES * 4 bytes the length of the certificate list * 4 bytes the size of first certificate * x bytes the certificate * and so on... */ static int pack_certificate_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { unsigned int i; int cur_size, ret; cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); int size_offset; size_offset = ps->length; BUFFER_APPEND_NUM(ps, 0); cur_size = ps->length; if (info) { BUFFER_APPEND_NUM(ps, info->dh.secret_bits); BUFFER_APPEND_PFX4(ps, info->dh.prime.data, info->dh.prime.size); BUFFER_APPEND_PFX4(ps, info->dh.generator.data, info->dh.generator.size); BUFFER_APPEND_PFX4(ps, info->dh.public_key.data, info->dh.public_key.size); BUFFER_APPEND_NUM(ps, info->ncerts); for (i = 0; i < info->ncerts; i++) { BUFFER_APPEND_PFX4(ps, info->raw_certificate_list[i]. data, info->raw_certificate_list[i]. size); } BUFFER_APPEND_NUM(ps, info->nocsp); for (i = 0; i < info->nocsp; i++) { BUFFER_APPEND_PFX4(ps, info->raw_ocsp_list[i]. data, info->raw_ocsp_list[i]. size); } } /* write the real size */ _gnutls_write_uint32(ps->length - cur_size, ps->data + size_offset); return 0; } /* Upack certificate info. */ static int unpack_certificate_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { int ret; unsigned int i = 0, j = 0; size_t pack_size; cert_auth_info_t info = NULL; unsigned cur_ncerts = 0; unsigned cur_nocsp = 0; BUFFER_POP_NUM(ps, pack_size); if (pack_size == 0) return 0; /* nothing to be done */ /* client and server have the same auth_info here */ ret = _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE, sizeof(cert_auth_info_st), 1); if (ret < 0) { gnutls_assert(); return ret; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); BUFFER_POP_NUM(ps, info->dh.secret_bits); BUFFER_POP_DATUM(ps, &info->dh.prime); BUFFER_POP_DATUM(ps, &info->dh.generator); BUFFER_POP_DATUM(ps, &info->dh.public_key); BUFFER_POP_NUM(ps, info->ncerts); if (info->ncerts > 0) { info->raw_certificate_list = gnutls_calloc(info->ncerts, sizeof(gnutls_datum_t)); if (info->raw_certificate_list == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } } for (i = 0; i < info->ncerts; i++) { BUFFER_POP_DATUM(ps, &info->raw_certificate_list[i]); cur_ncerts++; } /* read OCSP responses */ BUFFER_POP_NUM(ps, info->nocsp); if (info->nocsp > 0) { info->raw_ocsp_list = gnutls_calloc(info->nocsp, sizeof(gnutls_datum_t)); if (info->raw_ocsp_list == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } } for (i = 0; i < info->nocsp; i++) { BUFFER_POP_DATUM(ps, &info->raw_ocsp_list[i]); cur_nocsp++; } return 0; error: if (info) { _gnutls_free_datum(&info->dh.prime); _gnutls_free_datum(&info->dh.generator); _gnutls_free_datum(&info->dh.public_key); for (j = 0; j < cur_ncerts; j++) _gnutls_free_datum(&info->raw_certificate_list[j]); for (j = 0; j < cur_nocsp; j++) _gnutls_free_datum(&info->raw_ocsp_list[j]); gnutls_free(info->raw_certificate_list); gnutls_free(info->raw_ocsp_list); } return ret; } #ifdef ENABLE_SRP /* Packs the SRP session authentication data. */ /* Format: * 1 byte the credentials type * 4 bytes the size of the SRP username (x) * x bytes the SRP username */ static int pack_srp_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { srp_server_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP); int len, ret; int size_offset; size_t cur_size; const char *username = NULL; if (info) { if (info->username) { username = info->username; len = strlen(info->username) + 1; /* include the terminating null */ } else { username = "\0"; len = 1; } } else len = 0; size_offset = ps->length; BUFFER_APPEND_NUM(ps, 0); cur_size = ps->length; BUFFER_APPEND_PFX4(ps, username, len); /* write the real size */ _gnutls_write_uint32(ps->length - cur_size, ps->data + size_offset); return 0; } static int unpack_srp_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { size_t username_size; int ret; srp_server_auth_info_t info; BUFFER_POP_NUM(ps, username_size); if (username_size > MAX_USERNAME_SIZE + 1) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ret = _gnutls_auth_info_init(session, GNUTLS_CRD_SRP, sizeof(srp_server_auth_info_st), 1); if (ret < 0) return gnutls_assert_val(ret); info = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); gnutls_free(info->username); if (username_size == 0) { info->username = NULL; } else { info->username = gnutls_malloc(username_size); if (info->username == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } BUFFER_POP(ps, info->username, username_size); ret = 0; error: return ret; } #endif #ifdef ENABLE_ANON /* Packs the ANON session authentication data. */ /* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * 2 bytes the size of secret key in bits * 4 bytes the size of the prime * x bytes the prime * 4 bytes the size of the generator * x bytes the generator * 4 bytes the size of the public key * x bytes the public key */ static int pack_anon_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { int cur_size, ret; anon_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); int size_offset; size_offset = ps->length; BUFFER_APPEND_NUM(ps, 0); cur_size = ps->length; if (info) { BUFFER_APPEND_NUM(ps, info->dh.secret_bits); BUFFER_APPEND_PFX4(ps, info->dh.prime.data, info->dh.prime.size); BUFFER_APPEND_PFX4(ps, info->dh.generator.data, info->dh.generator.size); BUFFER_APPEND_PFX4(ps, info->dh.public_key.data, info->dh.public_key.size); } /* write the real size */ _gnutls_write_uint32(ps->length - cur_size, ps->data + size_offset); return 0; } static int unpack_anon_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { int ret; size_t pack_size; anon_auth_info_t info = NULL; BUFFER_POP_NUM(ps, pack_size); if (pack_size == 0) return 0; /* nothing to be done */ /* client and server have the same auth_info here */ ret = _gnutls_auth_info_init(session, GNUTLS_CRD_ANON, sizeof(anon_auth_info_st), 1); if (ret < 0) { gnutls_assert(); return ret; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); BUFFER_POP_NUM(ps, info->dh.secret_bits); BUFFER_POP_DATUM(ps, &info->dh.prime); BUFFER_POP_DATUM(ps, &info->dh.generator); BUFFER_POP_DATUM(ps, &info->dh.public_key); return 0; error: if (info) { _gnutls_free_datum(&info->dh.prime); _gnutls_free_datum(&info->dh.generator); _gnutls_free_datum(&info->dh.public_key); } return ret; } #endif /* ANON */ #ifdef ENABLE_PSK /* Packs the PSK session authentication data. */ /* Format: * 1 byte the credentials type * 4 bytes the size of the whole structure * * 4 bytes the size of the PSK username (x) * x bytes the PSK username * 2 bytes the size of secret key in bits * 4 bytes the size of the prime * x bytes the prime * 4 bytes the size of the generator * x bytes the generator * 4 bytes the size of the public key * x bytes the public key */ static int pack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { psk_auth_info_t info; int username_len; int hint_len, ret; int size_offset; size_t cur_size; info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); username_len = info->username_len; hint_len = info->hint_len + 1; /* include the terminating null */ size_offset = ps->length; BUFFER_APPEND_NUM(ps, 0); cur_size = ps->length; BUFFER_APPEND_PFX4(ps, info->username, username_len); BUFFER_APPEND_PFX4(ps, info->hint ? info->hint : "\0", hint_len); BUFFER_APPEND_NUM(ps, info->dh.secret_bits); BUFFER_APPEND_PFX4(ps, info->dh.prime.data, info->dh.prime.size); BUFFER_APPEND_PFX4(ps, info->dh.generator.data, info->dh.generator.size); BUFFER_APPEND_PFX4(ps, info->dh.public_key.data, info->dh.public_key.size); /* write the real size */ _gnutls_write_uint32(ps->length - cur_size, ps->data + size_offset); return 0; } static int unpack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * ps) { size_t username_size, hint_size; int ret; psk_auth_info_t info; unsigned pack_size; ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { gnutls_assert(); return ret; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); BUFFER_POP_NUM(ps, pack_size); if (pack_size == 0) return GNUTLS_E_INVALID_REQUEST; BUFFER_POP_NUM(ps, username_size); if (username_size > MAX_USERNAME_SIZE) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); gnutls_free(info->username); info->username = gnutls_malloc(username_size + 1); if (info->username == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); BUFFER_POP(ps, info->username, username_size); info->username[username_size] = 0; info->username_len = username_size; /* hint_size includes the terminating null */ BUFFER_POP_NUM(ps, hint_size); if (hint_size > MAX_USERNAME_SIZE + 1) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); gnutls_free(info->hint); info->hint = gnutls_malloc(hint_size); if (info->hint == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); BUFFER_POP(ps, info->hint, hint_size); info->hint_len = hint_size - 1; BUFFER_POP_NUM(ps, info->dh.secret_bits); BUFFER_POP_DATUM(ps, &info->dh.prime); BUFFER_POP_DATUM(ps, &info->dh.generator); BUFFER_POP_DATUM(ps, &info->dh.public_key); ret = 0; error: _gnutls_free_datum(&info->dh.prime); _gnutls_free_datum(&info->dh.generator); _gnutls_free_datum(&info->dh.public_key); return ret; } #endif /* Packs the security parameters. */ static int pack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps) { int ret; int size_offset; size_t cur_size; if (session->security_parameters.epoch_read != session->security_parameters.epoch_write && !(session->internals.hsk_flags & HSK_EARLY_START_USED)) { gnutls_assert(); return GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE; } ret = _gnutls_epoch_get(session, EPOCH_READ_CURRENT, NULL); if (ret < 0) { gnutls_assert(); return ret; } /* move after the auth info stuff. */ size_offset = ps->length; BUFFER_APPEND_NUM(ps, 0); cur_size = ps->length; BUFFER_APPEND_NUM(ps, session->security_parameters.entity); BUFFER_APPEND_NUM(ps, session->security_parameters.prf->id); BUFFER_APPEND_NUM(ps, session->security_parameters.client_auth_type); BUFFER_APPEND_NUM(ps, session->security_parameters.server_auth_type); BUFFER_APPEND(ps, &session->security_parameters.session_id_size, 1); BUFFER_APPEND(ps, session->security_parameters.session_id, session->security_parameters.session_id_size); BUFFER_APPEND_NUM(ps, session->security_parameters.pversion->id); BUFFER_APPEND_NUM(ps, session->security_parameters.client_ctype); BUFFER_APPEND_NUM(ps, session->security_parameters.server_ctype); BUFFER_APPEND(ps, session->security_parameters.cs->id, 2); /* if we are under TLS 1.3 do not pack keys or params negotiated using an extension * they are not necessary */ if (!session->security_parameters.pversion->tls13_sem) { BUFFER_APPEND_PFX1(ps, session->security_parameters.master_secret, GNUTLS_MASTER_SIZE); BUFFER_APPEND_PFX1(ps, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); BUFFER_APPEND_PFX1(ps, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); /* reset max_record_recv_size if it was negotiated * using the record_size_limit extension */ if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED) { BUFFER_APPEND_NUM(ps, session->security_parameters. max_user_record_send_size); BUFFER_APPEND_NUM(ps, session->security_parameters. max_user_record_recv_size); } else { BUFFER_APPEND_NUM(ps, session->security_parameters. max_record_recv_size); BUFFER_APPEND_NUM(ps, session->security_parameters. max_record_send_size); } if (session->security_parameters.grp) { BUFFER_APPEND_NUM(ps, session->security_parameters.grp->id); } else { BUFFER_APPEND_NUM(ps, 0); } BUFFER_APPEND_NUM(ps, session->security_parameters.server_sign_algo); BUFFER_APPEND_NUM(ps, session->security_parameters.client_sign_algo); BUFFER_APPEND_NUM(ps, session->security_parameters.ext_master_secret); BUFFER_APPEND_NUM(ps, session->security_parameters.etm); } _gnutls_write_uint32(ps->length - cur_size, ps->data + size_offset); return 0; } static int unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps) { size_t pack_size; int ret; unsigned version; gnutls_datum_t t; time_t timestamp; uint8_t cs[2]; BUFFER_POP_NUM(ps, pack_size); if (pack_size == 0) return GNUTLS_E_INVALID_REQUEST; timestamp = session->internals.resumed_security_parameters.timestamp; memset(&session->internals.resumed_security_parameters, 0, sizeof(session->internals.resumed_security_parameters)); session->internals.resumed_security_parameters.timestamp = timestamp; BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. entity); BUFFER_POP_NUM(ps, version); session->internals.resumed_security_parameters.prf = mac_to_entry(version); if (session->internals.resumed_security_parameters.prf == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. client_auth_type); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. server_auth_type); BUFFER_POP(ps, &session->internals.resumed_security_parameters. session_id_size, 1); BUFFER_POP(ps, session->internals.resumed_security_parameters. session_id, session->internals.resumed_security_parameters. session_id_size); BUFFER_POP_NUM(ps, version); session->internals.resumed_security_parameters.pversion = version_to_entry(version); if (session->internals.resumed_security_parameters.pversion == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. client_ctype); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. server_ctype); BUFFER_POP(ps, cs, 2); session->internals.resumed_security_parameters.cs = ciphersuite_to_entry(cs); if (session->internals.resumed_security_parameters.cs == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (!session->internals.resumed_security_parameters.pversion->tls13_sem) { /* master secret */ ret = _gnutls_buffer_pop_datum_prefix8(ps, &t); if (ret < 0) { ret = GNUTLS_E_PARSING_ERROR; gnutls_assert(); goto error; } if (t.size == GNUTLS_MASTER_SIZE) memcpy(session->internals.resumed_security_parameters.master_secret, t.data, t.size); /* client random */ ret = _gnutls_buffer_pop_datum_prefix8(ps, &t); if (ret < 0) { ret = GNUTLS_E_PARSING_ERROR; gnutls_assert(); goto error; } if (t.size == GNUTLS_RANDOM_SIZE) memcpy(session->internals.resumed_security_parameters.client_random, t.data, t.size); /* server random */ ret = _gnutls_buffer_pop_datum_prefix8(ps, &t); if (ret < 0) { ret = GNUTLS_E_PARSING_ERROR; gnutls_assert(); goto error; } if (t.size == GNUTLS_RANDOM_SIZE) memcpy(session->internals.resumed_security_parameters.server_random, t.data, t.size); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. max_record_send_size); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. max_record_recv_size); BUFFER_POP_NUM(ps, ret); session->internals.resumed_security_parameters.grp = _gnutls_id_to_group(ret); /* it can be null */ BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. server_sign_algo); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. client_sign_algo); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. ext_master_secret); BUFFER_POP_NUM(ps, session->internals.resumed_security_parameters. etm); if (session->internals.resumed_security_parameters. max_record_recv_size == 0 || session->internals.resumed_security_parameters. max_record_send_size == 0) { return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } } ret = 0; error: return ret; } /** * gnutls_session_set_premaster: * @session: is a #gnutls_session_t type. * @entity: GNUTLS_SERVER or GNUTLS_CLIENT * @version: the TLS protocol version * @kx: the key exchange method * @cipher: the cipher * @mac: the MAC algorithm * @comp: the compression method (ignored) * @master: the master key to use * @session_id: the session identifier * * This function sets the premaster secret in a session. This is * a function intended for exceptional uses. Do not use this * function unless you are implementing a legacy protocol. * Use gnutls_session_set_data() instead. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_session_set_premaster(gnutls_session_t session, unsigned int entity, gnutls_protocol_t version, gnutls_kx_algorithm_t kx, gnutls_cipher_algorithm_t cipher, gnutls_mac_algorithm_t mac, gnutls_compression_method_t comp, const gnutls_datum_t * master, const gnutls_datum_t * session_id) { int ret; uint8_t cs[2]; memset(&session->internals.resumed_security_parameters, 0, sizeof(session->internals.resumed_security_parameters)); session->internals.resumed_security_parameters.entity = entity; ret = _gnutls_cipher_suite_get_id(kx, cipher, mac, cs); if (ret < 0) return gnutls_assert_val(ret); session->internals.resumed_security_parameters.cs = ciphersuite_to_entry(cs); if (session->internals.resumed_security_parameters.cs == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); session->internals.resumed_security_parameters.client_ctype = DEFAULT_CERT_TYPE; session->internals.resumed_security_parameters.server_ctype = DEFAULT_CERT_TYPE; session->internals.resumed_security_parameters.pversion = version_to_entry(version); if (session->internals.resumed_security_parameters.pversion == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (session->internals.resumed_security_parameters.pversion->selectable_prf) session->internals.resumed_security_parameters.prf = mac_to_entry(session->internals.resumed_security_parameters.cs->prf); else session->internals.resumed_security_parameters.prf = mac_to_entry(GNUTLS_MAC_MD5_SHA1); if (session->internals.resumed_security_parameters.prf == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (master->size != GNUTLS_MASTER_SIZE) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); memcpy(session->internals.resumed_security_parameters. master_secret, master->data, master->size); if (session_id->size > GNUTLS_MAX_SESSION_ID) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); session->internals.resumed_security_parameters.session_id_size = session_id->size; memcpy(session->internals.resumed_security_parameters.session_id, session_id->data, session_id->size); session->internals.resumed_security_parameters. max_record_send_size = session->internals.resumed_security_parameters. max_record_recv_size = DEFAULT_MAX_RECORD_SIZE; session->internals.resumed_security_parameters.timestamp = gnutls_time(0); session->internals.resumed_security_parameters.grp = 0; session->internals.resumed_security_parameters.post_handshake_auth = 0; session->internals.premaster_set = 1; return 0; }