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 <zy...@linux.ibm.com> --- crypto/x509-utils.c | 110 ++++++++++++++++++++++++++++++++++++ include/crypto/x509-utils.h | 39 +++++++++++++ 2 files changed, 149 insertions(+) diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c index 135f83f55e..2b1ed5ee26 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, @@ -366,6 +367,98 @@ cleanup: return ret; } +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 = { 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)); + gnutls_free(sig_datum_pem.data); + goto cleanup; + } + + *result = g_steal_pointer(&sig_datum_pem.data); + *resultlen = sig_datum_pem.size; + + ret = 0; + +cleanup: + gnutls_pkcs7_deinit(signature); + 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; + gnutls_pkcs7_t signature; + 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)); + return ret; + } + + 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)); + gnutls_x509_crt_deinit(crt); + return ret; + } + + rc = gnutls_pkcs7_init(&signature); + if (rc < 0) { + error_setg(errp, "Failed to initalize pkcs7 data: %s", gnutls_strerror(rc)); + gnutls_x509_crt_deinit(crt); + return ret; + } + + 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_x509_convert_cert_der(uint8_t *cert, size_t size, @@ -427,4 +520,21 @@ int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size, 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 c122df0a98..8fcf7becbd 100644 --- a/include/crypto/x509-utils.h +++ b/include/crypto/x509-utils.h @@ -160,4 +160,43 @@ int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size, size_t *resultlen, 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.49.0