1*ddc87cffSjob /* $OpenBSD: print.c,v 1.47 2024/02/13 20:36:42 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; 86*ddc87cffSjob const unsigned char *der, *pkey_der; 87*ddc87cffSjob X509_PUBKEY *pubkey; 88*ddc87cffSjob ASN1_OBJECT *obj; 89e911df76Sjob unsigned char md[SHA_DIGEST_LENGTH]; 90*ddc87cffSjob int nid, der_len; 91714f4e3fSclaudio size_t i; 92714f4e3fSclaudio 93*ddc87cffSjob pkey_der = p->pkey; 94*ddc87cffSjob if ((pubkey = d2i_X509_PUBKEY(NULL, &pkey_der, p->pkeysz)) == NULL) 95*ddc87cffSjob errx(1, "d2i_X509_PUBKEY failed"); 96e911df76Sjob 97*ddc87cffSjob if (!X509_PUBKEY_get0_param(&obj, &der, &der_len, NULL, pubkey)) 98*ddc87cffSjob errx(1, "X509_PUBKEY_get0_param failed"); 99e911df76Sjob 100*ddc87cffSjob if ((nid = OBJ_obj2nid(obj)) != NID_rsaEncryption) 101*ddc87cffSjob errx(1, "RFC 7935: wrong signature algorithm %s, want %s", 102*ddc87cffSjob nid2str(nid), LN_rsaEncryption); 103*ddc87cffSjob 104*ddc87cffSjob if (!EVP_Digest(der, der_len, md, NULL, EVP_sha1(), NULL)) 105*ddc87cffSjob errx(1, "EVP_Digest failed"); 106e911df76Sjob 107e911df76Sjob ski = hex_encode(md, SHA_DIGEST_LENGTH); 108e911df76Sjob 109530399e8Sjob if (outformats & FORMAT_JSON) { 1107aabcda0Sclaudio json_do_string("type", "tal"); 1117aabcda0Sclaudio json_do_string("name", p->descr); 1127aabcda0Sclaudio json_do_string("ski", pretty_key_id(ski)); 1137aabcda0Sclaudio json_do_array("trust_anchor_locations"); 1147aabcda0Sclaudio for (i = 0; i < p->urisz; i++) 1157aabcda0Sclaudio json_do_string("tal", p->uri[i]); 1167aabcda0Sclaudio json_do_end(); 117530399e8Sjob } else { 118530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 119530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 1204486d057Sjob printf("Trust anchor locations: "); 1214486d057Sjob for (i = 0; i < p->urisz; i++) { 1224486d057Sjob if (i > 0) 1234486d057Sjob printf("%26s", ""); 1244486d057Sjob printf("%s\n", p->uri[i]); 1254486d057Sjob } 126530399e8Sjob } 127e911df76Sjob 128*ddc87cffSjob X509_PUBKEY_free(pubkey); 129e911df76Sjob free(ski); 130714f4e3fSclaudio } 131714f4e3fSclaudio 132714f4e3fSclaudio void 133530399e8Sjob x509_print(const X509 *x) 134530399e8Sjob { 135530399e8Sjob const ASN1_INTEGER *xserial; 136e0b87278Sjob const X509_NAME *xissuer; 137e0b87278Sjob char *issuer = NULL; 138530399e8Sjob char *serial = NULL; 139530399e8Sjob 140e0b87278Sjob if ((xissuer = X509_get_issuer_name(x)) == NULL) { 141e0b87278Sjob warnx("X509_get_issuer_name failed"); 142530399e8Sjob goto out; 143530399e8Sjob } 144530399e8Sjob 145e0b87278Sjob if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) { 146e0b87278Sjob warnx("X509_NAME_oneline failed"); 147530399e8Sjob goto out; 148530399e8Sjob } 149530399e8Sjob 150e0b87278Sjob if ((xserial = X509_get0_serialNumber(x)) == NULL) { 151e0b87278Sjob warnx("X509_get0_serialNumber failed"); 152e0b87278Sjob goto out; 153e0b87278Sjob } 154e0b87278Sjob 155e0b87278Sjob if ((serial = x509_convert_seqnum(__func__, xserial)) == NULL) 156e0b87278Sjob goto out; 157e0b87278Sjob 158530399e8Sjob if (outformats & FORMAT_JSON) { 1597aabcda0Sclaudio json_do_string("cert_issuer", issuer); 1607aabcda0Sclaudio json_do_string("cert_serial", serial); 161530399e8Sjob } else { 162e0b87278Sjob printf("Certificate issuer: %s\n", issuer); 163530399e8Sjob printf("Certificate serial: %s\n", serial); 164530399e8Sjob } 165530399e8Sjob 166530399e8Sjob out: 167e0b87278Sjob free(issuer); 168530399e8Sjob free(serial); 169530399e8Sjob } 170530399e8Sjob 1717aabcda0Sclaudio static void 1727aabcda0Sclaudio as_resources_print(struct cert_as *as, size_t asz) 1737aabcda0Sclaudio { 1747aabcda0Sclaudio size_t i; 1757aabcda0Sclaudio 1767aabcda0Sclaudio for (i = 0; i < asz; i++) { 1777aabcda0Sclaudio if (outformats & FORMAT_JSON) 178a09a3191Sclaudio json_do_object("resource", 1); 1797aabcda0Sclaudio switch (as[i].type) { 1807aabcda0Sclaudio case CERT_AS_ID: 1817aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1827aabcda0Sclaudio json_do_uint("asid", as[i].id); 1837aabcda0Sclaudio } else { 1847aabcda0Sclaudio if (i > 0) 1857aabcda0Sclaudio printf("%26s", ""); 1867aabcda0Sclaudio printf("AS: %u", as[i].id); 1877aabcda0Sclaudio } 1887aabcda0Sclaudio break; 1897aabcda0Sclaudio case CERT_AS_INHERIT: 1907aabcda0Sclaudio if (outformats & FORMAT_JSON) { 1917aabcda0Sclaudio json_do_bool("asid_inherit", 1); 1927aabcda0Sclaudio } else { 1937aabcda0Sclaudio if (i > 0) 1947aabcda0Sclaudio printf("%26s", ""); 1957aabcda0Sclaudio printf("AS: inherit"); 1967aabcda0Sclaudio } 1977aabcda0Sclaudio break; 1987aabcda0Sclaudio case CERT_AS_RANGE: 1997aabcda0Sclaudio if (outformats & FORMAT_JSON) { 200a09a3191Sclaudio json_do_object("asrange", 1); 2017aabcda0Sclaudio json_do_uint("min", as[i].range.min); 2027aabcda0Sclaudio json_do_uint("max", as[i].range.max); 2037aabcda0Sclaudio json_do_end(); 2047aabcda0Sclaudio } else { 2057aabcda0Sclaudio if (i > 0) 2067aabcda0Sclaudio printf("%26s", ""); 2077aabcda0Sclaudio printf("AS: %u -- %u", as[i].range.min, 2087aabcda0Sclaudio as[i].range.max); 2097aabcda0Sclaudio } 2107aabcda0Sclaudio break; 2117aabcda0Sclaudio } 2127aabcda0Sclaudio if (outformats & FORMAT_JSON) 2137aabcda0Sclaudio json_do_end(); 2147aabcda0Sclaudio else 2157aabcda0Sclaudio printf("\n"); 2167aabcda0Sclaudio } 2177aabcda0Sclaudio } 2187aabcda0Sclaudio 2197aabcda0Sclaudio static void 2207aabcda0Sclaudio ip_resources_print(struct cert_ip *ips, size_t ipsz, size_t asz) 2217aabcda0Sclaudio { 2227aabcda0Sclaudio char buf1[64], buf2[64]; 2237aabcda0Sclaudio size_t i; 2247aabcda0Sclaudio int sockt; 2257aabcda0Sclaudio 2267aabcda0Sclaudio 2277aabcda0Sclaudio for (i = 0; i < ipsz; i++) { 2287aabcda0Sclaudio if (outformats & FORMAT_JSON) 229a09a3191Sclaudio json_do_object("resource", 1); 2307aabcda0Sclaudio switch (ips[i].type) { 2317aabcda0Sclaudio case CERT_IP_INHERIT: 2327aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2337aabcda0Sclaudio json_do_bool("ip_inherit", 1); 2347aabcda0Sclaudio } else { 2357aabcda0Sclaudio if (i > 0 || asz > 0) 2367aabcda0Sclaudio printf("%26s", ""); 2377aabcda0Sclaudio printf("IP: inherit"); 2387aabcda0Sclaudio } 2397aabcda0Sclaudio break; 2407aabcda0Sclaudio case CERT_IP_ADDR: 2417aabcda0Sclaudio ip_addr_print(&ips[i].ip, ips[i].afi, buf1, 2427aabcda0Sclaudio sizeof(buf1)); 2437aabcda0Sclaudio if (outformats & FORMAT_JSON) { 2447aabcda0Sclaudio json_do_string("ip_prefix", buf1); 2457aabcda0Sclaudio } else { 2467aabcda0Sclaudio if (i > 0 || asz > 0) 2477aabcda0Sclaudio printf("%26s", ""); 2487aabcda0Sclaudio printf("IP: %s", buf1); 2497aabcda0Sclaudio } 2507aabcda0Sclaudio break; 2517aabcda0Sclaudio case CERT_IP_RANGE: 2527aabcda0Sclaudio sockt = (ips[i].afi == AFI_IPV4) ? 2537aabcda0Sclaudio AF_INET : AF_INET6; 2547aabcda0Sclaudio inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1)); 2557aabcda0Sclaudio inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2)); 2567aabcda0Sclaudio if (outformats & FORMAT_JSON) { 257a09a3191Sclaudio json_do_object("ip_range", 1); 2587aabcda0Sclaudio json_do_string("min", buf1); 2597aabcda0Sclaudio json_do_string("max", buf2); 2607aabcda0Sclaudio json_do_end(); 2617aabcda0Sclaudio } else { 2627aabcda0Sclaudio if (i > 0 || asz > 0) 2637aabcda0Sclaudio printf("%26s", ""); 2647aabcda0Sclaudio printf("IP: %s -- %s", buf1, buf2); 2657aabcda0Sclaudio } 2667aabcda0Sclaudio break; 2677aabcda0Sclaudio } 2687aabcda0Sclaudio if (outformats & FORMAT_JSON) 2697aabcda0Sclaudio json_do_end(); 2707aabcda0Sclaudio else 2717aabcda0Sclaudio printf("\n"); 2727aabcda0Sclaudio } 2737aabcda0Sclaudio } 2747aabcda0Sclaudio 275530399e8Sjob void 276714f4e3fSclaudio cert_print(const struct cert *p) 277714f4e3fSclaudio { 278530399e8Sjob if (outformats & FORMAT_JSON) { 279530399e8Sjob if (p->pubkey != NULL) 2807aabcda0Sclaudio json_do_string("type", "router_key"); 281530399e8Sjob else 2827aabcda0Sclaudio json_do_string("type", "ca_cert"); 2837aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 284530399e8Sjob if (p->aki != NULL) 2857aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 286530399e8Sjob x509_print(p->x509); 287530399e8Sjob if (p->aia != NULL) 2887aabcda0Sclaudio json_do_string("aia", p->aia); 289530399e8Sjob if (p->mft != NULL) 2907aabcda0Sclaudio json_do_string("manifest", p->mft); 291530399e8Sjob if (p->repo != NULL) 2927aabcda0Sclaudio json_do_string("carepository", p->repo); 293530399e8Sjob if (p->notify != NULL) 2947aabcda0Sclaudio json_do_string("notify_url", p->notify); 295530399e8Sjob if (p->pubkey != NULL) 2967aabcda0Sclaudio json_do_string("router_key", p->pubkey); 2977aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 2987aabcda0Sclaudio json_do_int("valid_until", p->notafter); 299894936b4Sjob if (p->expires) 3007aabcda0Sclaudio json_do_int("expires", p->expires); 3017aabcda0Sclaudio json_do_array("subordinate_resources"); 302530399e8Sjob } else { 303714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 304714f4e3fSclaudio if (p->aki != NULL) 30567642cb5Stb printf("Authority key identifier: %s\n", 30667642cb5Stb pretty_key_id(p->aki)); 307530399e8Sjob x509_print(p->x509); 308714f4e3fSclaudio if (p->aia != NULL) 309714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 310714f4e3fSclaudio if (p->mft != NULL) 311714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 312714f4e3fSclaudio if (p->repo != NULL) 313714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 314714f4e3fSclaudio if (p->notify != NULL) 315714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 31614d83341Sjob if (p->pubkey != NULL) { 3176530cf17Sjob printf("BGPsec ECDSA public key: %s\n", 31867642cb5Stb p->pubkey); 3194dbb22b8Sjob printf("Router key not before: %s\n", 320f5999ddfSjob time2str(p->notbefore)); 3214dbb22b8Sjob printf("Router key not after: %s\n", 3229f544822Sjob time2str(p->notafter)); 323f5999ddfSjob } else { 3244dbb22b8Sjob printf("Certificate not before: %s\n", 325f5999ddfSjob time2str(p->notbefore)); 3264dbb22b8Sjob printf("Certificate not after: %s\n", 3279f544822Sjob time2str(p->notafter)); 328f5999ddfSjob } 3294486d057Sjob printf("Subordinate resources: "); 330530399e8Sjob } 331714f4e3fSclaudio 3327aabcda0Sclaudio as_resources_print(p->as, p->asz); 3337aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 334530399e8Sjob 335530399e8Sjob if (outformats & FORMAT_JSON) 3367aabcda0Sclaudio json_do_end(); 337714f4e3fSclaudio } 338714f4e3fSclaudio 339714f4e3fSclaudio void 340220c707cSclaudio crl_print(const struct crl *p) 341220c707cSclaudio { 342220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 343220c707cSclaudio X509_REVOKED *rev; 344e0b87278Sjob X509_NAME *xissuer; 345220c707cSclaudio int i; 346e0b87278Sjob char *issuer, *serial; 347220c707cSclaudio time_t t; 348220c707cSclaudio 349530399e8Sjob if (outformats & FORMAT_JSON) { 3507aabcda0Sclaudio json_do_string("type", "crl"); 3517aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 352530399e8Sjob } else 353220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 3547cdd491fSclaudio 355e0b87278Sjob xissuer = X509_CRL_get_issuer(p->x509_crl); 356e0b87278Sjob issuer = X509_NAME_oneline(xissuer, NULL, 0); 3570a722356Stb if (issuer != NULL && p->number != NULL) { 358e0b87278Sjob if (outformats & FORMAT_JSON) { 3597aabcda0Sclaudio json_do_string("crl_issuer", issuer); 3600a722356Stb json_do_string("crl_serial", p->number); 361e0b87278Sjob } else { 362e0b87278Sjob printf("CRL issuer: %s\n", issuer); 3630a722356Stb printf("CRL serial number: %s\n", p->number); 364530399e8Sjob } 365e0b87278Sjob } 366e0b87278Sjob free(issuer); 3677cdd491fSclaudio 368530399e8Sjob if (outformats & FORMAT_JSON) { 369c527cc7aSjob json_do_int("valid_since", p->thisupdate); 3707aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 3717aabcda0Sclaudio json_do_array("revoked_certs"); 372530399e8Sjob } else { 373c527cc7aSjob printf("CRL this update: %s\n", 374c527cc7aSjob time2str(p->thisupdate)); 3754dbb22b8Sjob printf("CRL next update: %s\n", 3769f544822Sjob time2str(p->nextupdate)); 377530399e8Sjob printf("Revoked Certificates:\n"); 378530399e8Sjob } 379220c707cSclaudio 380220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 381220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 382220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3837cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3847cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 385220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 386530399e8Sjob if (serial != NULL) { 387530399e8Sjob if (outformats & FORMAT_JSON) { 388a09a3191Sclaudio json_do_object("cert", 1); 3897aabcda0Sclaudio json_do_string("serial", serial); 3907aabcda0Sclaudio json_do_string("date", time2str(t)); 3917aabcda0Sclaudio json_do_end(); 392530399e8Sjob } else 3934486d057Sjob printf("%25s Serial: %8s Revocation Date: %s" 3944486d057Sjob "\n", "", serial, time2str(t)); 395530399e8Sjob } 3967cdd491fSclaudio free(serial); 397220c707cSclaudio } 398530399e8Sjob 399530399e8Sjob if (outformats & FORMAT_JSON) 4007aabcda0Sclaudio json_do_end(); 401530399e8Sjob else if (i == 0) 402220c707cSclaudio printf("No Revoked Certificates\n"); 403220c707cSclaudio } 404220c707cSclaudio 405220c707cSclaudio void 406530399e8Sjob mft_print(const X509 *x, const struct mft *p) 407714f4e3fSclaudio { 408714f4e3fSclaudio size_t i; 409714f4e3fSclaudio char *hash; 410714f4e3fSclaudio 411530399e8Sjob if (outformats & FORMAT_JSON) { 4127aabcda0Sclaudio json_do_string("type", "manifest"); 4137aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 414530399e8Sjob x509_print(x); 4157aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4167aabcda0Sclaudio json_do_string("aia", p->aia); 4177aabcda0Sclaudio json_do_string("sia", p->sia); 4187aabcda0Sclaudio json_do_string("manifest_number", p->seqnum); 4191bb1e509Sjob if (p->signtime != 0) 4207aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4217aabcda0Sclaudio json_do_int("valid_since", p->thisupdate); 4227aabcda0Sclaudio json_do_int("valid_until", p->nextupdate); 423894936b4Sjob if (p->expires) 4247aabcda0Sclaudio json_do_int("expires", p->expires); 425530399e8Sjob } else { 426714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 427714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 428530399e8Sjob x509_print(x); 429714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4302cf0e122Sjob printf("Subject info access: %s\n", p->sia); 431489e308aSjob printf("Manifest number: %s\n", p->seqnum); 4321bb1e509Sjob if (p->signtime != 0) 4331bb1e509Sjob printf("Signing time: %s\n", 4341bb1e509Sjob time2str(p->signtime)); 4354dbb22b8Sjob printf("Manifest this update: %s\n", time2str(p->thisupdate)); 4364dbb22b8Sjob printf("Manifest next update: %s\n", time2str(p->nextupdate)); 4374486d057Sjob printf("Files and hashes: "); 438530399e8Sjob } 439530399e8Sjob 4407aabcda0Sclaudio if (outformats & FORMAT_JSON) 4417aabcda0Sclaudio json_do_array("filesandhashes"); 442714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 443714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 444714f4e3fSclaudio &hash) == -1) 445714f4e3fSclaudio errx(1, "base64_encode failure"); 446530399e8Sjob 447530399e8Sjob if (outformats & FORMAT_JSON) { 448a09a3191Sclaudio json_do_object("filehash", 1); 4497aabcda0Sclaudio json_do_string("filename", p->files[i].file); 4507aabcda0Sclaudio json_do_string("hash", hash); 4517aabcda0Sclaudio json_do_end(); 452530399e8Sjob } else { 4534486d057Sjob if (i > 0) 4544486d057Sjob printf("%26s", ""); 4554486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file, 4564486d057Sjob hash); 457530399e8Sjob } 458530399e8Sjob 459714f4e3fSclaudio free(hash); 460714f4e3fSclaudio } 461530399e8Sjob if (outformats & FORMAT_JSON) 4627aabcda0Sclaudio json_do_end(); 463714f4e3fSclaudio } 464714f4e3fSclaudio 465714f4e3fSclaudio void 466530399e8Sjob roa_print(const X509 *x, const struct roa *p) 467714f4e3fSclaudio { 468714f4e3fSclaudio char buf[128]; 469714f4e3fSclaudio size_t i; 470714f4e3fSclaudio 471530399e8Sjob if (outformats & FORMAT_JSON) { 4727aabcda0Sclaudio json_do_string("type", "roa"); 4737aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 474530399e8Sjob x509_print(x); 4757aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 4767aabcda0Sclaudio json_do_string("aia", p->aia); 4777aabcda0Sclaudio json_do_string("sia", p->sia); 4781bb1e509Sjob if (p->signtime != 0) 4797aabcda0Sclaudio json_do_int("signing_time", p->signtime); 4807aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 4817aabcda0Sclaudio json_do_int("valid_until", p->notafter); 4829c1f5d6bSjob if (p->expires) 4837aabcda0Sclaudio json_do_int("expires", p->expires); 484530399e8Sjob } else { 485714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 486530399e8Sjob x509_print(x); 487714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 488714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4892cf0e122Sjob printf("Subject info access: %s\n", p->sia); 4901bb1e509Sjob if (p->signtime != 0) 4911bb1e509Sjob printf("Signing time: %s\n", 4921bb1e509Sjob time2str(p->signtime)); 4934dbb22b8Sjob printf("ROA not before: %s\n", 494f5999ddfSjob time2str(p->notbefore)); 4954dbb22b8Sjob printf("ROA not after: %s\n", time2str(p->notafter)); 496714f4e3fSclaudio printf("asID: %u\n", p->asid); 4974486d057Sjob printf("IP address blocks: "); 498530399e8Sjob } 499530399e8Sjob 5007aabcda0Sclaudio if (outformats & FORMAT_JSON) 5017aabcda0Sclaudio json_do_array("vrps"); 502714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 503714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 504714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 505530399e8Sjob 506530399e8Sjob if (outformats & FORMAT_JSON) { 507a09a3191Sclaudio json_do_object("vrp", 1); 5087aabcda0Sclaudio json_do_string("prefix", buf); 5097aabcda0Sclaudio json_do_uint("asid", p->asid); 5107aabcda0Sclaudio json_do_uint("maxlen", p->ips[i].maxlength); 5117aabcda0Sclaudio json_do_end(); 5124486d057Sjob } else { 5134486d057Sjob if (i > 0) 5144486d057Sjob printf("%26s", ""); 5154486d057Sjob printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength); 5164486d057Sjob } 517714f4e3fSclaudio } 518530399e8Sjob if (outformats & FORMAT_JSON) 5197aabcda0Sclaudio json_do_end(); 520714f4e3fSclaudio } 521714f4e3fSclaudio 522714f4e3fSclaudio void 523530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 524714f4e3fSclaudio { 525530399e8Sjob if (outformats & FORMAT_JSON) { 5267aabcda0Sclaudio json_do_string("type", "gbr"); 5277aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 528530399e8Sjob x509_print(x); 5297aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 5307aabcda0Sclaudio json_do_string("aia", p->aia); 5317aabcda0Sclaudio json_do_string("sia", p->sia); 5321bb1e509Sjob if (p->signtime != 0) 5337aabcda0Sclaudio json_do_int("signing_time", p->signtime); 5347aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 5357aabcda0Sclaudio json_do_int("valid_until", p->notafter); 536894936b4Sjob if (p->expires) 5377aabcda0Sclaudio json_do_int("expires", p->expires); 5387aabcda0Sclaudio json_do_string("vcard", p->vcard); 539530399e8Sjob } else { 540714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 541530399e8Sjob x509_print(x); 542714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 543714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 5442cf0e122Sjob printf("Subject info access: %s\n", p->sia); 5451bb1e509Sjob if (p->signtime != 0) 5461bb1e509Sjob printf("Signing time: %s\n", 5471bb1e509Sjob time2str(p->signtime)); 5484dbb22b8Sjob printf("GBR not before: %s\n", 549f5999ddfSjob time2str(p->notbefore)); 5504dbb22b8Sjob printf("GBR not after: %s\n", time2str(p->notafter)); 551714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 552714f4e3fSclaudio } 553530399e8Sjob } 55404834fbdSjob 55504834fbdSjob void 55604834fbdSjob rsc_print(const X509 *x, const struct rsc *p) 55704834fbdSjob { 55804834fbdSjob char *hash; 5597aabcda0Sclaudio size_t i; 56004834fbdSjob 56104834fbdSjob if (outformats & FORMAT_JSON) { 5627aabcda0Sclaudio json_do_string("type", "rsc"); 5637aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 56404834fbdSjob x509_print(x); 5657aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 5667aabcda0Sclaudio json_do_string("aia", p->aia); 5671bb1e509Sjob if (p->signtime != 0) 5687aabcda0Sclaudio json_do_int("signing_time", p->signtime); 5697aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 5707aabcda0Sclaudio json_do_int("valid_until", p->notafter); 571894936b4Sjob if (p->expires) 5727aabcda0Sclaudio json_do_int("expires", p->expires); 5737aabcda0Sclaudio json_do_array("signed_with_resources"); 57404834fbdSjob } else { 57504834fbdSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 57604834fbdSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 57704834fbdSjob x509_print(x); 57804834fbdSjob printf("Authority info access: %s\n", p->aia); 5791bb1e509Sjob if (p->signtime != 0) 5801bb1e509Sjob printf("Signing time: %s\n", 5811bb1e509Sjob time2str(p->signtime)); 5824dbb22b8Sjob printf("RSC not before: %s\n", 583f5999ddfSjob time2str(p->notbefore)); 5844dbb22b8Sjob printf("RSC not after: %s\n", time2str(p->notafter)); 5854486d057Sjob printf("Signed with resources: "); 58604834fbdSjob } 58704834fbdSjob 5887aabcda0Sclaudio as_resources_print(p->as, p->asz); 5897aabcda0Sclaudio ip_resources_print(p->ips, p->ipsz, p->asz); 59004834fbdSjob 59104834fbdSjob if (outformats & FORMAT_JSON) { 5927aabcda0Sclaudio json_do_end(); 5937aabcda0Sclaudio json_do_array("filenamesandhashes"); 59404834fbdSjob } else 5954486d057Sjob printf("Filenames and hashes: "); 59604834fbdSjob 59704834fbdSjob for (i = 0; i < p->filesz; i++) { 59804834fbdSjob if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 59904834fbdSjob &hash) == -1) 60004834fbdSjob errx(1, "base64_encode failure"); 60104834fbdSjob 60204834fbdSjob if (outformats & FORMAT_JSON) { 603a09a3191Sclaudio json_do_object("filehash", 1); 6047aabcda0Sclaudio if (p->files[i].filename) 6057aabcda0Sclaudio json_do_string("filename", 6067aabcda0Sclaudio p->files[i].filename); 6077aabcda0Sclaudio json_do_string("hash_digest", hash); 6087aabcda0Sclaudio json_do_end(); 60904834fbdSjob } else { 6104486d057Sjob if (i > 0) 6114486d057Sjob printf("%26s", ""); 6124486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, 6134486d057Sjob p->files[i].filename ? p->files[i].filename 6144486d057Sjob : "no filename", hash); 61504834fbdSjob } 61604834fbdSjob 61704834fbdSjob free(hash); 61804834fbdSjob } 61904834fbdSjob 62004834fbdSjob if (outformats & FORMAT_JSON) 6217aabcda0Sclaudio json_do_end(); 62204834fbdSjob } 623a29ddfd5Sjob 624a29ddfd5Sjob void 625a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p) 626a29ddfd5Sjob { 6274b5fc138Sjob size_t i; 6284b5fc138Sjob 629a29ddfd5Sjob if (outformats & FORMAT_JSON) { 6307aabcda0Sclaudio json_do_string("type", "aspa"); 6317aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 632a29ddfd5Sjob x509_print(x); 6337aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 6347aabcda0Sclaudio json_do_string("aia", p->aia); 6357aabcda0Sclaudio json_do_string("sia", p->sia); 6361bb1e509Sjob if (p->signtime != 0) 6377aabcda0Sclaudio json_do_int("signing_time", p->signtime); 6387aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 6397aabcda0Sclaudio json_do_int("valid_until", p->notafter); 6409c1f5d6bSjob if (p->expires) 6417aabcda0Sclaudio json_do_int("expires", p->expires); 6427aabcda0Sclaudio json_do_uint("customer_asid", p->custasid); 6434a0be80eSjob json_do_array("providers"); 644a29ddfd5Sjob } else { 645a29ddfd5Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 646a29ddfd5Sjob x509_print(x); 647a29ddfd5Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 648a29ddfd5Sjob printf("Authority info access: %s\n", p->aia); 6492cf0e122Sjob printf("Subject info access: %s\n", p->sia); 6501bb1e509Sjob if (p->signtime != 0) 6511bb1e509Sjob printf("Signing time: %s\n", 6521bb1e509Sjob time2str(p->signtime)); 6534dbb22b8Sjob printf("ASPA not before: %s\n", 654f5999ddfSjob time2str(p->notbefore)); 6554dbb22b8Sjob printf("ASPA not after: %s\n", time2str(p->notafter)); 656ba54bc08Sjob printf("Customer ASID: %u\n", p->custasid); 6574a0be80eSjob printf("Providers: "); 658a29ddfd5Sjob } 6597aabcda0Sclaudio 6604b5fc138Sjob for (i = 0; i < p->providersz; i++) { 661b179db0eSjob if (outformats & FORMAT_JSON) 662b179db0eSjob json_do_uint("asid", p->providers[i]); 663b179db0eSjob else { 664b179db0eSjob if (i > 0) 6654b5fc138Sjob printf("%26s", ""); 666b179db0eSjob printf("AS: %u\n", p->providers[i]); 667b179db0eSjob } 6684b5fc138Sjob } 6697aabcda0Sclaudio 6707aabcda0Sclaudio if (outformats & FORMAT_JSON) 6717aabcda0Sclaudio json_do_end(); 672a29ddfd5Sjob } 673ee2a33daSjob 674ee2a33daSjob static void 675ee2a33daSjob takey_print(char *name, const struct takey *t) 676ee2a33daSjob { 677ee2a33daSjob char *spki = NULL; 678ee2a33daSjob size_t i, j = 0; 679ee2a33daSjob 680ee2a33daSjob if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0) 681ee2a33daSjob errx(1, "base64_encode failed in %s", __func__); 682ee2a33daSjob 683ee2a33daSjob if (outformats & FORMAT_JSON) { 684a09a3191Sclaudio json_do_object("takey", 0); 6857aabcda0Sclaudio json_do_string("name", name); 6867aabcda0Sclaudio json_do_array("comments"); 6877aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 6887aabcda0Sclaudio json_do_string("comment", t->comments[i]); 6897aabcda0Sclaudio json_do_end(); 6907aabcda0Sclaudio json_do_array("uris"); 6917aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 6927aabcda0Sclaudio json_do_string("uri", t->uris[i]); 6937aabcda0Sclaudio json_do_end(); 6947aabcda0Sclaudio json_do_string("spki", spki); 695ee2a33daSjob } else { 696ee2a33daSjob printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name); 697ee2a33daSjob 6987aabcda0Sclaudio for (i = 0; i < t->commentsz; i++) 699ee2a33daSjob printf("\t# %s\n", t->comments[i]); 7007aabcda0Sclaudio printf("\n"); 7017aabcda0Sclaudio for (i = 0; i < t->urisz; i++) 7027aabcda0Sclaudio printf("\t%s\n\t", t->uris[i]); 703ee2a33daSjob for (i = 0; i < strlen(spki); i++) { 704ee2a33daSjob printf("%c", spki[i]); 7057aabcda0Sclaudio if ((++j % 64) == 0) 706ee2a33daSjob printf("\n\t"); 707ee2a33daSjob } 708ee2a33daSjob printf("\n\n"); 709ee2a33daSjob } 710ee2a33daSjob 711ee2a33daSjob free(spki); 712ee2a33daSjob } 713ee2a33daSjob 714ee2a33daSjob void 715ee2a33daSjob tak_print(const X509 *x, const struct tak *p) 716ee2a33daSjob { 717ee2a33daSjob if (outformats & FORMAT_JSON) { 7187aabcda0Sclaudio json_do_string("type", "tak"); 7197aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 720ee2a33daSjob x509_print(x); 7217aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 7227aabcda0Sclaudio json_do_string("aia", p->aia); 7237aabcda0Sclaudio json_do_string("sia", p->sia); 7241bb1e509Sjob if (p->signtime != 0) 7257aabcda0Sclaudio json_do_int("signing_time", p->signtime); 7267aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 7277aabcda0Sclaudio json_do_int("valid_until", p->notafter); 728894936b4Sjob if (p->expires) 7297aabcda0Sclaudio json_do_int("expires", p->expires); 7307aabcda0Sclaudio json_do_array("takeys"); 731ee2a33daSjob } else { 732ee2a33daSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 733ee2a33daSjob x509_print(x); 734ee2a33daSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 735ee2a33daSjob printf("Authority info access: %s\n", p->aia); 7362cf0e122Sjob printf("Subject info access: %s\n", p->sia); 7371bb1e509Sjob if (p->signtime != 0) 7381bb1e509Sjob printf("Signing time: %s\n", 7391bb1e509Sjob time2str(p->signtime)); 7404dbb22b8Sjob printf("TAK not before: %s\n", 741f5999ddfSjob time2str(p->notbefore)); 7424dbb22b8Sjob printf("TAK not after: %s\n", time2str(p->notafter)); 743ee2a33daSjob } 744ee2a33daSjob 745ee2a33daSjob takey_print("current", p->current); 7467aabcda0Sclaudio if (p->predecessor != NULL) 747ee2a33daSjob takey_print("predecessor", p->predecessor); 7487aabcda0Sclaudio if (p->successor != NULL) 749ee2a33daSjob takey_print("successor", p->successor); 750ee2a33daSjob 751ee2a33daSjob if (outformats & FORMAT_JSON) 7527aabcda0Sclaudio json_do_end(); 753ee2a33daSjob } 754ef3f6f56Sjob 755ef3f6f56Sjob void 756ef3f6f56Sjob geofeed_print(const X509 *x, const struct geofeed *p) 757ef3f6f56Sjob { 758ef3f6f56Sjob char buf[128]; 759ef3f6f56Sjob size_t i; 760ef3f6f56Sjob 761ef3f6f56Sjob if (outformats & FORMAT_JSON) { 7627aabcda0Sclaudio json_do_string("type", "geofeed"); 7637aabcda0Sclaudio json_do_string("ski", pretty_key_id(p->ski)); 764ef3f6f56Sjob x509_print(x); 7657aabcda0Sclaudio json_do_string("aki", pretty_key_id(p->aki)); 7667aabcda0Sclaudio json_do_string("aia", p->aia); 7671bb1e509Sjob if (p->signtime != 0) 7687aabcda0Sclaudio json_do_int("signing_time", p->signtime); 7697aabcda0Sclaudio json_do_int("valid_since", p->notbefore); 7707aabcda0Sclaudio json_do_int("valid_until", p->notafter); 7717aabcda0Sclaudio if (p->expires) 7727aabcda0Sclaudio json_do_int("expires", p->expires); 7737aabcda0Sclaudio json_do_array("records"); 774ef3f6f56Sjob } else { 775ef3f6f56Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 776ef3f6f56Sjob x509_print(x); 777ef3f6f56Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 778ef3f6f56Sjob printf("Authority info access: %s\n", p->aia); 7791bb1e509Sjob if (p->signtime != 0) 7801bb1e509Sjob printf("Signing time: %s\n", 7811bb1e509Sjob time2str(p->signtime)); 7824dbb22b8Sjob printf("Geofeed not before: %s\n", 783f5999ddfSjob time2str(p->notbefore)); 7844dbb22b8Sjob printf("Geofeed not after: %s\n", time2str(p->notafter)); 785bd19f13dSjob printf("Geofeed CSV records: "); 786ef3f6f56Sjob } 787ef3f6f56Sjob 788ef3f6f56Sjob for (i = 0; i < p->geoipsz; i++) { 789ef3f6f56Sjob if (p->geoips[i].ip->type != CERT_IP_ADDR) 790ef3f6f56Sjob continue; 791ef3f6f56Sjob 792ef3f6f56Sjob ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf, 793ef3f6f56Sjob sizeof(buf)); 7947aabcda0Sclaudio if (outformats & FORMAT_JSON) { 795a09a3191Sclaudio json_do_object("geoip", 1); 7967aabcda0Sclaudio json_do_string("prefix", buf); 7977aabcda0Sclaudio json_do_string("location", p->geoips[i].loc); 7987aabcda0Sclaudio json_do_end(); 7997aabcda0Sclaudio } else { 8004486d057Sjob if (i > 0) 8014486d057Sjob printf("%26s", ""); 8027aabcda0Sclaudio printf("IP: %s (%s)\n", buf, p->geoips[i].loc); 8034486d057Sjob } 804ef3f6f56Sjob } 805ef3f6f56Sjob 806ef3f6f56Sjob if (outformats & FORMAT_JSON) 8077aabcda0Sclaudio json_do_end(); 808ef3f6f56Sjob } 809