xref: /openbsd-src/usr.sbin/rpki-client/print.c (revision 30a085025d55af7cc5799cf5d05a8d03f20d20ee)
1*30a08502Stb /*	$OpenBSD: print.c,v 1.58 2024/11/13 12:51:04 tb Exp $ */
2714f4e3fSclaudio /*
3714f4e3fSclaudio  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4714f4e3fSclaudio  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5714f4e3fSclaudio  *
6714f4e3fSclaudio  * Permission to use, copy, modify, and distribute this software for any
7714f4e3fSclaudio  * purpose with or without fee is hereby granted, provided that the above
8714f4e3fSclaudio  * copyright notice and this permission notice appear in all copies.
9714f4e3fSclaudio  *
10714f4e3fSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11714f4e3fSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12714f4e3fSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13714f4e3fSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14714f4e3fSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15714f4e3fSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16714f4e3fSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17714f4e3fSclaudio  */
18714f4e3fSclaudio 
19714f4e3fSclaudio #include <sys/types.h>
20714f4e3fSclaudio #include <sys/socket.h>
21714f4e3fSclaudio #include <arpa/inet.h>
22714f4e3fSclaudio 
23714f4e3fSclaudio #include <err.h>
24714f4e3fSclaudio #include <stdio.h>
25714f4e3fSclaudio #include <string.h>
26714f4e3fSclaudio #include <time.h>
27714f4e3fSclaudio 
28e911df76Sjob #include <openssl/evp.h>
29e911df76Sjob 
30714f4e3fSclaudio #include "extern.h"
317aabcda0Sclaudio #include "json.h"
32714f4e3fSclaudio 
33714f4e3fSclaudio static const char *
34254fd372Sclaudio pretty_key_id(const char *hex)
35714f4e3fSclaudio {
36714f4e3fSclaudio 	static char buf[128];	/* bigger than SHA_DIGEST_LENGTH * 3 */
37714f4e3fSclaudio 	size_t i;
38714f4e3fSclaudio 
39714f4e3fSclaudio 	for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) {
40254fd372Sclaudio 		if (i % 3 == 2)
41714f4e3fSclaudio 			buf[i] = ':';
42714f4e3fSclaudio 		else
43714f4e3fSclaudio 			buf[i] = *hex++;
44714f4e3fSclaudio 	}
45714f4e3fSclaudio 	if (i == sizeof(buf))
46714f4e3fSclaudio 		memcpy(buf + sizeof(buf) - 4, "...", 4);
47254fd372Sclaudio 	else
48254fd372Sclaudio 		buf[i] = '\0';
49714f4e3fSclaudio 	return buf;
50714f4e3fSclaudio }
51714f4e3fSclaudio 
52220c707cSclaudio char *
5378de3577Stb nid2str(int nid)
5478de3577Stb {
5578de3577Stb 	static char buf[128];
5678de3577Stb 	const char *name;
5778de3577Stb 
5878de3577Stb 	if ((name = OBJ_nid2ln(nid)) == NULL)
5978de3577Stb 		name = OBJ_nid2sn(nid);
6078de3577Stb 	if (name == NULL)
6178de3577Stb 		name = "unknown";
6278de3577Stb 
6378de3577Stb 	snprintf(buf, sizeof(buf), "nid %d (%s)", nid, name);
6478de3577Stb 
6578de3577Stb 	return buf;
6678de3577Stb }
6778de3577Stb 
683e8d4b7dStb const char *
693e8d4b7dStb purpose2str(enum cert_purpose purpose)
703e8d4b7dStb {
713e8d4b7dStb 	switch (purpose) {
723e8d4b7dStb 	case CERT_PURPOSE_INVALID:
733e8d4b7dStb 		return "invalid cert";
743e8d4b7dStb 	case CERT_PURPOSE_TA:
753e8d4b7dStb 		return "TA cert";
763e8d4b7dStb 	case CERT_PURPOSE_CA:
773e8d4b7dStb 		return "CA cert";
783e8d4b7dStb 	case CERT_PURPOSE_EE:
793e8d4b7dStb 		return "EE cert";
803e8d4b7dStb 	case CERT_PURPOSE_BGPSEC_ROUTER:
813e8d4b7dStb 		return "BGPsec Router cert";
823e8d4b7dStb 	default:
833e8d4b7dStb 		return "unknown certificate purpose";
843e8d4b7dStb 	}
853e8d4b7dStb }
863e8d4b7dStb 
8778de3577Stb char *
88220c707cSclaudio time2str(time_t t)
89220c707cSclaudio {
90220c707cSclaudio 	static char buf[64];
91220c707cSclaudio 	struct tm tm;
92220c707cSclaudio 
93220c707cSclaudio 	if (gmtime_r(&t, &tm) == NULL)
94220c707cSclaudio 		return "could not convert time";
95220c707cSclaudio 
96cc6f004eSjob 	strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm);
97cc6f004eSjob 
98220c707cSclaudio 	return buf;
99220c707cSclaudio }
100220c707cSclaudio 
101714f4e3fSclaudio void
102714f4e3fSclaudio tal_print(const struct tal *p)
103714f4e3fSclaudio {
104e911df76Sjob 	char			*ski;
10523c6f3a2Stb 	const unsigned char	*der;
106ddc87cffSjob 	X509_PUBKEY		*pubkey;
107714f4e3fSclaudio 	size_t			 i;
108714f4e3fSclaudio 
10923c6f3a2Stb 	der = p->pkey;
11023c6f3a2Stb 	if ((pubkey = d2i_X509_PUBKEY(NULL, &der, p->pkeysz)) == NULL)
111ddc87cffSjob 		errx(1, "d2i_X509_PUBKEY failed");
112e911df76Sjob 
11323c6f3a2Stb 	if ((ski = x509_pubkey_get_ski(pubkey, p->descr)) == NULL)
11423c6f3a2Stb 		errx(1, "x509_pubkey_get_ski failed");
115e911df76Sjob 
116530399e8Sjob 	if (outformats & FORMAT_JSON) {
1177aabcda0Sclaudio 		json_do_string("type", "tal");
1187aabcda0Sclaudio 		json_do_string("name", p->descr);
1197aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(ski));
1207aabcda0Sclaudio 		json_do_array("trust_anchor_locations");
121*30a08502Stb 		for (i = 0; i < p->num_uris; i++)
1227aabcda0Sclaudio 			json_do_string("tal", p->uri[i]);
1237aabcda0Sclaudio 		json_do_end();
124530399e8Sjob 	} else {
125530399e8Sjob 		printf("Trust anchor name:        %s\n", p->descr);
126530399e8Sjob 		printf("Subject key identifier:   %s\n", pretty_key_id(ski));
1274486d057Sjob 		printf("Trust anchor locations:   ");
128*30a08502Stb 		for (i = 0; i < p->num_uris; i++) {
1294486d057Sjob 			if (i > 0)
1304486d057Sjob 				printf("%26s", "");
1314486d057Sjob 			printf("%s\n", p->uri[i]);
1324486d057Sjob 		}
133530399e8Sjob 	}
134e911df76Sjob 
135ddc87cffSjob 	X509_PUBKEY_free(pubkey);
136e911df76Sjob 	free(ski);
137714f4e3fSclaudio }
138714f4e3fSclaudio 
139714f4e3fSclaudio void
140530399e8Sjob x509_print(const X509 *x)
141530399e8Sjob {
142530399e8Sjob 	const ASN1_INTEGER	*xserial;
143e0b87278Sjob 	const X509_NAME		*xissuer;
144e0b87278Sjob 	char			*issuer = NULL;
145530399e8Sjob 	char			*serial = NULL;
146530399e8Sjob 
147e0b87278Sjob 	if ((xissuer = X509_get_issuer_name(x)) == NULL) {
148e0b87278Sjob 		warnx("X509_get_issuer_name failed");
149530399e8Sjob 		goto out;
150530399e8Sjob 	}
151530399e8Sjob 
152e0b87278Sjob 	if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) {
153e0b87278Sjob 		warnx("X509_NAME_oneline failed");
154530399e8Sjob 		goto out;
155530399e8Sjob 	}
156530399e8Sjob 
157e0b87278Sjob 	if ((xserial = X509_get0_serialNumber(x)) == NULL) {
158e0b87278Sjob 		warnx("X509_get0_serialNumber failed");
159e0b87278Sjob 		goto out;
160e0b87278Sjob 	}
161e0b87278Sjob 
162904d9c60Stb 	if ((serial = x509_convert_seqnum(__func__, "serial number",
163904d9c60Stb 	    xserial)) == NULL)
164e0b87278Sjob 		goto out;
165e0b87278Sjob 
166530399e8Sjob 	if (outformats & FORMAT_JSON) {
1677aabcda0Sclaudio 		json_do_string("cert_issuer", issuer);
1687aabcda0Sclaudio 		json_do_string("cert_serial", serial);
169530399e8Sjob 	} else {
170e0b87278Sjob 		printf("Certificate issuer:       %s\n", issuer);
171530399e8Sjob 		printf("Certificate serial:       %s\n", serial);
172530399e8Sjob 	}
173530399e8Sjob 
174530399e8Sjob  out:
175e0b87278Sjob 	free(issuer);
176530399e8Sjob 	free(serial);
177530399e8Sjob }
178530399e8Sjob 
1797aabcda0Sclaudio static void
180381ee599Stb as_resources_print(struct cert_as *ases, size_t num_ases)
1817aabcda0Sclaudio {
1827aabcda0Sclaudio 	size_t i;
1837aabcda0Sclaudio 
184381ee599Stb 	for (i = 0; i < num_ases; i++) {
1857aabcda0Sclaudio 		if (outformats & FORMAT_JSON)
186a09a3191Sclaudio 			json_do_object("resource", 1);
187381ee599Stb 		switch (ases[i].type) {
1887aabcda0Sclaudio 		case CERT_AS_ID:
1897aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
190381ee599Stb 				json_do_uint("asid", ases[i].id);
1917aabcda0Sclaudio 			} else {
1927aabcda0Sclaudio 				if (i > 0)
1937aabcda0Sclaudio 					printf("%26s", "");
194381ee599Stb 				printf("AS: %u", ases[i].id);
1957aabcda0Sclaudio 			}
1967aabcda0Sclaudio 			break;
1977aabcda0Sclaudio 		case CERT_AS_INHERIT:
1987aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
1997aabcda0Sclaudio 				json_do_bool("asid_inherit", 1);
2007aabcda0Sclaudio 			} else {
2017aabcda0Sclaudio 				if (i > 0)
2027aabcda0Sclaudio 					printf("%26s", "");
2037aabcda0Sclaudio 				printf("AS: inherit");
2047aabcda0Sclaudio 			}
2057aabcda0Sclaudio 			break;
2067aabcda0Sclaudio 		case CERT_AS_RANGE:
2077aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
208a09a3191Sclaudio 				json_do_object("asrange", 1);
209381ee599Stb 				json_do_uint("min", ases[i].range.min);
210381ee599Stb 				json_do_uint("max", ases[i].range.max);
2117aabcda0Sclaudio 				json_do_end();
2127aabcda0Sclaudio 			} else {
2137aabcda0Sclaudio 				if (i > 0)
2147aabcda0Sclaudio 					printf("%26s", "");
215381ee599Stb 				printf("AS: %u -- %u", ases[i].range.min,
216381ee599Stb 				    ases[i].range.max);
2177aabcda0Sclaudio 			}
2187aabcda0Sclaudio 			break;
2197aabcda0Sclaudio 		}
2207aabcda0Sclaudio 		if (outformats & FORMAT_JSON)
2217aabcda0Sclaudio 			json_do_end();
2227aabcda0Sclaudio 		else
2237aabcda0Sclaudio 			printf("\n");
2247aabcda0Sclaudio 	}
2257aabcda0Sclaudio }
2267aabcda0Sclaudio 
2277aabcda0Sclaudio static void
228381ee599Stb ip_resources_print(struct cert_ip *ips, size_t num_ips, size_t num_ases)
2297aabcda0Sclaudio {
2307aabcda0Sclaudio 	char buf1[64], buf2[64];
2317aabcda0Sclaudio 	size_t i;
2327aabcda0Sclaudio 	int sockt;
2337aabcda0Sclaudio 
234381ee599Stb 	for (i = 0; i < num_ips; i++) {
2357aabcda0Sclaudio 		if (outformats & FORMAT_JSON)
236a09a3191Sclaudio 			json_do_object("resource", 1);
2377aabcda0Sclaudio 		switch (ips[i].type) {
2387aabcda0Sclaudio 		case CERT_IP_INHERIT:
2397aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
2407aabcda0Sclaudio 				json_do_bool("ip_inherit", 1);
2417aabcda0Sclaudio 			} else {
242381ee599Stb 				if (i > 0 || num_ases > 0)
2437aabcda0Sclaudio 					printf("%26s", "");
2447aabcda0Sclaudio 				printf("IP: inherit");
2457aabcda0Sclaudio 			}
2467aabcda0Sclaudio 			break;
2477aabcda0Sclaudio 		case CERT_IP_ADDR:
2487aabcda0Sclaudio 			ip_addr_print(&ips[i].ip, ips[i].afi, buf1,
2497aabcda0Sclaudio 			    sizeof(buf1));
2507aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
2517aabcda0Sclaudio 				json_do_string("ip_prefix", buf1);
2527aabcda0Sclaudio 			} else {
253381ee599Stb 				if (i > 0 || num_ases > 0)
2547aabcda0Sclaudio 					printf("%26s", "");
2557aabcda0Sclaudio 				printf("IP: %s", buf1);
2567aabcda0Sclaudio 			}
2577aabcda0Sclaudio 			break;
2587aabcda0Sclaudio 		case CERT_IP_RANGE:
2597aabcda0Sclaudio 			sockt = (ips[i].afi == AFI_IPV4) ?
2607aabcda0Sclaudio 			    AF_INET : AF_INET6;
2617aabcda0Sclaudio 			inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1));
2627aabcda0Sclaudio 			inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2));
2637aabcda0Sclaudio 			if (outformats & FORMAT_JSON) {
264a09a3191Sclaudio 				json_do_object("ip_range", 1);
2657aabcda0Sclaudio 				json_do_string("min", buf1);
2667aabcda0Sclaudio 				json_do_string("max", buf2);
2677aabcda0Sclaudio 				json_do_end();
2687aabcda0Sclaudio 			} else {
269381ee599Stb 				if (i > 0 || num_ases > 0)
2707aabcda0Sclaudio 					printf("%26s", "");
2717aabcda0Sclaudio 				printf("IP: %s -- %s", buf1, buf2);
2727aabcda0Sclaudio 			}
2737aabcda0Sclaudio 			break;
2747aabcda0Sclaudio 		}
2757aabcda0Sclaudio 		if (outformats & FORMAT_JSON)
2767aabcda0Sclaudio 			json_do_end();
2777aabcda0Sclaudio 		else
2787aabcda0Sclaudio 			printf("\n");
2797aabcda0Sclaudio 	}
2807aabcda0Sclaudio }
2817aabcda0Sclaudio 
282530399e8Sjob void
283714f4e3fSclaudio cert_print(const struct cert *p)
284714f4e3fSclaudio {
285530399e8Sjob 	if (outformats & FORMAT_JSON) {
286530399e8Sjob 		if (p->pubkey != NULL)
2877aabcda0Sclaudio 			json_do_string("type", "router_key");
288530399e8Sjob 		else
2897aabcda0Sclaudio 			json_do_string("type", "ca_cert");
2907aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
291530399e8Sjob 		if (p->aki != NULL)
2927aabcda0Sclaudio 			json_do_string("aki", pretty_key_id(p->aki));
293530399e8Sjob 		x509_print(p->x509);
294530399e8Sjob 		if (p->aia != NULL)
2957aabcda0Sclaudio 			json_do_string("aia", p->aia);
296530399e8Sjob 		if (p->mft != NULL)
2977aabcda0Sclaudio 			json_do_string("manifest", p->mft);
298530399e8Sjob 		if (p->repo != NULL)
2997aabcda0Sclaudio 			json_do_string("carepository", p->repo);
300530399e8Sjob 		if (p->notify != NULL)
3017aabcda0Sclaudio 			json_do_string("notify_url", p->notify);
302530399e8Sjob 		if (p->pubkey != NULL)
3037aabcda0Sclaudio 			json_do_string("router_key", p->pubkey);
3047aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
3057aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
306894936b4Sjob 		if (p->expires)
3077aabcda0Sclaudio 			json_do_int("expires", p->expires);
3087aabcda0Sclaudio 		json_do_array("subordinate_resources");
309530399e8Sjob 	} else {
310714f4e3fSclaudio 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
311714f4e3fSclaudio 		if (p->aki != NULL)
31267642cb5Stb 			printf("Authority key identifier: %s\n",
31367642cb5Stb 			    pretty_key_id(p->aki));
314530399e8Sjob 		x509_print(p->x509);
315714f4e3fSclaudio 		if (p->aia != NULL)
316714f4e3fSclaudio 			printf("Authority info access:    %s\n", p->aia);
317714f4e3fSclaudio 		if (p->mft != NULL)
318714f4e3fSclaudio 			printf("Manifest:                 %s\n", p->mft);
319714f4e3fSclaudio 		if (p->repo != NULL)
320714f4e3fSclaudio 			printf("caRepository:             %s\n", p->repo);
321714f4e3fSclaudio 		if (p->notify != NULL)
322714f4e3fSclaudio 			printf("Notify URL:               %s\n", p->notify);
32314d83341Sjob 		if (p->pubkey != NULL) {
3246530cf17Sjob 			printf("BGPsec ECDSA public key:  %s\n",
32567642cb5Stb 			    p->pubkey);
3264dbb22b8Sjob 			printf("Router key not before:    %s\n",
327f5999ddfSjob 			    time2str(p->notbefore));
3284dbb22b8Sjob 			printf("Router key not after:     %s\n",
3299f544822Sjob 			    time2str(p->notafter));
330f5999ddfSjob 		} else {
3314dbb22b8Sjob 			printf("Certificate not before:   %s\n",
332f5999ddfSjob 			    time2str(p->notbefore));
3334dbb22b8Sjob 			printf("Certificate not after:    %s\n",
3349f544822Sjob 			    time2str(p->notafter));
335f5999ddfSjob 		}
3364486d057Sjob 		printf("Subordinate resources:    ");
337530399e8Sjob 	}
338714f4e3fSclaudio 
339381ee599Stb 	as_resources_print(p->ases, p->num_ases);
340381ee599Stb 	ip_resources_print(p->ips, p->num_ips, p->num_ases);
341530399e8Sjob 
342530399e8Sjob 	if (outformats & FORMAT_JSON)
3437aabcda0Sclaudio 		json_do_end();
344714f4e3fSclaudio }
345714f4e3fSclaudio 
34609383accStb static char *
34709383accStb crl_parse_number(const X509_CRL *x509_crl)
34809383accStb {
34909383accStb 	ASN1_INTEGER	*aint = NULL;
35009383accStb 	int		 crit;
35109383accStb 	char		*s = NULL;
35209383accStb 
35309383accStb 	aint = X509_CRL_get_ext_d2i(x509_crl, NID_crl_number, &crit, NULL);
35409383accStb 	if (aint == NULL) {
35509383accStb 		if (crit != -1)
356904d9c60Stb 			warnx("%s: RFC 6487, section 5: "
357904d9c60Stb 			    "failed to parse CRL number", __func__);
35809383accStb 		else
359904d9c60Stb 			warnx("%s: RFC 6487, section 5: missing CRL number",
360904d9c60Stb 			    __func__);
361904d9c60Stb 		goto out;
362904d9c60Stb 	}
363904d9c60Stb 	if (crit != 0) {
364904d9c60Stb 		warnx("%s: RFC 6487, section 5: CRL number not non-critical",
365904d9c60Stb 		    __func__);
36609383accStb 		goto out;
36709383accStb 	}
36809383accStb 
369904d9c60Stb 	s = x509_convert_seqnum(__func__, "CRL Number", aint);
37009383accStb 
37109383accStb  out:
37209383accStb 	ASN1_INTEGER_free(aint);
37309383accStb 	return s;
37409383accStb }
37509383accStb 
376714f4e3fSclaudio void
377220c707cSclaudio crl_print(const struct crl *p)
378220c707cSclaudio {
379220c707cSclaudio 	STACK_OF(X509_REVOKED)	*revlist;
380220c707cSclaudio 	X509_REVOKED *rev;
381e0b87278Sjob 	X509_NAME *xissuer;
382220c707cSclaudio 	int i;
383e0b87278Sjob 	char *issuer, *serial;
384220c707cSclaudio 	time_t t;
385220c707cSclaudio 
386530399e8Sjob 	if (outformats & FORMAT_JSON) {
3877aabcda0Sclaudio 		json_do_string("type", "crl");
3887aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
389530399e8Sjob 	} else
390220c707cSclaudio 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
3917cdd491fSclaudio 
392e0b87278Sjob 	xissuer = X509_CRL_get_issuer(p->x509_crl);
393e0b87278Sjob 	issuer = X509_NAME_oneline(xissuer, NULL, 0);
39409383accStb 	if (issuer != NULL) {
39509383accStb 		char *number;
39609383accStb 
39709383accStb 		if ((number = crl_parse_number(p->x509_crl)) != NULL) {
398e0b87278Sjob 			if (outformats & FORMAT_JSON) {
3997aabcda0Sclaudio 				json_do_string("crl_issuer", issuer);
40009383accStb 				json_do_string("crl_serial", number);
401e0b87278Sjob 			} else {
40209383accStb 				printf("CRL issuer:               %s\n",
40309383accStb 				    issuer);
40409383accStb 				printf("CRL serial number:        %s\n",
40509383accStb 				    number);
40609383accStb 			}
40709383accStb 			free(number);
408530399e8Sjob 		}
409e0b87278Sjob 	}
410e0b87278Sjob 	free(issuer);
4117cdd491fSclaudio 
412530399e8Sjob 	if (outformats & FORMAT_JSON) {
413c527cc7aSjob 		json_do_int("valid_since", p->thisupdate);
4147aabcda0Sclaudio 		json_do_int("valid_until", p->nextupdate);
4157aabcda0Sclaudio 		json_do_array("revoked_certs");
416530399e8Sjob 	} else {
417c527cc7aSjob 		printf("CRL this update:          %s\n",
418c527cc7aSjob 		    time2str(p->thisupdate));
4194dbb22b8Sjob 		printf("CRL next update:          %s\n",
4209f544822Sjob 		    time2str(p->nextupdate));
421530399e8Sjob 		printf("Revoked Certificates:\n");
422530399e8Sjob 	}
423220c707cSclaudio 
424220c707cSclaudio 	revlist = X509_CRL_get_REVOKED(p->x509_crl);
425220c707cSclaudio 	for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) {
426220c707cSclaudio 		rev = sk_X509_REVOKED_value(revlist, i);
427904d9c60Stb 		serial = x509_convert_seqnum(__func__, "serial number",
4287cdd491fSclaudio 		    X509_REVOKED_get0_serialNumber(rev));
429220c707cSclaudio 		x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t);
430530399e8Sjob 		if (serial != NULL) {
431530399e8Sjob 			if (outformats & FORMAT_JSON) {
432a09a3191Sclaudio 				json_do_object("cert", 1);
4337aabcda0Sclaudio 				json_do_string("serial", serial);
4347aabcda0Sclaudio 				json_do_string("date", time2str(t));
4357aabcda0Sclaudio 				json_do_end();
436530399e8Sjob 			} else
4374486d057Sjob 				printf("%25s Serial: %8s   Revocation Date: %s"
4384486d057Sjob 				    "\n", "", serial, time2str(t));
439530399e8Sjob 		}
4407cdd491fSclaudio 		free(serial);
441220c707cSclaudio 	}
442530399e8Sjob 
443530399e8Sjob 	if (outformats & FORMAT_JSON)
4447aabcda0Sclaudio 		json_do_end();
445530399e8Sjob 	else if (i == 0)
446220c707cSclaudio 		printf("No Revoked Certificates\n");
447220c707cSclaudio }
448220c707cSclaudio 
449220c707cSclaudio void
450530399e8Sjob mft_print(const X509 *x, const struct mft *p)
451714f4e3fSclaudio {
452714f4e3fSclaudio 	size_t i;
453714f4e3fSclaudio 	char *hash;
454714f4e3fSclaudio 
455530399e8Sjob 	if (outformats & FORMAT_JSON) {
4567aabcda0Sclaudio 		json_do_string("type", "manifest");
4577aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
458530399e8Sjob 		x509_print(x);
4597aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
4607aabcda0Sclaudio 		json_do_string("aia", p->aia);
4617aabcda0Sclaudio 		json_do_string("sia", p->sia);
4627aabcda0Sclaudio 		json_do_string("manifest_number", p->seqnum);
4631bb1e509Sjob 		if (p->signtime != 0)
4647aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
4657aabcda0Sclaudio 		json_do_int("valid_since", p->thisupdate);
4667aabcda0Sclaudio 		json_do_int("valid_until", p->nextupdate);
467894936b4Sjob 		if (p->expires)
4687aabcda0Sclaudio 			json_do_int("expires", p->expires);
469530399e8Sjob 	} else {
470714f4e3fSclaudio 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
471714f4e3fSclaudio 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
472530399e8Sjob 		x509_print(x);
473714f4e3fSclaudio 		printf("Authority info access:    %s\n", p->aia);
4742cf0e122Sjob 		printf("Subject info access:      %s\n", p->sia);
475489e308aSjob 		printf("Manifest number:          %s\n", p->seqnum);
4761bb1e509Sjob 		if (p->signtime != 0)
4771bb1e509Sjob 			printf("Signing time:             %s\n",
4781bb1e509Sjob 			    time2str(p->signtime));
4794dbb22b8Sjob 		printf("Manifest this update:     %s\n", time2str(p->thisupdate));
4804dbb22b8Sjob 		printf("Manifest next update:     %s\n", time2str(p->nextupdate));
4814486d057Sjob 		printf("Files and hashes:         ");
482530399e8Sjob 	}
483530399e8Sjob 
4847aabcda0Sclaudio 	if (outformats & FORMAT_JSON)
4857aabcda0Sclaudio 		json_do_array("filesandhashes");
486714f4e3fSclaudio 	for (i = 0; i < p->filesz; i++) {
487714f4e3fSclaudio 		if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
488714f4e3fSclaudio 		    &hash) == -1)
489714f4e3fSclaudio 			errx(1, "base64_encode failure");
490530399e8Sjob 
491530399e8Sjob 		if (outformats & FORMAT_JSON) {
492a09a3191Sclaudio 			json_do_object("filehash", 1);
4937aabcda0Sclaudio 			json_do_string("filename", p->files[i].file);
4947aabcda0Sclaudio 			json_do_string("hash", hash);
4957aabcda0Sclaudio 			json_do_end();
496530399e8Sjob 		} else {
4974486d057Sjob 			if (i > 0)
4984486d057Sjob 				printf("%26s", "");
4994486d057Sjob 			printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file,
5004486d057Sjob 			    hash);
501530399e8Sjob 		}
502530399e8Sjob 
503714f4e3fSclaudio 		free(hash);
504714f4e3fSclaudio 	}
505530399e8Sjob 	if (outformats & FORMAT_JSON)
5067aabcda0Sclaudio 		json_do_end();
507714f4e3fSclaudio }
508714f4e3fSclaudio 
509714f4e3fSclaudio void
510530399e8Sjob roa_print(const X509 *x, const struct roa *p)
511714f4e3fSclaudio {
512714f4e3fSclaudio 	char	 buf[128];
513714f4e3fSclaudio 	size_t	 i;
514714f4e3fSclaudio 
515530399e8Sjob 	if (outformats & FORMAT_JSON) {
5167aabcda0Sclaudio 		json_do_string("type", "roa");
5177aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
518530399e8Sjob 		x509_print(x);
5197aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
5207aabcda0Sclaudio 		json_do_string("aia", p->aia);
5217aabcda0Sclaudio 		json_do_string("sia", p->sia);
5221bb1e509Sjob 		if (p->signtime != 0)
5237aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
5247aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
5257aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
5269c1f5d6bSjob 		if (p->expires)
5277aabcda0Sclaudio 			json_do_int("expires", p->expires);
528530399e8Sjob 	} else {
529714f4e3fSclaudio 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
530530399e8Sjob 		x509_print(x);
531714f4e3fSclaudio 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
532714f4e3fSclaudio 		printf("Authority info access:    %s\n", p->aia);
5332cf0e122Sjob 		printf("Subject info access:      %s\n", p->sia);
5341bb1e509Sjob 		if (p->signtime != 0)
5351bb1e509Sjob 			printf("Signing time:             %s\n",
5361bb1e509Sjob 			    time2str(p->signtime));
5374dbb22b8Sjob 		printf("ROA not before:           %s\n",
538f5999ddfSjob 		    time2str(p->notbefore));
5394dbb22b8Sjob 		printf("ROA not after:            %s\n", time2str(p->notafter));
540714f4e3fSclaudio 		printf("asID:                     %u\n", p->asid);
5414486d057Sjob 		printf("IP address blocks:        ");
542530399e8Sjob 	}
543530399e8Sjob 
5447aabcda0Sclaudio 	if (outformats & FORMAT_JSON)
5457aabcda0Sclaudio 		json_do_array("vrps");
546381ee599Stb 	for (i = 0; i < p->num_ips; i++) {
547381ee599Stb 		ip_addr_print(&p->ips[i].addr, p->ips[i].afi, buf, sizeof(buf));
548530399e8Sjob 
549530399e8Sjob 		if (outformats & FORMAT_JSON) {
550a09a3191Sclaudio 			json_do_object("vrp", 1);
5517aabcda0Sclaudio 			json_do_string("prefix", buf);
5527aabcda0Sclaudio 			json_do_uint("asid", p->asid);
5537aabcda0Sclaudio 			json_do_uint("maxlen", p->ips[i].maxlength);
5547aabcda0Sclaudio 			json_do_end();
5554486d057Sjob 		} else {
5564486d057Sjob 			if (i > 0)
5574486d057Sjob 				printf("%26s", "");
5584486d057Sjob 			printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength);
5594486d057Sjob 		}
560714f4e3fSclaudio 	}
561530399e8Sjob 	if (outformats & FORMAT_JSON)
5627aabcda0Sclaudio 		json_do_end();
563714f4e3fSclaudio }
564714f4e3fSclaudio 
565714f4e3fSclaudio void
566d4be4cdeSjob spl_print(const X509 *x, const struct spl *s)
567d4be4cdeSjob {
568d4be4cdeSjob 	char	 buf[128];
569d4be4cdeSjob 	size_t	 i;
570d4be4cdeSjob 
571d4be4cdeSjob 	if (outformats & FORMAT_JSON) {
572d4be4cdeSjob 		json_do_string("type", "spl");
573d4be4cdeSjob 		json_do_string("ski", pretty_key_id(s->ski));
574d4be4cdeSjob 		x509_print(x);
575d4be4cdeSjob 		json_do_string("aki", pretty_key_id(s->aki));
576d4be4cdeSjob 		json_do_string("aia", s->aia);
577d4be4cdeSjob 		json_do_string("sia", s->sia);
578d4be4cdeSjob 		if (s->signtime != 0)
579d4be4cdeSjob 			json_do_int("signing_time", s->signtime);
580d4be4cdeSjob 		json_do_int("valid_since", s->notbefore);
581d4be4cdeSjob 		json_do_int("valid_until", s->notafter);
582d4be4cdeSjob 		if (s->expires)
583d4be4cdeSjob 			json_do_int("expires", s->expires);
584d4be4cdeSjob 		json_do_int("asid", s->asid);
585d4be4cdeSjob 	} else {
586d4be4cdeSjob 		printf("Subject key identifier:   %s\n", pretty_key_id(s->ski));
587d4be4cdeSjob 		x509_print(x);
588d4be4cdeSjob 		printf("Authority key identifier: %s\n", pretty_key_id(s->aki));
589d4be4cdeSjob 		printf("Authority info access:    %s\n", s->aia);
590d4be4cdeSjob 		printf("Subject info access:      %s\n", s->sia);
591d4be4cdeSjob 		if (s->signtime != 0)
592d4be4cdeSjob 			printf("Signing time:             %s\n",
593d4be4cdeSjob 			    time2str(s->signtime));
594d4be4cdeSjob 		printf("SPL not before:           %s\n",
595d4be4cdeSjob 		    time2str(s->notbefore));
596d4be4cdeSjob 		printf("SPL not after:            %s\n", time2str(s->notafter));
597d4be4cdeSjob 		printf("asID:                     %u\n", s->asid);
598d4be4cdeSjob 		printf("Originated IP Prefixes:   ");
599d4be4cdeSjob 	}
600d4be4cdeSjob 
601d4be4cdeSjob 	if (outformats & FORMAT_JSON)
602d4be4cdeSjob 		json_do_array("prefixes");
603*30a08502Stb 	for (i = 0; i < s->num_prefixes; i++) {
604*30a08502Stb 		ip_addr_print(&s->prefixes[i].prefix, s->prefixes[i].afi, buf,
605d4be4cdeSjob 		    sizeof(buf));
606d4be4cdeSjob 
607d4be4cdeSjob 		if (outformats & FORMAT_JSON) {
608d4be4cdeSjob 			json_do_string("prefix", buf);
609d4be4cdeSjob 		} else {
610d4be4cdeSjob 			if (i > 0)
611d4be4cdeSjob 				printf("%26s", "");
612d4be4cdeSjob 			printf("%s\n", buf);
613d4be4cdeSjob 		}
614d4be4cdeSjob 	}
615d4be4cdeSjob 	if (outformats & FORMAT_JSON)
616d4be4cdeSjob 		json_do_end();
617d4be4cdeSjob }
618d4be4cdeSjob 
619d4be4cdeSjob void
620530399e8Sjob gbr_print(const X509 *x, const struct gbr *p)
621714f4e3fSclaudio {
622530399e8Sjob 	if (outformats & FORMAT_JSON) {
6237aabcda0Sclaudio 		json_do_string("type", "gbr");
6247aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
625530399e8Sjob 		x509_print(x);
6267aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
6277aabcda0Sclaudio 		json_do_string("aia", p->aia);
6287aabcda0Sclaudio 		json_do_string("sia", p->sia);
6291bb1e509Sjob 		if (p->signtime != 0)
6307aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
6317aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
6327aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
633894936b4Sjob 		if (p->expires)
6347aabcda0Sclaudio 			json_do_int("expires", p->expires);
6357aabcda0Sclaudio 		json_do_string("vcard", p->vcard);
636530399e8Sjob 	} else {
637714f4e3fSclaudio 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
638530399e8Sjob 		x509_print(x);
639714f4e3fSclaudio 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
640714f4e3fSclaudio 		printf("Authority info access:    %s\n", p->aia);
6412cf0e122Sjob 		printf("Subject info access:      %s\n", p->sia);
6421bb1e509Sjob 		if (p->signtime != 0)
6431bb1e509Sjob 			printf("Signing time:             %s\n",
6441bb1e509Sjob 			    time2str(p->signtime));
6454dbb22b8Sjob 		printf("GBR not before:           %s\n",
646f5999ddfSjob 		    time2str(p->notbefore));
6474dbb22b8Sjob 		printf("GBR not after:            %s\n", time2str(p->notafter));
648714f4e3fSclaudio 		printf("vcard:\n%s", p->vcard);
649714f4e3fSclaudio 	}
650530399e8Sjob }
65104834fbdSjob 
65204834fbdSjob void
65304834fbdSjob rsc_print(const X509 *x, const struct rsc *p)
65404834fbdSjob {
65504834fbdSjob 	char	*hash;
6567aabcda0Sclaudio 	size_t	 i;
65704834fbdSjob 
65804834fbdSjob 	if (outformats & FORMAT_JSON) {
6597aabcda0Sclaudio 		json_do_string("type", "rsc");
6607aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
66104834fbdSjob 		x509_print(x);
6627aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
6637aabcda0Sclaudio 		json_do_string("aia", p->aia);
6641bb1e509Sjob 		if (p->signtime != 0)
6657aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
6667aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
6677aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
668894936b4Sjob 		if (p->expires)
6697aabcda0Sclaudio 			json_do_int("expires", p->expires);
6707aabcda0Sclaudio 		json_do_array("signed_with_resources");
67104834fbdSjob 	} else {
67204834fbdSjob 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
67304834fbdSjob 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
67404834fbdSjob 		x509_print(x);
67504834fbdSjob 		printf("Authority info access:    %s\n", p->aia);
6761bb1e509Sjob 		if (p->signtime != 0)
6771bb1e509Sjob 			printf("Signing time:             %s\n",
6781bb1e509Sjob 			    time2str(p->signtime));
6794dbb22b8Sjob 		printf("RSC not before:           %s\n",
680f5999ddfSjob 		    time2str(p->notbefore));
6814dbb22b8Sjob 		printf("RSC not after:            %s\n", time2str(p->notafter));
6824486d057Sjob 		printf("Signed with resources:    ");
68304834fbdSjob 	}
68404834fbdSjob 
685381ee599Stb 	as_resources_print(p->ases, p->num_ases);
686381ee599Stb 	ip_resources_print(p->ips, p->num_ips, p->num_ases);
68704834fbdSjob 
68804834fbdSjob 	if (outformats & FORMAT_JSON) {
6897aabcda0Sclaudio 		json_do_end();
6907aabcda0Sclaudio 		json_do_array("filenamesandhashes");
69104834fbdSjob 	} else
6924486d057Sjob 		printf("Filenames and hashes:     ");
69304834fbdSjob 
694*30a08502Stb 	for (i = 0; i < p->num_files; i++) {
69504834fbdSjob 		if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
69604834fbdSjob 		    &hash) == -1)
69704834fbdSjob 			errx(1, "base64_encode failure");
69804834fbdSjob 
69904834fbdSjob 		if (outformats & FORMAT_JSON) {
700a09a3191Sclaudio 			json_do_object("filehash", 1);
7017aabcda0Sclaudio 			if (p->files[i].filename)
7027aabcda0Sclaudio 				json_do_string("filename",
7037aabcda0Sclaudio 				    p->files[i].filename);
7047aabcda0Sclaudio 			json_do_string("hash_digest", hash);
7057aabcda0Sclaudio 			json_do_end();
70604834fbdSjob 		} else {
7074486d057Sjob 			if (i > 0)
7084486d057Sjob 				printf("%26s", "");
7094486d057Sjob 			printf("%zu: %s (hash: %s)\n", i + 1,
7104486d057Sjob 			    p->files[i].filename ? p->files[i].filename
7114486d057Sjob 			    : "no filename", hash);
71204834fbdSjob 		}
71304834fbdSjob 
71404834fbdSjob 		free(hash);
71504834fbdSjob 	}
71604834fbdSjob 
71704834fbdSjob 	if (outformats & FORMAT_JSON)
7187aabcda0Sclaudio 		json_do_end();
71904834fbdSjob }
720a29ddfd5Sjob 
721a29ddfd5Sjob void
722a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p)
723a29ddfd5Sjob {
7244b5fc138Sjob 	size_t	i;
7254b5fc138Sjob 
726a29ddfd5Sjob 	if (outformats & FORMAT_JSON) {
7277aabcda0Sclaudio 		json_do_string("type", "aspa");
7287aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
729a29ddfd5Sjob 		x509_print(x);
7307aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
7317aabcda0Sclaudio 		json_do_string("aia", p->aia);
7327aabcda0Sclaudio 		json_do_string("sia", p->sia);
7331bb1e509Sjob 		if (p->signtime != 0)
7347aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
7357aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
7367aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
7379c1f5d6bSjob 		if (p->expires)
7387aabcda0Sclaudio 			json_do_int("expires", p->expires);
7397aabcda0Sclaudio 		json_do_uint("customer_asid", p->custasid);
7404a0be80eSjob 		json_do_array("providers");
741a29ddfd5Sjob 	} else {
742a29ddfd5Sjob 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
743a29ddfd5Sjob 		x509_print(x);
744a29ddfd5Sjob 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
745a29ddfd5Sjob 		printf("Authority info access:    %s\n", p->aia);
7462cf0e122Sjob 		printf("Subject info access:      %s\n", p->sia);
7471bb1e509Sjob 		if (p->signtime != 0)
7481bb1e509Sjob 			printf("Signing time:             %s\n",
7491bb1e509Sjob 			    time2str(p->signtime));
7504dbb22b8Sjob 		printf("ASPA not before:          %s\n",
751f5999ddfSjob 		    time2str(p->notbefore));
7524dbb22b8Sjob 		printf("ASPA not after:           %s\n", time2str(p->notafter));
753ba54bc08Sjob 		printf("Customer ASID:            %u\n", p->custasid);
7544a0be80eSjob 		printf("Providers:                ");
755a29ddfd5Sjob 	}
7567aabcda0Sclaudio 
757*30a08502Stb 	for (i = 0; i < p->num_providers; i++) {
758b179db0eSjob 		if (outformats & FORMAT_JSON)
759b179db0eSjob 			json_do_uint("asid", p->providers[i]);
760b179db0eSjob 		else {
761b179db0eSjob 			if (i > 0)
7624b5fc138Sjob 				printf("%26s", "");
763b179db0eSjob 			printf("AS: %u\n", p->providers[i]);
764b179db0eSjob 		}
7654b5fc138Sjob 	}
7667aabcda0Sclaudio 
7677aabcda0Sclaudio 	if (outformats & FORMAT_JSON)
7687aabcda0Sclaudio 		json_do_end();
769a29ddfd5Sjob }
770ee2a33daSjob 
771ee2a33daSjob static void
772ee2a33daSjob takey_print(char *name, const struct takey *t)
773ee2a33daSjob {
774ee2a33daSjob 	char	*spki = NULL;
775ee2a33daSjob 	size_t	 i, j = 0;
776ee2a33daSjob 
777ee2a33daSjob 	if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0)
778ee2a33daSjob 		errx(1, "base64_encode failed in %s", __func__);
779ee2a33daSjob 
780ee2a33daSjob 	if (outformats & FORMAT_JSON) {
781a09a3191Sclaudio 		json_do_object("takey", 0);
7827aabcda0Sclaudio 		json_do_string("name", name);
7837aabcda0Sclaudio 		json_do_array("comments");
784*30a08502Stb 		for (i = 0; i < t->num_comments; i++)
7857aabcda0Sclaudio 			json_do_string("comment", t->comments[i]);
7867aabcda0Sclaudio 		json_do_end();
7877aabcda0Sclaudio 		json_do_array("uris");
788*30a08502Stb 		for (i = 0; i < t->num_uris; i++)
7897aabcda0Sclaudio 			json_do_string("uri", t->uris[i]);
7907aabcda0Sclaudio 		json_do_end();
7917aabcda0Sclaudio 		json_do_string("spki", spki);
79217f7a478Sjob 		json_do_end();
793ee2a33daSjob 	} else {
794ee2a33daSjob 		printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name);
795ee2a33daSjob 
796*30a08502Stb 		for (i = 0; i < t->num_comments; i++)
797ee2a33daSjob 			printf("\t# %s\n", t->comments[i]);
798*30a08502Stb 		if (t->num_comments > 0)
7997aabcda0Sclaudio 			printf("\n");
800*30a08502Stb 		for (i = 0; i < t->num_uris; i++)
801eb3e3a76Sjob 			printf("\t%s\n", t->uris[i]);
802eb3e3a76Sjob 		printf("\n\t");
803ee2a33daSjob 		for (i = 0; i < strlen(spki); i++) {
804ee2a33daSjob 			printf("%c", spki[i]);
8057aabcda0Sclaudio 			if ((++j % 64) == 0)
806ee2a33daSjob 				printf("\n\t");
807ee2a33daSjob 		}
808ee2a33daSjob 		printf("\n\n");
809ee2a33daSjob 	}
810ee2a33daSjob 
811ee2a33daSjob 	free(spki);
812ee2a33daSjob }
813ee2a33daSjob 
814ee2a33daSjob void
815ee2a33daSjob tak_print(const X509 *x, const struct tak *p)
816ee2a33daSjob {
817ee2a33daSjob 	if (outformats & FORMAT_JSON) {
8187aabcda0Sclaudio 		json_do_string("type", "tak");
8197aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
820ee2a33daSjob 		x509_print(x);
8217aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
8227aabcda0Sclaudio 		json_do_string("aia", p->aia);
8237aabcda0Sclaudio 		json_do_string("sia", p->sia);
8241bb1e509Sjob 		if (p->signtime != 0)
8257aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
8267aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
8277aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
828894936b4Sjob 		if (p->expires)
8297aabcda0Sclaudio 			json_do_int("expires", p->expires);
8307aabcda0Sclaudio 		json_do_array("takeys");
831ee2a33daSjob 	} else {
832ee2a33daSjob 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
833ee2a33daSjob 		x509_print(x);
834ee2a33daSjob 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
835ee2a33daSjob 		printf("Authority info access:    %s\n", p->aia);
8362cf0e122Sjob 		printf("Subject info access:      %s\n", p->sia);
8371bb1e509Sjob 		if (p->signtime != 0)
8381bb1e509Sjob 			printf("Signing time:             %s\n",
8391bb1e509Sjob 			    time2str(p->signtime));
8404dbb22b8Sjob 		printf("TAK not before:           %s\n",
841f5999ddfSjob 		    time2str(p->notbefore));
8424dbb22b8Sjob 		printf("TAK not after:            %s\n", time2str(p->notafter));
843ee2a33daSjob 	}
844ee2a33daSjob 
845ee2a33daSjob 	takey_print("current", p->current);
8467aabcda0Sclaudio 	if (p->predecessor != NULL)
847ee2a33daSjob 		takey_print("predecessor", p->predecessor);
8487aabcda0Sclaudio 	if (p->successor != NULL)
849ee2a33daSjob 		takey_print("successor", p->successor);
850ee2a33daSjob 
851ee2a33daSjob 	if (outformats & FORMAT_JSON)
8527aabcda0Sclaudio 		json_do_end();
853ee2a33daSjob }
854ef3f6f56Sjob 
855ef3f6f56Sjob void
856ef3f6f56Sjob geofeed_print(const X509 *x, const struct geofeed *p)
857ef3f6f56Sjob {
858ef3f6f56Sjob 	char	 buf[128];
859ef3f6f56Sjob 	size_t	 i;
860ef3f6f56Sjob 
861ef3f6f56Sjob 	if (outformats & FORMAT_JSON) {
8627aabcda0Sclaudio 		json_do_string("type", "geofeed");
8637aabcda0Sclaudio 		json_do_string("ski", pretty_key_id(p->ski));
864ef3f6f56Sjob 		x509_print(x);
8657aabcda0Sclaudio 		json_do_string("aki", pretty_key_id(p->aki));
8667aabcda0Sclaudio 		json_do_string("aia", p->aia);
8671bb1e509Sjob 		if (p->signtime != 0)
8687aabcda0Sclaudio 			json_do_int("signing_time", p->signtime);
8697aabcda0Sclaudio 		json_do_int("valid_since", p->notbefore);
8707aabcda0Sclaudio 		json_do_int("valid_until", p->notafter);
8717aabcda0Sclaudio 		if (p->expires)
8727aabcda0Sclaudio 			json_do_int("expires", p->expires);
8737aabcda0Sclaudio 		json_do_array("records");
874ef3f6f56Sjob 	} else {
875ef3f6f56Sjob 		printf("Subject key identifier:   %s\n", pretty_key_id(p->ski));
876ef3f6f56Sjob 		x509_print(x);
877ef3f6f56Sjob 		printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
878ef3f6f56Sjob 		printf("Authority info access:    %s\n", p->aia);
8791bb1e509Sjob 		if (p->signtime != 0)
8801bb1e509Sjob 			printf("Signing time:             %s\n",
8811bb1e509Sjob 			    time2str(p->signtime));
8824dbb22b8Sjob 		printf("Geofeed not before:       %s\n",
883f5999ddfSjob 		    time2str(p->notbefore));
8844dbb22b8Sjob 		printf("Geofeed not after:        %s\n", time2str(p->notafter));
885bd19f13dSjob 		printf("Geofeed CSV records:      ");
886ef3f6f56Sjob 	}
887ef3f6f56Sjob 
888381ee599Stb 	for (i = 0; i < p->num_geoips; i++) {
889ef3f6f56Sjob 		if (p->geoips[i].ip->type != CERT_IP_ADDR)
890ef3f6f56Sjob 			continue;
891ef3f6f56Sjob 
892ef3f6f56Sjob 		ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf,
893ef3f6f56Sjob 		    sizeof(buf));
8947aabcda0Sclaudio 		if (outformats & FORMAT_JSON) {
895a09a3191Sclaudio 			json_do_object("geoip", 1);
8967aabcda0Sclaudio 			json_do_string("prefix", buf);
8977aabcda0Sclaudio 			json_do_string("location", p->geoips[i].loc);
8987aabcda0Sclaudio 			json_do_end();
8997aabcda0Sclaudio 		} else {
9004486d057Sjob 			if (i > 0)
9014486d057Sjob 				printf("%26s", "");
9027aabcda0Sclaudio 			printf("IP: %s (%s)\n", buf, p->geoips[i].loc);
9034486d057Sjob 		}
904ef3f6f56Sjob 	}
905ef3f6f56Sjob 
906ef3f6f56Sjob 	if (outformats & FORMAT_JSON)
9077aabcda0Sclaudio 		json_do_end();
908ef3f6f56Sjob }
909