Skip to content

Commit

Permalink
RSA PKCS1.5 SHA1 signing (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyMusatkin authored Nov 15, 2024
1 parent f7a0d43 commit fbbe261
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 4 deletions.
1 change: 1 addition & 0 deletions include/aws/cal/rsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum aws_rsa_encryption_algorithm {

enum aws_rsa_signature_algorithm {
AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256,
AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1,
AWS_CAL_RSA_SIGNATURE_PSS_SHA256,
};

Expand Down
3 changes: 3 additions & 0 deletions source/darwin/securityframework_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ static int s_map_rsa_signing_algo_to_sec(enum aws_rsa_signature_algorithm algori
case AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256:
*out = kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256;
return AWS_OP_SUCCESS;
case AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1:
*out = kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
return AWS_OP_SUCCESS;
case AWS_CAL_RSA_SIGNATURE_PSS_SHA256:
#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 /* macOS 10.13 */)) || \
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* iOS v11 */)) || \
Expand Down
3 changes: 2 additions & 1 deletion source/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ int aws_rsa_key_pair_sign_message(
AWS_PRECONDITION(aws_byte_cursor_is_valid(&digest));

AWS_FATAL_ASSERT(
algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 || algorithm == AWS_CAL_RSA_SIGNATURE_PSS_SHA256);
algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 || algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1 ||
algorithm == AWS_CAL_RSA_SIGNATURE_PSS_SHA256);

if (digest.len > AWS_SHA256_LEN) {
AWS_LOGF_ERROR(
Expand Down
9 changes: 9 additions & 0 deletions source/unix/openssl_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@ static int s_set_signature_ctx_from_algo(EVP_PKEY_CTX *ctx, enum aws_rsa_signatu
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()), "EVP_PKEY_CTX_set_signature_md")) {
return AWS_OP_ERR;
}
} else if (algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1) {
if (s_reinterpret_evp_error_as_crt(
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), "EVP_PKEY_CTX_set_rsa_padding")) {
return AWS_OP_ERR;
}
if (s_reinterpret_evp_error_as_crt(
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()), "EVP_PKEY_CTX_set_signature_md")) {
return AWS_OP_ERR;
}
} else if (algorithm == AWS_CAL_RSA_SIGNATURE_PSS_SHA256) {
if (s_reinterpret_evp_error_as_crt(
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), "EVP_PKEY_CTX_set_rsa_padding")) {
Expand Down
11 changes: 9 additions & 2 deletions source/windows/bcrypt_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ static int s_sign_padding_info_init(union sign_padding_info *info, enum aws_rsa_
if (algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256) {
info->pkcs1.pszAlgId = BCRYPT_SHA256_ALGORITHM;
return AWS_OP_SUCCESS;
} else if (algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1) {
info->pkcs1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
return AWS_OP_SUCCESS;
} else if (algorithm == AWS_CAL_RSA_SIGNATURE_PSS_SHA256) {
info->pss.pszAlgId = BCRYPT_SHA256_ALGORITHM;
info->pss.cbSalt = 32;
Expand All @@ -203,6 +206,8 @@ static int s_rsa_sign(
}

ULONG length_written = 0;
bool is_pkcs1_padding =
(algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 || algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1);
NTSTATUS status = BCryptSignHash(
key_pair_impl->key_handle,
&padding_info,
Expand All @@ -211,7 +216,7 @@ static int s_rsa_sign(
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);
is_pkcs1_padding ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_PSS);

if (s_reinterpret_bc_error_as_crt(status, "BCryptSignHash")) {
goto on_error;
Expand Down Expand Up @@ -244,14 +249,16 @@ static int s_rsa_verify(
return aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
}
/* okay, now we've got a windows compatible signature, let's verify it. */
bool is_pkcs1_padding =
(algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 || algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1);
NTSTATUS status = BCryptVerifySignature(
key_pair_impl->key_handle,
&padding_info,
digest.ptr,
(ULONG)digest.len,
signature.ptr,
(ULONG)signature.len,
algorithm == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256 ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_PSS);
is_pkcs1_padding ? BCRYPT_PAD_PKCS1 : BCRYPT_PAD_PSS);

if (status == STATUS_INVALID_SIGNATURE) {
return aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
Expand Down
3 changes: 3 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,18 @@ add_test_case(rsa_encryption_roundtrip_oaep_sha256_from_user)
add_test_case(rsa_encryption_roundtrip_oaep_sha512_from_user)
add_test_case(rsa_signing_roundtrip_pkcs1_sha256_from_user)
add_test_case(rsa_signing_roundtrip_pss_sha256_from_user)
add_test_case(rsa_signing_roundtrip_pkcs1_sha1_from_user)
add_test_case(rsa_getters)
add_test_case(rsa_private_pkcs1_der_parsing)
add_test_case(rsa_public_pkcs1_der_parsing)
add_test_case(rsa_verify_signing_pkcs1_sha256)
add_test_case(rsa_verify_signing_pkcs1_sha1)
add_test_case(rsa_verify_signing_pss_sha256)
add_test_case(rsa_decrypt_pkcs1)
add_test_case(rsa_decrypt_oaep256)
add_test_case(rsa_decrypt_oaep512)
add_test_case(rsa_signing_mismatch_pkcs1_sha256)
add_test_case(rsa_signing_mismatch_pkcs1_sha1)

add_test_case(aes_cbc_NIST_CBCGFSbox256_case_1)
add_test_case(aes_cbc_NIST_CBCVarKey256_case_254)
Expand Down
120 changes: 119 additions & 1 deletion tests/rsa_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ static const char *TEST_RSA_SIGNATURE_PKCS1 = "Gqu9pLlPvSFIW+5ZFo9ZCxMmPR8LnAeiu
"TYJ45P3c94lQIQD3SVJ3XMSAyAEWTE2pcj0F/oPzzxLcXK9cyv2Iphe4XuBjWCOVdHgFg"
"rD/yAA8b+B94AqE9U/B2+k9/C3Bz2YApo=";

static const char *TEST_RSA_SIGNATURE_PKCS1_SHA1 =
"QJxUx+4OM+v1wh0z0PJWMeGBdvjhQHxjFCdzDLeNH6zoJpgPtFXNk6i83ff75MgPpW0m33"
"zrrzLWfzLojZFi2KFXYu1Y39We3AfREEOyG+porTmxNQ4dJH29joXS0XNf52dJpN04Lw3WN"
"XUHDP6eG2K71uXlsus2Tm0uBe4TF0g=";

static const char *TEST_RSA_SIGNATURE_PSS = "j//04sVoqQVSmUgH+Id0oad7OgW+hGnIqx6hjr28VnVk75Obig+n3tJGWd0r+3S4ARxf2fK"
"7taVvJXISQ5aWJAYx6QRgR+25rcE96eOfi6L7ShIZIUYFzGxhc9wpUMGbqHEIhm+8QP7uNo4D"
"FmaPzJMgGDKL2qhedxnjtg3p8E4=";
Expand Down Expand Up @@ -247,6 +252,44 @@ static int s_rsa_verify_signing_pkcs1_sha256(struct aws_allocator *allocator, vo
}
AWS_TEST_CASE(rsa_verify_signing_pkcs1_sha256, s_rsa_verify_signing_pkcs1_sha256);

static int s_rsa_verify_signing_pkcs1_sha1(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
struct aws_byte_cursor message = aws_byte_cursor_from_c_str(TEST_ENCRYPTION_STRING);

aws_cal_library_init(allocator);

struct aws_byte_buf public_key_buf;
ASSERT_SUCCESS(s_byte_buf_decoded_from_base64_cur(
allocator, aws_byte_cursor_from_c_str(TEST_PKCS1_RSA_PUBLIC_KEY_1024), &public_key_buf));
struct aws_rsa_key_pair *key_pair_public =
aws_rsa_key_pair_new_from_public_key_pkcs1(allocator, aws_byte_cursor_from_buf(&public_key_buf));
ASSERT_NOT_NULL(key_pair_public);

uint8_t hash[AWS_SHA1_LEN];
AWS_ZERO_ARRAY(hash);
struct aws_byte_buf hash_value = aws_byte_buf_from_empty_array(hash, sizeof(hash));
aws_sha1_compute(allocator, &message, &hash_value, 0);
struct aws_byte_cursor hash_cur = aws_byte_cursor_from_buf(&hash_value);

struct aws_byte_buf signature_buf;
ASSERT_SUCCESS(s_byte_buf_decoded_from_base64_cur(
allocator, aws_byte_cursor_from_c_str(TEST_RSA_SIGNATURE_PKCS1_SHA1), &signature_buf));
struct aws_byte_cursor signature_cur = aws_byte_cursor_from_buf(&signature_buf);

ASSERT_SUCCESS(aws_rsa_key_pair_verify_signature(
key_pair_public, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, hash_cur, signature_cur));

aws_byte_buf_clean_up(&hash_value);
aws_byte_buf_clean_up(&signature_buf);
aws_byte_buf_clean_up(&public_key_buf);
aws_rsa_key_pair_release(key_pair_public);

aws_cal_library_clean_up();

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(rsa_verify_signing_pkcs1_sha1, s_rsa_verify_signing_pkcs1_sha1);

static int s_rsa_verify_signing_pss_sha256(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
struct aws_byte_cursor message = aws_byte_cursor_from_c_str(TEST_ENCRYPTION_STRING);
Expand Down Expand Up @@ -410,7 +453,12 @@ static int s_rsa_signing_roundtrip_helper(
uint8_t hash[AWS_SHA256_LEN];
AWS_ZERO_ARRAY(hash);
struct aws_byte_buf hash_value = aws_byte_buf_from_empty_array(hash, sizeof(hash));
aws_sha256_compute(allocator, &message, &hash_value, 0);
if (algo == AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1) {
aws_sha1_compute(allocator, &message, &hash_value, 0);
} else {
aws_sha256_compute(allocator, &message, &hash_value, 0);
}

struct aws_byte_cursor hash_cur = aws_byte_cursor_from_buf(&hash_value);

/*since our apis work by appending to buffer, lets make sure they dont
Expand Down Expand Up @@ -494,6 +542,20 @@ static int s_rsa_signing_roundtrip_pkcs1_sha256_from_user(struct aws_allocator *
}
AWS_TEST_CASE(rsa_signing_roundtrip_pkcs1_sha256_from_user, s_rsa_signing_roundtrip_pkcs1_sha256_from_user);

static int s_rsa_signing_roundtrip_pkcs1_sha1_from_user(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

aws_cal_library_init(allocator);

ASSERT_SUCCESS(s_rsa_signing_roundtrip_from_user(
allocator, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, TEST_RSA_SIGNATURE_PKCS1_SHA1));

aws_cal_library_clean_up();

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(rsa_signing_roundtrip_pkcs1_sha1_from_user, s_rsa_signing_roundtrip_pkcs1_sha1_from_user);

static int s_rsa_signing_roundtrip_pss_sha256_from_user(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

Expand Down Expand Up @@ -747,3 +809,59 @@ static int s_rsa_signing_mismatch_pkcs1_sha256(struct aws_allocator *allocator,
return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(rsa_signing_mismatch_pkcs1_sha256, s_rsa_signing_mismatch_pkcs1_sha256);

static int s_rsa_signing_mismatch_pkcs1_sha1(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
struct aws_byte_cursor message = aws_byte_cursor_from_c_str(TEST_ENCRYPTION_STRING);

aws_cal_library_init(allocator);

struct aws_byte_buf public_key_buf;
ASSERT_SUCCESS(s_byte_buf_decoded_from_base64_cur(
allocator, aws_byte_cursor_from_c_str(TEST_PKCS1_RSA_PRIVATE_KEY_1024), &public_key_buf));
struct aws_rsa_key_pair *key_pair_private =
aws_rsa_key_pair_new_from_private_key_pkcs1(allocator, aws_byte_cursor_from_buf(&public_key_buf));
ASSERT_NOT_NULL(key_pair_private);

uint8_t hash[AWS_SHA1_LEN];
AWS_ZERO_ARRAY(hash);
struct aws_byte_buf hash_value = aws_byte_buf_from_empty_array(hash, sizeof(hash));
aws_sha1_compute(allocator, &message, &hash_value, 0);
struct aws_byte_cursor hash_cur = aws_byte_cursor_from_buf(&hash_value);

struct aws_byte_buf signature_buf;
ASSERT_SUCCESS(aws_byte_buf_init(&signature_buf, allocator, aws_rsa_key_pair_signature_length(key_pair_private)));
ASSERT_SUCCESS(
aws_rsa_key_pair_sign_message(key_pair_private, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, hash_cur, &signature_buf));
struct aws_byte_cursor signature_cur = aws_byte_cursor_from_buf(&signature_buf);

hash[5] += 59; /* modify digest to force signature mismatch */

ASSERT_ERROR(
AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED,
aws_rsa_key_pair_verify_signature(
key_pair_private, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, hash_cur, signature_cur));

hash[5] -= 59; /* undo digest modification and corrupt signature */
signature_buf.buffer[5] += 59;
ASSERT_ERROR(
AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED,
aws_rsa_key_pair_verify_signature(
key_pair_private, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, hash_cur, signature_cur));

struct aws_byte_cursor short_signature_cur = aws_byte_cursor_from_c_str("bad signature");
ASSERT_ERROR(
AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED,
aws_rsa_key_pair_verify_signature(
key_pair_private, AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA1, hash_cur, short_signature_cur));

aws_byte_buf_clean_up(&hash_value);
aws_byte_buf_clean_up(&signature_buf);
aws_byte_buf_clean_up(&public_key_buf);
aws_rsa_key_pair_release(key_pair_private);

aws_cal_library_clean_up();

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(rsa_signing_mismatch_pkcs1_sha1, s_rsa_signing_mismatch_pkcs1_sha1);

0 comments on commit fbbe261

Please sign in to comment.