Trying to get a public info for a certificate

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Trying to get a public info for a certificate

Daniel Pedraza
Hi guys!

I'm trying to upgrade an old C project from OpenSSL 1.0.2 to the newest 1.1.1 version. Everything's going smoothly, except for one little detail:

There's a part of the code where we're doing a sha256 hash of the public key of our certificate. On the older OpenSSL, we were able to get the public key by doing cert->cert_info->key->public_key->data. On the newer version, we no longer have access to the cert_info struct.

I tried doing:

EVP_PKEY * public_key = X509_get0_pubkey(cert);

this gives me an EVP_PKEY value, which I tried to convert to a char** by doing this:

unsigned char *buf, *p;
int len = i2d_PublicKey(public_key, NULL);
buf = OPENSSL_malloc(len);
p = buf;
i2d_PublicKey(public_key, &p);

This gives me a buffer with the correct length, but it seems like it has different data from what the public_key->data used to give me.

Granted, I am not very savvy with OpenSSL, or with ssl in general, so maybe I'm doing something wrong/dumb? I've spent a fair bit of time on the documentation/wiki but I can´t seem to find the answer. Seems to me like this should be something very straightforward?

Any help would be v much appreciated

-Daniel

Reply | Threaded
Open this post in threaded view
|

Re: Trying to get a public info for a certificate

Matt Caswell-2


On 03/06/2019 16:40, Daniel Pedraza wrote:

> Hi guys!
>
> I'm trying to upgrade an old C project from OpenSSL 1.0.2 to the newest 1.1.1
> version. Everything's going smoothly, except for one little detail:
>
> There's a part of the code where we're doing a sha256 hash of the public key of
> our certificate. On the older OpenSSL, we were able to get the public key by
> doing cert->cert_info->key->public_key->data. On the newer version, we no longer
> have access to the cert_info struct.
>
> I tried doing:
>
> EVP_PKEY * public_key = X509_get0_pubkey(cert);
>
> this gives me an EVP_PKEY value, which I tried to convert to a char** by doing this:
>
> unsigned char *buf, *p;
> int len = i2d_PublicKey(public_key, NULL);
> buf = OPENSSL_malloc(len);
> p = buf;
> i2d_PublicKey(public_key, &p);
>
> This gives me a buffer with the correct length, but it seems like it has
> different data from what the public_key->data used to give me.
>
> Granted, I am not very savvy with OpenSSL, or with ssl in general, so maybe I'm
> doing something wrong/dumb? I've spent a fair bit of time on the
> documentation/wiki but I can´t seem to find the answer. Seems to me like this
> should be something very straightforward?
>
> Any help would be v much appreciated

Probably what you want is the X509_get0_pubkey_bitstr() function. This gives you
the data as an ASN1_BIT_STRING structure (i.e. what used to be accessible as
cert->cert_info->key->public_key).

Matt

Reply | Threaded
Open this post in threaded view
|

Re: Trying to get a public info for a certificate

Viktor Dukhovni
In reply to this post by Daniel Pedraza
On Mon, Jun 03, 2019 at 10:40:02AM -0500, Daniel Pedraza wrote:

> There's a part of the code where we're doing a sha256 hash of the public
> key of our certificate. On the older OpenSSL, we were able to get the
> public key by doing cert->cert_info->key->public_key->data. On the newer
> version, we no longer have access to the cert_info struct.
>
> I tried doing:
>
> EVP_PKEY * public_key = X509_get0_pubkey(cert);
>
> this gives me an EVP_PKEY value, which I tried to convert to a char** by
> doing this:
>
> unsigned char *buf, *p;
> int len = i2d_PublicKey(public_key, NULL);
> buf = OPENSSL_malloc(len);
> p = buf;
> i2d_PublicKey(public_key, &p);

To obtain the serialized buffer 'buf' of length 'len' that you
can then checksum, there are two essentially equivalent approaches:

   1.   X509 *cert = ...;
        X509_PUBKEY *xpk = X509_get_X509_PUBKEY(cert);
        int len = i2d_X509_PUBKEY(xpk, NULL);
        unsigned char *buf = malloc(len); /* error check */
        unsigned char *buf2 = buf;

        i2d_X509_PUBKEY(xpk, &buf2);
        OPENSSL_assert(buf2 - buf == len);

   2.   X509 *cert = ...;
        EVP_PKEY *pkey = X509_get0_pubkey(cert);
        int len = i2d_PUBKEY(pkey, NULL);
        unsigned char *buf = malloc(len); /* error check */
        unsigned char *buf2 = buf;

        i2d_PUBKEY(pkey, &buf2);
        OPENSSL_assert(buf2 - buf == len);

The first approach avoids having to reconstruct (allocate, use and
free) the X509_PUBKEY (SPKI) from the underlying EVP_PKEY, so will
be slightly more efficient.

> This gives me a buffer with the correct length, but it seems like it has
> different data from what the public_key->data used to give me.

I don't recall what public_key->data contains, but if different it
was probably not the right thing to use, since you should be capturing
the complete SPKI structure (public key algorithm OID, any parameters
and the key data).  If it contains just the key bits, without the
algorithm and parameters, it is unwise to use that.

If needed for backwards-compatibility, you should be able to recover
the key bitstring with X509_get0_pubkey_bitstr(3), but you really
should not.  The SPKI is the right object to fingerprint.

--
        Viktor.
Reply | Threaded
Open this post in threaded view
|

Re: Trying to get a public info for a certificate

Daniel Pedraza
Thanks a lot, Matt and Viktor! You guys are absolutely right, X509_get0_pubkey_bitstr gives me the same struct that was once inside of cert_info->key->public_key.

@Viktor I had also tried your second approach (didn't know about the first one!) and for some reason it doesn't have the "correct" data. My guess is you're right and the application has been hashing the wrong thing all along. I will look into it.

Anyway, thanks a lot you guys, you are the best!

On Mon, Jun 3, 2019 at 11:31 AM Viktor Dukhovni <[hidden email]> wrote:
On Mon, Jun 03, 2019 at 10:40:02AM -0500, Daniel Pedraza wrote:

> There's a part of the code where we're doing a sha256 hash of the public
> key of our certificate. On the older OpenSSL, we were able to get the
> public key by doing cert->cert_info->key->public_key->data. On the newer
> version, we no longer have access to the cert_info struct.
>
> I tried doing:
>
> EVP_PKEY * public_key = X509_get0_pubkey(cert);
>
> this gives me an EVP_PKEY value, which I tried to convert to a char** by
> doing this:
>
> unsigned char *buf, *p;
> int len = i2d_PublicKey(public_key, NULL);
> buf = OPENSSL_malloc(len);
> p = buf;
> i2d_PublicKey(public_key, &p);

To obtain the serialized buffer 'buf' of length 'len' that you
can then checksum, there are two essentially equivalent approaches:

   1.   X509 *cert = ...;
        X509_PUBKEY *xpk = X509_get_X509_PUBKEY(cert);
        int len = i2d_X509_PUBKEY(xpk, NULL);
        unsigned char *buf = malloc(len);       /* error check */
        unsigned char *buf2 = buf;

        i2d_X509_PUBKEY(xpk, &buf2);
        OPENSSL_assert(buf2 - buf == len);

   2.   X509 *cert = ...;
        EVP_PKEY *pkey = X509_get0_pubkey(cert);
        int len = i2d_PUBKEY(pkey, NULL);
        unsigned char *buf = malloc(len);       /* error check */
        unsigned char *buf2 = buf;

        i2d_PUBKEY(pkey, &buf2);
        OPENSSL_assert(buf2 - buf == len);

The first approach avoids having to reconstruct (allocate, use and
free) the X509_PUBKEY (SPKI) from the underlying EVP_PKEY, so will
be slightly more efficient.

> This gives me a buffer with the correct length, but it seems like it has
> different data from what the public_key->data used to give me.

I don't recall what public_key->data contains, but if different it
was probably not the right thing to use, since you should be capturing
the complete SPKI structure (public key algorithm OID, any parameters
and the key data).  If it contains just the key bits, without the
algorithm and parameters, it is unwise to use that.

If needed for backwards-compatibility, you should be able to recover
the key bitstring with X509_get0_pubkey_bitstr(3), but you really
should not.  The SPKI is the right object to fingerprint.

--
        Viktor.