static int OnDecrypt()

in aws-encryption-sdk-cpp/source/kms_keyring.cpp [49:159]


static int OnDecrypt(
    struct aws_cryptosdk_keyring *keyring,
    struct aws_allocator *request_alloc,
    struct aws_byte_buf *unencrypted_data_key,
    struct aws_array_list *keyring_trace,
    const struct aws_array_list *edks,
    const struct aws_hash_table *enc_ctx,
    enum aws_cryptosdk_alg_id alg) {
    (void)alg;

    auto self = static_cast<Aws::Cryptosdk::Private::KmsKeyringImpl *>(keyring);
    if (!self || !request_alloc || !unencrypted_data_key || !edks || !enc_ctx) {
        abort();
    }

    Aws::StringStream error_buf;
    const auto enc_ctx_cpp = aws_map_from_c_aws_hash_table(enc_ctx);

    size_t num_elems = aws_array_list_length(edks);
    for (unsigned int idx = 0; idx < num_elems; idx++) {
        struct aws_cryptosdk_edk *edk;
        int rv = aws_array_list_get_at_ptr(edks, (void **)&edk, idx);
        if (rv != AWS_OP_SUCCESS) {
            continue;
        }

        if (!aws_byte_buf_eq(&edk->provider_id, &self->key_provider)) {
            // EDK belongs to a different non KMS keyring. Skip.
            continue;
        }

        const Aws::String key_arn = Private::aws_string_from_c_aws_byte_buf(&edk->provider_info);

        /* If there are no key IDs in the list, keyring is in "discovery" mode and will attempt KMS calls with
         * every key ARN it comes across in the message, so long as the key ARN is authorized by the
         * DiscoveryFilter (matches the partition and an account ID).
         *
         * If there are key IDs in the list, it will cross check the ARN it reads with that list
         * before attempting KMS calls. Note that if caller provided key IDs in anything other than
         * a CMK ARN format, the SDK will not attempt to decrypt those data keys, because the EDK
         * data format always specifies the CMK with the full (non-alias) ARN.
         */
        if (self->key_ids.size() &&
            std::find(self->key_ids.begin(), self->key_ids.end(), key_arn) == self->key_ids.end()) {
            // This keyring does not have access to the CMK used to encrypt this data key. Skip.
            continue;
        }
        // self->discovery_filter is non-null only if self was constructed via BuildDiscovery, which
        // in turn implies discovery mode
        if (self->discovery_filter && !self->discovery_filter->IsAuthorized(key_arn)) {
            // The DiscoveryFilter blocks the CMK used to encrypt this data key. Skip.
            continue;
        }

        Aws::String kms_region = Private::parse_region_from_kms_key_arn(key_arn);
        if (kms_region.empty()) {
            error_buf << "Error: Malformed ciphertext. Provider ID field of KMS EDK is invalid KMS CMK ARN: " << key_arn
                      << " ";
            continue;
        }

        std::function<void()> report_success;
        auto kms_client = self->kms_client_supplier->GetClient(kms_region, report_success);
        if (!kms_client) {
            // Client supplier does not serve this region. Skip.
            continue;
        }

        Aws::KMS::Model::DecryptRequest kms_request;
        kms_request.WithGrantTokens(self->grant_tokens)
            .WithKeyId(key_arn)
            .WithCiphertextBlob(aws_utils_byte_buffer_from_c_aws_byte_buf(&edk->ciphertext))
            .WithEncryptionContext(enc_ctx_cpp);

        Aws::KMS::Model::DecryptOutcome outcome = kms_client->Decrypt(kms_request);
        if (!outcome.IsSuccess()) {
            // Failing on this call is normal behavior in "discovery" mode, but not in standard mode.
            if (self->key_ids.size()) {
                error_buf << "Error: " << outcome.GetError().GetExceptionName()
                          << " Message:" << outcome.GetError().GetMessage() << " ";
            }
            continue;
        }
        report_success();

        const Aws::String &outcome_key_id = outcome.GetResult().GetKeyId();
        if (outcome_key_id == key_arn) {
            int ret = aws_byte_buf_dup_from_aws_utils(
                request_alloc, unencrypted_data_key, outcome.GetResult().GetPlaintext());
            if (ret == AWS_OP_SUCCESS) {
                aws_cryptosdk_keyring_trace_add_record_c_str(
                    request_alloc,
                    keyring_trace,
                    KEY_PROVIDER_STR,
                    key_arn.c_str(),
                    AWS_CRYPTOSDK_WRAPPING_KEY_DECRYPTED_DATA_KEY | AWS_CRYPTOSDK_WRAPPING_KEY_VERIFIED_ENC_CTX);
            }
            return ret;
        } else {
            // Since we specified the key ARN explicitly in the request,
            // KMS had better use that key to decrypt
            return aws_raise_error(AWS_ERROR_INVALID_STATE);
        }
    }

    AWS_LOGSTREAM_ERROR(
        AWS_CRYPTO_SDK_KMS_CLASS_TAG,
        "Could not find any data key that can be decrypted by KMS. Errors:" << error_buf.str());
    // According to materials.h we should return success when no key was found
    return AWS_OP_SUCCESS;
}