int s2n_asn1der_to_rsa_public_key(struct s2n_rsa_public_key *key, struct s2n_blob *asn1der) { uint8_t *original_ptr = asn1der->data; X509 *cert = d2i_X509(NULL, (const unsigned char **)(void *)&asn1der->data, asn1der->size); if (cert == NULL) { S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); } if (asn1der->data - original_ptr != asn1der->size) { X509_free(cert); S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); } asn1der->data = original_ptr; EVP_PKEY *public_key = X509_get_pubkey(cert); X509_free(cert); if (public_key == NULL) { S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); } if (public_key->type != EVP_PKEY_RSA) { EVP_PKEY_free(public_key); S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); } key->rsa = EVP_PKEY_get1_RSA(public_key); if (key->rsa == NULL) { EVP_PKEY_free(public_key); S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); } EVP_PKEY_free(public_key); return 0; }
static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g, struct s2n_blob *Ys) { BIGNUM *bn_p = BN_bin2bn((const unsigned char *)p->data, p->size, NULL); BIGNUM *bn_g = BN_bin2bn((const unsigned char *)g->data, g->size, NULL); BIGNUM *bn_Ys = BN_bin2bn((const unsigned char *)Ys->data, Ys->size, NULL); #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER dh_params->dh->p = bn_p; dh_params->dh->g = bn_g; dh_params->dh->pub_key = bn_Ys; #else if (DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g) == 0) { /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html: * values that have been passed in should not be freed directly after this function has been called */ S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } if (DH_set0_key(dh_params->dh, bn_Ys, NULL) == 0) { /* Same as DH_set0_pqg */ S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } #endif return 0; }
static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params) { notnull_check(dh_params); notnull_check(dh_params->dh); const BIGNUM *p = s2n_get_p_dh_param(dh_params); const BIGNUM *g = s2n_get_g_dh_param(dh_params); notnull_check(g); notnull_check(p); if (DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES) { S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } if (BN_is_zero(g)) { S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } if (BN_is_zero(p)) { S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } 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_rsa_sign(struct s2n_rsa_private_key *key, struct s2n_hash_state *digest, struct s2n_blob *signature) { uint8_t digest_out[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; int type, digest_length; if (digest->alg == S2N_HASH_MD5_SHA1) { type = NID_md5_sha1; digest_length = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; } else if (digest->alg == S2N_HASH_SHA1) { type = NID_sha1; digest_length = SHA_DIGEST_LENGTH; } else { S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); } GUARD(s2n_hash_digest(digest, digest_out, digest_length)); unsigned int signature_size = signature->size; if (RSA_sign(type, digest_out, digest_length, signature->data, &signature_size, key->rsa) == 0) { S2N_ERROR(S2N_ERR_SIGN); } if (signature_size > signature->size) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } signature->size = signature_size; return 0; }
int s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) { if (map->immutable) { S2N_ERROR(S2N_ERR_MAP_IMMUTABLE); } if (map->capacity < (map->size * 2)) { /* Embiggen the map */ GUARD(s2n_map_embiggen(map, map->capacity * 2)); } uint32_t slot = s2n_map_slot(map, key); /* Linear probing until we find an empty slot */ while(map->table[slot].key.size) { if (key->size != map->table[slot].key.size || memcmp(key->data, map->table[slot].key.data, key->size)) { slot++; slot %= map->capacity; continue; } /* We found a duplicate key */ S2N_ERROR(S2N_ERR_MAP_DUPLICATE); } GUARD(s2n_dup(key, &map->table[slot].key)); GUARD(s2n_dup(value, &map->table[slot].value)); map->size++; return 0; }
/* See http://www-archive.mozilla.org/projects/security/pki/nss/ssl/draft02.html 2.5 */ int s2n_sslv2_client_hello_recv(struct s2n_connection *conn) { struct s2n_stuffer *in = &conn->handshake.io; uint16_t session_id_length; uint16_t cipher_suites_length; uint16_t challenge_length; uint8_t *cipher_suites; if (conn->client_protocol_version < conn->config->cipher_preferences->minimum_protocol_version || conn->client_protocol_version > conn->server_protocol_version) { GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); S2N_ERROR(S2N_ERR_BAD_MESSAGE); } conn->actual_protocol_version = MIN(conn->client_protocol_version, conn->server_protocol_version); conn->client_hello_version = S2N_SSLv2; /* We start 5 bytes into the record */ GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); if (cipher_suites_length % S2N_SSLv2_CIPHER_SUITE_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } GUARD(s2n_stuffer_read_uint16(in, &session_id_length)); GUARD(s2n_stuffer_read_uint16(in, &challenge_length)); if (challenge_length > S2N_TLS_RANDOM_DATA_LEN) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } cipher_suites = s2n_stuffer_raw_read(in, cipher_suites_length); notnull_check(cipher_suites); GUARD(s2n_set_cipher_as_sslv2_server(conn, cipher_suites, cipher_suites_length / S2N_SSLv2_CIPHER_SUITE_LEN)); if (session_id_length > s2n_stuffer_data_available(in)) { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } if (session_id_length > 0 && session_id_length <= S2N_TLS_SESSION_ID_MAX_LEN) { GUARD(s2n_stuffer_read_bytes(in, conn->session_id, session_id_length)); conn->session_id_len = (uint8_t) session_id_length; } else { GUARD(s2n_stuffer_skip_read(in, session_id_length)); } struct s2n_blob b; b.data = conn->secure.client_random; b.size = S2N_TLS_RANDOM_DATA_LEN; b.data += S2N_TLS_RANDOM_DATA_LEN - challenge_length; b.size -= S2N_TLS_RANDOM_DATA_LEN - challenge_length; GUARD(s2n_stuffer_read(in, &b)); conn->server->chosen_cert_chain = conn->config->cert_and_key_pairs; GUARD(s2n_conn_set_handshake_type(conn)); return 0; }
static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, uint32_t count, uint32_t cipher_suite_len) { uint8_t fallback_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_FALLBACK_SCSV }; struct s2n_cipher_suite *higher_vers_match = NULL; /* s2n supports only server order */ for (int i = 0; i < conn->config->cipher_preferences->count; i++) { uint8_t *ours = conn->config->cipher_preferences->wire_format + (i * S2N_TLS_CIPHER_SUITE_LEN); for (int j = 0; j < count; j++) { uint8_t *theirs = wire + (j * cipher_suite_len) + (cipher_suite_len - S2N_TLS_CIPHER_SUITE_LEN); if (!memcmp(fallback_scsv, theirs, S2N_TLS_CIPHER_SUITE_LEN)) { if (conn->client_protocol_version < S2N_TLS12) { conn->closed = 1; S2N_ERROR(S2N_ERR_FALLBACK_DETECTED); } } if (!memcmp(ours, theirs, S2N_TLS_CIPHER_SUITE_LEN)) { /* We have a match */ struct s2n_cipher_suite *match; match = s2n_cipher_suite_match(ours); /* This should never happen */ if (match == NULL) { S2N_ERROR(S2N_ERR_CIPHER_NOT_SUPPORTED); } /* Don't choose DHE key exchange if it's not configured. */ if (conn->config->dhparams == NULL && match->key_exchange_alg == &s2n_dhe) { continue; } /* Don't choose EC ciphers if the curve was not agreed upon. */ if (conn->pending.server_ecc_params.negotiated_curve == NULL && (match->key_exchange_alg->flags & S2N_KEY_EXCHANGE_ECC)) { continue; } /* Don't immediately choose a cipher the client shouldn't be able to support */ if (conn->client_protocol_version < match->minimum_required_tls_version) { higher_vers_match = match; continue; } conn->pending.cipher_suite = match; return 0; } } } /* Settle for a cipher with a higher required proto version, if it was set */ if (higher_vers_match != NULL) { conn->pending.cipher_suite = higher_vers_match; return 0; } S2N_ERROR(S2N_ERR_CIPHER_NOT_SUPPORTED); }
int s2n_realloc(struct s2n_blob *b, uint32_t size) { if (size == 0) { return s2n_free(b); } /* blob already has space for the request */ if (size < b->allocated) { b->size = size; return 0; } void *data; if (!use_mlock) { data = realloc(b->data, size); if (!data) { S2N_ERROR(S2N_ERR_ALLOC); } b->data = data; b->size = size; b->allocated = size; return 0; } /* Page aligned allocation required for mlock */ uint32_t allocate = page_size * (((size - 1) / page_size) + 1); if (posix_memalign(&data, page_size, allocate)) { S2N_ERROR(S2N_ERR_ALLOC); } if (b->size) { memcpy_check(data, b->data, b->size); GUARD(s2n_free(b)); } b->data = data; b->size = size; b->allocated = allocate; #ifdef MADV_DONTDUMP if (madvise(b->data, size, MADV_DONTDUMP) < 0) { GUARD(s2n_free(b)); S2N_ERROR(S2N_ERR_MADVISE); } #endif if (mlock(b->data, size) < 0) { GUARD(s2n_free(b)); S2N_ERROR(S2N_ERR_MLOCK); } b->mlocked = 1; return 0; }
int s2n_rsa_encrypt(struct s2n_rsa_public_key *key, struct s2n_blob *in, struct s2n_blob *out) { if (out->size < s2n_rsa_public_encrypted_size(key)) { S2N_ERROR(S2N_ERR_NOMEM); } int r = RSA_public_encrypt(in->size, (unsigned char *)in->data, (unsigned char *)out->data, key->rsa, RSA_PKCS1_PADDING); if (r != out->size) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } return 0; }
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_dh_params_check(struct s2n_dh_params *params) { int codes = 0; if (DH_check(params->dh, &codes) == 0) { S2N_ERROR(S2N_ERR_DH_PARAMETER_CHECK); } if (codes != 0) { S2N_ERROR(S2N_ERR_DH_PARAMETER_CHECK); } return 0; }
int s2n_asn1der_to_rsa_private_key(struct s2n_rsa_private_key *key, struct s2n_blob *asn1der) { uint8_t *original_ptr = asn1der->data; key->rsa = d2i_RSAPrivateKey(NULL, (const unsigned char **)(void *)&asn1der->data, asn1der->size); if (key->rsa == NULL) { S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); } if (asn1der->data - original_ptr != asn1der->size) { S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); } return 0; }
int s2n_set_server_name(struct s2n_connection *conn, const char *server_name) { if (conn->mode != S2N_CLIENT) { S2N_ERROR(S2N_ERR_CLIENT_MODE); } int len = strlen(server_name); if (len > 255) { S2N_ERROR(S2N_ERR_SERVER_NAME_TOO_LONG); } memcpy_check(conn->server_name, server_name, len); return 0; }
int s2n_cbc_cipher_3des_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) { gte_check(out->size, in->size); if (EVP_DecryptInit_ex(&key->native_format.evp_cipher_ctx, NULL, NULL, NULL, iv->data) == 0) { S2N_ERROR(S2N_ERR_KEY_INIT); } int len = out->size; if (EVP_DecryptUpdate(&key->native_format.evp_cipher_ctx, out->data, &len, in->data, in->size) == 0) { S2N_ERROR(S2N_ERR_DECRYPT); } return 0; }
static int s2n_composite_cipher_aes_sha_initial_hmac(struct s2n_session_key *key, uint8_t *sequence_number, uint8_t content_type, uint16_t protocol_version, uint16_t payload_and_eiv_len, int *extra) { uint8_t ctrl_buf[S2N_TLS12_AAD_LEN]; struct s2n_blob ctrl_blob = { .data = ctrl_buf, .size = S2N_TLS12_AAD_LEN }; struct s2n_stuffer ctrl_stuffer; GUARD(s2n_stuffer_init(&ctrl_stuffer, &ctrl_blob)); GUARD(s2n_stuffer_write_bytes(&ctrl_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, content_type)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version / 10)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version % 10)); GUARD(s2n_stuffer_write_uint16(&ctrl_stuffer, payload_and_eiv_len)); /* This will unnecessarily mangle the input buffer, which is fine since it's temporary * Return value will be length of digest, padding, and padding length byte. * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L814 * and https://github.com/openssl/openssl/blob/4f0c475719defd7c051964ef9964cc6e5b3a63bf/ssl/record/ssl3_record.c#L743 */ int ctrl_ret = EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_TLS1_AAD, S2N_TLS12_AAD_LEN, ctrl_buf); if (ctrl_ret < 0) { S2N_ERROR(S2N_ERR_INITIAL_HMAC); } *extra = ctrl_ret; return 0; }
int s2n_kem_find_supported_kem(struct s2n_blob *client_kem_ids, const struct s2n_kem *server_kem_pref_list, const int num_server_supported_kems, const struct s2n_kem **matching_kem) { struct s2n_stuffer client_kems_in = {{0}}; GUARD(s2n_stuffer_init(&client_kems_in, client_kem_ids)); GUARD(s2n_stuffer_write(&client_kems_in, client_kem_ids)); for (int i = 0; i < num_server_supported_kems; i++) { const struct s2n_kem candidate_server_kem_name = server_kem_pref_list[i]; for (int j = 0; j < client_kem_ids->size / 2; j++) { kem_extension_size candidate_client_kem_id; GUARD(s2n_stuffer_read_uint16(&client_kems_in, &candidate_client_kem_id)); if (candidate_server_kem_name.kem_extension_id == candidate_client_kem_id) { *matching_kem = &server_kem_pref_list[i]; return 0; } } GUARD(s2n_stuffer_reread(&client_kems_in)); } /* Nothing found */ S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); return 0; }
int s2n_client_ccs_recv(struct s2n_connection *conn) { uint8_t type; GUARD(s2n_prf_client_finished(conn)); GUARD(s2n_prf_key_expansion(conn)); struct s2n_blob seq = {.data = conn->pending.client_sequence_number, .size = sizeof(conn->pending.client_sequence_number) }; GUARD(s2n_blob_zero(&seq)); /* Update the client to use the pending cipher-suite */ conn->client = &conn->pending; GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); if (type != CHANGE_CIPHER_SPEC_TYPE) { S2N_ERROR(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_handshake_get_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state *hash_state) { switch (hash_alg) { case S2N_HASH_MD5: *hash_state = conn->handshake.md5; break; case S2N_HASH_SHA1: *hash_state = conn->handshake.sha1; break; case S2N_HASH_SHA224: *hash_state = conn->handshake.sha224; break; case S2N_HASH_SHA256: *hash_state = conn->handshake.sha256; break; case S2N_HASH_SHA384: *hash_state = conn->handshake.sha384; break; case S2N_HASH_SHA512: *hash_state = conn->handshake.sha512; break; case S2N_HASH_MD5_SHA1: *hash_state = conn->handshake.md5_sha1; break; default: S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); } return 0; }
int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key) { uint16_t Yc_length; struct s2n_blob Yc; int shared_key_size; BIGNUM *pub_key; GUARD(s2n_check_all_dh_params(server_dh_params)); GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length)); Yc.size = Yc_length; Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size); notnull_check(Yc.data); pub_key = BN_bin2bn((const unsigned char *)Yc.data, Yc.size, NULL); notnull_check(pub_key); GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh); if (shared_key_size <= 0) { BN_free(pub_key); S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); } shared_key->size = shared_key_size; BN_free(pub_key); return 0; }
static int s2n_evp_hmac_p_hash_init(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret) { /* Initialize the message digest */ switch (alg) { case S2N_HMAC_SSLv3_MD5: case S2N_HMAC_MD5: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_md5(); break; case S2N_HMAC_SSLv3_SHA1: case S2N_HMAC_SHA1: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha1(); break; case S2N_HMAC_SHA224: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha224(); break; case S2N_HMAC_SHA256: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha256(); break; case S2N_HMAC_SHA384: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha384(); break; case S2N_HMAC_SHA512: ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha512(); break; default: S2N_ERROR(S2N_ERR_P_HASH_INVALID_ALGORITHM); } /* Initialize the mac key using the provided secret */ notnull_check(ws->tls.p_hash.evp_hmac.mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret->data, secret->size)); /* Initialize the message digest context with the above message digest and mac key */ return s2n_evp_hmac_p_hash_digest_init(ws); }
int s2n_map_lookup(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) { if (!map->immutable) { S2N_ERROR(S2N_ERR_MAP_MUTABLE); } uint32_t slot = s2n_map_slot(map, key); while(map->table[slot].key.size) { if (key->size != map->table[slot].key.size || memcmp(key->data, map->table[slot].key.data, key->size)) { slot++; slot %= map->capacity; continue; } /* We found a match */ value->data = map->table[slot].value.data; value->size = map->table[slot].value.size; return 1; } 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_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_CIPHER_SUITE_LEN]) { /* See if the pending cipher is one we support */ conn->pending.cipher_suite = s2n_cipher_suite_match(wire); if (conn->pending.cipher_suite == NULL) { S2N_ERROR(S2N_ERR_CIPHER_NOT_SUPPORTED); } return 0; }
int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params) { GUARD(s2n_check_p_g_dh_params(dh_params)); if (DH_generate_key(dh_params->dh) == 0) { S2N_ERROR(S2N_ERR_DH_GENERATING_PARAMETERS); } 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; if (EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE) != 1) { S2N_ERROR(S2N_ERR_DRBG); } eq_check(len, S2N_DRBG_BLOCK_SIZE); return 0; }
int s2n_realloc(struct s2n_blob *b, uint32_t size) { if (size == 0) { return s2n_free(b); } if (size < b->allocated) { b->size = size; return 0; } uint32_t allocate = page_size * ((size + (page_size - 1)) / page_size); // preventing unsigned overflow occurs at (size + (page_size - 1)) uint32_t allocate = page_size * (((size - 1) / page_size) + 1); void *data; if (posix_memalign(&data, page_size, allocate)) { S2N_ERROR(S2N_ERR_ALLOC); } if (b->size) { memcpy_check(data, b->data, b->size); GUARD(s2n_free(b)); } b->data = data; b->size = size; b->allocated = allocate; #ifdef MADV_DONTDUMP if (madvise(b->data, size, MADV_DONTDUMP) < 0) { GUARD(s2n_free(b)); S2N_ERROR(S2N_ERR_MADVISE); } #endif if (use_mlock == 0) { return 0; } if (mlock(b->data, size) < 0) { GUARD(s2n_free(b)); S2N_ERROR(S2N_ERR_MLOCK); } b->mlocked = 1; return 0; }
int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output) { GUARD(s2n_check_all_dh_params(server_dh_params)); const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params); const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params); const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params); uint16_t p_size = BN_num_bytes(bn_p); uint16_t g_size = BN_num_bytes(bn_g); uint16_t Ys_size = BN_num_bytes(bn_Ys); uint8_t *p; uint8_t *g; uint8_t *Ys; output->data = s2n_stuffer_raw_write(out, 0); notnull_check(output->data); GUARD(s2n_stuffer_write_uint16(out, p_size)); p = s2n_stuffer_raw_write(out, p_size); notnull_check(p); if (BN_bn2bin(bn_p, p) != p_size) { S2N_ERROR(S2N_ERR_DH_SERIALIZING); } GUARD(s2n_stuffer_write_uint16(out, g_size)); g = s2n_stuffer_raw_write(out, g_size); notnull_check(g); if (BN_bn2bin(bn_g, g) != g_size) { S2N_ERROR(S2N_ERR_DH_SERIALIZING); } GUARD(s2n_stuffer_write_uint16(out, Ys_size)); Ys = s2n_stuffer_raw_write(out, Ys_size); notnull_check(Ys); if (BN_bn2bin(bn_Ys, Ys) != Ys_size) { S2N_ERROR(S2N_ERR_DH_SERIALIZING); } output->size = p_size + 2 + g_size + 2 + Ys_size + 2; return 0; }
int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key) { struct s2n_dh_params client_params; uint8_t *client_pub_key; uint16_t client_pub_key_size; int shared_key_size; GUARD(s2n_dh_params_check(server_dh_params)); GUARD(s2n_dh_params_copy(server_dh_params, &client_params)); GUARD(s2n_dh_generate_ephemeral_key(&client_params)); GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params); client_pub_key_size = BN_num_bytes(client_pub_key_bn); GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size)); client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size); if (client_pub_key == NULL) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY); } if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY); } /* server_dh_params already validated */ const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params); shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh); if (shared_key_size < 0) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); } shared_key->size = shared_key_size; GUARD(s2n_dh_params_free(&client_params)); return 0; }
int s2n_rsa_decrypt(struct s2n_rsa_private_key *key, struct s2n_blob *in, struct s2n_blob *out) { unsigned char intermediate[4096]; if (s2n_rsa_private_encrypted_size(key) > sizeof(intermediate)) { S2N_ERROR(S2N_ERR_NOMEM); } if (out->size > sizeof(intermediate)) { S2N_ERROR(S2N_ERR_NOMEM); } int r = RSA_private_decrypt(in->size, (unsigned char *)in->data, intermediate, key->rsa, RSA_PKCS1_PADDING); GUARD(s2n_constant_time_copy_or_dont(out->data, intermediate, out->size, r != out->size)); if (r != out->size) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } return 0; }