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_ALG__MAX] = { 19 [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, 20 [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, 21 [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224, 22 [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, 23 [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384, 24 [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512, 25 [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160, 26 }; 27 28 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, 29 QCryptoHashAlgorithm 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