The OpenSSL library includes two very similar functions:

        int X509_digest(
                X509 *cert,
                const EVP_MD *digest,
                unsigned char *md,
                int *len);

        int X509_pubkey_digest(
                const X509 *cert,
                const EVP_MD *type,
                unsigned char *md,
                int *len)

The former generates the (raw binary form of) "fingerprint" of an
X.509 certificate, which is printed in hex for example by 

        $ openssl x509 -noout -fingerprint -<digest>

The latter I had assumed for some time produces the corresponding
public key fingerprint, but this turns out not to be case. Instead
of producing the digest of the full key (algorithm, parameters and
key data) as with:

        $ openssl x509 -noout -pubkey |
                openssl pkey -pubin -outform DER | 
                openssl dgst -<dgst> -c

it produces a digest of just the key data. I believe this matches
the digest used in constructing subject and authority key identifiers,
(usually with the digest set to SHA-1). While this digest is thus
potentially useful its security properties are entirely different
from the similar X509_digest() function.

The full certificate digest, with a suitably second-preimage
resistant hash can be used a compact proxy for the full certificate,
and some applications (e.g. RFC 6698 DANE TLSA) encourage or at least
support the use of digests as secure replacements for the underlying
certificate.

The same can be said of the digest of the full public key (algorithm,
parameters and key data), when one wants to trust the holder of
the private key rather than any particular CA's name binding to
that key.  And indeed RFC 6698 also supports public-key fingerprint
security bindings.

In developing preliminary RFC 6698 support for Postfix, I was
surprised to find that the X509_pubkey_digest() function was not
the right tool. Instead I have to use:

    len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
    buf2 = buf = OPENSSL_malloc(len);
    i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **)&buf2);

and then additional EVP functions to compute the digest of "buf" (can't
use buf2 as this pointer is set to "buf + len" by i2d_X509_PUBKEY()).

This is a rather non-obvious interface, and X509_get_X509_PUBKEY() is
not documented.

I'd like to request that the existing X509_pubkey_digest() be
renamed to something like x509_pubkey_identifier() just for
internal use by the library.

At the same time, it would be very useful to have a manual page
that describes X509_digest() and a new X509_pkey_digest() each
of which produce intuitive results.

The existing X509_pubkey_digest() can easily mislead even experienced
OpenSSL users since key data that is safe for one algorithm and
set of parameters may be entirely unsafe with another algorithm or
set of parameters.

-- 
        Viktor.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to