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; }
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 main(int argc, char **argv) { struct s2n_stuffer dhparams_in, dhparams_out; struct s2n_dh_params dh_params; struct s2n_blob b; BEGIN_TEST(); EXPECT_EQUAL(s2n_get_private_random_bytes_used(), 0); /* Parse the DH params */ b.data = dhparams; b.size = sizeof(dhparams); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_in, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_out, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_write(&dhparams_in, &b)); EXPECT_SUCCESS(s2n_stuffer_dhparams_from_pem(&dhparams_in, &dhparams_out)); b.size = s2n_stuffer_data_available(&dhparams_out); b.data = s2n_stuffer_raw_read(&dhparams_out, b.size); EXPECT_SUCCESS(s2n_pkcs3_to_dh_params(&dh_params, &b)); EXPECT_SUCCESS(s2n_dh_generate_ephemeral_key(&dh_params)); /* Verify that our DRBG is called and that over-riding works */ EXPECT_NOT_EQUAL(s2n_get_private_random_bytes_used(), 0); EXPECT_SUCCESS(s2n_dh_params_free(&dh_params)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_out)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_in)); END_TEST(); }
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)); }
int s2n_server_status_send(struct s2n_connection *conn) { uint32_t length = conn->config->cert_and_key_pairs->ocsp_status.size + 4; GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length)); GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, (uint8_t)S2N_STATUS_REQUEST_OCSP)); GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, conn->config->cert_and_key_pairs->ocsp_status.size)); GUARD(s2n_stuffer_write(&conn->handshake.io, &conn->config->cert_and_key_pairs->ocsp_status)); return 0; }
int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn) { uint8_t alert[2]; struct s2n_blob out = {.data = alert,.size = sizeof(alert) }; /* If there is an alert pending or we've already sent a close_notify, do nothing */ if (s2n_stuffer_data_available(&conn->writer_alert_out) || conn->close_notify_queued) { return 0; } alert[0] = S2N_TLS_ALERT_LEVEL_WARNING; alert[1] = S2N_TLS_ALERT_CLOSE_NOTIFY; GUARD(s2n_stuffer_write(&conn->writer_alert_out, &out)); conn->close_notify_queued = 1; return 0; } int s2n_queue_reader_unsupported_protocol_version_alert(struct s2n_connection *conn) { uint8_t alert[2]; struct s2n_blob out = {.data = alert,.size = sizeof(alert) }; /* If there is an alert pending, do nothing */ if (s2n_stuffer_data_available(&conn->reader_alert_out)) { return 0; } alert[0] = S2N_TLS_ALERT_LEVEL_FATAL; alert[1] = S2N_TLS_ALERT_PROTOCOL_VERSION; GUARD(s2n_stuffer_write(&conn->reader_alert_out, &out)); return 0; }
int s2n_server_status_send(struct s2n_connection *conn) { uint32_t length = conn->config->cert_and_key_pairs->ocsp_status.size + 4; GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length)); GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, (uint8_t)S2N_STATUS_REQUEST_OCSP)); GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, conn->config->cert_and_key_pairs->ocsp_status.size)); GUARD(s2n_stuffer_write(&conn->handshake.io, &conn->config->cert_and_key_pairs->ocsp_status)); conn->handshake.next_state = SERVER_HELLO_DONE; if (conn->pending.cipher_suite->key_exchange_alg->flags & S2N_KEY_EXCHANGE_EPH) { conn->handshake.next_state = SERVER_KEY; } return 0; }
int s2n_record_write(struct s2n_connection *conn, uint8_t content_type, struct s2n_blob *in) { struct s2n_blob out, iv, aad; uint8_t padding = 0; uint16_t block_size = 0; uint8_t aad_gen[S2N_TLS_MAX_AAD_LEN] = { 0 }; uint8_t aad_iv[S2N_TLS_MAX_IV_LEN] = { 0 }; uint8_t *sequence_number = conn->server->server_sequence_number; struct s2n_hmac_state *mac = &conn->server->server_record_mac; struct s2n_session_key *session_key = &conn->server->server_key; const struct s2n_cipher_suite *cipher_suite = conn->server->cipher_suite; uint8_t *implicit_iv = conn->server->server_implicit_iv; if (conn->mode == S2N_CLIENT) { sequence_number = conn->client->client_sequence_number; mac = &conn->client->client_record_mac; session_key = &conn->client->client_key; cipher_suite = conn->client->cipher_suite; implicit_iv = conn->client->client_implicit_iv; } S2N_ERROR_IF(s2n_stuffer_data_available(&conn->out), S2N_ERR_BAD_MESSAGE); uint8_t mac_digest_size; GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); /* Before we do anything, we need to figure out what the length of the * fragment is going to be. */ uint16_t data_bytes_to_take = MIN(in->size, s2n_record_max_write_payload_size(conn)); uint16_t extra = overhead(conn); /* If we have padding to worry about, figure that out too */ if (cipher_suite->record_alg->cipher->type == S2N_CBC) { block_size = cipher_suite->record_alg->cipher->io.cbc.block_size; if (((data_bytes_to_take + extra) % block_size)) { padding = block_size - ((data_bytes_to_take + extra) % block_size); } } else if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { block_size = cipher_suite->record_alg->cipher->io.comp.block_size; } /* Start the MAC with the sequence number */ GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); /* Now that we know the length, start writing the record */ GUARD(s2n_stuffer_write_uint8(&conn->out, content_type)); GUARD(s2n_record_write_protocol_version(conn)); /* First write a header that has the payload length, this is for the MAC */ GUARD(s2n_stuffer_write_uint16(&conn->out, data_bytes_to_take)); if (conn->actual_protocol_version > S2N_SSLv3) { GUARD(s2n_hmac_update(mac, conn->out.blob.data, S2N_TLS_RECORD_HEADER_LENGTH)); } else { /* SSLv3 doesn't include the protocol version in the MAC */ GUARD(s2n_hmac_update(mac, conn->out.blob.data, 1)); GUARD(s2n_hmac_update(mac, conn->out.blob.data + 3, 2)); } /* Compute non-payload parts of the MAC(seq num, type, proto vers, fragment length) for composite ciphers. * Composite "encrypt" will MAC the payload data and fill in padding. */ if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { /* Only fragment length is needed for MAC, but the EVP ctrl function needs fragment length + eiv len. */ uint16_t payload_and_eiv_len = data_bytes_to_take; if (conn->actual_protocol_version > S2N_TLS10) { payload_and_eiv_len += block_size; } /* Outputs number of extra bytes required for MAC and padding */ int pad_and_mac_len; GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, payload_and_eiv_len, &pad_and_mac_len)); extra += pad_and_mac_len; } /* Rewrite the length to be the actual fragment length */ uint16_t actual_fragment_length = data_bytes_to_take + padding + extra; GUARD(s2n_stuffer_wipe_n(&conn->out, 2)); GUARD(s2n_stuffer_write_uint16(&conn->out, actual_fragment_length)); /* If we're AEAD, write the sequence number as an IV, and generate the AAD */ if (cipher_suite->record_alg->cipher->type == S2N_AEAD) { struct s2n_stuffer iv_stuffer = {{0}}; iv.data = aad_iv; iv.size = sizeof(aad_iv); GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); if (cipher_suite->record_alg->flags & S2N_TLS12_AES_GCM_AEAD_NONCE) { /* Partially explicit nonce. See RFC 5288 Section 3 */ GUARD(s2n_stuffer_write_bytes(&conn->out, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); } else if (cipher_suite->record_alg->flags & S2N_TLS12_CHACHA_POLY_AEAD_NONCE) { /* Fully implicit nonce. See RFC7905 Section 2 */ uint8_t four_zeroes[4] = { 0 }; GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); for(int i = 0; i < cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; i++) { aad_iv[i] = aad_iv[i] ^ implicit_iv[i]; } } else { S2N_ERROR(S2N_ERR_INVALID_NONCE_TYPE); } /* Set the IV size to the amount of data written */ iv.size = s2n_stuffer_data_available(&iv_stuffer); aad.data = aad_gen; aad.size = sizeof(aad_gen); struct s2n_stuffer ad_stuffer = {{0}}; GUARD(s2n_stuffer_init(&ad_stuffer, &aad)); GUARD(s2n_aead_aad_init(conn, sequence_number, content_type, data_bytes_to_take, &ad_stuffer)); } else if (cipher_suite->record_alg->cipher->type == S2N_CBC || cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { iv.size = block_size; iv.data = implicit_iv; /* For TLS1.1/1.2; write the IV with random data */ if (conn->actual_protocol_version > S2N_TLS10) { GUARD(s2n_get_public_random_data(&iv)); GUARD(s2n_stuffer_write(&conn->out, &iv)); } } /* We are done with this sequence number, so we can increment it */ struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; GUARD(s2n_increment_sequence_number(&seq)); /* Write the plaintext data */ out.data = in->data; out.size = data_bytes_to_take; GUARD(s2n_stuffer_write(&conn->out, &out)); GUARD(s2n_hmac_update(mac, out.data, out.size)); /* Write the digest */ uint8_t *digest = s2n_stuffer_raw_write(&conn->out, mac_digest_size); notnull_check(digest); GUARD(s2n_hmac_digest(mac, digest, mac_digest_size)); GUARD(s2n_hmac_reset(mac)); if (cipher_suite->record_alg->cipher->type == S2N_CBC) { /* Include padding bytes, each with the value 'p', and * include an extra padding length byte, also with the value 'p'. */ for (int i = 0; i <= padding; i++) { GUARD(s2n_stuffer_write_uint8(&conn->out, padding)); } } /* Rewind to rewrite/encrypt the packet */ GUARD(s2n_stuffer_rewrite(&conn->out)); /* Skip the header */ GUARD(s2n_stuffer_skip_write(&conn->out, S2N_TLS_RECORD_HEADER_LENGTH)); uint16_t encrypted_length = data_bytes_to_take + mac_digest_size; switch (cipher_suite->record_alg->cipher->type) { case S2N_AEAD: GUARD(s2n_stuffer_skip_write(&conn->out, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); encrypted_length += cipher_suite->record_alg->cipher->io.aead.tag_size; break; case S2N_CBC: if (conn->actual_protocol_version > S2N_TLS10) { /* Leave the IV alone and unencrypted */ GUARD(s2n_stuffer_skip_write(&conn->out, iv.size)); } /* Encrypt the padding and the padding length byte too */ encrypted_length += padding + 1; break; case S2N_COMPOSITE: /* Composite CBC expects a pointer starting at explicit IV: [Explicit IV | fragment | MAC | padding | padding len ] * extra will account for the explicit IV len(if applicable), MAC digest len, padding len + padding byte. */ encrypted_length += extra; break; default: break; } /* Do the encryption */ struct s2n_blob en = {0}; en.size = encrypted_length; en.data = s2n_stuffer_raw_write(&conn->out, en.size); notnull_check(en.data); switch (cipher_suite->record_alg->cipher->type) { case S2N_STREAM: GUARD(cipher_suite->record_alg->cipher->io.stream.encrypt(session_key, &en, &en)); break; case S2N_CBC: GUARD(cipher_suite->record_alg->cipher->io.cbc.encrypt(session_key, &iv, &en, &en)); /* Copy the last encrypted block to be the next IV */ if (conn->actual_protocol_version < S2N_TLS11) { gte_check(en.size, block_size); memcpy_check(implicit_iv, en.data + en.size - block_size, block_size); } break; case S2N_AEAD: GUARD(cipher_suite->record_alg->cipher->io.aead.encrypt(session_key, &iv, &aad, &en, &en)); break; case S2N_COMPOSITE: /* This will: compute mac, append padding, append padding length, and encrypt */ GUARD(cipher_suite->record_alg->cipher->io.comp.encrypt(session_key, &iv, &en, &en)); /* Copy the last encrypted block to be the next IV */ gte_check(en.size, block_size); memcpy_check(implicit_iv, en.data + en.size - block_size, block_size); break; default: S2N_ERROR(S2N_ERR_CIPHER_TYPE); break; } conn->wire_bytes_out += actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH; return data_bytes_to_take; }
/** * Private helper: write n (up to 64) bits of hex data */ static int s2n_stuffer_write_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u) { uint8_t hex_data[16] = { 0 }; struct s2n_blob b = { .data = hex_data, .size = n / 4 }; lte_check(n, 64); for (int i = b.size; i > 0; i--) { b.data[i - 1] = hex[u & 0x0f]; u >>= 4; } GUARD(s2n_stuffer_write(stuffer, &b)); return 0; } int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u) { return s2n_stuffer_write_n_bits_hex(stuffer, 64, u); } int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u) { return s2n_stuffer_write_n_bits_hex(stuffer, 32, u); } int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u) { return s2n_stuffer_write_n_bits_hex(stuffer, 16, u); } int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u) { return s2n_stuffer_write_n_bits_hex(stuffer, 8, u); } int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str) { if (strlen(str) % 2) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } GUARD(s2n_stuffer_alloc(stuffer, strlen(str) / 2)); for (int i = 0; i < strlen(str); i += 2) { uint8_t u = 0; if (str[i] >= '0' && str[i] <= '9') { u = str[i] - '0'; } else if (str[i] >= 'a' && str[i] <= 'f') { u = str[i] - 'a' + 10; } else if (str[i] >= 'A' && str[i] <= 'F') { u = str[i] - 'A' + 10; } else { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } u <<= 4; if (str[i + 1] >= '0' && str[i + 1] <= '9') { u |= str[i + 1] - '0'; } else if (str[i + 1] >= 'a' && str[i + 1] <= 'f') { u |= str[i + 1] - 'a' + 10; } else if (str[i + 1] >= 'A' && str[i + 1] <= 'F') { u |= str[i + 1] - 'A' + 10; } else { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } GUARD(s2n_stuffer_write_uint8(stuffer, u)); } return 0; }
static int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label, struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out) { /* seed_a is always required, seed_b is optional, if seed_c is provided seed_b must also be provided */ S2N_ERROR_IF(seed_a == NULL, S2N_ERR_PRF_INVALID_SEED); S2N_ERROR_IF(seed_b == NULL && seed_c != NULL, S2N_ERR_PRF_INVALID_SEED); if (conn->actual_protocol_version == S2N_SSLv3) { return s2n_sslv3_prf(&conn->prf_space, secret, seed_a, seed_b, seed_c, out); } /* We zero the out blob because p_hash works by XOR'ing with the existing * buffer. This is a little convoluted but means we can avoid dynamic memory * allocation. When we call p_hash once (in the TLS1.2 case) it will produce * the right values. When we call it twice in the regular case, the two * outputs will be XORd just ass the TLS 1.0 and 1.1 RFCs require. */ GUARD(s2n_blob_zero(out)); /* Ensure that p_hash_hmac_impl is set, as it may have been reset for prf_space on s2n_connection_wipe. * When in FIPS mode, the EVP API's must be used for the p_hash HMAC. */ conn->prf_space.tls.p_hash_hmac_impl = s2n_is_in_fips_mode() ? &s2n_evp_hmac : &s2n_hmac; if (conn->actual_protocol_version == S2N_TLS12) { return s2n_p_hash(&conn->prf_space, conn->secure.cipher_suite->tls12_prf_alg, secret, label, seed_a, seed_b, seed_c, out); } struct s2n_blob half_secret = {.data = secret->data,.size = (secret->size + 1) / 2 }; GUARD(s2n_p_hash(&conn->prf_space, S2N_HMAC_MD5, &half_secret, label, seed_a, seed_b, seed_c, out)); half_secret.data += secret->size - half_secret.size; GUARD(s2n_p_hash(&conn->prf_space, S2N_HMAC_SHA1, &half_secret, label, seed_a, seed_b, seed_c, out)); return 0; } int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret) { struct s2n_blob client_random = {.size = sizeof(conn->secure.client_random), .data = conn->secure.client_random}; struct s2n_blob server_random = {.size = sizeof(conn->secure.server_random), .data = conn->secure.server_random}; struct s2n_blob master_secret = {.size = sizeof(conn->secure.master_secret), .data = conn->secure.master_secret}; uint8_t master_secret_label[] = "master secret"; struct s2n_blob label = {.size = sizeof(master_secret_label) - 1, .data = master_secret_label}; return s2n_prf(conn, premaster_secret, &label, &client_random, &server_random, NULL, &master_secret); } int s2n_hybrid_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret) { struct s2n_blob client_random = {.size = sizeof(conn->secure.client_random), .data = conn->secure.client_random}; struct s2n_blob server_random = {.size = sizeof(conn->secure.server_random), .data = conn->secure.server_random}; struct s2n_blob master_secret = {.size = sizeof(conn->secure.master_secret), .data = conn->secure.master_secret}; uint8_t master_secret_label[] = "hybrid master secret"; struct s2n_blob label = {.size = sizeof(master_secret_label) - 1, .data = master_secret_label}; return s2n_prf(conn, premaster_secret, &label, &client_random, &server_random, &conn->secure.client_key_exchange_message, &master_secret); } static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], struct s2n_hash_state *md5, struct s2n_hash_state *sha1, uint8_t * out) { uint8_t xorpad1[48] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 }; uint8_t xorpad2[48] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c }; uint8_t *md5_digest = out; uint8_t *sha_digest = out + MD5_DIGEST_LENGTH; lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); GUARD(s2n_hash_update(md5, prefix, 4)); GUARD(s2n_hash_update(md5, conn->secure.master_secret, sizeof(conn->secure.master_secret))); GUARD(s2n_hash_update(md5, xorpad1, 48)); GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); GUARD(s2n_hash_reset(md5)); GUARD(s2n_hash_update(md5, conn->secure.master_secret, sizeof(conn->secure.master_secret))); GUARD(s2n_hash_update(md5, xorpad2, 48)); GUARD(s2n_hash_update(md5, md5_digest, MD5_DIGEST_LENGTH)); GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); GUARD(s2n_hash_reset(md5)); GUARD(s2n_hash_update(sha1, prefix, 4)); GUARD(s2n_hash_update(sha1, conn->secure.master_secret, sizeof(conn->secure.master_secret))); GUARD(s2n_hash_update(sha1, xorpad1, 40)); GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); GUARD(s2n_hash_reset(sha1)); GUARD(s2n_hash_update(sha1, conn->secure.master_secret, sizeof(conn->secure.master_secret))); GUARD(s2n_hash_update(sha1, xorpad2, 40)); GUARD(s2n_hash_update(sha1, sha_digest, SHA_DIGEST_LENGTH)); GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); GUARD(s2n_hash_reset(sha1)); return 0; } static int s2n_sslv3_client_finished(struct s2n_connection *conn) { uint8_t prefix[4] = { 0x43, 0x4c, 0x4e, 0x54 }; lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); return s2n_sslv3_finished(conn, prefix, &conn->handshake.prf_md5_hash_copy, &conn->handshake.prf_sha1_hash_copy, conn->handshake.client_finished); } static int s2n_sslv3_server_finished(struct s2n_connection *conn) { uint8_t prefix[4] = { 0x53, 0x52, 0x56, 0x52 }; lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.server_finished)); GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); return s2n_sslv3_finished(conn, prefix, &conn->handshake.prf_md5_hash_copy, &conn->handshake.prf_sha1_hash_copy, conn->handshake.server_finished); } int s2n_prf_client_finished(struct s2n_connection *conn) { struct s2n_blob master_secret, md5, sha; uint8_t md5_digest[MD5_DIGEST_LENGTH]; uint8_t sha_digest[SHA384_DIGEST_LENGTH]; uint8_t client_finished_label[] = "client finished"; struct s2n_blob client_finished = {0}; struct s2n_blob label = {0}; if (conn->actual_protocol_version == S2N_SSLv3) { return s2n_sslv3_client_finished(conn); } client_finished.data = conn->handshake.client_finished; client_finished.size = S2N_TLS_FINISHED_LEN; label.data = client_finished_label; label.size = sizeof(client_finished_label) - 1; master_secret.data = conn->secure.master_secret; master_secret.size = sizeof(conn->secure.master_secret); if (conn->actual_protocol_version == S2N_TLS12) { switch (conn->secure.cipher_suite->tls12_prf_alg) { case S2N_HMAC_SHA256: GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha256)); GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA256_DIGEST_LENGTH)); sha.size = SHA256_DIGEST_LENGTH; break; case S2N_HMAC_SHA384: GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha384)); GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA384_DIGEST_LENGTH)); sha.size = SHA384_DIGEST_LENGTH; break; default: S2N_ERROR(S2N_ERR_PRF_INVALID_ALGORITHM); } sha.data = sha_digest; return s2n_prf(conn, &master_secret, &label, &sha, NULL, NULL, &client_finished); } GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); GUARD(s2n_hash_digest(&conn->handshake.prf_md5_hash_copy, md5_digest, MD5_DIGEST_LENGTH)); GUARD(s2n_hash_digest(&conn->handshake.prf_sha1_hash_copy, sha_digest, SHA_DIGEST_LENGTH)); md5.data = md5_digest; md5.size = MD5_DIGEST_LENGTH; sha.data = sha_digest; sha.size = SHA_DIGEST_LENGTH; return s2n_prf(conn, &master_secret, &label, &md5, &sha, NULL, &client_finished); } int s2n_prf_server_finished(struct s2n_connection *conn) { struct s2n_blob master_secret, md5, sha; uint8_t md5_digest[MD5_DIGEST_LENGTH]; uint8_t sha_digest[SHA384_DIGEST_LENGTH]; uint8_t server_finished_label[] = "server finished"; struct s2n_blob server_finished = {0}; struct s2n_blob label = {0}; if (conn->actual_protocol_version == S2N_SSLv3) { return s2n_sslv3_server_finished(conn); } server_finished.data = conn->handshake.server_finished; server_finished.size = S2N_TLS_FINISHED_LEN; label.data = server_finished_label; label.size = sizeof(server_finished_label) - 1; master_secret.data = conn->secure.master_secret; master_secret.size = sizeof(conn->secure.master_secret); if (conn->actual_protocol_version == S2N_TLS12) { switch (conn->secure.cipher_suite->tls12_prf_alg) { case S2N_HMAC_SHA256: GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha256)); GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA256_DIGEST_LENGTH)); sha.size = SHA256_DIGEST_LENGTH; break; case S2N_HMAC_SHA384: GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha384)); GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA384_DIGEST_LENGTH)); sha.size = SHA384_DIGEST_LENGTH; break; default: S2N_ERROR(S2N_ERR_PRF_INVALID_ALGORITHM); } sha.data = sha_digest; return s2n_prf(conn, &master_secret, &label, &sha, NULL, NULL, &server_finished); } GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); GUARD(s2n_hash_digest(&conn->handshake.prf_md5_hash_copy, md5_digest, MD5_DIGEST_LENGTH)); GUARD(s2n_hash_digest(&conn->handshake.prf_sha1_hash_copy, sha_digest, SHA_DIGEST_LENGTH)); md5.data = md5_digest; md5.size = MD5_DIGEST_LENGTH; sha.data = sha_digest; sha.size = SHA_DIGEST_LENGTH; return s2n_prf(conn, &master_secret, &label, &md5, &sha, NULL, &server_finished); } static int s2n_prf_make_client_key(struct s2n_connection *conn, struct s2n_stuffer *key_material) { struct s2n_blob client_key = {0}; client_key.size = conn->secure.cipher_suite->record_alg->cipher->key_material_size; client_key.data = s2n_stuffer_raw_read(key_material, client_key.size); notnull_check(client_key.data); if (conn->mode == S2N_CLIENT) { GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.client_key, &client_key)); } else { GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.client_key, &client_key)); } return 0; } static int s2n_prf_make_server_key(struct s2n_connection *conn, struct s2n_stuffer *key_material) { struct s2n_blob server_key = {0}; server_key.size = conn->secure.cipher_suite->record_alg->cipher->key_material_size; server_key.data = s2n_stuffer_raw_read(key_material, server_key.size); notnull_check(server_key.data); if (conn->mode == S2N_SERVER) { GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.server_key, &server_key)); } else { GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.server_key, &server_key)); } return 0; } int s2n_prf_key_expansion(struct s2n_connection *conn) { struct s2n_blob client_random = {.data = conn->secure.client_random,.size = sizeof(conn->secure.client_random) }; struct s2n_blob server_random = {.data = conn->secure.server_random,.size = sizeof(conn->secure.server_random) }; struct s2n_blob master_secret = {.data = conn->secure.master_secret,.size = sizeof(conn->secure.master_secret) }; struct s2n_blob label, out; uint8_t key_expansion_label[] = "key expansion"; uint8_t key_block[S2N_MAX_KEY_BLOCK_LEN]; label.data = key_expansion_label; label.size = sizeof(key_expansion_label) - 1; out.data = key_block; out.size = sizeof(key_block); struct s2n_stuffer key_material = {{0}}; GUARD(s2n_prf(conn, &master_secret, &label, &server_random, &client_random, NULL, &out)); GUARD(s2n_stuffer_init(&key_material, &out)); GUARD(s2n_stuffer_write(&key_material, &out)); GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.client_key)); GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.server_key)); /* Check that we have a valid MAC and key size */ uint8_t mac_size; if (conn->secure.cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { mac_size = conn->secure.cipher_suite->record_alg->cipher->io.comp.mac_key_size; } else { GUARD(s2n_hmac_digest_size(conn->secure.cipher_suite->record_alg->hmac_alg, &mac_size)); } /* Seed the client MAC */ uint8_t *client_mac_write_key = s2n_stuffer_raw_read(&key_material, mac_size); notnull_check(client_mac_write_key); GUARD(s2n_hmac_reset(&conn->secure.client_record_mac)); GUARD(s2n_hmac_init(&conn->secure.client_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, client_mac_write_key, mac_size)); /* Seed the server MAC */ uint8_t *server_mac_write_key = s2n_stuffer_raw_read(&key_material, mac_size); notnull_check(server_mac_write_key); GUARD(s2n_hmac_reset(&conn->secure.server_record_mac)); GUARD(s2n_hmac_init(&conn->secure.server_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, server_mac_write_key, mac_size)); /* Make the client key */ GUARD(s2n_prf_make_client_key(conn, &key_material)); /* Make the server key */ GUARD(s2n_prf_make_server_key(conn, &key_material)); /* Composite CBC does MAC inside the cipher, pass it the MAC key. * Must happen after setting encryption/decryption keys. */ if (conn->secure.cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.server_key, server_mac_write_key, mac_size)); GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.client_key, client_mac_write_key, mac_size)); } /* TLS >= 1.1 has no implicit IVs for non AEAD ciphers */ if (conn->actual_protocol_version > S2N_TLS10 && conn->secure.cipher_suite->record_alg->cipher->type != S2N_AEAD) { return 0; } uint32_t implicit_iv_size = 0; switch (conn->secure.cipher_suite->record_alg->cipher->type) { case S2N_AEAD: implicit_iv_size = conn->secure.cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; break; case S2N_CBC: implicit_iv_size = conn->secure.cipher_suite->record_alg->cipher->io.cbc.block_size; break; case S2N_COMPOSITE: implicit_iv_size = conn->secure.cipher_suite->record_alg->cipher->io.comp.block_size; break; /* No-op for stream ciphers */ default: break; } struct s2n_blob client_implicit_iv = {.data = conn->secure.client_implicit_iv,.size = implicit_iv_size }; struct s2n_blob server_implicit_iv = {.data = conn->secure.server_implicit_iv,.size = implicit_iv_size }; GUARD(s2n_stuffer_read(&key_material, &client_implicit_iv)); GUARD(s2n_stuffer_read(&key_material, &server_implicit_iv)); return 0; }
int main(int argc, char **argv) { struct s2n_stuffer certificate_in, certificate_out; struct s2n_stuffer dhparams_in, dhparams_out; struct s2n_stuffer rsa_key_in, rsa_key_out; struct s2n_blob b; BEGIN_TEST(); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_in, sizeof(certificate))); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_out, sizeof(certificate))); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_in, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_out, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_alloc(&rsa_key_in, sizeof(private_key))); EXPECT_SUCCESS(s2n_stuffer_alloc(&rsa_key_out, sizeof(private_key))); b.data = certificate; b.size = sizeof(certificate); EXPECT_SUCCESS(s2n_stuffer_write(&certificate_in, &b)); b.data = private_key; b.size = sizeof(private_key); EXPECT_SUCCESS(s2n_stuffer_write(&rsa_key_in, &b)); b.data = dhparams; b.size = sizeof(dhparams); EXPECT_SUCCESS(s2n_stuffer_write(&dhparams_in, &b)); EXPECT_SUCCESS(s2n_stuffer_certificate_from_pem(&certificate_in, &certificate_out)); EXPECT_SUCCESS(s2n_stuffer_rsa_private_key_from_pem(&rsa_key_in, &rsa_key_out)); EXPECT_SUCCESS(s2n_stuffer_dhparams_from_pem(&dhparams_in, &dhparams_out)); struct s2n_rsa_private_key priv_key; struct s2n_rsa_public_key pub_key; b.size = s2n_stuffer_data_available(&certificate_out); b.data = s2n_stuffer_raw_read(&certificate_out, b.size); EXPECT_SUCCESS(s2n_asn1der_to_rsa_public_key(&pub_key, &b)); b.size = s2n_stuffer_data_available(&rsa_key_out); b.data = s2n_stuffer_raw_read(&rsa_key_out, b.size); EXPECT_SUCCESS(s2n_asn1der_to_rsa_private_key(&priv_key, &b)); EXPECT_SUCCESS(s2n_rsa_keys_match(&pub_key, &priv_key)); struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key(conn->config, (char *)chain, (char *)private_key)); struct s2n_dh_params dh_params; b.size = s2n_stuffer_data_available(&dhparams_out); b.data = s2n_stuffer_raw_read(&dhparams_out, b.size); EXPECT_SUCCESS(s2n_pkcs3_to_dh_params(&dh_params, &b)); EXPECT_SUCCESS(s2n_config_add_dhparams(conn->config, (char *)dhparams)); /* Try signing and verification with RSA */ uint8_t inputpad[] = "Hello world!"; struct s2n_blob signature; struct s2n_hash_state tls10_one, tls10_two, tls12_one, tls12_two; EXPECT_SUCCESS(s2n_hash_init(&tls10_one, S2N_HASH_MD5_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls10_two, S2N_HASH_MD5_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls12_one, S2N_HASH_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls12_two, S2N_HASH_SHA1)); EXPECT_SUCCESS(s2n_alloc(&signature, s2n_rsa_public_encrypted_size(&pub_key))); EXPECT_SUCCESS(s2n_hash_update(&tls10_one, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_hash_update(&tls10_two, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_rsa_sign(&priv_key, &tls10_one, &signature)); EXPECT_SUCCESS(s2n_rsa_verify(&pub_key, &tls10_two, &signature)); EXPECT_SUCCESS(s2n_hash_update(&tls12_one, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_hash_update(&tls12_two, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_rsa_sign(&priv_key, &tls12_one, &signature)); EXPECT_SUCCESS(s2n_rsa_verify(&pub_key, &tls12_two, &signature)); EXPECT_SUCCESS(s2n_dh_params_free(&dh_params)); EXPECT_SUCCESS(s2n_rsa_private_key_free(&priv_key)); EXPECT_SUCCESS(s2n_rsa_public_key_free(&pub_key)); EXPECT_SUCCESS(s2n_config_free_dhparams(conn->config)); EXPECT_SUCCESS(s2n_config_free_cert_chain_and_key(conn->config)); EXPECT_SUCCESS(s2n_connection_free(conn)); EXPECT_SUCCESS(s2n_free(&signature)); EXPECT_SUCCESS(s2n_stuffer_free(&certificate_in)); EXPECT_SUCCESS(s2n_stuffer_free(&certificate_out)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_in)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_out)); EXPECT_SUCCESS(s2n_stuffer_free(&rsa_key_in)); EXPECT_SUCCESS(s2n_stuffer_free(&rsa_key_out)); END_TEST(); }
s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn, uint8_t *cert_chain_in, uint32_t cert_chain_len, s2n_cert_type *cert_type, struct s2n_pkey *public_key_out) { if (!validator->skip_cert_validation && !s2n_x509_trust_store_has_certs(validator->trust_store)) { return S2N_CERT_ERR_UNTRUSTED; } DEFER_CLEANUP(X509_STORE_CTX *ctx = NULL, X509_STORE_CTX_free_pointer); struct s2n_blob cert_chain_blob = {.data = cert_chain_in, .size = cert_chain_len}; DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = {{0}}, s2n_stuffer_free); if (s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob) < 0) { return S2N_CERT_ERR_INVALID; } if (s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob) < 0) { return S2N_CERT_ERR_INVALID; } uint32_t certificate_count = 0; X509 *server_cert = NULL; DEFER_CLEANUP(struct s2n_pkey public_key = {{{0}}}, s2n_pkey_free); s2n_pkey_zero_init(&public_key); while (s2n_stuffer_data_available(&cert_chain_in_stuffer) && certificate_count < validator->max_chain_depth) { uint32_t certificate_size = 0; if (s2n_stuffer_read_uint24(&cert_chain_in_stuffer, &certificate_size) < 0) { return S2N_CERT_ERR_INVALID; } if (certificate_size == 0 || certificate_size > s2n_stuffer_data_available(&cert_chain_in_stuffer)) { return S2N_CERT_ERR_INVALID; } struct s2n_blob asn1cert = {0}; asn1cert.data = s2n_stuffer_raw_read(&cert_chain_in_stuffer, certificate_size); asn1cert.size = certificate_size; if (asn1cert.data == NULL) { return S2N_CERT_ERR_INVALID; } const uint8_t *data = asn1cert.data; if (!validator->skip_cert_validation) { /* the cert is der encoded, just convert it. */ server_cert = d2i_X509(NULL, &data, asn1cert.size); if (!server_cert) { return S2N_CERT_ERR_INVALID; } /* add the cert to the chain. */ if (!sk_X509_push(validator->cert_chain, server_cert)) { X509_free(server_cert); return S2N_CERT_ERR_INVALID; } } /* Pull the public key from the first certificate */ if (certificate_count == 0) { if (s2n_asn1der_to_public_key_and_type(&public_key, cert_type, &asn1cert) < 0) { return S2N_CERT_ERR_INVALID; } } certificate_count++; } /* if this occurred we exceeded validator->max_chain_depth */ if (!validator->skip_cert_validation && s2n_stuffer_data_available(&cert_chain_in_stuffer)) { return S2N_CERT_ERR_MAX_CHAIN_DEPTH_EXCEEDED; } if (certificate_count < 1) { return S2N_CERT_ERR_INVALID; } if (!validator->skip_cert_validation) { X509 *leaf = sk_X509_value(validator->cert_chain, 0); if (!leaf) { return S2N_CERT_ERR_INVALID; } if (conn->verify_host_fn && !s2n_verify_host_information(validator, conn, leaf)) { return S2N_CERT_ERR_UNTRUSTED; } /* now that we have a chain, get the store and check against it. */ ctx = X509_STORE_CTX_new(); int op_code = X509_STORE_CTX_init(ctx, validator->trust_store->trust_store, leaf, validator->cert_chain); if (op_code <= 0) { return S2N_CERT_ERR_INVALID; } X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx); X509_VERIFY_PARAM_set_depth(param, validator->max_chain_depth); uint64_t current_sys_time = 0; conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_sys_time); /* this wants seconds not nanoseconds */ time_t current_time = (time_t)(current_sys_time / 1000000000); X509_STORE_CTX_set_time(ctx, 0, current_time); op_code = X509_verify_cert(ctx); if (op_code <= 0) { return S2N_CERT_ERR_UNTRUSTED; } } *public_key_out = public_key; /* Reset the old struct, so we don't clean up public_key_out */ s2n_pkey_zero_init(&public_key); return S2N_CERT_OK; }
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 main(int argc, char **argv) { BEGIN_TEST(); EXPECT_SUCCESS(setenv("S2N_ENABLE_CLIENT_MODE", "1", 0)); /* Part 1 setup a client and server connection with everything they need for a key exchange */ struct s2n_connection *client_conn, *server_conn; EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); struct s2n_config *server_config, *client_config; client_config = s2n_fetch_unsafe_client_testing_config(); GUARD(s2n_connection_set_config(client_conn, client_config)); /* Part 1.1 setup server's keypair and the give the client the certificate */ char *cert_chain; char *private_key; char *client_chain; EXPECT_NOT_NULL(cert_chain = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(private_key = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(client_chain = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(server_config = s2n_config_new()); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_CERT_CHAIN, cert_chain, S2N_MAX_TEST_PEM_SIZE)); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_KEY, private_key, S2N_MAX_TEST_PEM_SIZE)); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_LEAF_CERT, client_chain, S2N_MAX_TEST_PEM_SIZE)); struct s2n_cert_chain_and_key *chain_and_key; EXPECT_NOT_NULL(chain_and_key = s2n_cert_chain_and_key_new()); EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain, private_key)); EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, chain_and_key)); EXPECT_SUCCESS(s2n_connection_set_config(server_conn, server_config)); GUARD(s2n_set_signature_hash_pair_from_preference_list(server_conn, &server_conn->handshake_params.client_sig_hash_algs, &server_conn->secure.conn_hash_alg, &server_conn->secure.conn_sig_alg)); DEFER_CLEANUP(struct s2n_stuffer certificate_in = {{0}}, s2n_stuffer_free); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_in, S2N_MAX_TEST_PEM_SIZE)); DEFER_CLEANUP(struct s2n_stuffer certificate_out = {{0}}, s2n_stuffer_free); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_out, S2N_MAX_TEST_PEM_SIZE)); struct s2n_blob temp_blob; temp_blob.data = (uint8_t *) client_chain; temp_blob.size = strlen(client_chain) + 1; EXPECT_SUCCESS(s2n_stuffer_write(&certificate_in, &temp_blob)); EXPECT_SUCCESS(s2n_stuffer_certificate_from_pem(&certificate_in, &certificate_out)); temp_blob.size = s2n_stuffer_data_available(&certificate_out); temp_blob.data = s2n_stuffer_raw_read(&certificate_out, temp_blob.size); s2n_cert_type cert_type; EXPECT_SUCCESS(s2n_asn1der_to_public_key_and_type(&client_conn->secure.server_public_key, &cert_type, &temp_blob)); server_conn->handshake_params.our_chain_and_key = chain_and_key; EXPECT_SUCCESS(setup_connection(server_conn)); EXPECT_SUCCESS(setup_connection(client_conn)); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Read the seed from the RSP_FILE and create the DRBG for the test. Since the seed is the same (and prediction * resistance is off) all calls to generate random data will return the same sequence. Thus the server always * generates the same ECDHE point and KEM public key, the client does the same. */ FILE *kat_file = fopen(RSP_FILE_NAME, "r"); EXPECT_NOT_NULL(kat_file); EXPECT_SUCCESS(s2n_alloc(&kat_entropy_blob, 48)); EXPECT_SUCCESS(ReadHex(kat_file, kat_entropy_blob.data, 48, "seed = ")); struct s2n_drbg drbg = {.entropy_generator = &s2n_entropy_generator}; s2n_stack_blob(personalization_string, 32, 32); EXPECT_SUCCESS(s2n_drbg_instantiate(&drbg, &personalization_string, S2N_DANGEROUS_AES_256_CTR_NO_DF_NO_PR)); EXPECT_SUCCESS(s2n_set_private_drbg_for_test(drbg)); #endif /* Part 2 server sends key first */ EXPECT_SUCCESS(s2n_server_key_send(server_conn)); /* Part 2.1 verify the results as best we can */ EXPECT_EQUAL(server_conn->handshake.io.write_cursor, SERVER_KEY_MESSAGE_LENGTH); struct s2n_blob server_key_message = {.size = SERVER_KEY_MESSAGE_LENGTH, .data = s2n_stuffer_raw_read(&server_conn->handshake.io, SERVER_KEY_MESSAGE_LENGTH)}; #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 2.1.1 if we're running in known answer mode check the server's key exchange message matches the expected value */ uint8_t expected_server_key_message[SERVER_KEY_MESSAGE_LENGTH]; EXPECT_SUCCESS(ReadHex(kat_file, expected_server_key_message, SERVER_KEY_MESSAGE_LENGTH, "expected_server_key_exchange = ")); EXPECT_BYTEARRAY_EQUAL(expected_server_key_message, server_key_message.data, SERVER_KEY_MESSAGE_LENGTH); #endif /* Part 2.2 copy server's message to the client's stuffer */ s2n_stuffer_write(&client_conn->handshake.io, &server_key_message); /* Part 3 client recvs the server's key and sends the client key exchange message */ EXPECT_SUCCESS(s2n_server_key_recv(client_conn)); EXPECT_SUCCESS(s2n_client_key_send(client_conn)); /* Part 3.1 verify the results as best we can */ EXPECT_EQUAL(client_conn->handshake.io.write_cursor - client_conn->handshake.io.read_cursor, CLIENT_KEY_MESSAGE_LENGTH); struct s2n_blob client_key_message = {.size = CLIENT_KEY_MESSAGE_LENGTH, .data = s2n_stuffer_raw_read(&client_conn->handshake.io, CLIENT_KEY_MESSAGE_LENGTH)}; #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 3.1.1 if we're running in known answer mode check the client's key exchange message matches the expected value */ uint8_t expected_client_key_message[CLIENT_KEY_MESSAGE_LENGTH]; EXPECT_SUCCESS(ReadHex(kat_file, expected_client_key_message, CLIENT_KEY_MESSAGE_LENGTH, "expected_client_key_exchange = ")); EXPECT_BYTEARRAY_EQUAL(expected_client_key_message, client_key_message.data, CLIENT_KEY_MESSAGE_LENGTH); #endif /* Part 3.2 copy the client's message back to the server's stuffer */ s2n_stuffer_write(&server_conn->handshake.io, &client_key_message); /* Part 4 server receives the client's message */ EXPECT_SUCCESS(s2n_client_key_recv(server_conn)); /* Part 4.1 verify results as best we can, the client and server should at least have the same master secret */ EXPECT_BYTEARRAY_EQUAL(server_conn->secure.master_secret, client_conn->secure.master_secret, S2N_TLS_SECRET_LEN); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 4.1.1 if we're running in known answer mode check that both the client and server got the expected master secret * from the RSP_FILE */ uint8_t expected_master_secret[S2N_TLS_SECRET_LEN]; EXPECT_SUCCESS(ReadHex(kat_file, expected_master_secret, S2N_TLS_SECRET_LEN, "expected_master_secret = ")); EXPECT_BYTEARRAY_EQUAL(expected_master_secret, client_conn->secure.master_secret, S2N_TLS_SECRET_LEN); EXPECT_BYTEARRAY_EQUAL(expected_master_secret, server_conn->secure.master_secret, S2N_TLS_SECRET_LEN); #endif EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key)); EXPECT_SUCCESS(s2n_connection_free(client_conn)); EXPECT_SUCCESS(s2n_connection_free(server_conn)); EXPECT_SUCCESS(s2n_config_free(server_config)); free(cert_chain); free(client_chain); free(private_key); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Extra cleanup needed for the known answer test */ fclose(kat_file); #endif END_TEST(); }
int s2n_client_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out) { uint16_t total_size = 0; /* Signature algorithms */ if (conn->actual_protocol_version == S2N_TLS12) { total_size += (sizeof(s2n_preferred_hashes) * 2) + 6; } uint16_t application_protocols_len = conn->config->application_protocols.size; uint16_t server_name_len = strlen(conn->server_name); uint16_t mfl_code_len = sizeof(conn->config->mfl_code); if (server_name_len) { total_size += 9 + server_name_len; } if (application_protocols_len) { total_size += 6 + application_protocols_len; } if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) { total_size += 9; } if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) { total_size += 4; } if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) { total_size += 5; } /* Write ECC extensions: Supported Curves and Supported Point Formats */ int ec_curves_count = sizeof(s2n_ecc_supported_curves) / sizeof(s2n_ecc_supported_curves[0]); total_size += 12 + ec_curves_count * 2; GUARD(s2n_stuffer_write_uint16(out, total_size)); if (conn->actual_protocol_version == S2N_TLS12) { GUARD(s2n_send_client_signature_algorithms_extension(conn, out)); } if (server_name_len) { /* Write the server name */ GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SERVER_NAME)); GUARD(s2n_stuffer_write_uint16(out, server_name_len + 5)); /* Size of all of the server names */ GUARD(s2n_stuffer_write_uint16(out, server_name_len + 3)); /* Name type - host name, RFC3546 */ GUARD(s2n_stuffer_write_uint8(out, 0)); struct s2n_blob server_name; server_name.data = (uint8_t *) conn->server_name; server_name.size = server_name_len; GUARD(s2n_stuffer_write_uint16(out, server_name_len)); GUARD(s2n_stuffer_write(out, &server_name)); } /* Write ALPN extension */ if (application_protocols_len) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ALPN)); GUARD(s2n_stuffer_write_uint16(out, application_protocols_len + 2)); GUARD(s2n_stuffer_write_uint16(out, application_protocols_len)); GUARD(s2n_stuffer_write(out, &conn->config->application_protocols)); } if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) { /* We only support OCSP */ eq_check(conn->config->status_request_type, S2N_STATUS_REQUEST_OCSP); GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_STATUS_REQUEST)); GUARD(s2n_stuffer_write_uint16(out, 5)); GUARD(s2n_stuffer_write_uint8(out, (uint8_t) conn->config->status_request_type)); GUARD(s2n_stuffer_write_uint16(out, 0)); GUARD(s2n_stuffer_write_uint16(out, 0)); } /* Write Certificate Transparency extension */ if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SCT_LIST)); GUARD(s2n_stuffer_write_uint16(out, 0)); } /* Write Maximum Fragmentation Length extension */ if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_MAX_FRAG_LEN)); GUARD(s2n_stuffer_write_uint16(out, mfl_code_len)); GUARD(s2n_stuffer_write_uint8(out, conn->config->mfl_code)); } /* * RFC 4492: Clients SHOULD send both the Supported Elliptic Curves Extension * and the Supported Point Formats Extension. */ { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ELLIPTIC_CURVES)); GUARD(s2n_stuffer_write_uint16(out, 2 + ec_curves_count * 2)); /* Curve list len */ GUARD(s2n_stuffer_write_uint16(out, ec_curves_count * 2)); /* Curve list */ for (int i = 0; i < ec_curves_count; i++) { GUARD(s2n_stuffer_write_uint16(out, s2n_ecc_supported_curves[i].iana_id)); } GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_EC_POINT_FORMATS)); GUARD(s2n_stuffer_write_uint16(out, 2)); /* Point format list len */ GUARD(s2n_stuffer_write_uint8(out, 1)); /* Only allow uncompressed format */ GUARD(s2n_stuffer_write_uint8(out, 0)); } return 0; }
int s2n_prf_key_expansion(struct s2n_connection *conn) { struct s2n_blob client_random = {.data = conn->secure.client_random,.size = sizeof(conn->secure.client_random) }; struct s2n_blob server_random = {.data = conn->secure.server_random,.size = sizeof(conn->secure.server_random) }; struct s2n_blob master_secret = {.data = conn->secure.master_secret,.size = sizeof(conn->secure.master_secret) }; struct s2n_blob label, out; uint8_t key_expansion_label[] = "key expansion"; uint8_t key_block[S2N_MAX_KEY_BLOCK_LEN]; label.data = key_expansion_label; label.size = sizeof(key_expansion_label) - 1; out.data = key_block; out.size = sizeof(key_block); struct s2n_stuffer key_material; GUARD(s2n_prf(conn, &master_secret, &label, &server_random, &client_random, &out)); GUARD(s2n_stuffer_init(&key_material, &out)); GUARD(s2n_stuffer_write(&key_material, &out)); GUARD(conn->secure.cipher_suite->cipher->init(&conn->secure.client_key)); GUARD(conn->secure.cipher_suite->cipher->init(&conn->secure.server_key)); /* What's our hmac algorithm? */ s2n_hmac_algorithm hmac_alg = conn->secure.cipher_suite->hmac_alg; if (conn->actual_protocol_version == S2N_SSLv3) { if (hmac_alg == S2N_HMAC_SHA1) { hmac_alg = S2N_HMAC_SSLv3_SHA1; } else if (hmac_alg == S2N_HMAC_MD5) { hmac_alg = S2N_HMAC_SSLv3_MD5; } else { S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); } } /* Check that we have a valid MAC and key size */ int mac_size; GUARD((mac_size = s2n_hmac_digest_size(hmac_alg))); /* Seed the client MAC */ uint8_t *client_write_mac_key = s2n_stuffer_raw_read(&key_material, mac_size); notnull_check(client_write_mac_key); GUARD(s2n_hmac_init(&conn->secure.client_record_mac, hmac_alg, client_write_mac_key, mac_size)); /* Seed the server MAC */ uint8_t *server_write_mac_key = s2n_stuffer_raw_read(&key_material, mac_size); notnull_check(server_write_mac_key); GUARD(s2n_hmac_init(&conn->secure.server_record_mac, hmac_alg, server_write_mac_key, mac_size)); /* Make the client key */ struct s2n_blob client_key; client_key.size = conn->secure.cipher_suite->cipher->key_material_size; client_key.data = s2n_stuffer_raw_read(&key_material, client_key.size); notnull_check(client_key.data); if (conn->mode == S2N_CLIENT) { GUARD(conn->secure.cipher_suite->cipher->get_encryption_key(&conn->secure.client_key, &client_key)); } else { GUARD(conn->secure.cipher_suite->cipher->get_decryption_key(&conn->secure.client_key, &client_key)); } /* Make the server key */ struct s2n_blob server_key; server_key.size = conn->secure.cipher_suite->cipher->key_material_size; server_key.data = s2n_stuffer_raw_read(&key_material, server_key.size); notnull_check(server_key.data); if (conn->mode == S2N_SERVER) { GUARD(conn->secure.cipher_suite->cipher->get_encryption_key(&conn->secure.server_key, &server_key)); } else { GUARD(conn->secure.cipher_suite->cipher->get_decryption_key(&conn->secure.server_key, &server_key)); } /* TLS >= 1.1 has no implicit IVs for non AEAD ciphers */ if (conn->actual_protocol_version > S2N_TLS10 && conn->secure.cipher_suite->cipher->type != S2N_AEAD) { return 0; } uint32_t implicit_iv_size = 0; switch(conn->secure.cipher_suite->cipher->type) { case S2N_AEAD: implicit_iv_size = conn->secure.cipher_suite->cipher->io.aead.fixed_iv_size; break; case S2N_CBC: implicit_iv_size = conn->secure.cipher_suite->cipher->io.cbc.block_size; break; /* No-op for stream ciphers */ default: break; } struct s2n_blob client_implicit_iv = { .data = conn->secure.client_implicit_iv, .size = implicit_iv_size }; struct s2n_blob server_implicit_iv = { .data = conn->secure.server_implicit_iv, .size = implicit_iv_size }; GUARD(s2n_stuffer_read(&key_material, &client_implicit_iv)); GUARD(s2n_stuffer_read(&key_material, &server_implicit_iv)); return 0; }