xref: /freebsd/lib/libsecureboot/vets.c (revision b7d75bb75cbcaee0015f024bef3476cd5710ba03)
1 /*-
2  * Copyright (c) 2017-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 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD$");
27 
28 /**
29  * @file vets.c - trust store
30  * @brief verify signatures
31  *
32  * We leverage code from BearSSL www.bearssl.org
33  */
34 
35 #include <sys/time.h>
36 #include <stdarg.h>
37 #define NEED_BRSSL_H
38 #include "libsecureboot-priv.h"
39 #include <brssl.h>
40 #include <ta.h>
41 
42 #ifndef TRUST_ANCHOR_STR
43 # define TRUST_ANCHOR_STR ta_PEM
44 #endif
45 
46 #define SECONDS_PER_DAY		86400
47 #define X509_DAYS_TO_UTC0	719528
48 
49 int DebugVe = 0;
50 
51 typedef VECTOR(br_x509_certificate) cert_list;
52 
53 static anchor_list trust_anchors = VEC_INIT;
54 
55 void
56 ve_debug_set(int n)
57 {
58 	DebugVe = n;
59 }
60 
61 static char ebuf[512];
62 
63 char *
64 ve_error_get(void)
65 {
66 	return (ebuf);
67 }
68 
69 int
70 ve_error_set(const char *fmt, ...)
71 {
72 	int rc;
73 	va_list ap;
74 
75 	va_start(ap, fmt);
76 	ebuf[0] = '\0';
77 	rc = 0;
78 	if (fmt) {
79 #ifdef STAND_H
80 		vsprintf(ebuf, fmt, ap); /* no vsnprintf in libstand */
81 		ebuf[sizeof(ebuf) - 1] = '\0';
82 		rc = strlen(ebuf);
83 #else
84 		rc = vsnprintf(ebuf, sizeof(ebuf), fmt, ap);
85 #endif
86 	}
87 	va_end(ap);
88 	return (rc);
89 }
90 
91 /* this is the time we use for verifying certs */
92 static time_t ve_utc = 0;
93 
94 /**
95  * @brief
96  * set ve_utc used for certificate verification
97  *
98  * @param[in] utc
99  *	time - ignored unless greater than current value.
100  */
101 void
102 ve_utc_set(time_t utc)
103 {
104 	if (utc > ve_utc) {
105 		DEBUG_PRINTF(2, ("Set ve_utc=%jd\n", (intmax_t)utc));
106 		ve_utc = utc;
107 	}
108 }
109 
110 static void
111 free_cert_contents(br_x509_certificate *xc)
112 {
113 	xfree(xc->data);
114 }
115 
116 /**
117  * @brief
118  * add certs to our trust store
119  */
120 size_t
121 ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
122 {
123 	br_x509_trust_anchor ta;
124 	size_t u;
125 
126 	for (u = 0; u < num; u++) {
127 		if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
128 			break;
129 		}
130 		VEC_ADD(trust_anchors, ta);
131 	}
132 	return (u);
133 }
134 
135 /**
136  * @brief
137  * initialize our trust_anchors from ta_PEM
138  */
139 int
140 ve_trust_init(void)
141 {
142 	br_x509_certificate *xcs;
143 	static int once = -1;
144 	size_t num;
145 
146 	if (once >= 0)
147 		return (once);
148 	once = 0;
149 
150 	ve_utc_set(time(NULL));
151 #ifdef BUILD_UTC
152 	ve_utc_set(BUILD_UTC);		/* just in case */
153 #endif
154 	ve_error_set(NULL);		/* make sure it is empty */
155 #ifdef VE_PCR_SUPPORT
156 	ve_pcr_init();
157 #endif
158 
159 #ifdef TRUST_ANCHOR_STR
160 	xcs = parse_certificates(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
161 	    sizeof(TRUST_ANCHOR_STR), &num);
162 	if (xcs == NULL)
163 		return (0);
164 	num = ve_trust_anchors_add(xcs, num);
165 	once = (int) num;
166 #else
167 	num = 0;
168 #endif
169 	return (num);
170 }
171 
172 /**
173  * if we can verify the certificate chain in "certs",
174  * return the public key and if "xcp" is !NULL the associated
175  * certificate
176  */
177 static br_x509_pkey *
178 verify_signer_xcs(br_x509_certificate *xcs,
179     size_t num,
180     br_name_element *elts, size_t num_elts)
181 {
182 	br_x509_minimal_context mc;
183 	br_x509_certificate *xc;
184 	size_t u;
185 	cert_list chain = VEC_INIT;
186 	const br_x509_pkey *tpk;
187 	br_x509_pkey *pk;
188 	unsigned int usages;
189 	int err;
190 
191 	DEBUG_PRINTF(5, ("verify_signer: %zu certs in chain\n", num));
192 	VEC_ADDMANY(chain, xcs, num);
193 	if (VEC_LEN(chain) == 0) {
194 		ve_error_set("ERROR: no/invalid certificate chain\n");
195 		return (NULL);
196 	}
197 
198 	DEBUG_PRINTF(5, ("verify_signer: %zu trust anchors\n",
199 		VEC_LEN(trust_anchors)));
200 
201 	br_x509_minimal_init(&mc, &br_sha256_vtable,
202 	    &VEC_ELT(trust_anchors, 0),
203 	    VEC_LEN(trust_anchors));
204 #ifdef VE_ECDSA_SUPPORT
205 	br_x509_minimal_set_ecdsa(&mc,
206 	    &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
207 #endif
208 #ifdef VE_RSA_SUPPORT
209 	br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
210 #endif
211 #if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT)
212 	/* This is deprecated! do not enable unless you absoultely have to */
213 	br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
214 #endif
215 	br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
216 #ifdef VE_SHA384_SUPPORT
217 	br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
218 #endif
219 #ifdef VE_SHA512_SUPPORT
220 	br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
221 #endif
222 	br_x509_minimal_set_name_elements(&mc, elts, num_elts);
223 
224 #ifdef _STANDALONE
225 	/*
226 	 * Clock is probably bogus so we use ve_utc.
227 	 */
228 	mc.days = (ve_utc / SECONDS_PER_DAY) + X509_DAYS_TO_UTC0;
229 	mc.seconds = (ve_utc % SECONDS_PER_DAY);
230 #endif
231 
232 	mc.vtable->start_chain(&mc.vtable, NULL);
233 	for (u = 0; u < VEC_LEN(chain); u ++) {
234 		xc = &VEC_ELT(chain, u);
235 		mc.vtable->start_cert(&mc.vtable, xc->data_len);
236 		mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
237 		mc.vtable->end_cert(&mc.vtable);
238 		switch (mc.err) {
239 		case 0:
240 		case BR_ERR_X509_OK:
241 		case BR_ERR_X509_EXPIRED:
242 			break;
243 		default:
244 			printf("u=%zu mc.err=%d\n", u, mc.err);
245 			break;
246 		}
247 	}
248 	err = mc.vtable->end_chain(&mc.vtable);
249 	pk = NULL;
250 	if (err) {
251 		ve_error_set("Validation failed, err = %d", err);
252 	} else {
253 		tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
254 		if (tpk != NULL) {
255 			pk = xpkeydup(tpk);
256 		}
257 	}
258 	VEC_CLEAREXT(chain, &free_cert_contents);
259 	return (pk);
260 }
261 
262 static br_x509_pkey *
263 verify_signer(const char *certs,
264     br_name_element *elts, size_t num_elts)
265 {
266 	br_x509_certificate *xcs;
267 	br_x509_pkey *pk;
268 	size_t num;
269 
270 	ve_trust_init();
271 	xcs = read_certificates(certs, &num);
272 	if (xcs == NULL) {
273 		ve_error_set("cannot read certificates\n");
274 		return (NULL);
275 	}
276 	pk = verify_signer_xcs(xcs, num, elts, num_elts);
277 	xfree(xcs);
278 	return (pk);
279 }
280 
281 /**
282  * we need a hex digest including trailing newline below
283  */
284 char *
285 hexdigest(char *buf, size_t bufsz, unsigned char *foo, size_t foo_len)
286 {
287 	char const hex2ascii[] = "0123456789abcdef";
288 	size_t i;
289 
290 	/* every binary byte is 2 chars in hex + newline + null  */
291 	if (bufsz < (2 * foo_len) + 2)
292 		return (NULL);
293 
294 	for (i = 0; i < foo_len; i++) {
295 		buf[i * 2] = hex2ascii[foo[i] >> 4];
296 		buf[i * 2 + 1] = hex2ascii[foo[i] & 0x0f];
297 	}
298 
299 	buf[i * 2] = 0x0A; /* we also want a newline */
300 	buf[i * 2 + 1] = '\0';
301 
302 	return (buf);
303 }
304 
305 /**
306  * @brief
307  * verify file against sigfile using pk
308  *
309  * When we generated the signature in sigfile,
310  * we hashed (sha256) file, and sent that to signing server
311  * which hashed (sha256) that hash.
312  *
313  * To verify we need to replicate that result.
314  *
315  * @param[in] pk
316  *	br_x509_pkey
317  *
318  * @paramp[in] file
319  *	file to be verified
320  *
321  * @param[in] sigfile
322  * 	signature (PEM encoded)
323  *
324  * @return NULL on error, otherwise content of file.
325  */
326 #ifdef VE_ECDSA_SUPPORT
327 static unsigned char *
328 verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile)
329 {
330 	char hexbuf[br_sha512_SIZE * 2 + 2];
331 	unsigned char rhbuf[br_sha512_SIZE];
332 	char *hex;
333 	br_sha256_context ctx;
334 	unsigned char *fcp, *scp;
335 	size_t flen, slen, plen;
336 	pem_object *po;
337 	const br_ec_impl *ec;
338 	br_ecdsa_vrfy vrfy;
339 
340 	if ((fcp = read_file(file, &flen)) == NULL)
341 		return (NULL);
342 	if ((scp = read_file(sigfile, &slen)) == NULL) {
343 		free(fcp);
344 		return (NULL);
345 	}
346 	if ((po = decode_pem(scp, slen, &plen)) == NULL) {
347 		free(fcp);
348 		free(scp);
349 		return (NULL);
350 	}
351 	br_sha256_init(&ctx);
352 	br_sha256_update(&ctx, fcp, flen);
353 	br_sha256_out(&ctx, rhbuf);
354 	hex = hexdigest(hexbuf, sizeof(hexbuf), rhbuf, br_sha256_SIZE);
355 	/* now hash that */
356 	if (hex) {
357 		br_sha256_init(&ctx);
358 		br_sha256_update(&ctx, hex, strlen(hex));
359 		br_sha256_out(&ctx, rhbuf);
360 	}
361 	ec = br_ec_get_default();
362 	vrfy = br_ecdsa_vrfy_asn1_get_default();
363 	if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data,
364 		po->data_len)) {
365 		free(fcp);
366 		fcp = NULL;
367 	}
368 	free(scp);
369 	return (fcp);
370 }
371 #endif
372 
373 #if defined(VE_RSA_SUPPORT) || defined(VE_OPENPGP_SUPPORT)
374 /**
375  * @brief verify an rsa digest
376  *
377  * @return 0 on failure
378  */
379 int
380 verify_rsa_digest (br_rsa_public_key *pkey,
381     const unsigned char *hash_oid,
382     unsigned char *mdata, size_t mlen,
383     unsigned char *sdata, size_t slen)
384 {
385 	br_rsa_pkcs1_vrfy vrfy;
386 	unsigned char vhbuf[br_sha512_SIZE];
387 
388 	vrfy = br_rsa_pkcs1_vrfy_get_default();
389 
390 	if (!vrfy(sdata, slen, hash_oid, mlen, pkey, vhbuf) ||
391 	    memcmp(vhbuf, mdata, mlen) != 0) {
392 		return (0);		/* fail */
393 	}
394 	return (1);			/* ok */
395 }
396 #endif
397 
398 /**
399  * @brief
400  * verify file against sigfile using pk
401  *
402  * When we generated the signature in sigfile,
403  * we hashed (sha256) file, and sent that to signing server
404  * which hashed (sha256) that hash.
405  *
406  * Or (deprecated) we simply used sha1 hash directly.
407  *
408  * To verify we need to replicate that result.
409  *
410  * @param[in] pk
411  *	br_x509_pkey
412  *
413  * @paramp[in] file
414  *	file to be verified
415  *
416  * @param[in] sigfile
417  * 	signature (PEM encoded)
418  *
419  * @return NULL on error, otherwise content of file.
420  */
421 #ifdef VE_RSA_SUPPORT
422 static unsigned char *
423 verify_rsa(br_x509_pkey *pk,  const char *file, const char *sigfile)
424 {
425 	unsigned char rhbuf[br_sha512_SIZE];
426 	const unsigned char *hash_oid;
427 	const br_hash_class *md;
428 	br_hash_compat_context mctx;
429 	unsigned char *fcp, *scp;
430 	size_t flen, slen, plen, hlen;
431 	pem_object *po;
432 
433 	if ((fcp = read_file(file, &flen)) == NULL)
434 		return (NULL);
435 	if ((scp = read_file(sigfile, &slen)) == NULL) {
436 		free(fcp);
437 		return (NULL);
438 	}
439 	if ((po = decode_pem(scp, slen, &plen)) == NULL) {
440 		free(fcp);
441 		free(scp);
442 		return (NULL);
443 	}
444 
445 	switch (po->data_len) {
446 #if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT)
447 	case 256:
448 		// this is our old deprecated sig method
449 		md = &br_sha1_vtable;
450 		hlen = br_sha1_SIZE;
451 		hash_oid = BR_HASH_OID_SHA1;
452 		break;
453 #endif
454 	default:
455 		md = &br_sha256_vtable;
456 		hlen = br_sha256_SIZE;
457 		hash_oid = BR_HASH_OID_SHA256;
458 		break;
459 	}
460 	md->init(&mctx.vtable);
461 	md->update(&mctx.vtable, fcp, flen);
462 	md->out(&mctx.vtable, rhbuf);
463 	if (!verify_rsa_digest(&pk->key.rsa, hash_oid,
464 		rhbuf, hlen, po->data, po->data_len)) {
465 		free(fcp);
466 		fcp = NULL;
467 	}
468 	free(scp);
469 	return (fcp);
470 }
471 #endif
472 
473 /**
474  * @brief
475  * verify a signature and return content of signed file
476  *
477  * @param[in] sigfile
478  * 	file containing signature
479  * 	we derrive path of signed file and certificate change from
480  * 	this.
481  *
482  * @param[in] flags
483  * 	only bit 1 significant so far
484  *
485  * @return NULL on error otherwise content of signed file
486  */
487 unsigned char *
488 verify_sig(const char *sigfile, int flags)
489 {
490 	br_x509_pkey *pk;
491 	br_name_element cn;
492 	char cn_buf[80];
493 	unsigned char cn_oid[4];
494 	char pbuf[MAXPATHLEN];
495 	char *cp;
496 	unsigned char *ucp;
497 	size_t n;
498 
499 	DEBUG_PRINTF(5, ("verify_sig: %s\n", sigfile));
500 	n = strlcpy(pbuf, sigfile, sizeof(pbuf));
501 	if (n > (sizeof(pbuf) - 5) || strcmp(&sigfile[n - 3], "sig") != 0)
502 		return (NULL);
503 	cp = strcpy(&pbuf[n - 3], "certs");
504 	/*
505 	 * We want the commonName field
506 	 * the OID we want is 2,5,4,3 - but DER encoded
507 	 */
508 	cn_oid[0] = 3;
509 	cn_oid[1] = 0x55;
510 	cn_oid[2] = 4;
511 	cn_oid[3] = 3;
512 	cn.oid = cn_oid;
513 	cn.buf = cn_buf;
514 	cn.len = sizeof(cn_buf);
515 
516 	pk = verify_signer(pbuf, &cn, 1);
517 	if (!pk) {
518 		printf("cannot verify: %s: %s\n", pbuf, ve_error_get());
519 		return (NULL);
520 	}
521 	for (; cp > pbuf; cp--) {
522 		if (*cp == '.') {
523 			*cp = '\0';
524 			break;
525 		}
526 	}
527 	switch (pk->key_type) {
528 #ifdef VE_ECDSA_SUPPORT
529 	case BR_KEYTYPE_EC:
530 		ucp = verify_ec(pk, pbuf, sigfile);
531 		break;
532 #endif
533 #ifdef VE_RSA_SUPPORT
534 	case BR_KEYTYPE_RSA:
535 		ucp = verify_rsa(pk, pbuf, sigfile);
536 		break;
537 #endif
538 	default:
539 		ucp = NULL;		/* not supported */
540 	}
541 	xfreepkey(pk);
542 	if (!ucp) {
543 		printf("Unverified %s (%s)\n", pbuf,
544 		    cn.status ? cn_buf : "unknown");
545 	} else if ((flags & 1) != 0) {
546 		printf("Verified %s signed by %s\n", pbuf,
547 		    cn.status ? cn_buf : "someone we trust");
548 	}
549 	return (ucp);
550 }
551 
552 
553 /**
554  * @brief verify hash matches
555  *
556  * We have finished hashing a file,
557  * see if we got the desired result.
558  *
559  * @param[in] ctx
560  *	pointer to hash context
561  *
562  * @param[in] md
563  *	pointer to hash class
564  *
565  * @param[in] path
566  *	name of the file we are checking
567  *
568  * @param[in] want
569  *	the expected result
570  *
571  * @param[in] hlen
572  *	size of hash output
573  *
574  * @return 0 on success
575  */
576 int
577 ve_check_hash(br_hash_compat_context *ctx, const br_hash_class *md,
578     const char *path, const char *want, size_t hlen)
579 {
580 	char hexbuf[br_sha512_SIZE * 2 + 2];
581 	unsigned char hbuf[br_sha512_SIZE];
582 	char *hex;
583 	int rc;
584 	int n;
585 
586 	md->out(&ctx->vtable, hbuf);
587 #ifdef VE_PCR_SUPPORT
588 	ve_pcr_update(hbuf, hlen);
589 #endif
590 	hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
591 	if (!hex)
592 		return (VE_FINGERPRINT_WRONG);
593 	n = 2*hlen;
594 	if ((rc = strncmp(hex, want, n))) {
595 		ve_error_set("%s: %.*s != %.*s", path, n, hex, n, want);
596 		rc = VE_FINGERPRINT_WRONG;
597 	}
598 	return (rc ? rc : VE_FINGERPRINT_OK);
599 }
600 
601 #ifdef VE_HASH_KAT_STR
602 static int
603 test_hash(const br_hash_class *md, size_t hlen,
604     const char *hname, const char *s, size_t slen, const char *want)
605 {
606 	br_hash_compat_context mctx;
607 
608 	md->init(&mctx.vtable);
609 	md->update(&mctx.vtable, s, slen);
610 	return (ve_check_hash(&mctx, md, hname, want, hlen) != VE_FINGERPRINT_OK);
611 }
612 
613 #endif
614 
615 #define ve_test_hash(n, N) \
616 	printf("Testing hash: " #n "\t\t\t\t%s\n", \
617 	    test_hash(&br_ ## n ## _vtable, br_ ## n ## _SIZE, #n, \
618 	    VE_HASH_KAT_STR, sizeof(VE_HASH_KAT_STR), \
619 	    vh_ ## N) ? "Failed" : "Passed")
620 
621 /**
622  * @brief
623  * run self tests on hash and signature verification
624  *
625  * Test that the hash methods (SHA1 and SHA256) work.
626  * Test that we can verify a certificate for each supported
627  * Root CA.
628  *
629  * @return cached result.
630  */
631 int
632 ve_self_tests(void)
633 {
634 	static int once = -1;
635 #ifdef VERIFY_CERTS_STR
636 	br_x509_certificate *xcs;
637 	br_x509_pkey *pk;
638 	br_name_element cn;
639 	char cn_buf[80];
640 	unsigned char cn_oid[4];
641 	size_t num;
642 	size_t u;
643 #endif
644 
645 	if (once >= 0)
646 		return (once);
647 	once = 0;
648 
649 	DEBUG_PRINTF(5, ("Self tests...\n"));
650 #ifdef VE_HASH_KAT_STR
651 #ifdef VE_SHA1_SUPPORT
652 	ve_test_hash(sha1, SHA1);
653 #endif
654 #ifdef VE_SHA256_SUPPORT
655 	ve_test_hash(sha256, SHA256);
656 #endif
657 #ifdef VE_SHA384_SUPPORT
658 	ve_test_hash(sha384, SHA384);
659 #endif
660 #ifdef VE_SHA512_SUPPORT
661 	ve_test_hash(sha512, SHA512);
662 #endif
663 #endif
664 #ifdef VERIFY_CERTS_STR
665 	xcs = parse_certificates(__DECONST(unsigned char *, VERIFY_CERTS_STR),
666 	    sizeof(VERIFY_CERTS_STR), &num);
667 	if (xcs == NULL)
668 		return (0);
669 	/*
670 	 * We want the commonName field
671 	 * the OID we want is 2,5,4,3 - but DER encoded
672 	 */
673 	cn_oid[0] = 3;
674 	cn_oid[1] = 0x55;
675 	cn_oid[2] = 4;
676 	cn_oid[3] = 3;
677 	cn.oid = cn_oid;
678 	cn.buf = cn_buf;
679 
680 	for (u = 0; u < num; u ++) {
681 		cn.len = sizeof(cn_buf);
682 		if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1)) != NULL) {
683 			once++;
684 			printf("Testing verify certificate: %s\tPassed\n",
685 			    cn.status ? cn_buf : "");
686 			xfreepkey(pk);
687 		}
688 	}
689 	if (!once)
690 		printf("Testing verify certificate:\t\t\tFailed\n");
691 	xfree(xcs);
692 #else
693 	printf("No X.509 self tests\n");
694 #endif	/* VERIFY_CERTS_STR */
695 #ifdef VE_OPENPGP_SUPPORT
696 	if (!openpgp_self_tests())
697 		once++;
698 #endif
699 	return (once);
700 }
701