An utility function for getting fingerprint from X.509 certificate
has been introduced. Implementation only provided using gnutls.
Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com>
---
crypto/meson.build | 4 ++
crypto/x509-utils.c | 75 +++++++++++++++++++++++++++++++++++++
include/crypto/x509-utils.h | 22 +++++++++++
3 files changed, 101 insertions(+)
create mode 100644 crypto/x509-utils.c
create mode 100644 include/crypto/x509-utils.h
diff --git a/crypto/meson.build b/crypto/meson.build
index c46f9c22a7..735635de1f 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -24,6 +24,10 @@ crypto_ss.add(files(
'rsakey.c',
))
+if gnutls.found()
+ crypto_ss.add(files('x509-utils.c'))
+endif
+
if nettle.found()
crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c'))
if hogweed.found()
diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
new file mode 100644
index 0000000000..593eb8968b
--- /dev/null
+++ b/crypto/x509-utils.c
@@ -0,0 +1,75 @@
+/*
+ * X.509 certificate related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "crypto/x509-utils.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/x509.h>
+
+static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
+ [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
+ [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
+ [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
+ [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
+ [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
+ [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
+ [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
+};
+
+int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
+ QCryptoHashAlgorithm alg,
+ uint8_t *result,
+ size_t *resultlen,
+ Error **errp)
+{
+ int ret;
+ gnutls_x509_crt_t crt;
+ gnutls_datum_t datum = {.data = cert, .size = size};
+
+ if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) {
+ error_setg(errp, "Unknown hash algorithm");
+ return -1;
+ }
+
+ if (result == NULL) {
+ error_setg(errp, "No valid buffer given");
+ return -1;
+ }
+
+ gnutls_x509_crt_init(&crt);
+
+ if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) {
+ error_setg(errp, "Failed to import certificate");
+ goto cleanup;
+ }
+
+ ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]);
+ if (*resultlen < ret) {
+ error_setg(errp,
+ "Result buffer size %zu is smaller than hash %d",
+ *resultlen, ret);
+ goto cleanup;
+ }
+
+ if (gnutls_x509_crt_get_fingerprint(crt,
+ qcrypto_to_gnutls_hash_alg_map[alg],
+ result, resultlen) != 0) {
+ error_setg(errp, "Failed to get fingerprint from certificate");
+ goto cleanup;
+ }
+
+ return 0;
+
+ cleanup:
+ gnutls_x509_crt_deinit(crt);
+ return -1;
+}
diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
new file mode 100644
index 0000000000..4210dfbcfc
--- /dev/null
+++ b/include/crypto/x509-utils.h
@@ -0,0 +1,22 @@
+/*
+ * X.509 certificate related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef QCRYPTO_X509_UTILS_H
+#define QCRYPTO_X509_UTILS_H
+
+#include "crypto/hash.h"
+
+int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
+ QCryptoHashAlgorithm hash,
+ uint8_t *result,
+ size_t *resultlen,
+ Error **errp);
+
+#endif
--
2.39.2
On Fri, Sep 06, 2024 at 01:57:30AM +0600, Dorjoy Chowdhury wrote: > An utility function for getting fingerprint from X.509 certificate > has been introduced. Implementation only provided using gnutls. > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > --- > crypto/meson.build | 4 ++ > crypto/x509-utils.c | 75 +++++++++++++++++++++++++++++++++++++ > include/crypto/x509-utils.h | 22 +++++++++++ > 3 files changed, 101 insertions(+) > create mode 100644 crypto/x509-utils.c > create mode 100644 include/crypto/x509-utils.h > +int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > + QCryptoHashAlgorithm alg, > + uint8_t *result, > + size_t *resultlen, > + Error **errp) > +{ > + int ret; > + gnutls_x509_crt_t crt; > + gnutls_datum_t datum = {.data = cert, .size = size}; > + > + if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) { > + error_setg(errp, "Unknown hash algorithm"); > + return -1; > + } > + > + if (result == NULL) { > + error_setg(errp, "No valid buffer given"); > + return -1; > + } > + > + gnutls_x509_crt_init(&crt); > + > + if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) { > + error_setg(errp, "Failed to import certificate"); > + goto cleanup; > + } > + > + ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > + if (*resultlen < ret) { > + error_setg(errp, > + "Result buffer size %zu is smaller than hash %d", > + *resultlen, ret); > + goto cleanup; > + } > + > + if (gnutls_x509_crt_get_fingerprint(crt, > + qcrypto_to_gnutls_hash_alg_map[alg], > + result, resultlen) != 0) { > + error_setg(errp, "Failed to get fingerprint from certificate"); > + goto cleanup; > + } > + > + return 0; > + > + cleanup: > + gnutls_x509_crt_deinit(crt); > + return -1; > +} This fails to call gnutls_x509_crt_deinit in the success path. I'm going to squash in the following change: diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c index 593eb8968b..6e157af76b 100644 --- a/crypto/x509-utils.c +++ b/crypto/x509-utils.c @@ -31,7 +31,8 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, size_t *resultlen, Error **errp) { - int ret; + int ret = -1; + int hlen; gnutls_x509_crt_t crt; gnutls_datum_t datum = {.data = cert, .size = size}; @@ -52,11 +53,11 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, goto cleanup; } - ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); - if (*resultlen < ret) { + hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); + if (*resultlen < hlen) { error_setg(errp, "Result buffer size %zu is smaller than hash %d", - *resultlen, ret); + *resultlen, hlen); goto cleanup; } @@ -67,9 +68,9 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, goto cleanup; } - return 0; + ret = 0; cleanup: gnutls_x509_crt_deinit(crt); - return -1; + return ret; } With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On 6/9/24 15:50, Daniel P. Berrangé wrote: > On Fri, Sep 06, 2024 at 01:57:30AM +0600, Dorjoy Chowdhury wrote: >> An utility function for getting fingerprint from X.509 certificate >> has been introduced. Implementation only provided using gnutls. >> >> Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> >> --- >> crypto/meson.build | 4 ++ >> crypto/x509-utils.c | 75 +++++++++++++++++++++++++++++++++++++ >> include/crypto/x509-utils.h | 22 +++++++++++ >> 3 files changed, 101 insertions(+) >> create mode 100644 crypto/x509-utils.c >> create mode 100644 include/crypto/x509-utils.h > > >> +int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, >> + QCryptoHashAlgorithm alg, >> + uint8_t *result, >> + size_t *resultlen, >> + Error **errp) >> +{ >> + int ret; >> + gnutls_x509_crt_t crt; >> + gnutls_datum_t datum = {.data = cert, .size = size}; >> + >> + if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) { >> + error_setg(errp, "Unknown hash algorithm"); >> + return -1; >> + } >> + >> + if (result == NULL) { >> + error_setg(errp, "No valid buffer given"); >> + return -1; >> + } >> + >> + gnutls_x509_crt_init(&crt); >> + >> + if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) { >> + error_setg(errp, "Failed to import certificate"); >> + goto cleanup; >> + } >> + >> + ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); >> + if (*resultlen < ret) { >> + error_setg(errp, >> + "Result buffer size %zu is smaller than hash %d", >> + *resultlen, ret); >> + goto cleanup; >> + } >> + >> + if (gnutls_x509_crt_get_fingerprint(crt, >> + qcrypto_to_gnutls_hash_alg_map[alg], >> + result, resultlen) != 0) { >> + error_setg(errp, "Failed to get fingerprint from certificate"); >> + goto cleanup; >> + } >> + >> + return 0; >> + >> + cleanup: >> + gnutls_x509_crt_deinit(crt); >> + return -1; >> +} > > This fails to call gnutls_x509_crt_deinit in the success path. > > I'm going to squash in the following change: > > > diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c > index 593eb8968b..6e157af76b 100644 > --- a/crypto/x509-utils.c > +++ b/crypto/x509-utils.c > @@ -31,7 +31,8 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > size_t *resultlen, > Error **errp) > { > - int ret; > + int ret = -1; > + int hlen; > gnutls_x509_crt_t crt; > gnutls_datum_t datum = {.data = cert, .size = size}; > > @@ -52,11 +53,11 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > goto cleanup; > } > > - ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > - if (*resultlen < ret) { > + hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > + if (*resultlen < hlen) { > error_setg(errp, > "Result buffer size %zu is smaller than hash %d", > - *resultlen, ret); > + *resultlen, hlen); > goto cleanup; > } > > @@ -67,9 +68,9 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > goto cleanup; > } > > - return 0; > + ret = 0; > > cleanup: > gnutls_x509_crt_deinit(crt); > - return -1; > + return ret; > } Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
On Fri, Sep 6, 2024 at 7:50 PM Daniel P. Berrangé <berrange@redhat.com> wrote: > > On Fri, Sep 06, 2024 at 01:57:30AM +0600, Dorjoy Chowdhury wrote: > > An utility function for getting fingerprint from X.509 certificate > > has been introduced. Implementation only provided using gnutls. > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > --- > > crypto/meson.build | 4 ++ > > crypto/x509-utils.c | 75 +++++++++++++++++++++++++++++++++++++ > > include/crypto/x509-utils.h | 22 +++++++++++ > > 3 files changed, 101 insertions(+) > > create mode 100644 crypto/x509-utils.c > > create mode 100644 include/crypto/x509-utils.h > > > > +int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > > + QCryptoHashAlgorithm alg, > > + uint8_t *result, > > + size_t *resultlen, > > + Error **errp) > > +{ > > + int ret; > > + gnutls_x509_crt_t crt; > > + gnutls_datum_t datum = {.data = cert, .size = size}; > > + > > + if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) { > > + error_setg(errp, "Unknown hash algorithm"); > > + return -1; > > + } > > + > > + if (result == NULL) { > > + error_setg(errp, "No valid buffer given"); > > + return -1; > > + } > > + > > + gnutls_x509_crt_init(&crt); > > + > > + if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) { > > + error_setg(errp, "Failed to import certificate"); > > + goto cleanup; > > + } > > + > > + ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > > + if (*resultlen < ret) { > > + error_setg(errp, > > + "Result buffer size %zu is smaller than hash %d", > > + *resultlen, ret); > > + goto cleanup; > > + } > > + > > + if (gnutls_x509_crt_get_fingerprint(crt, > > + qcrypto_to_gnutls_hash_alg_map[alg], > > + result, resultlen) != 0) { > > + error_setg(errp, "Failed to get fingerprint from certificate"); > > + goto cleanup; > > + } > > + > > + return 0; > > + > > + cleanup: > > + gnutls_x509_crt_deinit(crt); > > + return -1; > > +} > > This fails to call gnutls_x509_crt_deinit in the success path. > > I'm going to squash in the following change: > > > diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c > index 593eb8968b..6e157af76b 100644 > --- a/crypto/x509-utils.c > +++ b/crypto/x509-utils.c > @@ -31,7 +31,8 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > size_t *resultlen, > Error **errp) > { > - int ret; > + int ret = -1; > + int hlen; > gnutls_x509_crt_t crt; > gnutls_datum_t datum = {.data = cert, .size = size}; > > @@ -52,11 +53,11 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > goto cleanup; > } > > - ret = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > - if (*resultlen < ret) { > + hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]); > + if (*resultlen < hlen) { > error_setg(errp, > "Result buffer size %zu is smaller than hash %d", > - *resultlen, ret); > + *resultlen, hlen); > goto cleanup; > } > > @@ -67,9 +68,9 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size, > goto cleanup; > } > > - return 0; > + ret = 0; > > cleanup: > gnutls_x509_crt_deinit(crt); > - return -1; > + return ret; > } > > Thanks! The change looks good. Regards, Dorjoy
© 2016 - 2024 Red Hat, Inc.