1*3e33af2cSGerd Hoffmann /*
2*3e33af2cSGerd Hoffmann * SPDX-License-Identifier: GPL-2.0-or-later
3*3e33af2cSGerd Hoffmann *
4*3e33af2cSGerd Hoffmann * uefi vars device - pkcs7 verification
5*3e33af2cSGerd Hoffmann */
6*3e33af2cSGerd Hoffmann #include "qemu/osdep.h"
7*3e33af2cSGerd Hoffmann #include "qemu/error-report.h"
8*3e33af2cSGerd Hoffmann #include "system/dma.h"
9*3e33af2cSGerd Hoffmann
10*3e33af2cSGerd Hoffmann #include <gnutls/gnutls.h>
11*3e33af2cSGerd Hoffmann #include <gnutls/pkcs7.h>
12*3e33af2cSGerd Hoffmann #include <gnutls/crypto.h>
13*3e33af2cSGerd Hoffmann
14*3e33af2cSGerd Hoffmann #include "hw/uefi/var-service.h"
15*3e33af2cSGerd Hoffmann
16*3e33af2cSGerd Hoffmann #define AUTHVAR_DIGEST_ALGO GNUTLS_DIG_SHA256
17*3e33af2cSGerd Hoffmann #define AUTHVAR_DIGEST_SIZE 32
18*3e33af2cSGerd Hoffmann
19*3e33af2cSGerd Hoffmann /*
20*3e33af2cSGerd Hoffmann * Replicate the signed data for signature verification.
21*3e33af2cSGerd Hoffmann */
build_signed_data(mm_variable_access * va,void * data)22*3e33af2cSGerd Hoffmann static gnutls_datum_t *build_signed_data(mm_variable_access *va, void *data)
23*3e33af2cSGerd Hoffmann {
24*3e33af2cSGerd Hoffmann variable_auth_2 *auth = data;
25*3e33af2cSGerd Hoffmann uint64_t data_offset = sizeof(efi_time) + auth->hdr_length;
26*3e33af2cSGerd Hoffmann uint16_t *name = (void *)va + sizeof(mm_variable_access);
27*3e33af2cSGerd Hoffmann gnutls_datum_t *sdata;
28*3e33af2cSGerd Hoffmann uint64_t pos = 0;
29*3e33af2cSGerd Hoffmann
30*3e33af2cSGerd Hoffmann sdata = g_new(gnutls_datum_t, 1);
31*3e33af2cSGerd Hoffmann sdata->size = (va->name_size - 2
32*3e33af2cSGerd Hoffmann + sizeof(QemuUUID)
33*3e33af2cSGerd Hoffmann + sizeof(va->attributes)
34*3e33af2cSGerd Hoffmann + sizeof(auth->timestamp)
35*3e33af2cSGerd Hoffmann + va->data_size - data_offset);
36*3e33af2cSGerd Hoffmann sdata->data = g_malloc(sdata->size);
37*3e33af2cSGerd Hoffmann
38*3e33af2cSGerd Hoffmann /* Variable Name (without terminating \0) */
39*3e33af2cSGerd Hoffmann memcpy(sdata->data + pos, name, va->name_size - 2);
40*3e33af2cSGerd Hoffmann pos += va->name_size - 2;
41*3e33af2cSGerd Hoffmann
42*3e33af2cSGerd Hoffmann /* Variable Namespace Guid */
43*3e33af2cSGerd Hoffmann memcpy(sdata->data + pos, &va->guid, sizeof(va->guid));
44*3e33af2cSGerd Hoffmann pos += sizeof(va->guid);
45*3e33af2cSGerd Hoffmann
46*3e33af2cSGerd Hoffmann /* Attributes */
47*3e33af2cSGerd Hoffmann memcpy(sdata->data + pos, &va->attributes, sizeof(va->attributes));
48*3e33af2cSGerd Hoffmann pos += sizeof(va->attributes);
49*3e33af2cSGerd Hoffmann
50*3e33af2cSGerd Hoffmann /* TimeStamp */
51*3e33af2cSGerd Hoffmann memcpy(sdata->data + pos, &auth->timestamp, sizeof(auth->timestamp));
52*3e33af2cSGerd Hoffmann pos += sizeof(auth->timestamp);
53*3e33af2cSGerd Hoffmann
54*3e33af2cSGerd Hoffmann /* Variable Content */
55*3e33af2cSGerd Hoffmann memcpy(sdata->data + pos, data + data_offset, va->data_size - data_offset);
56*3e33af2cSGerd Hoffmann pos += va->data_size - data_offset;
57*3e33af2cSGerd Hoffmann
58*3e33af2cSGerd Hoffmann assert(pos == sdata->size);
59*3e33af2cSGerd Hoffmann return sdata;
60*3e33af2cSGerd Hoffmann }
61*3e33af2cSGerd Hoffmann
62*3e33af2cSGerd Hoffmann /*
63*3e33af2cSGerd Hoffmann * See WrapPkcs7Data() in edk2.
64*3e33af2cSGerd Hoffmann *
65*3e33af2cSGerd Hoffmann * UEFI spec allows pkcs7 signatures being used without the envelope which
66*3e33af2cSGerd Hoffmann * identifies them as pkcs7 signatures. openssl and gnutls will not parse them
67*3e33af2cSGerd Hoffmann * without the envelope though. So add it if needed.
68*3e33af2cSGerd Hoffmann */
wrap_pkcs7(gnutls_datum_t * pkcs7)69*3e33af2cSGerd Hoffmann static void wrap_pkcs7(gnutls_datum_t *pkcs7)
70*3e33af2cSGerd Hoffmann {
71*3e33af2cSGerd Hoffmann static uint8_t signed_data_oid[9] = {
72*3e33af2cSGerd Hoffmann 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02
73*3e33af2cSGerd Hoffmann };
74*3e33af2cSGerd Hoffmann gnutls_datum_t wrap;
75*3e33af2cSGerd Hoffmann
76*3e33af2cSGerd Hoffmann if (pkcs7->data[4] == 0x06 &&
77*3e33af2cSGerd Hoffmann pkcs7->data[5] == 0x09 &&
78*3e33af2cSGerd Hoffmann memcmp(pkcs7->data + 6, signed_data_oid, sizeof(signed_data_oid)) == 0 &&
79*3e33af2cSGerd Hoffmann pkcs7->data[15] == 0x0a &&
80*3e33af2cSGerd Hoffmann pkcs7->data[16] == 0x82) {
81*3e33af2cSGerd Hoffmann return;
82*3e33af2cSGerd Hoffmann }
83*3e33af2cSGerd Hoffmann
84*3e33af2cSGerd Hoffmann wrap.size = pkcs7->size + 19;
85*3e33af2cSGerd Hoffmann wrap.data = g_malloc(wrap.size);
86*3e33af2cSGerd Hoffmann
87*3e33af2cSGerd Hoffmann wrap.data[0] = 0x30;
88*3e33af2cSGerd Hoffmann wrap.data[1] = 0x82;
89*3e33af2cSGerd Hoffmann wrap.data[2] = (wrap.size - 4) >> 8;
90*3e33af2cSGerd Hoffmann wrap.data[3] = (wrap.size - 4) & 0xff;
91*3e33af2cSGerd Hoffmann wrap.data[4] = 0x06;
92*3e33af2cSGerd Hoffmann wrap.data[5] = 0x09;
93*3e33af2cSGerd Hoffmann memcpy(wrap.data + 6, signed_data_oid, sizeof(signed_data_oid));
94*3e33af2cSGerd Hoffmann
95*3e33af2cSGerd Hoffmann wrap.data[15] = 0xa0;
96*3e33af2cSGerd Hoffmann wrap.data[16] = 0x82;
97*3e33af2cSGerd Hoffmann wrap.data[17] = pkcs7->size >> 8;
98*3e33af2cSGerd Hoffmann wrap.data[18] = pkcs7->size & 0xff;
99*3e33af2cSGerd Hoffmann memcpy(wrap.data + 19, pkcs7->data, pkcs7->size);
100*3e33af2cSGerd Hoffmann
101*3e33af2cSGerd Hoffmann g_free(pkcs7->data);
102*3e33af2cSGerd Hoffmann *pkcs7 = wrap;
103*3e33af2cSGerd Hoffmann }
104*3e33af2cSGerd Hoffmann
build_pkcs7(void * data)105*3e33af2cSGerd Hoffmann static gnutls_datum_t *build_pkcs7(void *data)
106*3e33af2cSGerd Hoffmann {
107*3e33af2cSGerd Hoffmann variable_auth_2 *auth = data;
108*3e33af2cSGerd Hoffmann gnutls_datum_t *pkcs7;
109*3e33af2cSGerd Hoffmann
110*3e33af2cSGerd Hoffmann pkcs7 = g_new(gnutls_datum_t, 1);
111*3e33af2cSGerd Hoffmann pkcs7->size = auth->hdr_length - 24;
112*3e33af2cSGerd Hoffmann pkcs7->data = g_malloc(pkcs7->size);
113*3e33af2cSGerd Hoffmann memcpy(pkcs7->data, data + 16 + 24, pkcs7->size);
114*3e33af2cSGerd Hoffmann
115*3e33af2cSGerd Hoffmann wrap_pkcs7(pkcs7);
116*3e33af2cSGerd Hoffmann
117*3e33af2cSGerd Hoffmann return pkcs7;
118*3e33af2cSGerd Hoffmann }
119*3e33af2cSGerd Hoffmann
120*3e33af2cSGerd Hoffmann /*
121*3e33af2cSGerd Hoffmann * Read UEFI signature database, store x509 all certificates found in
122*3e33af2cSGerd Hoffmann * gnutls_x509_trust_list_t.
123*3e33af2cSGerd Hoffmann */
build_trust_list_sb(uefi_variable * var)124*3e33af2cSGerd Hoffmann static gnutls_x509_trust_list_t build_trust_list_sb(uefi_variable *var)
125*3e33af2cSGerd Hoffmann {
126*3e33af2cSGerd Hoffmann gnutls_x509_trust_list_t tlist;
127*3e33af2cSGerd Hoffmann gnutls_datum_t cert_data;
128*3e33af2cSGerd Hoffmann gnutls_x509_crt_t cert;
129*3e33af2cSGerd Hoffmann uefi_vars_siglist siglist;
130*3e33af2cSGerd Hoffmann uefi_vars_cert *c;
131*3e33af2cSGerd Hoffmann int rc;
132*3e33af2cSGerd Hoffmann
133*3e33af2cSGerd Hoffmann rc = gnutls_x509_trust_list_init(&tlist, 0);
134*3e33af2cSGerd Hoffmann if (rc < 0) {
135*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_trust_list_init error: %s",
136*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
137*3e33af2cSGerd Hoffmann return NULL;
138*3e33af2cSGerd Hoffmann }
139*3e33af2cSGerd Hoffmann
140*3e33af2cSGerd Hoffmann uefi_vars_siglist_init(&siglist);
141*3e33af2cSGerd Hoffmann uefi_vars_siglist_parse(&siglist, var->data, var->data_size);
142*3e33af2cSGerd Hoffmann
143*3e33af2cSGerd Hoffmann QTAILQ_FOREACH(c, &siglist.x509, next) {
144*3e33af2cSGerd Hoffmann cert_data.size = c->size;
145*3e33af2cSGerd Hoffmann cert_data.data = c->data;
146*3e33af2cSGerd Hoffmann
147*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_init(&cert);
148*3e33af2cSGerd Hoffmann if (rc < 0) {
149*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
150*3e33af2cSGerd Hoffmann break;
151*3e33af2cSGerd Hoffmann }
152*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_import(cert, &cert_data, GNUTLS_X509_FMT_DER);
153*3e33af2cSGerd Hoffmann if (rc < 0) {
154*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_import error: %s",
155*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
156*3e33af2cSGerd Hoffmann gnutls_x509_crt_deinit(cert);
157*3e33af2cSGerd Hoffmann break;
158*3e33af2cSGerd Hoffmann }
159*3e33af2cSGerd Hoffmann rc = gnutls_x509_trust_list_add_cas(tlist, &cert, 1, 0);
160*3e33af2cSGerd Hoffmann if (rc < 0) {
161*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_import error: %s",
162*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
163*3e33af2cSGerd Hoffmann gnutls_x509_crt_deinit(cert);
164*3e33af2cSGerd Hoffmann break;
165*3e33af2cSGerd Hoffmann }
166*3e33af2cSGerd Hoffmann }
167*3e33af2cSGerd Hoffmann
168*3e33af2cSGerd Hoffmann uefi_vars_siglist_free(&siglist);
169*3e33af2cSGerd Hoffmann
170*3e33af2cSGerd Hoffmann return tlist;
171*3e33af2cSGerd Hoffmann }
172*3e33af2cSGerd Hoffmann
build_digest_authvar(gnutls_x509_crt_t signer,gnutls_x509_crt_t root,uint8_t * hash_digest)173*3e33af2cSGerd Hoffmann static int build_digest_authvar(gnutls_x509_crt_t signer,
174*3e33af2cSGerd Hoffmann gnutls_x509_crt_t root,
175*3e33af2cSGerd Hoffmann uint8_t *hash_digest)
176*3e33af2cSGerd Hoffmann {
177*3e33af2cSGerd Hoffmann char *cn;
178*3e33af2cSGerd Hoffmann size_t cn_size = 0;
179*3e33af2cSGerd Hoffmann uint8_t fp[AUTHVAR_DIGEST_SIZE];
180*3e33af2cSGerd Hoffmann size_t fp_size = sizeof(fp);
181*3e33af2cSGerd Hoffmann gnutls_hash_hd_t hash;
182*3e33af2cSGerd Hoffmann int rc;
183*3e33af2cSGerd Hoffmann
184*3e33af2cSGerd Hoffmann /* get signer CN */
185*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
186*3e33af2cSGerd Hoffmann 0, 0, NULL, &cn_size);
187*3e33af2cSGerd Hoffmann if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER) {
188*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_get_dn_by_oid error #1: %s",
189*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
190*3e33af2cSGerd Hoffmann return rc;
191*3e33af2cSGerd Hoffmann }
192*3e33af2cSGerd Hoffmann
193*3e33af2cSGerd Hoffmann cn = g_malloc(cn_size);
194*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
195*3e33af2cSGerd Hoffmann 0, 0, cn, &cn_size);
196*3e33af2cSGerd Hoffmann if (rc < 0) {
197*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_get_dn_by_oid error #2: %s",
198*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
199*3e33af2cSGerd Hoffmann goto err;
200*3e33af2cSGerd Hoffmann }
201*3e33af2cSGerd Hoffmann
202*3e33af2cSGerd Hoffmann /* get root certificate fingerprint */
203*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_get_fingerprint(root, AUTHVAR_DIGEST_ALGO,
204*3e33af2cSGerd Hoffmann fp, &fp_size);
205*3e33af2cSGerd Hoffmann if (rc < 0) {
206*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_get_fingerprint error: %s",
207*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
208*3e33af2cSGerd Hoffmann goto err;
209*3e33af2cSGerd Hoffmann }
210*3e33af2cSGerd Hoffmann
211*3e33af2cSGerd Hoffmann /* digest both items */
212*3e33af2cSGerd Hoffmann rc = gnutls_hash_init(&hash, AUTHVAR_DIGEST_ALGO);
213*3e33af2cSGerd Hoffmann if (rc < 0) {
214*3e33af2cSGerd Hoffmann warn_report("gnutls_hash_init error: %s",
215*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
216*3e33af2cSGerd Hoffmann goto err;
217*3e33af2cSGerd Hoffmann }
218*3e33af2cSGerd Hoffmann rc = gnutls_hash(hash, cn, cn_size);
219*3e33af2cSGerd Hoffmann if (rc < 0) {
220*3e33af2cSGerd Hoffmann warn_report("gnutls_hash error: %s",
221*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
222*3e33af2cSGerd Hoffmann goto err;
223*3e33af2cSGerd Hoffmann }
224*3e33af2cSGerd Hoffmann rc = gnutls_hash(hash, fp, fp_size);
225*3e33af2cSGerd Hoffmann if (rc < 0) {
226*3e33af2cSGerd Hoffmann warn_report("gnutls_hash error: %s",
227*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
228*3e33af2cSGerd Hoffmann goto err;
229*3e33af2cSGerd Hoffmann }
230*3e33af2cSGerd Hoffmann gnutls_hash_deinit(hash, hash_digest);
231*3e33af2cSGerd Hoffmann
232*3e33af2cSGerd Hoffmann return 0;
233*3e33af2cSGerd Hoffmann
234*3e33af2cSGerd Hoffmann err:
235*3e33af2cSGerd Hoffmann g_free(cn);
236*3e33af2cSGerd Hoffmann return rc;
237*3e33af2cSGerd Hoffmann }
238*3e33af2cSGerd Hoffmann
239*3e33af2cSGerd Hoffmann /*
240*3e33af2cSGerd Hoffmann * uefi spec 2.9, section 8.2.2
241*3e33af2cSGerd Hoffmann *
242*3e33af2cSGerd Hoffmann * For EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS variables which are
243*3e33af2cSGerd Hoffmann * NOT secure boot variables we should track the root certificate of the trust
244*3e33af2cSGerd Hoffmann * chain, and the subject CN of the signer certificate.
245*3e33af2cSGerd Hoffmann *
246*3e33af2cSGerd Hoffmann * So we'll go store a digest of these two items so we can verify this. Also
247*3e33af2cSGerd Hoffmann * create a gnutls_x509_trust_list_t with the root certificate, so
248*3e33af2cSGerd Hoffmann * gnutls_pkcs7_verify() will pass (assuming the signature is otherwise
249*3e33af2cSGerd Hoffmann * correct).
250*3e33af2cSGerd Hoffmann */
build_trust_list_authvar(gnutls_pkcs7_t pkcs7,uint8_t * hash_digest)251*3e33af2cSGerd Hoffmann static gnutls_x509_trust_list_t build_trust_list_authvar(gnutls_pkcs7_t pkcs7,
252*3e33af2cSGerd Hoffmann uint8_t *hash_digest)
253*3e33af2cSGerd Hoffmann {
254*3e33af2cSGerd Hoffmann gnutls_datum_t signer_data = { 0 };
255*3e33af2cSGerd Hoffmann gnutls_datum_t root_data = { 0 };
256*3e33af2cSGerd Hoffmann gnutls_x509_crt_t signer = NULL;
257*3e33af2cSGerd Hoffmann gnutls_x509_crt_t root = NULL;
258*3e33af2cSGerd Hoffmann gnutls_x509_trust_list_t tlist = NULL;
259*3e33af2cSGerd Hoffmann int n, rc;
260*3e33af2cSGerd Hoffmann
261*3e33af2cSGerd Hoffmann n = gnutls_pkcs7_get_crt_count(pkcs7);
262*3e33af2cSGerd Hoffmann
263*3e33af2cSGerd Hoffmann /* first is signer certificate */
264*3e33af2cSGerd Hoffmann rc = gnutls_pkcs7_get_crt_raw2(pkcs7, 0, &signer_data);
265*3e33af2cSGerd Hoffmann if (rc < 0) {
266*3e33af2cSGerd Hoffmann warn_report("gnutls_pkcs7_get_crt_raw2(0) error: %s",
267*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
268*3e33af2cSGerd Hoffmann goto done;
269*3e33af2cSGerd Hoffmann }
270*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_init(&signer);
271*3e33af2cSGerd Hoffmann if (rc < 0) {
272*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
273*3e33af2cSGerd Hoffmann goto done;
274*3e33af2cSGerd Hoffmann }
275*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_import(signer, &signer_data, GNUTLS_X509_FMT_DER);
276*3e33af2cSGerd Hoffmann if (rc < 0) {
277*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_import error: %s",
278*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
279*3e33af2cSGerd Hoffmann gnutls_x509_crt_deinit(signer);
280*3e33af2cSGerd Hoffmann goto done;
281*3e33af2cSGerd Hoffmann }
282*3e33af2cSGerd Hoffmann
283*3e33af2cSGerd Hoffmann /* last is root-of-trust certificate (can be identical to signer) */
284*3e33af2cSGerd Hoffmann rc = gnutls_pkcs7_get_crt_raw2(pkcs7, n - 1, &root_data);
285*3e33af2cSGerd Hoffmann if (rc < 0) {
286*3e33af2cSGerd Hoffmann warn_report("gnutls_pkcs7_get_crt_raw2(%d) error: %s",
287*3e33af2cSGerd Hoffmann n - 1, gnutls_strerror(rc));
288*3e33af2cSGerd Hoffmann goto done;
289*3e33af2cSGerd Hoffmann }
290*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_init(&root);
291*3e33af2cSGerd Hoffmann if (rc < 0) {
292*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
293*3e33af2cSGerd Hoffmann goto done;
294*3e33af2cSGerd Hoffmann }
295*3e33af2cSGerd Hoffmann rc = gnutls_x509_crt_import(root, &root_data, GNUTLS_X509_FMT_DER);
296*3e33af2cSGerd Hoffmann if (rc < 0) {
297*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_import error: %s",
298*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
299*3e33af2cSGerd Hoffmann goto done;
300*3e33af2cSGerd Hoffmann }
301*3e33af2cSGerd Hoffmann
302*3e33af2cSGerd Hoffmann /* calc digest for signer CN + root cert */
303*3e33af2cSGerd Hoffmann rc = build_digest_authvar(signer, root, hash_digest);
304*3e33af2cSGerd Hoffmann if (rc < 0) {
305*3e33af2cSGerd Hoffmann goto done;
306*3e33af2cSGerd Hoffmann }
307*3e33af2cSGerd Hoffmann
308*3e33af2cSGerd Hoffmann /* add root to trust list */
309*3e33af2cSGerd Hoffmann rc = gnutls_x509_trust_list_init(&tlist, 0);
310*3e33af2cSGerd Hoffmann if (rc < 0) {
311*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_trust_list_init error: %s",
312*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
313*3e33af2cSGerd Hoffmann goto done;
314*3e33af2cSGerd Hoffmann }
315*3e33af2cSGerd Hoffmann rc = gnutls_x509_trust_list_add_cas(tlist, &root, 1, 0);
316*3e33af2cSGerd Hoffmann if (rc < 0) {
317*3e33af2cSGerd Hoffmann warn_report("gnutls_x509_crt_import error: %s",
318*3e33af2cSGerd Hoffmann gnutls_strerror(rc));
319*3e33af2cSGerd Hoffmann gnutls_x509_trust_list_deinit(tlist, 1);
320*3e33af2cSGerd Hoffmann tlist = NULL;
321*3e33af2cSGerd Hoffmann goto done;
322*3e33af2cSGerd Hoffmann } else {
323*3e33af2cSGerd Hoffmann /* ownership passed to tlist */
324*3e33af2cSGerd Hoffmann root = NULL;
325*3e33af2cSGerd Hoffmann }
326*3e33af2cSGerd Hoffmann
327*3e33af2cSGerd Hoffmann done:
328*3e33af2cSGerd Hoffmann if (signer_data.data) {
329*3e33af2cSGerd Hoffmann gnutls_free(signer_data.data);
330*3e33af2cSGerd Hoffmann }
331*3e33af2cSGerd Hoffmann if (root_data.data) {
332*3e33af2cSGerd Hoffmann gnutls_free(root_data.data);
333*3e33af2cSGerd Hoffmann }
334*3e33af2cSGerd Hoffmann if (signer) {
335*3e33af2cSGerd Hoffmann gnutls_x509_crt_deinit(signer);
336*3e33af2cSGerd Hoffmann }
337*3e33af2cSGerd Hoffmann if (root) {
338*3e33af2cSGerd Hoffmann gnutls_x509_crt_deinit(root);
339*3e33af2cSGerd Hoffmann }
340*3e33af2cSGerd Hoffmann return tlist;
341*3e33af2cSGerd Hoffmann }
342*3e33af2cSGerd Hoffmann
free_datum(gnutls_datum_t * ptr)343*3e33af2cSGerd Hoffmann static void free_datum(gnutls_datum_t *ptr)
344*3e33af2cSGerd Hoffmann {
345*3e33af2cSGerd Hoffmann if (!ptr) {
346*3e33af2cSGerd Hoffmann return;
347*3e33af2cSGerd Hoffmann }
348*3e33af2cSGerd Hoffmann g_free(ptr->data);
349*3e33af2cSGerd Hoffmann g_free(ptr);
350*3e33af2cSGerd Hoffmann }
351*3e33af2cSGerd Hoffmann
gnutls_log_stderr(int level,const char * msg)352*3e33af2cSGerd Hoffmann static void gnutls_log_stderr(int level, const char *msg)
353*3e33af2cSGerd Hoffmann {
354*3e33af2cSGerd Hoffmann if (strncmp(msg, "ASSERT:", 7) == 0) {
355*3e33af2cSGerd Hoffmann return;
356*3e33af2cSGerd Hoffmann }
357*3e33af2cSGerd Hoffmann fprintf(stderr, " %d: %s", level, msg);
358*3e33af2cSGerd Hoffmann }
359*3e33af2cSGerd Hoffmann
360*3e33af2cSGerd Hoffmann /*
361*3e33af2cSGerd Hoffmann * pkcs7 signature verification (EFI_VARIABLE_AUTHENTICATION_2).
362*3e33af2cSGerd Hoffmann */
uefi_vars_check_pkcs7_2(uefi_variable * siglist,void ** digest,uint32_t * digest_size,mm_variable_access * va,void * data)363*3e33af2cSGerd Hoffmann efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
364*3e33af2cSGerd Hoffmann void **digest, uint32_t *digest_size,
365*3e33af2cSGerd Hoffmann mm_variable_access *va, void *data)
366*3e33af2cSGerd Hoffmann {
367*3e33af2cSGerd Hoffmann gnutls_x509_trust_list_t tlist = NULL;
368*3e33af2cSGerd Hoffmann gnutls_datum_t *signed_data = NULL;
369*3e33af2cSGerd Hoffmann gnutls_datum_t *pkcs7_data = NULL;
370*3e33af2cSGerd Hoffmann gnutls_pkcs7_t pkcs7 = NULL;
371*3e33af2cSGerd Hoffmann efi_status status = EFI_SECURITY_VIOLATION;
372*3e33af2cSGerd Hoffmann int rc;
373*3e33af2cSGerd Hoffmann
374*3e33af2cSGerd Hoffmann if (0) {
375*3e33af2cSGerd Hoffmann /* gnutls debug logging */
376*3e33af2cSGerd Hoffmann static bool first = true;
377*3e33af2cSGerd Hoffmann
378*3e33af2cSGerd Hoffmann if (first) {
379*3e33af2cSGerd Hoffmann first = false;
380*3e33af2cSGerd Hoffmann gnutls_global_set_log_function(gnutls_log_stderr);
381*3e33af2cSGerd Hoffmann gnutls_global_set_log_level(99);
382*3e33af2cSGerd Hoffmann }
383*3e33af2cSGerd Hoffmann }
384*3e33af2cSGerd Hoffmann
385*3e33af2cSGerd Hoffmann signed_data = build_signed_data(va, data);
386*3e33af2cSGerd Hoffmann pkcs7_data = build_pkcs7(data);
387*3e33af2cSGerd Hoffmann
388*3e33af2cSGerd Hoffmann rc = gnutls_pkcs7_init(&pkcs7);
389*3e33af2cSGerd Hoffmann if (rc < 0) {
390*3e33af2cSGerd Hoffmann warn_report("gnutls_pkcs7_init error: %s", gnutls_strerror(rc));
391*3e33af2cSGerd Hoffmann goto out;
392*3e33af2cSGerd Hoffmann }
393*3e33af2cSGerd Hoffmann
394*3e33af2cSGerd Hoffmann rc = gnutls_pkcs7_import(pkcs7, pkcs7_data, GNUTLS_X509_FMT_DER);
395*3e33af2cSGerd Hoffmann if (rc < 0) {
396*3e33af2cSGerd Hoffmann warn_report("gnutls_pkcs7_import error: %s", gnutls_strerror(rc));
397*3e33af2cSGerd Hoffmann goto out;
398*3e33af2cSGerd Hoffmann }
399*3e33af2cSGerd Hoffmann
400*3e33af2cSGerd Hoffmann if (siglist) {
401*3e33af2cSGerd Hoffmann /* secure boot variables */
402*3e33af2cSGerd Hoffmann tlist = build_trust_list_sb(siglist);
403*3e33af2cSGerd Hoffmann } else if (digest && digest_size) {
404*3e33af2cSGerd Hoffmann /* other authenticated variables */
405*3e33af2cSGerd Hoffmann *digest_size = AUTHVAR_DIGEST_SIZE;
406*3e33af2cSGerd Hoffmann *digest = g_malloc(*digest_size);
407*3e33af2cSGerd Hoffmann tlist = build_trust_list_authvar(pkcs7, *digest);
408*3e33af2cSGerd Hoffmann } else {
409*3e33af2cSGerd Hoffmann /* should not happen */
410*3e33af2cSGerd Hoffmann goto out;
411*3e33af2cSGerd Hoffmann }
412*3e33af2cSGerd Hoffmann
413*3e33af2cSGerd Hoffmann rc = gnutls_pkcs7_verify(pkcs7, tlist,
414*3e33af2cSGerd Hoffmann NULL, 0,
415*3e33af2cSGerd Hoffmann 0, signed_data,
416*3e33af2cSGerd Hoffmann GNUTLS_VERIFY_DISABLE_TIME_CHECKS |
417*3e33af2cSGerd Hoffmann GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS);
418*3e33af2cSGerd Hoffmann if (rc < 0) {
419*3e33af2cSGerd Hoffmann warn_report("gnutls_pkcs7_verify error: %s", gnutls_strerror(rc));
420*3e33af2cSGerd Hoffmann goto out;
421*3e33af2cSGerd Hoffmann }
422*3e33af2cSGerd Hoffmann
423*3e33af2cSGerd Hoffmann /* check passed */
424*3e33af2cSGerd Hoffmann status = EFI_SUCCESS;
425*3e33af2cSGerd Hoffmann
426*3e33af2cSGerd Hoffmann out:
427*3e33af2cSGerd Hoffmann free_datum(signed_data);
428*3e33af2cSGerd Hoffmann free_datum(pkcs7_data);
429*3e33af2cSGerd Hoffmann if (tlist) {
430*3e33af2cSGerd Hoffmann gnutls_x509_trust_list_deinit(tlist, 1);
431*3e33af2cSGerd Hoffmann }
432*3e33af2cSGerd Hoffmann if (pkcs7) {
433*3e33af2cSGerd Hoffmann gnutls_pkcs7_deinit(pkcs7);
434*3e33af2cSGerd Hoffmann }
435*3e33af2cSGerd Hoffmann return status;
436*3e33af2cSGerd Hoffmann }
437