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