int s2n_dup(struct s2n_blob *from, struct s2n_blob *to) { eq_check(to->size, 0); eq_check(to->data, NULL); GUARD(s2n_alloc(to, from->size)); memcpy_check(to->data, from->data, to->size); 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; }
static int s2n_drbg_block_encrypt(EVP_CIPHER_CTX * ctx, uint8_t in[S2N_DRBG_BLOCK_SIZE], uint8_t out[S2N_DRBG_BLOCK_SIZE]) { int len = S2N_DRBG_BLOCK_SIZE; GUARD_OSSL(EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE), S2N_ERR_DRBG); eq_check(len, S2N_DRBG_BLOCK_SIZE); return 0; }
static int s2n_composite_cipher_aes_sha256_set_mac_write_key(struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size) { eq_check(mac_size, SHA256_DIGEST_LENGTH); EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY, mac_size, mac_key); return 0; }
static int s2n_composite_cipher_aes256_sha256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) { eq_check(in->size, 32); EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha256(), NULL, in->data, NULL); return 0; }
static int s2n_cbc_cipher_3des_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) { eq_check(in->size, 192 / 8); EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); return 0; }
int s2n_cbc_cipher_3des_get_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) { eq_check(in->size, 192 / 8); EVP_CIPHER_CTX_init(&key->native_format.evp_cipher_ctx); EVP_CIPHER_CTX_set_padding(&key->native_format.evp_cipher_ctx, EVP_CIPH_NO_PADDING); EVP_EncryptInit_ex(&key->native_format.evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL); return 0; }
int s2n_kem_decapsulate(const struct s2n_kem_keypair *kem_keys, struct s2n_blob *shared_secret, const struct s2n_blob *ciphertext) { notnull_check(kem_keys); const struct s2n_kem *kem = kem_keys->negotiated_kem; notnull_check(kem->decapsulate); eq_check(kem_keys->private_key.size, kem->private_key_length); notnull_check(kem_keys->private_key.data); eq_check(ciphertext->size, kem->ciphertext_length); notnull_check(ciphertext->data); GUARD(s2n_alloc(shared_secret, kem_keys->negotiated_kem->shared_secret_key_length)); GUARD(kem->decapsulate(shared_secret->data, ciphertext->data, kem_keys->private_key.data)); return 0; }
int s2n_cbc_cipher_aes128_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) { eq_check(in->size, 128 / 8); /* Always returns 1 */ EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); return 0; }
bool heap_equality(Heap1 const & lhs, Heap2 const & rhs) { const bool use_ordered_iterators = Heap1::has_ordered_iterators && Heap2::has_ordered_iterators; typedef typename boost::mpl::if_c<use_ordered_iterators, heap_equivalence_iteration, heap_equivalence_copy >::type equivalence_check; equivalence_check eq_check; return eq_check(lhs, rhs); }
static int s2n_composite_cipher_aes_sha_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) { eq_check(out->size, in->size); if (EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data) == 0) { S2N_ERROR(S2N_ERR_KEY_INIT); } if (EVP_Cipher(key->evp_cipher_ctx, out->data, in->data, in->size) == 0) { S2N_ERROR(S2N_ERR_DECRYPT); } return 0; }
int s2n_kem_generate_keypair(struct s2n_kem_keypair *kem_keys) { notnull_check(kem_keys); const struct s2n_kem *kem = kem_keys->negotiated_kem; notnull_check(kem->generate_keypair); eq_check(kem_keys->public_key.size, kem->public_key_length); notnull_check(kem_keys->public_key.data); /* The private key is needed for client_key_recv and must be saved */ GUARD(s2n_alloc(&kem_keys->private_key, kem->private_key_length)); GUARD(kem->generate_keypair(kem_keys->public_key.data, kem_keys->private_key.data)); return 0; }
int s2n_client_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out) { uint16_t total_size = 0; /* Signature algorithms */ if (conn->actual_protocol_version == S2N_TLS12) { total_size += (sizeof(s2n_preferred_hashes) * 2) + 6; } uint16_t application_protocols_len = conn->config->application_protocols.size; uint16_t server_name_len = strlen(conn->server_name); uint16_t mfl_code_len = sizeof(conn->config->mfl_code); if (server_name_len) { total_size += 9 + server_name_len; } if (application_protocols_len) { total_size += 6 + application_protocols_len; } if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) { total_size += 9; } if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) { total_size += 4; } if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) { total_size += 5; } /* Write ECC extensions: Supported Curves and Supported Point Formats */ int ec_curves_count = sizeof(s2n_ecc_supported_curves) / sizeof(s2n_ecc_supported_curves[0]); total_size += 12 + ec_curves_count * 2; GUARD(s2n_stuffer_write_uint16(out, total_size)); if (conn->actual_protocol_version == S2N_TLS12) { GUARD(s2n_send_client_signature_algorithms_extension(conn, out)); } if (server_name_len) { /* Write the server name */ GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SERVER_NAME)); GUARD(s2n_stuffer_write_uint16(out, server_name_len + 5)); /* Size of all of the server names */ GUARD(s2n_stuffer_write_uint16(out, server_name_len + 3)); /* Name type - host name, RFC3546 */ GUARD(s2n_stuffer_write_uint8(out, 0)); struct s2n_blob server_name; server_name.data = (uint8_t *) conn->server_name; server_name.size = server_name_len; GUARD(s2n_stuffer_write_uint16(out, server_name_len)); GUARD(s2n_stuffer_write(out, &server_name)); } /* Write ALPN extension */ if (application_protocols_len) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ALPN)); GUARD(s2n_stuffer_write_uint16(out, application_protocols_len + 2)); GUARD(s2n_stuffer_write_uint16(out, application_protocols_len)); GUARD(s2n_stuffer_write(out, &conn->config->application_protocols)); } if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) { /* We only support OCSP */ eq_check(conn->config->status_request_type, S2N_STATUS_REQUEST_OCSP); GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_STATUS_REQUEST)); GUARD(s2n_stuffer_write_uint16(out, 5)); GUARD(s2n_stuffer_write_uint8(out, (uint8_t) conn->config->status_request_type)); GUARD(s2n_stuffer_write_uint16(out, 0)); GUARD(s2n_stuffer_write_uint16(out, 0)); } /* Write Certificate Transparency extension */ if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SCT_LIST)); GUARD(s2n_stuffer_write_uint16(out, 0)); } /* Write Maximum Fragmentation Length extension */ if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_MAX_FRAG_LEN)); GUARD(s2n_stuffer_write_uint16(out, mfl_code_len)); GUARD(s2n_stuffer_write_uint8(out, conn->config->mfl_code)); } /* * RFC 4492: Clients SHOULD send both the Supported Elliptic Curves Extension * and the Supported Point Formats Extension. */ { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ELLIPTIC_CURVES)); GUARD(s2n_stuffer_write_uint16(out, 2 + ec_curves_count * 2)); /* Curve list len */ GUARD(s2n_stuffer_write_uint16(out, ec_curves_count * 2)); /* Curve list */ for (int i = 0; i < ec_curves_count; i++) { GUARD(s2n_stuffer_write_uint16(out, s2n_ecc_supported_curves[i].iana_id)); } GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_EC_POINT_FORMATS)); GUARD(s2n_stuffer_write_uint16(out, 2)); /* Point format list len */ GUARD(s2n_stuffer_write_uint8(out, 1)); /* Only allow uncompressed format */ GUARD(s2n_stuffer_write_uint8(out, 0)); } return 0; }
static int s2n_stream_cipher_rc4_get_key(struct s2n_session_key *key, struct s2n_blob *in) { eq_check(in->size, 16); RC4_set_key(&key->native_format.rc4, in->size, in->data); return 0; }
static int s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out) { struct s2n_blob value = {.data = drbg->v,.size = sizeof(drbg->v) }; int block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE); /* Per NIST SP800-90A 10.2.1.2: */ for (int i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) { GUARD(s2n_increment_sequence_number(&value)); GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, out->data + i)); drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; } if (out->size <= block_aligned_size) { return 0; } uint8_t spare_block[S2N_DRBG_BLOCK_SIZE]; GUARD(s2n_increment_sequence_number(&value)); GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, spare_block)); drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; memcpy_check(out->data + block_aligned_size, spare_block, out->size - block_aligned_size); return 0; } static int s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data) { uint8_t temp[32]; struct s2n_blob temp_blob = {.data = temp,.size = sizeof(temp) }; eq_check(provided_data->size, sizeof(temp)); GUARD(s2n_drbg_bits(drbg, &temp_blob)); /* XOR in the provided data */ for (int i = 0; i < provided_data->size; i++) { temp[i] ^= provided_data->data[i]; } /* Update the key and value */ GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, temp, NULL), S2N_ERR_DRBG); memcpy_check(drbg->v, temp + S2N_DRBG_BLOCK_SIZE, S2N_DRBG_BLOCK_SIZE); return 0; } int s2n_drbg_seed(struct s2n_drbg *drbg, struct s2n_blob *ps) { uint8_t seed[32]; struct s2n_blob blob = {.data = seed,.size = sizeof(seed) }; lte_check(ps->size, sizeof(seed)); if (drbg->entropy_generator) { GUARD(drbg->entropy_generator(&blob)); } else { GUARD(s2n_get_urandom_data(&blob)); } for (int i = 0; i < ps->size; i++) { blob.data[i] ^= ps->data[i]; } GUARD(s2n_drbg_update(drbg, &blob)); drbg->bytes_used = 0; drbg->generation += 1; return 0; } int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string) { struct s2n_blob value = {.data = drbg->v,.size = sizeof(drbg->v) }; uint8_t ps_prefix[32]; struct s2n_blob ps = {.data = ps_prefix,.size = sizeof(ps_prefix) }; /* Start off with zeroed data, per 10.2.1.3.1 item 4 */ GUARD(s2n_blob_zero(&value)); drbg->ctx = EVP_CIPHER_CTX_new(); S2N_ERROR_IF(!drbg->ctx, S2N_ERR_DRBG); (void)EVP_CIPHER_CTX_init(drbg->ctx); /* Start off with zeroed key, per 10.2.1.3.1 item 5 */ GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, drbg->v, NULL), S2N_ERR_DRBG); /* Copy the personalization string */ GUARD(s2n_blob_zero(&ps)); memcpy_check(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size)); /* Seed / update the DRBG */ GUARD(s2n_drbg_seed(drbg, &ps)); /* After initial seeding, pivot to RDRAND if available and not overridden */ if (drbg->entropy_generator == NULL && s2n_cpu_supports_rdrand()) { drbg->entropy_generator = s2n_get_rdrand_data; } return 0; } int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob) { uint8_t all_zeros[32] = { 0 }; struct s2n_blob zeros = {.data = all_zeros,.size = sizeof(all_zeros) }; S2N_ERROR_IF(blob->size > S2N_DRBG_GENERATE_LIMIT, S2N_ERR_DRBG_REQUEST_SIZE); /* If either the entropy generator is set, for prediction resistance, * or if we reach the definitely-need-to-reseed limit, then reseed. */ if (drbg->entropy_generator || drbg->bytes_used + blob->size + S2N_DRBG_BLOCK_SIZE >= S2N_DRBG_RESEED_LIMIT) { GUARD(s2n_drbg_seed(drbg, &zeros)); } GUARD(s2n_drbg_bits(drbg, blob)); GUARD(s2n_drbg_update(drbg, &zeros)); return 0; } int s2n_drbg_wipe(struct s2n_drbg *drbg) { struct s2n_blob state = {.data = (void *)drbg,.size = sizeof(struct s2n_drbg) }; if (drbg->ctx) { GUARD_OSSL(EVP_CIPHER_CTX_cleanup(drbg->ctx), S2N_ERR_DRBG); EVP_CIPHER_CTX_free(drbg->ctx); drbg->ctx = NULL; } GUARD(s2n_blob_zero(&state)); return 0; } int s2n_drbg_bytes_used(struct s2n_drbg *drbg) { return drbg->bytes_used; }
int s2n_entropy_generator(struct s2n_blob *blob) { eq_check(blob->size, kat_entropy_blob.size); blob->data = kat_entropy_blob.data; return 0; }
static int s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out) { struct s2n_blob value = {.data = drbg->v, .size = sizeof(drbg->v) }; int block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE); /* Per NIST SP800-90A 10.2.1.2: */ for (int i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) { GUARD(s2n_increment_sequence_number(&value)); GUARD(s2n_drbg_block_encrypt(&drbg->ctx, drbg->v, out->data + i)); drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; } if (out->size <= block_aligned_size) { return 0; } uint8_t spare_block[S2N_DRBG_BLOCK_SIZE]; GUARD(s2n_increment_sequence_number(&value)); GUARD(s2n_drbg_block_encrypt(&drbg->ctx, drbg->v, spare_block)); drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; memcpy_check(out->data + block_aligned_size, spare_block, out->size - block_aligned_size); return 0; } static int s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data) { uint8_t temp[32]; struct s2n_blob temp_blob = {.data = temp, .size = sizeof(temp) }; eq_check(provided_data->size, sizeof(temp)); GUARD(s2n_drbg_bits(drbg, &temp_blob)); /* XOR in the provided data */ for (int i = 0; i < provided_data->size; i++) { temp[i] ^= provided_data->data[i]; } /* Update the key and value */ if (EVP_EncryptInit_ex(&drbg->ctx, EVP_aes_128_ecb(), NULL, temp, NULL) != 1) { S2N_ERROR(S2N_ERR_DRBG); } memcpy_check(drbg->v, temp + S2N_DRBG_BLOCK_SIZE, S2N_DRBG_BLOCK_SIZE); return 0; } int s2n_drbg_seed(struct s2n_drbg *drbg) { uint8_t seed[32]; struct s2n_blob blob = {.data = seed, .size = sizeof(seed) }; if (drbg->entropy_generator) { GUARD(drbg->entropy_generator(&blob)); } else { GUARD(s2n_get_urandom_data(&blob)); } for (int i = 0; i < sizeof(drbg->ps); i++) { blob.data[i] ^= drbg->ps[i]; } GUARD(s2n_drbg_update(drbg, &blob)); drbg->bytes_used = 0; drbg->generation += 1; return 0; } int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string) { struct s2n_blob value = {.data = drbg->v, .size = sizeof(drbg->v) }; struct s2n_blob ps = {.data = drbg->ps, .size = sizeof(drbg->ps) }; /* Start off with zerod data, per 10.2.1.3.1 item 4 */ GUARD(s2n_blob_zero(&value)); /* Start off with zerod key, per 10.2.1.3.1 item 5 */ (void) EVP_CIPHER_CTX_init(&drbg->ctx); if (EVP_EncryptInit_ex(&drbg->ctx, EVP_aes_128_ecb(), NULL, drbg->v, NULL) != 1) { S2N_ERROR(S2N_ERR_DRBG); } /* Copy the personalization string */ GUARD(s2n_blob_zero(&ps)); memcpy_check(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size)); /* Seed / update the DRBG */ GUARD(s2n_drbg_seed(drbg)); return 0; } int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob) { uint8_t all_zeros[32] = { 0 }; struct s2n_blob zeros = {.data = all_zeros, .size = sizeof(all_zeros) }; if (blob->size > S2N_DRBG_GENERATE_LIMIT) { S2N_ERROR(S2N_ERR_DRBG_REQUEST_SIZE); } if (drbg->bytes_used + blob->size + S2N_DRBG_BLOCK_SIZE >= S2N_DRBG_RESEED_LIMIT) { GUARD(s2n_drbg_seed(drbg)); } GUARD(s2n_drbg_bits(drbg, blob)); GUARD(s2n_drbg_update(drbg, &zeros)); return 0; } int s2n_drbg_wipe(struct s2n_drbg *drbg) { struct s2n_blob state = {.data = (void *) drbg, .size = sizeof(struct s2n_drbg) }; if (EVP_CIPHER_CTX_cleanup(&drbg->ctx) != 1) { S2N_ERROR(S2N_ERR_DRBG); } GUARD(s2n_blob_zero(&state)); return 0; } int s2n_drbg_bytes_used(struct s2n_drbg *drbg) { return drbg->bytes_used; }