int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char *pem) { notnull_check(store); notnull_check(pem); if (!store->trust_store) { store->trust_store = X509_STORE_new(); } DEFER_CLEANUP(struct s2n_stuffer pem_in_stuffer = {{0}}, s2n_stuffer_free); DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = {{0}}, s2n_stuffer_free); GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem)); GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048)); do { DEFER_CLEANUP(struct s2n_blob next_cert = {0}, s2n_free); GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer)); GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer))); GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert)); const uint8_t *data = next_cert.data; DEFER_CLEANUP(X509 *ca_cert = d2i_X509(NULL, &data, next_cert.size), X509_free_pointer); S2N_ERROR_IF(ca_cert == NULL, S2N_ERR_DECODE_CERTIFICATE); GUARD_OSSL(X509_STORE_add_cert(store->trust_store, ca_cert), S2N_ERR_DECODE_CERTIFICATE); } while (s2n_stuffer_data_available(&pem_in_stuffer)); return 0; }
int s2n_process_alert_fragment(struct s2n_connection *conn) { if (s2n_stuffer_data_available(&conn->alert_in) == 2) { S2N_ERROR(S2N_ERR_ALERT_PRESENT); } while (s2n_stuffer_data_available(&conn->in)) { uint8_t bytes_required = 2; /* Alerts are two bytes long, but can still be fragmented or coalesced */ if (s2n_stuffer_data_available(&conn->alert_in) == 1) { bytes_required = 1; } int bytes_to_read = MIN(bytes_required, s2n_stuffer_data_available(&conn->in)); GUARD(s2n_stuffer_copy(&conn->in, &conn->alert_in, bytes_to_read)); if (s2n_stuffer_data_available(&conn->alert_in) == 2) { conn->closed = 1; /* Close notifications are handled as shutdowns */ if (conn->alert_in_data[1] == S2N_TLS_ALERT_CLOSE_NOTIFY) { return 0; } /* All other alerts are treated as fatal errors (even warnings) */ S2N_ERROR(S2N_ERR_ALERT); } } 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_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_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 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(); }
/* 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_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n) { if (s2n_stuffer_data_available(stuffer) < n) { S2N_ERROR(S2N_ERR_STUFFER_OUT_OF_DATA); } stuffer->read_cursor += n; 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; }
static int s2n_recv_client_renegotiation_info(struct s2n_connection *conn, struct s2n_stuffer *extension) { /* RFC5746 Section 3.2: The renegotiated_connection field is of zero length for the initial handshake. */ uint8_t renegotiated_connection_len; GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); if (s2n_stuffer_data_available(extension) || renegotiated_connection_len) { S2N_ERROR(S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO); } conn->secure_renegotiation = 1; return 0; }
int s2n_connection_get_alert(struct s2n_connection *conn) { if (s2n_stuffer_data_available(&conn->alert_in) != 2) { S2N_ERROR(S2N_ERR_NO_ALERT); } uint8_t alert_code = 0; GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); return alert_code; }
int s2n_handshake_parse_header(struct s2n_connection *conn, uint8_t * message_type, uint32_t * length) { if (s2n_stuffer_data_available(&conn->handshake.io) < TLS_HANDSHAKE_HEADER_LENGTH) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } /* read the message header */ GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, message_type)); GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, length)); 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_handshake_write_header(struct s2n_connection *conn, uint8_t message_type) { if (s2n_stuffer_data_available(&conn->handshake.io)) { S2N_ERROR(S2N_ERR_HANDSHAKE_STATE); } /* Write the message header */ GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, message_type)); /* Leave the length blank for now */ uint16_t length = 0; GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length)); return 0; }
int s2n_handshake_finish_header(struct s2n_connection *conn) { uint16_t length = s2n_stuffer_data_available(&conn->handshake.io); if (length < TLS_HANDSHAKE_HEADER_LENGTH) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } uint16_t payload = length - TLS_HANDSHAKE_HEADER_LENGTH; /* Write the message header */ GUARD(s2n_stuffer_rewrite(&conn->handshake.io)); GUARD(s2n_stuffer_skip_write(&conn->handshake.io, 1)); GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, payload)); GUARD(s2n_stuffer_skip_write(&conn->handshake.io, payload)); 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; }
int s2n_server_cert_recv(struct s2n_connection *conn) { uint32_t size_of_all_certificates; GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &size_of_all_certificates)); S2N_ERROR_IF(size_of_all_certificates > s2n_stuffer_data_available(&conn->handshake.io) || size_of_all_certificates < 3, S2N_ERR_BAD_MESSAGE); s2n_cert_public_key public_key; GUARD(s2n_pkey_zero_init(&public_key)); s2n_cert_type cert_type; struct s2n_blob cert_chain = {0}; cert_chain.data = s2n_stuffer_raw_read(&conn->handshake.io, size_of_all_certificates); cert_chain.size = size_of_all_certificates; S2N_ERROR_IF(s2n_x509_validator_validate_cert_chain(&conn->x509_validator, conn, cert_chain.data, cert_chain.size, &cert_type, &public_key) != S2N_CERT_OK, S2N_ERR_CERT_UNTRUSTED); s2n_authentication_method expected_auth_method = conn->secure.cipher_suite->auth_method; switch (cert_type) { case S2N_CERT_TYPE_RSA_SIGN: if (expected_auth_method == S2N_AUTHENTICATION_RSA) { break; } case S2N_CERT_TYPE_ECDSA_SIGN: if (expected_auth_method == S2N_AUTHENTICATION_ECDSA) { break; } default: S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); } conn->secure.client_cert_type = cert_type; s2n_pkey_setup_for_type(&public_key, cert_type); conn->secure.server_public_key = public_key; return 0; }
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 main(int argc, char **argv) { struct s2n_connection *conn; uint8_t mac_key[] = "sample mac key"; uint8_t rc4_key[] = "123456789012345"; struct s2n_blob key_iv = {.data = rc4_key,.size = sizeof(rc4_key) }; uint8_t random_data[S2N_SMALL_FRAGMENT_LENGTH + 1]; struct s2n_blob r = {.data = random_data, .size = sizeof(random_data)}; BEGIN_TEST(); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_get_urandom_data(&r)); /* Peer and we are in sync */ conn->server = &conn->active; /* test the RC4 cipher with a SHA1 hash */ conn->active.cipher_suite->cipher = &s2n_rc4; conn->active.cipher_suite->hmac_alg = S2N_HMAC_SHA1; EXPECT_SUCCESS(conn->active.cipher_suite->cipher->init(&conn->active.server_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->init(&conn->active.client_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_decryption_key(&conn->active.client_key, &key_iv)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_encryption_key(&conn->active.server_key, &key_iv)); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.client_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); conn->actual_protocol_version = S2N_TLS11; for (int i = 0; i <= S2N_SMALL_FRAGMENT_LENGTH + 1; i++) { struct s2n_blob in = {.data = random_data,.size = i }; int bytes_written; EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &in)); if (i <= S2N_SMALL_FRAGMENT_LENGTH - 20) { EXPECT_EQUAL(bytes_written, i); } else { EXPECT_EQUAL(bytes_written, S2N_SMALL_FRAGMENT_LENGTH - 20); } uint16_t predicted_length = bytes_written + 20; EXPECT_EQUAL(conn->out.blob.data[0], TLS_APPLICATION_DATA); EXPECT_EQUAL(conn->out.blob.data[1], 3); EXPECT_EQUAL(conn->out.blob.data[2], 2); EXPECT_EQUAL(conn->out.blob.data[3], (predicted_length >> 8) & 0xff); EXPECT_EQUAL(conn->out.blob.data[4], predicted_length & 0xff); /* The data should be encrypted */ if (bytes_written > 10) { EXPECT_NOT_EQUAL(memcmp(conn->out.blob.data + 5, random_data, bytes_written), 0); } /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)) EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))) /* Check that the data looks right */ EXPECT_EQUAL(bytes_written + 20, s2n_stuffer_data_available(&conn->in)); /* Let's decrypt it */ uint8_t content_type; uint16_t fragment_length; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_SUCCESS(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_EQUAL(fragment_length, predicted_length); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.server_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.client_key)); EXPECT_SUCCESS(s2n_connection_free(conn)); END_TEST(); }
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; }
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(); }
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(); }
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_config_free_cert_chain_and_key(struct s2n_config *config) { struct s2n_blob b = { .data = (uint8_t *) config->cert_and_key_pairs, .size = sizeof(struct s2n_cert_chain_and_key) }; /* If there were cert and key pairs set, walk the chain and free the certs */ if (config->cert_and_key_pairs) { struct s2n_cert_chain *node = config->cert_and_key_pairs->head; while (node) { struct s2n_blob n = { .data = (uint8_t *)node, .size = sizeof(struct s2n_cert_chain) }; /* Free the cert */ GUARD(s2n_free(&node->cert)); /* Advance to next */ node = node->next; /* Free the node */ GUARD(s2n_free(&n)); } GUARD(s2n_rsa_private_key_free(&config->cert_and_key_pairs->private_key)); GUARD(s2n_free(&config->cert_and_key_pairs->ocsp_status)); } GUARD(s2n_free(&b)); return 0; } int s2n_config_free_dhparams(struct s2n_config *config) { struct s2n_blob b = { .data = (uint8_t *) config->dhparams, .size = sizeof(struct s2n_dh_params) }; if (config->dhparams) { GUARD(s2n_dh_params_free(config->dhparams)); } GUARD(s2n_free(&b)); return 0; } int s2n_config_free(struct s2n_config *config) { struct s2n_blob b = {.data = (uint8_t *) config,.size = sizeof(struct s2n_config) }; GUARD(s2n_config_free_cert_chain_and_key(config)); GUARD(s2n_config_free_dhparams(config)); GUARD(s2n_free(&config->application_protocols)); GUARD(s2n_free(&b)); return 0; } int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version) { for (int i = 0; selection[i].version != NULL; i++) { if (!strcasecmp(version, selection[i].version)) { config->cipher_preferences = selection[i].preferences; return 0; } } s2n_errno = S2N_ERR_INVALID_CIPHER_PREFERENCES; return -1; } int s2n_config_set_protocol_preferences(struct s2n_config *config, const char * const *protocols, int protocol_count) { struct s2n_stuffer protocol_stuffer; GUARD(s2n_free(&config->application_protocols)); if (protocols == NULL || protocol_count == 0) { /* NULL value indicates no prference, so nothing to do */ return 0; } GUARD(s2n_stuffer_growable_alloc(&protocol_stuffer, 256)); for (int i = 0; i < protocol_count; i++) { size_t length = strlen(protocols[i]); uint8_t protocol[255]; if (length > 255 || (s2n_stuffer_data_available(&protocol_stuffer) + length + 1) > 65535) { return S2N_ERR_APPLICATION_PROTOCOL_TOO_LONG; } memcpy_check(protocol, protocols[i], length); GUARD(s2n_stuffer_write_uint8(&protocol_stuffer, length)); GUARD(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, length)); } uint32_t size = s2n_stuffer_data_available(&protocol_stuffer); /* config->application_protocols blob now owns this data */ config->application_protocols.size = size; config->application_protocols.data = s2n_stuffer_raw_read(&protocol_stuffer, size); notnull_check(config->application_protocols.data); return 0; } int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_request_type type) { config->status_request_type = type; return 0; } int s2n_config_add_cert_chain_and_key_with_status(struct s2n_config *config, char *cert_chain_pem, char *private_key_pem, const uint8_t *status, uint32_t length) { struct s2n_stuffer chain_in_stuffer, cert_out_stuffer, key_in_stuffer, key_out_stuffer; struct s2n_blob key_blob; struct s2n_blob mem; /* Allocate the memory for the chain and key struct */ GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert_chain_and_key))); config->cert_and_key_pairs = (struct s2n_cert_chain_and_key *)(void *)mem.data; config->cert_and_key_pairs->ocsp_status.data = NULL; config->cert_and_key_pairs->ocsp_status.size = 0; /* Put the private key pem in a stuffer */ GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem)); GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem))); /* Convert pem to asn1 and asn1 to the private key */ GUARD(s2n_stuffer_rsa_private_key_from_pem(&key_in_stuffer, &key_out_stuffer)); GUARD(s2n_stuffer_free(&key_in_stuffer)); key_blob.size = s2n_stuffer_data_available(&key_out_stuffer); key_blob.data = s2n_stuffer_raw_read(&key_out_stuffer, key_blob.size); notnull_check(key_blob.data); GUARD(s2n_asn1der_to_rsa_private_key(&config->cert_and_key_pairs->private_key, &key_blob)); GUARD(s2n_stuffer_free(&key_out_stuffer)); /* Turn the chain into a stuffer */ GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem)); GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048)); struct s2n_cert_chain **insert = &config->cert_and_key_pairs->head; uint32_t chain_size = 0; do { struct s2n_cert_chain *new_node; if (s2n_stuffer_certificate_from_pem(&chain_in_stuffer, &cert_out_stuffer) < 0) { if (chain_size == 0) { S2N_ERROR(S2N_ERR_NO_CERTIFICATE_IN_PEM); } break; } GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert_chain))); new_node = (struct s2n_cert_chain *)(void *)mem.data; GUARD(s2n_alloc(&new_node->cert, s2n_stuffer_data_available(&cert_out_stuffer))); GUARD(s2n_stuffer_read(&cert_out_stuffer, &new_node->cert)); /* Additional 3 bytes for the length field in the protocol */ chain_size += new_node->cert.size + 3; new_node->next = NULL; *insert = new_node; insert = &new_node->next; } while (s2n_stuffer_data_available(&chain_in_stuffer)); GUARD(s2n_stuffer_free(&chain_in_stuffer)); GUARD(s2n_stuffer_free(&cert_out_stuffer)); config->cert_and_key_pairs->chain_size = chain_size; if (status && length > 0) { GUARD(s2n_alloc(&config->cert_and_key_pairs->ocsp_status, length)); memcpy_check(config->cert_and_key_pairs->ocsp_status.data, status, length); } return 0; } int s2n_config_add_cert_chain_and_key(struct s2n_config *config, char *cert_chain_pem, char *private_key_pem) { GUARD(s2n_config_add_cert_chain_and_key_with_status(config, cert_chain_pem, private_key_pem, NULL, 0)); return 0; } int s2n_config_add_dhparams(struct s2n_config *config, char *dhparams_pem) { struct s2n_stuffer dhparams_in_stuffer, dhparams_out_stuffer; struct s2n_blob dhparams_blob; struct s2n_blob mem; /* Allocate the memory for the chain and key struct */ GUARD(s2n_alloc(&mem, sizeof(struct s2n_dh_params))); config->dhparams = (struct s2n_dh_params *)(void *)mem.data; GUARD(s2n_stuffer_alloc_ro_from_string(&dhparams_in_stuffer, dhparams_pem)); GUARD(s2n_stuffer_growable_alloc(&dhparams_out_stuffer, strlen(dhparams_pem))); /* Convert pem to asn1 and asn1 to the private key */ GUARD(s2n_stuffer_dhparams_from_pem(&dhparams_in_stuffer, &dhparams_out_stuffer)); GUARD(s2n_stuffer_free(&dhparams_in_stuffer)); dhparams_blob.size = s2n_stuffer_data_available(&dhparams_out_stuffer); dhparams_blob.data = s2n_stuffer_raw_read(&dhparams_out_stuffer, dhparams_blob.size); notnull_check(dhparams_blob.data); GUARD(s2n_pkcs3_to_dh_params(config->dhparams, &dhparams_blob)); GUARD(s2n_free(&dhparams_blob)); return 0; } int s2n_config_set_nanoseconds_since_epoch_callback(struct s2n_config *config, int (*nanoseconds_since_epoch)(void *, uint64_t *), void * data) { notnull_check(nanoseconds_since_epoch); config->nanoseconds_since_epoch = nanoseconds_since_epoch; config->data_for_nanoseconds_since_epoch = data; 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; }
int main(int argc, char **argv) { struct s2n_connection *conn; uint8_t random_data[S2N_DEFAULT_FRAGMENT_LENGTH + 1]; uint8_t mac_key[] = "sample mac key"; uint8_t aes128_key[] = "123456789012345"; uint8_t aes256_key[] = "1234567890123456789012345678901"; struct s2n_blob aes128 = {.data = aes128_key,.size = sizeof(aes128_key) }; struct s2n_blob aes256 = {.data = aes256_key,.size = sizeof(aes256_key) }; struct s2n_blob r = {.data = random_data, .size = sizeof(random_data)}; BEGIN_TEST(); EXPECT_SUCCESS(s2n_init()); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_get_urandom_data(&r)); /* Peer and we are in sync */ conn->server = &conn->active; conn->client = &conn->active; /* test the AES128 cipher with a SHA1 hash */ conn->active.cipher_suite->cipher = &s2n_aes128_gcm; conn->active.cipher_suite->hmac_alg = S2N_HMAC_SHA1; EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_encryption_key(&conn->active.server_key, &aes128)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_decryption_key(&conn->active.client_key, &aes128)); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.client_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); conn->actual_protocol_version = S2N_TLS12; int max_fragment = S2N_DEFAULT_FRAGMENT_LENGTH; for (int i = 0; i <= max_fragment + 1; i++) { struct s2n_blob in = {.data = random_data,.size = i }; int bytes_written; EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &in)); static const int overhead = 20 /* TLS header */ + 8 /* IV */ + 16; /* TAG */ if (i < max_fragment - overhead) { EXPECT_EQUAL(bytes_written, i); } else { EXPECT_EQUAL(bytes_written, max_fragment - overhead); } uint16_t predicted_length = bytes_written + 20; predicted_length += conn->active.cipher_suite->cipher->io.aead.record_iv_size; predicted_length += conn->active.cipher_suite->cipher->io.aead.tag_size; EXPECT_EQUAL(conn->out.blob.data[0], TLS_APPLICATION_DATA); EXPECT_EQUAL(conn->out.blob.data[1], 3); EXPECT_EQUAL(conn->out.blob.data[2], 3); EXPECT_EQUAL(conn->out.blob.data[3], (predicted_length >> 8) & 0xff); EXPECT_EQUAL(conn->out.blob.data[4], predicted_length & 0xff); /* The data should be encrypted */ if (bytes_written > 10) { EXPECT_NOT_EQUAL(memcmp(conn->out.blob.data + 5, random_data, bytes_written), 0); } /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); /* Let's decrypt it */ uint8_t content_type; uint16_t fragment_length; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_SUCCESS(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_EQUAL(fragment_length, predicted_length); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); /* Now lets corrupt some data and ensure the tests pass */ /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); /* Tamper the protocol version in the header, and ensure decryption fails, as we use this in the AAD */ conn->in.blob.data[2] = 2; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); /* Tamper with the IV and ensure decryption fails */ for (int j = 0; j < S2N_TLS_GCM_IV_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[5 + j] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } /* Tamper with the TAG and ensure decryption fails */ for (int j = 0; j < S2N_TLS_GCM_TAG_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[conn->in.blob.size - j - 1] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } /* Tamper w ith the cipher text and ensure decryption fails */ for (int j = S2N_TLS_GCM_IV_LEN; j < conn->in.blob.size - S2N_TLS_GCM_TAG_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[5 + j] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } } EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.server_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.client_key)); EXPECT_SUCCESS(s2n_connection_free(conn)); /* test the AES256 cipher with a SHA1 hash */ EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); conn->active.cipher_suite->cipher = &s2n_aes256_gcm; conn->active.cipher_suite->hmac_alg = S2N_HMAC_SHA1; EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_encryption_key(&conn->active.server_key, &aes256)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_decryption_key(&conn->active.client_key, &aes256)); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.client_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); conn->actual_protocol_version = S2N_TLS12; for (int i = 0; i <= max_fragment + 1; i++) { struct s2n_blob in = {.data = random_data,.size = i }; int bytes_written; EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &in)); static const int overhead = 20 /* TLS header */ + 8 /* IV */ + 16; /* TAG */ if (i < max_fragment - overhead) { EXPECT_EQUAL(bytes_written, i); } else { EXPECT_EQUAL(bytes_written, max_fragment - overhead); } uint16_t predicted_length = bytes_written + 20; predicted_length += conn->active.cipher_suite->cipher->io.aead.record_iv_size; predicted_length += conn->active.cipher_suite->cipher->io.aead.tag_size; EXPECT_EQUAL(conn->out.blob.data[0], TLS_APPLICATION_DATA); EXPECT_EQUAL(conn->out.blob.data[1], 3); EXPECT_EQUAL(conn->out.blob.data[2], 3); EXPECT_EQUAL(conn->out.blob.data[3], (predicted_length >> 8) & 0xff); EXPECT_EQUAL(conn->out.blob.data[4], predicted_length & 0xff); /* The data should be encrypted */ if (bytes_written > 10) { EXPECT_NOT_EQUAL(memcmp(conn->out.blob.data + 5, random_data, bytes_written), 0); } /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); /* Let's decrypt it */ uint8_t content_type; uint16_t fragment_length; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_SUCCESS(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_EQUAL(fragment_length, predicted_length); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); /* Now lets corrupt some data and ensure the tests pass */ /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); /* Tamper the protocol version in the header, and ensure decryption fails, as we use this in the AAD */ conn->in.blob.data[2] = 2; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); /* Tamper with the IV and ensure decryption fails */ for (int j = 0; j < S2N_TLS_GCM_IV_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[5 + j] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } /* Tamper with the TAG and ensure decryption fails */ for (int j = 0; j < S2N_TLS_GCM_TAG_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[conn->in.blob.size - j - 1] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } /* Tamper w ith the cipher text and ensure decryption fails */ for (int j = S2N_TLS_GCM_IV_LEN; j < conn->in.blob.size - S2N_TLS_GCM_TAG_LEN; j++) { /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_reread(&conn->out)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))); conn->in.blob.data[5 + j] ++; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_FAILURE(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } } EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.server_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.client_key)); EXPECT_SUCCESS(s2n_connection_free(conn)); 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; }
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; }