int main(int argc, char **argv) { struct s2n_connection *conn; uint8_t mac_key[] = "sample mac key"; uint8_t aes128_key[] = "123456789012345"; struct s2n_blob aes128 = {.data = aes128_key,.size = sizeof(aes128_key) }; uint8_t random_data[S2N_LARGE_RECORD_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->secure; conn->client = &conn->secure; /* test the AES128 cipher with a SHA1 hash */ conn->secure.cipher_suite->cipher = &s2n_aes128; conn->secure.cipher_suite->hmac_alg = S2N_HMAC_SHA1; EXPECT_SUCCESS(conn->secure.cipher_suite->cipher->get_encryption_key(&conn->secure.server_key, &aes128)); EXPECT_SUCCESS(conn->secure.cipher_suite->cipher->get_decryption_key(&conn->secure.client_key, &aes128)); EXPECT_SUCCESS(s2n_hmac_init(&conn->secure.client_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); EXPECT_SUCCESS(s2n_hmac_init(&conn->secure.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); conn->actual_protocol_version = S2N_TLS11; /* Align the record size, then subtract 20 bytes for the HMAC, 16 bytes for the explicit IV, and one byte * for the padding length byte. */ int small_aligned_payload = S2N_SMALL_FRAGMENT_LENGTH - (S2N_SMALL_FRAGMENT_LENGTH % 16) - 20 - 16 - 1; int large_aligned_payload = S2N_LARGE_FRAGMENT_LENGTH - (S2N_LARGE_FRAGMENT_LENGTH % 16) - 20 - 16 - 1; int bytes_written; /* Check the default: small record */ EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &r)); EXPECT_EQUAL(bytes_written, small_aligned_payload); /* Check explicitly small records */ EXPECT_SUCCESS(s2n_connection_prefer_low_latency(conn)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &r)); EXPECT_EQUAL(bytes_written, small_aligned_payload); /* Check explicitly large records */ EXPECT_SUCCESS(s2n_connection_prefer_throughput(conn)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &r)); EXPECT_EQUAL(bytes_written, large_aligned_payload); /* Clean up */ EXPECT_SUCCESS(conn->secure.cipher_suite->cipher->destroy_key(&conn->secure.server_key)); EXPECT_SUCCESS(conn->secure.cipher_suite->cipher->destroy_key(&conn->secure.client_key)); EXPECT_SUCCESS(s2n_connection_free(conn)); EXPECT_SUCCESS(s2n_hmac_init(&conn->secure.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); END_TEST(); }
int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status * more) { notnull_check(conn); notnull_check(more); /* Treat this call as a no-op if already wiped */ if (conn->send == NULL && conn->recv == NULL) { return 0; } uint64_t elapsed; GUARD(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); S2N_ERROR_IF(elapsed < conn->delay, S2N_ERR_SHUTDOWN_PAUSED); /* Queue our close notify, once. Use warning level so clients don't give up */ GUARD(s2n_queue_writer_close_alert_warning(conn)); /* Write it */ GUARD(s2n_flush(conn, more)); /* Assume caller isn't interested in pending incoming data */ if (conn->in_status == PLAINTEXT) { GUARD(s2n_stuffer_wipe(&conn->header_in)); GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } /* Fails with S2N_ERR_SHUTDOWN_RECORD_TYPE or S2N_ERR_ALERT on receipt of anything but a close_notify */ GUARD(s2n_recv_close_notify(conn, more)); return 0; }
int main(int argc, char **argv) { uint8_t u8; uint16_t u16; uint32_t u32; uint32_t stuffer_size = nondet_uint32(); __CPROVER_assume(stuffer_size > 0); uint32_t entropy_size = nondet_uint32(); __CPROVER_assume(entropy_size > 0); uint8_t entropy[entropy_size]; struct s2n_stuffer stuffer; GUARD(s2n_stuffer_alloc(&stuffer, stuffer_size)); struct s2n_blob in = {.data = entropy,.size = entropy_size}; GUARD(s2n_stuffer_write(&stuffer, &in)); GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint8(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint8(&stuffer, &u8)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint16(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint16(&stuffer, &u16)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint24(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint24(&stuffer, &u32)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint32(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint32(&stuffer, &u32)); } GUARD(s2n_stuffer_free(&stuffer)); }
int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) { int rc; rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_RSA_PRIVATE_KEY); if (!rc) { return rc; } s2n_stuffer_reread(pem); s2n_stuffer_reread(asn1); /* By default, OpenSSL tools always generate both "EC PARAMETERS" and "EC PRIVATE * KEY" PEM objects in the keyfile. Skip the first "EC PARAMETERS" object so that we're * compatible with OpenSSL's default output, and since "EC PARAMETERS" is * only needed for non-standard curves that aren't currently supported. */ rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_EC_PARAMETERS); if (rc < 0) { s2n_stuffer_reread(pem); } s2n_stuffer_wipe(asn1); rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_EC_PRIVATE_KEY); if (!rc) { return rc; } /* If it does not match either format, try PKCS#8 */ s2n_stuffer_reread(pem); s2n_stuffer_reread(asn1); return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS8_PRIVATE_KEY); }
int s2n_client_ccs_recv(struct s2n_connection *conn) { uint8_t type; GUARD(s2n_prf_client_finished(conn)); struct s2n_blob seq = {.data = conn->secure.client_sequence_number,.size = sizeof(conn->secure.client_sequence_number) }; GUARD(s2n_blob_zero(&seq)); /* Update the client to use the cipher-suite */ conn->client = &conn->secure; GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); S2N_ERROR_IF(type != CHANGE_CIPHER_SPEC_TYPE, S2N_ERR_BAD_MESSAGE); /* Flush any partial alert messages that were pending */ GUARD(s2n_stuffer_wipe(&conn->alert_in)); return 0; } int s2n_client_ccs_send(struct s2n_connection *conn) { GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, CHANGE_CIPHER_SPEC_TYPE)); return 0; }
int s2n_stuffer_free(struct s2n_stuffer *stuffer) { if (stuffer->alloced == 0) { return 0; } if (stuffer->wiped == 0) { GUARD(s2n_stuffer_wipe(stuffer)); } GUARD(s2n_free(&stuffer->blob)); stuffer->blob.data = NULL; stuffer->blob.size = 0; 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_connection_wipe(struct s2n_connection *conn) { /* First make a copy of everything we'd like to save, which isn't very * much. */ int mode = conn->mode; struct s2n_config *config = conn->config; struct s2n_stuffer alert_in; struct s2n_stuffer reader_alert_out; struct s2n_stuffer writer_alert_out; struct s2n_stuffer handshake_io; struct s2n_stuffer header_in; struct s2n_stuffer in; struct s2n_stuffer out; /* Wipe all of the sensitive stuff */ GUARD(s2n_connection_free_keys(conn)); GUARD(s2n_stuffer_wipe(&conn->alert_in)); GUARD(s2n_stuffer_wipe(&conn->reader_alert_out)); GUARD(s2n_stuffer_wipe(&conn->writer_alert_out)); GUARD(s2n_stuffer_wipe(&conn->handshake.io)); GUARD(s2n_stuffer_wipe(&conn->header_in)); GUARD(s2n_stuffer_wipe(&conn->in)); GUARD(s2n_stuffer_wipe(&conn->out)); /* Allocate or resize to their original sizes */ GUARD(s2n_stuffer_resize(&conn->in, S2N_DEFAULT_FRAGMENT_LENGTH)); /* Allocate memory for handling handshakes */ GUARD(s2n_stuffer_resize(&conn->handshake.io, S2N_DEFAULT_RECORD_LENGTH)); /* Clone the stuffers */ /* ignore gcc 4.7 address warnings because dest is allocated on the stack */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Waddress" memcpy_check(&alert_in, &conn->alert_in, sizeof(struct s2n_stuffer)); memcpy_check(&reader_alert_out, &conn->reader_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&writer_alert_out, &conn->writer_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&handshake_io, &conn->handshake.io, sizeof(struct s2n_stuffer)); memcpy_check(&header_in, &conn->header_in, sizeof(struct s2n_stuffer)); memcpy_check(&in, &conn->in, sizeof(struct s2n_stuffer)); memcpy_check(&out, &conn->out, sizeof(struct s2n_stuffer)); #pragma GCC diagnostic pop /* Zero the whole connection structure */ memset_check(conn, 0, sizeof(struct s2n_connection)); conn->mode = mode; conn->config = config; conn->active.cipher_suite = &s2n_null_cipher_suite; conn->pending.cipher_suite = &s2n_null_cipher_suite; conn->server = &conn->active; conn->client = &conn->active; conn->max_fragment_length = S2N_DEFAULT_FRAGMENT_LENGTH; conn->handshake.state = CLIENT_HELLO; GUARD(s2n_hash_init(&conn->handshake.client_md5, S2N_HASH_MD5)); GUARD(s2n_hash_init(&conn->handshake.client_sha1, S2N_HASH_SHA1)); GUARD(s2n_hash_init(&conn->handshake.client_sha256, S2N_HASH_SHA256)); GUARD(s2n_hash_init(&conn->handshake.server_md5, S2N_HASH_MD5)); GUARD(s2n_hash_init(&conn->handshake.server_sha1, S2N_HASH_SHA1)); GUARD(s2n_hash_init(&conn->handshake.server_sha256, S2N_HASH_SHA256)); memcpy_check(&conn->alert_in, &alert_in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->reader_alert_out, &reader_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&conn->writer_alert_out, &writer_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&conn->handshake.io, &handshake_io, sizeof(struct s2n_stuffer)); memcpy_check(&conn->header_in, &header_in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->in, &in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->out, &out, sizeof(struct s2n_stuffer)); /* Set everything to the highest version at first */ conn->server_protocol_version = s2n_highest_protocol_version; conn->client_protocol_version = s2n_highest_protocol_version; conn->actual_protocol_version = s2n_highest_protocol_version; return 0; }
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(); }
int s2n_connection_wipe(struct s2n_connection *conn) { /* First make a copy of everything we'd like to save, which isn't very * much. */ int mode = conn->mode; struct s2n_config *config = conn->config; struct s2n_stuffer alert_in; struct s2n_stuffer reader_alert_out; struct s2n_stuffer writer_alert_out; struct s2n_stuffer handshake_io; struct s2n_stuffer header_in; struct s2n_stuffer in; struct s2n_stuffer out; /* Session keys will be wiped. Preserve structs to avoid reallocation */ struct s2n_session_key initial_client_key; struct s2n_session_key initial_server_key; struct s2n_session_key secure_client_key; struct s2n_session_key secure_server_key; /* Wipe all of the sensitive stuff */ GUARD(s2n_connection_wipe_keys(conn)); GUARD(s2n_stuffer_wipe(&conn->alert_in)); GUARD(s2n_stuffer_wipe(&conn->reader_alert_out)); GUARD(s2n_stuffer_wipe(&conn->writer_alert_out)); GUARD(s2n_stuffer_wipe(&conn->handshake.io)); GUARD(s2n_stuffer_wipe(&conn->header_in)); GUARD(s2n_stuffer_wipe(&conn->in)); GUARD(s2n_stuffer_wipe(&conn->out)); /* Restore the socket option values */ GUARD(s2n_socket_read_restore(conn)); GUARD(s2n_socket_write_restore(conn)); GUARD(s2n_free(&conn->status_response)); /* Allocate or resize to their original sizes */ GUARD(s2n_stuffer_resize(&conn->in, S2N_LARGE_FRAGMENT_LENGTH)); /* Allocate memory for handling handshakes */ GUARD(s2n_stuffer_resize(&conn->handshake.io, S2N_LARGE_RECORD_LENGTH)); /* Clone the stuffers */ /* ignore gcc 4.7 address warnings because dest is allocated on the stack */ /* pragma gcc diagnostic was added in gcc 4.6 */ #if defined(__GNUC__) && GCC_VERSION >= 40600 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Waddress" #endif memcpy_check(&alert_in, &conn->alert_in, sizeof(struct s2n_stuffer)); memcpy_check(&reader_alert_out, &conn->reader_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&writer_alert_out, &conn->writer_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&handshake_io, &conn->handshake.io, sizeof(struct s2n_stuffer)); memcpy_check(&header_in, &conn->header_in, sizeof(struct s2n_stuffer)); memcpy_check(&in, &conn->in, sizeof(struct s2n_stuffer)); memcpy_check(&out, &conn->out, sizeof(struct s2n_stuffer)); memcpy_check(&initial_client_key, &conn->initial.client_key, sizeof(struct s2n_session_key)); memcpy_check(&initial_server_key, &conn->initial.server_key, sizeof(struct s2n_session_key)); memcpy_check(&secure_client_key, &conn->secure.client_key, sizeof(struct s2n_session_key)); memcpy_check(&secure_server_key, &conn->secure.server_key, sizeof(struct s2n_session_key)); #if defined(__GNUC__) && GCC_VERSION >= 40600 #pragma GCC diagnostic pop #endif /* Zero the whole connection structure */ memset_check(conn, 0, sizeof(struct s2n_connection)); conn->readfd = -1; conn->writefd = -1; conn->mode = mode; conn->config = config; conn->close_notify_queued = 0; conn->current_user_data_consumed = 0; conn->initial.cipher_suite = &s2n_null_cipher_suite; conn->secure.cipher_suite = &s2n_null_cipher_suite; conn->server = &conn->initial; conn->client = &conn->initial; conn->max_fragment_length = S2N_SMALL_FRAGMENT_LENGTH; conn->handshake.handshake_type = INITIAL; conn->handshake.message_number = 0; GUARD(s2n_hash_init(&conn->handshake.md5, S2N_HASH_MD5)); GUARD(s2n_hash_init(&conn->handshake.sha1, S2N_HASH_SHA1)); GUARD(s2n_hash_init(&conn->handshake.sha256, S2N_HASH_SHA256)); GUARD(s2n_hash_init(&conn->handshake.sha384, S2N_HASH_SHA384)); GUARD(s2n_hmac_init(&conn->client->client_record_mac, S2N_HMAC_NONE, NULL, 0)); GUARD(s2n_hmac_init(&conn->server->server_record_mac, S2N_HMAC_NONE, NULL, 0)); memcpy_check(&conn->alert_in, &alert_in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->reader_alert_out, &reader_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&conn->writer_alert_out, &writer_alert_out, sizeof(struct s2n_stuffer)); memcpy_check(&conn->handshake.io, &handshake_io, sizeof(struct s2n_stuffer)); memcpy_check(&conn->header_in, &header_in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->in, &in, sizeof(struct s2n_stuffer)); memcpy_check(&conn->out, &out, sizeof(struct s2n_stuffer)); memcpy_check(&conn->initial.client_key, &initial_client_key, sizeof(struct s2n_session_key)); memcpy_check(&conn->initial.server_key, &initial_server_key, sizeof(struct s2n_session_key)); memcpy_check(&conn->secure.client_key, &secure_client_key, sizeof(struct s2n_session_key)); memcpy_check(&conn->secure.server_key, &secure_server_key, sizeof(struct s2n_session_key)); if (conn->mode == S2N_SERVER) { conn->server_protocol_version = s2n_highest_protocol_version; conn->client_protocol_version = s2n_unknown_protocol_version; } else { conn->server_protocol_version = s2n_unknown_protocol_version; conn->client_protocol_version = s2n_highest_protocol_version; } conn->actual_protocol_version = s2n_unknown_protocol_version; return 0; }