aws / aws-nitro-enclaves-sdk-c

This repo provides a C API for AWS Nitro Enclaves, including a KMS SDK that integrates it with attestation.
Apache License 2.0
99 stars 74 forks source link

Support For Sign operation in KMS Enclave SDK Apis #127

Open adp-nume opened 10 months ago

adp-nume commented 10 months ago

Hi , We have modified AWS Nitro C SDK to Support Sign operations within Enclave. It works well without attestation document and gives the desired output. But when PCR value is added in KMS policy, Like below,

        {
            "Sid": "Enable Enclave access",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "kms:Put*",
                "kms:Sign"
            ],
            "Resource": "*",
            "Condition": {
                "StringEqualsIgnoreCase": {
                    "kms:RecipientAttestation:ImageSha384": "700d541ae32c8b789a1f266aae221387c6910dc3bdc78cc55b02c2711ce0b08b54156ef45d6c733702d79ed35e59c6fb"
                }
            }
        }

It would end up giving following error.

Got non-200 answer from KMS: 400 - {"__type":"AccessDeniedException","Message":"User: arn:aws:sts::3598780XXXXX:assumed-role/nume-enclave-role/i-0b11f180a81f2fea2 is not authorized to perform: kms:Sign on resource: arn:aws:kms:us-east-1:3598780XXXXX:key/fb506b65-0192-4881-b1d2-8ce98aXXXXX because no resource-based policy allows the kms:Sign action"}

Could the team please add the support for Attestation document check verification for KMS Sign and PutKeyPolicy APIs (at KMS Backend) We have a use case where we want to securely Sign the message as well as update update KMS policy from enclave.

richardfan1126 commented 10 months ago

Are you running the enclave in debug mode? If so, the image digest is always 000000000000000000000000000000000000000000000000

adp-nume commented 10 months ago

Hello Richard and thanks for your response. We are trying it non Debug mode nitro-cli run-enclave --eif-path merkle-tree-build.eif --cpu-count 12 --memory 15436

as visible in cloudtrail log, request is "AccessDenied"

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROAVHSTH55KT5XXXXXX:i-0b11f180a81fXXXXX",
        "arn": "arn:aws:sts::359878XXXXX:assumed-role/nume-enclave-role/i-0b11f180a81XXXXX",
        "accountId": "3598780XXXXX",
        "accessKeyId": "ASIAVHSTH55KWXXXXX",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAVHSTH55KT5DRN767X",
                "arn": "arn:aws:iam::3598780XXXXX:role/nume-enclave-role",
                "accountId": "3598780XXXXX",
                "userName": "nume-enclave-role"
            },
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2023-11-08T02:29:31Z",
                "mfaAuthenticated": "false"
            },
            "ec2RoleDelivery": "1.0"
        }
    },
    "eventTime": "2023-11-08T03:29:53Z",
    "eventSource": "kms.amazonaws.com",
    "eventName": "Sign",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "52.207.XX.116",
    "userAgent": "aws-nitro_enclaves-sdk-c/v0.2.1-unknown",
    "errorCode": "AccessDenied",
    "errorMessage": "User: arn:aws:sts::3598780XXXXX:assumed-role/nume-enclave-role/i-0b11f180a81f2fea2 is not authorized to perform: kms:Sign on resource: arn:aws:kms:us-east-1:359878094677:key/fb506b65-0192-4881-b1d2-8ce98aXXXXX because no resource-based policy allows the kms:Sign action",
    "requestParameters": null,
    "responseElements": null,
    "requestID": "698bf67e-10c0-4894-8dce-18dbc2cce02b",
    "eventID": "f9e9986e-a01d-4cd4-8c11-522d701020a5",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "3598780XXXXX",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_256_GCM_SHA384",
        "clientProvidedHostHeader": "kms.us-east-1.amazonaws.com"
    }
}
adp-nume commented 10 months ago

Cloud trail logs of previously successful call when KMS policy doesn't contain Attestation value conditions

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROAVHSTH55KT5DXXXXX:i-0b11f180a81XXXXX",
        "arn": "arn:aws:sts::3598780XXXXX:assumed-role/nume-enclave-role/i-0b11f180a81XXXXX",
        "accountId": "3598780XXXXX",
        "accessKeyId": "ASIAVHSTH55KZNZTJMNW",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAVHSTH55KT5DRN767X",
                "arn": "arn:aws:iam::3598780XXXXX:role/nume-enclave-role",
                "accountId": "3598780XXXXX",
                "userName": "nume-enclave-admin"
            },
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2023-10-30T08:03:45Z",
                "mfaAuthenticated": "false"
            },
            "ec2RoleDelivery": "1.0"
        }
    },
    "eventTime": "2023-10-30T08:56:38Z",
    "eventSource": "kms.amazonaws.com",
    "eventName": "Sign",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "52.207.XX.XXX",
    "userAgent": "aws-nitro_enclaves-sdk-c/v0.2.1-unknown",
    "requestParameters": {
        "messageType": "DIGEST",
        "keyId": "fb506b65-0192-4881-b1d2-8ce98aXXXXX",
        "signingAlgorithm": "ECDSA_SHA_256"
    },
    "responseElements": null,
    "requestID": "65b8599b-07b8-40d7-99e8-a791ef9c86cc",
    "eventID": "7f9f1342-6cfd-44af-b4aa-7fb3033ee51a",
    "readOnly": true,
    "resources": [
        {
            "accountId": "359878094677",
            "type": "AWS::KMS::Key",
            "ARN": "arn:aws:kms:us-east-1:359878XXXXX:key/fb506b65-0192-4881-b1d2-8ce98aXXXXX"
        }
    ],
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "359878XXXXX",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_256_GCM_SHA384",
        "clientProvidedHostHeader": "kms.us-east-1.amazonaws.com"
    }
}

I am making sure that Attestation documents are getting passed in KMS C SDK Code.

int aws_kms_sign_blocking(
    struct aws_nitro_enclaves_kms_client *client,
    const struct aws_string *key_id,
    enum aws_signing_algorithm signing_algorithm,
    const struct aws_byte_buf *message,
    enum aws_message_type message_type,
    struct aws_string **signature /* TODO: err_reason */) {
    AWS_PRECONDITION(client != NULL);
    AWS_PRECONDITION(key_id != NULL);
    AWS_PRECONDITION(signing_algorithm != AWS_SA_UNINITIALIZED);
    AWS_PRECONDITION(message != NULL);
    AWS_PRECONDITION(signature != NULL);

    struct aws_string *response = NULL;
    struct aws_string *request = NULL;
    struct aws_kms_sign_response *response_structure = NULL;
    struct aws_kms_sign_request *request_structure = NULL;
    int rc = 0;

    request_structure = aws_kms_sign_request_new(client->allocator);
    if (request_structure == NULL) {
        return AWS_OP_ERR;
    }

    request_structure->recipient = aws_recipient_new(client->allocator);
    if (request_structure->recipient == NULL) {
        goto err_clean;
    }

    aws_byte_buf_init_copy(&request_structure->message, client->allocator, message);
    request_structure->key_id = aws_string_clone_or_reuse(client->allocator, key_id);
    request_structure->signing_algorithm = signing_algorithm;
    request_structure->message_type = message_type;

    rc = aws_attestation_request(
        client->allocator, client->keypair, &request_structure->recipient->attestation_document);
    if (rc != AWS_OP_SUCCESS) {
        goto err_clean;
    }

    request = aws_kms_sign_request_to_json(request_structure);
    const char *json_c_str = aws_string_c_str(request);
    //fprintf(stdout,"JSON string: %s\n", json_c_str);
    if (request == NULL) {
        goto err_clean;
    }

    rc = s_aws_nitro_enclaves_kms_client_call_blocking(client, kms_target_sign, request, &response);
    if (rc != 200) {
        fprintf(stderr, "Got non-200 answer from KMS: %d - %s\n", rc, aws_string_c_str(response));
        goto err_clean;
    }
    const char *json_c_str_2 = aws_string_c_str(response);
    rc = AWS_OP_SUCCESS;
    struct json_object *parsed_json = json_tokener_parse(json_c_str_2);
    struct json_object *sig_obj = json_object_object_get(parsed_json, "Signature"); 
    const char *sig = json_object_get_string(sig_obj);
    *signature = aws_string_new_from_array(client->allocator,(const uint8_t *)sig, strlen(sig));
    aws_kms_sign_request_destroy(request_structure);
    aws_kms_sign_response_destroy(response_structure);
    aws_string_destroy(request);
    aws_string_destroy(response);

    return rc;
err_clean:
    aws_kms_sign_request_destroy(request_structure);
    aws_kms_sign_response_destroy(response_structure);
    aws_string_destroy(request);
    aws_string_destroy(response);
    return AWS_OP_ERR;
}