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