JCA design for RFC 7748

classic Classic list List threaded Threaded
40 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

JCA design for RFC 7748

Adam Petcher
I'm working on the Java implementation of RFC 7748 (Diffie-Hellman with
X25519 and X448). I know some of you have been anxious to talk about how
this would fit into JCA, and I appreciate your patience while I learned
enough about JCA and existing crypto implementations to develop this API
proposal. This API/design proposal is for RFC 7748 only, and it does not
include the API for RFC 8032 (EdDSA). Of course, I expect many of the
decisions that we make for RFC 7748 will also impact RFC 8032.

First off, I think it is important to separate RFC 7748 from the
existing ECDH API and implementation. RFC 7748 is a different standard,
it uses different encodings and algorithms, and it has different
properties. Further, this separation will reduce the probability of
programming errors (e.g. accidentally interpreting a Weierstrass point
as an RFC 7748 point). So I propose that we use distinct algorithm names
for RFC 7748, and that we don't use any of the existing EC classes like
EllipticCurve and ECPoint with RFC 7748.

We can achieve this separation without duplicating a lot of code if we
start with some simplifying assumptions. My goal is to remove
functionality that nobody needs in order to simplify the design and API.
If I am simplifying away something that you think you will need, please
let me know.

A) We don't need to expose actual curve parameters over the API. Curves
can be specified using names (e.g. "X25519") or OIDs. The underlying
implementation will likely support arbitrary Montgomery curves, but the
JCA application will only be able to use the supported named curves.
B) We don't need direct interoperability between different providers
using opaque key representations. We can communicate with other
providers using X509/PKCS8 encoding, or by using KeyFactory and key specs.

These two assumptions greatly simplify the API. We won't need classes
that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField,
ECPublicKey, etc. for X25519/X448.

Now that the motivation and assumptions are out of the way, here is a
description of the proposed JCA API:

1) The string "XDH" will be used in getInstance() to refer to all
services related to RFC 7748 (KeyAgreement, KeyFactory,
KeyPairGenerator, etc). This is a departure from the ECDH API that used
"EC" for key generation (shared with ECDSA) and "ECDH" for KeyAgreement,
and makes the RFC 7748 API more like "DiffieHellman" and other
algorithms that use the same name for all services.
2) The new class java.security.spec.NamedParameterSpec (which implements
AlgorithmParameterSpec) will be used to specify curves for RFC 7748.
This class has a single String member which holds the name of the curve
("X25519" or "X448"). This parameter spec class can be reused by other
crypto algorithms that similarly identify parameter sets using names
(e.g. FFDHE3072 in DiffieHellman). This new class can be inserted into
the hierarchy above ECGenParameterSpec.
3) There will be no classes in java.security.spec for EC public keys and
private keys. An RFC 7748 implementation can use the existing classes
X509EncodedKeySpec and PKCS8EncodedKeySpec for public and private key
specs, respectively.
4) There will be no interfaces in java.security.interfaces for RFC 7748
public/private keys. Public/private key implementation classes will
implement java.security.PublicKey and java.security.PrivateKey, which
allows access to their encoded representations.

Here is how the API will be implemented in the SunEC provider:

1) The public key and private key implementation classes will extend
sun.security.ec.X509Key and sun.security.ec.PKCS8Key, respectively. This
is similar to ECPublicKeyImpl and ECPrivateKeyImpl.
2) The KeyFactory for RFC 7748 will support translation to/from opaque
keys and X509EncodedKeySpec/PKCS8EncodedKeySpec.

Example code:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
kpg.initialize(paramSpec); // equivalent to kpg.initialize(255)
KeyPair kp = kpg.generateKeyPair();

KeyFactory kf = KeyFactory.getInstance("XDH");
X509EncodedKeySpec pubSpec = ...
PublicKey pubKey = kf.generatePublic(pubSpec);

KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(kp.getPrivate());
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();


One thing that is missing from the "core" API proposal is a way to
easily produce a public/private key from an encoded numeric value. Of
course, it's possible to put this value into a complete encoded
X509/PKCS8 key, but that is not very convenient. Perhaps we can add
another key spec class (that holds e.g. an AlgorithmParameterSpec and a
byte array) to make this easier, but I don't know how valuable this
would be.

I appreciate any feedback the experts on the mailing list may have for
me. Please let me know what you think.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
On 8/7/2017 4:37 PM, Adam Petcher wrote:
> I'm working on the Java implementation of RFC 7748 (Diffie-Hellman
> with X25519 and X448). I know some of you have been anxious to talk
> about how this would fit into JCA, and I appreciate your patience
> while I learned enough about JCA and existing crypto implementations
> to develop this API proposal. This API/design proposal is for RFC 7748
> only, and it does not include the API for RFC 8032 (EdDSA).

So you're expecting yet another set of APIs to cover those as well?
Rather than one API to cover all of the new curves?  Seems to be a bit
short sighted.

> Of course, I expect many of the decisions that we make for RFC 7748
> will also impact RFC 8032.
>
> First off, I think it is important to separate RFC 7748 from the
> existing ECDH API and implementation. RFC 7748 is a different standard,

It's still an elliptic curve.  Note that there is already a worked
example here - F2m vs Fp curves.

> it uses different encodings and algorithms,

 From a JCA point of view, the public key gets encoded as an
SubjectPublicKeyInfo and the private key gets encoded as a PKCS8 -
that's for lots and lots of compatibility reasons.  The public point of
the public key might be encoded (inside the SPKI) as little endian OCTET
STRING array vs a  big endian ASN1 INTEGER, but its still just an
integer internally.

The algorithms are Key Agreement and Signature - those are at least what
JCA will see them as.  The actual KeyAgreement.getInstance("name") is of
course going to be different than KeyAgreement.getInstance("ECDH") for
example.


> and it has different properties.

Details please?  Or do you mean that you can't use a given type of key
for both key agreement and signature?

> Further, this separation will reduce the probability of programming
> errors (e.g. accidentally interpreting a Weierstrass point as an RFC
> 7748 point).

Um.  What?   It actually won't.

> So I propose that we use distinct algorithm names for RFC 7748,
Yes.

> and that we don't use any of the existing EC classes like
> EllipticCurve and ECPoint with RFC 7748.
No.   (My opinion but...) It's *hard* to add new meta classes for keys.  
Just considering the EC stuff you have ECKey, ECPublicKey, ECPrivateKey,
EllipticCurve, ECPublicKeySpec, ECPrivateKeySpec, ECPoint,
ECParameterSpec, ECGenParameterSpec, EllipticCurve and ECField (with
ECFieldF2M and ECFieldF2P being the differentiator for all of the
various keys within this space).

>
> We can achieve this separation without duplicating a lot of code if we
> start with some simplifying assumptions. My goal is to remove
> functionality that nobody needs in order to simplify the design and
> API. If I am simplifying away something that you think you will need,
> please let me know.

There's a difference with what you do with the public API vs what you do
with the plugin provider.    Throwing away all of the "functionality
that nobody needs" will probably come back to bite those who come later
with something that looks *almost* like what you did, but needs just one
more parameter than you were kind enough to leave behind.

>
> A) We don't need to expose actual curve parameters over the API.
> Curves can be specified using names (e.g. "X25519") or OIDs. The
> underlying implementation will likely support arbitrary Montgomery
> curves, but the JCA application will only be able to use the supported
> named curves.

Strangely, this hasn't turned out all that well.  There needs to be a
name, OID in the public space (primarily for the encodings and PKIX
stuff) and to be honest - you really want the parameters in public space
as well (the ECParameterSpec and its ilk) so that a given key can be
used with different providers or even to play around internally with new
curves before giving them a name.

> B) We don't need direct interoperability between different providers
> using opaque key representations. We can communicate with other
> providers using X509/PKCS8 encoding, or by using KeyFactory and key
> specs.
I don't actually understand that statement.  Keys of different providers
generally don't interoperate anyways, but you can mostly take an
"encoded" one and create a new one in a new provider via the
Keyfactory.  KeySpecs provide you with a way of manually building a key
- and that turns out to be VERY necessary, especially when you're
dealing with adapting hardware modules to the JCA.

>
> These two assumptions greatly simplify the API. We won't need classes
> that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField,
> ECPublicKey, etc. for X25519/X448.

That assumption holds only if your various other assumptions hold. My
opinion is that they probably don't.  (BTW - I'm pretty sure, given that
every single asymmetric JCA crypto api takes a PublicKey or PrivateKey
you're going to need to mirror those classes at least; you'll also need
a ParameterSpec and a GenParameterSpec class with whatever underlying
supporting classes are required to deal with KeyFactory's)

>
> Now that the motivation and assumptions are out of the way, here is a
> description of the proposed JCA API:

I'd suggest getting agreement on the above before proceeding.

Later, Mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Anders Rundgren
On 2017-08-07 23:52, Michael StJohns wrote:
> On 8/7/2017 4:37 PM, Adam Petcher wrote:

>> These two assumptions greatly simplify the API. We won't need classes
>> that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField,
>> ECPublicKey, etc. for X25519/X448.
>
> That assumption holds only if your various other assumptions hold. My
> opinion is that they probably don't.  (BTW - I'm pretty sure, given that
> every single asymmetric JCA crypto api takes a PublicKey or PrivateKey
> you're going to need to mirror those classes at least; you'll also need
> a ParameterSpec and a GenParameterSpec class with whatever underlying
> supporting classes are required to deal with KeyFactory's)

+1

There are virtually tons of third-party encryption libraries out there using a PublicKey
as input argument but internally do things differently depending on if it is an
RSAKey or ECKey.  This is also needed for JSON (JWK) serialization.

Anders
https://github.com/cyberphone/java-cfrg-spec
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
In reply to this post by Michael StJohns
Thanks for the feedback. See below for my responses.

On 8/7/2017 5:52 PM, Michael StJohns wrote:

> On 8/7/2017 4:37 PM, Adam Petcher wrote:
>> I'm working on the Java implementation of RFC 7748 (Diffie-Hellman
>> with X25519 and X448). I know some of you have been anxious to talk
>> about how this would fit into JCA, and I appreciate your patience
>> while I learned enough about JCA and existing crypto implementations
>> to develop this API proposal. This API/design proposal is for RFC
>> 7748 only, and it does not include the API for RFC 8032 (EdDSA).
>
> So you're expecting yet another set of APIs to cover those as well?
> Rather than one API to cover all of the new curves?  Seems to be a bit
> short sighted.

I'm expecting that we don't need to expose curve parameters/points in
the API, so we won't need any new API for EdDSA, other than the
algorithm name. If we decide we need to expose curve parameters, then we
may want to back up and consider how EdDSA fits into this.

>
>> Of course, I expect many of the decisions that we make for RFC 7748
>> will also impact RFC 8032.
>>
>> First off, I think it is important to separate RFC 7748 from the
>> existing ECDH API and implementation. RFC 7748 is a different standard,
>
> It's still an elliptic curve.  Note that there is already a worked
> example here - F2m vs Fp curves.
>
>> it uses different encodings and algorithms,
>
> From a JCA point of view, the public key gets encoded as an
> SubjectPublicKeyInfo and the private key gets encoded as a PKCS8 -
> that's for lots and lots of compatibility reasons.  The public point
> of the public key might be encoded (inside the SPKI) as little endian
> OCTET STRING array vs a  big endian ASN1 INTEGER, but its still just
> an integer internally.
>
> The algorithms are Key Agreement and Signature - those are at least
> what JCA will see them as.  The actual
> KeyAgreement.getInstance("name") is of course going to be different
> than KeyAgreement.getInstance("ECDH") for example.
>
>
>> and it has different properties.
>
> Details please?  Or do you mean that you can't use a given type of key
> for both key agreement and signature?

Specifically, RFC 7748 resists (some) side-channel attacks and
invalid-point attacks. The "ECDH" algorithm in JCA (PKCS#3) does not
have these properties, so I want to make sure programmers don't get them
confused. This difference in security properties partially motivates the
use of a new algorithm name, rather than reusing "ECDH" for RFC 7748.

>
>> Further, this separation will reduce the probability of programming
>> errors (e.g. accidentally interpreting a Weierstrass point as an RFC
>> 7748 point).
>
> Um.  What?   It actually won't.

This is the sort of problem I want to avoid:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
KeyPair kp = kpg.generateKeyPair();
KeyFactory eckf = KeyFactory.getInstance("ECDH");
ECPrivateKeySpec priSpec = eckf.getKeySpec(kf.getPrivate(),
ECPrivateKeySpec.class);

KeyFactory xdhkf = KeyFactory.getInstance("XDH");
PrivateKey xdhPrivate = xdhkf.generatePrivate(priSpec);

// Now use xdhPrivate for key agreement, which uses the wrong algorithm
and curve, and may leak information about the private key

This sort of thing can happen if we use the existing EC spec classes for
RFC 7748 (e.g. redefining what "a" and "b" mean in EllipticCurve when
used with a Montgomery curve, leaving "y" null in ECPoint). Of course,
we can prevent it by tagging these objects and checking the tags to make
sure they are used with the correct algorithms, but I would prefer to
use separate classes (if necessary) and let the type checker do this.

My intention is that errors like the one above are impossible in my
proposed design. We should be able to accomplish this by only using
encoded key specs (which already have checking based on OID), or by
using new classes, if this is necessary (and I hope it is not).

>
>> So I propose that we use distinct algorithm names for RFC 7748,
> Yes.
>
>> and that we don't use any of the existing EC classes like
>> EllipticCurve and ECPoint with RFC 7748.
> No.   (My opinion but...) It's *hard* to add new meta classes for
> keys.  Just considering the EC stuff you have ECKey, ECPublicKey,
> ECPrivateKey, EllipticCurve, ECPublicKeySpec, ECPrivateKeySpec,
> ECPoint, ECParameterSpec, ECGenParameterSpec, EllipticCurve and
> ECField (with ECFieldF2M and ECFieldF2P being the differentiator for
> all of the various keys within this space).
>
>>
>> We can achieve this separation without duplicating a lot of code if
>> we start with some simplifying assumptions. My goal is to remove
>> functionality that nobody needs in order to simplify the design and
>> API. If I am simplifying away something that you think you will need,
>> please let me know.
>
> There's a difference with what you do with the public API vs what you
> do with the plugin provider.    Throwing away all of the
> "functionality that nobody needs" will probably come back to bite
> those who come later with something that looks *almost* like what you
> did, but needs just one more parameter than you were kind enough to
> leave behind.

I agree, but we have to draw the line somewhere, and I think that line
should be determined by the most common use cases. I would prefer to put
in too little, and add more to the API later when people ask for it.
Adding things to the API isn't trivial, but it is much easier than
removing things that we don't need that are complicating the API and
causing problems.

>
>>
>> A) We don't need to expose actual curve parameters over the API.
>> Curves can be specified using names (e.g. "X25519") or OIDs. The
>> underlying implementation will likely support arbitrary Montgomery
>> curves, but the JCA application will only be able to use the
>> supported named curves.
>
> Strangely, this hasn't turned out all that well.  There needs to be a
> name, OID in the public space (primarily for the encodings and PKIX
> stuff) and to be honest - you really want the parameters in public
> space as well (the ECParameterSpec and its ilk) so that a given key
> can be used with different providers or even to play around internally
> with new curves before giving them a name.

I don't understand why we need public curve parameters to allow keys to
be used with different providers. It seems like this should work as long
as the providers all understand the OIDs or curve names. Can you explain
this part a bit more?

Related to tinkering with new curves that don't have a name: I don't
think that this is a feature that JCA needs to have. In the common use
case, the programmer wants to only use standard algorithms and curves,
and I think we should focus on that use case.

>
>> B) We don't need direct interoperability between different providers
>> using opaque key representations. We can communicate with other
>> providers using X509/PKCS8 encoding, or by using KeyFactory and key
>> specs.
> I don't actually understand that statement.  Keys of different
> providers generally don't interoperate anyways, but you can mostly
> take an "encoded" one and create a new one in a new provider via the
> Keyfactory.  KeySpecs provide you with a way of manually building a
> key - and that turns out to be VERY necessary, especially when you're
> dealing with adapting hardware modules to the JCA.

I'll admit that it is a strange statement. The only reason why I stated
this assumption is that ECPublicKey and ECPrivateKey expose a lot of
information that allows direct interoperability with opaque key objects
(that implement these interfaces). I don't know if this is
necessary/valuable, and I don't have any particular desire to allow the
same thing with RFC 7748 keys.

>
>>
>> These two assumptions greatly simplify the API. We won't need classes
>> that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField,
>> ECPublicKey, etc. for X25519/X448.
>
> That assumption holds only if your various other assumptions hold. My
> opinion is that they probably don't.  (BTW - I'm pretty sure, given
> that every single asymmetric JCA crypto api takes a PublicKey or
> PrivateKey you're going to need to mirror those classes at least;
> you'll also need a ParameterSpec and a GenParameterSpec class with
> whatever underlying supporting classes are required to deal with
> KeyFactory's)

I agree with the second part of your parenthetical statement, but I need
more information about the first. It sounds like what you are saying is
that I will need something like XDHPublicKey and XDHPrivateKey in
java.security.interfaces. Can you tell me why? What is it that we can't
do without these interfaces?

>
>>
>> Now that the motivation and assumptions are out of the way, here is a
>> description of the proposed JCA API:
>
> I'd suggest getting agreement on the above before proceeding.
>
> Later, Mike
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Anders Rundgren
On 2017-08-08 17:25, Adam Petcher wrote:

> It sounds like what you are saying is
> that I will need something like XDHPublicKey and XDHPrivateKey in
> java.security.interfaces. Can you tell me why? What is it that we can't
> do without these interfaces?

Every JOSE Java library I have seen constructs and deconstructs RSA and EC keys
based on JWK definitions.  Maybe we don't need XDH keys but it would be nice to
hear what the solution would be without such.

Then there's lot of stuff out there like this which also needs some
explanations on how to enhance with RFC7748 on board:

Object myOwnEncrypt(PublicKey publicKey) throws SecurityException {
    if (publicKey instanceof RSAKey) {
      // RSA
    } else {
      // It should be EC
    }
}

CC:ing the creator of OKP keys.

https://tools.ietf.org/html/rfc8037#section-2

Anders
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
In reply to this post by Adam Petcher
On 8/8/2017 11:25 AM, Adam Petcher wrote:

> Thanks for the feedback. See below for my responses.
>
> On 8/7/2017 5:52 PM, Michael StJohns wrote:
>> On 8/7/2017 4:37 PM, Adam Petcher wrote:
>>> I'm working on the Java implementation of RFC 7748 (Diffie-Hellman
>>> with X25519 and X448). I know some of you have been anxious to talk
>>> about how this would fit into JCA, and I appreciate your patience
>>> while I learned enough about JCA and existing crypto implementations
>>> to develop this API proposal. This API/design proposal is for RFC
>>> 7748 only, and it does not include the API for RFC 8032 (EdDSA).
>>
>> So you're expecting yet another set of APIs to cover those as well?
>> Rather than one API to cover all of the new curves?  Seems to be a
>> bit short sighted.
>
> I'm expecting that we don't need to expose curve parameters/points in
> the API, so we won't need any new API for EdDSA, other than the
> algorithm name. If we decide we need to expose curve parameters, then
> we may want to back up and consider how EdDSA fits into this.

We'll leave this for later.  But generally, the JCA is a general
interface to a set of crypto primitives modeled on just a few key
types.  To go in the direction you want to go it you need to explain why
its impossible to model an elliptic curve as an elliptic curve.   As I
noted, I think that the inclusion of extension of ECField is probably
all that's necessary for representing both public and private key pairs
here.

>>
>>> Of course, I expect many of the decisions that we make for RFC 7748
>>> will also impact RFC 8032.
>>>
>>> First off, I think it is important to separate RFC 7748 from the
>>> existing ECDH API and implementation. RFC 7748 is a different standard,
>>
>> It's still an elliptic curve.  Note that there is already a worked
>> example here - F2m vs Fp curves.
>>
>>> it uses different encodings and algorithms,
>>
>> From a JCA point of view, the public key gets encoded as an
>> SubjectPublicKeyInfo and the private key gets encoded as a PKCS8 -
>> that's for lots and lots of compatibility reasons.  The public point
>> of the public key might be encoded (inside the SPKI) as little endian
>> OCTET STRING array vs a  big endian ASN1 INTEGER, but its still just
>> an integer internally.
>>
>> The algorithms are Key Agreement and Signature - those are at least
>> what JCA will see them as.  The actual
>> KeyAgreement.getInstance("name") is of course going to be different
>> than KeyAgreement.getInstance("ECDH") for example.
>>
>>
>>> and it has different properties.
>>
>> Details please?  Or do you mean that you can't use a given type of
>> key for both key agreement and signature?
>
> Specifically, RFC 7748 resists (some) side-channel attacks and
> invalid-point attacks. The "ECDH" algorithm in JCA (PKCS#3) does not
> have these properties, so I want to make sure programmers don't get
> them confused. This difference in security properties partially
> motivates the use of a new algorithm name, rather than reusing "ECDH"
> for RFC 7748.

There is no problem with using new names for new algorithms - especially
if the math is different.  Ask the java folks to register the names as
Standard Names.  That's what will be used in the
KeyAgreement.getInstance and Signature.getInstance calls.


>
>>
>>> Further, this separation will reduce the probability of programming
>>> errors (e.g. accidentally interpreting a Weierstrass point as an RFC
>>> 7748 point).
>>
>> Um.  What?   It actually won't.
>
> This is the sort of problem I want to avoid:
>
> KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
> KeyPair kp = kpg.generateKeyPair();
> KeyFactory eckf = KeyFactory.getInstance("ECDH");
> ECPrivateKeySpec priSpec = eckf.getKeySpec(kf.getPrivate(),
> ECPrivateKeySpec.class);
>
> KeyFactory xdhkf = KeyFactory.getInstance("XDH");
> PrivateKey xdhPrivate = xdhkf.generatePrivate(priSpec);
>
> // Now use xdhPrivate for key agreement, which uses the wrong
> algorithm and curve, and may leak information about the private key

This is setting up a strawman and knocking it down.  It's already
possible to do the above with any software based key - either directly
or by pulling out the data.  Creating the API as you suggest will still
not prevent this as long as I can retrieve the private value from the key.

If you want absolute protection from this - go to hardware based keys.

>
> This sort of thing can happen if we use the existing EC spec classes
> for RFC 7748 (e.g. redefining what "a" and "b" mean in EllipticCurve
> when used with a Montgomery curve, leaving "y" null in ECPoint). Of
> course, we can prevent it by tagging these objects and checking the
> tags to make sure they are used with the correct algorithms, but I
> would prefer to use separate classes (if necessary) and let the type
> checker do this.
That's the responsibility of the plugin provider - not the public API.

>
> My intention is that errors like the one above are impossible in my
> proposed design.
Nope.  See above.
> We should be able to accomplish this by only using encoded key specs
> (which already have checking based on OID), or by using new classes,
> if this is necessary (and I hope it is not).
Nope.  It doesn't work that way.  Key spec's mostly don't do checking...
the checking is done by the factory classes.

>
>>
>>> So I propose that we use distinct algorithm names for RFC 7748,
>> Yes.
>>
>>> and that we don't use any of the existing EC classes like
>>> EllipticCurve and ECPoint with RFC 7748.
>> No.   (My opinion but...) It's *hard* to add new meta classes for
>> keys.  Just considering the EC stuff you have ECKey, ECPublicKey,
>> ECPrivateKey, EllipticCurve, ECPublicKeySpec, ECPrivateKeySpec,
>> ECPoint, ECParameterSpec, ECGenParameterSpec, EllipticCurve and
>> ECField (with ECFieldF2M and ECFieldF2P being the differentiator for
>> all of the various keys within this space).
>>
>>>
>>> We can achieve this separation without duplicating a lot of code if
>>> we start with some simplifying assumptions. My goal is to remove
>>> functionality that nobody needs in order to simplify the design and
>>> API. If I am simplifying away something that you think you will
>>> need, please let me know.
>>
>> There's a difference with what you do with the public API vs what you
>> do with the plugin provider.    Throwing away all of the
>> "functionality that nobody needs" will probably come back to bite
>> those who come later with something that looks *almost* like what you
>> did, but needs just one more parameter than you were kind enough to
>> leave behind.
>
> I agree, but we have to draw the line somewhere, and I think that line
> should be determined by the most common use cases. I would prefer to
> put in too little, and add more to the API later when people ask for
> it. Adding things to the API isn't trivial, but it is much easier than
> removing things that we don't need that are complicating the API and
> causing problems.

Adding MANY different new APIs because you haven't done the work to
harmonize them seems to be crossing the line substantially.   Not
explaining how

>
>>
>>>
>>> A) We don't need to expose actual curve parameters over the API.
>>> Curves can be specified using names (e.g. "X25519") or OIDs. The
>>> underlying implementation will likely support arbitrary Montgomery
>>> curves, but the JCA application will only be able to use the
>>> supported named curves.
>>
>> Strangely, this hasn't turned out all that well.  There needs to be a
>> name, OID in the public space (primarily for the encodings and PKIX
>> stuff) and to be honest - you really want the parameters in public
>> space as well (the ECParameterSpec and its ilk) so that a given key
>> can be used with different providers or even to play around
>> internally with new curves before giving them a name.
>
> I don't understand why we need public curve parameters to allow keys
> to be used with different providers. It seems like this should work as
> long as the providers all understand the OIDs or curve names. Can you
> explain this part a bit more?
Because names and OIDs get assigned later than the curve parameters.  
There are two parts to the JCA - the general crypto part and then
there's the PKIX part.  For the EC stuff, they sort of overlap because
of a desire not to have to have everyone remember each of the parameter
sets (curves) and those sets are tagged by name(s) and OID.  But its
still  perfectly possible to do EC math on curves that were generated
elsewhere (or even with a curve where everything but the basepoint is
the same with a public curve).

What you need to be able to do is to pass to an "older" provider a
"newer" curve - assuming the curve fits within the math already
implemented.  There's really no good reason to implement a whole new set
of API changes just to permit a single new curve.
>
> Related to tinkering with new curves that don't have a name: I don't
> think that this is a feature that JCA needs to have. In the common use
> case, the programmer wants to only use standard algorithms and curves,
> and I think we should focus on that use case.

The common use case is much wider than you think it is.  I find myself
using the curve parameters much more than I would like - specifically
because I use JCA in conjunction with PKCS11, HSMs and smart cards.   So
no - focusing on a software only subset of things is really not the
right approach.

>
>>
>>> B) We don't need direct interoperability between different providers
>>> using opaque key representations. We can communicate with other
>>> providers using X509/PKCS8 encoding, or by using KeyFactory and key
>>> specs.
>> I don't actually understand that statement.  Keys of different
>> providers generally don't interoperate anyways, but you can mostly
>> take an "encoded" one and create a new one in a new provider via the
>> Keyfactory.  KeySpecs provide you with a way of manually building a
>> key - and that turns out to be VERY necessary, especially when you're
>> dealing with adapting hardware modules to the JCA.
>
> I'll admit that it is a strange statement. The only reason why I
> stated this assumption is that ECPublicKey and ECPrivateKey expose a
> lot of information that allows direct interoperability with opaque key
> objects (that implement these interfaces). I don't know if this is
> necessary/valuable, and I don't have any particular desire to allow
> the same thing with RFC 7748 keys.

*sigh* Both of those classes allow for a full representation of the key
in software.  But the ECPrivateKey allows for the concept of a key
handle that just references a hardware key without making the sensitive
data accessible.  E.g. getS() returns null or an exception (I wish this
were better specified, but much of this is discussed in the JCA guide).

Spec's ALWAYS provide a full non-opaque representation and are a
required part of the JCA for key types.

Key.getEncoded() usually provides a full non-opaque representation (e.g.
SPKI or PKCS8 or just a byte array for SecretKeys)


>
>>
>>>
>>> These two assumptions greatly simplify the API. We won't need
>>> classes that mirror ECParameterSpec, EllipticCurve, ECPoint,
>>> ECField, ECPublicKey, etc. for X25519/X448.
>>
>> That assumption holds only if your various other assumptions hold. My
>> opinion is that they probably don't.  (BTW - I'm pretty sure, given
>> that every single asymmetric JCA crypto api takes a PublicKey or
>> PrivateKey you're going to need to mirror those classes at least;
>> you'll also need a ParameterSpec and a GenParameterSpec class with
>> whatever underlying supporting classes are required to deal with
>> KeyFactory's)
>
> I agree with the second part of your parenthetical statement, but I
> need more information about the first. It sounds like what you are
> saying is that I will need something like XDHPublicKey and
> XDHPrivateKey in java.security.interfaces. Can you tell me why? What
> is it that we can't do without these interfaces?

The method signatures for Signature.initSign(PrivateKey
privateKey[,SecureRandom random]), Signature.initVerify(PublicKey
publicKey) should give you a clue.  E.g. the calls to the JCA provider
classes require that you submit either a PublicKey or a PrivateKey.  So
you're going to need a concrete class with a subinterface that matches
the key type needed by the signature instance that is a sub interface
for PublicKey or PrivateKey.

KeyAgreement requires a "Key" (both the public and private keys are
passed in a Key's).

KeyPairGenerator.init requires an AlgorithmParameter or a key size in bits.

KeyFactory requires a KeySpec.

Basically, you can't sign, perform a key agreement, generate a random
key pair or generate a key from an encoded value without these classes.


It's scary that you asked this question because it implies perhaps a
need to spend a bit more time looking at the JCA and how its structured.


Later, Mike


>
>>
>>>
>>> Now that the motivation and assumptions are out of the way, here is
>>> a description of the proposed JCA API:
>>
>> I'd suggest getting agreement on the above before proceeding.
>>
>> Later, Mike
>>
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
In reply to this post by Anders Rundgren
On 8/8/2017 11:45 AM, Anders Rundgren wrote:

> On 2017-08-08 17:25, Adam Petcher wrote:
>
>> It sounds like what you are saying is
>> that I will need something like XDHPublicKey and XDHPrivateKey in
>> java.security.interfaces. Can you tell me why? What is it that we can't
>> do without these interfaces?
>
> Every JOSE Java library I have seen constructs and deconstructs RSA
> and EC keys
> based on JWK definitions.  Maybe we don't need XDH keys but it would
> be nice to
> hear what the solution would be without such.

Of course, you could get the X.509 or PKCS#8 encoding of the key, and
then convert that to JWK (I think all the information you need is in the
algorithm ID), but that is not a very good solution. So perhaps it would
be helpful to have an interface that exposes the key array along with
its associated algorithm name and parameters. This would be similar to
your OKP interface, but we can make it a bit more general so that it can
be reused by other algorithms. We could also add interfaces for RFC 7748
public keys and private keys, but they wouldn't have any additional
information, and I still don't know if they are needed.

>
> Then there's lot of stuff out there like this which also needs some
> explanations on how to enhance with RFC7748 on board:
>
> Object myOwnEncrypt(PublicKey publicKey) throws SecurityException {
>    if (publicKey instanceof RSAKey) {
>      // RSA
>    } else {
>      // It should be EC
>    }
> }

Like before, there is a (not very good) solution using X.509 encoding,
and a better solution involving a new interface that provides the
required information. Something like:

Object myOwnEncrypt(PublicKey publicKey) throws SecurityException {
    if (publicKey instanceof RSAKey) {
      // RSA
    } else if (publicKey instanceof ECKey) {
      // EC
    } else if (publicKey instanceof ByteArrayKey) {
      ByteArrayKey baKey = (ByteArrayKey)publicKey;
      if(baKey.getAlgorithm().equals("XDH") {
        // RFC 7748
      }
    }
}

The ByteArrayKey would also hold a parameter spec that can be used to
determine which curve is associated with the key. Would something like
this work?


>
> CC:ing the creator of OKP keys.
>
> https://tools.ietf.org/html/rfc8037#section-2
>
> Anders

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Xuelei Fan-2
In reply to this post by Anders Rundgren
On 8/8/2017 8:45 AM, Anders Rundgren wrote:

> On 2017-08-08 17:25, Adam Petcher wrote:
>
>> It sounds like what you are saying is
>> that I will need something like XDHPublicKey and XDHPrivateKey in
>> java.security.interfaces. Can you tell me why? What is it that we can't
>> do without these interfaces?
>
> Every JOSE Java library I have seen constructs and deconstructs RSA and
> EC keys
> based on JWK definitions.  Maybe we don't need XDH keys but it would be
> nice to
> hear what the solution would be without such.
>
> Then there's lot of stuff out there like this which also needs some
> explanations on how to enhance with RFC7748 on board:
>
> Object myOwnEncrypt(PublicKey publicKey) throws SecurityException {
>     if (publicKey instanceof RSAKey) {
>       // RSA
>     } else {
>       // It should be EC
>     }
> }
>
The code above is not reliable unless one understand the underlying
JCA/JCE provider behavior exactly this way.  For a certain provider, an
RSA key may be not an instance of RSAKey.  I would use
key.getAlgorithm() instead.

Xuelei

> CC:ing the creator of OKP keys.
>
> https://tools.ietf.org/html/rfc8037#section-2
>
> Anders
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
In reply to this post by Michael StJohns
On 8/8/2017 12:50 PM, Michael StJohns wrote:

>
> We'll leave this for later.  But generally, the JCA is a general
> interface to a set of crypto primitives modeled on just a few key
> types.  To go in the direction you want to go it you need to explain
> why its impossible to model an elliptic curve as an elliptic curve.  
> As I noted, I think that the inclusion of extension of ECField is
> probably all that's necessary for representing both public and private
> key pairs here.

The problem with the existing EC classes (EllipticCurve, ECPoint, etc.)
is that they are intended to represent curves in Weierstrass form: y^2 =
x^3 + ax + b. EllipticCurve has two parameters "a" and "b" corresponding
to the coefficients in the equation above. RFC 7748 uses elliptic curves
in Montgomery form: y^2 = x^3 + ax^2 + x. So the parameters are
different. Further complicating things: every curve in Montgomery form
has an isomorphic curve in Weierstrass form (but not vice-versa).

So if we reuse EllipticCurve (and related classes), we could map the
parameters onto Montgomery curve coefficients. For example interpret "a"
as the second-degree coefficient instead of the first-degree
coefficient, and ignore "b". But we have the problem that the programmer
may not know when the parameters will be interpreted as Weierstrass
coefficients instead of Montgomery coefficients. I am particularly
concerned about this because these parameters were always interpreted as
Weierstrass coefficients in the past.

So we would want a way to tag the objects and check the tags to ensure
that they are not misused. You suggested making new ECField subclasses
for Montgomery/Edwards curves. The field used in RFC 7748/8032 is GF(p),
which corresponds to the existing class ECFieldFp. So it seems strange
and surprising to use this member to identify how coefficients should be
interpreted, because this has nothing to do with the field. Though I can
see why this approach is appealing, because the field is the only part
of EllipticCurve that was designed to be extensible. If the coefficients
(and their interpretation) were similarly extensible, then we wouldn't
have these problems.

In short: I'm not sure that reusing the existing EC classes is a good
idea, because they were intended for something else, they are not
general enough, and the potential for misuse/confusion is high.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Anders Rundgren
In reply to this post by Xuelei Fan-2
On 2017-08-08 21:42, Xuelei Fan wrote:

> On 8/8/2017 8:45 AM, Anders Rundgren wrote:
>> Object myOwnEncrypt(PublicKey publicKey) throws SecurityException {
>>      if (publicKey instanceof RSAKey) {
>>        // RSA
>>      } else {
>>        // It should be EC
>>      }
>> }
>>
> The code above is not reliable unless one understand the underlying
> JCA/JCE provider behavior exactly this way.  For a certain provider, an
> RSA key may be not an instance of RSAKey.  I would use
> key.getAlgorithm() instead.

You mean that some providers do not always adhere even to RSAPublicKey (which extends RSAKey)?

Well, then there's a lot of broken stuff out there.

Anders


>
> Xuelei
>
>> CC:ing the creator of OKP keys.
>>
>> https://tools.ietf.org/html/rfc8037#section-2
>>
>> Anders

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
In reply to this post by Michael StJohns
On 8/8/2017 12:50 PM, Michael StJohns wrote:

>>>
>>>> Further, this separation will reduce the probability of programming
>>>> errors (e.g. accidentally interpreting a Weierstrass point as an
>>>> RFC 7748 point).
>>>
>>> Um.  What?   It actually won't.
>>
>> This is the sort of problem I want to avoid:
>>
>> KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
>> KeyPair kp = kpg.generateKeyPair();
>> KeyFactory eckf = KeyFactory.getInstance("ECDH");
>> ECPrivateKeySpec priSpec = eckf.getKeySpec(kf.getPrivate(),
>> ECPrivateKeySpec.class);
>>
>> KeyFactory xdhkf = KeyFactory.getInstance("XDH");
>> PrivateKey xdhPrivate = xdhkf.generatePrivate(priSpec);
>>
>> // Now use xdhPrivate for key agreement, which uses the wrong
>> algorithm and curve, and may leak information about the private key
>
> This is setting up a strawman and knocking it down.  It's already
> possible to do the above with any software based key - either directly
> or by pulling out the data.  Creating the API as you suggest will
> still not prevent this as long as I can retrieve the private value
> from the key.
>
> If you want absolute protection from this - go to hardware based keys.

The goal is the prevention of common programming errors that lead to
security issues, not absolute protection like you would get from
hardware crypto. More like the kind of assurance you get from a type
system.

<snip>

>>>>
>>>> A) We don't need to expose actual curve parameters over the API.
>>>> Curves can be specified using names (e.g. "X25519") or OIDs. The
>>>> underlying implementation will likely support arbitrary Montgomery
>>>> curves, but the JCA application will only be able to use the
>>>> supported named curves.
>>>
>>> Strangely, this hasn't turned out all that well.  There needs to be
>>> a name, OID in the public space (primarily for the encodings and
>>> PKIX stuff) and to be honest - you really want the parameters in
>>> public space as well (the ECParameterSpec and its ilk) so that a
>>> given key can be used with different providers or even to play
>>> around internally with new curves before giving them a name.
>>
>> I don't understand why we need public curve parameters to allow keys
>> to be used with different providers. It seems like this should work
>> as long as the providers all understand the OIDs or curve names. Can
>> you explain this part a bit more?
> Because names and OIDs get assigned later than the curve parameters.  
> There are two parts to the JCA - the general crypto part and then
> there's the PKIX part.  For the EC stuff, they sort of overlap because
> of a desire not to have to have everyone remember each of the
> parameter sets (curves) and those sets are tagged by name(s) and OID.  
> But its still  perfectly possible to do EC math on curves that were
> generated elsewhere (or even with a curve where everything but the
> basepoint is the same with a public curve).
>
> What you need to be able to do is to pass to an "older" provider a
> "newer" curve - assuming the curve fits within the math already
> implemented.  There's really no good reason to implement a whole new
> set of API changes just to permit a single new curve.

Okay, thanks. If I am reading this right, this feature supports
interoperability with providers that don't know about a specific curve
name/OID, but support all curves within some family. Without a way to
express the curve parameters in JCA, you would resort to using some
provider-specific parameter spec, which would be unfortunate.

>>
>> Related to tinkering with new curves that don't have a name: I don't
>> think that this is a feature that JCA needs to have. In the common
>> use case, the programmer wants to only use standard algorithms and
>> curves, and I think we should focus on that use case.
>
> The common use case is much wider than you think it is.  I find myself
> using the curve parameters much more than I would like - specifically
> because I use JCA in conjunction with PKCS11, HSMs and smart cards.  
> So no - focusing on a software only subset of things is really not the
> right approach.

I actually would have expected hardware crypto to have *less* support
for arbitrary curves, and so this issue would come up more with software
implementations. Why does this come up so frequently in hardware?

>
>>
>>>
>>>>
>>>> These two assumptions greatly simplify the API. We won't need
>>>> classes that mirror ECParameterSpec, EllipticCurve, ECPoint,
>>>> ECField, ECPublicKey, etc. for X25519/X448.
>>>
>>> That assumption holds only if your various other assumptions hold.
>>> My opinion is that they probably don't.  (BTW - I'm pretty sure,
>>> given that every single asymmetric JCA crypto api takes a PublicKey
>>> or PrivateKey you're going to need to mirror those classes at least;
>>> you'll also need a ParameterSpec and a GenParameterSpec class with
>>> whatever underlying supporting classes are required to deal with
>>> KeyFactory's)
>>
>> I agree with the second part of your parenthetical statement, but I
>> need more information about the first. It sounds like what you are
>> saying is that I will need something like XDHPublicKey and
>> XDHPrivateKey in java.security.interfaces. Can you tell me why? What
>> is it that we can't do without these interfaces?
>
> The method signatures for Signature.initSign(PrivateKey
> privateKey[,SecureRandom random]), Signature.initVerify(PublicKey
> publicKey) should give you a clue.  E.g. the calls to the JCA provider
> classes require that you submit either a PublicKey or a PrivateKey.  
> So you're going to need a concrete class with a subinterface that
> matches the key type needed by the signature instance that is a sub
> interface for PublicKey or PrivateKey.

Does my Signature service need to support a public subinterface of (for
example) PublicKey? At a minimum, I need a concrete class that
implements PublicKey. This class could be entirely internal to my
provider. In Signature.initVerify(PublicKey), I can check whether the
provided key is an instance of my internal concrete class, and fail
otherwise. In this circumstance, my concrete key class doesn't need to
implement any public subinterface of PublicKey.

The above arrangement basically works, but is it okay? Of course,
objects of my concrete class could not be used by other providers,
because they don't know how to interpret them. Is there some requirement
or expectation of interoperability with other providers that I am missing?

Another option to consider is that we don't have subinterfaces for RFC
7748 public/private keys, but rather we use some common subinterface
that provides enough information (e.g. the encoded number and the curve
parameters).

>
> KeyAgreement requires a "Key" (both the public and private keys are
> passed in a Key's).
>
> KeyPairGenerator.init requires an AlgorithmParameter or a key size in
> bits.
>
> KeyFactory requires a KeySpec.
>
> Basically, you can't sign, perform a key agreement, generate a random
> key pair or generate a key from an encoded value without these classes.
>
>
> It's scary that you asked this question because it implies perhaps a
> need to spend a bit more time looking at the JCA and how its structured.
>
>
> Later, Mike
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
On 8/8/2017 5:00 PM, Adam Petcher wrote:

> On 8/8/2017 12:50 PM, Michael StJohns wrote:
>
>>>>
>>>>> Further, this separation will reduce the probability of
>>>>> programming errors (e.g. accidentally interpreting a Weierstrass
>>>>> point as an RFC 7748 point).
>>>>
>>>> Um.  What?   It actually won't.
>>>
>>> This is the sort of problem I want to avoid:
>>>
>>> KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
>>> KeyPair kp = kpg.generateKeyPair();
>>> KeyFactory eckf = KeyFactory.getInstance("ECDH");
>>> ECPrivateKeySpec priSpec = eckf.getKeySpec(kf.getPrivate(),
>>> ECPrivateKeySpec.class);
>>>
>>> KeyFactory xdhkf = KeyFactory.getInstance("XDH");
>>> PrivateKey xdhPrivate = xdhkf.generatePrivate(priSpec);
>>>
>>> // Now use xdhPrivate for key agreement, which uses the wrong
>>> algorithm and curve, and may leak information about the private key
>>
>> This is setting up a strawman and knocking it down.  It's already
>> possible to do the above with any software based key - either
>> directly or by pulling out the data.  Creating the API as you suggest
>> will still not prevent this as long as I can retrieve the private
>> value from the key.
>>
>> If you want absolute protection from this - go to hardware based keys.
>
> The goal is the prevention of common programming errors that lead to
> security issues, not absolute protection like you would get from
> hardware crypto. More like the kind of assurance you get from a type
> system.

The engine implementation (provider plugin) is responsible for
preventing the "common programming errors", not the API.  The JCA really
doesn't have support for a type system style assurance.


>
> <snip>
>
>>>>>
>>>>> A) We don't need to expose actual curve parameters over the API.
>>>>> Curves can be specified using names (e.g. "X25519") or OIDs. The
>>>>> underlying implementation will likely support arbitrary Montgomery
>>>>> curves, but the JCA application will only be able to use the
>>>>> supported named curves.
>>>>
>>>> Strangely, this hasn't turned out all that well.  There needs to be
>>>> a name, OID in the public space (primarily for the encodings and
>>>> PKIX stuff) and to be honest - you really want the parameters in
>>>> public space as well (the ECParameterSpec and its ilk) so that a
>>>> given key can be used with different providers or even to play
>>>> around internally with new curves before giving them a name.
>>>
>>> I don't understand why we need public curve parameters to allow keys
>>> to be used with different providers. It seems like this should work
>>> as long as the providers all understand the OIDs or curve names. Can
>>> you explain this part a bit more?
>> Because names and OIDs get assigned later than the curve parameters.  
>> There are two parts to the JCA - the general crypto part and then
>> there's the PKIX part.  For the EC stuff, they sort of overlap
>> because of a desire not to have to have everyone remember each of the
>> parameter sets (curves) and those sets are tagged by name(s) and
>> OID.  But its still  perfectly possible to do EC math on curves that
>> were generated elsewhere (or even with a curve where everything but
>> the basepoint is the same with a public curve).
>>
>> What you need to be able to do is to pass to an "older" provider a
>> "newer" curve - assuming the curve fits within the math already
>> implemented.  There's really no good reason to implement a whole new
>> set of API changes just to permit a single new curve.
>
> Okay, thanks. If I am reading this right, this feature supports
> interoperability with providers that don't know about a specific curve
> name/OID, but support all curves within some family. Without a way to
> express the curve parameters in JCA, you would resort to using some
> provider-specific parameter spec, which would be unfortunate.

Pretty much.   This is why I've been pushing back so hard on "just one
more key type" style arguments.


>
>>>
>>> Related to tinkering with new curves that don't have a name: I don't
>>> think that this is a feature that JCA needs to have. In the common
>>> use case, the programmer wants to only use standard algorithms and
>>> curves, and I think we should focus on that use case.
>>
>> The common use case is much wider than you think it is.  I find
>> myself using the curve parameters much more than I would like -
>> specifically because I use JCA in conjunction with PKCS11, HSMs and
>> smart cards.   So no - focusing on a software only subset of things
>> is really not the right approach.
>
> I actually would have expected hardware crypto to have *less* support
> for arbitrary curves, and so this issue would come up more with
> software implementations. Why does this come up so frequently in
> hardware?

Because the hardware tends to work either very generally or very
specifically.  A PKCS11 big iron HSM for example mostly doesn't do
multiple curves and requires that you just give them the curve OID, but
the JCOP smart cards work over a broad set of curves - as long as you
give them the entire curve data set.  But the JCOP cards don't do ASN1
so I keep getting to have to convert raw EC points into formatted EC
public keys.   One set of programs I have has to deal with at least
three different representations - all of which are appropriate at
various points.

As it stands, I find the JCOP smart cards more flexible than the PKCS11
HSMs, but the PKCS11 HSMs more able to deal with large amounts of
calculations (and generally better at keeping things secret than the
smart cards).



>
>>
>>>
>>>>
>>>>>
>>>>> These two assumptions greatly simplify the API. We won't need
>>>>> classes that mirror ECParameterSpec, EllipticCurve, ECPoint,
>>>>> ECField, ECPublicKey, etc. for X25519/X448.
>>>>
>>>> That assumption holds only if your various other assumptions hold.
>>>> My opinion is that they probably don't.  (BTW - I'm pretty sure,
>>>> given that every single asymmetric JCA crypto api takes a PublicKey
>>>> or PrivateKey you're going to need to mirror those classes at
>>>> least; you'll also need a ParameterSpec and a GenParameterSpec
>>>> class with whatever underlying supporting classes are required to
>>>> deal with KeyFactory's)
>>>
>>> I agree with the second part of your parenthetical statement, but I
>>> need more information about the first. It sounds like what you are
>>> saying is that I will need something like XDHPublicKey and
>>> XDHPrivateKey in java.security.interfaces. Can you tell me why? What
>>> is it that we can't do without these interfaces?
>>
>> The method signatures for Signature.initSign(PrivateKey
>> privateKey[,SecureRandom random]), Signature.initVerify(PublicKey
>> publicKey) should give you a clue.  E.g. the calls to the JCA
>> provider classes require that you submit either a PublicKey or a
>> PrivateKey.  So you're going to need a concrete class with a
>> subinterface that matches the key type needed by the signature
>> instance that is a sub interface for PublicKey or PrivateKey.
>
> Does my Signature service need to support a public subinterface of
> (for example) PublicKey? At a minimum, I need a concrete class that
> implements PublicKey. This class could be entirely internal to my
> provider. In Signature.initVerify(PublicKey), I can check whether the
> provided key is an instance of my internal concrete class, and fail
> otherwise. In this circumstance, my concrete key class doesn't need to
> implement any public subinterface of PublicKey.

I think I understand what you're asking.  Signature needs a PublicKey.  
PublicKey is an interface so you can "implement" just that interface in
your concrete class.  However, you should mostly NEVER be looking at
whether or not a given key is an instance of a particular internal class
as this will break at some point.  Any implementation should be checking
for public markers - either directly as an instance of  ECPublicKey or
indirectly looking at the parameter set of the public key.


>
> The above arrangement basically works, but is it okay? Of course,
> objects of my concrete class could not be used by other providers,
> because they don't know how to interpret them. Is there some
> requirement or expectation of interoperability with other providers
> that I am missing?

There's somewhat of a contract that says that public keys should be
convertible.  So while you might get away with hiding the class info for
a private key, you really should provide a mechanism for a common
representation of the public keys so that things like signature
verification just work across providers.

>
> Another option to consider is that we don't have subinterfaces for RFC
> 7748 public/private keys, but rather we use some common subinterface
> that provides enough information (e.g. the encoded number and the
> curve parameters).
>

You mean like "ECKey"?  This is implemented by both public and private
EC keys and mostly contains the ECParameterSpec set.

Mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
On 8/8/2017 9:55 PM, Michael StJohns wrote:
>>
>> Another option to consider is that we don't have subinterfaces for
>> RFC 7748 public/private keys, but rather we use some common
>> subinterface that provides enough information (e.g. the encoded
>> number and the curve parameters).
>>
>
> You mean like "ECKey"?  This is implemented by both public and private
> EC keys and mostly contains the ECParameterSpec set.

Sort of. I'm trying to figure out how appropriate it is to have the
equivalent of ECKey without the equivalent of ECPrivateKey and
ECPublicKey. In this scenario, the equivalent of ECKey contains all the
information about the public/private key (in RFC 7748, it's an integer
in both cases).

>
> Mike
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Adam Petcher
In reply to this post by Adam Petcher
Anyone have any additional thoughts on this?

I think the most significant item we need to discuss is the extent to
which JCA should allow curve parameters for RFC 7748/8032 to be
specified over the API. Does anyone know of a particular use case (that
we haven't discuss already) that would require a provider to support
arbitrary curves? Any other arguments for or against this feature?


On 8/7/2017 4:37 PM, Adam Petcher wrote:

> I'm working on the Java implementation of RFC 7748 (Diffie-Hellman
> with X25519 and X448). I know some of you have been anxious to talk
> about how this would fit into JCA, and I appreciate your patience
> while I learned enough about JCA and existing crypto implementations
> to develop this API proposal. This API/design proposal is for RFC 7748
> only, and it does not include the API for RFC 8032 (EdDSA). Of course,
> I expect many of the decisions that we make for RFC 7748 will also
> impact RFC 8032.
>
> First off, I think it is important to separate RFC 7748 from the
> existing ECDH API and implementation. RFC 7748 is a different
> standard, it uses different encodings and algorithms, and it has
> different properties. Further, this separation will reduce the
> probability of programming errors (e.g. accidentally interpreting a
> Weierstrass point as an RFC 7748 point). So I propose that we use
> distinct algorithm names for RFC 7748, and that we don't use any of
> the existing EC classes like EllipticCurve and ECPoint with RFC 7748.
>
> We can achieve this separation without duplicating a lot of code if we
> start with some simplifying assumptions. My goal is to remove
> functionality that nobody needs in order to simplify the design and
> API. If I am simplifying away something that you think you will need,
> please let me know.
>
> A) We don't need to expose actual curve parameters over the API.
> Curves can be specified using names (e.g. "X25519") or OIDs. The
> underlying implementation will likely support arbitrary Montgomery
> curves, but the JCA application will only be able to use the supported
> named curves.
> B) We don't need direct interoperability between different providers
> using opaque key representations. We can communicate with other
> providers using X509/PKCS8 encoding, or by using KeyFactory and key
> specs.
>
> These two assumptions greatly simplify the API. We won't need classes
> that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField,
> ECPublicKey, etc. for X25519/X448.
>
> Now that the motivation and assumptions are out of the way, here is a
> description of the proposed JCA API:
>
> 1) The string "XDH" will be used in getInstance() to refer to all
> services related to RFC 7748 (KeyAgreement, KeyFactory,
> KeyPairGenerator, etc). This is a departure from the ECDH API that
> used "EC" for key generation (shared with ECDSA) and "ECDH" for
> KeyAgreement, and makes the RFC 7748 API more like "DiffieHellman" and
> other algorithms that use the same name for all services.
> 2) The new class java.security.spec.NamedParameterSpec (which
> implements AlgorithmParameterSpec) will be used to specify curves for
> RFC 7748. This class has a single String member which holds the name
> of the curve ("X25519" or "X448"). This parameter spec class can be
> reused by other crypto algorithms that similarly identify parameter
> sets using names (e.g. FFDHE3072 in DiffieHellman). This new class can
> be inserted into the hierarchy above ECGenParameterSpec.
> 3) There will be no classes in java.security.spec for EC public keys
> and private keys. An RFC 7748 implementation can use the existing
> classes X509EncodedKeySpec and PKCS8EncodedKeySpec for public and
> private key specs, respectively.
> 4) There will be no interfaces in java.security.interfaces for RFC
> 7748 public/private keys. Public/private key implementation classes
> will implement java.security.PublicKey and java.security.PrivateKey,
> which allows access to their encoded representations.
>
> Here is how the API will be implemented in the SunEC provider:
>
> 1) The public key and private key implementation classes will extend
> sun.security.ec.X509Key and sun.security.ec.PKCS8Key, respectively.
> This is similar to ECPublicKeyImpl and ECPrivateKeyImpl.
> 2) The KeyFactory for RFC 7748 will support translation to/from opaque
> keys and X509EncodedKeySpec/PKCS8EncodedKeySpec.
>
> Example code:
>
> KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
> NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
> kpg.initialize(paramSpec); // equivalent to kpg.initialize(255)
> KeyPair kp = kpg.generateKeyPair();
>
> KeyFactory kf = KeyFactory.getInstance("XDH");
> X509EncodedKeySpec pubSpec = ...
> PublicKey pubKey = kf.generatePublic(pubSpec);
>
> KeyAgreement ka = KeyAgreement.getInstance("XDH");
> ka.init(kp.getPrivate());
> ka.doPhase(pubKey, true);
> byte[] secret = ka.generateSecret();
>
>
> One thing that is missing from the "core" API proposal is a way to
> easily produce a public/private key from an encoded numeric value. Of
> course, it's possible to put this value into a complete encoded
> X509/PKCS8 key, but that is not very convenient. Perhaps we can add
> another key spec class (that holds e.g. an AlgorithmParameterSpec and
> a byte array) to make this easier, but I don't know how valuable this
> would be.
>
> I appreciate any feedback the experts on the mailing list may have for
> me. Please let me know what you think.
>
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
On 8/10/2017 9:44 AM, Adam Petcher wrote:
> Does anyone know of a particular use case (that we haven't discuss
> already) that would require a provider to support arbitrary curves?
> Any other arguments for or against this feature?

There are uses for changing out the base point.  PAKE and SPAKE use
similar math (e.g. G^s*sharedSecret is the equivalent of a new base point).

There are uses for private curves - e.g. when you want to actually be
sure that the curve was randomly generated (sort of the same argument
that got us to Curve25519 in the first place).

There are the whole set of Edwards curves that are mostly not included
in any provider (except possible Microsoft's) as of yet.

Basically, you're trying to argue that there are no better curves (for
the 'new' math) than have already been specified and there never will
be.  I think that's a very shortsighted argument.

Later, Mike


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Xuelei Fan-2
In reply to this post by Adam Petcher
Hi,

I want to extend the comment a little bit.

1. The background
A elliptic curve is determined by either an equation of form
      y^2 = x^3 + ax + b            (1) [Weierstrass form]
or
      y^2 + xy = x^3 + ax^2 + b.    (2)

However, some other forms may also be used.  For example:
      y^2 = x(x-1)(x-r)             (3)
or
      By^2 = x^3 + Ax^2 + x         (4) [RFC 7748, Montgomery curve]
      x^2 + y^2 = 1 + dx^2y^2       (5) [RFC 7748, Edwards curve]

In general, any elliptic curve can be written in Weierstrass form (1) or
(2).  That's, Montgomery curve and Edwards curve can be expressed in
Weierstrass form.

2. Where we are now?
In JDK, an elliptic curve is defined in the Weierstrass form ((1)/(2)).
See java.security.spec.EllipticCurve:

     EllipticCurve​(ECField field, BigInteger a, BigInteger b)

In theory, the existing APIs can be used for RFC 7748, by converting the
Montgomery curve and Edwards curve to the Weierstrass form.  However,
the conversion can be misleading and complicate the implementation
significantly.  For example, before using a point Weierstrass form (x,
y), the implementation need to convert it to Montgomery curve (x', -) so
as to use the fully potential of RFC 7748.   The curves returned in
public APIs need to use (x, y), while the implementation need to use
(x', y').  It's very confusing and the compatibility impact could be
significant.  For example:

     public something(ECPublicKey ecPublicKey)  {
        // Problem: If no other information, it is unclear
        // whether the ecPublicKey can be used for a particular
        // signature verification or not when the RFC 7748/8032
        // get supported.

        // Problem: an old application may use ecPublicKey for
        // the old style operation, even the ecPublicKey is supposed
        // to be x25519.  It's not easy to control the behavior in
        // legacy application code, and may introduce unexpected
        // security issues.
     }

     public KeyAgreement getKeyAgreement(AlgorithmParameterSpec aps) {
        // Problem: the code bellow should be comment in the current
        // code.  However, the ECParameterSpec may not be able to use
        // for the old style "EC" key agreement.
        //
        // JDK crypto provider can take special action to avoid this
        // issue in the JCA/JCE implementation.  But it cannot be
        // granted other provider can do this as well, and old
        // provider may run into problems as well.
        if (aps instance of ECParameterSpec) {
            return KeyAgreement.getInstance("EC");
        }
     }

What's the problem with ECPublicKey/ECPrivateKey/ECKey? It's mainly
about the ECParameterSpec:

      ECParameterSpec ECKey.getParams​()

and ECParameterSpec is using java.security.spec.EllipticCurve.  This
design makes it pretty confusing to use ECPublicKey/ECPrivateKey/ECKey
for RFC 7748 (Edwards curve form and Montgomery curve form).

Can EllipticCurve be extended to support more forms? The
java.security.spec.EllipticCurve defines two methods to get the
coefficients of Weierstrass form.
      public BigInteger getA()
      public BigInteger getB()

The 'A' and 'B' may not exist in other forms, for example the (3)(4)(5)
forms above.  While, the spec might be able to be updated by throwing
UnsupportedOperationException for getA() and getB() for the (3)(4)(5)
forms, and define new extended classes for new forms, like:
      public MCEllipticCurve extends EllipticCurve   // Montgomery curve
      public EDEllipticCurve extends EllipticCurve   // Edwards curve

However, I'm not very sure of the compatibility impact (see above).

3. Where we are not now?
Using named curves is popular.  There is a ECGenParameterSpec class
using named curves:
      ECGenParameterSpec​ ecgp =
          new ECGenParameterSpec​(secp256r1);
      KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
      kpg.initialize(ecpg);
      KeyPair kp = kpg.generateKeyPair​();

      ECPublicKey pubKey = (ECPublicKey)kp.getPublic();
      String keyAlgorithm = pubKey.getAlgorithm​();  // "EC"

However, it is used for key generation only.  Once the keys are
generated, there is no public API to know the name of the curve in
ECKey.  ECKey.getAlgorithm() will return "EC" only.  If it is required
to known whether a key is of a named curve, the solution is not
straightforward.

4. A general proposal
Support named curves could be a solution for #2 and #3 concerns above.
For named curves, the parameters are defined explicitly.  So, it is
REQUIRED to have the public APIs for named curves' parameters any more.
It can be something hidden in the implementation layer.  The key pair
generation may looks like:

     KeyPairGenerator kpg =
         KeyPairGenerator.getInstance("ECWithSecp256k1");
     KeyPair kp = kpg.generateKeyPair​();

     PublicKey pubKey = kp.getPublic();
     String keyAlgorithm = pubKey.getAlgorithm​();  // "ECWithSecp256k1"

As no explicit parameters is required, the EllipticCurve issue for
Edwards curve form and Montgomery curve form in #2 is not a issue any
more here.

The compatibility impact is limited as the name "ECWithSecp256k1" is not
used in the past, and the Weierstrass form APIs, like
ECKey/ECParameterSpec/EllipticCurve, are not necessarily to be used in
this solution.

The benefits: simplify the APIs for named curves (including the
Weierstrass form), and simplify the support of named curves for Edwards
curve form and Montgomery curve form.

The disadvantages: no support of arbitrary curves (no surprise as this
is a named curve solution), and new learn curve to use this new solution.

5. Can be more aggressive?
It looks amazing to support arbitrary curves for Edwards curve form and
Montgomery curve form, as JDK did for Weierstrass form.  However,
because of the compatibility impact (see #2), a new set of algorithms
names, interfaces and specs may be required.  It could be overloaded if
the requirements are not so strong in practice.  If arbitrary curves
support is strong, it can be re-considered in the future.

Per my understanding, supporting named curves and arbitrary curves can
be two things, and can be considered in different stages.  However, the
design needs to take care of the potential conflicts between the two
solutions.

Thanks,
Xuelei

On 8/8/2017 12:43 PM, Adam Petcher wrote:

> On 8/8/2017 12:50 PM, Michael StJohns wrote:
>
>>
>> We'll leave this for later.  But generally, the JCA is a general
>> interface to a set of crypto primitives modeled on just a few key
>> types.  To go in the direction you want to go it you need to explain
>> why its impossible to model an elliptic curve as an elliptic curve. As
>> I noted, I think that the inclusion of extension of ECField is
>> probably all that's necessary for representing both public and private
>> key pairs here.
>
> The problem with the existing EC classes (EllipticCurve, ECPoint, etc.)
> is that they are intended to represent curves in Weierstrass form: y^2 =
> x^3 + ax + b. EllipticCurve has two parameters "a" and "b" corresponding
> to the coefficients in the equation above. RFC 7748 uses elliptic curves
> in Montgomery form: y^2 = x^3 + ax^2 + x. So the parameters are
> different. Further complicating things: every curve in Montgomery form
> has an isomorphic curve in Weierstrass form (but not vice-versa).
>
> So if we reuse EllipticCurve (and related classes), we could map the
> parameters onto Montgomery curve coefficients. For example interpret "a"
> as the second-degree coefficient instead of the first-degree
> coefficient, and ignore "b". But we have the problem that the programmer
> may not know when the parameters will be interpreted as Weierstrass
> coefficients instead of Montgomery coefficients. I am particularly
> concerned about this because these parameters were always interpreted as
> Weierstrass coefficients in the past.
>
> So we would want a way to tag the objects and check the tags to ensure
> that they are not misused. You suggested making new ECField subclasses
> for Montgomery/Edwards curves. The field used in RFC 7748/8032 is GF(p),
> which corresponds to the existing class ECFieldFp. So it seems strange
> and surprising to use this member to identify how coefficients should be
> interpreted, because this has nothing to do with the field. Though I can
> see why this approach is appealing, because the field is the only part
> of EllipticCurve that was designed to be extensible. If the coefficients
> (and their interpretation) were similarly extensible, then we wouldn't
> have these problems.
>
> In short: I'm not sure that reusing the existing EC classes is a good
> idea, because they were intended for something else, they are not
> general enough, and the potential for misuse/confusion is high.
>
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
Hi Xuelei -

Great analysis.

Some comments in line.

On 8/10/2017 3:10 PM, Xuelei Fan wrote:

> Hi,
>
> I want to extend the comment a little bit.
>
> 1. The background
> A elliptic curve is determined by either an equation of form
>      y^2 = x^3 + ax + b            (1) [Weierstrass form]
> or
>      y^2 + xy = x^3 + ax^2 + b.    (2)
>
> However, some other forms may also be used.  For example:
>      y^2 = x(x-1)(x-r)             (3)
> or
>      By^2 = x^3 + Ax^2 + x         (4) [RFC 7748, Montgomery curve]
>      x^2 + y^2 = 1 + dx^2y^2       (5) [RFC 7748, Edwards curve]
>
> In general, any elliptic curve can be written in Weierstrass form (1)
> or (2).  That's, Montgomery curve and Edwards curve can be expressed
> in Weierstrass form.
>
> 2. Where we are now?
> In JDK, an elliptic curve is defined in the Weierstrass form
> ((1)/(2)). See java.security.spec.EllipticCurve:
>
>     EllipticCurve​(ECField field, BigInteger a, BigInteger b)
>
> In theory, the existing APIs can be used for RFC 7748, by converting
> the Montgomery curve and Edwards curve to the Weierstrass form.  
> However, the conversion can be misleading and complicate the
> implementation significantly.  For example, before using a point
> Weierstrass form (x, y), the implementation need to convert it to
> Montgomery curve (x', -) so as to use the fully potential of RFC
> 7748.   The curves returned in public APIs need to use (x, y), while
> the implementation need to use (x', y'). It's very confusing and the
> compatibility impact could be significant.  For example:
>
>     public something(ECPublicKey ecPublicKey)  {
>        // Problem: If no other information, it is unclear
>        // whether the ecPublicKey can be used for a particular
>        // signature verification or not when the RFC 7748/8032
>        // get supported.
>
>        // Problem: an old application may use ecPublicKey for
>        // the old style operation, even the ecPublicKey is supposed
>        // to be x25519.  It's not easy to control the behavior in
>        // legacy application code, and may introduce unexpected
>        // security issues.
>     }
>
>     public KeyAgreement getKeyAgreement(AlgorithmParameterSpec aps) {
>        // Problem: the code bellow should be comment in the current
>        // code.  However, the ECParameterSpec may not be able to use
>        // for the old style "EC" key agreement.
>        //
>        // JDK crypto provider can take special action to avoid this
>        // issue in the JCA/JCE implementation.  But it cannot be
>        // granted other provider can do this as well, and old
>        // provider may run into problems as well.
>        if (aps instance of ECParameterSpec) {
>            return KeyAgreement.getInstance("EC");
>        }
>     }
>
> What's the problem with ECPublicKey/ECPrivateKey/ECKey? It's mainly
> about the ECParameterSpec:
>
>      ECParameterSpec ECKey.getParams​()
>
> and ECParameterSpec is using java.security.spec.EllipticCurve. This
> design makes it pretty confusing to use ECPublicKey/ECPrivateKey/ECKey
> for RFC 7748 (Edwards curve form and Montgomery curve form).
>
> Can EllipticCurve be extended to support more forms? The
> java.security.spec.EllipticCurve defines two methods to get the
> coefficients of Weierstrass form.
>      public BigInteger getA()
>      public BigInteger getB()
>
> The 'A' and 'B' may not exist in other forms, for example the
> (3)(4)(5) forms above.  While, the spec might be able to be updated by
> throwing UnsupportedOperationException for getA() and getB() for the
> (3)(4)(5) forms, and define new extended classes for new forms, like:
>      public MCEllipticCurve extends EllipticCurve   // Montgomery curve
>      public EDEllipticCurve extends EllipticCurve   // Edwards curve

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.


>
> However, I'm not very sure of the compatibility impact (see above).
>
> 3. Where we are not now?
> Using named curves is popular.  There is a ECGenParameterSpec class
> using named curves:
>      ECGenParameterSpec​ ecgp =
>          new ECGenParameterSpec​(secp256r1);
>      KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
>      kpg.initialize(ecpg);
>      KeyPair kp = kpg.generateKeyPair​();
>
>      ECPublicKey pubKey = (ECPublicKey)kp.getPublic();
>      String keyAlgorithm = pubKey.getAlgorithm​();  // "EC"
>
> However, it is used for key generation only.  Once the keys are
> generated, there is no public API to know the name of the curve in
> ECKey.  ECKey.getAlgorithm() will return "EC" only.  If it is required
> to known whether a key is of a named curve, the solution is not
> straightforward.

This ties back to "getEncoded()" representations.  Under the hood, if
you do a getEncoded() there's a "which name does this parameter set
match up to" search which checks various tables for an OID and uses that
in an X.509 SPKI output object.  On input, the table lookup has to see
whether or not it understands the curve OID (or the key type OID -
depending).

To deal with this without having to modify the internal parameter tables
I currently match keys against parameter sets that have known OIDs.

>
> 4. A general proposal
> Support named curves could be a solution for #2 and #3 concerns above.
> For named curves, the parameters are defined explicitly. So, it is
> REQUIRED to have the public APIs for named curves' parameters any
> more. It can be something hidden in the implementation layer.  The key
> pair generation may looks like:
>
>     KeyPairGenerator kpg =
>         KeyPairGenerator.getInstance("ECWithSecp256k1");
>     KeyPair kp = kpg.generateKeyPair​();
>
>     PublicKey pubKey = kp.getPublic();
>     String keyAlgorithm = pubKey.getAlgorithm​();  // "ECWithSecp256k1"
>
> As no explicit parameters is required, the EllipticCurve issue for
> Edwards curve form and Montgomery curve form in #2 is not a issue any
> more here.
>
> The compatibility impact is limited as the name "ECWithSecp256k1" is
> not used in the past, and the Weierstrass form APIs, like
> ECKey/ECParameterSpec/EllipticCurve, are not necessarily to be used in
> this solution.
>
> The benefits: simplify the APIs for named curves (including the
> Weierstrass form), and simplify the support of named curves for
> Edwards curve form and Montgomery curve form.
>
> The disadvantages: no support of arbitrary curves (no surprise as this
> is a named curve solution), and new learn curve to use this new solution.

Right now there are 3 major APIs  (JCA, PKCS11 and Microsoft CSP) and at
least 4 major representational domains (Raw, PKIX, XML and JSON).  In
the current situation, I can take a JCA EC Public key and convert it to
pretty much any of the other APIs or representations. For much of the
hardware based stuff (ie, smart cards), I go straight from JCA into raw
and vice versa.  Assuming you left the "getEncoded()" stuff in the API
and the encoding was PKIX, I'd have to encode to PKIX, decode the PKIX
to extract the actual raw key or encode a PKIX blob and hope that the
KeyFactory stuff actually worked.

It's not just support of arbitrary keys, but the ability to convert
things without having to do multiple steps or stages.

Your solution would probably work reasonably well for TLS or IPSEC - but
would not work well for anything else.


>
> 5. Can be more aggressive?
> It looks amazing to support arbitrary curves for Edwards curve form
> and Montgomery curve form, as JDK did for Weierstrass form. However,
> because of the compatibility impact (see #2), a new set of algorithms
> names, interfaces and specs may be required.  It could be overloaded
> if the requirements are not so strong in practice.  If arbitrary
> curves support is strong, it can be re-considered in the future.
>
> Per my understanding, supporting named curves and arbitrary curves can
> be two things, and can be considered in different stages. However, the
> design needs to take care of the potential conflicts between the two
> solutions.

As I understand it, the JEP process takes some time and right now
proposed changes *might* make it into JDK10?     Do you really want to
do multiple JEPs to handle multiple new Edwards and Montgomery curves?

If we can hide most of this under the current EC covers, then the
implementations can just implement the plugin interface and do that now.

Mike



>
> Thanks,
> Xuelei

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Xuelei Fan-2
Hi Michael,

Good points!  See comments inlines.

On 8/10/2017 3:20 PM, Michael StJohns wrote:

> Hi Xuelei -
>
> Great analysis.
>
> Some comments in line.
>
> On 8/10/2017 3:10 PM, Xuelei Fan wrote:
>> Hi,
>>
>> I want to extend the comment a little bit.
>>
>> 1. The background
>> A elliptic curve is determined by either an equation of form
>>      y^2 = x^3 + ax + b            (1) [Weierstrass form]
>> or
>>      y^2 + xy = x^3 + ax^2 + b.    (2)
>>
>> However, some other forms may also be used.  For example:
>>      y^2 = x(x-1)(x-r)             (3)
>> or
>>      By^2 = x^3 + Ax^2 + x         (4) [RFC 7748, Montgomery curve]
>>      x^2 + y^2 = 1 + dx^2y^2       (5) [RFC 7748, Edwards curve]
>>
>> In general, any elliptic curve can be written in Weierstrass form (1)
>> or (2).  That's, Montgomery curve and Edwards curve can be expressed
>> in Weierstrass form.
>>
>> 2. Where we are now?
>> In JDK, an elliptic curve is defined in the Weierstrass form
>> ((1)/(2)). See java.security.spec.EllipticCurve:
>>
>>     EllipticCurve​(ECField field, BigInteger a, BigInteger b)
>>
>> In theory, the existing APIs can be used for RFC 7748, by converting
>> the Montgomery curve and Edwards curve to the Weierstrass form.
>> However, the conversion can be misleading and complicate the
>> implementation significantly.  For example, before using a point
>> Weierstrass form (x, y), the implementation need to convert it to
>> Montgomery curve (x', -) so as to use the fully potential of RFC
>> 7748.   The curves returned in public APIs need to use (x, y), while
>> the implementation need to use (x', y'). It's very confusing and the
>> compatibility impact could be significant.  For example:
>>
>>     public something(ECPublicKey ecPublicKey)  {
>>        // Problem: If no other information, it is unclear
>>        // whether the ecPublicKey can be used for a particular
>>        // signature verification or not when the RFC 7748/8032
>>        // get supported.
>>
>>        // Problem: an old application may use ecPublicKey for
>>        // the old style operation, even the ecPublicKey is supposed
>>        // to be x25519.  It's not easy to control the behavior in
>>        // legacy application code, and may introduce unexpected
>>        // security issues.
>>     }
>>
>>     public KeyAgreement getKeyAgreement(AlgorithmParameterSpec aps) {
>>        // Problem: the code bellow should be comment in the current
>>        // code.  However, the ECParameterSpec may not be able to use
>>        // for the old style "EC" key agreement.
>>        //
>>        // JDK crypto provider can take special action to avoid this
>>        // issue in the JCA/JCE implementation.  But it cannot be
>>        // granted other provider can do this as well, and old
>>        // provider may run into problems as well.
>>        if (aps instance of ECParameterSpec) {
>>            return KeyAgreement.getInstance("EC");
>>        }
>>     }
>>
>> What's the problem with ECPublicKey/ECPrivateKey/ECKey? It's mainly
>> about the ECParameterSpec:
>>
>>      ECParameterSpec ECKey.getParams​()
>>
>> and ECParameterSpec is using java.security.spec.EllipticCurve. This
>> design makes it pretty confusing to use ECPublicKey/ECPrivateKey/ECKey
>> for RFC 7748 (Edwards curve form and Montgomery curve form).
>>
>> Can EllipticCurve be extended to support more forms? The
>> java.security.spec.EllipticCurve defines two methods to get the
>> coefficients of Weierstrass form.
>>      public BigInteger getA()
>>      public BigInteger getB()
>>
>> The 'A' and 'B' may not exist in other forms, for example the
>> (3)(4)(5) forms above.  While, the spec might be able to be updated by
>> throwing UnsupportedOperationException for getA() and getB() for the
>> (3)(4)(5) forms, and define new extended classes for new forms, like:
>>      public MCEllipticCurve extends EllipticCurve   // Montgomery curve
>>      public EDEllipticCurve extends EllipticCurve   // Edwards curve
>
> 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.

>
>>
>> However, I'm not very sure of the compatibility impact (see above).
>>
>> 3. Where we are not now?
>> Using named curves is popular.  There is a ECGenParameterSpec class
>> using named curves:
>>      ECGenParameterSpec​ ecgp =
>>          new ECGenParameterSpec​(secp256r1);
>>      KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
>>      kpg.initialize(ecpg);
>>      KeyPair kp = kpg.generateKeyPair​();
>>
>>      ECPublicKey pubKey = (ECPublicKey)kp.getPublic();
>>      String keyAlgorithm = pubKey.getAlgorithm​();  // "EC"
>>
>> However, it is used for key generation only.  Once the keys are
>> generated, there is no public API to know the name of the curve in
>> ECKey.  ECKey.getAlgorithm() will return "EC" only.  If it is required
>> to known whether a key is of a named curve, the solution is not
>> straightforward.
>
> This ties back to "getEncoded()" representations.  Under the hood, if
> you do a getEncoded() there's a "which name does this parameter set
> match up to" search which checks various tables for an OID and uses that
> in an X.509 SPKI output object.  On input, the table lookup has to see
> whether or not it understands the curve OID (or the key type OID -
> depending).
>
> To deal with this without having to modify the internal parameter tables
> I currently match keys against parameter sets that have known OIDs.
>
I see.

>>
>> 4. A general proposal
>> Support named curves could be a solution for #2 and #3 concerns above.
>> For named curves, the parameters are defined explicitly. So, it is
>> REQUIRED to have the public APIs for named curves' parameters any
>> more. It can be something hidden in the implementation layer.  The key
>> pair generation may looks like:
>>
>>     KeyPairGenerator kpg =
>>         KeyPairGenerator.getInstance("ECWithSecp256k1");
>>     KeyPair kp = kpg.generateKeyPair​();
>>
>>     PublicKey pubKey = kp.getPublic();
>>     String keyAlgorithm = pubKey.getAlgorithm​();  // "ECWithSecp256k1"
>>
>> As no explicit parameters is required, the EllipticCurve issue for
>> Edwards curve form and Montgomery curve form in #2 is not a issue any
>> more here.
>>
>> The compatibility impact is limited as the name "ECWithSecp256k1" is
>> not used in the past, and the Weierstrass form APIs, like
>> ECKey/ECParameterSpec/EllipticCurve, are not necessarily to be used in
>> this solution.
>>
>> The benefits: simplify the APIs for named curves (including the
>> Weierstrass form), and simplify the support of named curves for
>> Edwards curve form and Montgomery curve form.
>>
>> The disadvantages: no support of arbitrary curves (no surprise as this
>> is a named curve solution), and new learn curve to use this new solution.
>
> Right now there are 3 major APIs  (JCA, PKCS11 and Microsoft CSP) and at
> least 4 major representational domains (Raw, PKIX, XML and JSON).  In
> the current situation, I can take a JCA EC Public key and convert it to
> pretty much any of the other APIs or representations. For much of the
> hardware based stuff (ie, smart cards), I go straight from JCA into raw
> and vice versa.  Assuming you left the "getEncoded()" stuff in the API
> and the encoding was PKIX, I'd have to encode to PKIX, decode the PKIX
> to extract the actual raw key or encode a PKIX blob and hope that the
> KeyFactory stuff actually worked.
>
> It's not just support of arbitrary keys, but the ability to convert
> things without having to do multiple steps or stages.
>
Good point!  It would be nice if transaction between two formats could
be done simply.  Using X.509 encoding is doable as you said above, but
maybe there are spaces to get improvements.

I need more time to think about it.  Please let me know if any one have
a solution to simplify the transaction if keeping use the proposed named
curves solution.

> Your solution would probably work reasonably well for TLS or IPSEC - but
> would not work well for anything else.
>
Properly a little bit more than TLS and IPSEC, but definitely not
everything else.

>
>>
>> 5. Can be more aggressive?
>> It looks amazing to support arbitrary curves for Edwards curve form
>> and Montgomery curve form, as JDK did for Weierstrass form. However,
>> because of the compatibility impact (see #2), a new set of algorithms
>> names, interfaces and specs may be required.  It could be overloaded
>> if the requirements are not so strong in practice.  If arbitrary
>> curves support is strong, it can be re-considered in the future.
>>
>> Per my understanding, supporting named curves and arbitrary curves can
>> be two things, and can be considered in different stages. However, the
>> design needs to take care of the potential conflicts between the two
>> solutions.
>
> As I understand it, the JEP process takes some time and right now
> proposed changes *might* make it into JDK10?     Do you really want to
> do multiple JEPs to handle multiple new Edwards and Montgomery curves?
>
It really depends per my understanding.  If I have a good idea, I would
do it all in one JEP.  Otherwise, I may do it step by step so that the
high priority requirements are not delayed before I have a mature
solution to meet more requirements.

> If we can hide most of this under the current EC covers, then the
> implementations can just implement the plugin interface and do that now.
>
You are right.  If everything goes smoothly, no public APIs update is
expected.  It's a kind of a provider implementation job, although some
external algorithm names may be defined (like "ECWithSecp256k1" or
"XDH") for this proposal.

Thanks & Regards,
Xuelei
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Michael StJohns
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.

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).


>
>>
>>>
>>> However, I'm not very sure of the compatibility impact (see above).
>>>
>>> 3. Where we are not now?
>>> Using named curves is popular.  There is a ECGenParameterSpec class
>>> using named curves:
>>>      ECGenParameterSpec​ ecgp =
>>>          new ECGenParameterSpec​(secp256r1);
>>>      KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
>>>      kpg.initialize(ecpg);
>>>      KeyPair kp = kpg.generateKeyPair​();
>>>
>>>      ECPublicKey pubKey = (ECPublicKey)kp.getPublic();
>>>      String keyAlgorithm = pubKey.getAlgorithm​();  // "EC"
>>>
>>> However, it is used for key generation only.  Once the keys are
>>> generated, there is no public API to know the name of the curve in
>>> ECKey.  ECKey.getAlgorithm() will return "EC" only. If it is
>>> required to known whether a key is of a named curve, the solution is
>>> not straightforward.
>>
>> This ties back to "getEncoded()" representations.  Under the hood, if
>> you do a getEncoded() there's a "which name does this parameter set
>> match up to" search which checks various tables for an OID and uses
>> that in an X.509 SPKI output object.  On input, the table lookup has
>> to see whether or not it understands the curve OID (or the key type
>> OID - depending).
>>
>> To deal with this without having to modify the internal parameter
>> tables I currently match keys against parameter sets that have known
>> OIDs.
>>
> I see.
>
>>>
>>> 4. A general proposal
>>> Support named curves could be a solution for #2 and #3 concerns
>>> above. For named curves, the parameters are defined explicitly. So,
>>> it is REQUIRED to have the public APIs for named curves' parameters
>>> any more. It can be something hidden in the implementation layer.  
>>> The key pair generation may looks like:
>>>
>>>     KeyPairGenerator kpg =
>>>         KeyPairGenerator.getInstance("ECWithSecp256k1");
>>>     KeyPair kp = kpg.generateKeyPair​();
>>>
>>>     PublicKey pubKey = kp.getPublic();
>>>     String keyAlgorithm = pubKey.getAlgorithm​();  // "ECWithSecp256k1"
>>>
>>> As no explicit parameters is required, the EllipticCurve issue for
>>> Edwards curve form and Montgomery curve form in #2 is not a issue
>>> any more here.
>>>
>>> The compatibility impact is limited as the name "ECWithSecp256k1" is
>>> not used in the past, and the Weierstrass form APIs, like
>>> ECKey/ECParameterSpec/EllipticCurve, are not necessarily to be used
>>> in this solution.
>>>
>>> The benefits: simplify the APIs for named curves (including the
>>> Weierstrass form), and simplify the support of named curves for
>>> Edwards curve form and Montgomery curve form.
>>>
>>> The disadvantages: no support of arbitrary curves (no surprise as
>>> this is a named curve solution), and new learn curve to use this new
>>> solution.
>>
>> Right now there are 3 major APIs  (JCA, PKCS11 and Microsoft CSP) and
>> at least 4 major representational domains (Raw, PKIX, XML and JSON).  
>> In the current situation, I can take a JCA EC Public key and convert
>> it to pretty much any of the other APIs or representations. For much
>> of the hardware based stuff (ie, smart cards), I go straight from JCA
>> into raw and vice versa. Assuming you left the "getEncoded()" stuff
>> in the API and the encoding was PKIX, I'd have to encode to PKIX,
>> decode the PKIX to extract the actual raw key or encode a PKIX blob
>> and hope that the KeyFactory stuff actually worked.
>>
>> It's not just support of arbitrary keys, but the ability to convert
>> things without having to do multiple steps or stages.
>>
> Good point!  It would be nice if transaction between two formats could
> be done simply.  Using X.509 encoding is doable as you said above, but
> maybe there are spaces to get improvements.
>
> I need more time to think about it.  Please let me know if any one
> have a solution to simplify the transaction if keeping use the
> proposed named curves solution.
>
>> Your solution would probably work reasonably well for TLS or IPSEC -
>> but would not work well for anything else.
>>
> Properly a little bit more than TLS and IPSEC, but definitely not
> everything else.
>
>>
>>>
>>> 5. Can be more aggressive?
>>> It looks amazing to support arbitrary curves for Edwards curve form
>>> and Montgomery curve form, as JDK did for Weierstrass form. However,
>>> because of the compatibility impact (see #2), a new set of
>>> algorithms names, interfaces and specs may be required.  It could be
>>> overloaded if the requirements are not so strong in practice.  If
>>> arbitrary curves support is strong, it can be re-considered in the
>>> future.
>>>
>>> Per my understanding, supporting named curves and arbitrary curves
>>> can be two things, and can be considered in different stages.
>>> However, the design needs to take care of the potential conflicts
>>> between the two solutions.
>>
>> As I understand it, the JEP process takes some time and right now
>> proposed changes *might* make it into JDK10?     Do you really want
>> to do multiple JEPs to handle multiple new Edwards and Montgomery
>> curves?
>>
> It really depends per my understanding.  If I have a good idea, I
> would do it all in one JEP.  Otherwise, I may do it step by step so
> that the high priority requirements are not delayed before I have a
> mature solution to meet more requirements.

There's doing it quickly and doing it right.  Not sure you can have both.

>
>> If we can hide most of this under the current EC covers, then the
>> implementations can just implement the plugin interface and do that now.
>>
> You are right.  If everything goes smoothly, no public APIs update is
> expected.  It's a kind of a provider implementation job, although some
> external algorithm names may be defined (like "ECWithSecp256k1" or
> "XDH") for this proposal.

Yup - but that's a registry entry rather than an implementation change.


>
> Thanks & Regards,
> Xuelei


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: JCA design for RFC 7748

Xuelei Fan-2
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
12
Loading...