]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsecureboot/openpgp/opgp_key.c
libsecureboot: make it easier to customize trust anchors
[FreeBSD/FreeBSD.git] / lib / libsecureboot / openpgp / opgp_key.c
1 /*-
2  * Copyright (c) 2018, Juniper Networks, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "../libsecureboot-priv.h"
30
31 #include "decode.h"
32 #include "packet.h"
33
34 /**
35  * @brief decode user-id packet
36  *
37  * This is trivial
38  *
39  * @sa rfc4880:5.11
40  */
41 ssize_t
42 decode_user(int tag, unsigned char **pptr, size_t len, OpenPGP_user *user)
43 {
44         char *cp;
45
46         if (tag == 13) {
47                 user->id = malloc(len + 1);
48                 strncpy(user->id, (char *)*pptr, len);
49                 user->id[len] = '\0';
50                 user->name = user->id;
51                 cp = strchr(user->id, '<');
52                 if (cp > user->id) {
53                         user->id = strdup(user->id);
54                         cp[-1] = '\0';
55                 }
56         }
57         *pptr += len;
58         return ((ssize_t)len);
59 }
60
61 /**
62  * @brief decode a key packet
63  *
64  * We only really support v4 and RSA
65  *
66  * @sa rfc4880:5.5.1.1
67  */
68 ssize_t
69 decode_key(int tag, unsigned char **pptr, size_t len, OpenPGP_key *key)
70 {
71         unsigned char *ptr;
72         int version;
73 #ifdef USE_BEARSSL
74         br_sha1_context mctx;
75         unsigned char mdata[br_sha512_SIZE];
76         size_t mlen;
77 #else
78         RSA *rsa = NULL;
79         const EVP_MD *md = NULL;
80         EVP_MD_CTX mctx;
81         unsigned char mdata[EVP_MAX_MD_SIZE];
82         unsigned int mlen;
83 #endif
84     
85         if (tag != 6)
86                 return (-1);
87
88         key->key = NULL;
89         ptr = *pptr;
90         version = *ptr;
91         if (version == 4) {             /* all we support really */
92                 /* comput key fingerprint and id @sa rfc4880:12.2 */
93                 mdata[0] = 0x99;        /* rfc4880: 12.2.a.1 */
94                 mdata[1] = (len >> 8) & 0xff;
95                 mdata[2] = len & 0xff;
96         
97 #ifdef USE_BEARSSL
98                 br_sha1_init(&mctx);
99                 br_sha1_update(&mctx, mdata, 3);
100                 br_sha1_update(&mctx, ptr, len);
101                 br_sha1_out(&mctx, mdata);
102                 mlen = br_sha1_SIZE;
103 #else
104                 md = EVP_get_digestbyname("sha1");
105                 EVP_DigestInit(&mctx, md);
106                 EVP_DigestUpdate(&mctx, mdata, 3);
107                 EVP_DigestUpdate(&mctx, ptr, len);
108                 mlen = (unsigned int)sizeof(mdata);
109                 EVP_DigestFinal(&mctx, mdata, &mlen);
110 #endif
111                 key->id = octets2hex(&mdata[mlen - 8], 8);
112         }
113         ptr += 1;                       /* done with version */
114         ptr += 4;                       /* skip ctime */
115         if (version == 3)
116                 ptr += 2;               /* valid days */
117         key->sig_alg = *ptr++;
118         if (key->sig_alg == 1) {        /* RSA */
119 #ifdef USE_BEARSSL
120                 key->key = NEW(br_rsa_public_key);
121                 if (!key->key)
122                         goto oops;
123                 key->key->n = mpi2bn(&ptr, &key->key->nlen);
124                 key->key->e = mpi2bn(&ptr, &key->key->elen);
125 #else
126                 rsa = RSA_new();
127                 if (!rsa)
128                         goto oops;
129                 rsa->n = mpi2bn(&ptr);
130                 rsa->e = mpi2bn(&ptr);
131                 key->key = EVP_PKEY_new();
132                 if (!key->key || !rsa->n || !rsa->e) {
133                         goto oops;
134                 }
135                 if (!EVP_PKEY_set1_RSA(key->key, rsa))
136                         goto oops;
137 #endif
138         }
139         /* we are done */
140         return ((ssize_t)len);
141 oops:
142 #ifdef USE_BEARSSL
143         free(key->key);
144         key->key = NULL;
145 #else
146         if (rsa)
147                 RSA_free(rsa);
148         if (key->key) {
149                 EVP_PKEY_free(key->key);
150                 key->key = NULL;
151         }
152 #endif
153         return (-1);
154 }
155
156 static OpenPGP_key *
157 load_key_buf(unsigned char *buf, size_t nbytes)
158 {
159         unsigned char *data = NULL;
160         unsigned char *ptr;
161         ssize_t rc;
162         int tag;
163         OpenPGP_key *key;
164     
165         if (!buf)
166                 return (NULL);
167
168         initialize();
169
170         if (!(buf[0] & OPENPGP_TAG_ISTAG)) {
171                 data = dearmor((char *)buf, nbytes, &nbytes);
172                 ptr = data;
173         } else
174                 ptr = buf;
175         key = NEW(OpenPGP_key);
176         if (key) {
177                 rc = decode_packet(0, &ptr, nbytes, (decoder_t)decode_key,
178                     key);
179                 if (rc < 0) {
180                         free(key);
181                         key = NULL;
182                 } else if (rc > 8) {
183                         int isnew, ltype;
184
185                         tag = decode_tag(ptr, &isnew, &ltype);
186                         if (tag == 13) {
187                                 key->user = NEW(OpenPGP_user);
188                                 rc = decode_packet(0, &ptr, (size_t)rc,
189                                     (decoder_t)decode_user, key->user);
190                         }
191                 }
192         }
193         free(data);
194         return (key);
195 }
196
197 static LIST_HEAD(, OpenPGP_key_) trust_list;
198
199 /**
200  * @brief add a key to our list
201  */
202 void
203 openpgp_trust_add(OpenPGP_key *key)
204 {
205         static int once = 0;
206
207         if (!once) {
208                 once = 1;
209
210                 LIST_INIT(&trust_list);
211         }
212         if (key)
213                 LIST_INSERT_HEAD(&trust_list, key, entries);
214 }
215
216 /**
217  * @brief if keyID is in our list return the key
218  *
219  * @return key or NULL
220  */
221 OpenPGP_key *
222 openpgp_trust_get(const char *keyID)
223 {
224         OpenPGP_key *key;
225
226         openpgp_trust_add(NULL);        /* initialize if needed */
227
228         LIST_FOREACH(key, &trust_list, entries) {
229                 if (strcmp(key->id, keyID) == 0)
230                         return (key);
231         }
232         return (NULL);
233 }
234
235 /**
236  * @brief load a key from file
237  */
238 OpenPGP_key *
239 load_key_file(const char *kfile)
240 {
241         unsigned char *data = NULL;
242         size_t n;
243         OpenPGP_key *key;
244
245         data = read_file(kfile, &n);
246         key = load_key_buf(data, n);
247         free(data);
248         openpgp_trust_add(key);
249         return (key);
250 }
251
252 #include <ta_asc.h>
253
254 #ifndef _STANDALONE
255 /* we can lookup keyID in filesystem */
256
257 static const char *trust_store[] = {
258         "/var/db/trust",
259         "/etc/db/trust",
260         NULL,
261 };
262
263 /**
264  * @brief lookup key id in trust store
265  *
266  */
267 static OpenPGP_key *
268 load_trusted_key_id(const char *keyID)
269 {
270         char kfile[MAXPATHLEN];
271         const char **tp;
272         size_t n;
273
274         for (tp = trust_store; *tp; tp++) {
275                 n = (size_t)snprintf(kfile, sizeof(kfile), "%s/%s", *tp, keyID);
276                 if (n >= sizeof(kfile))
277                         return (NULL);
278                 if (access(kfile, R_OK) == 0) {
279                         return (load_key_file(kfile));
280                 }
281         }
282         return (NULL);
283 }
284 #endif
285
286 /**
287  * @brief return key if trusted
288  */
289 OpenPGP_key *
290 load_key_id(const char *keyID)
291 {
292         OpenPGP_key *key;
293
294         key = openpgp_trust_get(keyID);
295 #ifndef _STANDALONE
296         if (!key)
297                 key = load_trusted_key_id(keyID);
298 #endif
299         return (key);
300 }
301
302 /**
303  * @brief initialize our internal trust store if any
304  */
305 int
306 openpgp_trust_init(void)
307 {
308         static int once = -1;
309 #ifdef HAVE_TA_ASC
310         OpenPGP_key *key;
311         const char **tp;
312         char *cp;
313         size_t n;
314 #endif
315
316         if (once < 0) {
317                 once = 0;
318 #ifdef HAVE_TA_ASC
319                 for (tp = ta_ASC; *tp; tp++) {
320                         if ((cp = strdup(*tp))) {
321                                 n = strlen(cp);
322                                 key = load_key_buf((unsigned char *)cp, n);
323                                 free(cp);
324                                 if (key) {
325                                         openpgp_trust_add(key);
326                                         once++;
327                                 }
328                         }
329                 }
330         }
331 #endif
332         return (once);
333 }
334
335 /**
336  * @brief test that we can verify a signature
337  *
338  * Unlike X.509 certificates, we only support RSA keys
339  * so we stop after first successful signature verification
340  * (which should also be the first attempt ;-)
341  */
342 int
343 openpgp_self_tests(void)
344 {
345         static int rc = -1;             /* remember result */
346 #ifdef HAVE_VC_ASC
347         const char **vp, **tp;
348         char *fdata, *sdata = NULL;
349         size_t fbytes, sbytes;
350
351         if (openpgp_trust_init() > 0) {
352                 for (tp = ta_ASC, vp = vc_ASC; *tp && *vp && rc; tp++, vp++) {
353                         if ((fdata = strdup(*tp)) &&
354                             (sdata = strdup(*vp))) {
355                                 fbytes = strlen(fdata);
356                                 sbytes = strlen(sdata);
357                                 rc = openpgp_verify("ta_ASC",
358                                     (unsigned char *)fdata, fbytes,
359                                     (unsigned char *)sdata, sbytes, 0);
360                                 printf("Testing verify OpenPGP signature:\t\t%s\n",
361                                     rc ? "Failed" : "Passed");
362                         }
363                         free(fdata);
364                         free(sdata);
365                 }
366         }
367 #endif
368         return (rc);
369 }