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