xref: /openbsd/usr.sbin/rpki-client/print.c (revision 904d9c60)
1 /*	$OpenBSD: print.c,v 1.56 2024/09/12 10:33:25 tb Exp $ */
2 /*
3  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <arpa/inet.h>
22 
23 #include <err.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #include <openssl/evp.h>
29 
30 #include "extern.h"
31 #include "json.h"
32 
33 static const char *
pretty_key_id(const char * hex)34 pretty_key_id(const char *hex)
35 {
36 	static char buf[128];	/* bigger than SHA_DIGEST_LENGTH * 3 */
37 	size_t i;
38 
39 	for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) {
40 		if (i % 3 == 2)
41 			buf[i] = ':';
42 		else
43 			buf[i] = *hex++;
44 	}
45 	if (i == sizeof(buf))
46 		memcpy(buf + sizeof(buf) - 4, "...", 4);
47 	else
48 		buf[i] = '\0';
49 	return buf;
50 }
51 
52 char *
nid2str(int nid)53 nid2str(int nid)
54 {
55 	static char buf[128];
56 	const char *name;
57 
58 	if ((name = OBJ_nid2ln(nid)) == NULL)
59 		name = OBJ_nid2sn(nid);
60 	if (name == NULL)
61 		name = "unknown";
62 
63 	snprintf(buf, sizeof(buf), "nid %d (%s)", nid, name);
64 
65 	return buf;
66 }
67 
68 const char *
purpose2str(enum cert_purpose purpose)69 purpose2str(enum cert_purpose purpose)
70 {
71 	switch (purpose) {
72 	case CERT_PURPOSE_INVALID:
73 		return "invalid cert";
74 	case CERT_PURPOSE_TA:
75 		return "TA cert";
76 	case CERT_PURPOSE_CA:
77 		return "CA cert";
78 	case CERT_PURPOSE_EE:
79 		return "EE cert";
80 	case CERT_PURPOSE_BGPSEC_ROUTER:
81 		return "BGPsec Router cert";
82 	default:
83 		return "unknown certificate purpose";
84 	}
85 }
86 
87 char *
time2str(time_t t)88 time2str(time_t t)
89 {
90 	static char buf[64];
91 	struct tm tm;
92 
93 	if (gmtime_r(&t, &tm) == NULL)
94 		return "could not convert time";
95 
96 	strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm);
97 
98 	return buf;
99 }
100 
101 void
tal_print(const struct tal * p)102 tal_print(const struct tal *p)
103 {
104 	char			*ski;
105 	const unsigned char	*der;
106 	X509_PUBKEY		*pubkey;
107 	size_t			 i;
108 
109 	der = p->pkey;
110 	if ((pubkey = d2i_X509_PUBKEY(NULL, &der, p->pkeysz)) == NULL)
111 		errx(1, "d2i_X509_PUBKEY failed");
112 
113 	if ((ski = x509_pubkey_get_ski(pubkey, p->descr)) == NULL)
114 		errx(1, "x509_pubkey_get_ski failed");
115 
116 	if (outformats & FORMAT_JSON) {
117 		json_do_string("type", "tal");
118 		json_do_string("name", p->descr);
119 		json_do_string("ski", pretty_key_id(ski));
120 		json_do_array("trust_anchor_locations");
121 		for (i = 0; i < p->urisz; i++)
122 			json_do_string("tal", p->uri[i]);
123 		json_do_end();
124 	} else {
125 		printf("Trust anchor name:        %s\n", p->descr);
126 		printf("Subject key identifier:   %s\n", pretty_key_id(ski));
127 		printf("Trust anchor locations:   ");
128 		for (i = 0; i < p->urisz; i++) {
129 			if (i > 0)
130 				printf("%26s", "");
131 			printf("%s\n", p->uri[i]);
132 		}
133 	}
134 
135 	X509_PUBKEY_free(pubkey);
136 	free(ski);
137 }
138 
139 void
x509_print(const X509 * x)140 x509_print(const X509 *x)
141 {
142 	const ASN1_INTEGER	*xserial;
143 	const X509_NAME		*xissuer;
144 	char			*issuer = NULL;
145 	char			*serial = NULL;
146 
147 	if ((xissuer = X509_get_issuer_name(x)) == NULL) {
148 		warnx("X509_get_issuer_name failed");
149 		goto out;
150 	}
151 
152 	if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) {
153 		warnx("X509_NAME_oneline failed");
154 		goto out;
155 	}
156 
157 	if ((xserial = X509_get0_serialNumber(x)) == NULL) {
158 		warnx("X509_get0_serialNumber failed");
159 		goto out;
160 	}
161 
162 	if ((serial = x509_convert_seqnum(__func__, "serial number",
163 	    xserial)) == NULL)
164 		goto out;
165 
166 	if (outformats & FORMAT_JSON) {
167 		json_do_string("cert_issuer", issuer);
168 		json_do_string("cert_serial", serial);
169 	} else {
170 		printf("Certificate issuer:       %s\n", issuer);
171 		printf("Certificate serial:       %s\n", serial);
172 	}
173 
174  out:
175 	free(issuer);
176 	free(serial);
177 }
178 
179 static void
as_resources_print(struct cert_as * as,size_t asz)180 as_resources_print(struct cert_as *as, size_t asz)
181 {
182 	size_t i;
183 
184 	for (i = 0; i < asz; i++) {
185 		if (outformats & FORMAT_JSON)
186 			json_do_object("resource", 1);
187 		switch (as[i].type) {
188 		case CERT_AS_ID:
189 			if (outformats & FORMAT_JSON) {
190 				json_do_uint("asid", as[i].id);
191 			} else {
192 				if (i > 0)
193 					printf("%26s", "");
194 				printf("AS: %u", as[i].id);
195 			}
196 			break;
197 		case CERT_AS_INHERIT:
198 			if (outformats & FORMAT_JSON) {
199 				json_do_bool("asid_inherit", 1);
200 			} else {
201 				if (i > 0)
202 					printf("%26s", "");
203 				printf("AS: inherit");
204 			}
205 			break;
206 		case CERT_AS_RANGE:
207 			if (outformats & FORMAT_JSON) {
208 				json_do_object("asrange", 1);
209 				json_do_uint("min", as[i].range.min);
210 				json_do_uint("max", as[i].range.max);
211 				json_do_end();
212 			} else {
213 				if (i > 0)
214 					printf("%26s", "");
215 				printf("AS: %u -- %u", as[i].range.min,
216 				    as[i].range.max);
217 			}
218 			break;
219 		}
220 		if (outformats & FORMAT_JSON)
221 			json_do_end();
222 		else
223 			printf("\n");
224 	}
225 }
226 
227 static void
ip_resources_print(struct cert_ip * ips,size_t ipsz,size_t asz)228 ip_resources_print(struct cert_ip *ips, size_t ipsz, size_t asz)
229 {
230 	char buf1[64], buf2[64];
231 	size_t i;
232 	int sockt;
233 
234 	for (i = 0; i < ipsz; i++) {
235 		if (outformats & FORMAT_JSON)
236 			json_do_object("resource", 1);
237 		switch (ips[i].type) {
238 		case CERT_IP_INHERIT:
239 			if (outformats & FORMAT_JSON) {
240 				json_do_bool("ip_inherit", 1);
241 			} else {
242 				if (i > 0 || asz > 0)
243 					printf("%26s", "");
244 				printf("IP: inherit");
245 			}
246 			break;
247 		case CERT_IP_ADDR:
248 			ip_addr_print(&ips[i].ip, ips[i].afi, buf1,
249 			    sizeof(buf1));
250 			if (outformats & FORMAT_JSON) {
251 				json_do_string("ip_prefix", buf1);
252 			} else {
253 				if (i > 0 || asz > 0)
254 					printf("%26s", "");
255 				printf("IP: %s", buf1);
256 			}
257 			break;
258 		case CERT_IP_RANGE:
259 			sockt = (ips[i].afi == AFI_IPV4) ?
260 			    AF_INET : AF_INET6;
261 			inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1));
262 			inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2));
263 			if (outformats & FORMAT_JSON) {
264 				json_do_object("ip_range", 1);
265 				json_do_string("min", buf1);
266 				json_do_string("max", buf2);
267 				json_do_end();
268 			} else {
269 				if (i > 0 || asz > 0)
270 					printf("%26s", "");
271 				printf("IP: %s -- %s", buf1, buf2);
272 			}
273 			break;
274 		}
275 		if (outformats & FORMAT_JSON)
276 			json_do_end();
277 		else
278 			printf("\n");
279 	}
280 }
281 
282 void
cert_print(const struct cert * p)283 cert_print(const struct cert *p)
284 {
285 	if (outformats & FORMAT_JSON) {
286 		if (p->pubkey != NULL)
287 			json_do_string("type", "router_key");
288 		else
289 			json_do_string("type", "ca_cert");
290 		json_do_string("ski", pretty_key_id(p->ski));
291 		if (p->aki != NULL)
292 			json_do_string("aki", pretty_key_id(p->aki));
293 		x509_print(p->x509);
294 		if (p->aia != NULL)
295 			json_do_string("aia", p->aia);
296 		if (p->mft != NULL)
297 			json_do_string("manifest", p->mft);
298 		if (p->repo != NULL)
299 			json_do_string("carepository", p->repo);
300 		if (p->notify != NULL)
301 			json_do_string("notify_url", p->notify);
302 		if (p->pubkey != NULL)
303 			json_do_string("router_key", p->pubkey);
304 		json_do_int("valid_since", p->notbefore);
305 		json_do_int("valid_until", p->notafter);
306 		if (p->expires)
307 			json_do_int("expires", p->expires);
308 		json_do_array("subordinate_resources");
309 	} else {
310 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
311 		if (p->aki != NULL)
312 			printf("Authority key identifier: %s\n",
313 			    pretty_key_id(p->aki));
314 		x509_print(p->x509);
315 		if (p->aia != NULL)
316 			printf("Authority info access:    %s\n", p->aia);
317 		if (p->mft != NULL)
318 			printf("Manifest:                 %s\n", p->mft);
319 		if (p->repo != NULL)
320 			printf("caRepository:             %s\n", p->repo);
321 		if (p->notify != NULL)
322 			printf("Notify URL:               %s\n", p->notify);
323 		if (p->pubkey != NULL) {
324 			printf("BGPsec ECDSA public key:  %s\n",
325 			    p->pubkey);
326 			printf("Router key not before:    %s\n",
327 			    time2str(p->notbefore));
328 			printf("Router key not after:     %s\n",
329 			    time2str(p->notafter));
330 		} else {
331 			printf("Certificate not before:   %s\n",
332 			    time2str(p->notbefore));
333 			printf("Certificate not after:    %s\n",
334 			    time2str(p->notafter));
335 		}
336 		printf("Subordinate resources:    ");
337 	}
338 
339 	as_resources_print(p->as, p->asz);
340 	ip_resources_print(p->ips, p->ipsz, p->asz);
341 
342 	if (outformats & FORMAT_JSON)
343 		json_do_end();
344 }
345 
346 static char *
crl_parse_number(const X509_CRL * x509_crl)347 crl_parse_number(const X509_CRL *x509_crl)
348 {
349 	ASN1_INTEGER	*aint = NULL;
350 	int		 crit;
351 	char		*s = NULL;
352 
353 	aint = X509_CRL_get_ext_d2i(x509_crl, NID_crl_number, &crit, NULL);
354 	if (aint == NULL) {
355 		if (crit != -1)
356 			warnx("%s: RFC 6487, section 5: "
357 			    "failed to parse CRL number", __func__);
358 		else
359 			warnx("%s: RFC 6487, section 5: missing CRL number",
360 			    __func__);
361 		goto out;
362 	}
363 	if (crit != 0) {
364 		warnx("%s: RFC 6487, section 5: CRL number not non-critical",
365 		    __func__);
366 		goto out;
367 	}
368 
369 	s = x509_convert_seqnum(__func__, "CRL Number", aint);
370 
371  out:
372 	ASN1_INTEGER_free(aint);
373 	return s;
374 }
375 
376 void
crl_print(const struct crl * p)377 crl_print(const struct crl *p)
378 {
379 	STACK_OF(X509_REVOKED)	*revlist;
380 	X509_REVOKED *rev;
381 	X509_NAME *xissuer;
382 	int i;
383 	char *issuer, *serial;
384 	time_t t;
385 
386 	if (outformats & FORMAT_JSON) {
387 		json_do_string("type", "crl");
388 		json_do_string("aki", pretty_key_id(p->aki));
389 	} else
390 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
391 
392 	xissuer = X509_CRL_get_issuer(p->x509_crl);
393 	issuer = X509_NAME_oneline(xissuer, NULL, 0);
394 	if (issuer != NULL) {
395 		char *number;
396 
397 		if ((number = crl_parse_number(p->x509_crl)) != NULL) {
398 			if (outformats & FORMAT_JSON) {
399 				json_do_string("crl_issuer", issuer);
400 				json_do_string("crl_serial", number);
401 			} else {
402 				printf("CRL issuer:               %s\n",
403 				    issuer);
404 				printf("CRL serial number:        %s\n",
405 				    number);
406 			}
407 			free(number);
408 		}
409 	}
410 	free(issuer);
411 
412 	if (outformats & FORMAT_JSON) {
413 		json_do_int("valid_since", p->thisupdate);
414 		json_do_int("valid_until", p->nextupdate);
415 		json_do_array("revoked_certs");
416 	} else {
417 		printf("CRL this update:          %s\n",
418 		    time2str(p->thisupdate));
419 		printf("CRL next update:          %s\n",
420 		    time2str(p->nextupdate));
421 		printf("Revoked Certificates:\n");
422 	}
423 
424 	revlist = X509_CRL_get_REVOKED(p->x509_crl);
425 	for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) {
426 		rev = sk_X509_REVOKED_value(revlist, i);
427 		serial = x509_convert_seqnum(__func__, "serial number",
428 		    X509_REVOKED_get0_serialNumber(rev));
429 		x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t);
430 		if (serial != NULL) {
431 			if (outformats & FORMAT_JSON) {
432 				json_do_object("cert", 1);
433 				json_do_string("serial", serial);
434 				json_do_string("date", time2str(t));
435 				json_do_end();
436 			} else
437 				printf("%25s Serial: %8s   Revocation Date: %s"
438 				    "\n", "", serial, time2str(t));
439 		}
440 		free(serial);
441 	}
442 
443 	if (outformats & FORMAT_JSON)
444 		json_do_end();
445 	else if (i == 0)
446 		printf("No Revoked Certificates\n");
447 }
448 
449 void
mft_print(const X509 * x,const struct mft * p)450 mft_print(const X509 *x, const struct mft *p)
451 {
452 	size_t i;
453 	char *hash;
454 
455 	if (outformats & FORMAT_JSON) {
456 		json_do_string("type", "manifest");
457 		json_do_string("ski", pretty_key_id(p->ski));
458 		x509_print(x);
459 		json_do_string("aki", pretty_key_id(p->aki));
460 		json_do_string("aia", p->aia);
461 		json_do_string("sia", p->sia);
462 		json_do_string("manifest_number", p->seqnum);
463 		if (p->signtime != 0)
464 			json_do_int("signing_time", p->signtime);
465 		json_do_int("valid_since", p->thisupdate);
466 		json_do_int("valid_until", p->nextupdate);
467 		if (p->expires)
468 			json_do_int("expires", p->expires);
469 	} else {
470 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
471 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
472 		x509_print(x);
473 		printf("Authority info access:    %s\n", p->aia);
474 		printf("Subject info access:      %s\n", p->sia);
475 		printf("Manifest number:          %s\n", p->seqnum);
476 		if (p->signtime != 0)
477 			printf("Signing time:             %s\n",
478 			    time2str(p->signtime));
479 		printf("Manifest this update:     %s\n", time2str(p->thisupdate));
480 		printf("Manifest next update:     %s\n", time2str(p->nextupdate));
481 		printf("Files and hashes:         ");
482 	}
483 
484 	if (outformats & FORMAT_JSON)
485 		json_do_array("filesandhashes");
486 	for (i = 0; i < p->filesz; i++) {
487 		if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
488 		    &hash) == -1)
489 			errx(1, "base64_encode failure");
490 
491 		if (outformats & FORMAT_JSON) {
492 			json_do_object("filehash", 1);
493 			json_do_string("filename", p->files[i].file);
494 			json_do_string("hash", hash);
495 			json_do_end();
496 		} else {
497 			if (i > 0)
498 				printf("%26s", "");
499 			printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file,
500 			    hash);
501 		}
502 
503 		free(hash);
504 	}
505 	if (outformats & FORMAT_JSON)
506 		json_do_end();
507 }
508 
509 void
roa_print(const X509 * x,const struct roa * p)510 roa_print(const X509 *x, const struct roa *p)
511 {
512 	char	 buf[128];
513 	size_t	 i;
514 
515 	if (outformats & FORMAT_JSON) {
516 		json_do_string("type", "roa");
517 		json_do_string("ski", pretty_key_id(p->ski));
518 		x509_print(x);
519 		json_do_string("aki", pretty_key_id(p->aki));
520 		json_do_string("aia", p->aia);
521 		json_do_string("sia", p->sia);
522 		if (p->signtime != 0)
523 			json_do_int("signing_time", p->signtime);
524 		json_do_int("valid_since", p->notbefore);
525 		json_do_int("valid_until", p->notafter);
526 		if (p->expires)
527 			json_do_int("expires", p->expires);
528 	} else {
529 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
530 		x509_print(x);
531 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
532 		printf("Authority info access:    %s\n", p->aia);
533 		printf("Subject info access:      %s\n", p->sia);
534 		if (p->signtime != 0)
535 			printf("Signing time:             %s\n",
536 			    time2str(p->signtime));
537 		printf("ROA not before:           %s\n",
538 		    time2str(p->notbefore));
539 		printf("ROA not after:            %s\n", time2str(p->notafter));
540 		printf("asID:                     %u\n", p->asid);
541 		printf("IP address blocks:        ");
542 	}
543 
544 	if (outformats & FORMAT_JSON)
545 		json_do_array("vrps");
546 	for (i = 0; i < p->ipsz; i++) {
547 		ip_addr_print(&p->ips[i].addr,
548 		    p->ips[i].afi, buf, sizeof(buf));
549 
550 		if (outformats & FORMAT_JSON) {
551 			json_do_object("vrp", 1);
552 			json_do_string("prefix", buf);
553 			json_do_uint("asid", p->asid);
554 			json_do_uint("maxlen", p->ips[i].maxlength);
555 			json_do_end();
556 		} else {
557 			if (i > 0)
558 				printf("%26s", "");
559 			printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength);
560 		}
561 	}
562 	if (outformats & FORMAT_JSON)
563 		json_do_end();
564 }
565 
566 void
spl_print(const X509 * x,const struct spl * s)567 spl_print(const X509 *x, const struct spl *s)
568 {
569 	char	 buf[128];
570 	size_t	 i;
571 
572 	if (outformats & FORMAT_JSON) {
573 		json_do_string("type", "spl");
574 		json_do_string("ski", pretty_key_id(s->ski));
575 		x509_print(x);
576 		json_do_string("aki", pretty_key_id(s->aki));
577 		json_do_string("aia", s->aia);
578 		json_do_string("sia", s->sia);
579 		if (s->signtime != 0)
580 			json_do_int("signing_time", s->signtime);
581 		json_do_int("valid_since", s->notbefore);
582 		json_do_int("valid_until", s->notafter);
583 		if (s->expires)
584 			json_do_int("expires", s->expires);
585 		json_do_int("asid", s->asid);
586 	} else {
587 		printf("Subject key identifier:   %s\n", pretty_key_id(s->ski));
588 		x509_print(x);
589 		printf("Authority key identifier: %s\n", pretty_key_id(s->aki));
590 		printf("Authority info access:    %s\n", s->aia);
591 		printf("Subject info access:      %s\n", s->sia);
592 		if (s->signtime != 0)
593 			printf("Signing time:             %s\n",
594 			    time2str(s->signtime));
595 		printf("SPL not before:           %s\n",
596 		    time2str(s->notbefore));
597 		printf("SPL not after:            %s\n", time2str(s->notafter));
598 		printf("asID:                     %u\n", s->asid);
599 		printf("Originated IP Prefixes:   ");
600 	}
601 
602 	if (outformats & FORMAT_JSON)
603 		json_do_array("prefixes");
604 	for (i = 0; i < s->pfxsz; i++) {
605 		ip_addr_print(&s->pfxs[i].prefix, s->pfxs[i].afi, buf,
606 		    sizeof(buf));
607 
608 		if (outformats & FORMAT_JSON) {
609 			json_do_string("prefix", buf);
610 		} else {
611 			if (i > 0)
612 				printf("%26s", "");
613 			printf("%s\n", buf);
614 		}
615 	}
616 	if (outformats & FORMAT_JSON)
617 		json_do_end();
618 }
619 
620 void
gbr_print(const X509 * x,const struct gbr * p)621 gbr_print(const X509 *x, const struct gbr *p)
622 {
623 	if (outformats & FORMAT_JSON) {
624 		json_do_string("type", "gbr");
625 		json_do_string("ski", pretty_key_id(p->ski));
626 		x509_print(x);
627 		json_do_string("aki", pretty_key_id(p->aki));
628 		json_do_string("aia", p->aia);
629 		json_do_string("sia", p->sia);
630 		if (p->signtime != 0)
631 			json_do_int("signing_time", p->signtime);
632 		json_do_int("valid_since", p->notbefore);
633 		json_do_int("valid_until", p->notafter);
634 		if (p->expires)
635 			json_do_int("expires", p->expires);
636 		json_do_string("vcard", p->vcard);
637 	} else {
638 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
639 		x509_print(x);
640 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
641 		printf("Authority info access:    %s\n", p->aia);
642 		printf("Subject info access:      %s\n", p->sia);
643 		if (p->signtime != 0)
644 			printf("Signing time:             %s\n",
645 			    time2str(p->signtime));
646 		printf("GBR not before:           %s\n",
647 		    time2str(p->notbefore));
648 		printf("GBR not after:            %s\n", time2str(p->notafter));
649 		printf("vcard:\n%s", p->vcard);
650 	}
651 }
652 
653 void
rsc_print(const X509 * x,const struct rsc * p)654 rsc_print(const X509 *x, const struct rsc *p)
655 {
656 	char	*hash;
657 	size_t	 i;
658 
659 	if (outformats & FORMAT_JSON) {
660 		json_do_string("type", "rsc");
661 		json_do_string("ski", pretty_key_id(p->ski));
662 		x509_print(x);
663 		json_do_string("aki", pretty_key_id(p->aki));
664 		json_do_string("aia", p->aia);
665 		if (p->signtime != 0)
666 			json_do_int("signing_time", p->signtime);
667 		json_do_int("valid_since", p->notbefore);
668 		json_do_int("valid_until", p->notafter);
669 		if (p->expires)
670 			json_do_int("expires", p->expires);
671 		json_do_array("signed_with_resources");
672 	} else {
673 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
674 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
675 		x509_print(x);
676 		printf("Authority info access:    %s\n", p->aia);
677 		if (p->signtime != 0)
678 			printf("Signing time:             %s\n",
679 			    time2str(p->signtime));
680 		printf("RSC not before:           %s\n",
681 		    time2str(p->notbefore));
682 		printf("RSC not after:            %s\n", time2str(p->notafter));
683 		printf("Signed with resources:    ");
684 	}
685 
686 	as_resources_print(p->as, p->asz);
687 	ip_resources_print(p->ips, p->ipsz, p->asz);
688 
689 	if (outformats & FORMAT_JSON) {
690 		json_do_end();
691 		json_do_array("filenamesandhashes");
692 	} else
693 		printf("Filenames and hashes:     ");
694 
695 	for (i = 0; i < p->filesz; i++) {
696 		if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
697 		    &hash) == -1)
698 			errx(1, "base64_encode failure");
699 
700 		if (outformats & FORMAT_JSON) {
701 			json_do_object("filehash", 1);
702 			if (p->files[i].filename)
703 				json_do_string("filename",
704 				    p->files[i].filename);
705 			json_do_string("hash_digest", hash);
706 			json_do_end();
707 		} else {
708 			if (i > 0)
709 				printf("%26s", "");
710 			printf("%zu: %s (hash: %s)\n", i + 1,
711 			    p->files[i].filename ? p->files[i].filename
712 			    : "no filename", hash);
713 		}
714 
715 		free(hash);
716 	}
717 
718 	if (outformats & FORMAT_JSON)
719 		json_do_end();
720 }
721 
722 void
aspa_print(const X509 * x,const struct aspa * p)723 aspa_print(const X509 *x, const struct aspa *p)
724 {
725 	size_t	i;
726 
727 	if (outformats & FORMAT_JSON) {
728 		json_do_string("type", "aspa");
729 		json_do_string("ski", pretty_key_id(p->ski));
730 		x509_print(x);
731 		json_do_string("aki", pretty_key_id(p->aki));
732 		json_do_string("aia", p->aia);
733 		json_do_string("sia", p->sia);
734 		if (p->signtime != 0)
735 			json_do_int("signing_time", p->signtime);
736 		json_do_int("valid_since", p->notbefore);
737 		json_do_int("valid_until", p->notafter);
738 		if (p->expires)
739 			json_do_int("expires", p->expires);
740 		json_do_uint("customer_asid", p->custasid);
741 		json_do_array("providers");
742 	} else {
743 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
744 		x509_print(x);
745 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
746 		printf("Authority info access:    %s\n", p->aia);
747 		printf("Subject info access:      %s\n", p->sia);
748 		if (p->signtime != 0)
749 			printf("Signing time:             %s\n",
750 			    time2str(p->signtime));
751 		printf("ASPA not before:          %s\n",
752 		    time2str(p->notbefore));
753 		printf("ASPA not after:           %s\n", time2str(p->notafter));
754 		printf("Customer ASID:            %u\n", p->custasid);
755 		printf("Providers:                ");
756 	}
757 
758 	for (i = 0; i < p->providersz; i++) {
759 		if (outformats & FORMAT_JSON)
760 			json_do_uint("asid", p->providers[i]);
761 		else {
762 			if (i > 0)
763 				printf("%26s", "");
764 			printf("AS: %u\n", p->providers[i]);
765 		}
766 	}
767 
768 	if (outformats & FORMAT_JSON)
769 		json_do_end();
770 }
771 
772 static void
takey_print(char * name,const struct takey * t)773 takey_print(char *name, const struct takey *t)
774 {
775 	char	*spki = NULL;
776 	size_t	 i, j = 0;
777 
778 	if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0)
779 		errx(1, "base64_encode failed in %s", __func__);
780 
781 	if (outformats & FORMAT_JSON) {
782 		json_do_object("takey", 0);
783 		json_do_string("name", name);
784 		json_do_array("comments");
785 		for (i = 0; i < t->commentsz; i++)
786 			json_do_string("comment", t->comments[i]);
787 		json_do_end();
788 		json_do_array("uris");
789 		for (i = 0; i < t->urisz; i++)
790 			json_do_string("uri", t->uris[i]);
791 		json_do_end();
792 		json_do_string("spki", spki);
793 		json_do_end();
794 	} else {
795 		printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name);
796 
797 		for (i = 0; i < t->commentsz; i++)
798 			printf("\t# %s\n", t->comments[i]);
799 		if (t->commentsz > 0)
800 			printf("\n");
801 		for (i = 0; i < t->urisz; i++)
802 			printf("\t%s\n", t->uris[i]);
803 		printf("\n\t");
804 		for (i = 0; i < strlen(spki); i++) {
805 			printf("%c", spki[i]);
806 			if ((++j % 64) == 0)
807 				printf("\n\t");
808 		}
809 		printf("\n\n");
810 	}
811 
812 	free(spki);
813 }
814 
815 void
tak_print(const X509 * x,const struct tak * p)816 tak_print(const X509 *x, const struct tak *p)
817 {
818 	if (outformats & FORMAT_JSON) {
819 		json_do_string("type", "tak");
820 		json_do_string("ski", pretty_key_id(p->ski));
821 		x509_print(x);
822 		json_do_string("aki", pretty_key_id(p->aki));
823 		json_do_string("aia", p->aia);
824 		json_do_string("sia", p->sia);
825 		if (p->signtime != 0)
826 			json_do_int("signing_time", p->signtime);
827 		json_do_int("valid_since", p->notbefore);
828 		json_do_int("valid_until", p->notafter);
829 		if (p->expires)
830 			json_do_int("expires", p->expires);
831 		json_do_array("takeys");
832 	} else {
833 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
834 		x509_print(x);
835 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
836 		printf("Authority info access:    %s\n", p->aia);
837 		printf("Subject info access:      %s\n", p->sia);
838 		if (p->signtime != 0)
839 			printf("Signing time:             %s\n",
840 			    time2str(p->signtime));
841 		printf("TAK not before:           %s\n",
842 		    time2str(p->notbefore));
843 		printf("TAK not after:            %s\n", time2str(p->notafter));
844 	}
845 
846 	takey_print("current", p->current);
847 	if (p->predecessor != NULL)
848 		takey_print("predecessor", p->predecessor);
849 	if (p->successor != NULL)
850 		takey_print("successor", p->successor);
851 
852 	if (outformats & FORMAT_JSON)
853 		json_do_end();
854 }
855 
856 void
geofeed_print(const X509 * x,const struct geofeed * p)857 geofeed_print(const X509 *x, const struct geofeed *p)
858 {
859 	char	 buf[128];
860 	size_t	 i;
861 
862 	if (outformats & FORMAT_JSON) {
863 		json_do_string("type", "geofeed");
864 		json_do_string("ski", pretty_key_id(p->ski));
865 		x509_print(x);
866 		json_do_string("aki", pretty_key_id(p->aki));
867 		json_do_string("aia", p->aia);
868 		if (p->signtime != 0)
869 			json_do_int("signing_time", p->signtime);
870 		json_do_int("valid_since", p->notbefore);
871 		json_do_int("valid_until", p->notafter);
872 		if (p->expires)
873 			json_do_int("expires", p->expires);
874 		json_do_array("records");
875 	} else {
876 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
877 		x509_print(x);
878 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
879 		printf("Authority info access:    %s\n", p->aia);
880 		if (p->signtime != 0)
881 			printf("Signing time:             %s\n",
882 			    time2str(p->signtime));
883 		printf("Geofeed not before:       %s\n",
884 		    time2str(p->notbefore));
885 		printf("Geofeed not after:        %s\n", time2str(p->notafter));
886 		printf("Geofeed CSV records:      ");
887 	}
888 
889 	for (i = 0; i < p->geoipsz; i++) {
890 		if (p->geoips[i].ip->type != CERT_IP_ADDR)
891 			continue;
892 
893 		ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf,
894 		    sizeof(buf));
895 		if (outformats & FORMAT_JSON) {
896 			json_do_object("geoip", 1);
897 			json_do_string("prefix", buf);
898 			json_do_string("location", p->geoips[i].loc);
899 			json_do_end();
900 		} else {
901 			if (i > 0)
902 				printf("%26s", "");
903 			printf("IP: %s (%s)\n", buf, p->geoips[i].loc);
904 		}
905 	}
906 
907 	if (outformats & FORMAT_JSON)
908 		json_do_end();
909 }
910