xref: /openbsd/usr.sbin/rpki-client/print.c (revision 30a08502)
1 /*	$OpenBSD: print.c,v 1.58 2024/11/13 12:51:04 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->num_uris; 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->num_uris; 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 * ases,size_t num_ases)180 as_resources_print(struct cert_as *ases, size_t num_ases)
181 {
182 	size_t i;
183 
184 	for (i = 0; i < num_ases; i++) {
185 		if (outformats & FORMAT_JSON)
186 			json_do_object("resource", 1);
187 		switch (ases[i].type) {
188 		case CERT_AS_ID:
189 			if (outformats & FORMAT_JSON) {
190 				json_do_uint("asid", ases[i].id);
191 			} else {
192 				if (i > 0)
193 					printf("%26s", "");
194 				printf("AS: %u", ases[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", ases[i].range.min);
210 				json_do_uint("max", ases[i].range.max);
211 				json_do_end();
212 			} else {
213 				if (i > 0)
214 					printf("%26s", "");
215 				printf("AS: %u -- %u", ases[i].range.min,
216 				    ases[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 num_ips,size_t num_ases)228 ip_resources_print(struct cert_ip *ips, size_t num_ips, size_t num_ases)
229 {
230 	char buf1[64], buf2[64];
231 	size_t i;
232 	int sockt;
233 
234 	for (i = 0; i < num_ips; 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 || num_ases > 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 || num_ases > 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 || num_ases > 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->ases, p->num_ases);
340 	ip_resources_print(p->ips, p->num_ips, p->num_ases);
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->num_ips; i++) {
547 		ip_addr_print(&p->ips[i].addr, p->ips[i].afi, buf, sizeof(buf));
548 
549 		if (outformats & FORMAT_JSON) {
550 			json_do_object("vrp", 1);
551 			json_do_string("prefix", buf);
552 			json_do_uint("asid", p->asid);
553 			json_do_uint("maxlen", p->ips[i].maxlength);
554 			json_do_end();
555 		} else {
556 			if (i > 0)
557 				printf("%26s", "");
558 			printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength);
559 		}
560 	}
561 	if (outformats & FORMAT_JSON)
562 		json_do_end();
563 }
564 
565 void
spl_print(const X509 * x,const struct spl * s)566 spl_print(const X509 *x, const struct spl *s)
567 {
568 	char	 buf[128];
569 	size_t	 i;
570 
571 	if (outformats & FORMAT_JSON) {
572 		json_do_string("type", "spl");
573 		json_do_string("ski", pretty_key_id(s->ski));
574 		x509_print(x);
575 		json_do_string("aki", pretty_key_id(s->aki));
576 		json_do_string("aia", s->aia);
577 		json_do_string("sia", s->sia);
578 		if (s->signtime != 0)
579 			json_do_int("signing_time", s->signtime);
580 		json_do_int("valid_since", s->notbefore);
581 		json_do_int("valid_until", s->notafter);
582 		if (s->expires)
583 			json_do_int("expires", s->expires);
584 		json_do_int("asid", s->asid);
585 	} else {
586 		printf("Subject key identifier:   %s\n", pretty_key_id(s->ski));
587 		x509_print(x);
588 		printf("Authority key identifier: %s\n", pretty_key_id(s->aki));
589 		printf("Authority info access:    %s\n", s->aia);
590 		printf("Subject info access:      %s\n", s->sia);
591 		if (s->signtime != 0)
592 			printf("Signing time:             %s\n",
593 			    time2str(s->signtime));
594 		printf("SPL not before:           %s\n",
595 		    time2str(s->notbefore));
596 		printf("SPL not after:            %s\n", time2str(s->notafter));
597 		printf("asID:                     %u\n", s->asid);
598 		printf("Originated IP Prefixes:   ");
599 	}
600 
601 	if (outformats & FORMAT_JSON)
602 		json_do_array("prefixes");
603 	for (i = 0; i < s->num_prefixes; i++) {
604 		ip_addr_print(&s->prefixes[i].prefix, s->prefixes[i].afi, buf,
605 		    sizeof(buf));
606 
607 		if (outformats & FORMAT_JSON) {
608 			json_do_string("prefix", buf);
609 		} else {
610 			if (i > 0)
611 				printf("%26s", "");
612 			printf("%s\n", buf);
613 		}
614 	}
615 	if (outformats & FORMAT_JSON)
616 		json_do_end();
617 }
618 
619 void
gbr_print(const X509 * x,const struct gbr * p)620 gbr_print(const X509 *x, const struct gbr *p)
621 {
622 	if (outformats & FORMAT_JSON) {
623 		json_do_string("type", "gbr");
624 		json_do_string("ski", pretty_key_id(p->ski));
625 		x509_print(x);
626 		json_do_string("aki", pretty_key_id(p->aki));
627 		json_do_string("aia", p->aia);
628 		json_do_string("sia", p->sia);
629 		if (p->signtime != 0)
630 			json_do_int("signing_time", p->signtime);
631 		json_do_int("valid_since", p->notbefore);
632 		json_do_int("valid_until", p->notafter);
633 		if (p->expires)
634 			json_do_int("expires", p->expires);
635 		json_do_string("vcard", p->vcard);
636 	} else {
637 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
638 		x509_print(x);
639 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
640 		printf("Authority info access:    %s\n", p->aia);
641 		printf("Subject info access:      %s\n", p->sia);
642 		if (p->signtime != 0)
643 			printf("Signing time:             %s\n",
644 			    time2str(p->signtime));
645 		printf("GBR not before:           %s\n",
646 		    time2str(p->notbefore));
647 		printf("GBR not after:            %s\n", time2str(p->notafter));
648 		printf("vcard:\n%s", p->vcard);
649 	}
650 }
651 
652 void
rsc_print(const X509 * x,const struct rsc * p)653 rsc_print(const X509 *x, const struct rsc *p)
654 {
655 	char	*hash;
656 	size_t	 i;
657 
658 	if (outformats & FORMAT_JSON) {
659 		json_do_string("type", "rsc");
660 		json_do_string("ski", pretty_key_id(p->ski));
661 		x509_print(x);
662 		json_do_string("aki", pretty_key_id(p->aki));
663 		json_do_string("aia", p->aia);
664 		if (p->signtime != 0)
665 			json_do_int("signing_time", p->signtime);
666 		json_do_int("valid_since", p->notbefore);
667 		json_do_int("valid_until", p->notafter);
668 		if (p->expires)
669 			json_do_int("expires", p->expires);
670 		json_do_array("signed_with_resources");
671 	} else {
672 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
673 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
674 		x509_print(x);
675 		printf("Authority info access:    %s\n", p->aia);
676 		if (p->signtime != 0)
677 			printf("Signing time:             %s\n",
678 			    time2str(p->signtime));
679 		printf("RSC not before:           %s\n",
680 		    time2str(p->notbefore));
681 		printf("RSC not after:            %s\n", time2str(p->notafter));
682 		printf("Signed with resources:    ");
683 	}
684 
685 	as_resources_print(p->ases, p->num_ases);
686 	ip_resources_print(p->ips, p->num_ips, p->num_ases);
687 
688 	if (outformats & FORMAT_JSON) {
689 		json_do_end();
690 		json_do_array("filenamesandhashes");
691 	} else
692 		printf("Filenames and hashes:     ");
693 
694 	for (i = 0; i < p->num_files; i++) {
695 		if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
696 		    &hash) == -1)
697 			errx(1, "base64_encode failure");
698 
699 		if (outformats & FORMAT_JSON) {
700 			json_do_object("filehash", 1);
701 			if (p->files[i].filename)
702 				json_do_string("filename",
703 				    p->files[i].filename);
704 			json_do_string("hash_digest", hash);
705 			json_do_end();
706 		} else {
707 			if (i > 0)
708 				printf("%26s", "");
709 			printf("%zu: %s (hash: %s)\n", i + 1,
710 			    p->files[i].filename ? p->files[i].filename
711 			    : "no filename", hash);
712 		}
713 
714 		free(hash);
715 	}
716 
717 	if (outformats & FORMAT_JSON)
718 		json_do_end();
719 }
720 
721 void
aspa_print(const X509 * x,const struct aspa * p)722 aspa_print(const X509 *x, const struct aspa *p)
723 {
724 	size_t	i;
725 
726 	if (outformats & FORMAT_JSON) {
727 		json_do_string("type", "aspa");
728 		json_do_string("ski", pretty_key_id(p->ski));
729 		x509_print(x);
730 		json_do_string("aki", pretty_key_id(p->aki));
731 		json_do_string("aia", p->aia);
732 		json_do_string("sia", p->sia);
733 		if (p->signtime != 0)
734 			json_do_int("signing_time", p->signtime);
735 		json_do_int("valid_since", p->notbefore);
736 		json_do_int("valid_until", p->notafter);
737 		if (p->expires)
738 			json_do_int("expires", p->expires);
739 		json_do_uint("customer_asid", p->custasid);
740 		json_do_array("providers");
741 	} else {
742 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
743 		x509_print(x);
744 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
745 		printf("Authority info access:    %s\n", p->aia);
746 		printf("Subject info access:      %s\n", p->sia);
747 		if (p->signtime != 0)
748 			printf("Signing time:             %s\n",
749 			    time2str(p->signtime));
750 		printf("ASPA not before:          %s\n",
751 		    time2str(p->notbefore));
752 		printf("ASPA not after:           %s\n", time2str(p->notafter));
753 		printf("Customer ASID:            %u\n", p->custasid);
754 		printf("Providers:                ");
755 	}
756 
757 	for (i = 0; i < p->num_providers; i++) {
758 		if (outformats & FORMAT_JSON)
759 			json_do_uint("asid", p->providers[i]);
760 		else {
761 			if (i > 0)
762 				printf("%26s", "");
763 			printf("AS: %u\n", p->providers[i]);
764 		}
765 	}
766 
767 	if (outformats & FORMAT_JSON)
768 		json_do_end();
769 }
770 
771 static void
takey_print(char * name,const struct takey * t)772 takey_print(char *name, const struct takey *t)
773 {
774 	char	*spki = NULL;
775 	size_t	 i, j = 0;
776 
777 	if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0)
778 		errx(1, "base64_encode failed in %s", __func__);
779 
780 	if (outformats & FORMAT_JSON) {
781 		json_do_object("takey", 0);
782 		json_do_string("name", name);
783 		json_do_array("comments");
784 		for (i = 0; i < t->num_comments; i++)
785 			json_do_string("comment", t->comments[i]);
786 		json_do_end();
787 		json_do_array("uris");
788 		for (i = 0; i < t->num_uris; i++)
789 			json_do_string("uri", t->uris[i]);
790 		json_do_end();
791 		json_do_string("spki", spki);
792 		json_do_end();
793 	} else {
794 		printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name);
795 
796 		for (i = 0; i < t->num_comments; i++)
797 			printf("\t# %s\n", t->comments[i]);
798 		if (t->num_comments > 0)
799 			printf("\n");
800 		for (i = 0; i < t->num_uris; i++)
801 			printf("\t%s\n", t->uris[i]);
802 		printf("\n\t");
803 		for (i = 0; i < strlen(spki); i++) {
804 			printf("%c", spki[i]);
805 			if ((++j % 64) == 0)
806 				printf("\n\t");
807 		}
808 		printf("\n\n");
809 	}
810 
811 	free(spki);
812 }
813 
814 void
tak_print(const X509 * x,const struct tak * p)815 tak_print(const X509 *x, const struct tak *p)
816 {
817 	if (outformats & FORMAT_JSON) {
818 		json_do_string("type", "tak");
819 		json_do_string("ski", pretty_key_id(p->ski));
820 		x509_print(x);
821 		json_do_string("aki", pretty_key_id(p->aki));
822 		json_do_string("aia", p->aia);
823 		json_do_string("sia", p->sia);
824 		if (p->signtime != 0)
825 			json_do_int("signing_time", p->signtime);
826 		json_do_int("valid_since", p->notbefore);
827 		json_do_int("valid_until", p->notafter);
828 		if (p->expires)
829 			json_do_int("expires", p->expires);
830 		json_do_array("takeys");
831 	} else {
832 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
833 		x509_print(x);
834 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
835 		printf("Authority info access:    %s\n", p->aia);
836 		printf("Subject info access:      %s\n", p->sia);
837 		if (p->signtime != 0)
838 			printf("Signing time:             %s\n",
839 			    time2str(p->signtime));
840 		printf("TAK not before:           %s\n",
841 		    time2str(p->notbefore));
842 		printf("TAK not after:            %s\n", time2str(p->notafter));
843 	}
844 
845 	takey_print("current", p->current);
846 	if (p->predecessor != NULL)
847 		takey_print("predecessor", p->predecessor);
848 	if (p->successor != NULL)
849 		takey_print("successor", p->successor);
850 
851 	if (outformats & FORMAT_JSON)
852 		json_do_end();
853 }
854 
855 void
geofeed_print(const X509 * x,const struct geofeed * p)856 geofeed_print(const X509 *x, const struct geofeed *p)
857 {
858 	char	 buf[128];
859 	size_t	 i;
860 
861 	if (outformats & FORMAT_JSON) {
862 		json_do_string("type", "geofeed");
863 		json_do_string("ski", pretty_key_id(p->ski));
864 		x509_print(x);
865 		json_do_string("aki", pretty_key_id(p->aki));
866 		json_do_string("aia", p->aia);
867 		if (p->signtime != 0)
868 			json_do_int("signing_time", p->signtime);
869 		json_do_int("valid_since", p->notbefore);
870 		json_do_int("valid_until", p->notafter);
871 		if (p->expires)
872 			json_do_int("expires", p->expires);
873 		json_do_array("records");
874 	} else {
875 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
876 		x509_print(x);
877 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
878 		printf("Authority info access:    %s\n", p->aia);
879 		if (p->signtime != 0)
880 			printf("Signing time:             %s\n",
881 			    time2str(p->signtime));
882 		printf("Geofeed not before:       %s\n",
883 		    time2str(p->notbefore));
884 		printf("Geofeed not after:        %s\n", time2str(p->notafter));
885 		printf("Geofeed CSV records:      ");
886 	}
887 
888 	for (i = 0; i < p->num_geoips; i++) {
889 		if (p->geoips[i].ip->type != CERT_IP_ADDR)
890 			continue;
891 
892 		ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf,
893 		    sizeof(buf));
894 		if (outformats & FORMAT_JSON) {
895 			json_do_object("geoip", 1);
896 			json_do_string("prefix", buf);
897 			json_do_string("location", p->geoips[i].loc);
898 			json_do_end();
899 		} else {
900 			if (i > 0)
901 				printf("%26s", "");
902 			printf("IP: %s (%s)\n", buf, p->geoips[i].loc);
903 		}
904 	}
905 
906 	if (outformats & FORMAT_JSON)
907 		json_do_end();
908 }
909