[PATCH v5 03/29] crypto/x509-utils: Add helper functions for certificate store

Zhuoying Cai posted 29 patches 2 months, 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>
There is a newer version of this series
[PATCH v5 03/29] crypto/x509-utils: Add helper functions for certificate store
Posted by Zhuoying Cai 2 months, 4 weeks ago
Introduce new helper functions for x509 certificate, which will be used
by the certificate store:

qcrypto_x509_convert_cert_der() - converts a certificate from PEM to DER format

These functions provide support for certificate format conversion.

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

diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
index 6176a88653..29d5146bb2 100644
--- a/crypto/x509-utils.c
+++ b/crypto/x509-utils.c
@@ -81,6 +81,48 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
     return ret;
 }
 
+int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
+                                  uint8_t **result, size_t *resultlen,
+                                  Error **errp)
+{
+    int ret = -1;
+    int rc;
+    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;
+    }
+
+    if (*resultlen == 0) {
+        error_setg(errp, "Invalid buffer size");
+        goto cleanup;
+    }
+
+    *result = g_malloc0(*resultlen);
+    rc = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, *result, resultlen);
+    if (rc != 0) {
+        error_setg(errp, "Failed to convert certificate to DER format: %s",
+                   gnutls_strerror(rc));
+        g_clear_pointer(result, g_free);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    gnutls_x509_crt_deinit(crt);
+    return ret;
+}
+
 #else /* ! CONFIG_GNUTLS */
 
 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
@@ -93,4 +135,13 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
     return -1;
 }
 
+int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
+                                  uint8_t **result,
+                                  size_t *resultlen,
+                                  Error **errp)
+{
+    error_setg(errp, "GNUTLS is required to export X.509 certificate");
+    return -1;
+}
+
 #endif /* ! CONFIG_GNUTLS */
diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
index 1e99661a71..4239e3e55a 100644
--- a/include/crypto/x509-utils.h
+++ b/include/crypto/x509-utils.h
@@ -19,4 +19,24 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
                                       size_t *resultlen,
                                       Error **errp);
 
+/**
+ * qcrypto_x509_convert_cert_der
+ * @cert: pointer to the raw certificate data in PEM format
+ * @size: size of the certificate
+ * @result: output location for the allocated buffer for the certificate in DER 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 DER-encoded certificate)
+ * @errp: error pointer
+ *
+ * Convert the given @cert from PEM to DER format.
+ *
+ * Returns: 0 on success,
+ *         -1 on error.
+ */
+int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
+                                  uint8_t **result,
+                                  size_t *resultlen,
+                                  Error **errp);
+
 #endif
-- 
2.50.1
Re: [PATCH v5 03/29] crypto/x509-utils: Add helper functions for certificate store
Posted by Daniel P. Berrangé 2 months, 2 weeks ago
On Mon, Aug 18, 2025 at 05:42:56PM -0400, Zhuoying Cai wrote:
> Introduce new helper functions for x509 certificate, which will be used
> by the certificate store:
> 
> qcrypto_x509_convert_cert_der() - converts a certificate from PEM to DER format
> 
> These functions provide support for certificate format conversion.
> 
> Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
> ---
>  crypto/x509-utils.c         | 51 +++++++++++++++++++++++++++++++++++++
>  include/crypto/x509-utils.h | 20 +++++++++++++++
>  2 files changed, 71 insertions(+)
> 
> diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
> index 6176a88653..29d5146bb2 100644
> --- a/crypto/x509-utils.c
> +++ b/crypto/x509-utils.c
> @@ -81,6 +81,48 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>      return ret;
>  }
>  
> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
> +                                  uint8_t **result, size_t *resultlen,
> +                                  Error **errp)
> +{
> +    int ret = -1;
> +    int rc;
> +    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;
> +    }
> +
> +    if (*resultlen == 0) {
> +        error_setg(errp, "Invalid buffer size");
> +        goto cleanup;
> +    }

Requiring resultlen to be set as an input parameter is strange, when
this function is allocating the buffer. It would be better if we
ignore resultlen on input and....


> +
> +    *result = g_malloc0(*resultlen);
> +    rc = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, *result, resultlen);

Use 'gnutls_x509_crt_export2' instead

     datum.data = NULL;
     datum.size = 0;
     rc = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &datum);
     if (rc != 0) {
     ....
     }
     *result = g_new0(uint8_t, datum.size);
     *resultlen = datum.size;
     memcpy(result, datum.data, datum.size);
     gnutls_free(datum.data);

> +    if (rc != 0) {
> +        error_setg(errp, "Failed to convert certificate to DER format: %s",
> +                   gnutls_strerror(rc));
> +        g_clear_pointer(result, g_free);
> +        goto cleanup;
> +    }
> +
> +    ret = 0;
> +
> +cleanup:
> +    gnutls_x509_crt_deinit(crt);
> +    return ret;
> +}
> +
>  #else /* ! CONFIG_GNUTLS */
>  
>  int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
> @@ -93,4 +135,13 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>      return -1;
>  }
>  
> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
> +                                  uint8_t **result,
> +                                  size_t *resultlen,
> +                                  Error **errp)
> +{
> +    error_setg(errp, "GNUTLS is required to export X.509 certificate");
> +    return -1;
> +}
> +
>  #endif /* ! CONFIG_GNUTLS */
> diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
> index 1e99661a71..4239e3e55a 100644
> --- a/include/crypto/x509-utils.h
> +++ b/include/crypto/x509-utils.h
> @@ -19,4 +19,24 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>                                        size_t *resultlen,
>                                        Error **errp);
>  
> +/**
> + * qcrypto_x509_convert_cert_der
> + * @cert: pointer to the raw certificate data in PEM format
> + * @size: size of the certificate
> + * @result: output location for the allocated buffer for the certificate in DER 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 DER-encoded certificate)
> + * @errp: error pointer
> + *
> + * Convert the given @cert from PEM to DER format.
> + *
> + * Returns: 0 on success,
> + *         -1 on error.
> + */
> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
> +                                  uint8_t **result,
> +                                  size_t *resultlen,
> +                                  Error **errp);
> +
>  #endif
> -- 
> 2.50.1
> 

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 :|
Re: [PATCH v5 03/29] crypto/x509-utils: Add helper functions for certificate store
Posted by Zhuoying Cai 2 months, 2 weeks ago
On 8/27/25 1:28 PM, Daniel P. Berrangé wrote:
> On Mon, Aug 18, 2025 at 05:42:56PM -0400, Zhuoying Cai wrote:
>> Introduce new helper functions for x509 certificate, which will be used
>> by the certificate store:
>>
>> qcrypto_x509_convert_cert_der() - converts a certificate from PEM to DER format
>>
>> These functions provide support for certificate format conversion.
>>
>> Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
>> ---
>>  crypto/x509-utils.c         | 51 +++++++++++++++++++++++++++++++++++++
>>  include/crypto/x509-utils.h | 20 +++++++++++++++
>>  2 files changed, 71 insertions(+)
>>
>> diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
>> index 6176a88653..29d5146bb2 100644
>> --- a/crypto/x509-utils.c
>> +++ b/crypto/x509-utils.c
>> @@ -81,6 +81,48 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>>      return ret;
>>  }
>>  
>> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
>> +                                  uint8_t **result, size_t *resultlen,
>> +                                  Error **errp)
>> +{
>> +    int ret = -1;
>> +    int rc;
>> +    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;
>> +    }
>> +
>> +    if (*resultlen == 0) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        goto cleanup;
>> +    }
> 
> Requiring resultlen to be set as an input parameter is strange, when
> this function is allocating the buffer. It would be better if we
> ignore resultlen on input and....
> 
> 
>> +
>> +    *result = g_malloc0(*resultlen);
>> +    rc = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, *result, resultlen);
> 
> Use 'gnutls_x509_crt_export2' instead
> 
>      datum.data = NULL;
>      datum.size = 0;
>      rc = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &datum);
>      if (rc != 0) {
>      ....
>      }
>      *result = g_new0(uint8_t, datum.size);
>      *resultlen = datum.size;
>      memcpy(result, datum.data, datum.size);
>      gnutls_free(datum.data);
> 

Thanks for the suggestion! I'll make the change in the next version.

>> +    if (rc != 0) {
>> +        error_setg(errp, "Failed to convert certificate to DER format: %s",
>> +                   gnutls_strerror(rc));
>> +        g_clear_pointer(result, g_free);
>> +        goto cleanup;
>> +    }
>> +
>> +    ret = 0;
>> +
>> +cleanup:
>> +    gnutls_x509_crt_deinit(crt);
>> +    return ret;
>> +}
>> +
>>  #else /* ! CONFIG_GNUTLS */
>>  
>>  int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>> @@ -93,4 +135,13 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>>      return -1;
>>  }
>>  
>> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
>> +                                  uint8_t **result,
>> +                                  size_t *resultlen,
>> +                                  Error **errp)
>> +{
>> +    error_setg(errp, "GNUTLS is required to export X.509 certificate");
>> +    return -1;
>> +}
>> +
>>  #endif /* ! CONFIG_GNUTLS */
>> diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
>> index 1e99661a71..4239e3e55a 100644
>> --- a/include/crypto/x509-utils.h
>> +++ b/include/crypto/x509-utils.h
>> @@ -19,4 +19,24 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
>>                                        size_t *resultlen,
>>                                        Error **errp);
>>  
>> +/**
>> + * qcrypto_x509_convert_cert_der
>> + * @cert: pointer to the raw certificate data in PEM format
>> + * @size: size of the certificate
>> + * @result: output location for the allocated buffer for the certificate in DER 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 DER-encoded certificate)
>> + * @errp: error pointer
>> + *
>> + * Convert the given @cert from PEM to DER format.
>> + *
>> + * Returns: 0 on success,
>> + *         -1 on error.
>> + */
>> +int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
>> +                                  uint8_t **result,
>> +                                  size_t *resultlen,
>> +                                  Error **errp);
>> +
>>  #endif
>> -- 
>> 2.50.1
>>
> 
> With regards,
> Daniel