From 80d9c1e036d3cbc81b8bacd8eb83dece45c28039 Mon Sep 17 00:00:00 2001 From: Samuel Chiang Date: Tue, 10 Sep 2024 13:18:14 -0700 Subject: [PATCH 1/4] More minor symbols Ruby depends on (#1837) We noticed three missing symbols after testing where we were at with our support for Ruby. These are all pretty minor and are related to work we've already done. * The underlying work for `d2i_ECPKParameters_bio` and `i2d_ECPKParameters_bio` was already completed with 6056999. Coverage for actually parsing is included in that PR, so I've only added brief tests to ensure that the same behavior applies to the BIO methods. * `RAND_egd_bytes` is for querying the entropy gathering daemon EGD on the socket path. We already no-op `RAND_egd` (which directly calls `RAND_egd_bytes` in OpenSSL), so I've applied the same no-op behavior here as well. ### Testing: Minor tests for `d2i_ECPKParameters_bio` and `i2d_ECPKParameters_bio`. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/ec_extra/ec_asn1.c | 63 +++++++++++++++++++++++---------- crypto/fipsmodule/ec/ec_test.cc | 9 +++++ crypto/fipsmodule/ec/internal.h | 5 ++- crypto/rand_extra/rand_extra.c | 4 +++ include/openssl/ec_key.h | 59 ++++++++++++++++++------------ include/openssl/rand.h | 3 ++ 6 files changed, 102 insertions(+), 41 deletions(-) diff --git a/crypto/ec_extra/ec_asn1.c b/crypto/ec_extra/ec_asn1.c index c01aaa08d2..e867a390df 100644 --- a/crypto/ec_extra/ec_asn1.c +++ b/crypto/ec_extra/ec_asn1.c @@ -56,8 +56,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -76,19 +77,15 @@ static const CBS_ASN1_TAG kPublicKeyTag = // acceptable groups, so parsers don't have to pull in all four. typedef const EC_GROUP *(*ec_group_func)(void); static const ec_group_func kAllGroups[] = { - &EC_group_p224, - &EC_group_p256, - &EC_group_p384, - &EC_group_p521, - &EC_group_secp256k1, + &EC_group_p224, &EC_group_p256, &EC_group_p384, + &EC_group_p521, &EC_group_secp256k1, }; EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) { CBS ec_private_key, private_key; uint64_t version; if (!CBS_get_asn1(cbs, &ec_private_key, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1_uint64(&ec_private_key, &version) || - version != 1 || + !CBS_get_asn1_uint64(&ec_private_key, &version) || version != 1 || !CBS_get_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); return NULL; @@ -151,8 +148,7 @@ EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) { !CBS_get_asn1(&child, &public_key, CBS_ASN1_BITSTRING) || // As in a SubjectPublicKeyInfo, the byte-encoded public key is then // encoded as a BIT STRING with bits ordered as in the DER encoding. - !CBS_get_u8(&public_key, &padding) || - padding != 0 || + !CBS_get_u8(&public_key, &padding) || padding != 0 || // Explicitly check |public_key| is non-empty to save the conversion // form later. CBS_len(&public_key) == 0 || @@ -264,16 +260,14 @@ static int parse_explicit_prime_curve(CBS *in, int has_cofactor; uint64_t version; if (!CBS_get_asn1(in, ¶ms, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1_uint64(¶ms, &version) || - version != 1 || + !CBS_get_asn1_uint64(¶ms, &version) || version != 1 || !CBS_get_asn1(¶ms, &field_id, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) || CBS_len(&field_type) != sizeof(kPrimeField) || OPENSSL_memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) != 0 || !CBS_get_asn1(&field_id, &out->prime, CBS_ASN1_INTEGER) || - !CBS_is_unsigned_asn1_integer(&out->prime) || - CBS_len(&field_id) != 0 || + !CBS_is_unsigned_asn1_integer(&out->prime) || CBS_len(&field_id) != 0 || !CBS_get_asn1(¶ms, &curve, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&curve, &out->a, CBS_ASN1_OCTETSTRING) || !CBS_get_asn1(&curve, &out->b, CBS_ASN1_OCTETSTRING) || @@ -292,8 +286,7 @@ static int parse_explicit_prime_curve(CBS *in, if (has_cofactor) { // We only support prime-order curves so the cofactor must be one. - if (CBS_len(&cofactor) != 1 || - CBS_data(&cofactor)[0] != 1) { + if (CBS_len(&cofactor) != 1 || CBS_data(&cofactor)[0] != 1) { OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); return 0; } @@ -546,6 +539,40 @@ int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) { return CBB_finish_i2d(&cbb, outp); } +EC_GROUP *d2i_ECPKParameters_bio(BIO *bio, EC_GROUP **out_group) { + if (bio == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + uint8_t *data; + size_t len; + if (!BIO_read_asn1(bio, &data, &len, INT_MAX)) { + return NULL; + } + const uint8_t *ptr = data; + EC_GROUP *ret = d2i_ECPKParameters(out_group, &ptr, len); + OPENSSL_free(data); + return ret; +} + +int i2d_ECPKParameters_bio(BIO *bio, const EC_GROUP *group) { + if (bio == NULL || group == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + uint8_t *out = NULL; + int len = i2d_ECPKParameters(group, &out); + if (out == NULL) { + return 0; + } + + int ret = BIO_write_all(bio, out, len); + OPENSSL_free(out); + return ret; +} + EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) { EC_KEY *ret = NULL; @@ -599,8 +626,8 @@ size_t EC_get_builtin_curves(EC_builtin_curve *out_curves, } static size_t EC_POINT_point2buf(const EC_GROUP *group, const EC_POINT *point, - point_conversion_form_t form, - uint8_t **pbuf, BN_CTX *ctx) { + point_conversion_form_t form, uint8_t **pbuf, + BN_CTX *ctx) { size_t len; uint8_t *buf; diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc index 20d91a9018..18a58ee49c 100644 --- a/crypto/fipsmodule/ec/ec_test.cc +++ b/crypto/fipsmodule/ec/ec_test.cc @@ -2551,3 +2551,12 @@ TEST(ECTest, ECEngine) { EC_KEY_METHOD_free(eng_funcs); } +TEST(ECTest, ECPKParmatersBio) { + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + + EXPECT_TRUE(i2d_ECPKParameters_bio(bio.get(), EC_group_p256())); + EXPECT_EQ(d2i_ECPKParameters_bio(bio.get(), nullptr), EC_group_p256()); + + EXPECT_TRUE(i2d_ECPKParameters_bio(bio.get(), EC_group_secp256k1())); + EXPECT_EQ(d2i_ECPKParameters_bio(bio.get(), nullptr), EC_group_secp256k1()); +} diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h index 86e7dfb202..70f493238e 100644 --- a/crypto/fipsmodule/ec/internal.h +++ b/crypto/fipsmodule/ec/internal.h @@ -823,7 +823,10 @@ struct ec_key_st { // d2i_ECPKParameters deserializes the |ECPKParameters| specified in RFC 3279 // to an |EC_GROUP| from |inp|. Only deserialization of namedCurves or -// explicitly-encoded versions of namedCurves are supported. +// explicitly-encoded versions of namedCurves are supported. If |*out_group| is +// non-null, the original |*out_group| is freed and the returned |EC_GROUP| is +// also written to |*out_group|. The user continues to maintain the memory +// assigned to |*out_group| if non-null. EC_GROUP *d2i_ECPKParameters(EC_GROUP **out_group, const uint8_t **inp, long len); diff --git a/crypto/rand_extra/rand_extra.c b/crypto/rand_extra/rand_extra.c index 48176e7bf9..65ba63d0b3 100644 --- a/crypto/rand_extra/rand_extra.c +++ b/crypto/rand_extra/rand_extra.c @@ -46,6 +46,10 @@ int RAND_egd(const char *path) { return 255; } +int RAND_egd_bytes(const char *path, int bytes) { + return bytes; +} + int RAND_poll(void) { return 1; } diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h index 3a826ba87a..824c043ac0 100644 --- a/include/openssl/ec_key.h +++ b/include/openssl/ec_key.h @@ -312,6 +312,22 @@ OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, // are supported. OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp); +// d2i_ECPKParameters_bio deserializes the |ECPKParameters| specified in RFC +// 3279 from |bio| and returns the corresponding |EC_GROUP|. If |*out_group| is +// non-null, the original |*out_group| is freed and the returned |EC_GROUP| is +// also written to |*out_group|. The user continues to maintain the memory +// assigned to |*out_group| if non-null. +// +// Only deserialization of namedCurves or +// explicitly-encoded versions of namedCurves are supported. +OPENSSL_EXPORT EC_GROUP *d2i_ECPKParameters_bio(BIO *bio, EC_GROUP **out_group); + +// i2d_ECPKParameters_bio serializes an |EC_GROUP| to |bio| according to the +// |ECPKParameters| specified in RFC 3279. It returns 1 on success and 0 on +// failure. +// Only serialization of namedCurves are supported. +OPENSSL_EXPORT int i2d_ECPKParameters_bio(BIO *bio, const EC_GROUP *group); + // o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into // |*out_key|. Note that this differs from the d2i format in that |*out_key| // must be non-NULL with a group set. On successful exit, |*inp| is advanced by @@ -361,7 +377,8 @@ OPENSSL_EXPORT const EC_KEY_METHOD *EC_KEY_OpenSSL(void); // returned |EC_KEY_METHOD| object will be initialized to the values from // |eckey_meth|. If |eckey_meth| is NULL, the returned object will be // initialized using the value returned from |EC_KEY_get_default_method|. -OPENSSL_EXPORT EC_KEY_METHOD *EC_KEY_METHOD_new(const EC_KEY_METHOD *eckey_meth); +OPENSSL_EXPORT EC_KEY_METHOD *EC_KEY_METHOD_new( + const EC_KEY_METHOD *eckey_meth); // EC_KEY_METHOD_free frees the memory associated with |eckey_meth| OPENSSL_EXPORT void EC_KEY_METHOD_free(EC_KEY_METHOD *eckey_meth); @@ -379,42 +396,40 @@ OPENSSL_EXPORT const EC_KEY_METHOD *EC_KEY_get_method(const EC_KEY *ec); // EC_KEY_METHOD_set_sign_awslc sets the |sign| and |sign_sig| pointers on // |meth|. -OPENSSL_EXPORT void EC_KEY_METHOD_set_sign_awslc(EC_KEY_METHOD *meth, - int (*sign)(int type, const uint8_t *digest, - int digest_len, uint8_t *sig, - unsigned int *siglen, - const BIGNUM *k_inv, - const BIGNUM *r, EC_KEY *eckey), - ECDSA_SIG *(*sign_sig)(const uint8_t *digest, - int digest_len, - const BIGNUM *in_kinv, - const BIGNUM *in_r, - EC_KEY *eckey)); +OPENSSL_EXPORT void EC_KEY_METHOD_set_sign_awslc( + EC_KEY_METHOD *meth, + int (*sign)(int type, const uint8_t *digest, int digest_len, uint8_t *sig, + unsigned int *siglen, const BIGNUM *k_inv, const BIGNUM *r, + EC_KEY *eckey), + ECDSA_SIG *(*sign_sig)(const uint8_t *digest, int digest_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey)); // EC_KEY_METHOD_set_sign sets function pointers on |meth|. AWS-LC currently // supports setting |sign| and |sign_sig|. |sign_setup| must be set to NULL in // order to compile with AWS-LC. -#define EC_KEY_METHOD_set_sign(meth, sign, sign_setup, sign_sig) \ - OPENSSL_STATIC_ASSERT((sign_setup) == NULL, \ - EC_KEY_METHOD_sign_setup_field_must_be_NULL); \ +#define EC_KEY_METHOD_set_sign(meth, sign, sign_setup, sign_sig) \ + OPENSSL_STATIC_ASSERT((sign_setup) == NULL, \ + EC_KEY_METHOD_sign_setup_field_must_be_NULL); \ EC_KEY_METHOD_set_sign_awslc(meth, sign, sign_sig); // EC_KEY_METHOD_set_init_awslc sets the |init| and |finish| pointers on |meth|. OPENSSL_EXPORT void EC_KEY_METHOD_set_init_awslc(EC_KEY_METHOD *meth, - int (*init)(EC_KEY *key), - void (*finish)(EC_KEY *key)); + int (*init)(EC_KEY *key), + void (*finish)(EC_KEY *key)); // EC_KEY_METHOD_set_init sets function pointers on |meth|. AWS-LC // currently only supports setting the |init| and |finish| fields. |copy|, // |set_group|, |set_private|, and |set_public| cannot be set yet and must // be NULL. -#define EC_KEY_METHOD_set_init(meth, init, finish, copy, set_group, \ - set_private, set_public) \ - OPENSSL_STATIC_ASSERT((copy) == NULL && (set_group) == NULL && \ - (set_private) == NULL && (set_public) == NULL, \ - EC_KEY_METHOD_copy_set_group_set_private_and_set_public_fields_must_be_NULL);\ +#define EC_KEY_METHOD_set_init(meth, init, finish, copy, set_group, \ + set_private, set_public) \ + OPENSSL_STATIC_ASSERT( \ + (copy) == NULL && (set_group) == NULL && (set_private) == NULL && \ + (set_public) == NULL, \ + EC_KEY_METHOD_copy_set_group_set_private_and_set_public_fields_must_be_NULL); \ EC_KEY_METHOD_set_init_awslc(meth, init, finish); // EC_KEY_METHOD_set_flags sets |flags| on |meth|. Currently, the only supported diff --git a/include/openssl/rand.h b/include/openssl/rand.h index d317da6016..fddb890f0c 100644 --- a/include/openssl/rand.h +++ b/include/openssl/rand.h @@ -104,6 +104,9 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED void RAND_add(const void *buf, int num, // RAND_egd returns 255. OPENSSL_EXPORT OPENSSL_DEPRECATED int RAND_egd(const char *); +// RAND_egd_bytes returns |bytes|. +OPENSSL_EXPORT OPENSSL_DEPRECATED int RAND_egd_bytes(const char *, int bytes); + // RAND_poll returns one. OPENSSL_EXPORT OPENSSL_DEPRECATED int RAND_poll(void); From 17bb2f27443d975ef8af5f95f294ab1088e55f65 Mon Sep 17 00:00:00 2001 From: Sean McGrail <549813+skmcgrail@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:02:52 +0000 Subject: [PATCH 2/4] ED25519 Power-on Self Test / CAST / KAT (#1834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description of changes: Per IG guidance: >Note10: the ECDSA signature generation and deterministic ECDSA signature generation methods shall each have their own CAST if both are implemented in the approved mode. • for the EdDSA algorithm, o if the module implements digital signature generation, the module shall have an EdDSA digital signature generation CAST. If a KAT is used, the EdDSA digital signature shall be pre- computed, generate an EdDSA digital signature using known data and keys, and then compare the result to the pre-computed value; o if the module implements digital signature verification, the module shall have an EdDSA digital signature verification CAST. If a KAT is used, the EdDSA digital signature shall be pre- computed (which could be the output of the EdDSA digital signature generate test), and using a known key, verify the signature as specified in section 7.7 of FIPS 186-5. This KAT was sourced from the ACVP vectors for SigGen that were validated with the NIST demo server. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/fipsmodule/self_check/self_check.c | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c index cb0659e2d8..26bc2f0928 100644 --- a/crypto/fipsmodule/self_check/self_check.c +++ b/crypto/fipsmodule/self_check/self_check.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1246,6 +1247,52 @@ static int boringssl_self_test_fast(void) { goto err; } + const uint8_t kEd25519PrivateKey[ED25519_PRIVATE_KEY_SEED_LEN] = { + 0xb3, 0x99, 0x05, 0xbf, 0x43, 0x0b, 0x2a, 0xd2, 0x1d, 0xb6, 0x5d, + 0x49, 0xa6, 0xab, 0x03, 0xc1, 0x7d, 0xdb, 0x72, 0xe7, 0xa9, 0x8e, + 0xb9, 0x8f, 0xae, 0x59, 0x91, 0x7a, 0xe2, 0x5f, 0x92, 0x14}; + const uint8_t kEd25519PublicKey[ED25519_PUBLIC_KEY_LEN] = { + 0xe7, 0x75, 0xcf, 0x0e, 0x33, 0x48, 0x52, 0xa7, 0xe6, 0x99, 0xbe, + 0xba, 0x13, 0xbc, 0x24, 0xf8, 0x32, 0xf3, 0xc2, 0xa3, 0xa0, 0x3d, + 0xc9, 0x3c, 0x42, 0xb5, 0x92, 0x76, 0x15, 0xa5, 0x46, 0xba}; + const uint8_t kEd25519Signature[ED25519_SIGNATURE_LEN] = { + 0x30, 0x1a, 0x4c, 0x56, 0xe0, 0x37, 0x0b, 0x57, 0x2f, 0x7d, 0x8c, + 0x75, 0x1b, 0x5c, 0xfa, 0xb6, 0xc3, 0x98, 0x7c, 0x6f, 0x5d, 0xe8, + 0x7c, 0xac, 0x4d, 0x71, 0x16, 0x73, 0xda, 0x8c, 0xb2, 0x19, 0x86, + 0x03, 0xcd, 0x91, 0x82, 0x73, 0xa5, 0x34, 0x24, 0x93, 0xf1, 0xc1, + 0xad, 0x0e, 0x8a, 0x78, 0x45, 0x15, 0xa7, 0xfe, 0xc8, 0xc9, 0xbe, + 0xa2, 0xa3, 0xf1, 0xcf, 0x7b, 0x3a, 0x89, 0x10, 0x0f}; + const uint8_t kEd25519Message[128] = { + 0x13, 0x1d, 0x2a, 0xa9, 0x8f, 0x46, 0xfd, 0x5a, 0xca, 0xef, 0x8e, 0x92, + 0xfa, 0x8c, 0x50, 0xd4, 0x8b, 0xda, 0xdf, 0xfe, 0x13, 0xd7, 0x9c, 0xc7, + 0x1b, 0x95, 0x85, 0x5f, 0xaf, 0xa4, 0x84, 0x66, 0x50, 0x2a, 0x1c, 0x61, + 0x4d, 0xb7, 0x85, 0xfc, 0xc9, 0x4c, 0x50, 0x61, 0x65, 0x23, 0x93, 0x42, + 0xcb, 0x9b, 0x3e, 0xe6, 0x3b, 0x35, 0xdc, 0x2f, 0x7e, 0x78, 0x61, 0x15, + 0x42, 0xc7, 0xa6, 0x1b, 0x50, 0xf3, 0xb6, 0x8e, 0xcf, 0x1b, 0x70, 0xca, + 0xc0, 0x1b, 0x34, 0xef, 0x06, 0x1b, 0x3f, 0x7c, 0xaa, 0xc8, 0x26, 0x56, + 0xbf, 0xd5, 0x5a, 0x06, 0xb8, 0xeb, 0x7d, 0xbe, 0x82, 0x45, 0x17, 0xfe, + 0x3c, 0x56, 0x7d, 0xa5, 0xa0, 0x3e, 0x0b, 0xf2, 0xf1, 0xfe, 0xbb, 0x96, + 0x3c, 0x94, 0x1a, 0xfc, 0x36, 0xe4, 0x5a, 0x5a, 0xc5, 0xe2, 0x71, 0xcd, + 0x99, 0x56, 0xcc, 0xda, 0x0d, 0x62, 0xc8, 0x7c}; + uint8_t ed25519_private_key[ED25519_PRIVATE_KEY_LEN] = {0}; + OPENSSL_memcpy(ed25519_private_key, kEd25519PrivateKey, + ED25519_PRIVATE_KEY_SEED_LEN); + OPENSSL_memcpy(ed25519_private_key + ED25519_PRIVATE_KEY_SEED_LEN, + kEd25519PublicKey, ED25519_PUBLIC_KEY_LEN); + uint8_t ed25519_out_sig[ED25519_SIGNATURE_LEN] = {0}; + if (!ED25519_sign(&ed25519_out_sig[0], &kEd25519Message[0], + sizeof(kEd25519Message), ed25519_private_key) || + !check_test(&kEd25519Signature[0], &ed25519_out_sig[0], + ED25519_SIGNATURE_LEN, "ED25519 sign")) { + fprintf(stderr, "ED25519 sign failed.\n"); + goto err; + } + if (!ED25519_verify(&kEd25519Message[0], sizeof(kEd25519Message), + ed25519_out_sig, kEd25519PublicKey)) { + fprintf(stderr, "ED25519 verify failed.\n"); + goto err; + } + ret = 1; err: From d13df4885b2609cc50d994065358466a0bd27207 Mon Sep 17 00:00:00 2001 From: Sean McGrail <549813+skmcgrail@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:03:12 +0000 Subject: [PATCH 3/4] ACVP ML-KEM testing (#1840) By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- .../acvp/acvptool/subprocess/ml_kem.go | 194 ++++++++++++++++++ .../acvp/acvptool/subprocess/subprocess.go | 1 + .../acvp/acvptool/test/expected/ML-KEM.bz2 | Bin 0 -> 13960 bytes util/fipstools/acvp/acvptool/test/tests.json | 3 +- .../acvp/acvptool/test/vectors/ML-KEM.bz2 | Bin 0 -> 15398 bytes .../acvp/modulewrapper/modulewrapper.cc | 136 +++++++++++- 6 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 util/fipstools/acvp/acvptool/subprocess/ml_kem.go create mode 100644 util/fipstools/acvp/acvptool/test/expected/ML-KEM.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/ML-KEM.bz2 diff --git a/util/fipstools/acvp/acvptool/subprocess/ml_kem.go b/util/fipstools/acvp/acvptool/subprocess/ml_kem.go new file mode 100644 index 0000000000..59d5c4d75f --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/ml_kem.go @@ -0,0 +1,194 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +package subprocess + +import ( + "encoding/json" + "fmt" + "strings" +) + +type mlKem struct{} + +func (*mlKem) Process(vectorSet []byte, m Transactable) (interface{}, error) { + var vs struct { + Mode string `json:"mode"` + TestGroups json.RawMessage `json:"testGroups"` + } + + if err := json.Unmarshal(vectorSet, &vs); err != nil { + return nil, err + } + + switch { + case strings.EqualFold(vs.Mode, "keyGen"): + return processMlKemKeyGen(vs.TestGroups, m) + case strings.EqualFold(vs.Mode, "encapDecap"): + return processMlKemEncapDecap(vs.TestGroups, m) + } + + return nil, fmt.Errorf("unknown ML-KEM mode: %v", vs.Mode) +} + +type mlKemKeyGenTestGroup struct { + ID uint64 `json:"tgId"` + Type string `json:"testType"` + ParameterSet string `json:"parameterSet"` + Tests []struct { + ID uint64 `json:"tcId"` + D hexEncodedByteString `json:"d"` + Z hexEncodedByteString `json:"z"` + } +} + +type mlKemKeyGenTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []mlKemKeyGenTestCaseResponse `json:"tests"` +} + +type mlKemKeyGenTestCaseResponse struct { + ID uint64 `json:"tcId"` + EK hexEncodedByteString `json:"ek"` + DK hexEncodedByteString `json:"dk"` +} + +func processMlKemKeyGen(vectors json.RawMessage, m Transactable) (interface{}, error) { + var groups []mlKemKeyGenTestGroup + + if err := json.Unmarshal(vectors, &groups); err != nil { + return nil, err + } + + var responses []mlKemKeyGenTestGroupResponse + + for _, group := range groups { + if !strings.EqualFold(group.Type, "AFT") { + return nil, fmt.Errorf("unsupported keyGen test type: %v", group.Type) + } + + response := mlKemKeyGenTestGroupResponse{ + ID: group.ID, + } + + for _, test := range group.Tests { + results, err := m.Transact("ML-KEM/"+group.ParameterSet+"/keyGen", 2, test.D, test.Z) + if err != nil { + return nil, err + } + + ek := results[0] + dk := results[1] + + response.Tests = append(response.Tests, mlKemKeyGenTestCaseResponse{ + ID: test.ID, + EK: ek, + DK: dk, + }) + } + + responses = append(responses, response) + } + + return responses, nil +} + +type mlKemEncapDecapTestGroup struct { + ID uint64 `json:"tgId"` + Type string `json:"testType"` + ParameterSet string `json:"parameterSet"` + Function string `json:"function"` + DK hexEncodedByteString `json:"dk"` + Tests []struct { + ID uint64 `json:"tcId"` + EK hexEncodedByteString `json:"ek"` + M hexEncodedByteString `json:"m"` + C hexEncodedByteString `json:"c"` + } +} + +type mlKemEncDecapTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []mlKemEncDecapTestCaseResponse `json:"tests"` +} + +type mlKemEncDecapTestCaseResponse struct { + ID uint64 `json:"tcId"` + C hexEncodedByteString `json:"c,omitempty"` + K hexEncodedByteString `json:"k,omitempty"` +} + +func processMlKemEncapDecap(vectors json.RawMessage, m Transactable) (interface{}, error) { + var groups []mlKemEncapDecapTestGroup + + if err := json.Unmarshal(vectors, &groups); err != nil { + return nil, err + } + + var responses []mlKemEncDecapTestGroupResponse + + for _, group := range groups { + if (strings.EqualFold(group.Function, "encapsulation") && !strings.EqualFold(group.Type, "AFT")) || + (strings.EqualFold(group.Function, "decapsulation") && !strings.EqualFold(group.Type, "VAL")) { + return nil, fmt.Errorf("unsupported encapDecap function and test group type pair: (%v, %v)", group.Function, group.Type) + } + + response := mlKemEncDecapTestGroupResponse{ + ID: group.ID, + } + + for _, test := range group.Tests { + var ( + err error + testResponse mlKemEncDecapTestCaseResponse + ) + + switch { + case strings.EqualFold(group.Function, "encapsulation"): + testResponse, err = processMlKemEncapTestCase(test.ID, group.ParameterSet, test.EK, test.M, m) + case strings.EqualFold(group.Function, "decapsulation"): + testResponse, err = processMlKemDecapTestCase(test.ID, group.ParameterSet, group.DK, test.C, m) + default: + return nil, fmt.Errorf("unknown encDecap function: %v", group.Function) + } + if err != nil { + return nil, err + } + + response.Tests = append(response.Tests, testResponse) + } + + responses = append(responses, response) + } + return responses, nil +} + +func processMlKemEncapTestCase(id uint64, algorithm string, ek []byte, m []byte, t Transactable) (mlKemEncDecapTestCaseResponse, error) { + results, err := t.Transact("ML-KEM/"+algorithm+"/encap", 2, ek, m) + if err != nil { + return mlKemEncDecapTestCaseResponse{}, err + } + + c := results[0] + k := results[1] + + return mlKemEncDecapTestCaseResponse{ + ID: id, + C: c, + K: k, + }, nil +} + +func processMlKemDecapTestCase(id uint64, algorithm string, dk []byte, c []byte, t Transactable) (mlKemEncDecapTestCaseResponse, error) { + results, err := t.Transact("ML-KEM/"+algorithm+"/decap", 1, dk, c) + if err != nil { + return mlKemEncDecapTestCaseResponse{}, err + } + + k := results[0] + + return mlKemEncDecapTestCaseResponse{ + ID: id, + K: k, + }, nil +} diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index b655b4a4ec..2f21c70723 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -153,6 +153,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess "KAS-ECC-SSC": &kas{}, "KAS-FFC-SSC": &kasDH{}, "PBKDF": &pbkdf{}, + "ML-KEM": &mlKem{}, } m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives} diff --git a/util/fipstools/acvp/acvptool/test/expected/ML-KEM.bz2 b/util/fipstools/acvp/acvptool/test/expected/ML-KEM.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..a1c8378cab24752f217f73a75b49d90eb76ac2bc GIT binary patch literal 13960 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 literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index 6aa28a1d70..c8f48bf2f9 100644 --- a/util/fipstools/acvp/acvptool/test/tests.json +++ b/util/fipstools/acvp/acvptool/test/tests.json @@ -31,5 +31,6 @@ {"Wrapper": "modulewrapper", "In": "vectors/TLS-1.2-KDF.bz2", "Out": "expected/TLS-1.2-KDF.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/KDA-HKDF.bz2", "Out": "expected/KDA-HKDF.bz2"}, -{"Wrapper": "modulewrapper", "In": "vectors/KDA-OneStep.bz2", "Out": "expected/KDA-OneStep.bz2"} +{"Wrapper": "modulewrapper", "In": "vectors/KDA-OneStep.bz2", "Out": "expected/KDA-OneStep.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"} ] diff --git a/util/fipstools/acvp/acvptool/test/vectors/ML-KEM.bz2 b/util/fipstools/acvp/acvptool/test/vectors/ML-KEM.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..09da3260915f774545c28690c93e017c7dae7951 GIT binary patch literal 15398 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 literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 59d72e5bdb..4a8c4c5e31 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -12,11 +12,12 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include #include -#include +#include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -732,7 +734,7 @@ static bool GetConfig(const Span args[], }] }] },)" - R"({ + R"({ "sigType": "pss", "properties": [{ "modulo": 2048, @@ -988,7 +990,7 @@ static bool GetConfig(const Span args[], }] }] },)" - R"({ + R"({ "sigType": "pss", "properties": [{ "modulo": 2048, @@ -1307,6 +1309,19 @@ static bool GetConfig(const Span args[], "encoding": ["concatenation"], "z": [{"min": 224, "max": 8192, "increment": 8}], "l": 2048 + },)" + R"({ + "algorithm": "ML-KEM", + "mode": "keyGen", + "revision": "FIPS203", + "parameterSets": ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"] + }, + { + "algorithm": "ML-KEM", + "mode": "encapDecap", + "revision": "FIPS203", + "parameterSets": ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"], + "functions": ["encapsulation", "decapsulation"] } ])"; return write_reply({Span( @@ -2830,6 +2845,112 @@ static bool KBKDF_CTR_HMAC(const Span args[], return write_reply({Span(out)}); } +template +static bool ML_KEM_KEYGEN(const Span args[], + ReplyCallback write_reply) { + const Span d = args[0]; + const Span z = args[1]; + + std::vector seed(d.size() + z.size()); + std::memcpy(seed.data(), d.data(), d.size()); + std::memcpy(seed.data() + d.size(), z.data(), z.size()); + + EVP_PKEY *raw = NULL; + size_t seed_len = 0; + + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr)); + if (!EVP_PKEY_CTX_kem_set_params(ctx.get(), nid) || + !EVP_PKEY_keygen_init(ctx.get()) || + !EVP_PKEY_keygen_deterministic(ctx.get(), &raw, NULL, &seed_len) || + seed_len != seed.size() || + !EVP_PKEY_keygen_deterministic(ctx.get(), &raw, seed.data(), &seed_len)) { + return false; + } + bssl::UniquePtr pkey(raw); + + size_t decaps_key_size = 0; + size_t encaps_key_size = 0; + + if (!EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &decaps_key_size) || + !EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &encaps_key_size)) { + return false; + } + + std::vector decaps_key(decaps_key_size); + std::vector encaps_key(encaps_key_size); + + if (!EVP_PKEY_get_raw_private_key(pkey.get(), decaps_key.data(), + &decaps_key_size) || + !EVP_PKEY_get_raw_public_key(pkey.get(), encaps_key.data(), + &encaps_key_size)) { + return false; + } + + return write_reply({Span(encaps_key.data(), encaps_key_size), + Span(decaps_key.data(), decaps_key_size)}); +} + +template +static bool ML_KEM_ENCAP(const Span args[], + ReplyCallback write_reply) { + const Span ek = args[0]; + const Span m = args[1]; + + bssl::UniquePtr pkey( + EVP_PKEY_kem_new_raw_public_key(nid, ek.data(), ek.size())); + bssl::UniquePtr ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); + + size_t ciphertext_len = 0; + size_t shared_secret_len = 0; + size_t seed_len = 0; + if (!EVP_PKEY_encapsulate_deterministic(ctx.get(), nullptr, &ciphertext_len, + nullptr, &shared_secret_len, nullptr, + &seed_len) || + seed_len != m.size()) { + return false; + } + + std::vector ciphertext(ciphertext_len); + std::vector shared_secret(shared_secret_len); + + if (!EVP_PKEY_encapsulate_deterministic( + ctx.get(), ciphertext.data(), &ciphertext_len, shared_secret.data(), + &shared_secret_len, m.data(), &seed_len)) { + return false; + } + + return write_reply( + {Span(ciphertext.data(), ciphertext_len), + Span(shared_secret.data(), shared_secret_len)}); +} + +template +static bool ML_KEM_DECAP(const Span args[], + ReplyCallback write_reply) { + const Span dk = args[0]; + const Span c = args[1]; + + bssl::UniquePtr pkey( + EVP_PKEY_kem_new_raw_secret_key(nid, dk.data(), dk.size())); + bssl::UniquePtr ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); + + size_t shared_secret_len = 0; + if (!EVP_PKEY_decapsulate(ctx.get(), nullptr, &shared_secret_len, c.data(), + c.size())) { + return false; + } + + std::vector shared_secret(shared_secret_len); + + if (!EVP_PKEY_decapsulate(ctx.get(), shared_secret.data(), &shared_secret_len, + c.data(), c.size())) { + return false; + } + + return write_reply( + {Span(shared_secret.data(), shared_secret_len)}); +} + static struct { char name[kMaxNameLength + 1]; uint8_t num_expected_args; @@ -3064,6 +3185,15 @@ static struct { {"KDF/Counter/HMAC-SHA2-512", 3, KBKDF_CTR_HMAC}, {"KDF/Counter/HMAC-SHA2-512/224", 3, KBKDF_CTR_HMAC}, {"KDF/Counter/HMAC-SHA2-512/256", 3, KBKDF_CTR_HMAC}, + {"ML-KEM/ML-KEM-512/keyGen", 2, ML_KEM_KEYGEN}, + {"ML-KEM/ML-KEM-768/keyGen", 2, ML_KEM_KEYGEN}, + {"ML-KEM/ML-KEM-1024/keyGen", 2, ML_KEM_KEYGEN}, + {"ML-KEM/ML-KEM-512/encap", 2, ML_KEM_ENCAP}, + {"ML-KEM/ML-KEM-768/encap", 2, ML_KEM_ENCAP}, + {"ML-KEM/ML-KEM-1024/encap", 2, ML_KEM_ENCAP}, + {"ML-KEM/ML-KEM-512/decap", 2, ML_KEM_DECAP}, + {"ML-KEM/ML-KEM-768/decap", 2, ML_KEM_DECAP}, + {"ML-KEM/ML-KEM-1024/decap", 2, ML_KEM_DECAP}, }; Handler FindHandler(Span> args) { From 51d9a8d3b3270fc506fb039a1af0c6f3033f37b6 Mon Sep 17 00:00:00 2001 From: Sean McGrail <549813+skmcgrail@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:03:42 +0000 Subject: [PATCH 4/4] ACVP ECDSA SHA3 Digest Testing (#1819) By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- .../acvp/acvptool/subprocess/ecdsa.go | 108 ++++++------------ .../acvp/acvptool/test/expected/ECDSA.bz2 | Bin 439 -> 524 bytes util/fipstools/acvp/acvptool/test/tests.json | 1 + .../acvptool/test/vectors/ECDSA-KeyGen.bz2 | Bin 0 -> 372 bytes .../acvptool/test/vectors/ECDSA-SigGen.bz2 | Bin 3416 -> 6112 bytes .../acvp/acvptool/test/vectors/ECDSA.bz2 | Bin 8485 -> 14928 bytes .../acvp/modulewrapper/modulewrapper.cc | 20 +++- 7 files changed, 52 insertions(+), 77 deletions(-) create mode 100644 util/fipstools/acvp/acvptool/test/vectors/ECDSA-KeyGen.bz2 diff --git a/util/fipstools/acvp/acvptool/subprocess/ecdsa.go b/util/fipstools/acvp/acvptool/subprocess/ecdsa.go index db240bb21f..798716aa49 100644 --- a/util/fipstools/acvp/acvptool/subprocess/ecdsa.go +++ b/util/fipstools/acvp/acvptool/subprocess/ecdsa.go @@ -16,7 +16,6 @@ package subprocess import ( "bytes" - "encoding/hex" "encoding/json" "fmt" ) @@ -36,30 +35,30 @@ type ecdsaTestGroup struct { HashAlgo string `json:"hashAlg,omitEmpty"` ComponentTest bool `json:"componentTest"` Tests []struct { - ID uint64 `json:"tcId"` - QxHex string `json:"qx,omitempty"` - QyHex string `json:"qy,omitempty"` - RHex string `json:"r,omitempty"` - SHex string `json:"s,omitempty"` - MsgHex string `json:"message,omitempty"` + ID uint64 `json:"tcId"` + Qx hexEncodedByteString `json:"qx,omitempty"` + Qy hexEncodedByteString `json:"qy,omitempty"` + R hexEncodedByteString `json:"r,omitempty"` + S hexEncodedByteString `json:"s,omitempty"` + Msg hexEncodedByteString `json:"message,omitempty"` } `json:"tests"` } type ecdsaTestGroupResponse struct { - ID uint64 `json:"tgId"` - Tests []ecdsaTestResponse `json:"tests"` - QxHex string `json:"qx,omitempty"` - QyHex string `json:"qy,omitempty"` + ID uint64 `json:"tgId"` + Tests []ecdsaTestResponse `json:"tests"` + Qx hexEncodedByteString `json:"qx,omitempty"` + Qy hexEncodedByteString `json:"qy,omitempty"` } type ecdsaTestResponse struct { - ID uint64 `json:"tcId"` - DHex string `json:"d,omitempty"` - QxHex string `json:"qx,omitempty"` - QyHex string `json:"qy,omitempty"` - RHex string `json:"r,omitempty"` - SHex string `json:"s,omitempty"` - Passed *bool `json:"testPassed,omitempty"` // using pointer so value is not omitted when it is false + ID uint64 `json:"tcId"` + D hexEncodedByteString `json:"d,omitempty"` + Qx hexEncodedByteString `json:"qx,omitempty"` + Qy hexEncodedByteString `json:"qy,omitempty"` + R hexEncodedByteString `json:"r,omitempty"` + S hexEncodedByteString `json:"s,omitempty"` + Passed *bool `json:"testPassed,omitempty"` // using pointer so value is not omitted when it is false } // ecdsa implements an ACVP algorithm by making requests to the @@ -83,8 +82,6 @@ func (e *ecdsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#name-test-vectors // for details about the tests. for _, group := range parsed.Groups { - group := group - if _, ok := e.curves[group.Curve]; !ok { return nil, fmt.Errorf("curve %q in test group %d not supported", group.Curve, group.ID) } @@ -92,13 +89,10 @@ func (e *ecdsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { response := ecdsaTestGroupResponse{ ID: group.ID, } + var sigGenPrivateKey []byte - var qxHex []byte - var qyHex []byte for _, test := range group.Tests { - test := test - var testResp ecdsaTestResponse switch parsed.Mode { @@ -110,20 +104,12 @@ func (e *ecdsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { if err != nil { return nil, fmt.Errorf("key generation failed for test case %d/%d: %s", group.ID, test.ID, err) } - testResp.DHex = hex.EncodeToString(result[0]) - testResp.QxHex = hex.EncodeToString(result[1]) - testResp.QyHex = hex.EncodeToString(result[2]) + testResp.D = result[0] + testResp.Qx = result[1] + testResp.Qy = result[2] case "keyVer": - qx, err := hex.DecodeString(test.QxHex) - if err != nil { - return nil, fmt.Errorf("failed to decode qx in test case %d/%d: %s", group.ID, test.ID, err) - } - qy, err := hex.DecodeString(test.QyHex) - if err != nil { - return nil, fmt.Errorf("failed to decode qy in test case %d/%d: %s", group.ID, test.ID, err) - } - result, err := m.Transact(e.algo+"/"+"keyVer", 1, []byte(group.Curve), qx, qy) + result, err := m.Transact(e.algo+"/"+"keyVer", 1, []byte(group.Curve), test.Qx, test.Qy) if err != nil { return nil, fmt.Errorf("key verification failed for test case %d/%d: %s", group.ID, test.ID, err) } @@ -154,39 +140,31 @@ func (e *ecdsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { } sigGenPrivateKey = result[0] - qxHex = result[1] - qyHex = result[2] - response.QxHex = hex.EncodeToString(qxHex) - response.QyHex = hex.EncodeToString(qyHex) + response.Qx = result[1] + response.Qy = result[2] } - msg, err := hex.DecodeString(test.MsgHex) - if err != nil { - return nil, fmt.Errorf("failed to decode message hex in test case %d/%d: %s", group.ID, test.ID, err) - } op := e.algo + "/" + "sigGen" if group.ComponentTest { - if len(msg) != h.size { - return nil, fmt.Errorf("test case %d/%d contains message %q of length %d, but expected length %d", group.ID, test.ID, test.MsgHex, len(msg), h.size) + if len(test.Msg) != h.size { + return nil, fmt.Errorf("test case %d/%d contains message %q of length %d, but expected length %d", group.ID, test.ID, test.Msg, len(test.Msg), h.size) } op += "/componentTest" } - result, err := m.Transact(op, 2, []byte(group.Curve), sigGenPrivateKey, []byte(group.HashAlgo), msg) + result, err := m.Transact(op, 2, []byte(group.Curve), sigGenPrivateKey, []byte(group.HashAlgo), test.Msg) if err != nil { return nil, fmt.Errorf("signature generation failed for test case %d/%d: %s", group.ID, test.ID, err) } - rHex := result[0] - sHex := result[1] - testResp.RHex = hex.EncodeToString(rHex) - testResp.SHex = hex.EncodeToString(sHex) + testResp.R = result[0] + testResp.S = result[1] // Ask the subprocess to verify the generated signature for this test case. - ver_result, ver_err := m.Transact(e.algo+"/"+"sigVer", 1, []byte(group.Curve), []byte(group.HashAlgo), msg, qxHex, qyHex, rHex, sHex) + ver_result, ver_err := m.Transact(e.algo+"/"+"sigVer", 1, []byte(group.Curve), []byte(group.HashAlgo), test.Msg, response.Qx, response.Qy, testResp.R, testResp.S) if ver_err != nil { - return nil, fmt.Errorf("After signature generation, signature verification failed for test case %d/%d: %s", group.ID, test.ID, ver_err) + return nil, fmt.Errorf("after signature generation, signature verification failed for test case %d/%d: %s", group.ID, test.ID, ver_err) } // ver_result[0] should be a single byte. The value should be one in this case. if !bytes.Equal(ver_result[0], []byte{01}) { - return nil, fmt.Errorf("After signature generation, signature verification returned unexpected result: %q for test case %d/%d.", ver_result[0], group.ID, test.ID) + return nil, fmt.Errorf("after signature generation, signature verification returned unexpected result: %q for test case %d/%d", ver_result[0], group.ID, test.ID) } case "sigVer": @@ -196,27 +174,7 @@ func (e *ecdsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { return nil, fmt.Errorf("unsupported hash algorithm %q in test group %d", group.HashAlgo, group.ID) } - msg, err := hex.DecodeString(test.MsgHex) - if err != nil { - return nil, fmt.Errorf("failed to decode message hex in test case %d/%d: %s", group.ID, test.ID, err) - } - qx, err := hex.DecodeString(test.QxHex) - if err != nil { - return nil, fmt.Errorf("failed to decode qx in test case %d/%d: %s", group.ID, test.ID, err) - } - qy, err := hex.DecodeString(test.QyHex) - if err != nil { - return nil, fmt.Errorf("failed to decode qy in test case %d/%d: %s", group.ID, test.ID, err) - } - r, err := hex.DecodeString(test.RHex) - if err != nil { - return nil, fmt.Errorf("failed to decode R in test case %d/%d: %s", group.ID, test.ID, err) - } - s, err := hex.DecodeString(test.SHex) - if err != nil { - return nil, fmt.Errorf("failed to decode S in test case %d/%d: %s", group.ID, test.ID, err) - } - result, err := m.Transact(e.algo+"/"+"sigVer", 1, []byte(group.Curve), []byte(group.HashAlgo), msg, qx, qy, r, s) + result, err := m.Transact(e.algo+"/"+"sigVer", 1, []byte(group.Curve), []byte(group.HashAlgo), test.Msg, test.Qx, test.Qy, test.R, test.S) if err != nil { return nil, fmt.Errorf("signature verification failed for test case %d/%d: %s", group.ID, test.ID, err) } diff --git a/util/fipstools/acvp/acvptool/test/expected/ECDSA.bz2 b/util/fipstools/acvp/acvptool/test/expected/ECDSA.bz2 index 0d508a8736a5783a3169b93c07eb1de50371946d..063cf2417dcec7b7626e390f03e896fd23924190 100644 GIT binary patch literal 524 zcmV+n0`vVsT4*^jL0KkKS@2Q!M*s*Me}F_(Kmbq%|L`uLP8u)g-wHqid`1IM8YIO0 zsWmb^BhVw$Ns|*JLnZ{8kW&*>^d^8B0BH398Vm-2&;SOS4FJ#vfTcL`NacpA-&QFefFsbqj0ci_BS_1n8oGk%qZr`ygskK!u$csN~=h>^Jub;i& z_(I`DfVAFsP&0=B2DAVJL4}}L9?;Cg+V2~*-+lg&%QTWxNl=nWNhIniB}ysiK|&FX z)RLvl=Q+jZX^ABli6q3M2}qJ?DisPy?Wc1s_QYm@ynzAI9(?O z5|HNE>IV94Y)$Q(^e{O@(|VreW~>iRrftU6j#Z|)wCQwC2y1FhN!gTASLot$60w3|k{rb4&5t1{s`Lt6PS)zY)%AqkC-MU9FqKtCR>6 zT=P3miG#TO&%%l-#ZgpND-}h2g%qmAMMet&MO0X;ECD%;?w$JU=#VFGr~>wPTYA`d zNd5)n3+Z@Y)GWbo<%S3>L|CL0g0IitC<1wAkbxQ12+SAVi$&k`Y6>Sr8T4Z=MJd;0pk>g3t>*hgUJ9@mk*w?mgazvXXhB#Mg{&Y;BX&3Hva2ME)m%w1FDl{-?Lp6D2}uN!s!1y> z3oOB&DM2`yJteV3?L8S8qR6s3qI1r_qQ@&v2QE7BcZ9qgu#x<<)JIl}0;yu(+ zRuy=LVipucMNwg7aRS;#_e~lVcWedMv8uus3Vs6eg6?jAL|OrG>5&N*5hc4^K(;wi zSn3p@7ScG{+{A*M4mdHT?kO`l%2Ho>aBp-b6}70KQv$94Ul0J90FN;jGXO3kHNHb2 hSs2F|Dwu-fF=5`oTR~v~V2_jjF64@Ep&?Jv$) ziKz7kk5Kf=4FCs}FwoEd02%-Q001h95DDrHq75zKUH#K7wf~9VIAK zNTJbjLhF%%7#n8;dX`d-$JuL`Ux#&2pE4ZT4NPG+qHWKVZ-C7a$Vm#L2PtJ$?&RL6yky5*GOXdmPDS`aVkV-}b0jWJ!n1*zqV>F2u9y{-Qsru?tiJm< S5}?eB{x0N-aG@bzC~|<*522g@ literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/vectors/ECDSA-SigGen.bz2 b/util/fipstools/acvp/acvptool/test/vectors/ECDSA-SigGen.bz2 index 474e3c0849e5ed207a618cc952d953863ccf1de8..ed73c4533cda937df8e44ff2305f5740909934a9 100644 GIT binary patch literal 6112 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 literal 3416 zcmV-e4X5%#T4*^jL0KkKS+d!XkN^>l-+)z6PzV3;KjKabFYn(fU=Tk5cX~YyREnrT zq*6*kg%qu_w!okTD5@R+0x7a+8klKN44N?-007e_2龺yP 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

rY%aQ$I44jne=NMV56eEw^! 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 args[], "SHA2-384", "SHA2-512", "SHA2-512/224", - "SHA2-512/256" + "SHA2-512/256", + "SHA3-224", + "SHA3-256", + "SHA3-384", + "SHA3-512" ] }] }, @@ -613,7 +617,11 @@ static bool GetConfig(const Span args[], "SHA2-384", "SHA2-512", "SHA2-512/224", - "SHA2-512/256" + "SHA2-512/256", + "SHA3-224", + "SHA3-256", + "SHA3-384", + "SHA3-512" ] }] },)" @@ -2287,6 +2295,14 @@ static const EVP_MD *HashFromName(Span name) { return EVP_sha512_224(); } else if (StringEq(name, "SHA2-512/256")) { return EVP_sha512_256(); + } else if (StringEq(name, "SHA3-224")) { + return EVP_sha3_224(); + } else if (StringEq(name, "SHA3-256")) { + return EVP_sha3_256(); + } else if (StringEq(name, "SHA3-384")) { + return EVP_sha3_384(); + } else if (StringEq(name, "SHA3-512")) { + return EVP_sha3_512(); } else if (StringEq(name, "SHAKE-128")) { return EVP_shake128(); } else if (StringEq(name, "SHAKE-256")) {