xref: /qemu/hw/uefi/var-service-pkcs7.c (revision 50aa3d0984d8a4a9c39d34e2f81e8a70674462e4)
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