#32 Supporting standard ECPublicKey and ECPrivateKey interfaces
Closed: fixed 4 years ago by cipherboy. Opened 5 years ago by edewata.


We face a few challenges in implementing this because of the mismatch between Java and NSS. Besides the obvious (supporting getS() likely won't happen for similar reasons as to why getPrivateExponent() isn't supported in the RSA equivalents), some of the other problems are discussed below.

What we Have (in JSS and NSS)

References to SECKEYPrivateKey and SECKEYPublicKey. The Public Key does have the publicValue member, which is an "encoded point", though it appears to lack documentation of how it is encoded, other than DER encoding. I'm guessing it is uncompressed.

The SECEYECParams structure is opaque (well, it appears to be DER encoded... Lovely!). From here we can call SECKEY_GetECCOid(...) to get the curve's OID, but we still need a way to go from SECKEYECPublicKey (or the Private key!) to SECKEYECParams....

Also missing is the generator of the curve and any way to identify the OID of the public key...

What we need (in Java)

The Java interfaces want us to provide an implementation of getParams(). This returns an ECParameterSpec, which in turn requires describing the EllipticCurve and the ECPoint of the curve's generator.

The most common usages of getGenerator() seem to be with equals() to see if it is in the CurveDB and is a known curve. In KeyUtil, getOrder is called.

We also need an implementation of getW() for public keys. This is utilized in ECDHKeyAgreement, among other places. However, it is an ECPoint again, which only seems to support a constructor with a pair of BigIntegers, and no other encodings.

Solutions

There are two potential solutions that I can see:

Potential Solution 1: DER {en,de}codings?

What remains unclear is if we can use AlgorithmParameters to accomplish what we want. The pseudo-code would look like this:

public ECParameterSpec getParams() {
    byte[] encoded_params = getParamsNative();
    AlgorithmParameters params = ???
    params.init(encoded_params);
    return params.getParameterSpec(ECParameterSpec);
}

The problem with the above approach is generating a AlgorithmParameters instance and whether or not the getParamsNative() call can return stuff in the correct format.

Potential Solution 2: Maintain our own list of Curves...

A lot of the material here is dependent on the curve, not the underlying algorithm. We'd want to provide a Curve-lookup mechanism and return parameters common to that curve, probably based on OID. We can sync it by a lookup table in Java/C similar to the (new) TLS Algorithm list. We can then augment the data returned by the Curve lookup (generator, curve, order, etc.) by the information in the Public/Private key as necessary.

Problems

Some of the code in the JDK requires the curve to be a Named Curve (for some reason), however, X25519 isn't a known curve, which is well, a problem. I'm not sure if we can ask them to standardize this curve, but to my knowledge it is neither in JDK8 nor JDK11, so perhaps unlikely for inclusion, especially before it is standardized by NIST for inclusion in FIPS. I'm also not sure if this means JSSE doesn't support x25519 at all for either handshakes or for CA keys.

Getting the public key from the private key might be a touch hard. Though, there is SECKEY_ConvertToPublicKey(...).

Metadata Update from @cipherboy:
- Custom field component adjusted to None
- Custom field feature adjusted to None
- Custom field origin adjusted to None
- Custom field proposedmilestone adjusted to None
- Custom field proposedpriority adjusted to None
- Custom field reviewer adjusted to None
- Custom field type adjusted to None
- Custom field version adjusted to None

5 years ago

Ok, so I've gotten the following to work on my add-ecpoint branch:

  • PK11PublicKey now implements ECPublicKey. This gives us getParams() and getW(). This is an API breaking change as getW previously returned a BigInteger, which IMO, is kinda silly.
  • ECCurve is now an Enum of curves. This will let us map between OIDs, Names, and curve data. Some effort will need to be spent to cultivate this database, but it is at least reusable by others since it is in the standard formats. We can eventually update PK11KeyGenerator to use this.
  • PK11PrivateKey is the sticking point still.
    • We'll likely end up using the SECKEY_ConvertToPublicKey for now (to implement getParams() via the public key).
    • We'll probably have to just return null from getS() like the PK11RSAPrivateKey key does.

If the API is not going to be backward compatible we should consider using a new JSS minor version number (i.e. 4.7.x).

Right, but check the version history on this:

Note though that "standard interface" is in quotes -- it never implemented ECPublicKey fully -- the return type of getW() was always wrong. IMO, the current return type is useless and misleading: it was never a BigInteger, it was a BigInteger which stored a byte[], which in turn was the ANSI X9.62 ECPoint value Q (a pair, (x, y) of values on a finite field), in something that vaguely looks like DER encoding.

In our code base and in Candlepin, nobody uses getW() for that reason. We don't need to worry about most other usages of getW() because nobody's trying to use it via the standard interface (ECPublicKey) yet, because it isn't an interface we implement yet. Nbody can rely on this, as-is.

I'm fine bumping to v4.7 on master, but I'd prefer to backport this to older branches if we can, and we can't cut a new major release out of the v4.4.x series. If we do that, there's no point in bumping to v4.7 on master.

Ah OK, if it never worked properly before it's not necessary to introduce JSS 4.7. Thanks for looking into this!

Metadata Update from @cipherboy:
- Issue close_status updated to: fixed
- Issue status updated to: Closed (was: Open)

4 years ago

Login to comment on this ticket.

Metadata