Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cryptotest] Add P-384 targets to cryptotest. #25510

Merged
merged 1 commit into from
Dec 5, 2024
Merged
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
23 changes: 9 additions & 14 deletions sw/device/tests/crypto/cryptotest/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ ECDSA_TESTVECTOR_TARGETS = [
"p256_sha512",
"p256_sha3_256",
"p256_sha3_512",
# TODO uncomment when cryptolib supports ECDSA with P-384
# "p384_sha384",
# "p384_sha512",
# "p384_sha3_384",
# "p384_sha3_512",
"p384_sha384",
"p384_sha512",
"p384_sha3_384",
"p384_sha3_512",
]
] + [
"//sw/host/cryptotest/testvectors/data:nist_cavp_ecdsa_fips_186_4_sig_ver_json",
Expand All @@ -51,13 +50,10 @@ ECDSA_TESTVECTOR_TARGETS = [
"p256_sha3_256",
"p256_sha3_384",
"p256_sha3_512",
# TODO uncomment when cryptolib supports ECDSA with P-384
# "p384_sha256",
# "p384_sha384",
# "p384_sha512",
# "p384_sha3_256",
# "p384_sha3_384",
# "p384_sha3_512",
"p384_sha384",
"p384_sha512",
"p384_sha3_384",
"p384_sha3_512",
]
]

Expand All @@ -78,8 +74,7 @@ ECDH_TESTVECTOR_TARGETS = [
"//sw/host/cryptotest/testvectors/data:wycheproof_ecdh_{}".format(mode)
for mode in [
"p256",
# TODO uncomment when ECDH supports P-384
# "p384",
"p384",
]
] + [
"//sw/host/cryptotest/testvectors/data:nist_cavp_ecdh_sp_800_56a_json",
Expand Down
44 changes: 36 additions & 8 deletions sw/device/tests/crypto/cryptotest/firmware/ecdh.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/crypto/impl/ecc/p256.h"
#include "sw/device/lib/crypto/impl/ecc/p384.h"
#include "sw/device/lib/crypto/impl/integrity.h"
#include "sw/device/lib/crypto/impl/keyblob.h"
#include "sw/device/lib/crypto/include/datatypes.h"
Expand All @@ -15,6 +16,7 @@
#include "sw/device/tests/crypto/cryptotest/json/ecdh_commands.h"

static const int P256_KEY_BYTES = 32;
static const int P384_KEY_BYTES = 48;

status_t handle_ecdh(ujson_t *uj) {
// Declare ECDH parameter ujson deserializer types
Expand All @@ -32,6 +34,9 @@ status_t handle_ecdh(ujson_t *uj) {
otcrypto_ecc_curve_type_t curve_type;
otcrypto_unblinded_key_t public_key;
p256_point_t pub_p256;
p384_point_t pub_p384;
p256_masked_scalar_t private_key_masked_p256;
p384_masked_scalar_t private_key_masked_p384;

otcrypto_key_config_t key_config = {
.version = kOtcryptoLibVersion1,
Expand All @@ -43,7 +48,7 @@ status_t handle_ecdh(ujson_t *uj) {
uint32_t *private_key_masked_raw;
uint32_t private_keyblob_length;
switch (uj_curve) {
case kCryptotestEcdhCurveP256:
case kCryptotestEcdhCurveP256: {
curve_type = kOtcryptoEccCurveTypeNistP256;
memset(pub_p256.x, 0, kP256CoordWords * 4);
memcpy(pub_p256.x, uj_qx.coordinate, uj_qx.coordinate_len);
Expand All @@ -54,14 +59,37 @@ status_t handle_ecdh(ujson_t *uj) {
public_key.key = (uint32_t *)&pub_p256;
key_config.key_length = P256_KEY_BYTES;
shared_key_words = P256_KEY_BYTES / sizeof(uint32_t);
p256_masked_scalar_t private_key_masked;
memset(private_key_masked.share0, 0, kP256MaskedScalarShareBytes);
memcpy(private_key_masked.share0, uj_private_key.d0, kP256ScalarBytes);
memset(private_key_masked.share1, 0, kP256MaskedScalarShareBytes);
memcpy(private_key_masked.share1, uj_private_key.d1, kP256ScalarBytes);
private_key_masked_raw = (uint32_t *)&private_key_masked;
private_keyblob_length = sizeof(private_key_masked);
memset(private_key_masked_p256.share0, 0, kP256MaskedScalarShareBytes);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to write a function that takes the same arguments as memset but that fills the buffer with random data instead of 0s?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, and in fact we already have one:

void hardened_memshred(uint32_t *dest, size_t word_len);

It's slightly different than memset because it only works with aligned pointers, but it's good practice to handle secret values in words rather than bytes anyway.

memcpy(private_key_masked_p256.share0, uj_private_key.d0,
kP256ScalarBytes);
memset(private_key_masked_p256.share1, 0, kP256MaskedScalarShareBytes);
memcpy(private_key_masked_p256.share1, uj_private_key.d1,
kP256ScalarBytes);
private_key_masked_raw = (uint32_t *)&private_key_masked_p256;
private_keyblob_length = sizeof(private_key_masked_p256);
break;
}
case kCryptotestEcdhCurveP384: {
curve_type = kOtcryptoEccCurveTypeNistP384;
memset(pub_p384.x, 0, kP384CoordWords * 4);
memcpy(pub_p384.x, uj_qx.coordinate, uj_qx.coordinate_len);
memset(pub_p384.y, 0, kP384CoordWords * 4);
memcpy(pub_p384.y, uj_qy.coordinate, uj_qy.coordinate_len);
public_key.key_mode = kOtcryptoKeyModeEcdh;
public_key.key_length = sizeof(p384_point_t);
public_key.key = (uint32_t *)&pub_p384;
key_config.key_length = P384_KEY_BYTES;
shared_key_words = P384_KEY_BYTES / sizeof(uint32_t);
memset(private_key_masked_p384.share0, 0, kP384MaskedScalarShareBytes);
memcpy(private_key_masked_p384.share0, uj_private_key.d0,
kP384ScalarBytes);
memset(private_key_masked_p384.share1, 0, kP384MaskedScalarShareBytes);
memcpy(private_key_masked_p384.share1, uj_private_key.d1,
kP384ScalarBytes);
private_key_masked_raw = (uint32_t *)&private_key_masked_p384;
private_keyblob_length = sizeof(private_key_masked_p384);
break;
}
default:
LOG_ERROR("Unsupported ECC curve: %d", uj_curve);
return INVALID_ARGUMENT();
Expand Down
114 changes: 114 additions & 0 deletions sw/device/tests/crypto/cryptotest/firmware/ecdsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/crypto/impl/ecc/p256.h"
#include "sw/device/lib/crypto/impl/ecc/p384.h"
#include "sw/device/lib/crypto/impl/integrity.h"
#include "sw/device/lib/crypto/impl/keyblob.h"
#include "sw/device/lib/crypto/include/datatypes.h"
Expand All @@ -18,6 +19,8 @@
enum {
/* Number of bytes in a P-256 private key. */
kP256PrivateKeyBytes = 256 / 8,
/* Number of bytes in a P-384 private key. */
kP384PrivateKeyBytes = 384 / 8,
};

static const otcrypto_key_config_t kP256PrivateKeyConfig = {
Expand All @@ -28,6 +31,14 @@ static const otcrypto_key_config_t kP256PrivateKeyConfig = {
.security_level = kOtcryptoKeySecurityLevelLow,
};

static const otcrypto_key_config_t kP384PrivateKeyConfig = {
.version = kOtcryptoLibVersion1,
.key_mode = kOtcryptoKeyModeEcdsa,
.key_length = kP384PrivateKeyBytes,
.hw_backed = kHardenedBoolFalse,
.security_level = kOtcryptoKeySecurityLevelLow,
};

int set_nist_p256_params(
cryptotest_ecdsa_coordinate_t uj_qx, cryptotest_ecdsa_coordinate_t uj_qy,
cryptotest_ecdsa_signature_t uj_signature,
Expand Down Expand Up @@ -81,6 +92,59 @@ int set_nist_p256_params(
return true;
}

int set_nist_p384_params(
cryptotest_ecdsa_coordinate_t uj_qx, cryptotest_ecdsa_coordinate_t uj_qy,
cryptotest_ecdsa_signature_t uj_signature,
otcrypto_ecc_curve_type_t *curve_type, otcrypto_unblinded_key_t *public_key,
p384_ecdsa_signature_t *signature_p384, p384_point_t *pub_p384,
otcrypto_word32_buf_t *signature_mut, size_t *digest_len) {
*curve_type = kOtcryptoEccCurveTypeNistP384;
if (uj_qx.coordinate_len > kP384CoordBytes) {
LOG_ERROR(
"Coordinate value qx too large for P384 (have = %d bytes, max = %d "
"bytes)",
uj_qx.coordinate_len, kP384CoordBytes);
return false;
}
if (uj_qy.coordinate_len > kP384CoordBytes) {
LOG_ERROR(
"Coordinate value qy too large for P384 (have = %d bytes, max = %d "
"bytes)",
uj_qy.coordinate_len, kP384CoordBytes);
return false;
}
memset(pub_p384->x, 0, kP384CoordBytes);
memcpy(pub_p384->x, uj_qx.coordinate, uj_qx.coordinate_len);
memset(pub_p384->y, 0, kP384CoordBytes);
memcpy(pub_p384->y, uj_qy.coordinate, uj_qy.coordinate_len);
public_key->key_mode = kOtcryptoKeyModeEcdsa;
public_key->key_length = sizeof(p384_point_t);
public_key->key = (uint32_t *)pub_p384;
*digest_len = kP384ScalarWords;
if (uj_signature.r_len > kP384ScalarBytes) {
LOG_ERROR(
"Signature r value too large for P384 (have = %d bytes, max = %d "
"bytes)",
uj_signature.r_len, kP384ScalarBytes);
return false;
}
if (uj_signature.s_len > kP384ScalarBytes) {
LOG_ERROR(
"Signature s value too large for P384 (have = %d bytes, max = %d "
"bytes)",
uj_signature.s_len, kP384ScalarBytes);
return false;
}
memset(signature_p384->r, 0, kP384ScalarBytes);
memcpy(signature_p384->r, uj_signature.r, uj_signature.r_len);
memset(signature_p384->s, 0, kP384ScalarBytes);
memcpy(signature_p384->s, uj_signature.s, uj_signature.s_len);
signature_mut->len = kP384ScalarWords * 2;
signature_mut->data = (uint32_t *)signature_p384;

return true;
}

status_t interpret_verification_result(ujson_t *uj,
hardened_bool_t *verification_result) {
cryptotest_ecdsa_verify_output_t uj_output;
Expand Down Expand Up @@ -158,6 +222,42 @@ status_t p256_sign(ujson_t *uj, cryptotest_ecdsa_private_key_t *uj_private_key,
return OK_STATUS(0);
}

status_t p384_sign(ujson_t *uj, cryptotest_ecdsa_private_key_t *uj_private_key,
otcrypto_ecc_curve_t elliptic_curve,
otcrypto_hash_digest_t message_digest,
otcrypto_word32_buf_t signature_mut,
cryptotest_ecdsa_signature_t *uj_signature) {
p384_masked_scalar_t private_key_masked;
otcrypto_blinded_key_t private_key = {
.config = kP384PrivateKeyConfig,
.keyblob_length = sizeof(private_key_masked),
.keyblob = (uint32_t *)&private_key_masked,
};
memset(private_key_masked.share0, 0, kP384MaskedScalarShareBytes);
memcpy(private_key_masked.share0, uj_private_key->d0, kP384ScalarBytes);
memset(private_key_masked.share1, 0, kP384MaskedScalarShareBytes);
memcpy(private_key_masked.share1, uj_private_key->d1, kP384ScalarBytes);
private_key.checksum = integrity_blinded_checksum(&private_key);

otcrypto_status_t status = otcrypto_ecdsa_sign(
&private_key, message_digest, &elliptic_curve, signature_mut);
if (status.value != kOtcryptoStatusValueOk) {
return INTERNAL(status.value);
}

memset(uj_signature->r, 0, ECDSA_CMD_MAX_SIGNATURE_SCALAR_BYTES);
memset(uj_signature->s, 0, ECDSA_CMD_MAX_SIGNATURE_SCALAR_BYTES);
p384_ecdsa_signature_t *signature_p384 =
(p384_ecdsa_signature_t *)signature_mut.data;
memcpy(uj_signature->r, signature_p384->r, kP384ScalarBytes);
uj_signature->r_len = kP384ScalarBytes;
memcpy(uj_signature->s, signature_p384->s, kP384ScalarBytes);
uj_signature->s_len = kP384ScalarBytes;
RESP_OK(ujson_serialize_cryptotest_ecdsa_signature_t, uj, uj_signature);

return OK_STATUS(0);
}

status_t handle_ecdsa(ujson_t *uj) {
// Declare ECDSA parameter ujson deserializer types
cryptotest_ecdsa_operation_t uj_op;
Expand Down Expand Up @@ -186,7 +286,9 @@ status_t handle_ecdsa(ujson_t *uj) {
otcrypto_word32_buf_t signature_mut;
int success;
p256_ecdsa_signature_t signature_p256;
p384_ecdsa_signature_t signature_p384;
p256_point_t pub_p256;
p384_point_t pub_p384;
switch (uj_curve) {
case kCryptotestEcdsaCurveP256:
success = set_nist_p256_params(uj_qx, uj_qy, uj_signature, &curve_type,
Expand All @@ -196,6 +298,14 @@ status_t handle_ecdsa(ujson_t *uj) {
return INVALID_ARGUMENT();
}
break;
case kCryptotestEcdsaCurveP384:
success = set_nist_p384_params(uj_qx, uj_qy, uj_signature, &curve_type,
&public_key, &signature_p384, &pub_p384,
&signature_mut, &digest_len);
if (!success) {
return INVALID_ARGUMENT();
}
break;
default:
LOG_ERROR("Unsupported ECC curve: %d", uj_curve);
return INVALID_ARGUMENT();
Expand Down Expand Up @@ -251,6 +361,10 @@ status_t handle_ecdsa(ujson_t *uj) {
return p256_sign(uj, &uj_private_key, elliptic_curve, message_digest,
signature_mut, &uj_signature);
}
case kCryptotestEcdsaCurveP384: {
return p384_sign(uj, &uj_private_key, elliptic_curve, message_digest,
signature_mut, &uj_signature);
}
default:
LOG_ERROR("Unsupported ECC curve: %d", uj_curve);
return INVALID_ARGUMENT();
Expand Down
Loading