xref: /freebsd/lib/libsecureboot/openpgp/opgp_sig.c (revision 8c5a9161d16094d9db474fe78ddead1325246d05)
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  * RCSid:
27  *	from: signer.c,v 1.10 2018/03/23 01:14:30 sjg
28  *
29  *	@(#) Copyright (c) 2012 Simon J. Gerraty
30  *
31  *	This file is provided in the hope that it will
32  *	be of use.  There is absolutely NO WARRANTY.
33  *	Permission to copy, redistribute or otherwise
34  *	use this file is hereby granted provided that
35  *	the above copyright notice and this notice are
36  *	left intact.
37  *
38  *	Please send copies of changes and bug-fixes to:
39  *	sjg@crufty.net
40  */
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include "../libsecureboot-priv.h"
46 #ifdef _STANDALONE
47 #define warnx printf
48 #else
49 
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <fcntl.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <err.h>
58 #endif
59 
60 #include "decode.h"
61 #include "packet.h"
62 
63 #ifdef USE_BEARSSL
64 
65 #define get_error_string ve_error_get
66 
67 void
68 initialize (void)
69 {
70 #ifdef _STANDALONE
71     ve_trust_init();
72 #endif
73 }
74 
75 #else
76 
77 #include <openssl/err.h>
78 
79 /**
80  * @brief intialize OpenSSL
81  */
82 void
83 initialize(void)
84 {
85 	static int once;
86 
87 	if (once)
88 		return);
89 	once = 1;
90 	//CRYPTO_malloc_init();
91 	ERR_load_crypto_strings();
92 	OpenSSL_add_all_algorithms();
93 }
94 
95 /**
96  * @brief
97  * last error from OpenSSL as a string
98  */
99 char *
100 get_error_string(void)
101 {
102 	initialize();
103 	return (ERR_error_string(ERR_get_error(), NULL));
104 }
105 #endif
106 
107 /**
108  * @brief decode a signature packet
109  *
110  * We only support RSA
111  *
112  * @sa rfc4880:5.2
113  */
114 ssize_t
115 decode_sig(int tag, unsigned char **pptr, size_t len, OpenPGP_sig *sig)
116 {
117 	unsigned char *ptr;
118 	unsigned char *pgpbytes;
119 	unsigned char *sp;
120 	int version;
121 	int hcount = 0;
122 	int ucount = 0;
123 	int stag = 0;
124 	int n;
125 
126 	n = tag;			/* avoid unused */
127 
128 	/*
129 	 * We need to keep a reference to the packet bytes
130 	 * as these form part of the signature data.
131 	 *
132 	 * @sa rfc4880:5.2.4
133 	 */
134 	pgpbytes = ptr = *pptr;
135 	version = *ptr++;
136 	if (version == 3) {
137 		ptr++;
138 		sig->pgpbytes = malloc(5);
139 		if (!sig->pgpbytes)
140 			return (-1);
141 		memcpy(sig->pgpbytes, ptr, 5);
142 		sig->pgpbytes_len = 5;
143 		sig->sig_type = *ptr++;
144 		ptr += 4;
145 		sig->key_id = octets2hex(ptr, 8);
146 		ptr += 8;
147 		sig->sig_alg = *ptr++;
148 		sig->hash_alg = *ptr++;
149 	} else if (version == 4) {
150 		sig->sig_type = *ptr++;
151 		sig->sig_alg = *ptr++;
152 		sig->hash_alg = *ptr++;
153 		hcount = octets2i(ptr, 2);
154 		ptr += 2;
155 		sig->pgpbytes_len = (size_t)hcount + 6;
156 		sig->pgpbytes = malloc(sig->pgpbytes_len + 6);
157 		if (!sig->pgpbytes)
158 			return (-1);
159 		memcpy(sig->pgpbytes, pgpbytes, sig->pgpbytes_len);
160 		sp = &sig->pgpbytes[sig->pgpbytes_len];
161 		*sp++ = 4;
162 		*sp++ = 255;
163 		memcpy(sp, i2octets(4, (int)sig->pgpbytes_len), 4);
164 		sig->pgpbytes_len += 6;
165 
166 		while (hcount > 0) {
167 			sp = decode_subpacket(&ptr, &stag, &n);
168 			hcount -= n;
169 			/* can check stag to see if we care */
170 		}
171 		ucount = octets2i(ptr, 2);
172 		ptr += 2;
173 		while (ucount > 0) {
174 			sp = decode_subpacket(&ptr, &stag, &n);
175 			ucount -= n;
176 			/* can check stag to see if we care */
177 			if (stag == 16) {
178 				free(sig->key_id);
179 				sig->key_id = octets2hex(sp, 8);
180 			}
181 		}
182 	} else
183 		return (-1);
184 	ptr += 2;			/* skip hash16 */
185 	if (sig->sig_alg == 1) {	/* RSA */
186 		sig->sig = decode_mpi(&ptr, &sig->sig_len);
187 	}
188 	/* we are done */
189 	return ((ssize_t)len);
190 }
191 
192 /**
193  * @brief map OpenPGP hash algorithm id's to name
194  *
195  * @sa rfc4880:9.4
196  */
197 static struct hash_alg_map {
198 	int halg;
199 	const char *hname;
200 } hash_algs[] = {
201 	{1, "md5"},
202 	{2, "sha1"},
203 	{8, "sha256"},
204 	{9, "sha384"},
205 	{10, "sha512"},
206 	{11, "sha224"},
207 	{0, NULL},
208 };
209 
210 static const char *
211 get_hname(int hash_alg)
212 {
213 	struct hash_alg_map *hmp;
214 
215 	for (hmp = hash_algs; hmp->halg > 0; hmp++) {
216 		if (hmp->halg == hash_alg)
217 			return (hmp->hname);
218 	}
219 	return (NULL);
220 }
221 
222 /* lifted from signer.c */
223 /**
224  * @brief verify a digest
225  *
226  * The public key, digest name, file and signature data.
227  *
228  * @return 1 on success 0 on failure, -1 on error
229  */
230 #ifndef USE_BEARSSL
231 static int
232 verify_digest (EVP_PKEY *pkey,
233     const char *digest,
234     unsigned char *mdata, size_t mlen,
235     unsigned char *sdata, size_t slen)
236 {
237 	EVP_MD_CTX ctx;
238 	const EVP_MD *md = NULL;
239 	EVP_PKEY_CTX *pctx = NULL;
240 	int rc = 0;
241 	int i = -1;
242 
243 	initialize();
244 	md = EVP_get_digestbyname(digest);
245 	EVP_DigestInit(&ctx, md);
246 
247 	pctx = EVP_PKEY_CTX_new(pkey, NULL);
248 	if (!pctx)
249 		goto fail;
250 	if (EVP_PKEY_verify_init(pctx) <= 0)
251 		goto fail;
252 	if (EVP_PKEY_CTX_set_signature_md(pctx, ctx.digest) <= 0)
253 		goto fail;
254 	i = EVP_PKEY_verify(pctx, sdata, slen, mdata, mlen);
255 	if (i >= 0)
256 		rc = i;
257 fail:
258 	EVP_PKEY_CTX_free(pctx);
259 	return (rc);
260 }
261 #endif
262 
263 
264 /**
265  * @brief verify OpenPGP signed file
266  *
267  *
268  * @param[in] filename
269  *	used to determine the signature name
270  *
271  * @param[in] fdata
272  *	content of filename
273  *
274  * @param[in] fbytes
275  *	of fdata
276  *
277  * @param[in] sdata
278  *	content of signature
279  *
280  * @param[in] sbytes
281  *	of sdata
282  *
283  * @param[in] flags
284  *
285  * @return 0 on success
286  */
287 int
288 openpgp_verify(const char *filename,
289     unsigned char *fdata, size_t fbytes,
290     unsigned char *sdata, size_t sbytes,
291     int flags)
292 {
293 	OpenPGP_key *key;
294 	OpenPGP_sig *sig;
295 #ifdef USE_BEARSSL
296 	const br_hash_class *md;
297 	br_hash_compat_context mctx;
298 	const unsigned char *hash_oid;
299 #else
300 	const EVP_MD *md = NULL;
301 	EVP_MD_CTX mctx;
302 #endif
303 	unsigned char mdata[64];
304 	unsigned char *ptr;
305 	unsigned char *ddata = NULL;
306 	const char *hname;
307 	size_t mlen;
308 	int rc = -1;
309 
310 	initialize();
311 
312 	sig = NEW(OpenPGP_sig);
313 	if (!sdata || !sig) {
314 		warnx("cannot verify %s", filename);
315 		goto oops;
316 	}
317 	if (!(sdata[0] & OPENPGP_TAG_ISTAG))
318 		sdata = ddata = dearmor((char *)sdata, sbytes, &sbytes);
319 	ptr = sdata;
320 	rc = decode_packet(2, &ptr, sbytes, (decoder_t)decode_sig, sig);
321 	DEBUG_PRINTF(2, ("rc=%d keyID=%s\n", rc, sig->key_id ? sig->key_id : "?"));
322 	if (rc == 0 && sig->key_id) {
323 		key = load_key_id(sig->key_id);
324 		if (!key) {
325 			warnx("cannot find key-id: %s", sig->key_id);
326 			rc = -1;
327 		} else if (!(hname = get_hname(sig->hash_alg))) {
328 			warnx("unsupported hash algorithm: %d", sig->hash_alg);
329 			rc = -1;
330 		} else {
331 			/*
332 			 * Hash fdata according to the OpenPGP recipe
333 			 *
334 			 * @sa rfc4880:5.2.4
335 			 */
336 #ifdef USE_BEARSSL
337 			switch (sig->hash_alg) { /* see hash_algs above */
338 			case 2:			 /* sha1 */
339 				md = &br_sha1_vtable;
340 				mlen = br_sha1_SIZE;
341 				hash_oid = BR_HASH_OID_SHA1;
342 				break;
343 			case 8:			/* sha256 */
344 				md = &br_sha256_vtable;
345 				mlen = br_sha256_SIZE;
346 				hash_oid = BR_HASH_OID_SHA256;
347 				break;
348 			default:
349 				warnx("unsupported hash algorithm: %s", hname);
350 				goto oops;
351 			}
352 			md->init(&mctx.vtable);
353 			md->update(&mctx.vtable, fdata, fbytes);
354 			md->update(&mctx.vtable, sig->pgpbytes,
355 			    sig->pgpbytes_len);
356 			md->out(&mctx.vtable, mdata);
357 
358 			rc = verify_rsa_digest(key->key, hash_oid,
359 			    mdata, mlen, sig->sig, sig->sig_len);
360 #else
361 			md = EVP_get_digestbyname(hname);
362 			EVP_DigestInit(&mctx, md);
363 			EVP_DigestUpdate(&mctx, fdata, fbytes);
364 			EVP_DigestUpdate(&mctx, sig->pgpbytes,
365 			    sig->pgpbytes_len);
366 			mlen = sizeof(mdata);
367 			EVP_DigestFinal(&mctx,mdata,(unsigned int *)&mlen);
368 
369 			rc = verify_digest(key->key, hname, mdata, mlen,
370 			    sig->sig, sig->sig_len);
371 #endif
372 
373 			if (rc > 0) {
374 				if ((flags & 1))
375 					printf("Verified %s signed by %s\n",
376 					    filename,
377 					    key->user ? key->user->name : "someone");
378 				rc = 0;	/* success */
379 			} else if (rc == 0) {
380 				printf("Unverified %s: %s\n",
381 				    filename, get_error_string());
382 				rc = 1;
383 			} else {
384 				printf("Unverified %s\n", filename);
385 			}
386 		}
387 	} else {
388 		warnx("cannot decode signature for %s", filename);
389 		rc = -1;
390 	}
391 oops:
392 	free(ddata);
393 	free(sig);
394 	return (rc);
395 }
396 
397 #ifndef _STANDALONE
398 /**
399  * @brief list of extensions we handle
400  *
401  * ".asc" is preferred as it works seamlessly with openpgp
402  */
403 static const char *sig_exts[] = {
404 	".asc",
405 	".pgp",
406 	".psig",
407 	NULL,
408 };
409 
410 /**
411  * @brief verify OpenPGP signed file
412  *
413  *
414  * @param[in] filename
415  *	used to determine the signature name
416  *
417  * @param[in] fdata
418  *	content of filename
419  *
420  * @param[in] nbytes
421  *	of fdata
422  *
423  * @return
424  */
425 
426 int
427 openpgp_verify_file(const char *filename, unsigned char *fdata, size_t nbytes)
428 {
429 	char pbuf[MAXPATHLEN];
430 	unsigned char *sdata;
431 	const char *sname = NULL;
432 	const char **ep;
433 	size_t sz;
434 	int n;
435 
436 	for (ep = sig_exts; *ep; ep++) {
437 		n = snprintf(pbuf, sizeof(pbuf), "%s%s", filename, *ep);
438 		if (n >= (int)sizeof(pbuf)) {
439 			warnx("cannot form signature name for %s", filename);
440 			return (-1);
441 		}
442 		if (access(pbuf, R_OK) == 0) {
443 			sname = pbuf;
444 			break;
445 		}
446 	}
447 	if (!sname) {
448 		warnx("cannot find signature for %s", filename);
449 		return (-1);
450 	}
451 	sdata = read_file(sname, &sz);
452 	return (openpgp_verify(filename, fdata, nbytes, sdata, sz, 1));
453 }
454 #endif
455 
456 /**
457  * @brief verify OpenPGP signature
458  *
459  * @return content of signed file
460  */
461 unsigned char *
462 verify_asc(const char *sigfile, int flags)
463 {
464 	char pbuf[MAXPATHLEN];
465 	char *cp;
466 	size_t n;
467 	unsigned char *fdata, *sdata;
468 	size_t fbytes, sbytes;
469 
470 	if ((sdata = read_file(sigfile, &sbytes))) {
471 		n = strlcpy(pbuf, sigfile, sizeof(pbuf));
472 		if ((cp = strrchr(pbuf, '.')))
473 			*cp = '\0';
474 		if ((fdata = read_file(pbuf, &fbytes))) {
475 			if (openpgp_verify(pbuf, fdata, fbytes, sdata,
476 				sbytes, flags)) {
477 				free(fdata);
478 				fdata = NULL;
479 			}
480 		}
481 	} else
482 		fdata = NULL;
483 	free(sdata);
484 	return (fdata);
485 }
486