[PATCH v6 11/28] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1

Zhuoying Cai posted 28 patches 1 month, 4 weeks ago
Maintainers: "Daniel P. Berrangé" <berrange@redhat.com>, Thomas Huth <thuth@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, David Hildenbrand <david@redhat.com>, Ilya Leoshkevich <iii@linux.ibm.com>, Halil Pasic <pasic@linux.ibm.com>, Christian Borntraeger <borntraeger@linux.ibm.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Jared Rossi <jrossi@linux.ibm.com>, Zhuoying Cai <zycai@linux.ibm.com>, Jason Herne <jjherne@linux.ibm.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>
[PATCH v6 11/28] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1
Posted by Zhuoying Cai 1 month, 4 weeks ago
Introduce helper functions to support signature verification required by
DIAG 508 subcode 1:

qcrypto_pkcs7_convert_sig_pem() – converts a signature from DER to PEM format
qcrypto_x509_verify_sig() – verifies the provided data against the given signature

These functions enable basic signature verification support.

Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
---
 crypto/x509-utils.c         | 109 ++++++++++++++++++++++++++++++++++++
 include/crypto/x509-utils.h |  39 +++++++++++++
 2 files changed, 148 insertions(+)

diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
index 763eccb190..8f3c895d7c 100644
--- a/crypto/x509-utils.c
+++ b/crypto/x509-utils.c
@@ -16,6 +16,7 @@
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
 #include <gnutls/x509.h>
+#include <gnutls/pkcs7.h>
 
 static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
     [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
@@ -342,6 +343,97 @@ int qcrypto_x509_is_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
     return 0;
 }
 
+int qcrypto_pkcs7_convert_sig_pem(uint8_t *sig, size_t sig_size,
+                                  uint8_t **result, size_t *resultlen,
+                                  Error **errp)
+{
+    int ret = -1;
+    int rc;
+    gnutls_pkcs7_t signature;
+    gnutls_datum_t sig_datum_der = {.data = sig, .size = sig_size};
+    gnutls_datum_t sig_datum_pem = {.data = NULL, .size = 0};
+
+    rc = gnutls_pkcs7_init(&signature);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc));
+        return ret;
+     }
+
+    rc = gnutls_pkcs7_import(signature, &sig_datum_der, GNUTLS_X509_FMT_DER);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import signature: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_pkcs7_export2(signature, GNUTLS_X509_FMT_PEM, &sig_datum_pem);
+    if (rc != 0) {
+        error_setg(errp, "Failed to convert signature to PEM format: %s",
+                   gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    *result = g_new0(uint8_t, sig_datum_pem.size);
+    *resultlen = sig_datum_pem.size;
+    memcpy(*result, sig_datum_pem.data, sig_datum_pem.size);
+
+    ret = 0;
+
+cleanup:
+    gnutls_pkcs7_deinit(signature);
+    gnutls_free(sig_datum_pem.data);
+    return ret;
+}
+
+int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
+                            uint8_t *comp, size_t comp_size,
+                            uint8_t *sig, size_t sig_size, Error **errp)
+{
+    int rc;
+    int ret = -1;
+    gnutls_x509_crt_t crt = NULL;
+    gnutls_pkcs7_t signature = NULL;
+    gnutls_datum_t cert_datum = {.data = cert, .size = cert_size};
+    gnutls_datum_t data_datum = {.data = comp, .size = comp_size};
+    gnutls_datum_t sig_datum = {.data = sig, .size = sig_size};
+
+    rc = gnutls_x509_crt_init(&crt);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_x509_crt_import(crt, &cert_datum, GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_pkcs7_init(&signature);
+    if (rc < 0) {
+        error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc));
+        goto cleanup;
+     }
+
+    rc = gnutls_pkcs7_import(signature, &sig_datum , GNUTLS_X509_FMT_PEM);
+    if (rc != 0) {
+        error_setg(errp, "Failed to import signature: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = gnutls_pkcs7_verify_direct(signature, crt, 0, &data_datum, 0);
+    if (rc != 0) {
+        error_setg(errp, "Failed to verify signature: %s", gnutls_strerror(rc));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    gnutls_pkcs7_deinit(signature);
+    return ret;
+}
+
 #else /* ! CONFIG_GNUTLS */
 
 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
@@ -391,4 +483,21 @@ int qcrypto_x509_is_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
     return -1;
 }
 
+int qcrypto_pkcs7_convert_sig_pem(uint8_t *sig, size_t sig_size,
+                                  uint8_t **result,
+                                  size_t *resultlen,
+                                  Error **errp)
+{
+    error_setg(errp, "GNUTLS is required to export pkcs7 signature");
+    return -1;
+}
+
+int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
+                            uint8_t *comp, size_t comp_size,
+                            uint8_t *sig, size_t sig_size, Error **errp)
+{
+    error_setg(errp, "GNUTLS is required for signature-verification support");
+    return -1;
+}
+
 #endif /* ! CONFIG_GNUTLS */
diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
index 6fc8d982b7..43a3dbb7a9 100644
--- a/include/crypto/x509-utils.h
+++ b/include/crypto/x509-utils.h
@@ -111,4 +111,43 @@ int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
  */
 int qcrypto_x509_is_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp);
 
+/**
+ * qcrypto_pkcs7_convert_sig_pem
+ * @sig: pointer to the PKCS#7 signature in DER format
+ * @sig_size: size of the signature
+ * @result: output location for the allocated buffer for the signature in PEM format
+            (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 the PEM-encoded signature)
+ * @errp: error pointer
+ *
+ * Convert given PKCS#7 @sig from DER to PEM format.
+ *
+ * Returns: 0 if PEM-encoded signature was successfully stored in @result,
+ *         -1 on error.
+ */
+int qcrypto_pkcs7_convert_sig_pem(uint8_t *sig, size_t sig_size,
+                                  uint8_t **result,
+                                  size_t *resultlen,
+                                  Error **errp);
+
+/**
+ * qcrypto_x509_verify_sig
+ * @cert: pointer to the raw certificate data
+ * @cert_size: size of the certificate
+ * @comp: pointer to the component to be verified
+ * @comp_size: size of the component
+ * @sig: pointer to the signature
+ * @sig_size: size of the signature
+ * @errp: error pointer
+ *
+ * Verify the provided @comp against the @sig and @cert.
+ *
+ * Returns: 0 on success,
+ *         -1 on error.
+ */
+int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
+                            uint8_t *comp, size_t comp_size,
+                            uint8_t *sig, size_t sig_size, Error **errp);
+
 #endif
-- 
2.50.1


Re: [PATCH v6 11/28] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1
Posted by Thomas Huth 1 month, 1 week ago
On 18/09/2025 01.21, Zhuoying Cai wrote:
> Introduce helper functions to support signature verification required by
> DIAG 508 subcode 1:
> 
> qcrypto_pkcs7_convert_sig_pem() – converts a signature from DER to PEM format
> qcrypto_x509_verify_sig() – verifies the provided data against the given signature
> 
> These functions enable basic signature verification support.
> 
> Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
> ---
>   crypto/x509-utils.c         | 109 ++++++++++++++++++++++++++++++++++++
>   include/crypto/x509-utils.h |  39 +++++++++++++
>   2 files changed, 148 insertions(+)
> 
> diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
> index 763eccb190..8f3c895d7c 100644
> --- a/crypto/x509-utils.c
> +++ b/crypto/x509-utils.c
> @@ -16,6 +16,7 @@
>   #include <gnutls/gnutls.h>
>   #include <gnutls/crypto.h>
>   #include <gnutls/x509.h>
> +#include <gnutls/pkcs7.h>
>   
>   static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
>       [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
> @@ -342,6 +343,97 @@ int qcrypto_x509_is_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
>       return 0;
>   }
>   
> +int qcrypto_pkcs7_convert_sig_pem(uint8_t *sig, size_t sig_size,
> +                                  uint8_t **result, size_t *resultlen,
> +                                  Error **errp)
> +{
> +    int ret = -1;
> +    int rc;
> +    gnutls_pkcs7_t signature;
> +    gnutls_datum_t sig_datum_der = {.data = sig, .size = sig_size};
> +    gnutls_datum_t sig_datum_pem = {.data = NULL, .size = 0};
> +
> +    rc = gnutls_pkcs7_init(&signature);
> +    if (rc < 0) {
> +        error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc));
> +        return ret;
> +     }

Indentation of the "}" is off by one.

> +    rc = gnutls_pkcs7_import(signature, &sig_datum_der, GNUTLS_X509_FMT_DER);
> +    if (rc != 0) {
> +        error_setg(errp, "Failed to import signature: %s", gnutls_strerror(rc));
> +        goto cleanup;
> +    }
> +
> +    rc = gnutls_pkcs7_export2(signature, GNUTLS_X509_FMT_PEM, &sig_datum_pem);
> +    if (rc != 0) {
> +        error_setg(errp, "Failed to convert signature to PEM format: %s",
> +                   gnutls_strerror(rc));
> +        goto cleanup;
> +    }
> +
> +    *result = g_new0(uint8_t, sig_datum_pem.size);
> +    *resultlen = sig_datum_pem.size;
> +    memcpy(*result, sig_datum_pem.data, sig_datum_pem.size);

I think you could replace the g_new0 + memcpy with a g_memdup2() here.

> +    ret = 0;
> +
> +cleanup:
> +    gnutls_pkcs7_deinit(signature);
> +    gnutls_free(sig_datum_pem.data);
> +    return ret;
> +}
> +
> +int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
> +                            uint8_t *comp, size_t comp_size,
> +                            uint8_t *sig, size_t sig_size, Error **errp)
> +{
> +    int rc;
> +    int ret = -1;
> +    gnutls_x509_crt_t crt = NULL;
> +    gnutls_pkcs7_t signature = NULL;
> +    gnutls_datum_t cert_datum = {.data = cert, .size = cert_size};
> +    gnutls_datum_t data_datum = {.data = comp, .size = comp_size};
> +    gnutls_datum_t sig_datum = {.data = sig, .size = sig_size};
> +
> +    rc = gnutls_x509_crt_init(&crt);
> +    if (rc < 0) {
> +        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
> +        goto cleanup;

So if you go to cleanup here, signature is still NULL ...

> +    }
> +
> +    rc = gnutls_x509_crt_import(crt, &cert_datum, GNUTLS_X509_FMT_PEM);
> +    if (rc != 0) {
> +        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
> +        goto cleanup;
> +    }
> +
> +    rc = gnutls_pkcs7_init(&signature);
> +    if (rc < 0) {
> +        error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc));
> +        goto cleanup;
> +     }
> +
> +    rc = gnutls_pkcs7_import(signature, &sig_datum , GNUTLS_X509_FMT_PEM);
> +    if (rc != 0) {
> +        error_setg(errp, "Failed to import signature: %s", gnutls_strerror(rc));
> +        goto cleanup;
> +    }
> +
> +    rc = gnutls_pkcs7_verify_direct(signature, crt, 0, &data_datum, 0);
> +    if (rc != 0) {
> +        error_setg(errp, "Failed to verify signature: %s", gnutls_strerror(rc));
> +        goto cleanup;
> +    }
> +
> +    ret = 0;
> +
> +cleanup:
> +    gnutls_x509_crt_deinit(crt);
> +    gnutls_pkcs7_deinit(signature);

... did you check whether gnutls_pkcs7_deinit() is able to deal with NULL 
pointers? The man-page does not mention it ... so just to be on the save 
side, maybe it would be better to have to cleanup labels, and only do the 
gnutls_pkcs7_deinit() if it has been initialized before?

> +    return ret;
> +}

  Thomas


Re: [PATCH v6 11/28] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1
Posted by Daniel P. Berrangé 1 month, 1 week ago
On Tue, Oct 07, 2025 at 11:58:03AM +0200, Thomas Huth wrote:
> On 18/09/2025 01.21, Zhuoying Cai wrote:
> > Introduce helper functions to support signature verification required by
> > DIAG 508 subcode 1:
> > 
> > qcrypto_pkcs7_convert_sig_pem() – converts a signature from DER to PEM format
> > qcrypto_x509_verify_sig() – verifies the provided data against the given signature
> > 
> > These functions enable basic signature verification support.
> > 
> > Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
> > ---
> >   crypto/x509-utils.c         | 109 ++++++++++++++++++++++++++++++++++++
> >   include/crypto/x509-utils.h |  39 +++++++++++++
> >   2 files changed, 148 insertions(+)
> > 
> > diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
> > index 763eccb190..8f3c895d7c 100644
> > --- a/crypto/x509-utils.c
> > +++ b/crypto/x509-utils.c


> > +int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
> > +                            uint8_t *comp, size_t comp_size,
> > +                            uint8_t *sig, size_t sig_size, Error **errp)
> > +{
> > +    int rc;
> > +    int ret = -1;
> > +    gnutls_x509_crt_t crt = NULL;
> > +    gnutls_pkcs7_t signature = NULL;
> > +    gnutls_datum_t cert_datum = {.data = cert, .size = cert_size};
> > +    gnutls_datum_t data_datum = {.data = comp, .size = comp_size};
> > +    gnutls_datum_t sig_datum = {.data = sig, .size = sig_size};
> > +
> > +    rc = gnutls_x509_crt_init(&crt);
> > +    if (rc < 0) {
> > +        error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
> > +        goto cleanup;
> 
> So if you go to cleanup here, signature is still NULL ...
> 
> > +    }
> > +
> > +    rc = gnutls_x509_crt_import(crt, &cert_datum, GNUTLS_X509_FMT_PEM);
> > +    if (rc != 0) {
> > +        error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
> > +        goto cleanup;
> > +    }
> > +
> > +    rc = gnutls_pkcs7_init(&signature);
> > +    if (rc < 0) {
> > +        error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc));
> > +        goto cleanup;
> > +     }
> > +
> > +    rc = gnutls_pkcs7_import(signature, &sig_datum , GNUTLS_X509_FMT_PEM);
> > +    if (rc != 0) {
> > +        error_setg(errp, "Failed to import signature: %s", gnutls_strerror(rc));
> > +        goto cleanup;
> > +    }
> > +
> > +    rc = gnutls_pkcs7_verify_direct(signature, crt, 0, &data_datum, 0);
> > +    if (rc != 0) {
> > +        error_setg(errp, "Failed to verify signature: %s", gnutls_strerror(rc));
> > +        goto cleanup;
> > +    }
> > +
> > +    ret = 0;
> > +
> > +cleanup:
> > +    gnutls_x509_crt_deinit(crt);
> > +    gnutls_pkcs7_deinit(signature);
> 
> ... did you check whether gnutls_pkcs7_deinit() is able to deal with NULL
> pointers? The man-page does not mention it ... so just to be on the save
> side, maybe it would be better to have to cleanup labels, and only do the
> gnutls_pkcs7_deinit() if it has been initialized before?

All gnutls APIs for free'ing objects accept NULL and act as a no-op,
so we're ok.

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 :|