-
Notifications
You must be signed in to change notification settings - Fork 96
Simplify RSA and EC public key formats #13
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
Conversation
Previously we weren't initializing the freshly allocated ECP keypair when importing private EC keys. This didn't seem to cause problems, at least according to our current test coverage, but it's better to ensure we don't have a partially initialized object by explicitly initializing the keypair.
0ca50fb
to
990d025
Compare
Force push to update commit descriptions. |
990d025
to
693b4c4
Compare
Rebased to add format specification for DH and DSA keys, and remove the request for crypto know-howerage. No implementation updates required for those, as Mbed Crypto doesn't have a PSA-exposed implementation of DH or DSA yet. |
693b4c4
to
1c3c49e
Compare
Rebase to fix memory leak fix (remember to free the imported "their_key") in ECDH. |
1c3c49e
to
990d025
Compare
Rebased and force-pushed an old version of this patchset so @gilles-peskine-arm can post his comments on the patchset he reviewed. Will push back the new version after no more active reviewers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crypto_sizes.h
needs some updates: implementation and documentation of some of thePSA_KEY_EXPORT_xxx
macros.- I haven't reviewed the changes to test data, but they look superficially ok.
@@ -188,65 +188,65 @@ PSA import/export EC secp224r1 key pair: good | |||
depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP224R1_ENABLED | |||
import_export:"6849f97d1066f6997759637c7e3899464cee3ec7ac970653a0be0742":PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP224R1):PSA_ALG_ECDSA_ANY:PSA_KEY_USAGE_EXPORT:224:0:PSA_SUCCESS:1 | |||
|
|||
PSA import/export-public EC secp224r1: good | |||
PSA import/export-public EC secp224r1: good XXX not sure why this was bit string not octet string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something I noticed when reading the ASN.1 and reading SEC 1 (http://www.secg.org/sec1-v2.pdf). We previously were using BIT_STRING
(0x03
) instead of OCTET_STRING
(0x04
) per the standard.
ECPoint ::= OCTET STRING
This might be worth fling an inter-op bug about unless we know some reason using BIT_STRING
is correct. It's not an issue for PSA anymore, since we won't use an ASN.1-formatted key, but is still a potential issue for Mbed TLS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see what you mean. I'm quite confident that there is no interoperability bug since Mbed TLS is able to interact with the other TLS implementations out there. The bug is partly on me for using the name ECPoint
for something that is not what the applicable specifications call ECPoint
, and I would say partly on SEC1 for having confusing language.
RFC 5280 defines SubjectPublicKeyInfo as containing a subjectPublicKey which is always a BIT STRING. The content of this BIT STRING depends on the key type. RFC 3279 defines the content of a subjectPublicKey for some common key types. For an RSA or DSA or DH key, the content of the BIT STRING is an ASN.1 SEQUENCE. For an EC key, SEC 1 §C.3 says (the same language appears in RFC 3279 §2.3.5):
The elliptic curve public key (an ECPoint which is an OCTET STRING) is mapped to a subjectPublicKey (a BIT STRING) as follows: the most significant bit of the OCTET STRING becomes the most significant bit of the BIT STRING, and the least significant bit of the OCTET STRING becomes the least significant bit of the BIT STRING.
What you do here is to take the content of the ECPoint and stuff it into a BIT STRING. You don't stuff the OCTET STRING (04
+ length + content) into the BIT STRING. By coincidence, the content of the BIT STRING happens to start with 04
in all the data we manipulate because that's the prefix for an uncompressed point representation (SEC1 §2.3.3 action 3.3). You can argue that SEC1 is ambiguous, and I'd agree with that, but everybody including the de facto standard openssl stuffs an EC point representation into a BIT STRING and not an ECPoint into a BIT STRING.
I filed a spec bug to go through all uses of “ECPoint” and fix them.
990d025
to
2920c1b
Compare
Rebased to update back to where we were before and additionally improve the Doxygen comments. |
Copy the nice and clear documentation from psa_export_key() as to what implementations are allowed to do regarding key export formats, as the same applies to public keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+ my comments from the previous review
2920c1b
to
936f278
Compare
Rebased to address code review feedback. |
936f278
to
7bc988f
Compare
Rebased to remove XXX observation for ECPoint representation. |
include/psa/crypto.h
Outdated
* of the domain parameters written to \p data is specified in the | ||
* documentation for psa_set_key_domain_parameters(). | ||
* | ||
* \param[out] data On success, the key domain parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle parameter documentation is missing. Similarly for psa_set_key_domain_parameters
.
7bc988f
to
b0ce828
Compare
Rebased to remove DH and DSA work, which has been raised in PR #14 instead. |
* `q` for a curve over `F_q`. The representation consists of: | ||
* - The byte 0x04; | ||
* - `x_P` as a `ceiling(m/8)`-byte string, big-endian; | ||
* - `y_P` as a `ceiling(m/8)`-byte string, big-endian. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't specify what implementations should/can do about the y
coordinate in the case of PSA_ECC_CURVE_CURVE25519
and PSA_ECC_CURVE_CURVE448
. Do we want to? I would assume that implementations simply ignore it, but are they allowed to omit it? Do we want to prescribe what is allowed if there is a parsing error on y
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would we do with y
if we had it? If we don't imagine we or any other implementations would have a use for it, we shouldn't require it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some implementations might want to require it to be a specific value for robustness.
But I just realised that Montgomery curves are out of scope for 1.0:
https://github.com/ARMmbed/psa-crypto/issues/101
So we could perhaps make it explicit that Montgomery and Edwards curves are not supported yet.
@gilles-peskine-arm what would be the best way to resolve the ambiguity here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's in scope for 1.0, but not for 1.0beta1. I think the 1.0 specification should define the format for Montgomery curves (and the reference implementation should support ECDH) and for Edwards curves (even if the reference implementation doesn't support them yet).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case I suggest we define the format according to RFC8032 and RFC7748. (That is x
coordinate in little endian byte order in the case of Montgomery and y
coordinate in little endian byte order, with the most significant bit of the last byte set to the least significant bit of x
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not changing format in this PR. Agreeing on a format is tracked in ARMmbed/psa-crypto#101
include/psa/crypto.h
Outdated
* `private_key_type` is the type of `private_key`. | ||
* For example, for EC keys, this means that peer_key | ||
* is interpreted as a point on the curve that the | ||
* private key is on. The standard formats for public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"private key is on." -> "private key is associated with."
(The private key is an integer it is not a point it is not on any curve.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
include/psa/crypto.h
Outdated
* ``` | ||
* - For elliptic curve public keys (key types for which | ||
* #PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY is true), the format is the uncompressed | ||
* representation defined by SEC1 §2.3.3 as the content of an ECPoint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: The reading flow is slightly interrupted here because it's not clear that you'll go on explaining the format. I think using a colon :
instead of a full stop .
after ... of an ECPoint
would help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a colon
include/psa/crypto.h
Outdated
* \param[in] peer_key Public key of the peer. The peer key must be in the | ||
* same format that psa_import_key() accepts for the | ||
* public key type corresponding to the type of | ||
* private_key. That is, this function performs the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Use \p
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
include/psa/crypto.h
Outdated
* `psa_import_key(internal_public_key_handle, | ||
* PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(private_key_type), | ||
* peer_key, peer_key_length)` where | ||
* `private_key_type` is the type of `private_key`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Use \p private_key
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
include/psa/crypto.h
Outdated
* PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(private_key_type), | ||
* peer_key, peer_key_length)` where | ||
* `private_key_type` is the type of `private_key`. | ||
* For example, for EC keys, this means that peer_key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Use \p peer_key
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
* keys are documented in the documentation of | ||
* psa_export_public_key(). | ||
* \param peer_key_length Size of \p peer_key in bytes. | ||
* \param alg The key agreement algorithm to compute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Very) minor: "algorithm to compute" sounds wrong, but that might just be me as a non-native. What about "The key agreement algorithm to use."?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That formulation is from me. It's copied from psa_key_derivation
and will move to psa_key_derivation_setup
in https://github.com/ARMmbed/mbedtls-psa/pull/244 . I'm not fond of “use” because it is very generic. “Algorithm to perform”? What do you think @Patater ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, algorithm to compute sounds like you are computing an algorithm. That's second order. Can't have computers programming themselves...
"Algorithm to follow" sounds OK to me.
* supports non-byte-aligned key sizes, but not well. For example, | ||
* mbedtls_rsa_get_len() returns the key size in bytes, not in bits. */ | ||
bits = PSA_BYTES_TO_BITS( mbedtls_rsa_get_len( rsa ) ); | ||
if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you also want to apply a lower bound on the number of bits in the RSA modulus?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment we're applying an upper bound in PSA to limit the amount of memory and CPU time that an operation might use. A lower bound would come from a security policy, and we don't have a minimum-key-size security policy. I'd prefer to do nothing in the PSA code for now and only follow Mbed TLS, but this isn't workable here since Mbed TLS allows unrealistiaclly large RSA key sizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No change planned here for this PR
} | ||
|
||
/* On success, store the content of the object in the RSA context. */ | ||
*p_rsa = rsa; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Strictly speaking, this violates the PK API because it is assumed that apart from the RSA context within the PK context, there is no other structure worth freeing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mbedtls_pk_context
is defined in pk.h
, not pk_internal.h
, and its fields are documented. So this assumption is validate by the documentation of pk.h
, even if we might wish that the type was more opaque.
goto exit; | ||
/* Load the public value. */ | ||
status = mbedtls_to_psa_error( | ||
mbedtls_ecp_point_read_binary( &ecp->grp, &ecp->Q, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mbedtls_ecp_point_read_binary()
supports the 1-Byte representation { 0x00 }
of the point of infinity, but as far as I see it's not documented above. If we don't want to accept the point at infinity here, we should rule it out by e.g. checking data_length
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this later get rejected during mbedtls_ecp_check_pubkey
?
|
||
/* Check that the point is on the curve. */ | ||
status = mbedtls_to_psa_error( | ||
mbedtls_ecp_check_pubkey( &ecp->grp, &ecp->Q ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ok, this would fail for the point at infinity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, OK.
Remove pkcs-1 and rsaEncryption front matter from RSA public keys. Move code that was shared between RSA and other key types (like EC keys) to be used only with non-RSA keys.
Use the PSA-native status type in psa_key_agreement_ecdh() in preparation for us calling PSA functions (and not just Mbed TLS functions) and still being able to return a psa_status_t (without having to translate it to a Mbed TLS error and then back again).
8afbff8
to
bc1759c
Compare
Rebased to update macros and documentation in |
Remove front matter from our EC key format, to make it just the contents of an ECPoint as defined by SEC1 section 2.3.3. As a consequence of the simplification, remove the restriction on not being able to use an ECDH key with ECDSA. There is no longer any OID specified when importing a key, so we can't reject importing of an ECDH key for the purpose of ECDSA based on the OID.
Move pk-using code to inside psa_import_rsa_key(). This aligns the shape of psa_import_rsa_key() to match that of psa_import_ec_private_key() and psa_import_ec_public_key().
Remove extra status handling code from psa_import_key_into_slot(). This helps save a tiny amount of code space, but mainly serves to improve the readability of the code.
Document `peer_key` parameter requirements, including an explanation of how the peer key is used and an example for EC keys.
bc1759c
to
21fec0c
Compare
Rebased to remove stale reference to ECPoint in |
Out of scope of this PR: