Skip to content

Commit

Permalink
address win impl comments
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyMusatkin committed Sep 27, 2023
1 parent 041c14d commit c0bef61
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 86 deletions.
60 changes: 46 additions & 14 deletions source/darwin/securityframework_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,39 @@ static void s_rsa_destroy_key(void *key_pair) {
aws_mem_release(base->allocator, impl);
}

/*
* Transforms security error code into crt error code and raises it as necessary.
* Docs on what security apis can throw are fairly sparse and so far in testing
* it only threw generic -50 error. So just log for now and we can add additional
* error translation later.
*/
static int s_reinterpret_sec_error_as_crt(CFErrorRef error, const char *function_name) {
if (error == NULL) {
return AWS_OP_SUCCESS;
}

CFIndex error_code = CFErrorGetCode(error);
CFStringRef error_message = CFErrorCopyDescription(error);

struct aws_byte_cursor error_cur;
AWS_ZERO_STRUCT(error_cur);
if (error_message != NULL) {
const char* error_cstr = CFStringGetCStringPtr(error_message, kCFStringEncodingASCII);
if (error_cstr != NULL) {
error_cur = aws_byte_cursor_from_c_str(error_cstr);
}
}

AWS_LOGF_ERROR(AWS_LS_CAL_RSA, "Calling function %s failed with %ld and extended error" PRInSTR,
function_name, error_code, AWS_BYTE_CURSOR_PRI(error_cur));

CFRelease(error_code);
CFRelease(error_message);

return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);

}

/*
* Maps crt encryption algo enum to Security Framework equivalent.
* Fails with AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM if mapping cannot be done for
Expand Down Expand Up @@ -124,8 +157,7 @@ int s_rsa_encrypt(

CFErrorRef error = NULL;
CFDataRef ciphertext_ref = SecKeyCreateEncryptedData(key_pair_impl->pub_key_ref, alg, plaintext_ref, &error);
if (error != NULL) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateEncryptedData")) {
CFRelease(error);
goto on_error;
}
Expand Down Expand Up @@ -182,7 +214,7 @@ int s_rsa_decrypt(

CFErrorRef error = NULL;
CFDataRef plaintext_ref = SecKeyCreateDecryptedData(key_pair_impl->priv_key_ref, alg, ciphertext_ref, &error);
if (error != NULL) {
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateDecryptedData")) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
CFRelease(error);
goto on_error;
Expand Down Expand Up @@ -239,7 +271,7 @@ int s_rsa_sign(

CFErrorRef error = NULL;
CFDataRef signature_ref = SecKeyCreateSignature(key_pair_impl->priv_key_ref, alg, digest_ref, &error);
if (error != NULL) {
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateSignature")) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
CFRelease(error);
goto on_error;
Expand Down Expand Up @@ -297,11 +329,14 @@ int s_rsa_verify(

CFErrorRef error = NULL;
Boolean result = SecKeyVerifySignature(key_pair_impl->pub_key_ref, alg, digest_ref, signature_ref, &error);

CFRelease(digest_ref);
CFRelease(signature_ref);
if (s_reinterpret_sec_error_as_crt(error, "SecKeyVerifySignature") || result == false) {
return aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
}

return result == true ? AWS_OP_SUCCESS : aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
return AWS_OP_SUCCESS;
}

static struct aws_rsa_key_vtable s_rsa_key_pair_vtable = {
Expand Down Expand Up @@ -344,9 +379,8 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_generate_random(

CFErrorRef error = NULL;
key_pair->priv_key_ref = SecKeyCreateRandomKey(key_attributes, &error);
if (error != NULL) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
CFRelease(error);
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateRandomKey")) {
CFRelease(error);
goto on_error;
}

Expand Down Expand Up @@ -423,15 +457,14 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_private_key_pkcs1_impl(

CFErrorRef error = NULL;
key_pair_impl->priv_key_ref = SecKeyCreateWithData(private_key_data, key_attributes, &error);
if (error != NULL) {
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateWithData")) {
CFRelease(error);
goto on_error;
}

key_pair_impl->pub_key_ref = SecKeyCopyPublicKey(key_pair_impl->priv_key_ref);
if (key_pair_impl->pub_key_ref == NULL) {
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
CFRelease(error);
goto on_error;
}
Expand Down Expand Up @@ -485,8 +518,7 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_public_key_pkcs1_impl(

CFErrorRef error = NULL;
key_pair_impl->pub_key_ref = SecKeyCreateWithData(public_key_data, key_attributes, &error);
if (error != NULL) {
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
if (s_reinterpret_sec_error_as_crt(error, "SecKeyCreateWithData")) {
CFRelease(error);
goto on_error;
}
Expand Down
32 changes: 16 additions & 16 deletions source/unix/openssl_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,26 @@ static void s_rsa_destroy_key(void *key_pair) {
static int s_reinterpret_evp_error_as_crt(int evp_error, const char *function_name) {
if (evp_error > 0) {
return AWS_OP_SUCCESS;
} else {
uint32_t error = ERR_peek_error();
if (evp_error == -2) {
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}
}

AWS_LOGF_ERROR(AWS_LS_CAL_RSA, "Calling function %s failed with %d and extended error %lu",
function_name, evp_error, (unsigned long)error);
uint32_t error = ERR_peek_error();
if (evp_error == -2) {
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}

if (ERR_GET_LIB(error) == ERR_LIB_EVP) {
switch (ERR_GET_REASON(error)) {
case EVP_R_BUFFER_TOO_SMALL:
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
case EVP_R_UNSUPPORTED_ALGORITHM:
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}
}
AWS_LOGF_ERROR(AWS_LS_CAL_RSA, "Calling function %s failed with %d and extended error %lu",
function_name, evp_error, (unsigned long)error);

return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (ERR_GET_LIB(error) == ERR_LIB_EVP) {
switch (ERR_GET_REASON(error)) {
case EVP_R_BUFFER_TOO_SMALL:
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
case EVP_R_UNSUPPORTED_ALGORITHM:
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}
}

return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
}

int s_set_encryption_ctx_from_algo(EVP_PKEY_CTX *ctx, enum aws_rsa_encryption_algorithm algorithm) {
Expand Down
109 changes: 53 additions & 56 deletions source/windows/bcrypt_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,27 @@ static void s_rsa_destroy_key(void *key_pair) {
aws_mem_release(base->allocator, impl);
}

int s_is_not_supported_enc_algo(enum aws_rsa_encryption_algorithm algorithm) {
/*
* Transforms bcrypt error code into crt error code and raises it as necessary.
*/
static int s_reinterpret_bc_error_as_crt(NTSTATUS error, const char *function_name) {
if (BCRYPT_SUCCESS(error)) {
return AWS_OP_SUCCESS;
}

AWS_LOGF_ERROR(AWS_LS_CAL_RSA, "Calling function %s failed with %X", function_name, evp_error);

switch (error) {
case STATUS_BUFFER_TOO_SMALL:
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
case STATUS_NOT_SUPPORTED:
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}

return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
}

int s_check_encryption_algorithm(enum aws_rsa_encryption_algorithm algorithm) {
if (algorithm != AWS_CAL_RSA_ENCRYPTION_PKCS1_5 && algorithm != AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256 &&
algorithm != AWS_CAL_RSA_ENCRYPTION_OAEP_SHA512) {
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
Expand All @@ -62,19 +82,15 @@ int s_rsa_encrypt(
struct aws_byte_buf *out) {
struct bcrypt_rsa_key_pair *key_pair_impl = key_pair->impl;

if (s_is_not_supported_enc_algo(algorithm)) {
if (s_check_encryption_algorithm(algorithm)) {
return AWS_OP_ERR;
}

if (out->capacity - out->len < aws_rsa_key_pair_block_length(key_pair)) {
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}

BCRYPT_OAEP_PADDING_INFO padding_info_oaep;
padding_info_oaep.pszAlgId =
algorithm == AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256 ? BCRYPT_SHA256_ALGORITHM : BCRYPT_SHA512_ALGORITHM;
padding_info_oaep.pbLabel = NULL;
padding_info_oaep.cbLabel = 0;
BCRYPT_OAEP_PADDING_INFO padding_info_oaep = {
.pszAlgId = algorithm == AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256 ? BCRYPT_SHA256_ALGORITHM : BCRYPT_SHA512_ALGORITHM,
.padding_info_oaep.pbLabel = NULL,
.padding_info_oaep.cbLabel = 0
};

ULONG length_written = 0;
NTSTATUS status = BCryptEncrypt(
Expand All @@ -89,8 +105,8 @@ int s_rsa_encrypt(
&length_written,
algorithm == AWS_CAL_RSA_ENCRYPTION_PKCS1_5 ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_OAEP);

if (!BCRYPT_SUCCESS(status)) {
return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_bc_error_as_crt(status, "BCryptEncrypt")) {
return AWS_OP_ERROR;
}

out->len += length_written;
Expand All @@ -104,19 +120,15 @@ int s_rsa_decrypt(
struct aws_byte_buf *out) {
struct bcrypt_rsa_key_pair *key_pair_impl = key_pair->impl;

if (s_is_not_supported_enc_algo(algorithm)) {
if (s_check_encryption_algorithm(algorithm)) {
return AWS_OP_ERR;
}

if (ciphertext.len == 0) {
return AWS_OP_SUCCESS;
}

BCRYPT_OAEP_PADDING_INFO padding_info_oaep;
padding_info_oaep.pszAlgId =
algorithm == AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256 ? BCRYPT_SHA256_ALGORITHM : BCRYPT_SHA512_ALGORITHM;
padding_info_oaep.pbLabel = NULL;
padding_info_oaep.cbLabel = 0;
BCRYPT_OAEP_PADDING_INFO padding_info_oaep = {
.pszAlgId = algorithm == AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256 ? BCRYPT_SHA256_ALGORITHM : BCRYPT_SHA512_ALGORITHM;
.pbLabel = NULL;
.cbLabel = 0;
};

ULONG length_written = 0;
NTSTATUS status = BCryptDecrypt(
Expand All @@ -131,8 +143,8 @@ int s_rsa_decrypt(
&length_written,
algorithm == AWS_CAL_RSA_ENCRYPTION_PKCS1_5 ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_OAEP);

if (!BCRYPT_SUCCESS(status)) {
return aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_bc_error_as_crt(status, "BCryptDecrypt")) {
return AWS_OP_ERR;
}

out->len += length_written;
Expand Down Expand Up @@ -169,43 +181,27 @@ int s_rsa_sign(
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}

size_t output_buf_space = out->capacity - out->len;

if (output_buf_space < aws_rsa_key_pair_signature_length(key_pair)) {
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}

struct aws_byte_buf temp_signature_buf;
aws_byte_buf_init(&temp_signature_buf, key_pair->allocator, aws_rsa_key_pair_signature_length(key_pair));
size_t signature_length = temp_signature_buf.capacity;

ULONG length_written = 0;
NTSTATUS status = BCryptSignHash(
key_pair_impl->key_handle,
padding_info,
digest.ptr,
(ULONG)digest.len,
temp_signature_buf.buffer,
(ULONG)signature_length,
(ULONG *)&signature_length,
out->buffer + out->len,
(ULONG)(out->capacity - out->len),
(ULONG *)&length_written,
algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_PSS);

if (!BCRYPT_SUCCESS(status)) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
goto on_error;
if (s_reinterpret_bc_error_as_crt(status, "BCryptSignHash")) {
goto on_error;
}

temp_signature_buf.len = signature_length;

struct aws_byte_cursor temp_signature_cur = aws_byte_cursor_from_buf(&temp_signature_buf);
aws_byte_buf_append(out, &temp_signature_cur);

aws_byte_buf_clean_up_secure(&temp_signature_buf);
out->len += length_written;
aws_mem_release(key_pair->allocator, padding_info);

return AWS_OP_SUCCESS;

on_error:
aws_byte_buf_clean_up_secure(&temp_signature_buf);
aws_mem_release(key_pair->allocator, padding_info);
return AWS_OP_ERR;
}
Expand Down Expand Up @@ -233,7 +229,11 @@ int s_rsa_verify(
algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_PSS);

aws_mem_release(key_pair->allocator, padding_info);
return status == 0 ? AWS_OP_SUCCESS : aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);

if (s_reinterpret_bc_error_as_crt(status, "BCryptVerifySignature")) {
return aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
}
return AWS_OP_SUCCESS;
}

static struct aws_rsa_key_vtable s_rsa_key_pair_vtable = {
Expand Down Expand Up @@ -261,15 +261,14 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_generate_random(

NTSTATUS status = BCryptGenerateKeyPair(s_rsa_alg, &key_impl->key_handle, (ULONG)key_size_in_bits, 0);

if (!BCRYPT_SUCCESS(status)) {
if (s_reinterpret_bc_error_as_crt(status, "BCryptGenerateKeyPair")) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
goto on_error;
}

status = BCryptFinalizeKeyPair(key_impl->key_handle, 0);

if (!BCRYPT_SUCCESS(status)) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_bc_error_as_crt(status, "BCryptFinalizeKeyPair")) {
goto on_error;
}

Expand Down Expand Up @@ -357,8 +356,7 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_private_key_pkcs1_impl(
(ULONG)key_pair_impl->key_buf.len,
flags);

if (!BCRYPT_SUCCESS(status)) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_bc_error_as_crt(status, "BCryptImportKeyPair")) {
goto on_error;
}

Expand Down Expand Up @@ -430,8 +428,7 @@ struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_public_key_pkcs1_impl(
(ULONG)key_pair_impl->key_buf.len,
flags);

if (!BCRYPT_SUCCESS(status)) {
aws_raise_error(AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED);
if (s_reinterpret_bc_error_as_crt(status, "BCryptImportKeyPair")) {
goto on_error;
}

Expand Down

0 comments on commit c0bef61

Please sign in to comment.