int aws_cryptosdk_priv_try_gen_key()

in source/session_encrypt.c [50:150]


int aws_cryptosdk_priv_try_gen_key(struct aws_cryptosdk_session *session) {
    AWS_PRECONDITION(aws_cryptosdk_session_is_valid(session));
    AWS_PRECONDITION(aws_cryptosdk_commitment_policy_is_valid(session->commitment_policy));
    AWS_PRECONDITION(session->state == ST_GEN_KEY);
    AWS_PRECONDITION(session->mode == AWS_CRYPTOSDK_ENCRYPT);
    struct aws_cryptosdk_enc_request request;
    struct aws_cryptosdk_enc_materials *materials = NULL;
    struct data_key data_key;
    int result = AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN;

    request.alloc   = session->alloc;
    request.enc_ctx = &session->header.enc_ctx;
    // The default CMM will fill this in.
    request.requested_alg     = 0;
    request.plaintext_size    = session->precise_size_known ? session->precise_size : session->size_bound;
    request.commitment_policy = session->commitment_policy;

    if (aws_cryptosdk_cmm_generate_enc_materials(session->cmm, &materials, &request)) {
        goto rethrow;
    }

    // Perform basic validation of the materials generated
    session->alg_props = aws_cryptosdk_alg_props(materials->alg);

    if (!session->alg_props) goto out;
    if (materials->unencrypted_data_key.len != session->alg_props->data_key_len) goto out;

    size_t num_encrypted_data_keys = aws_array_list_length(&materials->encrypted_data_keys);
    if (!num_encrypted_data_keys) goto out;
    if (session->max_encrypted_data_keys && num_encrypted_data_keys > session->max_encrypted_data_keys) {
        result = AWS_CRYPTOSDK_ERR_LIMIT_EXCEEDED;
        goto out;
    }

    // We should have a signature context iff this is a signed alg suite
    if (!!session->alg_props->signature_len != !!materials->signctx) goto out;
    if (!aws_cryptosdk_priv_algorithm_allowed_for_encrypt(materials->alg, session->commitment_policy)) {
        result = AWS_CRYPTOSDK_ERR_COMMITMENT_POLICY_VIOLATION;
        goto out;
    }

    // Move ownership of the signature context before we go any further.
    session->signctx   = materials->signctx;
    materials->signctx = NULL;

    // TODO - eliminate the data_key type
    memcpy(&data_key, materials->unencrypted_data_key.buffer, materials->unencrypted_data_key.len);

    aws_cryptosdk_transfer_list(&session->keyring_trace, &materials->keyring_trace);
    session->cmm_success = true;

    // Generate message ID and derive the content key from the data key.
    size_t message_id_len = aws_cryptosdk_private_algorithm_message_id_len(session->alg_props);
    if (aws_byte_buf_init(&session->header.message_id, session->alloc, message_id_len) != AWS_OP_SUCCESS) {
        goto out;
    }
    if (aws_cryptosdk_genrandom(session->header.message_id.buffer, message_id_len)) {
        goto out;
    }
    session->header.message_id.len = message_id_len;

    if (aws_cryptosdk_commitment_policy_encrypt_must_include_commitment(session->commitment_policy)) {
        assert(session->alg_props->commitment_len <= sizeof(session->key_commitment_arr));
        session->header.alg_suite_data =
            aws_byte_buf_from_array(session->key_commitment_arr, session->alg_props->commitment_len);
    }

    if (aws_cryptosdk_private_derive_key(
            session->alg_props,
            &session->content_key,
            &data_key,
            &session->header.alg_suite_data,
            &session->header.message_id)) {
        goto rethrow;
    }

    if (build_header(session, materials)) {
        goto rethrow;
    }

    if (sign_header(session)) {
        goto rethrow;
    }

    result = AWS_ERROR_SUCCESS;

out:
    if (result) result = aws_raise_error(result);
    goto cleanup;
rethrow:
    result = AWS_OP_ERR;
cleanup:
    if (materials) {
        aws_byte_buf_secure_zero(&materials->unencrypted_data_key);
        aws_cryptosdk_enc_materials_destroy(materials);
    }

    aws_secure_zero(&data_key, sizeof(data_key));

    return result;
}