Open mpg opened 1 year ago
For reference, we have a single test for SpecifiedECDomain, in test_suite_pkparse
, using tests/data_files/ec_prv.specdom.der
.
The specification for the format can be found in SEC 1, C.2, and is largely quoted in our current source. This spec also defines compressed and uncompressed point formats (2.3.3 and 2.3.4). (Note: we only support prime fields, hence the name of the module ecp: Elliptic Curves over Prime fields.)
General information about ASN.1 and pointers to tools can be found in our documentation.
Examined with openssl asn1parse
, our test file tests/data_files/ec_prv.specdom.der
looks like:
0:d=0 hl=3 l= 211 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :01
6:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:8EA106A78201D7BFC11AF5C9230803DB1EB104E0A4F47FA3AF4A23A785584206
40:d=1 hl=3 l= 133 cons: cont [ 0 ]
43:d=2 hl=3 l= 130 cons: SEQUENCE
46:d=3 hl=2 l= 1 prim: INTEGER :01
49:d=3 hl=2 l= 44 cons: SEQUENCE
51:d=4 hl=2 l= 7 prim: OBJECT :prime-field
60:d=4 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
95:d=3 hl=2 l= 6 cons: SEQUENCE
97:d=4 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:00
100:d=4 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:07
103:d=3 hl=2 l= 33 prim: OCTET STRING [HEX DUMP]:0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
138:d=3 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
173:d=3 hl=2 l= 1 prim: INTEGER :01
176:d=1 hl=2 l= 36 cons: cont [ 1 ]
178:d=2 hl=2 l= 34 prim: BIT STRING
Unless I'm mistaken, the SpecifiedECDomain structure is the SEQUENCE
starting at offset 43. We can see the version identifier :01
then the field specification, with a value matching secp256k1 (warning: different endianness). Then we have the equation constants A == 0
and B == 7
as expected, then the base point G (here in compressed form, as indicated both by the length and the leading byte 0x02
), then the order N
. again with the expected value, and we can ignore the rest.
@tom-daubney-arm I'm thinking a good starting point here would to:
mbedtls_pk_group_id_from_p()
(suggested prototype below);pk_group_from_specified()
);pk_group_from_specified()
);pk_group_id_from_specified()
assert that it's equal to what pk_group_id_from_group()
finds.Suggested prototype:
/* [in] p: pointer to the value of the prime
* [in] len: length of the prime in bytes
* return: the corresponding group ID, or MBEDTLS_ECP_DP_NONE
*/
mbedtls_ecp_group_id mbedtls_pk_group_id_from_p(const unsigned char *p, size_t len);
(Really just a suggestion to clarify my thinking, but feel free to change if it's not convenient or I forgot things.)
Note: I'd suggest starting on top of https://github.com/Mbed-TLS/mbedtls/pull/7861 which will hopefully be merged soon. Otherwise you risk getting stupid conflicts: file contents re-order, internal functions renamed...
Context: ECC keys need to specify the domain parameters, aka curve, aka group, they use. This is most often done by means of a predefined identifier for well-known curves. However, standards also allow an alternative where all the elements that define the curve (type of field, modulus for prime field, coefficients of the curve's equation, base point) are explicitly encoded. This is known as SpecifiedECDomain and we have opt-in support for it with the option
MBEDTLS_PK_PARSE_EC_EXTENDED
. However we do not accept arbitrary parameters, but only explicit encoding of one of the curves we support. (Also, this is only possible for Short Weierstrass curves, newer curves can only be referred to by a predefined identifier.)Currently, our implementation goes as follows:
SpecifiedECDomain
structure into anmbedtls_ecp_group
structure - this ispk_group_from_specified()
.mbedtls_ecp_group
to those we know, and output the ID if found or an error - this ispk_group_id_from_group()
.These two functions are combined in
pk_group_id_from_specified()
which is the only one called by the rest of the code. This task is to refactorpk_group_id_from_specified()
in order to pave the way for supportingMBEDTLS_PK_PARSE_EC_EXTENDED
withoutECP_LIGHT
. (Secondary goals: (1) reduce the amount of parsing by preferring to match inputs against expected values, (2) reduce RAM usage.)The new strategy will be as follows:
SpecifiedECDomain
structure up to the prime P that defines the group. Identify the group ID from that (turns out P is enough to uniquely identify it).When
ECP_LIGHT
is enabled, this will be done by making use of the group data available; when it isn't, group data will be encoded in tables inpkparse.c
- but that will be the next task. This task is only about changing the code structure, still relying onECP_LIGHT
, but keeping the next step in mind while designing the new internal functions.Suggested internal functions:
mbedtls_pk_group_id_from_p
. Input: the length of P in bytes and a const pointer to it (inside the SpecifiedECDomain structure, no copy). Output: either the ID of the matching group, or NONE (in which case the caller propagates an error). Implementation strategy withECP_LIGHT
: iterate on known groups (in a similar way to the currentpk_group_id_from_group()
), serializegrp.P
to a temporary buffer andmemcmp
to the input (or similar).mbedtls_pk_validate_a
. Input: a const pointer to the encodeda
from the input (no copy) (and length), and the group ID that was identified previously. Output: either OK or an error. Implementation strategy withECP_LIGHT
: callmbedtls_ecp-gorup_load()
with the ID passed, serializegrp.A
to a temporary buffer andmemcmp
to the input (or similar).mbedtls_pk_validate_b
,validate_n
: similar tovalidate_a
.mbedtls_pk_validate_g
: similar to the above except G may be either compressed or uncompressed, so we need to check which format it is (the fist by tells it), and serialize in the same format before comparing.Note: the next task will provide implementations of these internal functions that don't depend on
ECP_LIGHT
but use hard-coded tables instead. The top-level functionpk_group_id_from_specified()
will be common to theECP_LIGHT
and!ECP_LIGHT
case: it will do the parsing, in a way similar to the currentpk_group_from_specified()
except instead of populating a temporarygrp
it will call the above functions.Note: this task is purely a refactoring, so it is complete when the existing tests pass and the code structure is as we want it.
Follow-up: #7789 Previous discussion: #7628, https://github.com/Mbed-TLS/mbedtls/issues/6792#issuecomment-1555065647