xref: /openbsd/usr.sbin/rpki-client/validate.c (revision 335482ab)
1 /*	$OpenBSD: validate.c,v 1.73 2024/03/19 05:04:13 tb Exp $ */
2 /*
3  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <arpa/inet.h>
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "extern.h"
29 
30 extern ASN1_OBJECT	*certpol_oid;
31 
32 /*
33  * Walk up the chain of certificates trying to match our AS number to
34  * one of the allocations in that chain.
35  * Returns 1 if covered or 0 if not.
36  */
37 static int
valid_as(struct auth * a,uint32_t min,uint32_t max)38 valid_as(struct auth *a, uint32_t min, uint32_t max)
39 {
40 	int	 c;
41 
42 	if (a == NULL)
43 		return 0;
44 
45 	/* Does this certificate cover our AS number? */
46 	c = as_check_covered(min, max, a->cert->as, a->cert->asz);
47 	if (c > 0)
48 		return 1;
49 	else if (c < 0)
50 		return 0;
51 
52 	/* If it inherits, walk up the chain. */
53 	return valid_as(a->issuer, min, max);
54 }
55 
56 /*
57  * Walk up the chain of certificates (really just the last one, but in
58  * the case of inheritance, the ones before) making sure that our IP
59  * prefix is covered in the first non-inheriting specification.
60  * Returns 1 if covered or 0 if not.
61  */
62 static int
valid_ip(struct auth * a,enum afi afi,const unsigned char * min,const unsigned char * max)63 valid_ip(struct auth *a, enum afi afi,
64     const unsigned char *min, const unsigned char *max)
65 {
66 	int	 c;
67 
68 	if (a == NULL)
69 		return 0;
70 
71 	/* Does this certificate cover our IP prefix? */
72 	c = ip_addr_check_covered(afi, min, max, a->cert->ips, a->cert->ipsz);
73 	if (c > 0)
74 		return 1;
75 	else if (c < 0)
76 		return 0;
77 
78 	/* If it inherits, walk up the chain. */
79 	return valid_ip(a->issuer, afi, min, max);
80 }
81 
82 /*
83  * Make sure the AKI is the same as the AKI listed on the Manifest,
84  * and that the SKI doesn't already exist.
85  * Return the issuer by its AKI, or NULL on failure.
86  */
87 struct auth *
valid_ski_aki(const char * fn,struct auth_tree * auths,const char * ski,const char * aki,const char * mftaki)88 valid_ski_aki(const char *fn, struct auth_tree *auths,
89     const char *ski, const char *aki, const char *mftaki)
90 {
91 	struct auth *a;
92 
93 	if (mftaki != NULL) {
94 		if (strcmp(aki, mftaki) != 0) {
95 			warnx("%s: AKI doesn't match Manifest AKI", fn);
96 			return NULL;
97 		}
98 	}
99 
100 	if (auth_find(auths, ski) != NULL) {
101 		warnx("%s: RFC 6487: duplicate SKI", fn);
102 		return NULL;
103 	}
104 
105 	a = auth_find(auths, aki);
106 	if (a == NULL)
107 		warnx("%s: RFC 6487: unknown AKI", fn);
108 
109 	return a;
110 }
111 
112 /*
113  * Validate a trust anchor by making sure that the SKI is unique.
114  * Returns 1 if valid, 0 otherwise.
115  */
116 int
valid_ta(const char * fn,struct auth_tree * auths,const struct cert * cert)117 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
118 {
119 	/* SKI must not be a dupe. */
120 	if (auth_find(auths, cert->ski) != NULL) {
121 		warnx("%s: RFC 6487: duplicate SKI", fn);
122 		return 0;
123 	}
124 
125 	return 1;
126 }
127 
128 /*
129  * Validate a non-TA certificate: make sure its IP and AS resources are
130  * fully covered by those in the authority key (which must exist).
131  * Returns 1 if valid, 0 otherwise.
132  */
133 int
valid_cert(const char * fn,struct auth * a,const struct cert * cert)134 valid_cert(const char *fn, struct auth *a, const struct cert *cert)
135 {
136 	size_t		 i;
137 	uint32_t	 min, max;
138 
139 	for (i = 0; i < cert->asz; i++) {
140 		if (cert->as[i].type == CERT_AS_INHERIT)
141 			continue;
142 
143 		if (cert->as[i].type == CERT_AS_ID) {
144 			min = cert->as[i].id;
145 			max = cert->as[i].id;
146 		} else {
147 			min = cert->as[i].range.min;
148 			max = cert->as[i].range.max;
149 		}
150 
151 		if (valid_as(a, min, max))
152 			continue;
153 
154 		as_warn(fn, "RFC 6487: uncovered resource", &cert->as[i]);
155 		return 0;
156 	}
157 
158 	for (i = 0; i < cert->ipsz; i++) {
159 		if (cert->ips[i].type == CERT_IP_INHERIT)
160 			continue;
161 
162 		if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min,
163 		    cert->ips[i].max))
164 			continue;
165 
166 		ip_warn(fn, "RFC 6487: uncovered resource", &cert->ips[i]);
167 		return 0;
168 	}
169 
170 	return 1;
171 }
172 
173 /*
174  * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained.
175  * Returns 1 if valid, 0 otherwise.
176  */
177 int
valid_roa(const char * fn,struct cert * cert,struct roa * roa)178 valid_roa(const char *fn, struct cert *cert, struct roa *roa)
179 {
180 	size_t	 i;
181 	char	 buf[64];
182 
183 	for (i = 0; i < roa->ipsz; i++) {
184 		if (ip_addr_check_covered(roa->ips[i].afi, roa->ips[i].min,
185 		    roa->ips[i].max, cert->ips, cert->ipsz) > 0)
186 			continue;
187 
188 		ip_addr_print(&roa->ips[i].addr, roa->ips[i].afi, buf,
189 		    sizeof(buf));
190 		warnx("%s: RFC 6482: uncovered IP: %s", fn, buf);
191 		return 0;
192 	}
193 
194 	return 1;
195 }
196 
197 /*
198  * Validate our SPL: check that the asID is contained in the end-entity
199  * certificate's resources.
200  * Returns 1 if valid, 0 otherwise.
201  */
202 int
valid_spl(const char * fn,struct cert * cert,struct spl * spl)203 valid_spl(const char *fn, struct cert *cert, struct spl *spl)
204 {
205 	if (as_check_covered(spl->asid, spl->asid, cert->as, cert->asz) > 0)
206 		return 1;
207 
208 	warnx("%s: SPL: uncovered ASID: %u", fn, spl->asid);
209 
210 	return 0;
211 }
212 
213 /*
214  * Validate a file by verifying the SHA256 hash of that file.
215  * The file to check is passed as a file descriptor.
216  * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
217  */
218 int
valid_filehash(int fd,const char * hash,size_t hlen)219 valid_filehash(int fd, const char *hash, size_t hlen)
220 {
221 	SHA256_CTX	ctx;
222 	char		filehash[SHA256_DIGEST_LENGTH];
223 	char		buffer[8192];
224 	ssize_t		nr;
225 
226 	if (hlen != sizeof(filehash))
227 		errx(1, "bad hash size");
228 
229 	if (fd == -1)
230 		return 0;
231 
232 	SHA256_Init(&ctx);
233 	while ((nr = read(fd, buffer, sizeof(buffer))) > 0)
234 		SHA256_Update(&ctx, buffer, nr);
235 	close(fd);
236 	SHA256_Final(filehash, &ctx);
237 
238 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
239 		return 0;
240 	return 1;
241 }
242 
243 /*
244  * Same as above but with a buffer instead of a fd.
245  */
246 int
valid_hash(unsigned char * buf,size_t len,const char * hash,size_t hlen)247 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen)
248 {
249 	char	filehash[SHA256_DIGEST_LENGTH];
250 
251 	if (hlen != sizeof(filehash))
252 		errx(1, "bad hash size");
253 
254 	if (buf == NULL || len == 0)
255 		return 0;
256 
257 	if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
258 		errx(1, "EVP_Digest failed");
259 
260 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
261 		return 0;
262 	return 1;
263 }
264 
265 /*
266  * Validate that a filename only contains characters from the POSIX portable
267  * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278.
268  */
269 int
valid_filename(const char * fn,size_t len)270 valid_filename(const char *fn, size_t len)
271 {
272 	const unsigned char *c;
273 	size_t i;
274 
275 	for (c = fn, i = 0; i < len; i++, c++)
276 		if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
277 			return 0;
278 	return 1;
279 }
280 
281 /*
282  * Validate a URI to make sure it is pure ASCII and does not point backwards
283  * or doing some other silly tricks. To enforce the protocol pass either
284  * https:// or rsync:// as proto, if NULL is passed no protocol is enforced.
285  * Returns 1 if valid, 0 otherwise.
286  */
287 int
valid_uri(const char * uri,size_t usz,const char * proto)288 valid_uri(const char *uri, size_t usz, const char *proto)
289 {
290 	size_t s;
291 
292 	if (usz > MAX_URI_LENGTH)
293 		return 0;
294 
295 	for (s = 0; s < usz; s++)
296 		if (!isalnum((unsigned char)uri[s]) &&
297 		    !ispunct((unsigned char)uri[s]))
298 			return 0;
299 
300 	if (proto != NULL) {
301 		s = strlen(proto);
302 		if (s >= usz)
303 			return 0;
304 		if (strncasecmp(uri, proto, s) != 0)
305 			return 0;
306 	}
307 
308 	/* do not allow files or directories to start with a '.' */
309 	if (strstr(uri, "/.") != NULL)
310 		return 0;
311 
312 	return 1;
313 }
314 
315 /*
316  * Validate that a URI has the same host as the URI passed in proto.
317  * Returns 1 if valid, 0 otherwise.
318  */
319 int
valid_origin(const char * uri,const char * proto)320 valid_origin(const char *uri, const char *proto)
321 {
322 	const char *to;
323 
324 	/* extract end of host from proto URI */
325 	to = strstr(proto, "://");
326 	if (to == NULL)
327 		return 0;
328 	to += strlen("://");
329 	if ((to = strchr(to, '/')) == NULL)
330 		return 0;
331 
332 	/* compare hosts including the / for the start of the path section */
333 	if (strncasecmp(uri, proto, to - proto + 1) != 0)
334 		return 0;
335 
336 	return 1;
337 }
338 
339 /*
340  * Walk the tree of known valid CA certificates until we find a certificate that
341  * doesn't inherit. Build a chain of intermediates and use the non-inheriting
342  * certificate as a trusted root by virtue of X509_V_FLAG_PARTIAL_CHAIN. The
343  * RFC 3779 path validation needs a non-inheriting trust root to ensure that
344  * all delegated resources are covered.
345  */
346 static void
build_chain(const struct auth * a,STACK_OF (X509)** intermediates,STACK_OF (X509)** root)347 build_chain(const struct auth *a, STACK_OF(X509) **intermediates,
348     STACK_OF(X509) **root)
349 {
350 	*intermediates = NULL;
351 	*root = NULL;
352 
353 	if (a == NULL)
354 		return;
355 
356 	if ((*intermediates = sk_X509_new_null()) == NULL)
357 		err(1, "sk_X509_new_null");
358 	if ((*root = sk_X509_new_null()) == NULL)
359 		err(1, "sk_X509_new_null");
360 	for (; a != NULL; a = a->issuer) {
361 		assert(a->cert->x509 != NULL);
362 		if (!a->any_inherits) {
363 			if (!sk_X509_push(*root, a->cert->x509))
364 				errx(1, "sk_X509_push");
365 			break;
366 		}
367 		if (!sk_X509_push(*intermediates, a->cert->x509))
368 			errx(1, "sk_X509_push");
369 	}
370 	assert(sk_X509_num(*root) == 1);
371 }
372 
373 /*
374  * Add the CRL based on the certs SKI value.
375  * No need to insert any other CRL since those were already checked.
376  */
377 static void
build_crls(const struct crl * crl,STACK_OF (X509_CRL)** crls)378 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls)
379 {
380 	*crls = NULL;
381 
382 	if (crl == NULL)
383 		return;
384 	if ((*crls = sk_X509_CRL_new_null()) == NULL)
385 		errx(1, "sk_X509_CRL_new_null");
386 	if (!sk_X509_CRL_push(*crls, crl->x509_crl))
387 		err(1, "sk_X509_CRL_push");
388 }
389 
390 /*
391  * Attempt to upgrade the generic 'certificate revoked' message to include
392  * a timestamp.
393  */
394 static void
pretty_revocation_time(X509 * x509,X509_CRL * crl,const char ** errstr)395 pretty_revocation_time(X509 *x509, X509_CRL *crl, const char **errstr)
396 {
397 	static char		 buf[64];
398 	X509_REVOKED		*revoked;
399 	const ASN1_TIME		*atime;
400 	time_t			 t;
401 
402 	if (X509_CRL_get0_by_cert(crl, &revoked, x509) != 1)
403 		return;
404 	if ((atime = X509_REVOKED_get0_revocationDate(revoked)) == NULL)
405 		return;
406 	if (!x509_get_time(atime, &t))
407 		return;
408 
409 	snprintf(buf, sizeof(buf), "certificate revoked on %s", time2str(t));
410 	*errstr = buf;
411 }
412 
413 /*
414  * Validate the X509 certificate. Returns 1 for valid certificates,
415  * returns 0 if there is a verify error and sets *errstr to the error
416  * returned by X509_verify_cert_error_string().
417  */
418 int
valid_x509(char * file,X509_STORE_CTX * store_ctx,X509 * x509,struct auth * a,struct crl * crl,const char ** errstr)419 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a,
420     struct crl *crl, const char **errstr)
421 {
422 	X509_VERIFY_PARAM	*params;
423 	ASN1_OBJECT		*cp_oid;
424 	STACK_OF(X509)		*intermediates, *root;
425 	STACK_OF(X509_CRL)	*crls = NULL;
426 	unsigned long		 flags;
427 	int			 error;
428 
429 	*errstr = NULL;
430 	build_chain(a, &intermediates, &root);
431 	build_crls(crl, &crls);
432 
433 	assert(store_ctx != NULL);
434 	assert(x509 != NULL);
435 	if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL))
436 		err(1, "X509_STORE_CTX_init");
437 
438 	if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL)
439 		errx(1, "X509_STORE_CTX_get0_param");
440 	if ((cp_oid = OBJ_dup(certpol_oid)) == NULL)
441 		err(1, "OBJ_dup");
442 	if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid))
443 		err(1, "X509_VERIFY_PARAM_add0_policy");
444 	X509_VERIFY_PARAM_set_time(params, get_current_time());
445 
446 	flags = X509_V_FLAG_CRL_CHECK;
447 	flags |= X509_V_FLAG_PARTIAL_CHAIN;
448 	flags |= X509_V_FLAG_POLICY_CHECK;
449 	flags |= X509_V_FLAG_EXPLICIT_POLICY;
450 	flags |= X509_V_FLAG_INHIBIT_MAP;
451 	X509_STORE_CTX_set_flags(store_ctx, flags);
452 	X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH);
453 	/*
454 	 * See the comment above build_chain() for details on what's happening
455 	 * here. The nomenclature in this API is dubious and poorly documented.
456 	 */
457 	X509_STORE_CTX_set0_untrusted(store_ctx, intermediates);
458 	X509_STORE_CTX_set0_trusted_stack(store_ctx, root);
459 	X509_STORE_CTX_set0_crls(store_ctx, crls);
460 
461 	if (X509_verify_cert(store_ctx) <= 0) {
462 		error = X509_STORE_CTX_get_error(store_ctx);
463 		*errstr = X509_verify_cert_error_string(error);
464 		if (filemode && error == X509_V_ERR_CERT_REVOKED)
465 			pretty_revocation_time(x509, crl->x509_crl, errstr);
466 		X509_STORE_CTX_cleanup(store_ctx);
467 		sk_X509_free(intermediates);
468 		sk_X509_free(root);
469 		sk_X509_CRL_free(crls);
470 		return 0;
471 	}
472 
473 	X509_STORE_CTX_cleanup(store_ctx);
474 	sk_X509_free(intermediates);
475 	sk_X509_free(root);
476 	sk_X509_CRL_free(crls);
477 	return 1;
478 }
479 
480 /*
481  * Validate our RSC: check that all items in the ResourceBlock are contained.
482  * Returns 1 if valid, 0 otherwise.
483  */
484 int
valid_rsc(const char * fn,struct cert * cert,struct rsc * rsc)485 valid_rsc(const char *fn, struct cert *cert, struct rsc *rsc)
486 {
487 	size_t		i;
488 	uint32_t	min, max;
489 
490 	for (i = 0; i < rsc->asz; i++) {
491 		if (rsc->as[i].type == CERT_AS_ID) {
492 			min = rsc->as[i].id;
493 			max = rsc->as[i].id;
494 		} else {
495 			min = rsc->as[i].range.min;
496 			max = rsc->as[i].range.max;
497 		}
498 
499 		if (as_check_covered(min, max, cert->as, cert->asz) > 0)
500 			continue;
501 
502 		as_warn(fn, "RSC ResourceBlock uncovered", &rsc->as[i]);
503 		return 0;
504 	}
505 
506 	for (i = 0; i < rsc->ipsz; i++) {
507 		if (ip_addr_check_covered(rsc->ips[i].afi, rsc->ips[i].min,
508 		    rsc->ips[i].max, cert->ips, cert->ipsz) > 0)
509 			continue;
510 
511 		ip_warn(fn, "RSC ResourceBlock uncovered", &rsc->ips[i]);
512 		return 0;
513 	}
514 
515 	return 1;
516 }
517 
518 int
valid_econtent_version(const char * fn,const ASN1_INTEGER * aint,uint64_t expected)519 valid_econtent_version(const char *fn, const ASN1_INTEGER *aint,
520     uint64_t expected)
521 {
522 	uint64_t version;
523 
524 	if (aint == NULL) {
525 		if (expected == 0)
526 			return 1;
527 		warnx("%s: unexpected version 0", fn);
528 		return 0;
529 	}
530 
531 	if (!ASN1_INTEGER_get_uint64(&version, aint)) {
532 		warnx("%s: ASN1_INTEGER_get_uint64 failed", fn);
533 		return 0;
534 	}
535 
536 	if (version == 0) {
537 		warnx("%s: incorrect encoding for version 0", fn);
538 		return 0;
539 	}
540 
541 	if (version != expected) {
542 		warnx("%s: unexpected version (expected %llu, got %llu)", fn,
543 		    (unsigned long long)expected, (unsigned long long)version);
544 		return 0;
545 	}
546 
547 	return 1;
548 }
549 
550 /*
551  * Validate the ASPA: check that the customerASID is contained.
552  * Returns 1 if valid, 0 otherwise.
553  */
554 int
valid_aspa(const char * fn,struct cert * cert,struct aspa * aspa)555 valid_aspa(const char *fn, struct cert *cert, struct aspa *aspa)
556 {
557 
558 	if (as_check_covered(aspa->custasid, aspa->custasid,
559 	    cert->as, cert->asz) > 0)
560 		return 1;
561 
562 	warnx("%s: ASPA: uncovered Customer ASID: %u", fn, aspa->custasid);
563 
564 	return 0;
565 }
566 
567 /*
568  * Validate Geofeed prefixes: check that the prefixes are contained.
569  * Returns 1 if valid, 0 otherwise.
570  */
571 int
valid_geofeed(const char * fn,struct cert * cert,struct geofeed * g)572 valid_geofeed(const char *fn, struct cert *cert, struct geofeed *g)
573 {
574 	size_t	 i;
575 	char	 buf[64];
576 
577 	for (i = 0; i < g->geoipsz; i++) {
578 		if (ip_addr_check_covered(g->geoips[i].ip->afi,
579 		    g->geoips[i].ip->min, g->geoips[i].ip->max, cert->ips,
580 		    cert->ipsz) > 0)
581 			continue;
582 
583 		ip_addr_print(&g->geoips[i].ip->ip, g->geoips[i].ip->afi, buf,
584 		    sizeof(buf));
585 		warnx("%s: Geofeed: uncovered IP: %s", fn, buf);
586 		return 0;
587 	}
588 
589 	return 1;
590 }
591 
592 /*
593  * Validate whether a given string is a valid UUID.
594  * Returns 1 if valid, 0 otherwise.
595  */
596 int
valid_uuid(const char * s)597 valid_uuid(const char *s)
598 {
599 	int n = 0;
600 
601 	while (1) {
602 		switch (n) {
603 		case 8:
604 		case 13:
605 		case 18:
606 		case 23:
607 			if (s[n] != '-')
608 				return 0;
609 			break;
610 		/* Check UUID is version 4 */
611 		case 14:
612 			if (s[n] != '4')
613 				return 0;
614 			break;
615 		/* Check UUID variant is 1 */
616 		case 19:
617 			if (s[n] != '8' && s[n] != '9' && s[n] != 'a' &&
618 			    s[n] != 'A' && s[n] != 'b' && s[n] != 'B')
619 				return 0;
620 			break;
621 		case 36:
622 			return s[n] == '\0';
623 		default:
624 			if (!isxdigit((unsigned char)s[n]))
625 				return 0;
626 			break;
627 		}
628 		n++;
629 	}
630 }
631 
632 static int
valid_ca_pkey_rsa(const char * fn,EVP_PKEY * pkey)633 valid_ca_pkey_rsa(const char *fn, EVP_PKEY *pkey)
634 {
635 	RSA		*rsa;
636 	const BIGNUM	*rsa_e;
637 	int		 key_bits;
638 
639 	if ((key_bits = EVP_PKEY_bits(pkey)) != 2048) {
640 		warnx("%s: RFC 7935: expected 2048-bit modulus, got %d bits",
641 		    fn, key_bits);
642 		return 0;
643 	}
644 
645 	if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
646 		warnx("%s: failed to extract RSA public key", fn);
647 		return 0;
648 	}
649 
650 	if ((rsa_e = RSA_get0_e(rsa)) == NULL) {
651 		warnx("%s: failed to get RSA exponent", fn);
652 		return 0;
653 	}
654 
655 	if (!BN_is_word(rsa_e, 65537)) {
656 		warnx("%s: incorrect exponent (e) in RSA public key", fn);
657 		return 0;
658 	}
659 
660 	return 1;
661 }
662 
663 static int
valid_ca_pkey_ec(const char * fn,EVP_PKEY * pkey)664 valid_ca_pkey_ec(const char *fn, EVP_PKEY *pkey)
665 {
666 	EC_KEY		*ec;
667 	const EC_GROUP	*group;
668 	int		 nid;
669 	const char	*cname;
670 
671 	if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
672 		warnx("%s: failed to extract ECDSA public key", fn);
673 		return 0;
674 	}
675 
676 	if ((group = EC_KEY_get0_group(ec)) == NULL) {
677 		warnx("%s: EC_KEY_get0_group failed", fn);
678 		return 0;
679 	}
680 
681 	nid = EC_GROUP_get_curve_name(group);
682 	if (nid != NID_X9_62_prime256v1) {
683 		if ((cname = EC_curve_nid2nist(nid)) == NULL)
684 			cname = nid2str(nid);
685 		warnx("%s: Expected P-256, got %s", fn, cname);
686 		return 0;
687 	}
688 
689 	if (!EC_KEY_check_key(ec)) {
690 		warnx("%s: EC_KEY_check_key failed", fn);
691 		return 0;
692 	}
693 
694 	return 1;
695 }
696 
697 int
valid_ca_pkey(const char * fn,EVP_PKEY * pkey)698 valid_ca_pkey(const char *fn, EVP_PKEY *pkey)
699 {
700 	if (pkey == NULL) {
701 		warnx("%s: failure, pkey is NULL", fn);
702 		return 0;
703 	}
704 
705 	if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA)
706 		return valid_ca_pkey_rsa(fn, pkey);
707 
708 	if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC)
709 		return valid_ca_pkey_ec(fn, pkey);
710 
711 	warnx("%s: unsupported public key algorithm", fn);
712 	return 0;
713 }
714