All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Farman <farman@linux.ibm.com>
To: qemu-devel@nongnu.org
Cc: qemu-s390x@nongnu.org, "Matthew Rosato" <mjrosato@linux.ibm.com>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Zhuoying Cai" <zycai@linux.ibm.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"Farhan Ali" <alifm@linux.ibm.com>,
	"Eric Farman" <farman@linux.ibm.com>
Subject: [PULL 10/37] crypto/x509-utils: Add helper functions for DIAG 320 subcode 2
Date: Wed, 26 Aug 2026 08:51:45 -0400	[thread overview]
Message-ID: <20260826125213.1901252-11-farman@linux.ibm.com> (raw)
In-Reply-To: <20260826125213.1901252-1-farman@linux.ibm.com>

From: Zhuoying Cai <zycai@linux.ibm.com>

Introduce new helper functions to extract certificate metadata:

qcrypto_x509_check_cert_times() - validates the certificate's validity period against the current time
qcrypto_x509_get_cert_key_id() - extracts the key ID from the certificate
qcrypto_x509_check_ecc_curve_p521() - determines the ECC public key algorithm uses P-521 curve

These functions provide support for metadata extraction and validity checking
for X.509 certificates.

Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20260730214624.2328883-9-zycai@linux.ibm.com
Signed-off-by: Eric Farman <farman@linux.ibm.com>
---
 crypto/x509-utils.c         | 236 ++++++++++++++++++++++++++++++++++++
 include/crypto/x509-utils.h |  51 ++++++++
 2 files changed, 287 insertions(+)

diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
index 369e7ca6af..543fc3007d 100644
--- a/crypto/x509-utils.c
+++ b/crypto/x509-utils.c
@@ -27,6 +27,16 @@ static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
     [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
 };
 
+static const int qcrypto_to_gnutls_keyid_flags_map[] = {
+    [QCRYPTO_HASH_ALGO_MD5] = -1,
+    [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_KEYID_USE_SHA1,
+    [QCRYPTO_HASH_ALGO_SHA224] = -1,
+    [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_KEYID_USE_SHA256,
+    [QCRYPTO_HASH_ALGO_SHA384] = -1,
+    [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_KEYID_USE_SHA512,
+    [QCRYPTO_HASH_ALGO_RIPEMD160] = -1,
+};
+
 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
                                       QCryptoHashAlgo alg,
                                       uint8_t *result,
@@ -122,6 +132,210 @@ cleanup:
     return ret;
 }
 
+int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp)
+{
+    int rc;
+    int ret = -1;
+    gnutls_x509_crt_t crt;
+    gnutls_datum_t datum = {.data = cert, .size = size};
+    time_t now = time(NULL);
+    time_t exp_time;
+    time_t act_time;
+
+    if (now == ((time_t)-1)) {
+        error_setg_errno(errp, errno, "Cannot get current time");
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_init(&crt);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    exp_time = gnutls_x509_crt_get_expiration_time(crt);
+    if (exp_time == ((time_t)-1)) {
+        error_setg(errp, "Failed to get certificate expiration time");
+        goto cleanup;
+    }
+    if (exp_time < now) {
+        error_setg(errp, "The certificate has expired");
+        goto cleanup;
+    }
+
+    act_time = gnutls_x509_crt_get_activation_time(crt);
+    if (act_time == ((time_t)-1)) {
+        error_setg(errp, "Failed to get certificate activation time");
+        goto cleanup;
+    }
+    if (act_time > now) {
+        error_setg(errp, "The certificate is not yet active");
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    return ret;
+}
+
+static int qcrypto_x509_get_pk_algorithm(uint8_t *cert, size_t size, Error **errp)
+{
+    int rc;
+    int ret = -1;
+    unsigned int bits;
+    gnutls_x509_crt_t crt;
+    gnutls_datum_t datum = {.data = cert, .size = size};
+
+    rc = gnutls_x509_crt_init(&crt);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_x509_crt_get_pk_algorithm(crt, &bits);
+    if (rc < 0) {
+        error_setg(errp, "Unknown public key algorithm %d", rc);
+        goto cleanup;
+    }
+
+    ret = rc;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    return ret;
+}
+
+int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
+                                 QCryptoHashAlgo hash_alg,
+                                 uint8_t **result,
+                                 size_t *resultlen,
+                                 Error **errp)
+{
+    int rc;
+    int ret = -1;
+    gnutls_x509_crt_t crt;
+    gnutls_datum_t datum = {.data = cert, .size = size};
+
+    if (hash_alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) {
+        error_setg(errp, "Unknown hash algorithm %d", hash_alg);
+        return ret;
+    }
+
+    if (hash_alg >= G_N_ELEMENTS(qcrypto_to_gnutls_keyid_flags_map) ||
+        qcrypto_to_gnutls_keyid_flags_map[hash_alg] == -1) {
+        error_setg(errp, "Unsupported key id flag %d", hash_alg);
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_init(&crt);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    *resultlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[hash_alg]);
+    if (*resultlen == 0) {
+        error_setg(errp, "Failed to get hash algorithm length: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    *result = g_malloc0(*resultlen);
+    if (gnutls_x509_crt_get_key_id(crt,
+                                   qcrypto_to_gnutls_keyid_flags_map[hash_alg],
+                                   *result, resultlen) != 0) {
+        error_setg(errp, "Failed to get key ID from certificate");
+        g_clear_pointer(result, g_free);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    return ret;
+}
+
+static int qcrypto_x509_get_ecc_curve(uint8_t *cert, size_t size, Error **errp)
+{
+    int rc;
+    int ret = -1;
+    gnutls_x509_crt_t crt;
+    gnutls_datum_t datum = {.data = cert, .size = size};
+    gnutls_ecc_curve_t curve_id;
+    gnutls_datum_t x = {.data = NULL, .size = 0};
+    gnutls_datum_t y = {.data = NULL, .size = 0};
+
+    rc = gnutls_x509_crt_init(&crt);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
+        return ret;
+    }
+
+    rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_x509_crt_get_pk_ecc_raw(crt, &curve_id, &x, &y);
+    if (rc != 0) {
+        error_setg(errp, "Failed to get ECC public key curve: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    ret = curve_id;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    g_free(x.data);
+    g_free(y.data);
+    return ret;
+}
+
+int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
+{
+    int algo;
+    int curve_id;
+
+    algo = qcrypto_x509_get_pk_algorithm(cert, size, errp);
+    if (algo != GNUTLS_PK_ECDSA) {
+        return 0;
+    }
+
+    curve_id = qcrypto_x509_get_ecc_curve(cert, size, errp);
+    if (curve_id == -1) {
+        error_setg(errp, "Failed to get ECC curve");
+        return -1;
+    }
+
+    if (curve_id == GNUTLS_ECC_CURVE_INVALID) {
+        error_setg(errp, "Invalid ECC curve");
+        return -1;
+    }
+
+    return curve_id == GNUTLS_ECC_CURVE_SECP521R1;
+}
+
 #else /* ! CONFIG_GNUTLS */
 
 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
@@ -143,4 +357,26 @@ int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
     return -1;
 }
 
+int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp)
+{
+    error_setg(errp, "GNUTLS is required to get certificate times");
+    return -1;
+}
+
+int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
+                                 QCryptoHashAlgo hash_alg,
+                                 uint8_t **result,
+                                 size_t *resultlen,
+                                 Error **errp)
+{
+    error_setg(errp, "GNUTLS is required to get key ID");
+    return -1;
+}
+
+int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
+{
+    error_setg(errp, "GNUTLS is required to determine ecc curve");
+    return -1;
+}
+
 #endif /* ! CONFIG_GNUTLS */
diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
index 91ae79fb03..fcace73c49 100644
--- a/include/crypto/x509-utils.h
+++ b/include/crypto/x509-utils.h
@@ -40,4 +40,55 @@ int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
                                   size_t *resultlen,
                                   Error **errp);
 
+/**
+ * qcrypto_x509_check_cert_times
+ * @cert: pointer to the raw certificate data
+ * @size: size of the certificate
+ * @errp: error pointer
+ *
+ * Check whether the activation and expiration times of @cert
+ * are valid at the current time.
+ *
+ * Returns: 0 if the certificate times are valid,
+ *         -1 on error.
+ */
+int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp);
+
+/**
+ * qcrypto_x509_get_cert_key_id
+ * @cert: pointer to the raw certificate data
+ * @size: size of the certificate
+ * @hash_alg: the hash algorithm flag
+ * @result: output location for the allocated buffer for key ID
+ *          (the function allocates memory which must be freed by the caller)
+ * @resultlen: pointer to the size of the buffer
+ *             (will be updated with the actual size of key id)
+ * @errp: error pointer
+ *
+ * Retrieve the key ID from the @cert based on the specified @hash_alg.
+ *
+ * Returns: 0 if key ID was successfully stored in @result,
+ *         -1 on error.
+ */
+int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
+                                 QCryptoHashAlgo hash_alg,
+                                 uint8_t **result,
+                                 size_t *resultlen,
+                                 Error **errp);
+
+/**
+ * qcrypto_x509_check_ecc_curve_p521
+ * @cert: pointer to the raw certificate data
+ * @size: size of the certificate
+ * @errp: error pointer
+ *
+ * Determine whether the ECC public key in the given certificate uses the P-521
+ * curve.
+ *
+ * Returns: 0 if ECC public key does not use P521 curve.
+ *          1 if ECC public key uses P521 curve.
+ *         -1 on error.
+ */
+int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp);
+
 #endif
-- 
2.55.0



  parent reply	other threads:[~2026-08-26 12:55 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 12:51 [PULL 00/37] s390x queue Eric Farman
2026-08-26 12:51 ` [PULL 01/37] s390x/sclp: pv: only copy the original SCCB buffer Eric Farman
2026-08-26 12:51 ` [PULL 02/37] s390x/css: Fix css stsch detection to go beyond 8192 devices Eric Farman
2026-08-26 12:51 ` [PULL 03/37] Add boot-certs to s390-ccw-virtio machine type option Eric Farman
2026-08-26 12:51 ` [PULL 04/37] crypto/x509-utils: Refactor with GNUTLS fallback Eric Farman
2026-08-26 12:51 ` [PULL 05/37] crypto/x509-utils: Add helper functions for certificate store Eric Farman
2026-08-26 12:51 ` [PULL 06/37] hw/s390x/ipl: Create " Eric Farman
2026-08-26 12:51 ` [PULL 07/37] s390x/diag: Introduce DIAG 320 for Certificate Store Facility Eric Farman
2026-08-26 12:51 ` [PULL 08/37] s390x/diag: Refactor address validation check from diag308_parm_check Eric Farman
2026-08-26 12:51 ` [PULL 09/37] s390x/diag: Implement DIAG 320 subcode 1 Eric Farman
2026-08-26 12:51 ` Eric Farman [this message]
2026-08-26 12:51 ` [PULL 11/37] s390x/diag: Implement DIAG 320 subcode 2 Eric Farman
2026-08-26 12:51 ` [PULL 12/37] hw/s390x: Define finite size for single entry VCEntry Eric Farman
2026-08-26 12:51 ` [PULL 13/37] s390x/diag: Introduce DIAG 508 for secure IPL operations Eric Farman
2026-08-26 12:51 ` [PULL 14/37] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1 Eric Farman
2026-08-26 12:51 ` [PULL 15/37] s390x/diag: Generalize s390_ipl_read/write to accept void * Eric Farman
2026-08-26 12:51 ` [PULL 16/37] s390x/diag: Implement DIAG 508 subcode 1 for signature verification Eric Farman
2026-08-26 12:51 ` [PULL 17/37] s390x/ipl: Introduce IPL Information Report Block (IIRB) Eric Farman
2026-08-26 12:51 ` [PULL 18/37] pc-bios/s390-ccw: Define memory for IPLB and convert IPLB to pointers Eric Farman
2026-08-26 12:51 ` [PULL 19/37] hw/s390x/ipl: Add IPIB flags to IPL Parameter Block Eric Farman
2026-08-26 12:51 ` [PULL 20/37] hw/s390x/ipl: Rework s390_ipl_map_iplb_chain for certificate storage Eric Farman
2026-08-26 12:51 ` [PULL 21/37] s390x: Guest support for Secure-IPL Facility Eric Farman
2026-08-26 12:51 ` [PULL 22/37] pc-bios/s390-ccw: Refactor zipl_run() Eric Farman
2026-08-26 12:51 ` [PULL 23/37] pc-bios/s390-ccw: Rework zipl_load_segment function Eric Farman
2026-08-26 12:51 ` [PULL 24/37] pc-bios/s390-ccw: Introduce ZiplBootMode enum for IPL mode selection Eric Farman
2026-08-26 12:52 ` [PULL 25/37] pc-bios/s390-ccw: Add signature verification for secure IPL in audit mode Eric Farman
2026-08-26 12:52 ` [PULL 26/37] pc-bios/s390-ccw: Add signed component address overlap checks Eric Farman
2026-08-26 12:52 ` [PULL 27/37] s390x: Guest support for Secure-IPL Code Loading Attributes Facility (SCLAF) Eric Farman
2026-08-26 12:52 ` [PULL 28/37] pc-bios/s390-ccw: Add additional security checks for secure boot Eric Farman
2026-08-26 12:52 ` [PULL 29/37] Add secure-boot to s390-ccw-virtio machine type option Eric Farman
2026-08-26 12:52 ` [PULL 30/37] hw/s390x/ipl: Set IPIB flags for secure IPL Eric Farman
2026-08-26 12:52 ` [PULL 31/37] pc-bios/s390-ccw: Handle true secure IPL mode Eric Farman
2026-08-26 12:52 ` [PULL 32/37] hw/s390x/ipl: Handle secure boot with multiple boot devices Eric Farman
2026-08-26 12:52 ` [PULL 33/37] tests/functional/s390x: Add secure IPL functional test Eric Farman
2026-08-26 12:52 ` [PULL 34/37] docs/specs: Add secure IPL documentation Eric Farman
2026-08-26 12:52 ` [PULL 35/37] docs/system/s390x: " Eric Farman
2026-08-26 12:52 ` [PULL 36/37] MAINTAINERS: Add secure IPL files to S390-ccw boot group Eric Farman
2026-08-26 12:52 ` [PULL 37/37] pc-bios/s390-ccw.img: update s390x bios Eric Farman
2026-08-27  4:18 ` [PULL 00/37] s390x queue Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260826125213.1901252-11-farman@linux.ibm.com \
    --to=farman@linux.ibm.com \
    --cc=alifm@linux.ibm.com \
    --cc=berrange@redhat.com \
    --cc=cohuck@redhat.com \
    --cc=mjrosato@linux.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-s390x@nongnu.org \
    --cc=zycai@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.