Re: Question about migrating from d2i_ECPrivateKey() to d2i_PrivateKey(EVP_PKEY_EC, ...)
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, ...)
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, ...)
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, ...)
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.