xref: /openbmc/qemu/crypto/x509-utils.c (revision 7d87775f)
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 
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     gnutls_x509_crt_init(&crt);
50 
51     if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) {
52         error_setg(errp, "Failed to import certificate");
53         goto cleanup;
54     }
55 
56     hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]);
57     if (*resultlen < hlen) {
58         error_setg(errp,
59                    "Result buffer size %zu is smaller than hash %d",
60                    *resultlen, hlen);
61         goto cleanup;
62     }
63 
64     if (gnutls_x509_crt_get_fingerprint(crt,
65                                         qcrypto_to_gnutls_hash_alg_map[alg],
66                                         result, resultlen) != 0) {
67         error_setg(errp, "Failed to get fingerprint from certificate");
68         goto cleanup;
69     }
70 
71     ret = 0;
72 
73  cleanup:
74     gnutls_x509_crt_deinit(crt);
75     return ret;
76 }
77