xref: /openbmc/qemu/crypto/x509-utils.c (revision b4f0b382fe241a1c57ab42ec538f49db45193df7)
1 /*
2  * X.509 certificate related helpers
3  *
4  * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or
7  * (at your option) any later version.  See the COPYING file in the
8  * top-level directory.
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "crypto/x509-utils.h"
14 #include <gnutls/gnutls.h>
15 #include <gnutls/crypto.h>
16 #include <gnutls/x509.h>
17 
18 static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
19     [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
20     [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_DIG_SHA1,
21     [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_DIG_SHA224,
22     [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_DIG_SHA256,
23     [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_DIG_SHA384,
24     [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_DIG_SHA512,
25     [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
26 };
27 
qcrypto_get_x509_cert_fingerprint(uint8_t * cert,size_t size,QCryptoHashAlgo alg,uint8_t * result,size_t * resultlen,Error ** errp)28 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
29                                       QCryptoHashAlgo alg,
30                                       uint8_t *result,
31                                       size_t *resultlen,
32                                       Error **errp)
33 {
34     int ret = -1;
35     int hlen;
36     gnutls_x509_crt_t crt;
37     gnutls_datum_t datum = {.data = cert, .size = size};
38 
39     if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) {
40         error_setg(errp, "Unknown hash algorithm");
41         return -1;
42     }
43 
44     if (result == NULL) {
45         error_setg(errp, "No valid buffer given");
46         return -1;
47     }
48 
49     if (gnutls_x509_crt_init(&crt) < 0) {
50         error_setg(errp, "Unable to initialize certificate: %s",
51                    gnutls_strerror(ret));
52         return -1;
53     }
54 
55     if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) {
56         error_setg(errp, "Failed to import certificate");
57         goto cleanup;
58     }
59 
60     hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]);
61     if (*resultlen < hlen) {
62         error_setg(errp,
63                    "Result buffer size %zu is smaller than hash %d",
64                    *resultlen, hlen);
65         goto cleanup;
66     }
67 
68     if (gnutls_x509_crt_get_fingerprint(crt,
69                                         qcrypto_to_gnutls_hash_alg_map[alg],
70                                         result, resultlen) != 0) {
71         error_setg(errp, "Failed to get fingerprint from certificate");
72         goto cleanup;
73     }
74 
75     ret = 0;
76 
77  cleanup:
78     gnutls_x509_crt_deinit(crt);
79     return ret;
80 }
81