Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/build-config-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,17 @@ jobs:
modifiers: "-HAVE_HKDF -HAVE_ECC_ENCRYPT"
- name: tls-prf
modifiers: "-WOLFSSL_HAVE_PRF"
# This config stays as a static library (not shared) because of a
# missing symbol in this build of wolfSSL. 'target' field and the
# LDFLAGS environment variable below can be removed after

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping LDFLAGS would also drop -z defs from every lane, so only the pbkdf2 target can go. That also has to wait for a wolfSSL stable release with wolfSSL/wolfssl#11958, since the matrix still builds v5.9.4-stable.

# wolfSSL#11958 merges.
- name: pbkdf2
modifiers: "-HAVE_PBKDF2 +NO_PBKDF2"
target: libwolfpsa.a
- name: ecc384
modifiers: "-WOLFSSL_SP_384 -HAVE_ECC384"
- name: no-ecc
modifiers: "-HAVE_ECC -HAVE_ECC_ENCRYPT"
- name: rsa-1024
modifiers: "-WOLFSSL_SP_1024 -RSA_MIN_SIZE +RSA_MIN_SIZE=2048"
# wolfPSA's own sources only: the bundled wolfCrypt sources do not
Expand All @@ -107,5 +114,7 @@ jobs:

- name: Build ${{ matrix.config.name }}
env:
BUILD_TARGET: ${{ matrix.config.target || 'libwolfpsa.a' }}
BUILD_TARGET: ${{ matrix.config.target || 'libwolfpsa.so' }}
# Fail on undefined symbols
LDFLAGS: -Wl,-z,defs
Comment thread
Frauschi marked this conversation as resolved.
Resolved
run: ./build-test/build-variant.sh "${{ matrix.config.name }}" ${{ matrix.config.modifiers }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ test/psa_des3_pkcs7_test
test/psa_ecc_curve_caps_test
test/psa_ecc_ecdh_curve_test
test/psa_ecc_sig_len_test
test/psa_rsa_status_test
test/psa_ecc_verify_curve_test
test/psa_eddsa_mont_export_test
test/psa_eddsa_mont_gen_test
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ UNIT_TESTS := psa_api_test \
psa_ecc_curve_caps_test \
psa_xof_no_backend_test \
psa_ecc_sig_len_test \
psa_rsa_status_test \
psa_xof_set_context_test \
psa_cipher_inplace_test \
psa_cipher_overlap_test \
Expand Down
28 changes: 26 additions & 2 deletions src/psa_asymmetric_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ psa_status_t psa_asymmetric_decrypt_rsa(psa_key_type_t key_type,
uint8_t *output,
size_t output_size,
size_t *output_length);
#ifdef HAVE_ECC
psa_status_t psa_asymmetric_sign_ecc(psa_key_type_t key_type,
size_t key_bits,
const uint8_t *key_buffer,
Expand All @@ -124,6 +125,7 @@ psa_status_t psa_asymmetric_verify_ecc(psa_key_type_t key_type,
size_t hash_length,
const uint8_t *signature,
size_t signature_length);
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type,
size_t key_bits,
Expand Down Expand Up @@ -367,6 +369,20 @@ static psa_status_t wolfpsa_check_context(psa_algorithm_t alg,
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Required signature size, or 0 when this build cannot sign with key_type */
static size_t wolfpsa_sign_output_size(psa_key_type_t key_type,
size_t key_bits,
psa_algorithm_t alg)
{
#ifndef HAVE_ECC
if (PSA_KEY_TYPE_IS_ECC(key_type) &&
key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS)) {
return 0;
}
#endif /* !HAVE_ECC */
return PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg);
}

psa_status_t psa_asymmetric_encrypt(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
Expand Down Expand Up @@ -562,7 +578,7 @@ static psa_status_t wolfpsa_sign_hash_worker(psa_key_id_t key,
* contract status for every signature family. Checked after the
* algorithm and key-type rejections above: a call that can never succeed
* must report why, not a buffer problem. */
sig_size = PSA_SIGN_OUTPUT_SIZE(attributes.type, attributes.bits, alg);
sig_size = wolfpsa_sign_output_size(attributes.type, attributes.bits, alg);
if (sig_size != 0 && signature_size < sig_size) {
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
return PSA_ERROR_BUFFER_TOO_SMALL;
Expand Down Expand Up @@ -604,13 +620,15 @@ static psa_status_t wolfpsa_sign_hash_worker(psa_key_id_t key,
}
}
#endif
#ifdef HAVE_ECC
Comment thread
Frauschi marked this conversation as resolved.
Resolved
else if (PSA_KEY_TYPE_IS_ECC(attributes.type)) {
status = psa_asymmetric_sign_ecc(attributes.type, attributes.bits,
key_data, key_data_length,
alg, hash, hash_length,
signature, signature_size,
signature_length);
}
#endif /* HAVE_ECC */
else {
status = PSA_ERROR_NOT_SUPPORTED;
}
Expand Down Expand Up @@ -745,12 +763,14 @@ static psa_status_t wolfpsa_verify_hash_worker(psa_key_id_t key,
}
}
#endif
#ifdef HAVE_ECC
else if (PSA_KEY_TYPE_IS_ECC(attributes.type)) {
status = psa_asymmetric_verify_ecc(attributes.type, attributes.bits,
key_data, key_data_length,
alg, hash, hash_length,
signature, signature_length);
}
#endif /* HAVE_ECC */
else {
status = PSA_ERROR_NOT_SUPPORTED;
}
Expand Down Expand Up @@ -871,7 +891,7 @@ static psa_status_t wolfpsa_sign_message_worker(psa_key_id_t key,

/* Required signature capacity, so a zero-capacity buffer gets the
* contract status for every signature family. */
sig_size = PSA_SIGN_OUTPUT_SIZE(attributes.type, attributes.bits, alg);
sig_size = wolfpsa_sign_output_size(attributes.type, attributes.bits, alg);
if (sig_size != 0 && signature_size < sig_size) {
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
return PSA_ERROR_BUFFER_TOO_SMALL;
Expand Down Expand Up @@ -1036,13 +1056,15 @@ static psa_status_t wolfpsa_sign_message_worker(psa_key_id_t key,
}
}
#endif
#ifdef HAVE_ECC
else if (PSA_KEY_TYPE_IS_ECC(attributes.type)) {
status = psa_asymmetric_sign_ecc(attributes.type, attributes.bits,
key_data, key_data_length,
alg, hash, hash_length,
signature, signature_size,
signature_length);
}
#endif /* HAVE_ECC */
else {
status = PSA_ERROR_NOT_SUPPORTED;
}
Expand Down Expand Up @@ -1284,12 +1306,14 @@ static psa_status_t wolfpsa_verify_message_worker(psa_key_id_t key,
}
}
#endif
#ifdef HAVE_ECC
else if (PSA_KEY_TYPE_IS_ECC(attributes.type)) {
status = psa_asymmetric_verify_ecc(attributes.type, attributes.bits,
key_data, key_data_length,
alg, hash, hash_length,
signature, signature_length);
}
#endif /* HAVE_ECC */
else {
status = PSA_ERROR_NOT_SUPPORTED;
}
Expand Down
85 changes: 50 additions & 35 deletions src/psa_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,36 @@ static int wc_psa_get_mgf(int hash_type)
}
#endif /* WC_RSA_PSS || WOLFSSL_RSA_OAEP */

/* PSA requires the hash to be as long as the one the algorithm names. Raw
* PKCS#1 v1.5 signs any input. */
static int wc_psa_rsa_hash_length_ok(psa_algorithm_t alg, size_t hash_length)
{
size_t expected;

if (alg == PSA_ALG_RSA_PKCS1V15_SIGN_RAW) {
return 1;
}
expected = PSA_HASH_LENGTH(PSA_ALG_SIGN_GET_HASH(alg));
return expected != 0 && hash_length == expected;
}

/* Status for a failed RSA operation. Callers check the output buffer size
* first, so a buffer, padding or range error refers to the input. */
static psa_status_t wc_psa_rsa_status(int ret, psa_status_t bad_input)
{
switch (ret) {
case BUFFER_E:
case RSA_BUFFER_E:
case BAD_PADDING_E:
case RSA_PAD_E:
case PSS_SALTLEN_E:
case RSA_OUT_OF_RANGE_E:
return bad_input;
default:
return wc_error_to_psa_status(ret);
}
}

#ifdef WC_RSA_PSS
static int wc_psa_rsa_pss_check_padding(const byte* hash, word32 hash_length,
const byte* encoded, word32 encoded_length,
Expand Down Expand Up @@ -136,7 +166,6 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type,
int padding;
int hash_type;
int hash_oid;
size_t expected_hash_len;
byte* sig_input = NULL;
word32 sig_input_len = 0;
word32 sig_input_alloc_len = 0;
Expand All @@ -150,7 +179,8 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type,
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) {
(wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS) ||
!wc_psa_rsa_hash_length_ok(alg, hash_length)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

Expand Down Expand Up @@ -194,18 +224,12 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);
return PSA_ERROR_NOT_SUPPORTED;
}
/* PSA requires the digest to be exactly as long as the hash
* named by the algorithm; anything else is INVALID_ARGUMENT.
* wc_EncodeSignature() would otherwise happily wrap a 20-byte
* digest in a SHA-256 DigestInfo, and since the verify path
* re-encodes the same way that malformed structure would
* round-trip to success in violation of RFC 8017 A.2.4. The
* WC_MAX_DIGEST_SIZE term is retained as the buffer
* precondition: wc_EncodeSignature() does not bound its own
* write, and the two constants can diverge. */
expected_hash_len = PSA_HASH_LENGTH(PSA_ALG_SIGN_GET_HASH(alg));
if (expected_hash_len == 0 || hash_length != expected_hash_len ||
hash_length > WC_MAX_DIGEST_SIZE) {
/* The hash length is checked above, so wc_EncodeSignature()
* cannot wrap a 20-byte digest in a SHA-256 DigestInfo. This is
* the buffer precondition: wc_EncodeSignature() does not bound
* its own write, and WC_MAX_DIGEST_SIZE and PSA_HASH_LENGTH()
* can diverge. */
if (hash_length > WC_MAX_DIGEST_SIZE) {
wc_FreeRng(&rng);
wc_FreeRsaKey(&rsa_key);
return PSA_ERROR_INVALID_ARGUMENT;
Expand Down Expand Up @@ -256,7 +280,7 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);

if (ret < 0) {
return wc_error_to_psa_status(ret);
return wc_psa_rsa_status(ret, PSA_ERROR_INVALID_ARGUMENT);
}

*signature_length = (size_t)ret;
Expand All @@ -280,7 +304,6 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type,
word32 idx = 0;
int padding;
int hash_type;
size_t expected_hash_len;

(void)key_bits;

Expand All @@ -291,7 +314,8 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type,
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) {
(wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS) ||
!wc_psa_rsa_hash_length_ok(alg, hash_length)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

Expand All @@ -314,6 +338,10 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);
return wc_error_to_psa_status(ret);
}
if (signature_length != (size_t)wc_RsaEncryptSize(&rsa_key)) {
wc_FreeRsaKey(&rsa_key);
return PSA_ERROR_INVALID_SIGNATURE;
}

/* Get padding type and hash type */
padding = wc_psa_get_rsa_padding(alg);
Expand Down Expand Up @@ -359,15 +387,8 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);
return PSA_ERROR_NOT_SUPPORTED;
}
/* Same bound as the sign path: PSA requires the digest to match
* the length of the hash named by the algorithm, and the
* WC_MAX_DIGEST_SIZE term is the buffer precondition for the
* unbounded write wc_EncodeSignature() performs. Accepting a
* mismatched length here would let a DigestInfo whose OID and
* digest length disagree verify successfully. */
expected_hash_len = PSA_HASH_LENGTH(PSA_ALG_SIGN_GET_HASH(alg));
if (expected_hash_len == 0 || hash_length != expected_hash_len ||
hash_length > WC_MAX_DIGEST_SIZE) {
/* Same buffer precondition as the sign path */
if (hash_length > WC_MAX_DIGEST_SIZE) {
wc_ForceZero(decoded, sizeof(decoded));
wc_FreeRsaKey(&rsa_key);
return PSA_ERROR_INVALID_ARGUMENT;
Expand Down Expand Up @@ -452,13 +473,7 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);

if (ret < 0) {
/* The shared mapper sends RSA_PAD_E to PSA_ERROR_INVALID_PADDING for
* the decrypt path. On a verification a failed unpad is a signature
* mismatch, and psa_verify_hash does not define INVALID_PADDING. */
if (ret == RSA_PAD_E) {
return PSA_ERROR_INVALID_SIGNATURE;
}
return wc_error_to_psa_status(ret);
return wc_psa_rsa_status(ret, PSA_ERROR_INVALID_SIGNATURE);
}

if ((size_t)ret != hash_length) {
Expand Down Expand Up @@ -575,7 +590,7 @@ psa_status_t psa_asymmetric_encrypt_rsa(psa_key_type_t key_type,
wc_FreeRsaKey(&rsa_key);

if (ret < 0) {
return wc_error_to_psa_status(ret);
return wc_psa_rsa_status(ret, PSA_ERROR_INVALID_ARGUMENT);
}

*output_length = (size_t)ret;
Expand Down Expand Up @@ -721,7 +736,7 @@ psa_status_t psa_asymmetric_decrypt_rsa(psa_key_type_t key_type,
status = PSA_ERROR_BUFFER_TOO_SMALL;
}
else if (ret < 0) {
status = wc_error_to_psa_status(ret);
status = wc_psa_rsa_status(ret, PSA_ERROR_INVALID_PADDING);
}
else {
if (ret > 0) {
Expand Down
1 change: 1 addition & 0 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ PSA_REGRESSION_TESTS = psa_aead_multipart_test \
psa_ecc_curve_caps_test \
psa_xof_no_backend_test \
psa_ecc_sig_len_test \
psa_rsa_status_test \
psa_xof_set_context_test \
psa_cipher_inplace_test \
psa_cipher_overlap_test \
Expand Down
18 changes: 18 additions & 0 deletions test/psa_server/psa_eddsa_mont_export_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static int test_export_pair_public(psa_ecc_family_t family,
psa_key_type_t key_type;
uint8_t pub[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(448)];
size_t pub_size = sizeof(pub);
uint8_t pair[PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(448)];
size_t pair_len = 0;
psa_status_t st;
int ok = 0;

Expand Down Expand Up @@ -76,6 +78,22 @@ static int test_export_pair_public(psa_ecc_family_t family,
goto destroy;
}

st = psa_export_key(key_id, pair,
PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, bits),
&pair_len);
if (st != PSA_SUCCESS) {
printf("FAIL %s key pair export into PSA_EXPORT_KEY_OUTPUT_SIZE "
"status=%d\n", label, (int)st);
goto destroy;
}

if (pair_len != PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, bits)) {
printf("FAIL %s key pair export len=%u expected=%u\n", label,
(unsigned)pair_len,
(unsigned)PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, bits));
goto destroy;
}

ok = 1;

destroy:
Expand Down
Loading
Loading