@samitouri / QOSamiQemu / commits / e8317c4c9f

crypto/x509-utils: Add helper functions for DIAG 320 subcode 2

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>

Zhuoying Cai committed Jul 30, 2026 at 17:45 UTC e8317c4c9f68c23b6e993efc71d26facafdfaa69
2 files changed +287
crypto/x509-utils.c
+236
@@ -27,6 +27,16 @@ static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
27 [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
28 };
29
30 +static const int qcrypto_to_gnutls_keyid_flags_map[] = {
31 + [QCRYPTO_HASH_ALGO_MD5] = -1,
32 + [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_KEYID_USE_SHA1,
33 + [QCRYPTO_HASH_ALGO_SHA224] = -1,
34 + [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_KEYID_USE_SHA256,
35 + [QCRYPTO_HASH_ALGO_SHA384] = -1,
36 + [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_KEYID_USE_SHA512,
37 + [QCRYPTO_HASH_ALGO_RIPEMD160] = -1,
38 +};
39 +
40 int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
41 QCryptoHashAlgo alg,
42 uint8_t *result,
@@ -122,6 +132,210 @@ cleanup:
132 return ret;
133 }
134
135 +int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp)
136 +{
137 + int rc;
138 + int ret = -1;
139 + gnutls_x509_crt_t crt;
140 + gnutls_datum_t datum = {.data = cert, .size = size};
141 + time_t now = time(NULL);
142 + time_t exp_time;
143 + time_t act_time;
144 +
145 + if (now == ((time_t)-1)) {
146 + error_setg_errno(errp, errno, "Cannot get current time");
147 + return ret;
148 + }
149 +
150 + rc = gnutls_x509_crt_init(&crt);
151 + if (rc < 0) {
152 + error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
153 + return ret;
154 + }
155 +
156 + rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
157 + if (rc != 0) {
158 + error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
159 + goto cleanup;
160 + }
161 +
162 + exp_time = gnutls_x509_crt_get_expiration_time(crt);
163 + if (exp_time == ((time_t)-1)) {
164 + error_setg(errp, "Failed to get certificate expiration time");
165 + goto cleanup;
166 + }
167 + if (exp_time < now) {
168 + error_setg(errp, "The certificate has expired");
169 + goto cleanup;
170 + }
171 +
172 + act_time = gnutls_x509_crt_get_activation_time(crt);
173 + if (act_time == ((time_t)-1)) {
174 + error_setg(errp, "Failed to get certificate activation time");
175 + goto cleanup;
176 + }
177 + if (act_time > now) {
178 + error_setg(errp, "The certificate is not yet active");
179 + goto cleanup;
180 + }
181 +
182 + ret = 0;
183 +
184 +cleanup:
185 + gnutls_x509_crt_deinit(crt);
186 + return ret;
187 +}
188 +
189 +static int qcrypto_x509_get_pk_algorithm(uint8_t *cert, size_t size, Error **errp)
190 +{
191 + int rc;
192 + int ret = -1;
193 + unsigned int bits;
194 + gnutls_x509_crt_t crt;
195 + gnutls_datum_t datum = {.data = cert, .size = size};
196 +
197 + rc = gnutls_x509_crt_init(&crt);
198 + if (rc < 0) {
199 + error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
200 + return ret;
201 + }
202 +
203 + rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
204 + if (rc != 0) {
205 + error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
206 + goto cleanup;
207 + }
208 +
209 + rc = gnutls_x509_crt_get_pk_algorithm(crt, &bits);
210 + if (rc < 0) {
211 + error_setg(errp, "Unknown public key algorithm %d", rc);
212 + goto cleanup;
213 + }
214 +
215 + ret = rc;
216 +
217 +cleanup:
218 + gnutls_x509_crt_deinit(crt);
219 + return ret;
220 +}
221 +
222 +int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
223 + QCryptoHashAlgo hash_alg,
224 + uint8_t **result,
225 + size_t *resultlen,
226 + Error **errp)
227 +{
228 + int rc;
229 + int ret = -1;
230 + gnutls_x509_crt_t crt;
231 + gnutls_datum_t datum = {.data = cert, .size = size};
232 +
233 + if (hash_alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) {
234 + error_setg(errp, "Unknown hash algorithm %d", hash_alg);
235 + return ret;
236 + }
237 +
238 + if (hash_alg >= G_N_ELEMENTS(qcrypto_to_gnutls_keyid_flags_map) ||
239 + qcrypto_to_gnutls_keyid_flags_map[hash_alg] == -1) {
240 + error_setg(errp, "Unsupported key id flag %d", hash_alg);
241 + return ret;
242 + }
243 +
244 + rc = gnutls_x509_crt_init(&crt);
245 + if (rc < 0) {
246 + error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
247 + return ret;
248 + }
249 +
250 + rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
251 + if (rc != 0) {
252 + error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
253 + goto cleanup;
254 + }
255 +
256 + *resultlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[hash_alg]);
257 + if (*resultlen == 0) {
258 + error_setg(errp, "Failed to get hash algorithm length: %s", gnutls_strerror(rc));
259 + goto cleanup;
260 + }
261 +
262 + *result = g_malloc0(*resultlen);
263 + if (gnutls_x509_crt_get_key_id(crt,
264 + qcrypto_to_gnutls_keyid_flags_map[hash_alg],
265 + *result, resultlen) != 0) {
266 + error_setg(errp, "Failed to get key ID from certificate");
267 + g_clear_pointer(result, g_free);
268 + goto cleanup;
269 + }
270 +
271 + ret = 0;
272 +
273 +cleanup:
274 + gnutls_x509_crt_deinit(crt);
275 + return ret;
276 +}
277 +
278 +static int qcrypto_x509_get_ecc_curve(uint8_t *cert, size_t size, Error **errp)
279 +{
280 + int rc;
281 + int ret = -1;
282 + gnutls_x509_crt_t crt;
283 + gnutls_datum_t datum = {.data = cert, .size = size};
284 + gnutls_ecc_curve_t curve_id;
285 + gnutls_datum_t x = {.data = NULL, .size = 0};
286 + gnutls_datum_t y = {.data = NULL, .size = 0};
287 +
288 + rc = gnutls_x509_crt_init(&crt);
289 + if (rc < 0) {
290 + error_setg(errp, "Failed to initialize certificate: %s", gnutls_strerror(rc));
291 + return ret;
292 + }
293 +
294 + rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
295 + if (rc != 0) {
296 + error_setg(errp, "Failed to import certificate: %s", gnutls_strerror(rc));
297 + goto cleanup;
298 + }
299 +
300 + rc = gnutls_x509_crt_get_pk_ecc_raw(crt, &curve_id, &x, &y);
301 + if (rc != 0) {
302 + error_setg(errp, "Failed to get ECC public key curve: %s", gnutls_strerror(rc));
303 + goto cleanup;
304 + }
305 +
306 + ret = curve_id;
307 +
308 +cleanup:
309 + gnutls_x509_crt_deinit(crt);
310 + g_free(x.data);
311 + g_free(y.data);
312 + return ret;
313 +}
314 +
315 +int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
316 +{
317 + int algo;
318 + int curve_id;
319 +
320 + algo = qcrypto_x509_get_pk_algorithm(cert, size, errp);
321 + if (algo != GNUTLS_PK_ECDSA) {
322 + return 0;
323 + }
324 +
325 + curve_id = qcrypto_x509_get_ecc_curve(cert, size, errp);
326 + if (curve_id == -1) {
327 + error_setg(errp, "Failed to get ECC curve");
328 + return -1;
329 + }
330 +
331 + if (curve_id == GNUTLS_ECC_CURVE_INVALID) {
332 + error_setg(errp, "Invalid ECC curve");
333 + return -1;
334 + }
335 +
336 + return curve_id == GNUTLS_ECC_CURVE_SECP521R1;
337 +}
338 +
339 #else /* ! CONFIG_GNUTLS */
340
341 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,
357 return -1;
358 }
359
360 +int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp)
361 +{
362 + error_setg(errp, "GNUTLS is required to get certificate times");
363 + return -1;
364 +}
365 +
366 +int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
367 + QCryptoHashAlgo hash_alg,
368 + uint8_t **result,
369 + size_t *resultlen,
370 + Error **errp)
371 +{
372 + error_setg(errp, "GNUTLS is required to get key ID");
373 + return -1;
374 +}
375 +
376 +int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp)
377 +{
378 + error_setg(errp, "GNUTLS is required to determine ecc curve");
379 + return -1;
380 +}
381 +
382 #endif /* ! CONFIG_GNUTLS */
include/crypto/x509-utils.h
+51
@@ -40,4 +40,55 @@ int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
40 size_t *resultlen,
41 Error **errp);
42
43 +/**
44 + * qcrypto_x509_check_cert_times
45 + * @cert: pointer to the raw certificate data
46 + * @size: size of the certificate
47 + * @errp: error pointer
48 + *
49 + * Check whether the activation and expiration times of @cert
50 + * are valid at the current time.
51 + *
52 + * Returns: 0 if the certificate times are valid,
53 + * -1 on error.
54 + */
55 +int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp);
56 +
57 +/**
58 + * qcrypto_x509_get_cert_key_id
59 + * @cert: pointer to the raw certificate data
60 + * @size: size of the certificate
61 + * @hash_alg: the hash algorithm flag
62 + * @result: output location for the allocated buffer for key ID
63 + * (the function allocates memory which must be freed by the caller)
64 + * @resultlen: pointer to the size of the buffer
65 + * (will be updated with the actual size of key id)
66 + * @errp: error pointer
67 + *
68 + * Retrieve the key ID from the @cert based on the specified @hash_alg.
69 + *
70 + * Returns: 0 if key ID was successfully stored in @result,
71 + * -1 on error.
72 + */
73 +int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
74 + QCryptoHashAlgo hash_alg,
75 + uint8_t **result,
76 + size_t *resultlen,
77 + Error **errp);
78 +
79 +/**
80 + * qcrypto_x509_check_ecc_curve_p521
81 + * @cert: pointer to the raw certificate data
82 + * @size: size of the certificate
83 + * @errp: error pointer
84 + *
85 + * Determine whether the ECC public key in the given certificate uses the P-521
86 + * curve.
87 + *
88 + * Returns: 0 if ECC public key does not use P521 curve.
89 + * 1 if ECC public key uses P521 curve.
90 + * -1 on error.
91 + */
92 +int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp);
93 +
94 #endif