On 5/14/25 12:18 PM, Thomas Huth wrote: > On 09/05/2025 00.50, Zhuoying Cai wrote: >> DIAG 320 subcode 2 provides verification-certificates (VCs) that are in the >> certificate store. Only X509 certificates in DER format and SHA-256 hash >> type are recognized. >> >> The subcode value is denoted by setting the second-left-most bit >> of an 8-byte field. >> >> The Verification Certificate Block (VCB) contains the output data >> when the operation completes successfully. It includes a common >> header followed by zero or more Verification Certificate Entries (VCEs), >> depending on the VCB input length and the VC range (from the first VC >> index to the last VC index) in the certificate store. >> >> Each VCE contains information about a certificate retrieved from >> the S390IPLCertificateStore, such as the certificate name, key type, >> key ID length, hash length, and the raw certificate data. >> The key ID and hash are extracted from the raw certificate by the crypto API. >> >> Signed-off-by: Zhuoying Cai <zy...@linux.ibm.com> >> --- >> crypto/x509-utils.c | 204 ++++++++++++++++++++++++++++- >> include/crypto/x509-utils.h | 10 ++ >> include/hw/s390x/ipl/diag320.h | 47 +++++++ >> qapi/crypto.json | 20 +++ >> target/s390x/diag.c | 227 ++++++++++++++++++++++++++++++++- >> 5 files changed, 506 insertions(+), 2 deletions(-) >> >> diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c >> index 0b8cfc9022..51bd75d4eb 100644 >> --- a/crypto/x509-utils.c >> +++ b/crypto/x509-utils.c >> @@ -129,6 +129,7 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, >> size_t size, >> int hlen; >> gnutls_x509_crt_t crt; >> gnutls_datum_t datum = {.data = cert, .size = size}; >> + gnutls_x509_crt_fmt_t fmt; >> >> if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) { >> error_setg(errp, "Unknown hash algorithm"); >> @@ -140,9 +141,15 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, >> size_t size, >> return -1; >> } >> >> + fmt = qcrypto_get_x509_cert_fmt(cert, size, errp); >> + if (fmt == -1) { >> + error_setg(errp, "Certificate is neither in DER or PEM format"); > > qcrypto_get_x509_cert_fmt() already has an errp parameter, so I'd expect > that the qcrypto_get_x509_cert_fmt() function already sets up errp in case > of errors, doesn't it? In that case you should not set errp here again, I > think. > >> + return -1; >> + } >> + >> gnutls_x509_crt_init(&crt); >> >> - if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) { >> + if (gnutls_x509_crt_import(crt, &datum, fmt) != 0) { >> error_setg(errp, "Failed to import certificate"); >> goto cleanup; >> } >> @@ -199,6 +206,173 @@ cleanup: >> return rc; >> } >> >> +int qcrypto_get_x509_cert_version(uint8_t *cert, size_t size, Error **errp) >> +{ >> + int rc = -1; >> + gnutls_x509_crt_t crt; >> + gnutls_datum_t datum = {.data = cert, .size = size}; >> + gnutls_x509_crt_fmt_t fmt; >> + >> + fmt = qcrypto_get_x509_cert_fmt(cert, size, errp); >> + if (fmt == -1) { >> + error_setg(errp, "Certificate is neither in DER or PEM format"); > > dito? > >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_init(&crt) < 0) { >> + error_setg(errp, "Failed to initialize certificate"); >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_import(crt, &datum, fmt) != 0) { >> + error_setg(errp, "Failed to import certificate"); >> + goto cleanup; >> + } >> + >> + rc = gnutls_x509_crt_get_version(crt); >> + >> +cleanup: >> + gnutls_x509_crt_deinit(crt); >> + return rc; >> +} >> + >> +int qcrypto_check_x509_cert_times(uint8_t *cert, size_t size, Error **errp) >> +{ >> + int rc = -1; >> + gnutls_x509_crt_t crt; >> + gnutls_datum_t datum = {.data = cert, .size = size}; >> + time_t now = time(0); >> + gnutls_x509_crt_fmt_t fmt; >> + >> + if (now == ((time_t)-1)) { >> + error_setg(errp, "Cannot get current time"); > > Maybe use error_setg_errno() here to get the information from errno, too? > >> + return rc; >> + } >> + >> + fmt = qcrypto_get_x509_cert_fmt(cert, size, errp); >> + if (fmt == -1) { >> + error_setg(errp, "Certificate is neither in DER or PEM format"); > > This is again ignoring the errp from qcrypto_get_x509_cert_fmt(). > >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_init(&crt) < 0) { >> + error_setg(errp, "Failed to initialize certificate"); >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_import(crt, &datum, fmt) != 0) { >> + error_setg(errp, "Failed to import certificate"); >> + goto cleanup; >> + } >> + >> + if (gnutls_x509_crt_get_expiration_time(crt) < now) { >> + error_setg(errp, "The certificate has expired"); >> + goto cleanup; >> + } >> + >> + if (gnutls_x509_crt_get_activation_time(crt) > now) { >> + error_setg(errp, "The certificate is not yet active"); >> + goto cleanup; >> + } > > gnutls_x509_crt_get_expiration_time() and > gnutls_x509_crt_get_activation_time() can both return -1 on errors. I think > you should take that into account in the checks here, too. > >> + rc = 0; >> + >> +cleanup: >> + gnutls_x509_crt_deinit(crt); >> + return rc; >> +} >> + >> +int qcrypto_get_x509_pk_algorithm(uint8_t *cert, size_t size, Error **errp) >> +{ >> + int rc = -1; >> + unsigned int bits; >> + gnutls_x509_crt_t crt; >> + gnutls_datum_t datum = {.data = cert, .size = size}; >> + gnutls_x509_crt_fmt_t fmt; >> + >> + fmt = qcrypto_get_x509_cert_fmt(cert, size, errp); >> + if (fmt == -1) { >> + error_setg(errp, "Certificate is neither in DER or PEM format"); >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_init(&crt) < 0) { >> + error_setg(errp, "Failed to initialize certificate"); >> + return rc; >> + } >> + >> + if (gnutls_x509_crt_import(crt, &datum, fmt) != 0) { >> + error_setg(errp, "Failed to import certificate"); >> + goto cleanup; >> + } >> + >> + rc = gnutls_x509_crt_get_pk_algorithm(crt, &bits); >> + >> +cleanup: >> + gnutls_x509_crt_deinit(crt); >> + return rc; >> +} >> + >> +int qcrypto_get_x509_cert_key_id(uint8_t *cert, size_t size, >> + QCryptoKeyidFlags flag, >> + uint8_t *result, >> + size_t *resultlen, >> + Error **errp) >> +{ >> + int ret = -1; >> + int keyid_len; >> + gnutls_x509_crt_t crt; >> + gnutls_datum_t datum = {.data = cert, .size = size}; >> + gnutls_x509_crt_fmt_t fmt; >> + >> + if (flag >= G_N_ELEMENTS(qcrypto_to_gnutls_keyid_flags_map)) { >> + error_setg(errp, "Unknown key id flag"); >> + return -1; >> + } >> + >> + if (result == NULL) { >> + error_setg(errp, "No valid buffer given"); >> + return -1; >> + } > > This check sounds like it could also be a simple g_assert() statement instead? >
g_assert() may not be ideal here, as it will terminate the guest if the assertion fails, which is not the intended behavior. [...]