Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

X509* and Extract Public Key?

948 views
Skip to first unread message

Jeffrey Walton

unread,
Feb 10, 2013, 10:12:05 PM2/10/13
to
Hi All,

I'm trying to extract a public key (subjectPublicKeyInfo) form an X509
certificate.

Should I look for the subjectPublicKeyInfo in X509_EXTENSION_get_object?

What is the easiest (or recommended) way?

Jeff
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openss...@openssl.org
Automated List Manager majo...@openssl.org

Daniel Black

unread,
Feb 10, 2013, 11:31:07 PM2/10/13
to
from apps/x509.c in the openssl source:

x=load_cert(bio_err,infile,informat,NULL,e,"Certificate");
...

EVP_PKEY *pkey;

pkey=X509_get_pubkey(x);
if (pkey == NULL)
{
BIO_printf(bio_err,"Error getting public key\n");
ERR_print_errors(bio_err);
goto end;
}
PEM_write_bio_PUBKEY(STDout, pkey);

Jeffrey Walton

unread,
Feb 11, 2013, 12:01:49 AM2/11/13
to
On Sun, Feb 10, 2013 at 11:31 PM, Daniel Black
<danie...@internode.on.net> wrote:
> On 11/02/13 14:12, Jeffrey Walton wrote:
>> Hi All,
>>
>> I'm trying to extract a public key (subjectPublicKeyInfo) form an X509
>> certificate.
>>
>
> from apps/x509.c in the openssl source:
>
> x=load_cert(bio_err,infile,informat,NULL,e,"Certificate");
> ...
>
> EVP_PKEY *pkey;
>
> pkey=X509_get_pubkey(x);
> if (pkey == NULL)
> {
> BIO_printf(bio_err,"Error getting public key\n");
> ERR_print_errors(bio_err);
> goto end;
> }
> PEM_write_bio_PUBKEY(STDout, pkey);
Thanks Daniel. I found those after sending the email by grepping
through s_client.c.

Is there anything built into OpenSSL to write out a DER encoding of
subjectPublicKeyInfo?

Viktor Dukhovni

unread,
Feb 11, 2013, 12:41:22 AM2/11/13
to
On Mon, Feb 11, 2013 at 12:01:49AM -0500, Jeffrey Walton wrote:

> >> I'm trying to extract a public key (subjectPublicKeyInfo) form an X509
> >> certificate.
> >
> > from apps/x509.c in the openssl source:
> >
> > EVP_PKEY *pkey;
> >
> > pkey=X509_get_pubkey(x);

This is not the subjectPublicKeyInfo. It is just the key bits, sans
algorithm and parameters. A common pitfall is to mistake this for
the subjectPublicKeyInfo or to assume that X509_pubkey_digest()
returns the digest of the subjectPublicKeyInfo.

> Is there anything built into OpenSSL to write out a DER encoding of
> subjectPublicKeyInfo?

X509 *cert
int len;
char *buf;
char *buf2;

len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
buf2 = buf = OPENSSL_malloc(len);
if (buff == NULL) {
/* Out of memory */
... report the error ...
}
i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **)&buf2);
if (buf2 - buf != len) {
/* Should never happen: unexpected encoded length */
OPENSSL_free(buf);
... report the error ...
}

/* buf[0..len-1] now contain the ASN.1 DER-encoded subjectPublicKeyInfo */
... use it ...

OPENSSL_free(buf);

--
Viktor.

Jeffrey Walton

unread,
Feb 11, 2013, 3:04:08 AM2/11/13
to
Thanks Victor, perfect.

I seem to recall Viega, Messier and Chandra covered that. I wish I had
that book with me now......

Jeff

Dave Thompson

unread,
Feb 11, 2013, 5:15:53 PM2/11/13
to
> From: owner-ope...@openssl.org On Behalf Of Viktor Dukhovni
> Sent: Monday, 11 February, 2013 00:41

> On Mon, Feb 11, 2013 at 12:01:49AM -0500, Jeffrey Walton wrote:
>
> > >> I'm trying to extract a public key (subjectPublicKeyInfo)
> > >> form an X509 certificate.
> > >
> > > from apps/x509.c in the openssl source:
> > >
> > > EVP_PKEY *pkey;
> > >
> > > pkey=X509_get_pubkey(x);
>
> This is not the subjectPublicKeyInfo. It is just the key bits, sans
> algorithm and parameters. A common pitfall is to mistake this for
> the subjectPublicKeyInfo or to assume that X509_pubkey_digest()
> returns the digest of the subjectPublicKeyInfo.
>
Not really. EVP_PKEY has the algorithm, parameters if any, and key
pulled apart and converted to OpenSSL form, but they are all there.

Yes, X509_pubkey_digest is the digest of only the "actual key"
bitstring, as required for SKI (and AKI), not the whole pubkeyinfo.
It works directly on the cert->key->public_key (bitstring) and has
no relationship to X509_get_pubkey except a similar name.

> > Is there anything built into OpenSSL to write out a DER encoding of
> > subjectPublicKeyInfo?

> X509 *cert
> int len;
> char *buf;
> char *buf2;
>
> len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
> buf2 = buf = OPENSSL_malloc(len);
> if (buff == NULL) {
Obviously should be buf or buf2.

> /* Out of memory */
> ... report the error ...
> }
> i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned
> char **)&buf2);
Obviously should be cert. I would just make buf and buf2
unsigned char* in the first place; they point to DER data
which should not be treated as text anyway (i.e. should not
be puts() or strlen() or strcmp() etc.)

> if (buf2 - buf != len) {
> /* Should never happen: unexpected encoded length */
> OPENSSL_free(buf);
> ... report the error ...
> }

To "write out" to a file, don't need to manage a buffer explicitly,
can just i2d_X509_PUBKEY_{fp,bio} in one step.

Also i2d_$alg?PUBKEY (and PEM_write_$alg?PUBKEY) write pubkeyinfo
from several OpenSSL internal structs including EVP_PKEY. But to
just take existing info from a cert, your approach is more direct.

Jeffrey Walton

unread,
Feb 11, 2013, 11:03:38 PM2/11/13
to
On Mon, Feb 11, 2013 at 5:15 PM, Dave Thompson <dtho...@prinpay.com> wrote:
>> From: owner-ope...@openssl.org On Behalf Of Viktor Dukhovni
>> Sent: Monday, 11 February, 2013 00:41
>
>> On Mon, Feb 11, 2013 at 12:01:49AM -0500, Jeffrey Walton wrote:
>>
>> > >> I'm trying to extract a public key (subjectPublicKeyInfo)
>> > >> form an X509 certificate.
>> > >
>> > > from apps/x509.c in the openssl source:
>> > >
>> > > EVP_PKEY *pkey;
>> > >
>> > > pkey=X509_get_pubkey(x);
>>
>> This is not the subjectPublicKeyInfo. It is just the key bits, sans
>> algorithm and parameters. A common pitfall is to mistake this for
>> the subjectPublicKeyInfo or to assume that X509_pubkey_digest()
>> returns the digest of the subjectPublicKeyInfo.
>>
> Not really. EVP_PKEY has the algorithm, parameters if any, and key
> pulled apart and converted to OpenSSL form, but they are all there.
>
> ...
>
> To "write out" to a file, don't need to manage a buffer explicitly,
> can just i2d_X509_PUBKEY_{fp,bio} in one step.
Unfortunately, it appears many of those functions (macros?) are
undocumented. But I kind of know they exist, and have come across them
in s_client.c and x509.c.

https://www.google.com/#q=i2d_X509_PUBKEY+site:openssl.org

> Also i2d_$alg?PUBKEY (and PEM_write_$alg?PUBKEY) write pubkeyinfo
> from several OpenSSL internal structs including EVP_PKEY. But to
> just take existing info from a cert, your approach is more direct.
It also has the benefit of direct memory comparison without the need for BIOs.

Since I was pinning, I needed a standard presentation format to
compare the public key offered by the server with the public key I
expect (embedded within the application). I had that with PKCS#1
format and ASN.1 notation.

I could write the server's public key to a memory BIO; but I could not
load the expected key in memory from a file BIO; and there was no
BIO_cmp_data(server, file) to tell me if there was a difference in
bits (in constant time of the larger, FTW!).

In the end, it was most expedient to simply use (1)
i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert)) on the server's
certificate, (2) fopen/fseek/ftell/fread on the embedded public key,
and then (3) memcmp.

Sorry about not mentioning pinning sooner. I did not want to distract
folks from the task at hand.

Jeff

Dave Thompson

unread,
Feb 13, 2013, 12:49:13 AM2/13/13
to
> From: owner-ope...@openssl.org On Behalf Of Jeffrey Walton
> Sent: Monday, 11 February, 2013 23:04

Some minor points:

> On Mon, Feb 11, 2013 at 5:15 PM, Dave Thompson <dtho...@prinpay.com>
wrote:

> >> On Mon, Feb 11, 2013 at 12:01:49AM -0500, Jeffrey Walton wrote:
<snip: extract subjectPublicKeyInfo from X509 cert>

> > To "write out" to a file, don't need to manage a buffer explicitly,
> > can just i2d_X509_PUBKEY_{fp,bio} in one step.

> Unfortunately, it appears many of those functions (macros?) are
> undocumented. But I kind of know they exist, and have come across them
> in s_client.c and x509.c.
>
All i2d_$thing{,_fp,_bio}, and d2i_, work the same ways. Some do
processing on the internal data before it is encoded or after it
is decoded, but not $thing's that are just ASN.1 structures like
X509_PUBKEY. Similarly all of the PEM_{write,read}[_bio]_$thing.

i2d_ and d2i_ are real functions, mostly implemented by one call
to a generic routine with a compiled-in description of the ASN.1.
Similarly PEM_{write,read} are real functions declared by macros
mostly implemented by macros which call a generic routine.

> > Also i2d_$alg?PUBKEY (and PEM_write_$alg?PUBKEY) write pubkeyinfo
> > from several OpenSSL internal structs including EVP_PKEY. But to
> > just take existing info from a cert, your approach is more direct.

> It also has the benefit of direct memory comparison without
> the need for BIOs.
>
I took your "write out" to mean to a file. As noted below you can
use a mem-BIO for memory, but you don't need it the way you need
a FILE* or file-BIO for a file.

> Since I was pinning, I needed a standard presentation format to
> compare the public key offered by the server with the public key I
> expect (embedded within the application). I had that with PKCS#1
> format and ASN.1 notation.
>
Not needed; you could get both keys in EVP_PKEY form and use
EVP_PKEY_cmp. But DER works too. (Not ASN.1 by itself; there
are other ASN.1 encodings that you can't just memcmp.)

I assume you understand that PKCS#1 format is only part of
SubjectPublicKeyInfo though a big part, so not memcmpable as is.

> I could write the server's public key to a memory BIO; but I could not
> load the expected key in memory from a file BIO; and there was no
> BIO_cmp_data(server, file) to tell me if there was a difference in
> bits (in constant time of the larger, FTW!).
>
Yes, not quite, and yes.

> In the end, it was most expedient to simply use (1)
> i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert)) on the server's
> certificate, (2) fopen/fseek/ftell/fread on the embedded public key,
> and then (3) memcmp.
>
For (1) you can write to a mem-BIO and then read the contents with
BIO_get_mem_data (which despite the name actually gets a pointer and
length) or BIO_get_mem_ptr (which gets a "fat" pointer). For the file
you could explicitly copy from a file-read-BIO to a mem-BIO and then
use those contents, but that's reaching the point of silliness. As
above, for memory (and not PEM) there is no real need for BIOs.

> Sorry about not mentioning pinning sooner. I did not want to distract
> folks from the task at hand.
>

0 new messages