Add support to retrieve the fingerprint of a public key from a cert.

Related-to: https://github.com/profanity-im/profanity/issues/2069
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
This commit is contained in:
Steffen Jaeckel
2025-10-31 16:03:26 +01:00
parent d38ecd5453
commit aab9cdd406
5 changed files with 46 additions and 14 deletions

View File

@@ -29,6 +29,17 @@
#include "parser.h"
#include "snprintf.h"
/** Define your own `STROPHE_STATIC_ASSERT` if your compiler doesn't support one
* of the below ones or define as noop if your compiler provides no replacement.
*/
#if !defined(STROPHE_STATIC_ASSERT)
#if (__STDC_VERSION__ >= 202000L)
#define STROPHE_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
#else
#define STROPHE_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#endif
#endif
/** handlers **/
#if (__STDC_VERSION__ >= 202000L)
typedef void *xmpp_void_handler;

View File

@@ -164,9 +164,13 @@ const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
"Expires On",
"Public Key Algorithm",
"Certificate Signature Algorithm",
"Fingerprint SHA-1",
"Fingerprint SHA-256",
"Certificate Fingerprint SHA-1",
"Certificate Fingerprint SHA-256",
"Public Key Fingerprint SHA-256",
};
STROPHE_STATIC_ASSERT(
ARRAY_SIZE(descriptions) == XMPP_CERT_ELEMENT_MAX,
"descriptions don't match the number of enum elements");
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return descriptions[elmnt];

View File

@@ -334,6 +334,12 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
size = sizeof(smallbuf);
gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, (void *)smallbuf,
&size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
strophe_strdup(ctx, buf);
strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);

View File

@@ -376,18 +376,26 @@ _get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
unsigned char buf[EVP_MAX_MD_SIZE];
unsigned int len;
int (*digest_fn)(const X509 *data, const EVP_MD *type, unsigned char *md,
unsigned int *len);
const EVP_MD *digest;
switch (el) {
case XMPP_CERT_FINGERPRINT_SHA1:
digest_fn = X509_digest;
digest = EVP_sha1();
break;
case XMPP_CERT_FINGERPRINT_SHA256:
digest_fn = X509_digest;
digest = EVP_sha256();
break;
case XMPP_CERT_PUBKEY_FINGERPRINT_SHA256:
digest_fn = X509_pubkey_digest;
digest = EVP_sha256();
break;
default:
return NULL;
}
if (X509_digest(err_cert, digest, buf, &len) != 0) {
if (digest_fn(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len);
return strophe_strdup(ctx, fingerprint);
@@ -475,6 +483,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_PUBKEY_FINGERPRINT_SHA256);
strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);

View File

@@ -251,17 +251,18 @@ typedef enum {
* @ingroup TLS
*/
typedef enum {
XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_PUBKEY_FINGERPRINT_SHA256, /**< SHA-256 fingerprint of pubkey */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
} xmpp_cert_element_t;
typedef struct {