Re: Question about migrating from d2i_ECPrivateKey() to d2i_PrivateKey(EVP_PKEY_EC, ...)

2022-11-24 Thread Viktor Dukhovni
On Tue, Nov 22, 2022 at 11:09:07AM -0600, Nico Williams wrote:

> > Not exactly, PKCS#8-based typing is used in d2i_PKCS8_PRIV_KEY_INFO()
> > (for unencrypted PKCS#8 blobs, so no password callback).  The
> > d2i_PrivateKey() function takes an explicit pkey_type instead.
> 
> Hmmm, well, d2i_PrivateKey() takes an explicit pkey_type, yes, but it's
> not sufficiently informative for ECDH, being just EVP_PKEY_EC.  Or are
> there more informative type values I've not discovered yet?  When I call
> d2i_PrivateKey(EVP_PKEY_EC, ...) it wants a PKCS#8 encoded private key.

Actually, it supports *both* the PKCS#8 and the legacy type-specific formats.

The algorithm-specific PEM key formats may not be defined for some newer
key types and are deprecated, so sure, you're supposed to use PKCS#8
whenever possible.

For EC private keys, the underlying legacy DER codecs are:

d2i_ECPrivateKey()
i2d_ECPrivateKey()

with signatures:

EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len);
int i2d_ECPrivateKey(const EC_KEY *a, unsigned char **out);

for d2i_ECPrivateKey(), you get back an EC_KEY() which you can convert
to an EVP_PKEY via the deprecated (copy vs. take ownership):

EVP_PKEY_set1_EC_KEY(3), or EVP_PKEY_assign_EC_KEY(3)

which direct you to EVP_PKEY_fromdata(3) (much scaffolding...).

However, d2i_PrivateKey(EVP_PKEY_EC, ...) given non-PKCS#8 input
internally tries:

static int old_ec_priv_decode(EVP_PKEY *pkey,
  const unsigned char **pder, int derlen)
{
EC_KEY *ec;

if ((ec = d2i_ECPrivateKey(NULL, pder, derlen)) == NULL)
return 0;
EVP_PKEY_assign_EC_KEY(pkey, ec);
return 1;
}

which does the expected thing without much fuss.  That said, you
mentioned ECDH in passing, so I'm not sure we're taking about the same
things...

-- 
Viktor.


Re: Question about migrating from d2i_ECPrivateKey() to d2i_PrivateKey(EVP_PKEY_EC, ...)

2022-11-22 Thread Viktor Dukhovni
On Tue, Nov 22, 2022 at 11:09:07AM -0600, Nico Williams wrote:

> > Not exactly, PKCS#8-based typing is used in d2i_PKCS8_PRIV_KEY_INFO()
> > (for unencrypted PKCS#8 blobs, so no password callback).  The
> > d2i_PrivateKey() function takes an explicit pkey_type instead.
> 
> Hmmm, well, d2i_PrivateKey() takes an explicit pkey_type, yes, but it's
> not sufficiently informative for ECDH, being just EVP_PKEY_EC.  Or are
> there more informative type values I've not discovered yet?  When I call
> d2i_PrivateKey(EVP_PKEY_EC, ...) it wants a PKCS#8 encoded private key.

Do you mean ECDH or ECDSA?  These are not exactly the same use case.
What are you actually doing?  Are you really doing static ECDH key
agreement?

-- 
VFiktor.


Re: Question about migrating from d2i_ECPrivateKey() to d2i_PrivateKey(EVP_PKEY_EC, ...)

2022-11-20 Thread Viktor Dukhovni
On Sun, Nov 20, 2022 at 02:12:34PM -0600, Nico Williams wrote:

> > Generally, I would expect d2i_... to automatically detect the algorithm
> > when tagged with a suitable OIDs, and so d2i_AutoPrivateKey() could
> > often work, but if you know the expected key type, you can ask for
> > that explicitly with d2i_PrivateKey().
> 
> So, d2i_PrivateKey() wants a PKCS#8 wrapper so it can figure out what
> the type of the private key blob is.

Not exactly, PKCS#8-based typing is used in d2i_PKCS8_PRIV_KEY_INFO()
(for unencrypted PKCS#8 blobs, so no password callback).  The
d2i_PrivateKey() function takes an explicit pkey_type instead.

> On the other hand, d2i_PublicKey() wants the input key to indicate the
> type of public key to import.  A strange asymmetry, but it works.
> Staring at Postfix and OpenSSL code helped.

For X.509 SPKI public keys (the ones you generally want to use) the right
interface is d2i_PUBKEY, not d2i_PublicKey().

-- 
Viktor.


Re: Question about migrating from d2i_ECPrivateKey() to d2i_PrivateKey(EVP_PKEY_EC, ...)

2022-11-18 Thread Viktor Dukhovni
On Fri, Nov 18, 2022 at 11:33:08PM -0600, Nico Williams wrote:
> On Fri, Nov 18, 2022 at 04:53:44PM -0600, Nico Williams wrote:
> > I can't use d2i_PrivateKey() because that requires an existing
> > EVP_PKEY * that has the group already set.
> 
> Although, that's just what's documented.  From code inspection, if the
> parameters are found in the encoded private key, then the group will be
> set internally and no error will be returned.

Often, if you want a clear example of OpenSSL API usage, one place to
look is the Postfix "tls" library.  In this case:


https://github.com/vdukhovni/postfix/blob/master/postfix/src/tls/tls_certkey.c#L245-L266

https://github.com/vdukhovni/postfix/blob/master/postfix/src/tls/tls_certkey.c#L363-L370

Postfix does not do much with low-level crypto, but it exercises a
non-trivial chunk of the certificate and TLS API surface, ECDH/DH
setup and digests.

Generally, I would expect d2i_... to automatically detect the algorithm
when tagged with a suitable OIDs, and so d2i_AutoPrivateKey() could
often work, but if you know the expected key type, you can ask for
that explicitly with d2i_PrivateKey().

You don't need to pass an existing key.  Just pass NULL for
(EVP_PKEY **) pointer, and let OpenSSL return a freshly allocated
key:

EVP_PKEY *key;

key = d2i_PrivateKey(type, NULL, ...);
key = d2i_AutoPrivateKey(NULL, ...);

I strive to also check that the buffer pointer advanced by the expected
length (no "left-over" data):


https://github.com/vdukhovni/postfix/blob/master/postfix/src/tls/tls_certkey.c#L293-L306

-- 
Viktor.