1*17f7a478Sjob /* $OpenBSD: print.c,v 1.52 2024/02/26 10:02:37 job 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 6878de3577Stb char * 69220c707cSclaudio time2str(time_t t) 70220c707cSclaudio { 71220c707cSclaudio static char buf[64]; 72220c707cSclaudio struct tm tm; 73220c707cSclaudio 74220c707cSclaudio if (gmtime_r(&t, &tm) == NULL) 75220c707cSclaudio return "could not convert time"; 76220c707cSclaudio 77cc6f004eSjob strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm); 78cc6f004eSjob 79220c707cSclaudio return buf; 80220c707cSclaudio } 81220c707cSclaudio 82714f4e3fSclaudio void 83714f4e3fSclaudio tal_print(const struct tal *p) 84714f4e3fSclaudio { 85e911df76Sjob char *ski; 8623c6f3a2Stb const unsigned char *der; 87ddc87cffSjob X509_PUBKEY *pubkey; 88714f4e3fSclaudio size_t i; 89714f4e3fSclaudio 9023c6f3a2Stb der = p->pkey; 9123c6f3a2Stb if ((pubkey = d2i_X509_PUBKEY(NULL, &der, p->pkeysz)) == NULL) 92ddc87cffSjob errx(1, "d2i_X509_PUBKEY failed"); 93e911df76Sjob 9423c6f3a2Stb if ((ski = x509_pubkey_get_ski(pubkey, p->descr)) == NULL) 9523c6f3a2Stb errx(1, "x509_pubkey_get_ski failed"); 96e911df76Sjob 97530399e8Sjob if (outformats & FORMAT_JSON) { 987aabcda0Sclaudio json_do_string("type", "tal"); 997aabcda0Sclaudio json_do_string("name", p->descr); 1007aabcda0Sclaudio json_do_string("ski", pretty_key_id(ski)); 1017aabcda0Sclaudio json_do_array("trust_anchor_locations"); 1027aabcda0Sclaudio for (i = 0; i < p->urisz; i++) 1037aabcda0Sclaudio json_do_string("tal", p->uri[i]); 1047aabcda0Sclaudio json_do_end(); 105530399e8Sjob } else { 106530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 107530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 1084486d057Sjob printf("Trust anchor locations: "); 1094486d057Sjob for (i = 0; i < p->urisz; i++) { 1104486d057Sjob if (i > 0) 1114486d057Sjob printf("%26s", ""); 1124486d057Sjob printf("%s\n", p->uri[i]); 1134486d057Sjob } 114530399e8Sjob } 115e911df76Sjob 116ddc87cffSjob X509_PUBKEY_free(pubkey); 117e911df76Sjob free(ski); 118714f4e3fSclaudio } 119714f4e3fSclaudio 120714f4e3fSclaudio void 121530399e8Sjob x509_print(const X509 *x) 122530399e8Sjob { 123530399e8Sjob const ASN1_INTEGER *xserial; 124e0b87278Sjob const X509_NAME *xissuer; 125e0b87278Sjob char *issuer = NULL; 126530399e8Sjob char *serial = NULL; 127530399e8Sjob 128e0b87278Sjob if ((xissuer = X509_get_issuer_name(x)) == NULL) { 129e0b87278Sjob warnx("X509_get_issuer_name failed"); 130530399e8Sjob goto out; 131530399e8Sjob } 132530399e8Sjob 133e0b87278Sjob if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) { 134e0b87278Sjob warnx("X509_NAME_oneline failed"); 135530399e8Sjob goto out; 136530399e8Sjob } 137530399e8Sjob 138e0b87278Sjob if ((xserial = X509_get0_serialNumber(x)) == NULL) { 139e0b87278Sjob warnx("X509_get0_serialNumber failed"); 140e0b87278Sjob goto out; 141e0b87278Sjob } 142e0b87278Sjob 143e0b87278Sjob if ((serial = x509_convert_seqnum(__func__, xserial)) == NULL) 144e0b87278Sjob goto out; 145e0b87278Sjob 146530399e8Sjob if (outformats & FORMAT_JSON) { 1477aabcda0Sclaudio json_do_string("cert_issuer", issuer); 1487aabcda0Sclaudio json_do_string("cert_serial", serial); 149530399e8Sjob } else { 150e0b87278Sjob printf("Certificate issuer: %s\n", issuer); 151530399e8Sjob printf("Certificate serial: %s\n", serial); 152530399e8Sjob } 153530399e8Sjob 154530399e8Sjob out: 155e0b87278Sjob free(issuer); 156530399e8Sjob free(serial); 157530399e8Sjob } 158530399e8Sjob 1597aabcda0Sclaudio static void 1607aabcda0Sclaudio as_resources_print(struct cert_as *as, size_t asz) 1617aabcda0Sclaudio { 1627aabcda0Sclaudio size_t i; 1637aabcda0Sclaudio 1647aabcda0Sclaudio for (i = 0; i < asz; i++) { 1657aabcda0Sclaudio if (outformats & FORMAT_JSON) 166a09a3191Sclaudio json_do_object("resource", 1); 1677aabcda0Sclaudio switch (as[i].type) { 1687aabcda0Sclaudio case CERT_AS_ID: 1697aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1707aabcda0Sclaudio json_do_uint("asid", as[i].id); 1717aabcda0Sclaudio } else { 1727aabcda0Sclaudio if (i > 0) 1737aabcda0Sclaudio printf("%26s", ""); 1747aabcda0Sclaudio printf("AS: %u", as[i].id); 1757aabcda0Sclaudio } 1767aabcda0Sclaudio break; 1777aabcda0Sclaudio case CERT_AS_INHERIT: 1787aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1797aabcda0Sclaudio json_do_bool("asid_inherit", 1); 1807aabcda0Sclaudio } else { 1817aabcda0Sclaudio if (i > 0) 1827aabcda0Sclaudio printf("%26s", ""); 1837aabcda0Sclaudio printf("AS: inherit"); 1847aabcda0Sclaudio } 1857aabcda0Sclaudio break; 1867aabcda0Sclaudio case CERT_AS_RANGE: 1877aabcda0Sclaudio if (outformats & FORMAT_JSON) { 188a09a3191Sclaudio json_do_object("asrange", 1); 1897aabcda0Sclaudio json_do_uint("min", as[i].range.min); 1907aabcda0Sclaudio json_do_uint("max", as[i].range.max); 1917aabcda0Sclaudio json_do_end(); 1927aabcda0Sclaudio } else { 1937aabcda0Sclaudio if (i > 0) 1947aabcda0Sclaudio printf("%26s", ""); 1957aabcda0Sclaudio printf("AS: %u -- %u", as[i].range.min, 1967aabcda0Sclaudio as[i].range.max); 1977aabcda0Sclaudio } 1987aabcda0Sclaudio break; 1997aabcda0Sclaudio } 2007aabcda0Sclaudio if (outformats & FORMAT_JSON) 2017aabcda0Sclaudio json_do_end(); 2027aabcda0Sclaudio else 2037aabcda0Sclaudio printf("\n"); 2047aabcda0Sclaudio } 2057aabcda0Sclaudio } 2067aabcda0Sclaudio 2077aabcda0Sclaudio static void 2087aabcda0Sclaudio ip_resources_print(struct cert_ip *ips, size_t ipsz, size_t asz) 2097aabcda0Sclaudio { 2107aabcda0Sclaudio char buf1[64], buf2[64]; 2117aabcda0Sclaudio size_t i; 2127aabcda0Sclaudio int sockt; 2137aabcda0Sclaudio 2147aabcda0Sclaudio 2157aabcda0Sclaudio for (i = 0; i < ipsz; i++) { 2167aabcda0Sclaudio if (outformats & FORMAT_JSON) 217a09a3191Sclaudio json_do_object("resource", 1); 2187aabcda0Sclaudio switch (ips[i].type) { 2197aabcda0Sclaudio case CERT_IP_INHERIT: 2207aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2217aabcda0Sclaudio json_do_bool("ip_inherit", 1); 2227aabcda0Sclaudio } else { 2237aabcda0Sclaudio if (i > 0 || asz > 0) 2247aabcda0Sclaudio printf("%26s", ""); 2257aabcda0Sclaudio printf("IP: inherit"); 2267aabcda0Sclaudio } 2277aabcda0Sclaudio break; 2287aabcda0Sclaudio case CERT_IP_ADDR: 2297aabcda0Sclaudio ip_addr_print(&ips[i].ip, ips[i].afi, buf1, 2307aabcda0Sclaudio sizeof(buf1)); 2317aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2327aabcda0Sclaudio json_do_string("ip_prefix", buf1); 2337aabcda0Sclaudio } else { 2347aabcda0Sclaudio if (i > 0 || asz > 0) 2357aabcda0Sclaudio printf("%26s", ""); 2367aabcda0Sclaudio printf("IP: %s", buf1); 2377aabcda0Sclaudio } 2387aabcda0Sclaudio break; 2397aabcda0Sclaudio case CERT_IP_RANGE: 2407aabcda0Sclaudio sockt = (ips[i].afi == AFI_IPV4) ? 2417aabcda0Sclaudio AF_INET : AF_INET6; 2427aabcda0Sclaudio inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1)); 2437aabcda0Sclaudio inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2)); 2447aabcda0Sclaudio if (outformats & FORMAT_JSON) { 245a09a3191Sclaudio json_do_object("ip_range", 1); 2467aabcda0Sclaudio json_do_string("min", buf1); 2477aabcda0Sclaudio json_do_string("max", buf2); 2487aabcda0Sclaudio json_do_end(); 2497aabcda0Sclaudio } else { 2507aabcda0Sclaudio if (i > 0 || asz > 0) 2517aabcda0Sclaudio printf("%26s", ""); 2527aabcda0Sclaudio printf("IP: %s -- %s", buf1, buf2); 2537aabcda0Sclaudio } 2547aabcda0Sclaudio break; 2557aabcda0Sclaudio } 2567aabcda0Sclaudio if (outformats & FORMAT_JSON) 2577aabcda0Sclaudio json_do_end(); 2587aabcda0Sclaudio else 2597aabcda0Sclaudio printf("\n"); 2607aabcda0Sclaudio } 2617aabcda0Sclaudio } 2627aabcda0Sclaudio 263530399e8Sjob void 264714f4e3fSclaudio cert_print(const struct cert *p) 265714f4e3fSclaudio { 266530399e8Sjob if (outformats & FORMAT_JSON) { 267530399e8Sjob if (p->pubkey != NULL) 2687aabcda0Sclaudio json_do_string("type", "router_key"); 269530399e8Sjob else 2707aabcda0Sclaudio json_do_string("type", "ca_cert"); 2717aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 272530399e8Sjob if (p->aki != NULL) 2737aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 274530399e8Sjob x509_print(p->x509); 275530399e8Sjob if (p->aia != NULL) 2767aabcda0Sclaudio json_do_string("aia", p->aia); 277530399e8Sjob if (p->mft != NULL) 2787aabcda0Sclaudio json_do_string("manifest", p->mft); 279530399e8Sjob if (p->repo != NULL) 2807aabcda0Sclaudio json_do_string("carepository", p->repo); 281530399e8Sjob if (p->notify != NULL) 2827aabcda0Sclaudio json_do_string("notify_url", p->notify); 283530399e8Sjob if (p->pubkey != NULL) 2847aabcda0Sclaudio json_do_string("router_key", p->pubkey); 2857aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 2867aabcda0Sclaudio json_do_int("valid_until", p->notafter); 287894936b4Sjob if (p->expires) 2887aabcda0Sclaudio json_do_int("expires", p->expires); 2897aabcda0Sclaudio json_do_array("subordinate_resources"); 290530399e8Sjob } else { 291714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 292714f4e3fSclaudio if (p->aki != NULL) 29367642cb5Stb printf("Authority key identifier: %s\n", 29467642cb5Stb pretty_key_id(p->aki)); 295530399e8Sjob x509_print(p->x509); 296714f4e3fSclaudio if (p->aia != NULL) 297714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 298714f4e3fSclaudio if (p->mft != NULL) 299714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 300714f4e3fSclaudio if (p->repo != NULL) 301714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 302714f4e3fSclaudio if (p->notify != NULL) 303714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 30414d83341Sjob if (p->pubkey != NULL) { 3056530cf17Sjob printf("BGPsec ECDSA public key: %s\n", 30667642cb5Stb p->pubkey); 3074dbb22b8Sjob printf("Router key not before: %s\n", 308f5999ddfSjob time2str(p->notbefore)); 3094dbb22b8Sjob printf("Router key not after: %s\n", 3109f544822Sjob time2str(p->notafter)); 311f5999ddfSjob } else { 3124dbb22b8Sjob printf("Certificate not before: %s\n", 313f5999ddfSjob time2str(p->notbefore)); 3144dbb22b8Sjob printf("Certificate not after: %s\n", 3159f544822Sjob time2str(p->notafter)); 316f5999ddfSjob } 3174486d057Sjob printf("Subordinate resources: "); 318530399e8Sjob } 319714f4e3fSclaudio 3207aabcda0Sclaudio as_resources_print(p->as, p->asz); 3217aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 322530399e8Sjob 323530399e8Sjob if (outformats & FORMAT_JSON) 3247aabcda0Sclaudio json_do_end(); 325714f4e3fSclaudio } 326714f4e3fSclaudio 327714f4e3fSclaudio void 328220c707cSclaudio crl_print(const struct crl *p) 329220c707cSclaudio { 330220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 331220c707cSclaudio X509_REVOKED *rev; 332e0b87278Sjob X509_NAME *xissuer; 333220c707cSclaudio int i; 334e0b87278Sjob char *issuer, *serial; 335220c707cSclaudio time_t t; 336220c707cSclaudio 337530399e8Sjob if (outformats & FORMAT_JSON) { 3387aabcda0Sclaudio json_do_string("type", "crl"); 3397aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 340530399e8Sjob } else 341220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 3427cdd491fSclaudio 343e0b87278Sjob xissuer = X509_CRL_get_issuer(p->x509_crl); 344e0b87278Sjob issuer = X509_NAME_oneline(xissuer, NULL, 0); 3450a722356Stb if (issuer != NULL && p->number != NULL) { 346e0b87278Sjob if (outformats & FORMAT_JSON) { 3477aabcda0Sclaudio json_do_string("crl_issuer", issuer); 3480a722356Stb json_do_string("crl_serial", p->number); 349e0b87278Sjob } else { 350e0b87278Sjob printf("CRL issuer: %s\n", issuer); 3510a722356Stb printf("CRL serial number: %s\n", p->number); 352530399e8Sjob } 353e0b87278Sjob } 354e0b87278Sjob free(issuer); 3557cdd491fSclaudio 356530399e8Sjob if (outformats & FORMAT_JSON) { 357c527cc7aSjob json_do_int("valid_since", p->thisupdate); 3587aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 3597aabcda0Sclaudio json_do_array("revoked_certs"); 360530399e8Sjob } else { 361c527cc7aSjob printf("CRL this update: %s\n", 362c527cc7aSjob time2str(p->thisupdate)); 3634dbb22b8Sjob printf("CRL next update: %s\n", 3649f544822Sjob time2str(p->nextupdate)); 365530399e8Sjob printf("Revoked Certificates:\n"); 366530399e8Sjob } 367220c707cSclaudio 368220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 369220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 370220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3717cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3727cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 373220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 374530399e8Sjob if (serial != NULL) { 375530399e8Sjob if (outformats & FORMAT_JSON) { 376a09a3191Sclaudio json_do_object("cert", 1); 3777aabcda0Sclaudio json_do_string("serial", serial); 3787aabcda0Sclaudio json_do_string("date", time2str(t)); 3797aabcda0Sclaudio json_do_end(); 380530399e8Sjob } else 3814486d057Sjob printf("%25s Serial: %8s Revocation Date: %s" 3824486d057Sjob "\n", "", serial, time2str(t)); 383530399e8Sjob } 3847cdd491fSclaudio free(serial); 385220c707cSclaudio } 386530399e8Sjob 387530399e8Sjob if (outformats & FORMAT_JSON) 3887aabcda0Sclaudio json_do_end(); 389530399e8Sjob else if (i == 0) 390220c707cSclaudio printf("No Revoked Certificates\n"); 391220c707cSclaudio } 392220c707cSclaudio 393220c707cSclaudio void 394530399e8Sjob mft_print(const X509 *x, const struct mft *p) 395714f4e3fSclaudio { 396714f4e3fSclaudio size_t i; 397714f4e3fSclaudio char *hash; 398714f4e3fSclaudio 399530399e8Sjob if (outformats & FORMAT_JSON) { 4007aabcda0Sclaudio json_do_string("type", "manifest"); 4017aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 402530399e8Sjob x509_print(x); 4037aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4047aabcda0Sclaudio json_do_string("aia", p->aia); 4057aabcda0Sclaudio json_do_string("sia", p->sia); 4067aabcda0Sclaudio json_do_string("manifest_number", p->seqnum); 4071bb1e509Sjob if (p->signtime != 0) 4087aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4097aabcda0Sclaudio json_do_int("valid_since", p->thisupdate); 4107aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 411894936b4Sjob if (p->expires) 4127aabcda0Sclaudio json_do_int("expires", p->expires); 413530399e8Sjob } else { 414714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 415714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 416530399e8Sjob x509_print(x); 417714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4182cf0e122Sjob printf("Subject info access: %s\n", p->sia); 419489e308aSjob printf("Manifest number: %s\n", p->seqnum); 4201bb1e509Sjob if (p->signtime != 0) 4211bb1e509Sjob printf("Signing time: %s\n", 4221bb1e509Sjob time2str(p->signtime)); 4234dbb22b8Sjob printf("Manifest this update: %s\n", time2str(p->thisupdate)); 4244dbb22b8Sjob printf("Manifest next update: %s\n", time2str(p->nextupdate)); 4254486d057Sjob printf("Files and hashes: "); 426530399e8Sjob } 427530399e8Sjob 4287aabcda0Sclaudio if (outformats & FORMAT_JSON) 4297aabcda0Sclaudio json_do_array("filesandhashes"); 430714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 431714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 432714f4e3fSclaudio &hash) == -1) 433714f4e3fSclaudio errx(1, "base64_encode failure"); 434530399e8Sjob 435530399e8Sjob if (outformats & FORMAT_JSON) { 436a09a3191Sclaudio json_do_object("filehash", 1); 4377aabcda0Sclaudio json_do_string("filename", p->files[i].file); 4387aabcda0Sclaudio json_do_string("hash", hash); 4397aabcda0Sclaudio json_do_end(); 440530399e8Sjob } else { 4414486d057Sjob if (i > 0) 4424486d057Sjob printf("%26s", ""); 4434486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file, 4444486d057Sjob hash); 445530399e8Sjob } 446530399e8Sjob 447714f4e3fSclaudio free(hash); 448714f4e3fSclaudio } 449530399e8Sjob if (outformats & FORMAT_JSON) 4507aabcda0Sclaudio json_do_end(); 451714f4e3fSclaudio } 452714f4e3fSclaudio 453714f4e3fSclaudio void 454530399e8Sjob roa_print(const X509 *x, const struct roa *p) 455714f4e3fSclaudio { 456714f4e3fSclaudio char buf[128]; 457714f4e3fSclaudio size_t i; 458714f4e3fSclaudio 459530399e8Sjob if (outformats & FORMAT_JSON) { 4607aabcda0Sclaudio json_do_string("type", "roa"); 4617aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 462530399e8Sjob x509_print(x); 4637aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4647aabcda0Sclaudio json_do_string("aia", p->aia); 4657aabcda0Sclaudio json_do_string("sia", p->sia); 4661bb1e509Sjob if (p->signtime != 0) 4677aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4687aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 4697aabcda0Sclaudio json_do_int("valid_until", p->notafter); 4709c1f5d6bSjob if (p->expires) 4717aabcda0Sclaudio json_do_int("expires", p->expires); 472530399e8Sjob } else { 473714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 474530399e8Sjob x509_print(x); 475714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 476714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4772cf0e122Sjob printf("Subject info access: %s\n", p->sia); 4781bb1e509Sjob if (p->signtime != 0) 4791bb1e509Sjob printf("Signing time: %s\n", 4801bb1e509Sjob time2str(p->signtime)); 4814dbb22b8Sjob printf("ROA not before: %s\n", 482f5999ddfSjob time2str(p->notbefore)); 4834dbb22b8Sjob printf("ROA not after: %s\n", time2str(p->notafter)); 484714f4e3fSclaudio printf("asID: %u\n", p->asid); 4854486d057Sjob printf("IP address blocks: "); 486530399e8Sjob } 487530399e8Sjob 4887aabcda0Sclaudio if (outformats & FORMAT_JSON) 4897aabcda0Sclaudio json_do_array("vrps"); 490714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 491714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 492714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 493530399e8Sjob 494530399e8Sjob if (outformats & FORMAT_JSON) { 495a09a3191Sclaudio json_do_object("vrp", 1); 4967aabcda0Sclaudio json_do_string("prefix", buf); 4977aabcda0Sclaudio json_do_uint("asid", p->asid); 4987aabcda0Sclaudio json_do_uint("maxlen", p->ips[i].maxlength); 4997aabcda0Sclaudio json_do_end(); 5004486d057Sjob } else { 5014486d057Sjob if (i > 0) 5024486d057Sjob printf("%26s", ""); 5034486d057Sjob printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength); 5044486d057Sjob } 505714f4e3fSclaudio } 506530399e8Sjob if (outformats & FORMAT_JSON) 5077aabcda0Sclaudio json_do_end(); 508714f4e3fSclaudio } 509714f4e3fSclaudio 510714f4e3fSclaudio void 511d4be4cdeSjob spl_print(const X509 *x, const struct spl *s) 512d4be4cdeSjob { 513d4be4cdeSjob char buf[128]; 514d4be4cdeSjob size_t i; 515d4be4cdeSjob 516d4be4cdeSjob if (outformats & FORMAT_JSON) { 517d4be4cdeSjob json_do_string("type", "spl"); 518d4be4cdeSjob json_do_string("ski", pretty_key_id(s->ski)); 519d4be4cdeSjob x509_print(x); 520d4be4cdeSjob json_do_string("aki", pretty_key_id(s->aki)); 521d4be4cdeSjob json_do_string("aia", s->aia); 522d4be4cdeSjob json_do_string("sia", s->sia); 523d4be4cdeSjob if (s->signtime != 0) 524d4be4cdeSjob json_do_int("signing_time", s->signtime); 525d4be4cdeSjob json_do_int("valid_since", s->notbefore); 526d4be4cdeSjob json_do_int("valid_until", s->notafter); 527d4be4cdeSjob if (s->expires) 528d4be4cdeSjob json_do_int("expires", s->expires); 529d4be4cdeSjob json_do_int("asid", s->asid); 530d4be4cdeSjob } else { 531d4be4cdeSjob printf("Subject key identifier: %s\n", pretty_key_id(s->ski)); 532d4be4cdeSjob x509_print(x); 533d4be4cdeSjob printf("Authority key identifier: %s\n", pretty_key_id(s->aki)); 534d4be4cdeSjob printf("Authority info access: %s\n", s->aia); 535d4be4cdeSjob printf("Subject info access: %s\n", s->sia); 536d4be4cdeSjob if (s->signtime != 0) 537d4be4cdeSjob printf("Signing time: %s\n", 538d4be4cdeSjob time2str(s->signtime)); 539d4be4cdeSjob printf("SPL not before: %s\n", 540d4be4cdeSjob time2str(s->notbefore)); 541d4be4cdeSjob printf("SPL not after: %s\n", time2str(s->notafter)); 542d4be4cdeSjob printf("asID: %u\n", s->asid); 543d4be4cdeSjob printf("Originated IP Prefixes: "); 544d4be4cdeSjob } 545d4be4cdeSjob 546d4be4cdeSjob if (outformats & FORMAT_JSON) 547d4be4cdeSjob json_do_array("prefixes"); 548d4be4cdeSjob for (i = 0; i < s->pfxsz; i++) { 549d4be4cdeSjob ip_addr_print(&s->pfxs[i].prefix, s->pfxs[i].afi, buf, 550d4be4cdeSjob sizeof(buf)); 551d4be4cdeSjob 552d4be4cdeSjob if (outformats & FORMAT_JSON) { 553d4be4cdeSjob json_do_string("prefix", buf); 554d4be4cdeSjob } else { 555d4be4cdeSjob if (i > 0) 556d4be4cdeSjob printf("%26s", ""); 557d4be4cdeSjob printf("%s\n", buf); 558d4be4cdeSjob } 559d4be4cdeSjob } 560d4be4cdeSjob if (outformats & FORMAT_JSON) 561d4be4cdeSjob json_do_end(); 562d4be4cdeSjob } 563d4be4cdeSjob 564d4be4cdeSjob void 565530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 566714f4e3fSclaudio { 567530399e8Sjob if (outformats & FORMAT_JSON) { 5687aabcda0Sclaudio json_do_string("type", "gbr"); 5697aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 570530399e8Sjob x509_print(x); 5717aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 5727aabcda0Sclaudio json_do_string("aia", p->aia); 5737aabcda0Sclaudio json_do_string("sia", p->sia); 5741bb1e509Sjob if (p->signtime != 0) 5757aabcda0Sclaudio json_do_int("signing_time", p->signtime); 5767aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 5777aabcda0Sclaudio json_do_int("valid_until", p->notafter); 578894936b4Sjob if (p->expires) 5797aabcda0Sclaudio json_do_int("expires", p->expires); 5807aabcda0Sclaudio json_do_string("vcard", p->vcard); 581530399e8Sjob } else { 582714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 583530399e8Sjob x509_print(x); 584714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 585714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 5862cf0e122Sjob printf("Subject info access: %s\n", p->sia); 5871bb1e509Sjob if (p->signtime != 0) 5881bb1e509Sjob printf("Signing time: %s\n", 5891bb1e509Sjob time2str(p->signtime)); 5904dbb22b8Sjob printf("GBR not before: %s\n", 591f5999ddfSjob time2str(p->notbefore)); 5924dbb22b8Sjob printf("GBR not after: %s\n", time2str(p->notafter)); 593714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 594714f4e3fSclaudio } 595530399e8Sjob } 59604834fbdSjob 59704834fbdSjob void 59804834fbdSjob rsc_print(const X509 *x, const struct rsc *p) 59904834fbdSjob { 60004834fbdSjob char *hash; 6017aabcda0Sclaudio size_t i; 60204834fbdSjob 60304834fbdSjob if (outformats & FORMAT_JSON) { 6047aabcda0Sclaudio json_do_string("type", "rsc"); 6057aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 60604834fbdSjob x509_print(x); 6077aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 6087aabcda0Sclaudio json_do_string("aia", p->aia); 6091bb1e509Sjob if (p->signtime != 0) 6107aabcda0Sclaudio json_do_int("signing_time", p->signtime); 6117aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 6127aabcda0Sclaudio json_do_int("valid_until", p->notafter); 613894936b4Sjob if (p->expires) 6147aabcda0Sclaudio json_do_int("expires", p->expires); 6157aabcda0Sclaudio json_do_array("signed_with_resources"); 61604834fbdSjob } else { 61704834fbdSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 61804834fbdSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 61904834fbdSjob x509_print(x); 62004834fbdSjob printf("Authority info access: %s\n", p->aia); 6211bb1e509Sjob if (p->signtime != 0) 6221bb1e509Sjob printf("Signing time: %s\n", 6231bb1e509Sjob time2str(p->signtime)); 6244dbb22b8Sjob printf("RSC not before: %s\n", 625f5999ddfSjob time2str(p->notbefore)); 6264dbb22b8Sjob printf("RSC not after: %s\n", time2str(p->notafter)); 6274486d057Sjob printf("Signed with resources: "); 62804834fbdSjob } 62904834fbdSjob 6307aabcda0Sclaudio as_resources_print(p->as, p->asz); 6317aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 63204834fbdSjob 63304834fbdSjob if (outformats & FORMAT_JSON) { 6347aabcda0Sclaudio json_do_end(); 6357aabcda0Sclaudio json_do_array("filenamesandhashes"); 63604834fbdSjob } else 6374486d057Sjob printf("Filenames and hashes: "); 63804834fbdSjob 63904834fbdSjob for (i = 0; i < p->filesz; i++) { 64004834fbdSjob if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 64104834fbdSjob &hash) == -1) 64204834fbdSjob errx(1, "base64_encode failure"); 64304834fbdSjob 64404834fbdSjob if (outformats & FORMAT_JSON) { 645a09a3191Sclaudio json_do_object("filehash", 1); 6467aabcda0Sclaudio if (p->files[i].filename) 6477aabcda0Sclaudio json_do_string("filename", 6487aabcda0Sclaudio p->files[i].filename); 6497aabcda0Sclaudio json_do_string("hash_digest", hash); 6507aabcda0Sclaudio json_do_end(); 65104834fbdSjob } else { 6524486d057Sjob if (i > 0) 6534486d057Sjob printf("%26s", ""); 6544486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, 6554486d057Sjob p->files[i].filename ? p->files[i].filename 6564486d057Sjob : "no filename", hash); 65704834fbdSjob } 65804834fbdSjob 65904834fbdSjob free(hash); 66004834fbdSjob } 66104834fbdSjob 66204834fbdSjob if (outformats & FORMAT_JSON) 6637aabcda0Sclaudio json_do_end(); 66404834fbdSjob } 665a29ddfd5Sjob 666a29ddfd5Sjob void 667a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p) 668a29ddfd5Sjob { 6694b5fc138Sjob size_t i; 6704b5fc138Sjob 671a29ddfd5Sjob if (outformats & FORMAT_JSON) { 6727aabcda0Sclaudio json_do_string("type", "aspa"); 6737aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 674a29ddfd5Sjob x509_print(x); 6757aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 6767aabcda0Sclaudio json_do_string("aia", p->aia); 6777aabcda0Sclaudio json_do_string("sia", p->sia); 6781bb1e509Sjob if (p->signtime != 0) 6797aabcda0Sclaudio json_do_int("signing_time", p->signtime); 6807aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 6817aabcda0Sclaudio json_do_int("valid_until", p->notafter); 6829c1f5d6bSjob if (p->expires) 6837aabcda0Sclaudio json_do_int("expires", p->expires); 6847aabcda0Sclaudio json_do_uint("customer_asid", p->custasid); 6854a0be80eSjob json_do_array("providers"); 686a29ddfd5Sjob } else { 687a29ddfd5Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 688a29ddfd5Sjob x509_print(x); 689a29ddfd5Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 690a29ddfd5Sjob printf("Authority info access: %s\n", p->aia); 6912cf0e122Sjob printf("Subject info access: %s\n", p->sia); 6921bb1e509Sjob if (p->signtime != 0) 6931bb1e509Sjob printf("Signing time: %s\n", 6941bb1e509Sjob time2str(p->signtime)); 6954dbb22b8Sjob printf("ASPA not before: %s\n", 696f5999ddfSjob time2str(p->notbefore)); 6974dbb22b8Sjob printf("ASPA not after: %s\n", time2str(p->notafter)); 698ba54bc08Sjob printf("Customer ASID: %u\n", p->custasid); 6994a0be80eSjob printf("Providers: "); 700a29ddfd5Sjob } 7017aabcda0Sclaudio 7024b5fc138Sjob for (i = 0; i < p->providersz; i++) { 703b179db0eSjob if (outformats & FORMAT_JSON) 704b179db0eSjob json_do_uint("asid", p->providers[i]); 705b179db0eSjob else { 706b179db0eSjob if (i > 0) 7074b5fc138Sjob printf("%26s", ""); 708b179db0eSjob printf("AS: %u\n", p->providers[i]); 709b179db0eSjob } 7104b5fc138Sjob } 7117aabcda0Sclaudio 7127aabcda0Sclaudio if (outformats & FORMAT_JSON) 7137aabcda0Sclaudio json_do_end(); 714a29ddfd5Sjob } 715ee2a33daSjob 716ee2a33daSjob static void 717ee2a33daSjob takey_print(char *name, const struct takey *t) 718ee2a33daSjob { 719ee2a33daSjob char *spki = NULL; 720ee2a33daSjob size_t i, j = 0; 721ee2a33daSjob 722ee2a33daSjob if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0) 723ee2a33daSjob errx(1, "base64_encode failed in %s", __func__); 724ee2a33daSjob 725ee2a33daSjob if (outformats & FORMAT_JSON) { 726a09a3191Sclaudio json_do_object("takey", 0); 7277aabcda0Sclaudio json_do_string("name", name); 7287aabcda0Sclaudio json_do_array("comments"); 7297aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 7307aabcda0Sclaudio json_do_string("comment", t->comments[i]); 7317aabcda0Sclaudio json_do_end(); 7327aabcda0Sclaudio json_do_array("uris"); 7337aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 7347aabcda0Sclaudio json_do_string("uri", t->uris[i]); 7357aabcda0Sclaudio json_do_end(); 7367aabcda0Sclaudio json_do_string("spki", spki); 737*17f7a478Sjob json_do_end(); 738ee2a33daSjob } else { 739ee2a33daSjob printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name); 740ee2a33daSjob 7417aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 742ee2a33daSjob printf("\t# %s\n", t->comments[i]); 743eb3e3a76Sjob if (t->commentsz > 0) 7447aabcda0Sclaudio printf("\n"); 7457aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 746eb3e3a76Sjob printf("\t%s\n", t->uris[i]); 747eb3e3a76Sjob printf("\n\t"); 748ee2a33daSjob for (i = 0; i < strlen(spki); i++) { 749ee2a33daSjob printf("%c", spki[i]); 7507aabcda0Sclaudio if ((++j % 64) == 0) 751ee2a33daSjob printf("\n\t"); 752ee2a33daSjob } 753ee2a33daSjob printf("\n\n"); 754ee2a33daSjob } 755ee2a33daSjob 756ee2a33daSjob free(spki); 757ee2a33daSjob } 758ee2a33daSjob 759ee2a33daSjob void 760ee2a33daSjob tak_print(const X509 *x, const struct tak *p) 761ee2a33daSjob { 762ee2a33daSjob if (outformats & FORMAT_JSON) { 7637aabcda0Sclaudio json_do_string("type", "tak"); 7647aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 765ee2a33daSjob x509_print(x); 7667aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 7677aabcda0Sclaudio json_do_string("aia", p->aia); 7687aabcda0Sclaudio json_do_string("sia", p->sia); 7691bb1e509Sjob if (p->signtime != 0) 7707aabcda0Sclaudio json_do_int("signing_time", p->signtime); 7717aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 7727aabcda0Sclaudio json_do_int("valid_until", p->notafter); 773894936b4Sjob if (p->expires) 7747aabcda0Sclaudio json_do_int("expires", p->expires); 7757aabcda0Sclaudio json_do_array("takeys"); 776ee2a33daSjob } else { 777ee2a33daSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 778ee2a33daSjob x509_print(x); 779ee2a33daSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 780ee2a33daSjob printf("Authority info access: %s\n", p->aia); 7812cf0e122Sjob printf("Subject info access: %s\n", p->sia); 7821bb1e509Sjob if (p->signtime != 0) 7831bb1e509Sjob printf("Signing time: %s\n", 7841bb1e509Sjob time2str(p->signtime)); 7854dbb22b8Sjob printf("TAK not before: %s\n", 786f5999ddfSjob time2str(p->notbefore)); 7874dbb22b8Sjob printf("TAK not after: %s\n", time2str(p->notafter)); 788ee2a33daSjob } 789ee2a33daSjob 790ee2a33daSjob takey_print("current", p->current); 7917aabcda0Sclaudio if (p->predecessor != NULL) 792ee2a33daSjob takey_print("predecessor", p->predecessor); 7937aabcda0Sclaudio if (p->successor != NULL) 794ee2a33daSjob takey_print("successor", p->successor); 795ee2a33daSjob 796ee2a33daSjob if (outformats & FORMAT_JSON) 7977aabcda0Sclaudio json_do_end(); 798ee2a33daSjob } 799ef3f6f56Sjob 800ef3f6f56Sjob void 801ef3f6f56Sjob geofeed_print(const X509 *x, const struct geofeed *p) 802ef3f6f56Sjob { 803ef3f6f56Sjob char buf[128]; 804ef3f6f56Sjob size_t i; 805ef3f6f56Sjob 806ef3f6f56Sjob if (outformats & FORMAT_JSON) { 8077aabcda0Sclaudio json_do_string("type", "geofeed"); 8087aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 809ef3f6f56Sjob x509_print(x); 8107aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 8117aabcda0Sclaudio json_do_string("aia", p->aia); 8121bb1e509Sjob if (p->signtime != 0) 8137aabcda0Sclaudio json_do_int("signing_time", p->signtime); 8147aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 8157aabcda0Sclaudio json_do_int("valid_until", p->notafter); 8167aabcda0Sclaudio if (p->expires) 8177aabcda0Sclaudio json_do_int("expires", p->expires); 8187aabcda0Sclaudio json_do_array("records"); 819ef3f6f56Sjob } else { 820ef3f6f56Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 821ef3f6f56Sjob x509_print(x); 822ef3f6f56Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 823ef3f6f56Sjob printf("Authority info access: %s\n", p->aia); 8241bb1e509Sjob if (p->signtime != 0) 8251bb1e509Sjob printf("Signing time: %s\n", 8261bb1e509Sjob time2str(p->signtime)); 8274dbb22b8Sjob printf("Geofeed not before: %s\n", 828f5999ddfSjob time2str(p->notbefore)); 8294dbb22b8Sjob printf("Geofeed not after: %s\n", time2str(p->notafter)); 830bd19f13dSjob printf("Geofeed CSV records: "); 831ef3f6f56Sjob } 832ef3f6f56Sjob 833ef3f6f56Sjob for (i = 0; i < p->geoipsz; i++) { 834ef3f6f56Sjob if (p->geoips[i].ip->type != CERT_IP_ADDR) 835ef3f6f56Sjob continue; 836ef3f6f56Sjob 837ef3f6f56Sjob ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf, 838ef3f6f56Sjob sizeof(buf)); 8397aabcda0Sclaudio if (outformats & FORMAT_JSON) { 840a09a3191Sclaudio json_do_object("geoip", 1); 8417aabcda0Sclaudio json_do_string("prefix", buf); 8427aabcda0Sclaudio json_do_string("location", p->geoips[i].loc); 8437aabcda0Sclaudio json_do_end(); 8447aabcda0Sclaudio } else { 8454486d057Sjob if (i > 0) 8464486d057Sjob printf("%26s", ""); 8477aabcda0Sclaudio printf("IP: %s (%s)\n", buf, p->geoips[i].loc); 8484486d057Sjob } 849ef3f6f56Sjob } 850ef3f6f56Sjob 851ef3f6f56Sjob if (outformats & FORMAT_JSON) 8527aabcda0Sclaudio json_do_end(); 853ef3f6f56Sjob } 854