1*0a722356Stb /* $OpenBSD: print.c,v 1.44 2023/11/16 11:18:47 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 * 53220c707cSclaudio time2str(time_t t) 54220c707cSclaudio { 55220c707cSclaudio static char buf[64]; 56220c707cSclaudio struct tm tm; 57220c707cSclaudio 58220c707cSclaudio if (gmtime_r(&t, &tm) == NULL) 59220c707cSclaudio return "could not convert time"; 60220c707cSclaudio 61cc6f004eSjob strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm); 62cc6f004eSjob 63220c707cSclaudio return buf; 64220c707cSclaudio } 65220c707cSclaudio 66714f4e3fSclaudio void 67714f4e3fSclaudio tal_print(const struct tal *p) 68714f4e3fSclaudio { 69e911df76Sjob char *ski; 70e911df76Sjob EVP_PKEY *pk; 71e911df76Sjob RSA *r; 72e911df76Sjob const unsigned char *der; 73e911df76Sjob unsigned char *rder = NULL; 74e911df76Sjob unsigned char md[SHA_DIGEST_LENGTH]; 75e911df76Sjob int rder_len; 76714f4e3fSclaudio size_t i; 77714f4e3fSclaudio 78e911df76Sjob der = p->pkey; 79e911df76Sjob pk = d2i_PUBKEY(NULL, &der, p->pkeysz); 80e911df76Sjob if (pk == NULL) 81e911df76Sjob errx(1, "d2i_PUBKEY failed in %s", __func__); 82e911df76Sjob 83e911df76Sjob r = EVP_PKEY_get0_RSA(pk); 84e911df76Sjob if (r == NULL) 85e911df76Sjob errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__); 86e911df76Sjob if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0) 87e911df76Sjob errx(1, "i2d_RSAPublicKey failed in %s", __func__); 88e911df76Sjob 89e911df76Sjob if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL)) 90e911df76Sjob errx(1, "EVP_Digest failed in %s", __func__); 91e911df76Sjob 92e911df76Sjob ski = hex_encode(md, SHA_DIGEST_LENGTH); 93e911df76Sjob 94530399e8Sjob if (outformats & FORMAT_JSON) { 957aabcda0Sclaudio json_do_string("type", "tal"); 967aabcda0Sclaudio json_do_string("name", p->descr); 977aabcda0Sclaudio json_do_string("ski", pretty_key_id(ski)); 987aabcda0Sclaudio json_do_array("trust_anchor_locations"); 997aabcda0Sclaudio for (i = 0; i < p->urisz; i++) 1007aabcda0Sclaudio json_do_string("tal", p->uri[i]); 1017aabcda0Sclaudio json_do_end(); 102530399e8Sjob } else { 103530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 104530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 1054486d057Sjob printf("Trust anchor locations: "); 1064486d057Sjob for (i = 0; i < p->urisz; i++) { 1074486d057Sjob if (i > 0) 1084486d057Sjob printf("%26s", ""); 1094486d057Sjob printf("%s\n", p->uri[i]); 1104486d057Sjob } 111530399e8Sjob } 112e911df76Sjob 113e911df76Sjob EVP_PKEY_free(pk); 114e911df76Sjob free(rder); 115e911df76Sjob free(ski); 116714f4e3fSclaudio } 117714f4e3fSclaudio 118714f4e3fSclaudio void 119530399e8Sjob x509_print(const X509 *x) 120530399e8Sjob { 121530399e8Sjob const ASN1_INTEGER *xserial; 122e0b87278Sjob const X509_NAME *xissuer; 123e0b87278Sjob char *issuer = NULL; 124530399e8Sjob char *serial = NULL; 125530399e8Sjob 126e0b87278Sjob if ((xissuer = X509_get_issuer_name(x)) == NULL) { 127e0b87278Sjob warnx("X509_get_issuer_name failed"); 128530399e8Sjob goto out; 129530399e8Sjob } 130530399e8Sjob 131e0b87278Sjob if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) { 132e0b87278Sjob warnx("X509_NAME_oneline failed"); 133530399e8Sjob goto out; 134530399e8Sjob } 135530399e8Sjob 136e0b87278Sjob if ((xserial = X509_get0_serialNumber(x)) == NULL) { 137e0b87278Sjob warnx("X509_get0_serialNumber failed"); 138e0b87278Sjob goto out; 139e0b87278Sjob } 140e0b87278Sjob 141e0b87278Sjob if ((serial = x509_convert_seqnum(__func__, xserial)) == NULL) 142e0b87278Sjob goto out; 143e0b87278Sjob 144530399e8Sjob if (outformats & FORMAT_JSON) { 1457aabcda0Sclaudio json_do_string("cert_issuer", issuer); 1467aabcda0Sclaudio json_do_string("cert_serial", serial); 147530399e8Sjob } else { 148e0b87278Sjob printf("Certificate issuer: %s\n", issuer); 149530399e8Sjob printf("Certificate serial: %s\n", serial); 150530399e8Sjob } 151530399e8Sjob 152530399e8Sjob out: 153e0b87278Sjob free(issuer); 154530399e8Sjob free(serial); 155530399e8Sjob } 156530399e8Sjob 1577aabcda0Sclaudio static void 1587aabcda0Sclaudio as_resources_print(struct cert_as *as, size_t asz) 1597aabcda0Sclaudio { 1607aabcda0Sclaudio size_t i; 1617aabcda0Sclaudio 1627aabcda0Sclaudio for (i = 0; i < asz; i++) { 1637aabcda0Sclaudio if (outformats & FORMAT_JSON) 164a09a3191Sclaudio json_do_object("resource", 1); 1657aabcda0Sclaudio switch (as[i].type) { 1667aabcda0Sclaudio case CERT_AS_ID: 1677aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1687aabcda0Sclaudio json_do_uint("asid", as[i].id); 1697aabcda0Sclaudio } else { 1707aabcda0Sclaudio if (i > 0) 1717aabcda0Sclaudio printf("%26s", ""); 1727aabcda0Sclaudio printf("AS: %u", as[i].id); 1737aabcda0Sclaudio } 1747aabcda0Sclaudio break; 1757aabcda0Sclaudio case CERT_AS_INHERIT: 1767aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1777aabcda0Sclaudio json_do_bool("asid_inherit", 1); 1787aabcda0Sclaudio } else { 1797aabcda0Sclaudio if (i > 0) 1807aabcda0Sclaudio printf("%26s", ""); 1817aabcda0Sclaudio printf("AS: inherit"); 1827aabcda0Sclaudio } 1837aabcda0Sclaudio break; 1847aabcda0Sclaudio case CERT_AS_RANGE: 1857aabcda0Sclaudio if (outformats & FORMAT_JSON) { 186a09a3191Sclaudio json_do_object("asrange", 1); 1877aabcda0Sclaudio json_do_uint("min", as[i].range.min); 1887aabcda0Sclaudio json_do_uint("max", as[i].range.max); 1897aabcda0Sclaudio json_do_end(); 1907aabcda0Sclaudio } else { 1917aabcda0Sclaudio if (i > 0) 1927aabcda0Sclaudio printf("%26s", ""); 1937aabcda0Sclaudio printf("AS: %u -- %u", as[i].range.min, 1947aabcda0Sclaudio as[i].range.max); 1957aabcda0Sclaudio } 1967aabcda0Sclaudio break; 1977aabcda0Sclaudio } 1987aabcda0Sclaudio if (outformats & FORMAT_JSON) 1997aabcda0Sclaudio json_do_end(); 2007aabcda0Sclaudio else 2017aabcda0Sclaudio printf("\n"); 2027aabcda0Sclaudio } 2037aabcda0Sclaudio } 2047aabcda0Sclaudio 2057aabcda0Sclaudio static void 2067aabcda0Sclaudio ip_resources_print(struct cert_ip *ips, size_t ipsz, size_t asz) 2077aabcda0Sclaudio { 2087aabcda0Sclaudio char buf1[64], buf2[64]; 2097aabcda0Sclaudio size_t i; 2107aabcda0Sclaudio int sockt; 2117aabcda0Sclaudio 2127aabcda0Sclaudio 2137aabcda0Sclaudio for (i = 0; i < ipsz; i++) { 2147aabcda0Sclaudio if (outformats & FORMAT_JSON) 215a09a3191Sclaudio json_do_object("resource", 1); 2167aabcda0Sclaudio switch (ips[i].type) { 2177aabcda0Sclaudio case CERT_IP_INHERIT: 2187aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2197aabcda0Sclaudio json_do_bool("ip_inherit", 1); 2207aabcda0Sclaudio } else { 2217aabcda0Sclaudio if (i > 0 || asz > 0) 2227aabcda0Sclaudio printf("%26s", ""); 2237aabcda0Sclaudio printf("IP: inherit"); 2247aabcda0Sclaudio } 2257aabcda0Sclaudio break; 2267aabcda0Sclaudio case CERT_IP_ADDR: 2277aabcda0Sclaudio ip_addr_print(&ips[i].ip, ips[i].afi, buf1, 2287aabcda0Sclaudio sizeof(buf1)); 2297aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2307aabcda0Sclaudio json_do_string("ip_prefix", buf1); 2317aabcda0Sclaudio } else { 2327aabcda0Sclaudio if (i > 0 || asz > 0) 2337aabcda0Sclaudio printf("%26s", ""); 2347aabcda0Sclaudio printf("IP: %s", buf1); 2357aabcda0Sclaudio } 2367aabcda0Sclaudio break; 2377aabcda0Sclaudio case CERT_IP_RANGE: 2387aabcda0Sclaudio sockt = (ips[i].afi == AFI_IPV4) ? 2397aabcda0Sclaudio AF_INET : AF_INET6; 2407aabcda0Sclaudio inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1)); 2417aabcda0Sclaudio inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2)); 2427aabcda0Sclaudio if (outformats & FORMAT_JSON) { 243a09a3191Sclaudio json_do_object("ip_range", 1); 2447aabcda0Sclaudio json_do_string("min", buf1); 2457aabcda0Sclaudio json_do_string("max", buf2); 2467aabcda0Sclaudio json_do_end(); 2477aabcda0Sclaudio } else { 2487aabcda0Sclaudio if (i > 0 || asz > 0) 2497aabcda0Sclaudio printf("%26s", ""); 2507aabcda0Sclaudio printf("IP: %s -- %s", buf1, buf2); 2517aabcda0Sclaudio } 2527aabcda0Sclaudio break; 2537aabcda0Sclaudio } 2547aabcda0Sclaudio if (outformats & FORMAT_JSON) 2557aabcda0Sclaudio json_do_end(); 2567aabcda0Sclaudio else 2577aabcda0Sclaudio printf("\n"); 2587aabcda0Sclaudio } 2597aabcda0Sclaudio } 2607aabcda0Sclaudio 261530399e8Sjob void 262714f4e3fSclaudio cert_print(const struct cert *p) 263714f4e3fSclaudio { 264530399e8Sjob if (outformats & FORMAT_JSON) { 265530399e8Sjob if (p->pubkey != NULL) 2667aabcda0Sclaudio json_do_string("type", "router_key"); 267530399e8Sjob else 2687aabcda0Sclaudio json_do_string("type", "ca_cert"); 2697aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 270530399e8Sjob if (p->aki != NULL) 2717aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 272530399e8Sjob x509_print(p->x509); 273530399e8Sjob if (p->aia != NULL) 2747aabcda0Sclaudio json_do_string("aia", p->aia); 275530399e8Sjob if (p->mft != NULL) 2767aabcda0Sclaudio json_do_string("manifest", p->mft); 277530399e8Sjob if (p->repo != NULL) 2787aabcda0Sclaudio json_do_string("carepository", p->repo); 279530399e8Sjob if (p->notify != NULL) 2807aabcda0Sclaudio json_do_string("notify_url", p->notify); 281530399e8Sjob if (p->pubkey != NULL) 2827aabcda0Sclaudio json_do_string("router_key", p->pubkey); 2837aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 2847aabcda0Sclaudio json_do_int("valid_until", p->notafter); 285894936b4Sjob if (p->expires) 2867aabcda0Sclaudio json_do_int("expires", p->expires); 2877aabcda0Sclaudio json_do_array("subordinate_resources"); 288530399e8Sjob } else { 289714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 290714f4e3fSclaudio if (p->aki != NULL) 29167642cb5Stb printf("Authority key identifier: %s\n", 29267642cb5Stb pretty_key_id(p->aki)); 293530399e8Sjob x509_print(p->x509); 294714f4e3fSclaudio if (p->aia != NULL) 295714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 296714f4e3fSclaudio if (p->mft != NULL) 297714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 298714f4e3fSclaudio if (p->repo != NULL) 299714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 300714f4e3fSclaudio if (p->notify != NULL) 301714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 30214d83341Sjob if (p->pubkey != NULL) { 3036530cf17Sjob printf("BGPsec ECDSA public key: %s\n", 30467642cb5Stb p->pubkey); 3054dbb22b8Sjob printf("Router key not before: %s\n", 306f5999ddfSjob time2str(p->notbefore)); 3074dbb22b8Sjob printf("Router key not after: %s\n", 3089f544822Sjob time2str(p->notafter)); 309f5999ddfSjob } else { 3104dbb22b8Sjob printf("Certificate not before: %s\n", 311f5999ddfSjob time2str(p->notbefore)); 3124dbb22b8Sjob printf("Certificate not after: %s\n", 3139f544822Sjob time2str(p->notafter)); 314f5999ddfSjob } 3154486d057Sjob printf("Subordinate resources: "); 316530399e8Sjob } 317714f4e3fSclaudio 3187aabcda0Sclaudio as_resources_print(p->as, p->asz); 3197aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 320530399e8Sjob 321530399e8Sjob if (outformats & FORMAT_JSON) 3227aabcda0Sclaudio json_do_end(); 323714f4e3fSclaudio } 324714f4e3fSclaudio 325714f4e3fSclaudio void 326220c707cSclaudio crl_print(const struct crl *p) 327220c707cSclaudio { 328220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 329220c707cSclaudio X509_REVOKED *rev; 330e0b87278Sjob X509_NAME *xissuer; 331220c707cSclaudio int i; 332e0b87278Sjob char *issuer, *serial; 333220c707cSclaudio time_t t; 334220c707cSclaudio 335530399e8Sjob if (outformats & FORMAT_JSON) { 3367aabcda0Sclaudio json_do_string("type", "crl"); 3377aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 338530399e8Sjob } else 339220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 3407cdd491fSclaudio 341e0b87278Sjob xissuer = X509_CRL_get_issuer(p->x509_crl); 342e0b87278Sjob issuer = X509_NAME_oneline(xissuer, NULL, 0); 343*0a722356Stb if (issuer != NULL && p->number != NULL) { 344e0b87278Sjob if (outformats & FORMAT_JSON) { 3457aabcda0Sclaudio json_do_string("crl_issuer", issuer); 346*0a722356Stb json_do_string("crl_serial", p->number); 347e0b87278Sjob } else { 348e0b87278Sjob printf("CRL issuer: %s\n", issuer); 349*0a722356Stb printf("CRL serial number: %s\n", p->number); 350530399e8Sjob } 351e0b87278Sjob } 352e0b87278Sjob free(issuer); 3537cdd491fSclaudio 354530399e8Sjob if (outformats & FORMAT_JSON) { 3557aabcda0Sclaudio json_do_int("valid_since", p->lastupdate); 3567aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 3577aabcda0Sclaudio json_do_array("revoked_certs"); 358530399e8Sjob } else { 3594dbb22b8Sjob printf("CRL last update: %s\n", 3609f544822Sjob time2str(p->lastupdate)); 3614dbb22b8Sjob printf("CRL next update: %s\n", 3629f544822Sjob time2str(p->nextupdate)); 363530399e8Sjob printf("Revoked Certificates:\n"); 364530399e8Sjob } 365220c707cSclaudio 366220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 367220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 368220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3697cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3707cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 371220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 372530399e8Sjob if (serial != NULL) { 373530399e8Sjob if (outformats & FORMAT_JSON) { 374a09a3191Sclaudio json_do_object("cert", 1); 3757aabcda0Sclaudio json_do_string("serial", serial); 3767aabcda0Sclaudio json_do_string("date", time2str(t)); 3777aabcda0Sclaudio json_do_end(); 378530399e8Sjob } else 3794486d057Sjob printf("%25s Serial: %8s Revocation Date: %s" 3804486d057Sjob "\n", "", serial, time2str(t)); 381530399e8Sjob } 3827cdd491fSclaudio free(serial); 383220c707cSclaudio } 384530399e8Sjob 385530399e8Sjob if (outformats & FORMAT_JSON) 3867aabcda0Sclaudio json_do_end(); 387530399e8Sjob else if (i == 0) 388220c707cSclaudio printf("No Revoked Certificates\n"); 389220c707cSclaudio } 390220c707cSclaudio 391220c707cSclaudio void 392530399e8Sjob mft_print(const X509 *x, const struct mft *p) 393714f4e3fSclaudio { 394714f4e3fSclaudio size_t i; 395714f4e3fSclaudio char *hash; 396714f4e3fSclaudio 397530399e8Sjob if (outformats & FORMAT_JSON) { 3987aabcda0Sclaudio json_do_string("type", "manifest"); 3997aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 400530399e8Sjob x509_print(x); 4017aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4027aabcda0Sclaudio json_do_string("aia", p->aia); 4037aabcda0Sclaudio json_do_string("sia", p->sia); 4047aabcda0Sclaudio json_do_string("manifest_number", p->seqnum); 4051bb1e509Sjob if (p->signtime != 0) 4067aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4077aabcda0Sclaudio json_do_int("valid_since", p->thisupdate); 4087aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 409894936b4Sjob if (p->expires) 4107aabcda0Sclaudio json_do_int("expires", p->expires); 411530399e8Sjob } else { 412714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 413714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 414530399e8Sjob x509_print(x); 415714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4162cf0e122Sjob printf("Subject info access: %s\n", p->sia); 417489e308aSjob printf("Manifest number: %s\n", p->seqnum); 4181bb1e509Sjob if (p->signtime != 0) 4191bb1e509Sjob printf("Signing time: %s\n", 4201bb1e509Sjob time2str(p->signtime)); 4214dbb22b8Sjob printf("Manifest this update: %s\n", time2str(p->thisupdate)); 4224dbb22b8Sjob printf("Manifest next update: %s\n", time2str(p->nextupdate)); 4234486d057Sjob printf("Files and hashes: "); 424530399e8Sjob } 425530399e8Sjob 4267aabcda0Sclaudio if (outformats & FORMAT_JSON) 4277aabcda0Sclaudio json_do_array("filesandhashes"); 428714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 429714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 430714f4e3fSclaudio &hash) == -1) 431714f4e3fSclaudio errx(1, "base64_encode failure"); 432530399e8Sjob 433530399e8Sjob if (outformats & FORMAT_JSON) { 434a09a3191Sclaudio json_do_object("filehash", 1); 4357aabcda0Sclaudio json_do_string("filename", p->files[i].file); 4367aabcda0Sclaudio json_do_string("hash", hash); 4377aabcda0Sclaudio json_do_end(); 438530399e8Sjob } else { 4394486d057Sjob if (i > 0) 4404486d057Sjob printf("%26s", ""); 4414486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file, 4424486d057Sjob hash); 443530399e8Sjob } 444530399e8Sjob 445714f4e3fSclaudio free(hash); 446714f4e3fSclaudio } 447530399e8Sjob if (outformats & FORMAT_JSON) 4487aabcda0Sclaudio json_do_end(); 449714f4e3fSclaudio } 450714f4e3fSclaudio 451714f4e3fSclaudio void 452530399e8Sjob roa_print(const X509 *x, const struct roa *p) 453714f4e3fSclaudio { 454714f4e3fSclaudio char buf[128]; 455714f4e3fSclaudio size_t i; 456714f4e3fSclaudio 457530399e8Sjob if (outformats & FORMAT_JSON) { 4587aabcda0Sclaudio json_do_string("type", "roa"); 4597aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 460530399e8Sjob x509_print(x); 4617aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4627aabcda0Sclaudio json_do_string("aia", p->aia); 4637aabcda0Sclaudio json_do_string("sia", p->sia); 4641bb1e509Sjob if (p->signtime != 0) 4657aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4667aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 4677aabcda0Sclaudio json_do_int("valid_until", p->notafter); 4689c1f5d6bSjob if (p->expires) 4697aabcda0Sclaudio json_do_int("expires", p->expires); 470530399e8Sjob } else { 471714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 472530399e8Sjob x509_print(x); 473714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 474714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4752cf0e122Sjob printf("Subject info access: %s\n", p->sia); 4761bb1e509Sjob if (p->signtime != 0) 4771bb1e509Sjob printf("Signing time: %s\n", 4781bb1e509Sjob time2str(p->signtime)); 4794dbb22b8Sjob printf("ROA not before: %s\n", 480f5999ddfSjob time2str(p->notbefore)); 4814dbb22b8Sjob printf("ROA not after: %s\n", time2str(p->notafter)); 482714f4e3fSclaudio printf("asID: %u\n", p->asid); 4834486d057Sjob printf("IP address blocks: "); 484530399e8Sjob } 485530399e8Sjob 4867aabcda0Sclaudio if (outformats & FORMAT_JSON) 4877aabcda0Sclaudio json_do_array("vrps"); 488714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 489714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 490714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 491530399e8Sjob 492530399e8Sjob if (outformats & FORMAT_JSON) { 493a09a3191Sclaudio json_do_object("vrp", 1); 4947aabcda0Sclaudio json_do_string("prefix", buf); 4957aabcda0Sclaudio json_do_uint("asid", p->asid); 4967aabcda0Sclaudio json_do_uint("maxlen", p->ips[i].maxlength); 4977aabcda0Sclaudio json_do_end(); 4984486d057Sjob } else { 4994486d057Sjob if (i > 0) 5004486d057Sjob printf("%26s", ""); 5014486d057Sjob printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength); 5024486d057Sjob } 503714f4e3fSclaudio } 504530399e8Sjob if (outformats & FORMAT_JSON) 5057aabcda0Sclaudio json_do_end(); 506714f4e3fSclaudio } 507714f4e3fSclaudio 508714f4e3fSclaudio void 509530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 510714f4e3fSclaudio { 511530399e8Sjob if (outformats & FORMAT_JSON) { 5127aabcda0Sclaudio json_do_string("type", "gbr"); 5137aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 514530399e8Sjob x509_print(x); 5157aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 5167aabcda0Sclaudio json_do_string("aia", p->aia); 5177aabcda0Sclaudio json_do_string("sia", p->sia); 5181bb1e509Sjob if (p->signtime != 0) 5197aabcda0Sclaudio json_do_int("signing_time", p->signtime); 5207aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 5217aabcda0Sclaudio json_do_int("valid_until", p->notafter); 522894936b4Sjob if (p->expires) 5237aabcda0Sclaudio json_do_int("expires", p->expires); 5247aabcda0Sclaudio json_do_string("vcard", p->vcard); 525530399e8Sjob } else { 526714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 527530399e8Sjob x509_print(x); 528714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 529714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 5302cf0e122Sjob printf("Subject info access: %s\n", p->sia); 5311bb1e509Sjob if (p->signtime != 0) 5321bb1e509Sjob printf("Signing time: %s\n", 5331bb1e509Sjob time2str(p->signtime)); 5344dbb22b8Sjob printf("GBR not before: %s\n", 535f5999ddfSjob time2str(p->notbefore)); 5364dbb22b8Sjob printf("GBR not after: %s\n", time2str(p->notafter)); 537714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 538714f4e3fSclaudio } 539530399e8Sjob } 54004834fbdSjob 54104834fbdSjob void 54204834fbdSjob rsc_print(const X509 *x, const struct rsc *p) 54304834fbdSjob { 54404834fbdSjob char *hash; 5457aabcda0Sclaudio size_t i; 54604834fbdSjob 54704834fbdSjob if (outformats & FORMAT_JSON) { 5487aabcda0Sclaudio json_do_string("type", "rsc"); 5497aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 55004834fbdSjob x509_print(x); 5517aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 5527aabcda0Sclaudio json_do_string("aia", p->aia); 5531bb1e509Sjob if (p->signtime != 0) 5547aabcda0Sclaudio json_do_int("signing_time", p->signtime); 5557aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 5567aabcda0Sclaudio json_do_int("valid_until", p->notafter); 557894936b4Sjob if (p->expires) 5587aabcda0Sclaudio json_do_int("expires", p->expires); 5597aabcda0Sclaudio json_do_array("signed_with_resources"); 56004834fbdSjob } else { 56104834fbdSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 56204834fbdSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 56304834fbdSjob x509_print(x); 56404834fbdSjob printf("Authority info access: %s\n", p->aia); 5651bb1e509Sjob if (p->signtime != 0) 5661bb1e509Sjob printf("Signing time: %s\n", 5671bb1e509Sjob time2str(p->signtime)); 5684dbb22b8Sjob printf("RSC not before: %s\n", 569f5999ddfSjob time2str(p->notbefore)); 5704dbb22b8Sjob printf("RSC not after: %s\n", time2str(p->notafter)); 5714486d057Sjob printf("Signed with resources: "); 57204834fbdSjob } 57304834fbdSjob 5747aabcda0Sclaudio as_resources_print(p->as, p->asz); 5757aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 57604834fbdSjob 57704834fbdSjob if (outformats & FORMAT_JSON) { 5787aabcda0Sclaudio json_do_end(); 5797aabcda0Sclaudio json_do_array("filenamesandhashes"); 58004834fbdSjob } else 5814486d057Sjob printf("Filenames and hashes: "); 58204834fbdSjob 58304834fbdSjob for (i = 0; i < p->filesz; i++) { 58404834fbdSjob if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 58504834fbdSjob &hash) == -1) 58604834fbdSjob errx(1, "base64_encode failure"); 58704834fbdSjob 58804834fbdSjob if (outformats & FORMAT_JSON) { 589a09a3191Sclaudio json_do_object("filehash", 1); 5907aabcda0Sclaudio if (p->files[i].filename) 5917aabcda0Sclaudio json_do_string("filename", 5927aabcda0Sclaudio p->files[i].filename); 5937aabcda0Sclaudio json_do_string("hash_digest", hash); 5947aabcda0Sclaudio json_do_end(); 59504834fbdSjob } else { 5964486d057Sjob if (i > 0) 5974486d057Sjob printf("%26s", ""); 5984486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, 5994486d057Sjob p->files[i].filename ? p->files[i].filename 6004486d057Sjob : "no filename", hash); 60104834fbdSjob } 60204834fbdSjob 60304834fbdSjob free(hash); 60404834fbdSjob } 60504834fbdSjob 60604834fbdSjob if (outformats & FORMAT_JSON) 6077aabcda0Sclaudio json_do_end(); 60804834fbdSjob } 609a29ddfd5Sjob 610a29ddfd5Sjob void 611a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p) 612a29ddfd5Sjob { 6134b5fc138Sjob size_t i; 6144b5fc138Sjob 615a29ddfd5Sjob if (outformats & FORMAT_JSON) { 6167aabcda0Sclaudio json_do_string("type", "aspa"); 6177aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 618a29ddfd5Sjob x509_print(x); 6197aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 6207aabcda0Sclaudio json_do_string("aia", p->aia); 6217aabcda0Sclaudio json_do_string("sia", p->sia); 6221bb1e509Sjob if (p->signtime != 0) 6237aabcda0Sclaudio json_do_int("signing_time", p->signtime); 6247aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 6257aabcda0Sclaudio json_do_int("valid_until", p->notafter); 6269c1f5d6bSjob if (p->expires) 6277aabcda0Sclaudio json_do_int("expires", p->expires); 6287aabcda0Sclaudio json_do_uint("customer_asid", p->custasid); 6294a0be80eSjob json_do_array("providers"); 630a29ddfd5Sjob } else { 631a29ddfd5Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 632a29ddfd5Sjob x509_print(x); 633a29ddfd5Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 634a29ddfd5Sjob printf("Authority info access: %s\n", p->aia); 6352cf0e122Sjob printf("Subject info access: %s\n", p->sia); 6361bb1e509Sjob if (p->signtime != 0) 6371bb1e509Sjob printf("Signing time: %s\n", 6381bb1e509Sjob time2str(p->signtime)); 6394dbb22b8Sjob printf("ASPA not before: %s\n", 640f5999ddfSjob time2str(p->notbefore)); 6414dbb22b8Sjob printf("ASPA not after: %s\n", time2str(p->notafter)); 642ba54bc08Sjob printf("Customer ASID: %u\n", p->custasid); 6434a0be80eSjob printf("Providers: "); 644a29ddfd5Sjob } 6457aabcda0Sclaudio 6464b5fc138Sjob for (i = 0; i < p->providersz; i++) { 647b179db0eSjob if (outformats & FORMAT_JSON) 648b179db0eSjob json_do_uint("asid", p->providers[i]); 649b179db0eSjob else { 650b179db0eSjob if (i > 0) 6514b5fc138Sjob printf("%26s", ""); 652b179db0eSjob printf("AS: %u\n", p->providers[i]); 653b179db0eSjob } 6544b5fc138Sjob } 6557aabcda0Sclaudio 6567aabcda0Sclaudio if (outformats & FORMAT_JSON) 6577aabcda0Sclaudio json_do_end(); 658a29ddfd5Sjob } 659ee2a33daSjob 660ee2a33daSjob static void 661ee2a33daSjob takey_print(char *name, const struct takey *t) 662ee2a33daSjob { 663ee2a33daSjob char *spki = NULL; 664ee2a33daSjob size_t i, j = 0; 665ee2a33daSjob 666ee2a33daSjob if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0) 667ee2a33daSjob errx(1, "base64_encode failed in %s", __func__); 668ee2a33daSjob 669ee2a33daSjob if (outformats & FORMAT_JSON) { 670a09a3191Sclaudio json_do_object("takey", 0); 6717aabcda0Sclaudio json_do_string("name", name); 6727aabcda0Sclaudio json_do_array("comments"); 6737aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 6747aabcda0Sclaudio json_do_string("comment", t->comments[i]); 6757aabcda0Sclaudio json_do_end(); 6767aabcda0Sclaudio json_do_array("uris"); 6777aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 6787aabcda0Sclaudio json_do_string("uri", t->uris[i]); 6797aabcda0Sclaudio json_do_end(); 6807aabcda0Sclaudio json_do_string("spki", spki); 681ee2a33daSjob } else { 682ee2a33daSjob printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name); 683ee2a33daSjob 6847aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 685ee2a33daSjob printf("\t# %s\n", t->comments[i]); 6867aabcda0Sclaudio printf("\n"); 6877aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 6887aabcda0Sclaudio printf("\t%s\n\t", t->uris[i]); 689ee2a33daSjob for (i = 0; i < strlen(spki); i++) { 690ee2a33daSjob printf("%c", spki[i]); 6917aabcda0Sclaudio if ((++j % 64) == 0) 692ee2a33daSjob printf("\n\t"); 693ee2a33daSjob } 694ee2a33daSjob printf("\n\n"); 695ee2a33daSjob } 696ee2a33daSjob 697ee2a33daSjob free(spki); 698ee2a33daSjob } 699ee2a33daSjob 700ee2a33daSjob void 701ee2a33daSjob tak_print(const X509 *x, const struct tak *p) 702ee2a33daSjob { 703ee2a33daSjob if (outformats & FORMAT_JSON) { 7047aabcda0Sclaudio json_do_string("type", "tak"); 7057aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 706ee2a33daSjob x509_print(x); 7077aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 7087aabcda0Sclaudio json_do_string("aia", p->aia); 7097aabcda0Sclaudio json_do_string("sia", p->sia); 7101bb1e509Sjob if (p->signtime != 0) 7117aabcda0Sclaudio json_do_int("signing_time", p->signtime); 7127aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 7137aabcda0Sclaudio json_do_int("valid_until", p->notafter); 714894936b4Sjob if (p->expires) 7157aabcda0Sclaudio json_do_int("expires", p->expires); 7167aabcda0Sclaudio json_do_array("takeys"); 717ee2a33daSjob } else { 718ee2a33daSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 719ee2a33daSjob x509_print(x); 720ee2a33daSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 721ee2a33daSjob printf("Authority info access: %s\n", p->aia); 7222cf0e122Sjob printf("Subject info access: %s\n", p->sia); 7231bb1e509Sjob if (p->signtime != 0) 7241bb1e509Sjob printf("Signing time: %s\n", 7251bb1e509Sjob time2str(p->signtime)); 7264dbb22b8Sjob printf("TAK not before: %s\n", 727f5999ddfSjob time2str(p->notbefore)); 7284dbb22b8Sjob printf("TAK not after: %s\n", time2str(p->notafter)); 729ee2a33daSjob } 730ee2a33daSjob 731ee2a33daSjob takey_print("current", p->current); 7327aabcda0Sclaudio if (p->predecessor != NULL) 733ee2a33daSjob takey_print("predecessor", p->predecessor); 7347aabcda0Sclaudio if (p->successor != NULL) 735ee2a33daSjob takey_print("successor", p->successor); 736ee2a33daSjob 737ee2a33daSjob if (outformats & FORMAT_JSON) 7387aabcda0Sclaudio json_do_end(); 739ee2a33daSjob } 740ef3f6f56Sjob 741ef3f6f56Sjob void 742ef3f6f56Sjob geofeed_print(const X509 *x, const struct geofeed *p) 743ef3f6f56Sjob { 744ef3f6f56Sjob char buf[128]; 745ef3f6f56Sjob size_t i; 746ef3f6f56Sjob 747ef3f6f56Sjob if (outformats & FORMAT_JSON) { 7487aabcda0Sclaudio json_do_string("type", "geofeed"); 7497aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 750ef3f6f56Sjob x509_print(x); 7517aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 7527aabcda0Sclaudio json_do_string("aia", p->aia); 7531bb1e509Sjob if (p->signtime != 0) 7547aabcda0Sclaudio json_do_int("signing_time", p->signtime); 7557aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 7567aabcda0Sclaudio json_do_int("valid_until", p->notafter); 7577aabcda0Sclaudio if (p->expires) 7587aabcda0Sclaudio json_do_int("expires", p->expires); 7597aabcda0Sclaudio json_do_array("records"); 760ef3f6f56Sjob } else { 761ef3f6f56Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 762ef3f6f56Sjob x509_print(x); 763ef3f6f56Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 764ef3f6f56Sjob printf("Authority info access: %s\n", p->aia); 7651bb1e509Sjob if (p->signtime != 0) 7661bb1e509Sjob printf("Signing time: %s\n", 7671bb1e509Sjob time2str(p->signtime)); 7684dbb22b8Sjob printf("Geofeed not before: %s\n", 769f5999ddfSjob time2str(p->notbefore)); 7704dbb22b8Sjob printf("Geofeed not after: %s\n", time2str(p->notafter)); 771bd19f13dSjob printf("Geofeed CSV records: "); 772ef3f6f56Sjob } 773ef3f6f56Sjob 774ef3f6f56Sjob for (i = 0; i < p->geoipsz; i++) { 775ef3f6f56Sjob if (p->geoips[i].ip->type != CERT_IP_ADDR) 776ef3f6f56Sjob continue; 777ef3f6f56Sjob 778ef3f6f56Sjob ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf, 779ef3f6f56Sjob sizeof(buf)); 7807aabcda0Sclaudio if (outformats & FORMAT_JSON) { 781a09a3191Sclaudio json_do_object("geoip", 1); 7827aabcda0Sclaudio json_do_string("prefix", buf); 7837aabcda0Sclaudio json_do_string("location", p->geoips[i].loc); 7847aabcda0Sclaudio json_do_end(); 7857aabcda0Sclaudio } else { 7864486d057Sjob if (i > 0) 7874486d057Sjob printf("%26s", ""); 7887aabcda0Sclaudio printf("IP: %s (%s)\n", buf, p->geoips[i].loc); 7894486d057Sjob } 790ef3f6f56Sjob } 791ef3f6f56Sjob 792ef3f6f56Sjob if (outformats & FORMAT_JSON) 7937aabcda0Sclaudio json_do_end(); 794ef3f6f56Sjob } 795