From 2d956b320c910a90528e9a3aeb4cf48221dba246 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Tue, 31 Mar 2020 17:20:24 +0200 Subject: [PATCH] PROV: Add DERlib support for ECDSA and EC keys This replaces crypto/ec/ecdsa_aid.c with new code and generated OIDs Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/11450) --- crypto/ec/build.info | 2 +- crypto/ec/ecdsa_aid.c | 105 ------------------ providers/common/der/EC.asn1 | 83 ++++++++++++++ providers/common/der/build.info | 9 +- providers/common/der/der_ec.c.in | 67 +++++++++++ providers/common/der/der_ec.h.in | 21 ++++ .../implementations/signature/build.info | 1 + providers/implementations/signature/ecdsa.c | 31 ++++-- 8 files changed, 203 insertions(+), 116 deletions(-) delete mode 100644 crypto/ec/ecdsa_aid.c create mode 100644 providers/common/der/EC.asn1 create mode 100644 providers/common/der/der_ec.c.in create mode 100644 providers/common/der/der_ec.h.in diff --git a/crypto/ec/build.info b/crypto/ec/build.info index 4494ce7a66..8f12e2e39e 100644 --- a/crypto/ec/build.info +++ b/crypto/ec/build.info @@ -51,7 +51,7 @@ $COMMON=ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \ ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c \ curve448/arch_32/f_impl.c curve448/f_generic.c curve448/scalar.c \ curve448/curve448_tables.c curve448/eddsa.c curve448/curve448.c \ - $ECASM ecdsa_aid.c ec_backend.c ecx_backend.c + $ECASM ec_backend.c ecx_backend.c SOURCE[../../libcrypto]=$COMMON ec_ameth.c ec_pmeth.c ecx_meth.c ecx_key.c \ ec_err.c ecdh_kdf.c eck_prn.c ec_evp_lib.c SOURCE[../../providers/libfips.a]=$COMMON diff --git a/crypto/ec/ecdsa_aid.c b/crypto/ec/ecdsa_aid.c deleted file mode 100644 index 01bca40f8c..0000000000 --- a/crypto/ec/ecdsa_aid.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include - -#include -#include "crypto/ec.h" - -#define ASN1_SEQUENCE 0x30 -#define ASN1_OID 0x06 -#define OID_FIRST(a, b) a * 40 + b -#define DER_840() 0x86, 0x48 /* DER encoding of number 840 is 2 bytes */ -#define DER_10045() 0xCE, 0x3D /* DER encoding of number 10045 is 2 bytes */ -#define SHA1_SZ 7 -#define SHA2_SZ 8 -#define SHA3_SZ 9 - -/* - * -- RFC 3279 - * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 10045 } - * id-ecSigType OBJECT IDENTIFIER ::= { ansi-X9-62 signatures(4) } - * - * ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 } - */ -#define ENCODE_ALGORITHMIDENTIFIER_SHA1(name) \ -static const unsigned char algorithmidentifier_##name##_der[] = { \ - ASN1_SEQUENCE, 2 + SHA1_SZ, \ - ASN1_OID, SHA1_SZ, OID_FIRST(1, 2), DER_840(), DER_10045(), 4, 1 \ -} - -/* - * -- RFC 5758 - * - * ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) - * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 } - * - * ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) - * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } - * - * ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) - * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } - * - * ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) - * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } - */ -#define ENCODE_ALGORITHMIDENTIFIER_SHA2(name, n) \ -static const unsigned char algorithmidentifier_##name##_der[] = { \ - ASN1_SEQUENCE, 2 + SHA2_SZ, \ - ASN1_OID, SHA2_SZ, OID_FIRST(1, 2), DER_840(), DER_10045(), 4, 3, n \ -} - -/* - * https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration - * - * sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 } - * - * id-ecdsa-with-sha3-224 ::= { sigAlgs 9 } - * id-ecdsa-with-sha3-256 ::= { sigAlgs 10 } - * id-ecdsa-with-sha3-384 ::= { sigAlgs 11 } - * id-ecdsa-with-sha3-512 ::= { sigAlgs 12 } - */ -#define ENCODE_ALGORITHMIDENTIFIER_SHA3(name, n) \ -static const unsigned char algorithmidentifier_##name##_der[] = { \ - ASN1_SEQUENCE, 2 + SHA3_SZ, \ - ASN1_OID, SHA3_SZ, OID_FIRST(2, 16), DER_840(), 1, 101, 3, 4, 3, n \ -} - -ENCODE_ALGORITHMIDENTIFIER_SHA1(sha1); -ENCODE_ALGORITHMIDENTIFIER_SHA2(sha224, 1); -ENCODE_ALGORITHMIDENTIFIER_SHA2(sha256, 2); -ENCODE_ALGORITHMIDENTIFIER_SHA2(sha384, 3); -ENCODE_ALGORITHMIDENTIFIER_SHA2(sha512, 4); -ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_224, 9); -ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_256, 10); -ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_384, 11); -ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_512, 12); -/* TODO - Add SHAKE OIDS when they are standardized */ - -#define MD_CASE(name) \ - case NID_##name: \ - *len = sizeof(algorithmidentifier_##name##_der); \ - return algorithmidentifier_##name##_der - -const unsigned char *ecdsa_algorithmidentifier_encoding(int md_nid, size_t *len) -{ - switch (md_nid) { - MD_CASE(sha1); - MD_CASE(sha224); - MD_CASE(sha256); - MD_CASE(sha384); - MD_CASE(sha512); - MD_CASE(sha3_224); - MD_CASE(sha3_256); - MD_CASE(sha3_384); - MD_CASE(sha3_512); - default: - return NULL; - } -} diff --git a/providers/common/der/EC.asn1 b/providers/common/der/EC.asn1 new file mode 100644 index 0000000000..d55a69273f --- /dev/null +++ b/providers/common/der/EC.asn1 @@ -0,0 +1,83 @@ +-- ------------------------------------------------------------------- +-- Taken from RFC 3279, 3 ASN.1 Module +-- (https://www.rfc-editor.org/rfc/rfc3279.html#section-3) + +ansi-X9-62 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) 10045 } + +-- Arc for ECDSA signature OIDS + +id-ecSigType OBJECT IDENTIFIER ::= { ansi-X9-62 signatures(4) } + +-- OID for ECDSA signatures with SHA-1 + +ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 } + +id-publicKeyType OBJECT IDENTIFIER ::= { ansi-X9-62 keyType(2) } + +id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 } + +-- Named Elliptic Curves in ANSI X9.62. + +ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) } + +c-TwoCurve OBJECT IDENTIFIER ::= { + ellipticCurve characteristicTwo(0) } + +c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 } +c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 } +c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 } +c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 } +c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 } +c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 } +c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 } +c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 } +c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 } +c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 } +c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 } +c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 } +c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 } +c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 } +c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 } +c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 } +c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 } +c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 } +c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 } +c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 } + +primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) } + +prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 } +prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 } +prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 } +prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 } +prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 } +prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 } +prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 } + +-- ------------------------------------------------------------------- +-- Taken from RFC 5758, 3.2. ECDSA Signature Algorithm +-- (https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2) + +ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 } + +ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } + +ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } + +ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } + +-- ------------------------------------------------------------------- +-- Taken from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration + +sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 } + +id-ecdsa-with-sha3-224 OBJECT IDENTIFIER ::= { sigAlgs 9 } +id-ecdsa-with-sha3-256 OBJECT IDENTIFIER ::= { sigAlgs 10 } +id-ecdsa-with-sha3-384 OBJECT IDENTIFIER ::= { sigAlgs 11 } +id-ecdsa-with-sha3-512 OBJECT IDENTIFIER ::= { sigAlgs 12 } + diff --git a/providers/common/der/build.info b/providers/common/der/build.info index c560a7084d..eda763ea8e 100644 --- a/providers/common/der/build.info +++ b/providers/common/der/build.info @@ -1,4 +1,4 @@ -$FIPSABLE=der_rsa.c der_dsa.c +$FIPSABLE=der_rsa.c der_dsa.c der_ec.c SOURCE[../../libfips.a]=$FIPSABLE SOURCE[../../libnonfips.a]=$FIPSABLE @@ -16,3 +16,10 @@ DEPEND[der_dsa.c]=oids_to_c.pm DEPEND[der_dsa.o]=../include/prov/der_dsa.h GENERATE[../include/prov/der_dsa.h]=der_dsa.h.in DEPEND[../include/prov/der_dsa.h]=oids_to_c.pm + +GENERATE[der_ec.c]=der_ec.c.in +DEPEND[der_ec.c]=oids_to_c.pm + +DEPEND[der_ec.o]=../include/prov/der_ec.h +GENERATE[../include/prov/der_ec.h]=der_ec.h.in +DEPEND[../include/prov/der_ec.h]=oids_to_c.pm diff --git a/providers/common/der/der_ec.c.in b/providers/common/der/der_ec.c.in new file mode 100644 index 0000000000..a617651e4e --- /dev/null +++ b/providers/common/der/der_ec.c.in @@ -0,0 +1,67 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include "prov/der_ec.h" + +/* Well known OIDs precompiled */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/EC.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_C }); +-} + +int DER_w_algorithmIdentifier_EC(WPACKET *pkt, int cont, EC_KEY *ec) +{ + return DER_w_begin_sequence(pkt, cont) + /* No parameters (yet?) */ + && DER_w_precompiled(pkt, -1, der_oid_id_ecPublicKey, + sizeof(der_oid_id_ecPublicKey)) + && DER_w_end_sequence(pkt, cont); +} + +/* Aliases so we can have a uniform MD_CASE */ +#define der_oid_id_ecdsa_with_sha1 der_oid_ecdsa_with_SHA1 +#define der_oid_id_ecdsa_with_sha224 der_oid_ecdsa_with_SHA224 +#define der_oid_id_ecdsa_with_sha256 der_oid_ecdsa_with_SHA256 +#define der_oid_id_ecdsa_with_sha384 der_oid_ecdsa_with_SHA384 +#define der_oid_id_ecdsa_with_sha512 der_oid_ecdsa_with_SHA512 + +#define MD_CASE(name) \ + case NID_##name: \ + precompiled = der_oid_id_ecdsa_with_##name; \ + precompiled_sz = sizeof(der_oid_id_ecdsa_with_##name); \ + break; + +int DER_w_algorithmIdentifier_ECDSA_with(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + + switch (mdnid) { + MD_CASE(sha1); + MD_CASE(sha224); + MD_CASE(sha256); + MD_CASE(sha384); + MD_CASE(sha512); + MD_CASE(sha3_224); + MD_CASE(sha3_256); + MD_CASE(sha3_384); + MD_CASE(sha3_512); + default: + return 0; + } + + return DER_w_begin_sequence(pkt, cont) + /* No parameters (yet?) */ + && DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) + && DER_w_end_sequence(pkt, cont); +} diff --git a/providers/common/der/der_ec.h.in b/providers/common/der/der_ec.h.in new file mode 100644 index 0000000000..24f153cd8f --- /dev/null +++ b/providers/common/der/der_ec.h.in @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/der.h" + +/* Well known OIDs precompiled */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/EC.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_H }); +-} + +int DER_w_algorithmIdentifier_EC(WPACKET *pkt, int cont, EC_KEY *ec); +int DER_w_algorithmIdentifier_ECDSA_with(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info index c53673409f..dbe0876a0e 100644 --- a/providers/implementations/signature/build.info +++ b/providers/implementations/signature/build.info @@ -19,3 +19,4 @@ SOURCE[../../libnonfips.a]=rsa.c DEPEND[rsa.o]=../../common/include/prov/der_rsa.h DEPEND[dsa.o]=../../common/include/prov/der_dsa.h +DEPEND[ecdsa.o]=../../common/include/prov/der_ec.h diff --git a/providers/implementations/signature/ecdsa.c b/providers/implementations/signature/ecdsa.c index 733c0a23a5..e05830f500 100644 --- a/providers/implementations/signature/ecdsa.c +++ b/providers/implementations/signature/ecdsa.c @@ -23,10 +23,12 @@ #include #include "internal/nelem.h" #include "internal/sizes.h" +#include "internal/cryptlib.h" #include "prov/providercommonerr.h" #include "prov/implementations.h" #include "prov/provider_ctx.h" #include "crypto/ec.h" +#include "prov/der_ec.h" static OSSL_OP_signature_newctx_fn ecdsa_newctx; static OSSL_OP_signature_sign_init_fn ecdsa_signature_init; @@ -62,7 +64,8 @@ typedef struct { char mdname[OSSL_MAX_NAME_SIZE]; /* The Algorithm Identifier of the combined signature algorithm */ - unsigned char aid[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; size_t aid_len; size_t mdsize; @@ -203,8 +206,8 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname, const char *props, void *ec) { PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; - size_t algorithmidentifier_len = 0; - const unsigned char *algorithmidentifier; + int md_nid = NID_undef; + WPACKET pkt; free_md(ctx); @@ -212,10 +215,7 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname, return 0; ctx->md = EVP_MD_fetch(ctx->libctx, mdname, props); - algorithmidentifier = - ecdsa_algorithmidentifier_encoding(get_md_nid(ctx->md), - &algorithmidentifier_len); - if (algorithmidentifier == NULL) + if ((md_nid = get_md_nid(ctx->md)) == NID_undef) goto error; ctx->mdsize = EVP_MD_size(ctx->md); @@ -223,8 +223,21 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname, if (ctx->mdctx == NULL) goto error; - memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len); - ctx->aid_len = algorithmidentifier_len; + /* + * TODO(3.0) Should we care about DER writing errors? + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) + && DER_w_algorithmIdentifier_ECDSA_with(&pkt, -1, ctx->ec, md_nid) + && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); if (!EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL)) goto error; -- 2.25.1