diff options
author | James Muir <muir.james.a@gmail.com> | 2022-10-15 22:23:39 -0400 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2023-01-13 07:09:09 +0000 |
commit | 836080a89a1f5e45dac4e0df76b9270587f65d5b (patch) | |
tree | 72abd378cbb77d89d85c3d1dcb14c7e92d0653a0 /crypto/ec | |
parent | 9fa553247874728cee8ca0ece9aaed476eb0f303 (diff) |
Support all five EdDSA instances from RFC 8032
Fixes #6277
Description:
Make each of the five EdDSA instances defined in RFC 8032 -- Ed25519,
Ed25519ctx, Ed25519ph, Ed448, Ed448ph -- available via the EVP APIs.
The desired EdDSA instance is specified via an OSSL_PARAM.
All instances, except for Ed25519, allow context strings as input.
Context strings are passed via an OSSL_PARAM. For Ed25519ctx, the
context string must be nonempty.
Ed25519, Ed25519ctx, Ed448 are PureEdDSA instances, which means that
the full message (not a digest) must be passed to sign and verify
operations.
Ed25519ph, Ed448ph are HashEdDSA instances, which means that the input
message is hashed before sign and verify.
Testing:
All 21 test vectors from RFC 8032 have been added to evppkey_ecx.txt
(thanks to Shane Lontis for showing how to do that). Those 21 test
vectors are exercised by evp_test.c and cover all five instances.
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/19705)
Diffstat (limited to 'crypto/ec')
-rw-r--r-- | crypto/ec/curve25519.c | 86 | ||||
-rw-r--r-- | crypto/ec/curve448/curve448_local.h | 11 | ||||
-rw-r--r-- | crypto/ec/curve448/eddsa.c | 50 | ||||
-rw-r--r-- | crypto/ec/ecx_meth.c | 12 |
4 files changed, 100 insertions, 59 deletions
diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c index 286d6bff80..4f033d74d0 100644 --- a/crypto/ec/curve25519.c +++ b/crypto/ec/curve25519.c @@ -5434,9 +5434,47 @@ static void sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b, s[31] = (uint8_t) (s11 >> 17); } +static int hash_init_with_dom(EVP_MD_CTX *hash_ctx, + EVP_MD *sha512, + const uint8_t dom2flag, + const uint8_t phflag, + const uint8_t *context, + const size_t context_len) +{ + /* ASCII: "SigEd25519 no Ed25519 collisions", in hex for EBCDIC compatibility */ + const char dom_s[] = + "\x53\x69\x67\x45\x64\x32\x35\x35\x31\x39\x20\x6e" + "\x6f\x20\x45\x64\x32\x35\x35\x31\x39\x20\x63\x6f" + "\x6c\x6c\x69\x73\x69\x6f\x6e\x73"; + uint8_t dom[2]; + + if (!EVP_DigestInit_ex(hash_ctx, sha512, NULL)) + return 0; + + /* return early if dom2flag is not set */ + if (!dom2flag) + return 1; + + if (context_len > UINT8_MAX) + return 0; + + dom[0] = (uint8_t)(phflag >= 1 ? 1 : 0); + dom[1] = (uint8_t)context_len; + + if (!EVP_DigestUpdate(hash_ctx, dom_s, sizeof(dom_s)-1) + || !EVP_DigestUpdate(hash_ctx, dom, sizeof(dom)) + || !EVP_DigestUpdate(hash_ctx, context, context_len)) { + return 0; + } + + return 1; +} + int -ossl_ed25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, +ossl_ed25519_sign(uint8_t *out_sig, const uint8_t *tbs, size_t tbs_len, const uint8_t public_key[32], const uint8_t private_key[32], + const uint8_t dom2flag, const uint8_t phflag, const uint8_t csflag, + const uint8_t *context, size_t context_len, OSSL_LIB_CTX *libctx, const char *propq) { uint8_t az[SHA512_DIGEST_LENGTH]; @@ -5448,6 +5486,17 @@ ossl_ed25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, unsigned int sz; int res = 0; + if (context == NULL) + context_len = 0; + + /* if csflag is set, then a non-empty context-string is required */ + if (csflag && context_len == 0) + goto err; + + /* if dom2flag is not set, then an empty context-string is required */ + if (!dom2flag && context_len > 0) + goto err; + if (sha512 == NULL || hash_ctx == NULL) goto err; @@ -5460,9 +5509,9 @@ ossl_ed25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, az[31] &= 63; az[31] |= 64; - if (!EVP_DigestInit_ex(hash_ctx, sha512, NULL) + if (!hash_init_with_dom(hash_ctx, sha512, dom2flag, phflag, context, context_len) || !EVP_DigestUpdate(hash_ctx, az + 32, 32) - || !EVP_DigestUpdate(hash_ctx, message, message_len) + || !EVP_DigestUpdate(hash_ctx, tbs, tbs_len) || !EVP_DigestFinal_ex(hash_ctx, nonce, &sz)) goto err; @@ -5470,10 +5519,10 @@ ossl_ed25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, ge_scalarmult_base(&R, nonce); ge_p3_tobytes(out_sig, &R); - if (!EVP_DigestInit_ex(hash_ctx, sha512, NULL) + if (!hash_init_with_dom(hash_ctx, sha512, dom2flag, phflag, context, context_len) || !EVP_DigestUpdate(hash_ctx, out_sig, 32) || !EVP_DigestUpdate(hash_ctx, public_key, 32) - || !EVP_DigestUpdate(hash_ctx, message, message_len) + || !EVP_DigestUpdate(hash_ctx, tbs, tbs_len) || !EVP_DigestFinal_ex(hash_ctx, hram, &sz)) goto err; @@ -5492,8 +5541,10 @@ err: static const char allzeroes[15]; int -ossl_ed25519_verify(const uint8_t *message, size_t message_len, +ossl_ed25519_verify(const uint8_t *tbs, size_t tbs_len, const uint8_t signature[64], const uint8_t public_key[32], + const uint8_t dom2flag, const uint8_t phflag, const uint8_t csflag, + const uint8_t *context, size_t context_len, OSSL_LIB_CTX *libctx, const char *propq) { int i; @@ -5512,6 +5563,17 @@ ossl_ed25519_verify(const uint8_t *message, size_t message_len, 0xDE, 0xF9, 0xDE, 0x14 }; + if (context == NULL) + context_len = 0; + + /* if csflag is set, then a non-empty context-string is required */ + if (csflag && context_len == 0) + return 0; + + /* if dom2flag is not set, then an empty context-string is required */ + if (!dom2flag && context_len > 0) + return 0; + r = signature; s = signature + 32; @@ -5556,10 +5618,10 @@ ossl_ed25519_verify(const uint8_t *message, size_t message_len, if (hash_ctx == NULL) goto err; - if (!EVP_DigestInit_ex(hash_ctx, sha512, NULL) + if (!hash_init_with_dom(hash_ctx, sha512, dom2flag, phflag, context, context_len) || !EVP_DigestUpdate(hash_ctx, r, 32) || !EVP_DigestUpdate(hash_ctx, public_key, 32) - || !EVP_DigestUpdate(hash_ctx, message, message_len) + || !EVP_DigestUpdate(hash_ctx, tbs, tbs_len) || !EVP_DigestFinal_ex(hash_ctx, h, &sz)) goto err; @@ -5570,6 +5632,14 @@ ossl_ed25519_verify(const uint8_t *message, size_t message_len, ge_tobytes(rcheck, &R); res = CRYPTO_memcmp(rcheck, r, sizeof(rcheck)) == 0; + + /* note that we have used the strict verification equation here. + * we checked that ENC( [h](-A) + [s]B ) == r + * B is the base point. + * + * the less strict verification equation uses the curve cofactor: + * [h*8](-A) + [s*8]B == [8]R + */ err: EVP_MD_free(sha512); EVP_MD_CTX_free(hash_ctx); diff --git a/crypto/ec/curve448/curve448_local.h b/crypto/ec/curve448/curve448_local.h index 3410f091a6..f118d851ee 100644 --- a/crypto/ec/curve448/curve448_local.h +++ b/crypto/ec/curve448/curve448_local.h @@ -10,15 +10,4 @@ # define OSSL_CRYPTO_EC_CURVE448_LOCAL_H # include "curve448utils.h" -int -ossl_ed448ph_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t hash[64], - const uint8_t public_key[57], const uint8_t private_key[57], - const uint8_t *context, size_t context_len, const char *propq); - -int -ossl_ed448ph_verify(OSSL_LIB_CTX *ctx, const uint8_t hash[64], - const uint8_t signature[114], const uint8_t public_key[57], - const uint8_t *context, size_t context_len, - const char *propq); - #endif /* OSSL_CRYPTO_EC_CURVE448_LOCAL_H */ diff --git a/crypto/ec/curve448/eddsa.c b/crypto/ec/curve448/eddsa.c index 6648692ff3..cbef27d9bb 100644 --- a/crypto/ec/curve448/eddsa.c +++ b/crypto/ec/curve448/eddsa.c @@ -61,12 +61,8 @@ static c448_error_t hash_init_with_dom(OSSL_LIB_CTX *ctx, EVP_MD_CTX *hashctx, size_t context_len, const char *propq) { -#ifdef CHARSET_EBCDIC - const char dom_s[] = {0x53, 0x69, 0x67, 0x45, - 0x64, 0x34, 0x34, 0x38, 0x00}; -#else - const char dom_s[] = "SigEd448"; -#endif + /* ASCII: "SigEd448", in hex for EBCDIC compatibility */ + const char dom_s[] = "\x53\x69\x67\x45\x64\x34\x34\x38"; uint8_t dom[2]; EVP_MD *shake256 = NULL; @@ -82,7 +78,7 @@ static c448_error_t hash_init_with_dom(OSSL_LIB_CTX *ctx, EVP_MD_CTX *hashctx, return C448_FAILURE; if (!EVP_DigestInit_ex(hashctx, shake256, NULL) - || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s)) + || !EVP_DigestUpdate(hashctx, dom_s, sizeof(dom_s)-1) || !EVP_DigestUpdate(hashctx, dom, sizeof(dom)) || !EVP_DigestUpdate(hashctx, context, context_len)) { EVP_MD_free(shake256); @@ -373,48 +369,30 @@ ossl_c448_ed448_verify_prehash( } int -ossl_ed448_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t *message, - size_t message_len, const uint8_t public_key[57], - const uint8_t private_key[57], const uint8_t *context, - size_t context_len, const char *propq) +ossl_ed448_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, + const uint8_t *message, size_t message_len, + const uint8_t public_key[57], const uint8_t private_key[57], + const uint8_t *context, size_t context_len, + const uint8_t phflag, const char *propq) { return ossl_c448_ed448_sign(ctx, out_sig, private_key, public_key, message, - message_len, 0, context, context_len, + message_len, phflag, context, context_len, propq) == C448_SUCCESS; } int -ossl_ed448_verify(OSSL_LIB_CTX *ctx, const uint8_t *message, size_t message_len, +ossl_ed448_verify(OSSL_LIB_CTX *ctx, + const uint8_t *message, size_t message_len, const uint8_t signature[114], const uint8_t public_key[57], - const uint8_t *context, size_t context_len, const char *propq) + const uint8_t *context, size_t context_len, + const uint8_t phflag, const char *propq) { return ossl_c448_ed448_verify(ctx, signature, public_key, message, - message_len, 0, context, (uint8_t)context_len, + message_len, phflag, context, (uint8_t)context_len, propq) == C448_SUCCESS; } int -ossl_ed448ph_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t hash[64], - const uint8_t public_key[57], const uint8_t private_key[57], - const uint8_t *context, size_t context_len, const char *propq) -{ - return ossl_c448_ed448_sign_prehash(ctx, out_sig, private_key, public_key, - hash, context, context_len, - propq) == C448_SUCCESS; -} - -int -ossl_ed448ph_verify(OSSL_LIB_CTX *ctx, const uint8_t hash[64], - const uint8_t signature[114], const uint8_t public_key[57], - const uint8_t *context, size_t context_len, - const char *propq) -{ - return ossl_c448_ed448_verify_prehash(ctx, signature, public_key, hash, - context, (uint8_t)context_len, - propq) == C448_SUCCESS; -} - -int ossl_ed448_public_from_private(OSSL_LIB_CTX *ctx, uint8_t out_public_key[57], const uint8_t private_key[57], const char *propq) { diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c index e83a2d7172..45531b86a1 100644 --- a/crypto/ec/ecx_meth.c +++ b/crypto/ec/ecx_meth.c @@ -821,8 +821,10 @@ static int pkey_ecd_digestsign25519(EVP_MD_CTX *ctx, unsigned char *sig, return 0; } - if (ossl_ed25519_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey, NULL, - NULL) == 0) + if (ossl_ed25519_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey, + 0, 0, 0, + NULL, 0, + NULL, NULL) == 0) return 0; *siglen = ED25519_SIGSIZE; return 1; @@ -849,7 +851,7 @@ static int pkey_ecd_digestsign448(EVP_MD_CTX *ctx, unsigned char *sig, } if (ossl_ed448_sign(edkey->libctx, sig, tbs, tbslen, edkey->pubkey, - edkey->privkey, NULL, 0, edkey->propq) == 0) + edkey->privkey, NULL, 0, 0, edkey->propq) == 0) return 0; *siglen = ED448_SIGSIZE; return 1; @@ -870,6 +872,8 @@ static int pkey_ecd_digestverify25519(EVP_MD_CTX *ctx, const unsigned char *sig, return 0; return ossl_ed25519_verify(tbs, tbslen, sig, edkey->pubkey, + 0, 0, 0, + NULL, 0, edkey->libctx, edkey->propq); } @@ -888,7 +892,7 @@ static int pkey_ecd_digestverify448(EVP_MD_CTX *ctx, const unsigned char *sig, return 0; return ossl_ed448_verify(edkey->libctx, tbs, tbslen, sig, edkey->pubkey, - NULL, 0, edkey->propq); + NULL, 0, 0, edkey->propq); } static int pkey_ecd_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) |