/* returns ciphertext which contains the headers too. This also * calculates the size in the header field. * * If random pad != 0 then the random pad data will be appended. */ int _gnutls_encrypt (gnutls_session_t session, const opaque * headers, size_t headers_size, const opaque * data, size_t data_size, opaque * ciphertext, size_t ciphertext_size, content_type_t type, record_parameters_st * params) { gnutls_datum_t comp; int free_comp = 0; int ret; if (data_size == 0 || is_write_comp_null (params) == 0) { comp.data = (opaque*)data; comp.size = data_size; } else { /* Here comp is allocated and must be * freed. */ free_comp = 1; comp.size = ciphertext_size - headers_size; comp.data = gnutls_malloc(comp.size); if (comp.data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ret = _gnutls_compress( ¶ms->write.compression_state, data, data_size, comp.data, comp.size); if (ret < 0) { gnutls_free(comp.data); return gnutls_assert_val(ret); } comp.size = ret; } ret = compressed_to_ciphertext (session, &ciphertext[headers_size], ciphertext_size - headers_size, &comp, type, params); if (free_comp) gnutls_free(comp.data); if (ret < 0) return gnutls_assert_val(ret); /* copy the headers */ memcpy (ciphertext, headers, headers_size); if(IS_DTLS(session)) _gnutls_write_uint16 (ret, &ciphertext[11]); else _gnutls_write_uint16 (ret, &ciphertext[3]); return ret + headers_size; }
static int pack_ticket(gnutls_session_t session, tls13_ticket_st *ticket, gnutls_datum_t *packed) { uint8_t *p; gnutls_datum_t state; int ret; ret = _gnutls_session_pack(session, &state); if (ret < 0) return gnutls_assert_val(ret); packed->size = 2 + 4 + 4 + 1 + ticket->prf->output_size + 1 + ticket->nonce_size + 2 + state.size + 12; packed->data = gnutls_malloc(packed->size); if (!packed->data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } p = packed->data; _gnutls_write_uint16(ticket->prf->id, p); p += 2; _gnutls_write_uint32(ticket->age_add, p); p += 4; _gnutls_write_uint32(ticket->lifetime, p); p += 4; *p = ticket->prf->output_size; p += 1; memcpy(p, ticket->resumption_master_secret, ticket->prf->output_size); p += ticket->prf->output_size; *p = ticket->nonce_size; p += 1; memcpy(p, ticket->nonce, ticket->nonce_size); p += ticket->nonce_size; _gnutls_write_uint16(state.size, p); p += 2; memcpy(p, state.data, state.size); p += state.size; _gnutls_write_uint32((uint64_t) ticket->creation_time.tv_sec >> 32, p); p += 4; _gnutls_write_uint32(ticket->creation_time.tv_sec & 0xFFFFFFFF, p); p += 4; _gnutls_write_uint32(ticket->creation_time.tv_nsec, p); ret = 0; cleanup: gnutls_free(state.data); return ret; }
/* Set the PSK premaster secret. */ int _gnutls_set_psk_session_key (gnutls_session_t session, gnutls_datum_t * ppsk /* key */, gnutls_datum_t * dh_secret) { gnutls_datum_t pwd_psk = { NULL, 0 }; size_t dh_secret_size; uint8_t * p; int ret; if (dh_secret == NULL) dh_secret_size = ppsk->size; else dh_secret_size = dh_secret->size; /* set the session key */ session->key.key.size = 4 + dh_secret_size + ppsk->size; session->key.key.data = gnutls_malloc (session->key.key.size); if (session->key.key.data == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* format of the premaster secret: * (uint16_t) psk_size * psk_size bytes of (0)s * (uint16_t) psk_size * the psk */ p = session->key.key.data; _gnutls_write_uint16 (dh_secret_size, p); p+=2; if (dh_secret == NULL) memset (p, 0, dh_secret_size); else memcpy (p, dh_secret->data, dh_secret->size); p += dh_secret_size; _gnutls_write_uint16 (ppsk->size, p); if (ppsk->data != NULL) memcpy (p+2, ppsk->data, ppsk->size); ret = 0; error: _gnutls_free_datum (&pwd_psk); return ret; }
/* returns ciphertext which contains the headers too. This also * calculates the size in the header field. * */ int _gnutls_encrypt(gnutls_session_t session, const uint8_t *data, size_t data_size, size_t min_pad, mbuffer_st *bufel, content_type_t type, record_parameters_st *params) { gnutls_datum_t plaintext; const version_entry_st *vers = get_version(session); int ret; plaintext.data = (uint8_t *) data; plaintext.size = data_size; if (vers && vers->tls13_sem) { /* it fills the header, as it is included in the authenticated * data of the AEAD cipher. */ ret = encrypt_packet_tls13(session, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel), &plaintext, min_pad, type, params); if (ret < 0) return gnutls_assert_val(ret); } else { ret = encrypt_packet(session, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size (bufel), &plaintext, min_pad, type, params); if (ret < 0) return gnutls_assert_val(ret); } if (IS_DTLS(session)) _gnutls_write_uint16(ret, ((uint8_t *) _mbuffer_get_uhead_ptr(bufel)) + 11); else _gnutls_write_uint16(ret, ((uint8_t *) _mbuffer_get_uhead_ptr(bufel)) + 3); _mbuffer_set_udata_size(bufel, ret); _mbuffer_set_uhead_size(bufel, 0); return _mbuffer_get_udata_size(bufel); }
void _gnutls_write_datum16 (opaque * dest, gnutls_datum_t dat) { _gnutls_write_uint16 (dat.size, dest); if (dat.data != NULL) memcpy (&dest[2], dat.data, dat.size); }
/* generates a SignatureAndHashAlgorithm structure with length as prefix * by using the setup priorities. */ int _gnutls_sign_algorithm_write_params (gnutls_session_t session, opaque * data, size_t max_data_size) { opaque *p = data; int len, i, j; sign_algorithm_st aid; len = session->internals.priorities.sign_algo.algorithms * 2; if (max_data_size < len + 2) { gnutls_assert (); return GNUTLS_E_SHORT_MEMORY_BUFFER; } _gnutls_write_uint16 (len, p); p += 2; for (i = j = 0; i < len; i += 2, j++) { aid = _gnutls_sign_to_tls_aid (session->internals.priorities. sign_algo.priority[j]); *p = aid.hash_algorithm; p++; *p = aid.sign_algorithm; p++; } return len + 2; }
int _gnutls_epoch_alloc (gnutls_session_t session, uint16_t epoch, record_parameters_st ** out) { record_parameters_st **slot; _gnutls_record_log ("REC[%p]: Allocating epoch #%u\n", session, epoch); slot = epoch_get_slot (session, epoch); /* If slot out of range or not empty. */ if (slot == NULL) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); if (*slot != NULL) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); *slot = gnutls_calloc (1, sizeof (record_parameters_st)); if (*slot == NULL) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); (*slot)->epoch = epoch; (*slot)->cipher_algorithm = GNUTLS_CIPHER_UNKNOWN; (*slot)->mac_algorithm = GNUTLS_MAC_UNKNOWN; (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN; if (IS_DTLS (session)) _gnutls_write_uint16 (epoch, UINT64DATA((*slot)->write.sequence_number)); if (out != NULL) *out = *slot; return 0; }
int _gnutls_buffer_append_prefix (gnutls_buffer_st * buf, int pfx_size, size_t data_size) { opaque ss[4]; if (pfx_size == 32) { _gnutls_write_uint32 (data_size, ss); pfx_size = 4; } else if (pfx_size == 24) { _gnutls_write_uint24 (data_size, ss); pfx_size = 3; } else if (pfx_size == 16) { _gnutls_write_uint16 (data_size, ss); pfx_size = 2; } else if (pfx_size == 8) { ss[0] = data_size; pfx_size = 1; } else return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); return _gnutls_buffer_append_data (buf, ss, pfx_size); }
/* returns ciphertext which contains the headers too. This also * calculates the size in the header field. * * If random pad != 0 then the random pad data will be appended. */ int _gnutls_encrypt (gnutls_session_t session, const opaque * headers, size_t headers_size, const opaque * data, size_t data_size, opaque * ciphertext, size_t ciphertext_size, content_type_t type, int random_pad, record_parameters_st * params) { gnutls_datum_t plain; gnutls_datum_t comp; int ret; int free_comp = 1; plain.data = (opaque *) data; plain.size = data_size; if (plain.size == 0 || is_write_comp_null (session) == 0) { comp = plain; free_comp = 0; } else { /* Here comp is allocated and must be * freed. */ ret = _gnutls_m_plaintext2compressed (session, &comp, &plain, params); if (ret < 0) { gnutls_assert (); return ret; } } ret = _gnutls_compressed2ciphertext (session, &ciphertext[headers_size], ciphertext_size - headers_size, comp, type, random_pad, params); if (free_comp) _gnutls_free_datum (&comp); if (ret < 0) { gnutls_assert (); return ret; } /* copy the headers */ memcpy (ciphertext, headers, headers_size); _gnutls_write_uint16 (ret, &ciphertext[3]); return ret + headers_size; }
/* Set the PSK premaster secret. */ static int set_rsa_psk_session_key(gnutls_session_t session, gnutls_datum_t * ppsk, gnutls_datum_t * rsa_secret) { unsigned char *p; size_t rsa_secret_size; int ret; rsa_secret_size = rsa_secret->size; /* set the session key */ session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size; session->key.key.data = gnutls_malloc(session->key.key.size); if (session->key.key.data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* format of the premaster secret: * (uint16_t) other_secret size (48) * other_secret: 2 byte version + 46 byte random * (uint16_t) psk_size * the psk */ _gnutls_write_uint16(rsa_secret_size, session->key.key.data); memcpy(&session->key.key.data[2], rsa_secret->data, rsa_secret->size); p = &session->key.key.data[rsa_secret_size + 2]; _gnutls_write_uint16(ppsk->size, p); if (ppsk->data != NULL) memcpy(p + 2, ppsk->data, ppsk->size); ret = 0; error: return ret; }
/* 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_datum_t * packed_session) { anon_auth_info_t info = _gnutls_get_auth_info (session); int pos = 0; size_t pack_size; if (info == NULL && session->key->auth_info_size != 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (info) pack_size = 2 + 4 * 3 + info->dh.prime.size + info->dh.generator.size + info->dh.public_key.size; else pack_size = 0; packed_session->size = PACK_HEADER_SIZE + pack_size + sizeof (uint32_t); /* calculate the size and allocate the data. */ packed_session->data = gnutls_malloc (packed_session->size + MAX_SEC_PARAMS); if (packed_session->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } packed_session->data[0] = GNUTLS_CRD_ANON; _gnutls_write_uint32 (pack_size, &packed_session->data[PACK_HEADER_SIZE]); pos += 4 + PACK_HEADER_SIZE; if (pack_size > 0) { _gnutls_write_uint16 (info->dh.secret_bits, &packed_session->data[pos]); pos += 2; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.prime); pos += 4 + info->dh.prime.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.generator); pos += 4 + info->dh.generator.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.public_key); pos += 4 + info->dh.public_key.size; } return 0; }
int oprfi_send_server (gnutls_session_t session, opaque * data, size_t _data_size) { opaque *p = data; int ret; ssize_t data_size = _data_size; size_t len; if (!session->security_parameters.extensions.oprfi_client || !session->internals.oprfi_cb) return 0; /* Allocate buffer for outgoing data. */ session->security_parameters.extensions.oprfi_server_len = session->security_parameters.extensions.oprfi_client_len; session->security_parameters.extensions.oprfi_server = gnutls_malloc (session->security_parameters.extensions.oprfi_server_len); if (!session->security_parameters.extensions.oprfi_server) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* Get outgoing data. */ ret = session->internals.oprfi_cb (session, session->internals.oprfi_userdata, session->security_parameters.extensions.oprfi_client_len, session->security_parameters.extensions.oprfi_client, session->security_parameters.extensions.oprfi_server); if (ret < 0) { gnutls_assert (); gnutls_free (session->security_parameters.extensions.oprfi_server); return ret; } DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER); _gnutls_write_uint16 (session->security_parameters.extensions. oprfi_server_len, p); p += 2; DECR_LENGTH_RET (data_size, session->security_parameters.extensions.oprfi_server_len, GNUTLS_E_SHORT_MEMORY_BUFFER); memcpy (p, session->security_parameters.extensions.oprfi_server, session->security_parameters.extensions.oprfi_server_len); return 2 + session->security_parameters.extensions.oprfi_server_len; }
static int add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list, gnutls_x509_crt_t ca) { gnutls_datum_t tmp; size_t newsize; unsigned char *newdata, *p; /* Add DN of the last added CAs to the RDN sequence * This will be sent to clients when a certificate * request message is sent. */ /* FIXME: in case of a client it is not needed * to do that. This would save time and memory. * However we don't have that information available * here. * Further, this function is now much more efficient, * so optimizing that is less important. */ tmp.data = ca->raw_dn.data; tmp.size = ca->raw_dn.size; newsize = list->x509_rdn_sequence.size + 2 + tmp.size; if (newsize < list->x509_rdn_sequence.size) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } newdata = gnutls_realloc_fast(list->x509_rdn_sequence.data, newsize); if (newdata == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p = newdata + list->x509_rdn_sequence.size; _gnutls_write_uint16(tmp.size, p); if (tmp.data != NULL) memcpy(p + 2, tmp.data, tmp.size); list->x509_rdn_sequence.size = newsize; list->x509_rdn_sequence.data = newdata; return 0; }
/* generates a SignatureAndHashAlgorithm structure with length as prefix * by using the setup priorities. */ int _gnutls_sign_algorithm_write_params(gnutls_session_t session, uint8_t * data, size_t max_data_size) { uint8_t *p = data, *len_p; unsigned int len, i, j; const sign_algorithm_st *aid; if (max_data_size < (session->internals.priorities.sign_algo.algorithms * 2) + 2) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } len = 0; len_p = p; p += 2; for (i = j = 0; j < session->internals.priorities.sign_algo.algorithms; i += 2, j++) { aid = _gnutls_sign_to_tls_aid(session->internals. priorities.sign_algo. priority[j]); if (aid == NULL) continue; _gnutls_handshake_log ("EXT[%p]: sent signature algo (%d.%d) %s\n", session, aid->hash_algorithm, aid->sign_algorithm, gnutls_sign_get_name(session->internals.priorities. sign_algo.priority[j])); *p = aid->hash_algorithm; p++; *p = aid->sign_algorithm; p++; len += 2; } _gnutls_write_uint16(len, len_p); return len + 2; }
int oprfi_send_client (gnutls_session_t session, opaque * data, size_t _data_size) { opaque *p = data; ssize_t data_size = _data_size; int oprf_size = session->security_parameters.extensions.oprfi_client_len; if (oprf_size == 0) return 0; DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER); _gnutls_write_uint16 (oprf_size, p); p += 2; DECR_LENGTH_RET (data_size, oprf_size, GNUTLS_E_SHORT_MEMORY_BUFFER); memcpy (p, session->security_parameters.extensions.oprfi_client, oprf_size); return 2 + oprf_size; }
static void pack_ticket(const struct ticket_st *ticket, gnutls_datum_t *ticket_data) { uint8_t *p; p = ticket_data->data; memcpy(p, ticket->key_name, TICKET_KEY_NAME_SIZE); p += TICKET_KEY_NAME_SIZE; memcpy(p, ticket->IV, TICKET_IV_SIZE); p += TICKET_IV_SIZE; _gnutls_write_uint16(ticket->encrypted_state_len, p); p += 2; memcpy(p, ticket->encrypted_state, ticket->encrypted_state_len); p += ticket->encrypted_state_len; memcpy(p, ticket->mac, TICKET_MAC_SIZE); }
static int add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list, gnutls_x509_crt_t ca) { gnutls_datum_t tmp; size_t newsize; unsigned char *newdata, *p; /* Add DN of the last added CAs to the RDN sequence * This will be sent to clients when a certificate * request message is sent. */ tmp.data = ca->raw_dn.data; tmp.size = ca->raw_dn.size; newsize = list->x509_rdn_sequence.size + 2 + tmp.size; if (newsize < list->x509_rdn_sequence.size) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } newdata = gnutls_realloc_fast(list->x509_rdn_sequence.data, newsize); if (newdata == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p = newdata + list->x509_rdn_sequence.size; _gnutls_write_uint16(tmp.size, p); if (tmp.data != NULL) memcpy(p + 2, tmp.data, tmp.size); list->x509_rdn_sequence.size = newsize; list->x509_rdn_sequence.data = newdata; return 0; }
/* * Sends heartbeat data. */ static int heartbeat_send_data(gnutls_session_t session, const void *data, size_t data_size, uint8_t type) { int ret, pos; uint8_t *response; response = gnutls_malloc(1 + 2 + data_size + DEFAULT_PAYLOAD_SIZE); if (response == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos = 0; response[pos++] = type; _gnutls_write_uint16(data_size, &response[pos]); pos += 2; memcpy(&response[pos], data, data_size); pos += data_size; ret = gnutls_rnd(GNUTLS_RND_NONCE, &response[pos], DEFAULT_PAYLOAD_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } pos += DEFAULT_PAYLOAD_SIZE; ret = _gnutls_send_int(session, GNUTLS_HEARTBEAT, -1, EPOCH_WRITE_CURRENT, response, pos, MBUFFER_FLUSH); cleanup: gnutls_free(response); return ret; }
int _gnutls_gen_extensions(gnutls_session_t session, gnutls_buffer_st * extdata, gnutls_ext_parse_type_t parse_type) { int size; int pos, size_pos, ret; size_t i, init_size = extdata->length; pos = extdata->length; /* we will store length later on */ ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < extfunc_size; i++) { extension_entry_st *p = &extfunc[i]; if (p->send_func == NULL) continue; if (parse_type != GNUTLS_EXT_ANY && p->parse_type != parse_type) continue; ret = _gnutls_buffer_append_prefix(extdata, 16, p->type); if (ret < 0) return gnutls_assert_val(ret); size_pos = extdata->length; ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); size = p->send_func(session, extdata); /* returning GNUTLS_E_INT_RET_0 means to send an empty * extension of this type. */ if (size > 0 || size == GNUTLS_E_INT_RET_0) { if (size == GNUTLS_E_INT_RET_0) size = 0; /* write the real size */ _gnutls_write_uint16(size, &extdata->data[size_pos]); /* add this extension to the extension list */ _gnutls_extension_list_add(session, p->type); _gnutls_handshake_log ("EXT[%p]: Sending extension %s (%d bytes)\n", session, p->name, size); } else if (size < 0) { gnutls_assert(); return size; } else if (size == 0) extdata->length -= 4; /* reset type and size */ } /* remove any initial data, and the size of the header */ size = extdata->length - init_size - 2; if (size > 0) _gnutls_write_uint16(size, &extdata->data[pos]); else if (size == 0) extdata->length -= 2; /* the length bytes */ return size; }
/* return A = g^a % N */ int _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data) { size_t n_a; int ret; uint8_t *data_a; char *username, *password; char buf[64]; gnutls_srp_client_credentials_t cred; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_SRP, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (session->internals.srp_username == NULL) { username = cred->username; password = cred->password; } else { username = session->internals.srp_username; password = session->internals.srp_password; } if (username == NULL || password == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* calc A = g^a % N */ if (G == NULL || N == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } A = _gnutls_calc_srp_A (&_a, G, N); if (A == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* Rest of SRP calculations */ /* calculate u */ session->key->u = _gnutls_calc_srp_u (A, B, N); if (session->key->u == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP U: ", session->key->u); /* S = (B - g^x) ^ (a + u * x) % N */ S = _gnutls_calc_srp_S2 (B, G, session->key->x, _a, session->key->u, N); if (S == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP B: ", B); _gnutls_mpi_release (&_b); _gnutls_mpi_release (&V); _gnutls_mpi_release (&session->key->u); _gnutls_mpi_release (&B); ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&S); if (ret < 0) { gnutls_assert(); return ret; } if (_gnutls_mpi_print (NULL, &n_a, A) != 0) { gnutls_assert (); return GNUTLS_E_MPI_PRINT_FAILED; } (*data) = gnutls_malloc (n_a + 2); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* copy A */ data_a = (*data); if (_gnutls_mpi_print (&data_a[2], &n_a, A) != 0) { gnutls_free (*data); return GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_hard_log ("INT: SRP A[%d]: %s\n", n_a, _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf))); _gnutls_mpi_release (&A); _gnutls_write_uint16 (n_a, data_a); return n_a + 2; }
/* Send the first key exchange message ( g, n, s) and append the verifier algorithm number * Data is allocated by the caller, and should have data_size size. */ int _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque ** data) { int ret; uint8_t *data_n, *data_s; uint8_t *data_g; char *username; SRP_PWD_ENTRY *pwd_entry; srp_server_auth_info_t info; ssize_t data_size; size_t n_b, tmp_size; char buf[64]; uint8_t *data_b; if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_SRP, sizeof (srp_server_auth_info_st), 1)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); username = info->username; _gnutls_str_cpy (username, MAX_SRP_USERNAME, session->security_parameters.extensions.srp_username); ret = _gnutls_srp_pwd_read_entry (session, username, &pwd_entry); if (ret < 0) { gnutls_assert (); return ret; } /* copy from pwd_entry to local variables (actually in session) */ tmp_size = pwd_entry->g.size; if (_gnutls_mpi_scan_nz (&G, pwd_entry->g.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } tmp_size = pwd_entry->n.size; if (_gnutls_mpi_scan_nz (&N, pwd_entry->n.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } tmp_size = pwd_entry->v.size; if (_gnutls_mpi_scan_nz (&V, pwd_entry->v.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* Calculate: B = (k*v + g^b) % N */ B = _gnutls_calc_srp_B (&_b, G, N, V); if (B == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } if (_gnutls_mpi_print (NULL, &n_b, B) != 0) { gnutls_assert (); return GNUTLS_E_MPI_PRINT_FAILED; } /* Allocate size to hold the N, g, s, B */ data_size = (pwd_entry->n.size + 2 + pwd_entry->g.size + 2 + pwd_entry->salt.size + 1) + (n_b + 2); (*data) = gnutls_malloc (data_size); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* copy N (mod n) */ data_n = *data; _gnutls_write_datum16 (data_n, pwd_entry->n); /* copy G (generator) to data */ data_g = &data_n[2 + pwd_entry->n.size]; _gnutls_write_datum16 (data_g, pwd_entry->g); /* copy the salt */ data_s = &data_g[2 + pwd_entry->g.size]; _gnutls_write_datum8 (data_s, pwd_entry->salt); /* Copy the B value */ data_b = &data_s[1 + pwd_entry->salt.size]; if (_gnutls_mpi_print (&data_b[2], &n_b, B) != 0) { gnutls_assert(); return GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_write_uint16 (n_b, data_b); _gnutls_hard_log ("INT: SRP B[%d]: %s\n", n_b, _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf))); _gnutls_srp_entry_free (pwd_entry); return data_size; }
/** * gnutls_dtls_cookie_send: * @key: is a random key to be used at cookie generation * @client_data: contains data identifying the client (i.e. address) * @client_data_size: The size of client's data * @prestate: The previous cookie returned by gnutls_dtls_cookie_verify() * @ptr: A transport pointer to be used by @push_func * @push_func: A function that will be used to reply * * This function can be used to prevent denial of service * attacks to a DTLS server by requiring the client to * reply using a cookie sent by this function. That way * it can be ensured that a client we allocated resources * for (i.e. #gnutls_session_t) is the one that the * original incoming packet was originated from. * * Returns: the number of bytes sent, or a negative error code. * * Since: 3.0 **/ int gnutls_dtls_cookie_send(gnutls_datum_t* key, void* client_data, size_t client_data_size, gnutls_dtls_prestate_st* prestate, gnutls_transport_ptr_t ptr, gnutls_push_func push_func) { uint8_t hvr[20+DTLS_HANDSHAKE_HEADER_SIZE+COOKIE_SIZE]; int hvr_size = 0, ret; uint8_t digest[C_HASH_SIZE]; if (key == NULL || key->data == NULL || key->size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* send * struct { * ContentType type - 1 byte GNUTLS_HANDSHAKE; * ProtocolVersion version; - 2 bytes (254,255) * uint16 epoch; - 2 bytes (0, 0) * uint48 sequence_number; - 4 bytes (0,0,0,0) * uint16 length; - 2 bytes (COOKIE_SIZE+1+2)+DTLS_HANDSHAKE_HEADER_SIZE * uint8_t fragment[DTLSPlaintext.length]; * } DTLSPlaintext; * * * struct { * HandshakeType msg_type; 1 byte - GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST * uint24 length; - COOKIE_SIZE+3 * uint16 message_seq; - 2 bytes (0,0) * uint24 fragment_offset; - 3 bytes (0,0,0) * uint24 fragment_length; - same as length * } * * struct { * ProtocolVersion server_version; * uint8_t cookie<0..32>; * } HelloVerifyRequest; */ hvr[hvr_size++] = GNUTLS_HANDSHAKE; /* version */ hvr[hvr_size++] = 254; hvr[hvr_size++] = 255; /* epoch + seq */ memset(&hvr[hvr_size], 0, 8); hvr_size += 7; hvr[hvr_size++] = prestate->record_seq; /* length */ _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE+COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 2; /* now handshake headers */ hvr[hvr_size++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST; _gnutls_write_uint24(COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 3; /* handshake seq */ hvr[hvr_size++] = 0; hvr[hvr_size++] = prestate->hsk_write_seq; _gnutls_write_uint24(0, &hvr[hvr_size]); hvr_size += 3; _gnutls_write_uint24(COOKIE_SIZE+3, &hvr[hvr_size]); hvr_size += 3; /* version */ hvr[hvr_size++] = 254; hvr[hvr_size++] = 255; hvr[hvr_size++] = COOKIE_SIZE; ret = _gnutls_hmac_fast(C_HASH, key->data, key->size, client_data, client_data_size, digest); if (ret < 0) return gnutls_assert_val(ret); memcpy(&hvr[hvr_size], digest, COOKIE_MAC_SIZE); hvr_size+= COOKIE_MAC_SIZE; ret = push_func(ptr, hvr, hvr_size); if (ret < 0) ret = GNUTLS_E_PUSH_ERROR; return ret; }
/* This function fragments and transmits a previously buffered * outgoing message. It accepts mtu_data which is a buffer to * be reused (should be set to NULL initially). */ static inline int transmit_message (gnutls_session_t session, mbuffer_st *bufel, uint8_t **buf) { uint8_t *data, *mtu_data; int ret = 0; unsigned int offset, frag_len, data_size; const unsigned int mtu = gnutls_dtls_get_data_mtu(session) - DTLS_HANDSHAKE_HEADER_SIZE; if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC) { _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d)\n", session, bufel->handshake_sequence, _gnutls_handshake2str (bufel->htype), bufel->htype); return _gnutls_send_int (session, bufel->type, -1, bufel->epoch, _mbuffer_get_uhead_ptr(bufel), _mbuffer_get_uhead_size(bufel), 0); } if (*buf == NULL) *buf = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE); if (*buf == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); mtu_data = *buf; data = _mbuffer_get_udata_ptr( bufel); data_size = _mbuffer_get_udata_size(bufel); /* Write fixed headers */ /* Handshake type */ mtu_data[0] = (uint8_t) bufel->htype; /* Total length */ _gnutls_write_uint24 (data_size, &mtu_data[1]); /* Handshake sequence */ _gnutls_write_uint16 (bufel->handshake_sequence, &mtu_data[4]); /* Chop up and send handshake message into mtu-size pieces. */ for (offset=0; offset <= data_size; offset += mtu) { /* Calculate fragment length */ if(offset + mtu > data_size) frag_len = data_size - offset; else frag_len = mtu; /* Fragment offset */ _gnutls_write_uint24 (offset, &mtu_data[6]); /* Fragment length */ _gnutls_write_uint24 (frag_len, &mtu_data[9]); memcpy (&mtu_data[DTLS_HANDSHAKE_HEADER_SIZE], data+offset, frag_len); _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with " "length: %u, offset: %u, fragment length: %u\n", session, bufel->handshake_sequence, _gnutls_handshake2str (bufel->htype), bufel->htype, data_size, offset, frag_len); ret = _gnutls_send_int (session, bufel->type, bufel->htype, bufel->epoch, mtu_data, DTLS_HANDSHAKE_HEADER_SIZE + frag_len, 0); if (ret < 0) { gnutls_assert(); break; } } return ret; }
static int gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data) { gnutls_rsa_params_t rsa_params; const bigint_t *rsa_mpis; size_t n_e, n_m; uint8_t *data_e, *data_m; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey *apr_pkey; int apr_cert_list_length; gnutls_datum_t signature, ddata; cert_auth_info_t info; gnutls_certificate_credentials_t cred; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } /* abort sending this message if we have a certificate * of 512 bits or less. */ if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } rsa_params = _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, session); rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params); if (rsa_mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); _gnutls_mpi_print (rsa_mpis[0], NULL, &n_m); _gnutls_mpi_print (rsa_mpis[1], NULL, &n_e); (*data) = gnutls_malloc (n_e + n_m + 4); if (*data == NULL) { return GNUTLS_E_MEMORY_ERROR; } data_m = &(*data)[0]; _gnutls_mpi_print (rsa_mpis[0], &data_m[2], &n_m); _gnutls_write_uint16 (n_m, data_m); data_e = &data_m[2 + n_m]; _gnutls_mpi_print (rsa_mpis[1], &data_e[2], &n_e); _gnutls_write_uint16 (n_e, data_e); data_size = n_m + n_e + 4; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_tls_sign_params (session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert (); gnutls_free (*data); *data = NULL; return ret; } } else { gnutls_assert (); return data_size; /* do not put a signature - ILLEGAL! */ } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&((*data)[data_size]), signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
int _gnutls_gen_extensions (gnutls_session_t session, opaque * data, size_t data_size) { int size; uint16_t pos = 0; opaque *sdata; int sdata_size; size_t i; if (data_size < 2) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* allocate enough data for each extension. */ sdata_size = data_size; sdata = gnutls_malloc (sdata_size); if (sdata == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } pos += 2; for (i = 0; i < extfunc_size; i++) { gnutls_extension_entry *p = &extfunc[i]; if (p->send_func == NULL) continue; size = p->send_func (session, sdata, sdata_size); if (size > 0) { if (data_size < pos + (size_t) size + 4) { gnutls_assert (); gnutls_free (sdata); return GNUTLS_E_INTERNAL_ERROR; } /* write extension type */ _gnutls_write_uint16 (p->type, &data[pos]); pos += 2; /* write size */ _gnutls_write_uint16 (size, &data[pos]); pos += 2; memcpy (&data[pos], sdata, size); pos += size; /* add this extension to the extension list */ _gnutls_extension_list_add (session, p->type); _gnutls_debug_log ("EXT[%p]: Sending extension %s\n", session, p->name); } else if (size < 0) { gnutls_assert (); gnutls_free (sdata); return size; } } size = pos; pos -= 2; /* remove the size of the size header! */ _gnutls_write_uint16 (pos, data); if (size == 2) { /* empty */ size = 0; } gnutls_free (sdata); return size; }
/* Format: * 4 bytes the total security data size * 1 byte the entity type (client/server) * 1 byte the key exchange algorithm used * 1 byte the read cipher algorithm * 1 byte the read mac algorithm * 1 byte the read compression algorithm * * 1 byte the write cipher algorithm * 1 byte the write mac algorithm * 1 byte the write compression algorithm * * 1 byte the certificate type * 1 byte the protocol version * * 2 bytes the cipher suite * * 48 bytes the master secret * * 32 bytes the client random * 32 bytes the server random * * 1 byte the session ID size * x bytes the session ID (32 bytes max) * * 4 bytes a timestamp * ------------------- * MAX: 165 bytes * * EXTENSIONS: * 2 bytes the record send size * 2 bytes the record recv size * * 1 byte the SRP username size * x bytes the SRP username (MAX_SRP_USERNAME) * * 2 bytes the number of server name extensions (up to MAX_SERVER_NAME_EXTENSIONS) * 1 byte the first name type * 2 bytes the size of the first name * x bytes the first name (MAX_SERVER_NAME_SIZE) * and so on... * * -------------------- * MAX: 7+MAX_SRP_USERNAME+MAX_SERVER_NAME_EXTENSIONS*(3+MAX_SERVER_NAME_SIZE) */ static int pack_security_parameters (gnutls_session_t session, gnutls_datum_t * packed_session) { int pos = 0; size_t len, init, i; /* move after the auth info stuff. */ init = _gnutls_read_uint32 (&packed_session->data[PACK_HEADER_SIZE]) + 4 + PACK_HEADER_SIZE; pos = init + 4; /* make some space to write later the size */ packed_session->data[pos++] = session->security_parameters.entity; packed_session->data[pos++] = session->security_parameters.kx_algorithm; packed_session->data[pos++] = session->security_parameters.read_bulk_cipher_algorithm; packed_session->data[pos++] = session->security_parameters.read_mac_algorithm; packed_session->data[pos++] = session->security_parameters.read_compression_algorithm; packed_session->data[pos++] = session->security_parameters.write_bulk_cipher_algorithm; packed_session->data[pos++] = session->security_parameters.write_mac_algorithm; packed_session->data[pos++] = session->security_parameters.write_compression_algorithm; packed_session->data[pos++] = session->security_parameters.current_cipher_suite.suite[0]; packed_session->data[pos++] = session->security_parameters.current_cipher_suite.suite[1]; packed_session->data[pos++] = session->security_parameters.cert_type; packed_session->data[pos++] = session->security_parameters.version; memcpy (&packed_session->data[pos], session->security_parameters.master_secret, TLS_MASTER_SIZE); pos += TLS_MASTER_SIZE; memcpy (&packed_session->data[pos], session->security_parameters.client_random, TLS_RANDOM_SIZE); pos += TLS_RANDOM_SIZE; memcpy (&packed_session->data[pos], session->security_parameters.server_random, TLS_RANDOM_SIZE); pos += TLS_RANDOM_SIZE; packed_session->data[pos++] = session->security_parameters.session_id_size; memcpy (&packed_session->data[pos], session->security_parameters.session_id, session->security_parameters.session_id_size); pos += session->security_parameters.session_id_size; _gnutls_write_uint32 (session->security_parameters.timestamp, &packed_session->data[pos]); pos += 4; /* Extensions */ _gnutls_write_uint16 (session->security_parameters.max_record_send_size, &packed_session->data[pos]); pos += 2; _gnutls_write_uint16 (session->security_parameters.max_record_recv_size, &packed_session->data[pos]); pos += 2; /* SRP */ len = strlen ((char *) session->security_parameters.extensions.srp_username); packed_session->data[pos++] = len; memcpy (&packed_session->data[pos], session->security_parameters.extensions.srp_username, len); pos += len; _gnutls_write_uint16 (session->security_parameters.extensions. server_names_size, &packed_session->data[pos]); pos += 2; for (i = 0; i < session->security_parameters.extensions.server_names_size; i++) { packed_session->data[pos++] = session->security_parameters.extensions.server_names[i].type; _gnutls_write_uint16 (session->security_parameters.extensions. server_names[i].name_length, &packed_session->data[pos]); pos += 2; memcpy (&packed_session->data[pos], session->security_parameters.extensions.server_names[i].name, session->security_parameters.extensions.server_names[i]. name_length); pos += session->security_parameters.extensions.server_names[i].name_length; } /* write the total size */ _gnutls_write_uint32 (pos - init - 4, &packed_session->data[init]); packed_session->size += pos - init; return 0; }
/* 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_datum_t * packed_session) { unsigned int pos = 0, i; int cert_size, pack_size; cert_auth_info_t info = _gnutls_get_auth_info (session); if (info == NULL && session->key->auth_info_size != 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (info) { cert_size = 4; for (i = 0; i < info->ncerts; i++) cert_size += 4 + info->raw_certificate_list[i].size; pack_size = 2 + 4 + info->dh.prime.size + 4 + info->dh.generator.size + 4 + info->dh.public_key.size + 4 + info->rsa_export.modulus.size + 4 + info->rsa_export.exponent.size + cert_size; } else pack_size = 0; packed_session->size = PACK_HEADER_SIZE + pack_size + sizeof (uint32_t); /* calculate the size and allocate the data. */ packed_session->data = gnutls_malloc (packed_session->size + MAX_SEC_PARAMS); if (packed_session->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } packed_session->data[0] = GNUTLS_CRD_CERTIFICATE; _gnutls_write_uint32 (pack_size, &packed_session->data[PACK_HEADER_SIZE]); pos += 4 + PACK_HEADER_SIZE; if (pack_size > 0) { _gnutls_write_uint16 (info->dh.secret_bits, &packed_session->data[pos]); pos += 2; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.prime); pos += 4 + info->dh.prime.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.generator); pos += 4 + info->dh.generator.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.public_key); pos += 4 + info->dh.public_key.size; _gnutls_write_datum32 (&packed_session->data[pos], info->rsa_export.modulus); pos += 4 + info->rsa_export.modulus.size; _gnutls_write_datum32 (&packed_session->data[pos], info->rsa_export.exponent); pos += 4 + info->rsa_export.exponent.size; _gnutls_write_uint32 (info->ncerts, &packed_session->data[pos]); pos += 4; for (i = 0; i < info->ncerts; i++) { _gnutls_write_datum32 (&packed_session->data[pos], info->raw_certificate_list[i]); pos += sizeof (uint32_t) + info->raw_certificate_list[i].size; } } return 0; }
static int compute_psk_binder(gnutls_session_t session, const mac_entry_st *prf, unsigned binders_length, int exts_length, int ext_offset, const gnutls_datum_t *psk, const gnutls_datum_t *client_hello, bool resuming, void *out) { int ret; unsigned client_hello_pos, extensions_len_pos; gnutls_buffer_st handshake_buf; uint8_t binder_key[MAX_HASH_SIZE]; _gnutls_buffer_init(&handshake_buf); if (session->security_parameters.entity == GNUTLS_CLIENT) { if (session->internals.hsk_flags & HSK_HRR_RECEIVED) { ret = gnutls_buffer_append_data(&handshake_buf, (const void *) session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer.length); if (ret < 0) { gnutls_assert(); goto error; } } client_hello_pos = handshake_buf.length; ret = gnutls_buffer_append_data(&handshake_buf, client_hello->data, client_hello->size); if (ret < 0) { gnutls_assert(); goto error; } /* This is a ClientHello message */ handshake_buf.data[client_hello_pos] = GNUTLS_HANDSHAKE_CLIENT_HELLO; /* At this point we have not yet added the binders to the ClientHello, * but we have to overwrite the size field, pretending as if binders * of the correct length were present. */ _gnutls_write_uint24(handshake_buf.length - client_hello_pos + binders_length - 2, &handshake_buf.data[client_hello_pos + 1]); _gnutls_write_uint16(handshake_buf.length - client_hello_pos + binders_length - ext_offset, &handshake_buf.data[client_hello_pos + ext_offset]); extensions_len_pos = handshake_buf.length - client_hello_pos - exts_length - 2; _gnutls_write_uint16(exts_length + binders_length + 2, &handshake_buf.data[client_hello_pos + extensions_len_pos]); } else { if (session->internals.hsk_flags & HSK_HRR_SENT) { if (unlikely(session->internals.handshake_hash_buffer.length <= client_hello->size)) { ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); goto error; } ret = gnutls_buffer_append_data(&handshake_buf, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer.length - client_hello->size); if (ret < 0) { gnutls_assert(); goto error; } } if (unlikely(client_hello->size <= binders_length)) { ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); goto error; } ret = gnutls_buffer_append_data(&handshake_buf, (const void *) client_hello->data, client_hello->size - binders_length); if (ret < 0) { gnutls_assert(); goto error; } } ret = compute_binder_key(prf, psk->data, psk->size, resuming, binder_key); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls13_compute_finished(prf, binder_key, &handshake_buf, out); if (ret < 0) { gnutls_assert(); goto error; } ret = 0; error: _gnutls_buffer_clear(&handshake_buf); return ret; }
static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, const gnutls_psk_client_credentials_t cred) { int ret, ext_offset = 0; uint8_t binder_value[MAX_HASH_SIZE]; size_t spos; gnutls_datum_t username = {NULL, 0}; gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0}; gnutls_datum_t client_hello; unsigned next_idx; const mac_entry_st *prf_res = NULL; const mac_entry_st *prf_psk = NULL; struct timespec cur_time; uint32_t ticket_age, ob_ticket_age; int free_username = 0; psk_auth_info_t info = NULL; unsigned psk_id_len = 0; unsigned binders_len, binders_pos; if (((session->internals.flags & GNUTLS_NO_TICKETS) || session->internals.tls13_ticket.ticket.data == NULL) && (!cred || !_gnutls_have_psk_credentials(cred, session))) { return 0; } binders_len = 0; /* placeholder to be filled later */ spos = extdata->length; ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); /* First, let's see if we have a session ticket to send */ if (!(session->internals.flags & GNUTLS_NO_TICKETS) && session->internals.tls13_ticket.ticket.data != NULL) { /* We found a session ticket */ if (unlikely(session->internals.tls13_ticket.prf == NULL)) { _gnutls13_session_ticket_unset(session); ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); goto cleanup; } prf_res = session->internals.tls13_ticket.prf; gnutls_gettime(&cur_time); if (unlikely(_gnutls_timespec_cmp(&cur_time, &session->internals. tls13_ticket. arrival_time) < 0)) { gnutls_assert(); _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Check whether the ticket is stale */ ticket_age = timespec_sub_ms(&cur_time, &session->internals.tls13_ticket. arrival_time); if (ticket_age / 1000 > session->internals.tls13_ticket.lifetime) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } ret = compute_psk_from_ticket(&session->internals.tls13_ticket, &rkey); if (ret < 0) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */ ob_ticket_age = ticket_age + session->internals.tls13_ticket.age_add; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, session->internals.tls13_ticket.ticket.data, session->internals.tls13_ticket.ticket.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + session->internals.tls13_ticket.ticket.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_res); } ignore_ticket: if (cred && _gnutls_have_psk_credentials(cred, session)) { gnutls_datum_t tkey; if (cred->binder_algo == NULL) { gnutls_assert(); ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); goto cleanup; } prf_psk = cred->binder_algo; ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username); if (ret < 0) { gnutls_assert(); goto cleanup; } if (username.size == 0 || username.size > UINT16_MAX) { ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD); goto cleanup; } if (!free_username) { /* we need to copy the key */ ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { user_key.data = tkey.data; user_key.size = tkey.size; } ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { gnutls_assert(); goto cleanup; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); assert(info != NULL); memcpy(info->username, username.data, username.size); info->username[username.size] = 0; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, username.data, username.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + username.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk); } /* if no tickets or identities to be sent */ if (psk_id_len == 0) { /* reset extensions buffer */ extdata->length = spos; return 0; } _gnutls_write_uint16(psk_id_len, &extdata->data[spos]); binders_pos = extdata->length-spos; ext_offset = _gnutls_ext_get_extensions_offset(session); /* Compute the binders. extdata->data points to the start * of this client hello. */ assert(extdata->length >= sizeof(mbuffer_st)); assert(ext_offset >= (ssize_t)sizeof(mbuffer_st)); ext_offset -= sizeof(mbuffer_st); client_hello.data = extdata->data+sizeof(mbuffer_st); client_hello.size = extdata->length-sizeof(mbuffer_st); next_idx = 0; ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len); if (ret < 0) { gnutls_assert_val(ret); goto cleanup; } if (prf_res && rkey.size > 0) { ret = compute_psk_binder(session, prf_res, binders_len, binders_pos, ext_offset, &rkey, &client_hello, 1, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = rkey.data; session->key.binders[next_idx].psk.size = rkey.size; rkey.data = NULL; session->key.binders[next_idx].prf = prf_res; session->key.binders[next_idx].resumption = 1; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT; } if (prf_psk && user_key.size > 0 && info) { ret = compute_psk_binder(session, prf_psk, binders_len, binders_pos, ext_offset, &user_key, &client_hello, 0, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = user_key.data; session->key.binders[next_idx].psk.size = user_key.size; user_key.data = NULL; session->key.binders[next_idx].prf = prf_psk; session->key.binders[next_idx].resumption = 0; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: if (free_username) _gnutls_free_datum(&username); _gnutls_free_temp_key_datum(&user_key); _gnutls_free_temp_key_datum(&rkey); return ret; }
/* 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_datum_t * packed_session) { psk_auth_info_t info; int pack_size, username_size = 0, pos; info = _gnutls_get_auth_info (session); if (info == NULL && session->key->auth_info_size != 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (info) { username_size = strlen (info->username) + 1; /* include the terminating null */ pack_size = username_size + 2 + 4 * 3 + info->dh.prime.size + info->dh.generator.size + info->dh.public_key.size; } else pack_size = 0; packed_session->size = PACK_HEADER_SIZE + pack_size + sizeof (uint32_t); /* calculate the size and allocate the data. */ packed_session->data = gnutls_malloc (packed_session->size + MAX_SEC_PARAMS); if (packed_session->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } pos = 0; packed_session->data[pos] = GNUTLS_CRD_PSK; pos++; _gnutls_write_uint32 (pack_size, &packed_session->data[pos]); pos += 4; if (pack_size > 0) { _gnutls_write_uint32 (username_size, &packed_session->data[pos]); pos += 4; memcpy (&packed_session->data[pos], info->username, username_size); pos += username_size; _gnutls_write_uint16 (info->dh.secret_bits, &packed_session->data[pos]); pos += 2; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.prime); pos += 4 + info->dh.prime.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.generator); pos += 4 + info->dh.generator.size; _gnutls_write_datum32 (&packed_session->data[pos], info->dh.public_key); pos += 4 + info->dh.public_key.size; } return 0; }