JCA design for RFC 7748
Xuelei Fan
xuelei.fan at oracle.com
Fri Aug 11 05:01:22 UTC 2017
On 8/10/2017 6:46 PM, Michael StJohns wrote:
> On 8/10/2017 7:36 PM, Xuelei Fan wrote:
>> Hi Michael,
>>
>> Good points! See comments inlines.
>>
>> On 8/10/2017 3:20 PM, Michael StJohns wrote:
>>>
>>> Instead of converting, I was thinking about mapping. E.g. Montgomery
>>> A and B matches the A and B of the curve. But the "x" of the
>>> Montgomery point is just the "x" of the ECPoint with the "y" left as
>>> null. For Edwards, it looks like you would map "d" to A. For [3] I'd
>>> map "r" to A. I'd leave B as null for both- no reason to throw an
>>> unsupported exception as the code generally has a clue about what
>>> types of keys they're dealing with (or we provide a marker so they
>>> can figure it out).
>>>
>>> The conversion in and out for points is a conversion from little
>>> endian to big endian and vice versa, but that only has to be done if
>>> you're importing or exporting a parameter set and that's an
>>> implementation issue not an API issue.
>>>
>>> Basically, all the math is BigIntegers under the hood. The
>>> curve25519 RFC specifies an implementation that's little endian, but
>>> the actual math is just math and things like the public key is really
>>> just a BigInteger.
>>>
>>> Old code would just continue to work - since it would not be using
>>> the new curves. New code would have to look for the curve type
>>> marker (e.g. the ECField) if there was the possibility of confusion.
>>>
>> I understand your points. The mapping may be confusing to application
>> developers, but no problem for new codes if following the new coding
>> guideline. I'm not very sure of the old code, for similar reason to
>> use the converting solution.
>>
>> For example, an Edwards curve form of the SubjectPublicKeyInfo field
>> in a X.509 cert is parsed as X509EncodedKeySpec, and "EC" KeyFactory
>> is used to generate the ECPublicKey. The algorithm name of the
>> ECPublicKey instance is "EC", and the parameter is an instance of
>> ECParameterSpec. Somehow, the ECPublicKey leave the key generation
>> environment, and the curve OID is unknown in the new environment. Then
>> the public could be used improperly. In the past, it's fine as the
>> only supported form is Weierstrass form, there is no need to tell the
>> curve forms in a crypto implementation. However, when a new form is
>> introduces, identify the EC form of a key is an essential part for the
>> following crypto operations. Old providers or codes may not be able to
>> tell the form, as may result in compatibility issues.
>
> I don't think any of this is an issue. An X509EncodedKeySpec for
> either type of key has a id-ecPublicKey OID identifying it (embedded in
> the SubjectPublicKeyInfo encoding). In the key body, there's the
> EcpkParameters structure which is a 'namedCurve' which consists of an
> OID. The curve OIDs for 25519 and 447 are different than any of the
> Weiserstrass keys. When the KeyFactory factory implementation reads
> the byte stream its going to build a JCA ECPublicKey that matches the
> OID AND that's a concrete ECPublicKey class of the key factory provider.
>
> If the factory implementation doesn't understand the oid, then the
> provider throws an error. I forget which one.
> > The concrete class for the ECPublic key is specific to the provider.
> Some providers may support the new key forms, some may not. There's no
> guarantee (and there never has been a guarantee) that an ECPublic key
> from one provider can be used with another provider (e.g. PKCS11
> provider vs a software provider) - you have to convert the key into a
> keyspec and then run the factory method on it.
>
I'm not sure of it. JDK is a multiple providers framework. A key
generated in one provider may work in another provider, as if the
conversion of the key works. It's not rare that the public key is
parsed by one provider, and used in another provider. For some cases,
we don't have conversion problem in the past as the key spec is clear.
But for some other cases, we do have problems. But if a case works in
the past, we don't want to break it; otherwise, it might be a kind of
compatibility issues.
As we discussed, there are multiple forms of EC curves. EC curves form
is an essential part of a EC key for following operation. As if the EC
curves form is unknown, there are potential problems. When a old
provider try to use a new provider generated keys for a new forms,
problems happens. This actually can be avoid if the old provider does
not support this algorithm. The "EC" name is too general to accept new
forms.
> So I don't think there's anything we have to worry about here - no
> violation of the API contract as far as I can tell.
>
> (As a more complete example - consider what happens when you have an F2M
> EC provider and an Fp EC provider both generating public keys and
> encoding them. Neither provider can decode the other's encoded key
> because they don't have the OIDs and the parameter sets).
>
If we define all of the forms at the same time, a provider would follow
the specs, and no compatibility issues. However, if we add something
new later, and if the old one does not compatible with the new one,
compatibility issues come.
For example,
// Provider A supports KeyFactory
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey pubECKey = ... // use the KF above, new form key.
// Provider A and B support "EC" signature, but B has the priority.
// Provider B is an old provider.
Signature sign = Signature.getInstacne("EC"); // Use provider B.
sign.initVerify(pubECkey); // the verification would fail
Suppose provider A and B are all good providers, the code above runs
into problems. The above code works with two old providers, and works
with two new providers, but may not work if mixing old and new
providers. However, it is expected to work as one of the providers
support the required features.
Xuelei
More information about the security-dev
mailing list