int s2n_dhe_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_blob *data_to_verify, union s2n_kex_raw_server_data *raw_server_data) { struct s2n_stuffer *in = &conn->handshake.io; struct s2n_dhe_raw_server_points *dhe_data = &raw_server_data->dhe_data; uint16_t p_length; uint16_t g_length; uint16_t Ys_length; /* Keep a copy to the start of the whole structure for the signature check */ data_to_verify->data = s2n_stuffer_raw_read(in, 0); notnull_check(data_to_verify->data); /* Read each of the three elements in */ GUARD(s2n_stuffer_read_uint16(in, &p_length)); dhe_data->p.size = p_length; dhe_data->p.data = s2n_stuffer_raw_read(in, p_length); notnull_check(dhe_data->p.data); GUARD(s2n_stuffer_read_uint16(in, &g_length)); dhe_data->g.size = g_length; dhe_data->g.data = s2n_stuffer_raw_read(in, g_length); notnull_check(dhe_data->g.data); GUARD(s2n_stuffer_read_uint16(in, &Ys_length)); dhe_data->Ys.size = Ys_length; dhe_data->Ys.data = s2n_stuffer_raw_read(in, Ys_length); notnull_check(dhe_data->Ys.data); /* Now we know the total size of the structure */ data_to_verify->size = 2 + p_length + 2 + g_length + 2 + Ys_length; return 0; }
int s2n_server_extensions_recv(struct s2n_connection *conn, struct s2n_blob *extensions) { struct s2n_stuffer in; GUARD(s2n_stuffer_init(&in, extensions)); GUARD(s2n_stuffer_write(&in, extensions)); while (s2n_stuffer_data_available(&in)) { struct s2n_blob ext; uint16_t extension_type, extension_size; struct s2n_stuffer extension; GUARD(s2n_stuffer_read_uint16(&in, &extension_type)); GUARD(s2n_stuffer_read_uint16(&in, &extension_size)); ext.size = extension_size; ext.data = s2n_stuffer_raw_read(&in, ext.size); notnull_check(ext.data); GUARD(s2n_stuffer_init(&extension, &ext)); GUARD(s2n_stuffer_write(&extension, &ext)); switch (extension_type) { case TLS_EXTENSION_ALPN: GUARD(s2n_recv_server_alpn(conn, &extension)); break; case TLS_EXTENSION_STATUS_REQUEST: GUARD(s2n_recv_server_status_request(conn, &extension)); break; } } return 0; }
/* See http://www-archive.mozilla.org/projects/security/pki/nss/ssl/draft02.html 2.5 */ int s2n_sslv2_client_hello_recv(struct s2n_connection *conn) { struct s2n_stuffer *in = &conn->handshake.io; uint16_t session_id_length; uint16_t cipher_suites_length; uint16_t challenge_length; uint8_t *cipher_suites; if (conn->client_protocol_version < conn->config->cipher_preferences->minimum_protocol_version || conn->client_protocol_version > conn->server_protocol_version) { GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); S2N_ERROR(S2N_ERR_BAD_MESSAGE); } conn->actual_protocol_version = MIN(conn->client_protocol_version, conn->server_protocol_version); conn->client_hello_version = S2N_SSLv2; /* We start 5 bytes into the record */ GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); if (cipher_suites_length % S2N_SSLv2_CIPHER_SUITE_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } GUARD(s2n_stuffer_read_uint16(in, &session_id_length)); GUARD(s2n_stuffer_read_uint16(in, &challenge_length)); if (challenge_length > S2N_TLS_RANDOM_DATA_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } cipher_suites = s2n_stuffer_raw_read(in, cipher_suites_length); notnull_check(cipher_suites); GUARD(s2n_set_cipher_as_sslv2_server(conn, cipher_suites, cipher_suites_length / S2N_SSLv2_CIPHER_SUITE_LEN)); if (session_id_length > s2n_stuffer_data_available(in)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } if (session_id_length > 0 && session_id_length <= S2N_TLS_SESSION_ID_MAX_LEN) { GUARD(s2n_stuffer_read_bytes(in, conn->session_id, session_id_length)); conn->session_id_len = (uint8_t) session_id_length; } else { GUARD(s2n_stuffer_skip_read(in, session_id_length)); } struct s2n_blob b; b.data = conn->secure.client_random; b.size = S2N_TLS_RANDOM_DATA_LEN; b.data += S2N_TLS_RANDOM_DATA_LEN - challenge_length; b.size -= S2N_TLS_RANDOM_DATA_LEN - challenge_length; GUARD(s2n_stuffer_read(in, &b)); conn->server->chosen_cert_chain = conn->config->cert_and_key_pairs; GUARD(s2n_conn_set_handshake_type(conn)); return 0; }
int s2n_client_extensions_recv(struct s2n_connection *conn, struct s2n_blob *extensions) { struct s2n_stuffer in; GUARD(s2n_stuffer_init(&in, extensions)); GUARD(s2n_stuffer_write(&in, extensions)); while (s2n_stuffer_data_available(&in)) { struct s2n_blob ext; uint16_t extension_type, extension_size; struct s2n_stuffer extension; GUARD(s2n_stuffer_read_uint16(&in, &extension_type)); GUARD(s2n_stuffer_read_uint16(&in, &extension_size)); ext.size = extension_size; lte_check(extension_size, s2n_stuffer_data_available(&in)); ext.data = s2n_stuffer_raw_read(&in, ext.size); notnull_check(ext.data); GUARD(s2n_stuffer_init(&extension, &ext)); GUARD(s2n_stuffer_write(&extension, &ext)); switch (extension_type) { case TLS_EXTENSION_SERVER_NAME: GUARD(s2n_recv_client_server_name(conn, &extension)); break; case TLS_EXTENSION_SIGNATURE_ALGORITHMS: GUARD(s2n_recv_client_signature_algorithms(conn, &extension, &conn->secure.conn_hash_alg, &conn->secure.conn_sig_alg)); break; case TLS_EXTENSION_ALPN: GUARD(s2n_recv_client_alpn(conn, &extension)); break; case TLS_EXTENSION_STATUS_REQUEST: GUARD(s2n_recv_client_status_request(conn, &extension)); break; case TLS_EXTENSION_ELLIPTIC_CURVES: GUARD(s2n_recv_client_elliptic_curves(conn, &extension)); break; case TLS_EXTENSION_EC_POINT_FORMATS: GUARD(s2n_recv_client_ec_point_formats(conn, &extension)); break; case TLS_EXTENSION_RENEGOTIATION_INFO: GUARD(s2n_recv_client_renegotiation_info(conn, &extension)); break; case TLS_EXTENSION_SCT_LIST: GUARD(s2n_recv_client_sct_list(conn, &extension)); break; case TLS_EXTENSION_MAX_FRAG_LEN: GUARD(s2n_recv_client_max_frag_len(conn, &extension)); break; } } return 0; }
int s2n_kem_find_supported_kem(struct s2n_blob *client_kem_ids, const struct s2n_kem *server_kem_pref_list, const int num_server_supported_kems, const struct s2n_kem **matching_kem) { struct s2n_stuffer client_kems_in = {{0}}; GUARD(s2n_stuffer_init(&client_kems_in, client_kem_ids)); GUARD(s2n_stuffer_write(&client_kems_in, client_kem_ids)); for (int i = 0; i < num_server_supported_kems; i++) { const struct s2n_kem candidate_server_kem_name = server_kem_pref_list[i]; for (int j = 0; j < client_kem_ids->size / 2; j++) { kem_extension_size candidate_client_kem_id; GUARD(s2n_stuffer_read_uint16(&client_kems_in, &candidate_client_kem_id)); if (candidate_server_kem_name.kem_extension_id == candidate_client_kem_id) { *matching_kem = &server_kem_pref_list[i]; return 0; } } GUARD(s2n_stuffer_reread(&client_kems_in)); } /* Nothing found */ S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); return 0; }
int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key) { uint16_t Yc_length; struct s2n_blob Yc; int shared_key_size; BIGNUM *pub_key; GUARD(s2n_check_all_dh_params(server_dh_params)); GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length)); Yc.size = Yc_length; Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size); notnull_check(Yc.data); pub_key = BN_bin2bn((const unsigned char *)Yc.data, Yc.size, NULL); notnull_check(pub_key); GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh); if (shared_key_size <= 0) { BN_free(pub_key); S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); } shared_key->size = shared_key_size; BN_free(pub_key); return 0; }
int s2n_kem_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_blob *data_to_verify, union s2n_kex_raw_server_data *raw_server_data) { struct s2n_kem_raw_server_params *kem_data = &raw_server_data->kem_data; struct s2n_stuffer *in = &conn->handshake.io; const struct s2n_kem *kem = conn->secure.s2n_kem_keys.negotiated_kem; kem_public_key_size key_length; /* Keep a copy to the start of the whole structure for the signature check */ data_to_verify->data = s2n_stuffer_raw_read(in, 0); notnull_check(data_to_verify->data); /* the server sends the KEM ID again and this must match what was agreed upon during server hello */ kem_extension_size kem_id; GUARD(s2n_stuffer_read_uint8(in, &kem_id)); eq_check(kem_id, kem->kem_extension_id); GUARD(s2n_stuffer_read_uint16(in, &key_length)); S2N_ERROR_IF(key_length > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); S2N_ERROR_IF(key_length != conn->secure.s2n_kem_keys.negotiated_kem->public_key_length, S2N_ERR_BAD_MESSAGE); kem_data->raw_public_key.data = s2n_stuffer_raw_read(in, key_length); notnull_check(kem_data->raw_public_key.data); kem_data->raw_public_key.size = key_length; data_to_verify->size = sizeof(kem_extension_size) + sizeof(kem_public_key_size) + key_length; return 0; }
int s2n_server_key_recv(struct s2n_connection *conn) { struct s2n_hash_state *signature_hash = &conn->secure.signature_hash; const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg; struct s2n_stuffer *in = &conn->handshake.io; struct s2n_blob data_to_verify = {0}; /* Read the KEX data */ union s2n_kex_raw_server_data kex_data = {{{0}}}; GUARD(s2n_kex_server_key_recv_read_data(key_exchange, conn, &data_to_verify, &kex_data)); /* Add common signature data */ if (conn->actual_protocol_version == S2N_TLS12) { s2n_hash_algorithm hash_algorithm; s2n_signature_algorithm signature_algorithm; GUARD(s2n_get_signature_hash_pair_if_supported(in, &hash_algorithm, &signature_algorithm)); GUARD(s2n_hash_init(signature_hash, hash_algorithm)); } else { GUARD(s2n_hash_init(signature_hash, conn->secure.conn_hash_alg)); } GUARD(s2n_hash_update(signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_hash_update(signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); /* Add KEX specific data */ GUARD(s2n_hash_update(signature_hash, data_to_verify.data, data_to_verify.size)); /* Verify the signature */ uint16_t signature_length; GUARD(s2n_stuffer_read_uint16(in, &signature_length)); struct s2n_blob signature = {.size = signature_length, .data = s2n_stuffer_raw_read(in, signature_length)}; notnull_check(signature.data); gt_check(signature_length, 0); S2N_ERROR_IF(s2n_pkey_verify(&conn->secure.server_public_key, signature_hash, &signature) < 0, S2N_ERR_BAD_MESSAGE); /* We don't need the key any more, so free it */ GUARD(s2n_pkey_free(&conn->secure.server_public_key)); /* Parse the KEX data into whatever form needed and save it to the connection object */ GUARD(s2n_kex_server_key_recv_parse_data(key_exchange, conn, &kex_data)); return 0; } int s2n_ecdhe_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_blob *data_to_verify, union s2n_kex_raw_server_data *raw_server_data) { struct s2n_stuffer *in = &conn->handshake.io; GUARD(s2n_ecc_read_ecc_params(in, data_to_verify, &raw_server_data->ecdhe_data)); return 0; } int s2n_ecdhe_server_key_recv_parse_data(struct s2n_connection *conn, union s2n_kex_raw_server_data *raw_server_data) { GUARD(s2n_ecc_parse_ecc_params(&conn->secure.server_ecc_params, &raw_server_data->ecdhe_data)); return 0; }
int main(int argc, char **argv) { uint8_t u8; uint16_t u16; uint32_t u32; uint32_t stuffer_size = nondet_uint32(); __CPROVER_assume(stuffer_size > 0); uint32_t entropy_size = nondet_uint32(); __CPROVER_assume(entropy_size > 0); uint8_t entropy[entropy_size]; struct s2n_stuffer stuffer; GUARD(s2n_stuffer_alloc(&stuffer, stuffer_size)); struct s2n_blob in = {.data = entropy,.size = entropy_size}; GUARD(s2n_stuffer_write(&stuffer, &in)); GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint8(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint8(&stuffer, &u8)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint16(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint16(&stuffer, &u16)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint24(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint24(&stuffer, &u32)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint32(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint32(&stuffer, &u32)); } GUARD(s2n_stuffer_free(&stuffer)); }
static int s2n_recv_client_server_name(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; uint8_t server_name_type; uint16_t server_name_len; uint8_t *server_name; GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all < 3) { /* the size of all server names is incorrect, ignore the extension */ return 0; } GUARD(s2n_stuffer_read_uint8(extension, &server_name_type)); if (server_name_type != 0) { /* unknown server name type, ignore the extension */ return 0; } GUARD(s2n_stuffer_read_uint16(extension, &server_name_len)); if (server_name_len + 3 > size_of_all) { /* the server name length is incorrect, ignore the extension */ return 0; } if (server_name_len > sizeof(conn->server_name) - 1) { /* the server name is too long, ignore the extension */ return 0; } notnull_check(server_name = s2n_stuffer_raw_read(extension, server_name_len)); /* copy the first server name */ memcpy_check(conn->server_name, server_name, server_name_len); return 0; }
int s2n_recv_client_signature_algorithms(struct s2n_connection *conn, struct s2n_stuffer *in, s2n_hash_algorithm *hash, s2n_signature_algorithm *sig) { uint16_t length_of_all_pairs; GUARD(s2n_stuffer_read_uint16(in, &length_of_all_pairs)); if (length_of_all_pairs > s2n_stuffer_data_available(in)) { /* Malformed length, ignore the extension */ return 0; } if (length_of_all_pairs % 2 || s2n_stuffer_data_available(in) % 2) { /* Pairs occur in two byte lengths. Malformed length, ignore the extension. */ return 0; } int pairs_available = length_of_all_pairs / 2; GUARD(s2n_choose_preferred_signature_hash_pair(in, pairs_available, hash, sig)); return 0; }
int s2n_recv_server_alpn(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all < 3) { /* ignore invalid extension size */ return 0; } uint8_t protocol_len; GUARD(s2n_stuffer_read_uint8(extension, &protocol_len)); uint8_t *protocol = s2n_stuffer_raw_read(extension, protocol_len); notnull_check(protocol); /* copy the first protocol name */ memcpy_check(conn->application_protocol, protocol, protocol_len); conn->application_protocol[protocol_len] = '\0'; return 0; }
static int s2n_recv_client_alpn(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; struct s2n_stuffer client_protos; struct s2n_stuffer server_protos; if (!conn->config->application_protocols.size) { /* No protocols configured, nothing to do */ return 0; } GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all < 3) { /* Malformed length, ignore the extension */ return 0; } struct s2n_blob application_protocols = { .data = s2n_stuffer_raw_read(extension, size_of_all), .size = size_of_all }; notnull_check(application_protocols.data); /* Find a matching protocol */ GUARD(s2n_stuffer_init(&client_protos, &application_protocols)); GUARD(s2n_stuffer_write(&client_protos, &application_protocols)); GUARD(s2n_stuffer_init(&server_protos, &conn->config->application_protocols)); GUARD(s2n_stuffer_write(&server_protos, &conn->config->application_protocols)); while (s2n_stuffer_data_available(&server_protos)) { uint8_t length; uint8_t protocol[255]; GUARD(s2n_stuffer_read_uint8(&server_protos, &length)); GUARD(s2n_stuffer_read_bytes(&server_protos, protocol, length)); while (s2n_stuffer_data_available(&client_protos)) { uint8_t client_length; GUARD(s2n_stuffer_read_uint8(&client_protos, &client_length)); if (client_length > s2n_stuffer_data_available(&client_protos)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } if (client_length != length) { GUARD(s2n_stuffer_skip_read(&client_protos, client_length)); } else { uint8_t client_protocol[255]; GUARD(s2n_stuffer_read_bytes(&client_protos, client_protocol, client_length)); if (memcmp(client_protocol, protocol, client_length) == 0) { memcpy_check(conn->application_protocol, client_protocol, client_length); conn->application_protocol[client_length] = '\0'; return 0; } } } GUARD(s2n_stuffer_reread(&client_protos)); } S2N_ERROR(S2N_ERR_NO_APPLICATION_PROTOCOL); } static int s2n_recv_client_status_request(struct s2n_connection *conn, struct s2n_stuffer *extension) { if (s2n_stuffer_data_available(extension) < 5) { /* Malformed length, ignore the extension */ return 0; } uint8_t type; GUARD(s2n_stuffer_read_uint8(extension, &type)); if (type != (uint8_t) S2N_STATUS_REQUEST_OCSP) { /* We only support OCSP (type 1), ignore the extension */ return 0; } conn->status_type = (s2n_status_request_type) type; return 0; } static int s2n_recv_client_elliptic_curves(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; struct s2n_blob proposed_curves; GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all % 2) { /* Malformed length, ignore the extension */ return 0; } proposed_curves.size = size_of_all; proposed_curves.data = s2n_stuffer_raw_read(extension, proposed_curves.size); notnull_check(proposed_curves.data); if (s2n_ecc_find_supported_curve(&proposed_curves, &conn->secure.server_ecc_params.negotiated_curve) != 0) { /* Can't agree on a curve, ECC is not allowed. Return success to proceed with the handshake. */ conn->secure.server_ecc_params.negotiated_curve = NULL; } return 0; }
int s2n_server_hello_recv(struct s2n_connection *conn) { struct s2n_stuffer *in = &conn->handshake.io; uint8_t compression_method; uint8_t session_id[S2N_TLS_SESSION_ID_LEN]; uint8_t session_id_len; uint16_t extensions_size; uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); conn->server_protocol_version = (protocol_version[0] * 10) + protocol_version[1]; if (conn->server_protocol_version > conn->actual_protocol_version) { GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); S2N_ERROR(S2N_ERR_BAD_MESSAGE); } conn->actual_protocol_version = conn->server_protocol_version; conn->actual_protocol_version_established = 1; /* Verify that the protocol version is sane */ if (conn->actual_protocol_version < S2N_SSLv3 || conn->actual_protocol_version > S2N_TLS12) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } conn->pending.signature_digest_alg = S2N_HASH_MD5_SHA1; if (conn->actual_protocol_version == S2N_TLS12) { conn->pending.signature_digest_alg = S2N_HASH_SHA1; } GUARD(s2n_stuffer_read_bytes(in, conn->pending.server_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_stuffer_read_uint8(in, &session_id_len)); if (session_id_len > S2N_TLS_SESSION_ID_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } GUARD(s2n_stuffer_read_bytes(in, session_id, session_id_len)); uint8_t *cipher_suite_wire = s2n_stuffer_raw_read(in, S2N_TLS_CIPHER_SUITE_LEN); notnull_check(cipher_suite_wire); GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); GUARD(s2n_stuffer_read_uint8(in, &compression_method)); if (compression_method != S2N_TLS_COMPRESSION_METHOD_NULL) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } if (s2n_stuffer_data_available(in) < 2) { GUARD(s2n_conn_set_handshake_type(conn)); /* No extensions */ return 0; } GUARD(s2n_stuffer_read_uint16(in, &extensions_size)); if (extensions_size > s2n_stuffer_data_available(in)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } struct s2n_blob extensions; extensions.size = extensions_size; extensions.data = s2n_stuffer_raw_read(in, extensions.size); GUARD(s2n_server_extensions_recv(conn, &extensions)); GUARD(s2n_conn_set_handshake_type(conn)); return 0; }
static int s2n_dhe_server_key_recv(struct s2n_connection *conn) { struct s2n_hash_state signature_hash; struct s2n_stuffer *in = &conn->handshake.io; struct s2n_blob p, g, Ys, serverDHparams, signature; uint16_t p_length; uint16_t g_length; uint16_t Ys_length; uint16_t signature_length; /* Keep a copy to the start of the whole structure for the signature check */ serverDHparams.data = s2n_stuffer_raw_read(in, 0); notnull_check(serverDHparams.data); /* Read each of the three elements in */ GUARD(s2n_stuffer_read_uint16(in, &p_length)); p.size = p_length; p.data = s2n_stuffer_raw_read(in, p.size); notnull_check(p.data); GUARD(s2n_stuffer_read_uint16(in, &g_length)); g.size = g_length; g.data = s2n_stuffer_raw_read(in, g.size); notnull_check(g.data); GUARD(s2n_stuffer_read_uint16(in, &Ys_length)); Ys.size = Ys_length; Ys.data = s2n_stuffer_raw_read(in, Ys.size); notnull_check(Ys.data); /* Now we know the total size of the structure */ serverDHparams.size = 2 + p_length + 2 + g_length + 2 + Ys_length; GUARD(s2n_hash_init(&signature_hash, conn->secure.signature_digest_alg)); if (conn->actual_protocol_version == S2N_TLS12) { uint8_t hash_algorithm; uint8_t signature_algorithm; GUARD(s2n_stuffer_read_uint8(in, &hash_algorithm)); GUARD(s2n_stuffer_read_uint8(in, &signature_algorithm)); if (signature_algorithm != TLS_SIGNATURE_ALGORITHM_RSA) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } switch(hash_algorithm) { case TLS_HASH_ALGORITHM_MD5: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_MD5)); break; case TLS_HASH_ALGORITHM_SHA1: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA1)); break; case TLS_HASH_ALGORITHM_SHA224: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA224)); break; case TLS_HASH_ALGORITHM_SHA256: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA256)); break; case TLS_HASH_ALGORITHM_SHA384: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA384)); break; case TLS_HASH_ALGORITHM_SHA512: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA512)); break; default: S2N_ERROR(S2N_ERR_BAD_MESSAGE); } } GUARD(s2n_hash_update(&signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_hash_update(&signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_hash_update(&signature_hash, serverDHparams.data, serverDHparams.size)); GUARD(s2n_stuffer_read_uint16(in, &signature_length)); signature.size = signature_length; signature.data = s2n_stuffer_raw_read(in, signature.size); notnull_check(signature.data); gt_check(signature_length, 0); if (s2n_rsa_verify(&conn->secure.server_rsa_public_key, &signature_hash, &signature) < 0) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } /* We don't need the key any more, so free it */ GUARD(s2n_rsa_public_key_free(&conn->secure.server_rsa_public_key)); /* Copy the DH details */ GUARD(s2n_dh_p_g_Ys_to_dh_params(&conn->secure.server_dh_params, &p, &g, &Ys)); return 0; }
int s2n_client_hello_recv(struct s2n_connection *conn) { struct s2n_stuffer *in = &conn->handshake.io; uint8_t compression_methods; uint16_t extensions_size; uint16_t cipher_suites_length; uint8_t *cipher_suites; uint8_t client_protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; GUARD(s2n_stuffer_read_bytes(in, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); GUARD(s2n_stuffer_read_bytes(in, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_stuffer_read_uint8(in, &conn->session_id_len)); conn->client_protocol_version = (client_protocol_version[0] * 10) + client_protocol_version[1]; if (conn->client_protocol_version < conn->config->cipher_preferences->minimum_protocol_version || conn->client_protocol_version > conn->server_protocol_version) { GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); S2N_ERROR(S2N_ERR_BAD_MESSAGE); } conn->client_hello_version = conn->client_protocol_version; conn->actual_protocol_version = MIN(conn->client_protocol_version, conn->server_protocol_version); if (conn->session_id_len > S2N_TLS_SESSION_ID_MAX_LEN || conn->session_id_len > s2n_stuffer_data_available(in)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } GUARD(s2n_stuffer_read_bytes(in, conn->session_id, conn->session_id_len)); GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); if (cipher_suites_length % S2N_TLS_CIPHER_SUITE_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } cipher_suites = s2n_stuffer_raw_read(in, cipher_suites_length); notnull_check(cipher_suites); /* Don't choose the cipher yet, read the extensions first */ GUARD(s2n_stuffer_read_uint8(in, &compression_methods)); GUARD(s2n_stuffer_skip_read(in, compression_methods)); /* This is going to be our default if the client has no preference. */ conn->secure.server_ecc_params.negotiated_curve = &s2n_ecc_supported_curves[0]; if (s2n_stuffer_data_available(in) >= 2) { /* Read extensions if they are present */ GUARD(s2n_stuffer_read_uint16(in, &extensions_size)); if (extensions_size > s2n_stuffer_data_available(in)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } struct s2n_blob extensions; extensions.size = extensions_size; extensions.data = s2n_stuffer_raw_read(in, extensions.size); notnull_check(extensions.data); GUARD(s2n_client_extensions_recv(conn, &extensions)); } /* Now choose the ciphers and the cert chain. */ GUARD(s2n_set_cipher_as_tls_server(conn, cipher_suites, cipher_suites_length / 2)); conn->server->chosen_cert_chain = conn->config->cert_and_key_pairs; /* Set the handshake type */ GUARD(s2n_conn_set_handshake_type(conn)); return 0; }
static int s2n_ecdhe_server_key_recv(struct s2n_connection *conn) { struct s2n_hash_state signature_hash; struct s2n_stuffer *in = &conn->handshake.io; struct s2n_blob ecdhparams; struct s2n_blob signature; uint16_t signature_length; /* Read server ECDH params and calculate their hash */ GUARD(s2n_ecc_read_ecc_params(&conn->secure.server_ecc_params, in, &ecdhparams)); GUARD(s2n_hash_init(&signature_hash, conn->secure.signature_digest_alg)); if (conn->actual_protocol_version == S2N_TLS12) { uint8_t hash_algorithm; uint8_t signature_algorithm; GUARD(s2n_stuffer_read_uint8(in, &hash_algorithm)); GUARD(s2n_stuffer_read_uint8(in, &signature_algorithm)); if (signature_algorithm != TLS_SIGNATURE_ALGORITHM_RSA) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } switch(hash_algorithm) { case TLS_HASH_ALGORITHM_MD5: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_MD5)); break; case TLS_HASH_ALGORITHM_SHA1: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA1)); break; case TLS_HASH_ALGORITHM_SHA224: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA224)); break; case TLS_HASH_ALGORITHM_SHA256: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA256)); break; case TLS_HASH_ALGORITHM_SHA384: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA384)); break; case TLS_HASH_ALGORITHM_SHA512: GUARD(s2n_hash_init(&signature_hash, S2N_HASH_SHA512)); break; default: S2N_ERROR(S2N_ERR_BAD_MESSAGE); } } GUARD(s2n_hash_update(&signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_hash_update(&signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_hash_update(&signature_hash, ecdhparams.data, ecdhparams.size)); /* Verify the signature */ GUARD(s2n_stuffer_read_uint16(in, &signature_length)); signature.size = signature_length; signature.data = s2n_stuffer_raw_read(in, signature.size); notnull_check(signature.data); gt_check(signature_length, 0); if (s2n_rsa_verify(&conn->secure.server_rsa_public_key, &signature_hash, &signature) < 0) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } /* We don't need the key any more, so free it */ GUARD(s2n_rsa_public_key_free(&conn->secure.server_rsa_public_key)); return 0; }