1*489e308aSjob /* $OpenBSD: print.c,v 1.36 2023/04/20 15:12:19 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" 31714f4e3fSclaudio 32714f4e3fSclaudio static const char * 33254fd372Sclaudio pretty_key_id(const char *hex) 34714f4e3fSclaudio { 35714f4e3fSclaudio static char buf[128]; /* bigger than SHA_DIGEST_LENGTH * 3 */ 36714f4e3fSclaudio size_t i; 37714f4e3fSclaudio 38714f4e3fSclaudio for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) { 39254fd372Sclaudio if (i % 3 == 2) 40714f4e3fSclaudio buf[i] = ':'; 41714f4e3fSclaudio else 42714f4e3fSclaudio buf[i] = *hex++; 43714f4e3fSclaudio } 44714f4e3fSclaudio if (i == sizeof(buf)) 45714f4e3fSclaudio memcpy(buf + sizeof(buf) - 4, "...", 4); 46254fd372Sclaudio else 47254fd372Sclaudio buf[i] = '\0'; 48714f4e3fSclaudio return buf; 49714f4e3fSclaudio } 50714f4e3fSclaudio 51220c707cSclaudio char * 52220c707cSclaudio time2str(time_t t) 53220c707cSclaudio { 54220c707cSclaudio static char buf[64]; 55220c707cSclaudio struct tm tm; 56220c707cSclaudio 57220c707cSclaudio if (gmtime_r(&t, &tm) == NULL) 58220c707cSclaudio return "could not convert time"; 59220c707cSclaudio 60cc6f004eSjob strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm); 61cc6f004eSjob 62220c707cSclaudio return buf; 63220c707cSclaudio } 64220c707cSclaudio 65714f4e3fSclaudio void 66714f4e3fSclaudio tal_print(const struct tal *p) 67714f4e3fSclaudio { 68e911df76Sjob char *ski; 69e911df76Sjob EVP_PKEY *pk; 70e911df76Sjob RSA *r; 71e911df76Sjob const unsigned char *der; 72e911df76Sjob unsigned char *rder = NULL; 73e911df76Sjob unsigned char md[SHA_DIGEST_LENGTH]; 74e911df76Sjob int rder_len; 75714f4e3fSclaudio size_t i; 76714f4e3fSclaudio 77e911df76Sjob der = p->pkey; 78e911df76Sjob pk = d2i_PUBKEY(NULL, &der, p->pkeysz); 79e911df76Sjob if (pk == NULL) 80e911df76Sjob errx(1, "d2i_PUBKEY failed in %s", __func__); 81e911df76Sjob 82e911df76Sjob r = EVP_PKEY_get0_RSA(pk); 83e911df76Sjob if (r == NULL) 84e911df76Sjob errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__); 85e911df76Sjob if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0) 86e911df76Sjob errx(1, "i2d_RSAPublicKey failed in %s", __func__); 87e911df76Sjob 88e911df76Sjob if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL)) 89e911df76Sjob errx(1, "EVP_Digest failed in %s", __func__); 90e911df76Sjob 91e911df76Sjob ski = hex_encode(md, SHA_DIGEST_LENGTH); 92e911df76Sjob 93530399e8Sjob if (outformats & FORMAT_JSON) { 94530399e8Sjob printf("\t\"type\": \"tal\",\n"); 953b3f075aSjob printf("\t\"name\": \"%s\",\n", p->descr); 963b3f075aSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(ski)); 97530399e8Sjob printf("\t\"trust_anchor_locations\": ["); 98530399e8Sjob for (i = 0; i < p->urisz; i++) { 99530399e8Sjob printf("\"%s\"", p->uri[i]); 100530399e8Sjob if (i + 1 < p->urisz) 101530399e8Sjob printf(", "); 102530399e8Sjob } 1033b3f075aSjob printf("],\n"); 104530399e8Sjob } else { 105530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 106530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 1074486d057Sjob printf("Trust anchor locations: "); 1084486d057Sjob for (i = 0; i < p->urisz; i++) { 1094486d057Sjob if (i > 0) 1104486d057Sjob printf("%26s", ""); 1114486d057Sjob printf("%s\n", p->uri[i]); 1124486d057Sjob } 113530399e8Sjob } 114e911df76Sjob 115e911df76Sjob EVP_PKEY_free(pk); 116e911df76Sjob free(rder); 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) { 147e0b87278Sjob printf("\t\"cert_issuer\": \"%s\",\n", issuer); 148530399e8Sjob printf("\t\"cert_serial\": \"%s\",\n", 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 159530399e8Sjob void 160714f4e3fSclaudio cert_print(const struct cert *p) 161714f4e3fSclaudio { 162530399e8Sjob size_t i, j; 163714f4e3fSclaudio char buf1[64], buf2[64]; 164714f4e3fSclaudio int sockt; 165530399e8Sjob 166530399e8Sjob if (outformats & FORMAT_JSON) { 167530399e8Sjob if (p->pubkey != NULL) 168530399e8Sjob printf("\t\"type\": \"router_key\",\n"); 169530399e8Sjob else 170530399e8Sjob printf("\t\"type\": \"ca_cert\",\n"); 171530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 172530399e8Sjob if (p->aki != NULL) 173530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 174530399e8Sjob x509_print(p->x509); 175530399e8Sjob if (p->aia != NULL) 176530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 177530399e8Sjob if (p->mft != NULL) 178530399e8Sjob printf("\t\"manifest\": \"%s\",\n", p->mft); 179530399e8Sjob if (p->repo != NULL) 180530399e8Sjob printf("\t\"carepository\": \"%s\",\n", p->repo); 181530399e8Sjob if (p->notify != NULL) 182530399e8Sjob printf("\t\"notify_url\": \"%s\",\n", p->notify); 183530399e8Sjob if (p->pubkey != NULL) 184530399e8Sjob printf("\t\"router_key\": \"%s\",\n", p->pubkey); 185f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 1869f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 187894936b4Sjob if (p->expires) 188894936b4Sjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 189530399e8Sjob printf("\t\"subordinate_resources\": [\n"); 190530399e8Sjob } else { 191714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 192714f4e3fSclaudio if (p->aki != NULL) 19367642cb5Stb printf("Authority key identifier: %s\n", 19467642cb5Stb pretty_key_id(p->aki)); 195530399e8Sjob x509_print(p->x509); 196714f4e3fSclaudio if (p->aia != NULL) 197714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 198714f4e3fSclaudio if (p->mft != NULL) 199714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 200714f4e3fSclaudio if (p->repo != NULL) 201714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 202714f4e3fSclaudio if (p->notify != NULL) 203714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 20414d83341Sjob if (p->pubkey != NULL) { 2056530cf17Sjob printf("BGPsec ECDSA public key: %s\n", 20667642cb5Stb p->pubkey); 2074dbb22b8Sjob printf("Router key not before: %s\n", 208f5999ddfSjob time2str(p->notbefore)); 2094dbb22b8Sjob printf("Router key not after: %s\n", 2109f544822Sjob time2str(p->notafter)); 211f5999ddfSjob } else { 2124dbb22b8Sjob printf("Certificate not before: %s\n", 213f5999ddfSjob time2str(p->notbefore)); 2144dbb22b8Sjob printf("Certificate not after: %s\n", 2159f544822Sjob time2str(p->notafter)); 216f5999ddfSjob } 2174486d057Sjob printf("Subordinate resources: "); 218530399e8Sjob } 219714f4e3fSclaudio 220530399e8Sjob for (i = 0; i < p->asz; i++) { 221714f4e3fSclaudio switch (p->as[i].type) { 222714f4e3fSclaudio case CERT_AS_ID: 223530399e8Sjob if (outformats & FORMAT_JSON) 224530399e8Sjob printf("\t\t{ \"asid\": %u }", p->as[i].id); 2254486d057Sjob else { 2264486d057Sjob if (i > 0) 2274486d057Sjob printf("%26s", ""); 2284486d057Sjob printf("AS: %u", p->as[i].id); 2294486d057Sjob } 230714f4e3fSclaudio break; 231714f4e3fSclaudio case CERT_AS_INHERIT: 232530399e8Sjob if (outformats & FORMAT_JSON) 233530399e8Sjob printf("\t\t{ \"asid_inherit\": \"true\" }"); 2344486d057Sjob else { 2354486d057Sjob if (i > 0) 2364486d057Sjob printf("%26s", ""); 2374486d057Sjob printf("AS: inherit"); 2384486d057Sjob } 239714f4e3fSclaudio break; 240714f4e3fSclaudio case CERT_AS_RANGE: 241530399e8Sjob if (outformats & FORMAT_JSON) 242530399e8Sjob printf("\t\t{ \"asrange\": { \"min\": %u, " 243530399e8Sjob "\"max\": %u }}", p->as[i].range.min, 244530399e8Sjob p->as[i].range.max); 2454486d057Sjob else { 2464486d057Sjob if (i > 0) 2474486d057Sjob printf("%26s", ""); 2484486d057Sjob printf("AS: %u -- %u", p->as[i].range.min, 2494486d057Sjob p->as[i].range.max); 2504486d057Sjob } 251714f4e3fSclaudio break; 252714f4e3fSclaudio } 253530399e8Sjob if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz) 254530399e8Sjob printf(",\n"); 255530399e8Sjob else 256530399e8Sjob printf("\n"); 257714f4e3fSclaudio } 258714f4e3fSclaudio 259530399e8Sjob for (j = 0; j < p->ipsz; j++) { 260530399e8Sjob switch (p->ips[j].type) { 261530399e8Sjob case CERT_IP_INHERIT: 262530399e8Sjob if (outformats & FORMAT_JSON) 263530399e8Sjob printf("\t\t{ \"ip_inherit\": \"true\" }"); 2644486d057Sjob else { 2654486d057Sjob if (i > 0 || j > 0) 2664486d057Sjob printf("%26s", ""); 2674486d057Sjob printf("IP: inherit"); 2684486d057Sjob } 269530399e8Sjob break; 270530399e8Sjob case CERT_IP_ADDR: 271530399e8Sjob ip_addr_print(&p->ips[j].ip, 272530399e8Sjob p->ips[j].afi, buf1, sizeof(buf1)); 273530399e8Sjob if (outformats & FORMAT_JSON) 274530399e8Sjob printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1); 2754486d057Sjob else { 2764486d057Sjob if (i > 0 || j > 0) 2774486d057Sjob printf("%26s", ""); 2784486d057Sjob printf("IP: %s", buf1); 2794486d057Sjob } 280530399e8Sjob break; 281530399e8Sjob case CERT_IP_RANGE: 282530399e8Sjob sockt = (p->ips[j].afi == AFI_IPV4) ? 283530399e8Sjob AF_INET : AF_INET6; 284530399e8Sjob inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1)); 285530399e8Sjob inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2)); 286530399e8Sjob if (outformats & FORMAT_JSON) 287530399e8Sjob printf("\t\t{ \"ip_range\": { \"min\": \"%s\"" 288530399e8Sjob ", \"max\": \"%s\" }}", buf1, buf2); 2894486d057Sjob else { 2904486d057Sjob if (i > 0 || j > 0) 2914486d057Sjob printf("%26s", ""); 2924486d057Sjob printf("IP: %s -- %s", buf1, buf2); 2934486d057Sjob } 294530399e8Sjob break; 295530399e8Sjob } 296530399e8Sjob if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz) 297530399e8Sjob printf(",\n"); 298530399e8Sjob else 299530399e8Sjob printf("\n"); 300530399e8Sjob } 301530399e8Sjob 302530399e8Sjob if (outformats & FORMAT_JSON) 303530399e8Sjob printf("\t],\n"); 304714f4e3fSclaudio } 305714f4e3fSclaudio 306714f4e3fSclaudio void 307220c707cSclaudio crl_print(const struct crl *p) 308220c707cSclaudio { 309220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 310220c707cSclaudio X509_REVOKED *rev; 3117cdd491fSclaudio ASN1_INTEGER *crlnum; 312e0b87278Sjob X509_NAME *xissuer; 313220c707cSclaudio int i; 314e0b87278Sjob char *issuer, *serial; 315220c707cSclaudio time_t t; 316220c707cSclaudio 317530399e8Sjob if (outformats & FORMAT_JSON) { 318530399e8Sjob printf("\t\"type\": \"crl\",\n"); 319530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 320530399e8Sjob } else 321220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 3227cdd491fSclaudio 323e0b87278Sjob xissuer = X509_CRL_get_issuer(p->x509_crl); 324e0b87278Sjob issuer = X509_NAME_oneline(xissuer, NULL, 0); 3257cdd491fSclaudio crlnum = X509_CRL_get_ext_d2i(p->x509_crl, NID_crl_number, NULL, NULL); 3267cdd491fSclaudio serial = x509_convert_seqnum(__func__, crlnum); 327e0b87278Sjob if (issuer != NULL && serial != NULL) { 328e0b87278Sjob if (outformats & FORMAT_JSON) { 329e0b87278Sjob printf("\t\"crl_issuer\": \"%s\",\n", issuer); 330530399e8Sjob printf("\t\"crl_serial\": \"%s\",\n", serial); 331e0b87278Sjob } else { 332e0b87278Sjob printf("CRL issuer: %s\n", issuer); 333e0b87278Sjob printf("CRL serial number: %s\n", serial); 334530399e8Sjob } 335e0b87278Sjob } 336e0b87278Sjob free(issuer); 3377cdd491fSclaudio free(serial); 3387cdd491fSclaudio ASN1_INTEGER_free(crlnum); 3397cdd491fSclaudio 340530399e8Sjob if (outformats & FORMAT_JSON) { 3419f544822Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->lastupdate); 3429f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->nextupdate); 343530399e8Sjob printf("\t\"revoked_certs\": [\n"); 344530399e8Sjob } else { 3454dbb22b8Sjob printf("CRL last update: %s\n", 3469f544822Sjob time2str(p->lastupdate)); 3474dbb22b8Sjob printf("CRL next update: %s\n", 3489f544822Sjob time2str(p->nextupdate)); 349530399e8Sjob printf("Revoked Certificates:\n"); 350530399e8Sjob } 351220c707cSclaudio 352220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 353220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 354220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3557cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3567cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 357220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 358530399e8Sjob if (serial != NULL) { 359530399e8Sjob if (outformats & FORMAT_JSON) { 360530399e8Sjob printf("\t\t{ \"serial\": \"%s\"", serial); 361530399e8Sjob printf(", \"date\": \"%s\" }", time2str(t)); 362530399e8Sjob if (i + 1 < sk_X509_REVOKED_num(revlist)) 363530399e8Sjob printf(","); 364530399e8Sjob printf("\n"); 365530399e8Sjob } else 3664486d057Sjob printf("%25s Serial: %8s Revocation Date: %s" 3674486d057Sjob "\n", "", serial, time2str(t)); 368530399e8Sjob } 3697cdd491fSclaudio free(serial); 370220c707cSclaudio } 371530399e8Sjob 372530399e8Sjob if (outformats & FORMAT_JSON) 373530399e8Sjob printf("\t],\n"); 374530399e8Sjob else if (i == 0) 375220c707cSclaudio printf("No Revoked Certificates\n"); 376220c707cSclaudio } 377220c707cSclaudio 378220c707cSclaudio void 379530399e8Sjob mft_print(const X509 *x, const struct mft *p) 380714f4e3fSclaudio { 381714f4e3fSclaudio size_t i; 382714f4e3fSclaudio char *hash; 383714f4e3fSclaudio 384530399e8Sjob if (outformats & FORMAT_JSON) { 385530399e8Sjob printf("\t\"type\": \"manifest\",\n"); 386530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 387530399e8Sjob x509_print(x); 388530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 389530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 3902cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 391530399e8Sjob printf("\t\"manifest_number\": \"%s\",\n", p->seqnum); 3921bb1e509Sjob if (p->signtime != 0) 3931bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 3941bb1e509Sjob (long long)p->signtime); 3954dbb22b8Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->thisupdate); 3964dbb22b8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->nextupdate); 397894936b4Sjob if (p->expires) 398894936b4Sjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 399530399e8Sjob } else { 400714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 401714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 402530399e8Sjob x509_print(x); 403714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4042cf0e122Sjob printf("Subject info access: %s\n", p->sia); 405*489e308aSjob printf("Manifest number: %s\n", p->seqnum); 4061bb1e509Sjob if (p->signtime != 0) 4071bb1e509Sjob printf("Signing time: %s\n", 4081bb1e509Sjob time2str(p->signtime)); 4094dbb22b8Sjob printf("Manifest this update: %s\n", time2str(p->thisupdate)); 4104dbb22b8Sjob printf("Manifest next update: %s\n", time2str(p->nextupdate)); 4114486d057Sjob printf("Files and hashes: "); 412530399e8Sjob } 413530399e8Sjob 414714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 415530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 416530399e8Sjob printf("\t\"filesandhashes\": [\n"); 417530399e8Sjob 418714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 419714f4e3fSclaudio &hash) == -1) 420714f4e3fSclaudio errx(1, "base64_encode failure"); 421530399e8Sjob 422530399e8Sjob if (outformats & FORMAT_JSON) { 423530399e8Sjob printf("\t\t{ \"filename\": \"%s\",", p->files[i].file); 424530399e8Sjob printf(" \"hash\": \"%s\" }", hash); 425530399e8Sjob if (i + 1 < p->filesz) 426530399e8Sjob printf(","); 427530399e8Sjob printf("\n"); 428530399e8Sjob } else { 4294486d057Sjob if (i > 0) 4304486d057Sjob printf("%26s", ""); 4314486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file, 4324486d057Sjob hash); 433530399e8Sjob } 434530399e8Sjob 435714f4e3fSclaudio free(hash); 436714f4e3fSclaudio } 437530399e8Sjob 438530399e8Sjob if (outformats & FORMAT_JSON) 439530399e8Sjob printf("\t],\n"); 440714f4e3fSclaudio } 441714f4e3fSclaudio 442714f4e3fSclaudio void 443530399e8Sjob roa_print(const X509 *x, const struct roa *p) 444714f4e3fSclaudio { 445714f4e3fSclaudio char buf[128]; 446714f4e3fSclaudio size_t i; 447714f4e3fSclaudio 448530399e8Sjob if (outformats & FORMAT_JSON) { 449530399e8Sjob printf("\t\"type\": \"roa\",\n"); 450530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 451530399e8Sjob x509_print(x); 452530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 453530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 4542cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 4551bb1e509Sjob if (p->signtime != 0) 4561bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 4571bb1e509Sjob (long long)p->signtime); 458f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 4599f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 4609c1f5d6bSjob if (p->expires) 4619c1f5d6bSjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 462530399e8Sjob } else { 463714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 464530399e8Sjob x509_print(x); 465714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 466714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4672cf0e122Sjob printf("Subject info access: %s\n", p->sia); 4681bb1e509Sjob if (p->signtime != 0) 4691bb1e509Sjob printf("Signing time: %s\n", 4701bb1e509Sjob time2str(p->signtime)); 4714dbb22b8Sjob printf("ROA not before: %s\n", 472f5999ddfSjob time2str(p->notbefore)); 4734dbb22b8Sjob printf("ROA not after: %s\n", time2str(p->notafter)); 474714f4e3fSclaudio printf("asID: %u\n", p->asid); 4754486d057Sjob printf("IP address blocks: "); 476530399e8Sjob } 477530399e8Sjob 478714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 479530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 480530399e8Sjob printf("\t\"vrps\": [\n"); 481530399e8Sjob 482714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 483714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 484530399e8Sjob 485530399e8Sjob if (outformats & FORMAT_JSON) { 486530399e8Sjob printf("\t\t{ \"prefix\": \"%s\",", buf); 487530399e8Sjob printf(" \"asid\": %u,", p->asid); 488530399e8Sjob printf(" \"maxlen\": %hhu }", p->ips[i].maxlength); 489530399e8Sjob if (i + 1 < p->ipsz) 490530399e8Sjob printf(","); 491530399e8Sjob printf("\n"); 4924486d057Sjob } else { 4934486d057Sjob if (i > 0) 4944486d057Sjob printf("%26s", ""); 4954486d057Sjob printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength); 4964486d057Sjob } 497714f4e3fSclaudio } 498530399e8Sjob 499530399e8Sjob if (outformats & FORMAT_JSON) 500530399e8Sjob printf("\t],\n"); 501714f4e3fSclaudio } 502714f4e3fSclaudio 503714f4e3fSclaudio void 504530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 505714f4e3fSclaudio { 506530399e8Sjob size_t i; 507530399e8Sjob 508530399e8Sjob if (outformats & FORMAT_JSON) { 509530399e8Sjob printf("\t\"type\": \"gbr\",\n"); 510530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 511530399e8Sjob x509_print(x); 512530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 513530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 5142cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 5151bb1e509Sjob if (p->signtime != 0) 5161bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 5171bb1e509Sjob (long long)p->signtime); 518f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 5199f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 520894936b4Sjob if (p->expires) 521894936b4Sjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 522530399e8Sjob printf("\t\"vcard\": \""); 523530399e8Sjob for (i = 0; i < strlen(p->vcard); i++) { 524530399e8Sjob if (p->vcard[i] == '"') 525530399e8Sjob printf("\\\""); 526530399e8Sjob if (p->vcard[i] == '\r') 527530399e8Sjob continue; 528530399e8Sjob if (p->vcard[i] == '\n') 529530399e8Sjob printf("\\r\\n"); 530530399e8Sjob else 531530399e8Sjob putchar(p->vcard[i]); 532530399e8Sjob } 533530399e8Sjob printf("\",\n"); 534530399e8Sjob } else { 535714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 536530399e8Sjob x509_print(x); 537714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 538714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 5392cf0e122Sjob printf("Subject info access: %s\n", p->sia); 5401bb1e509Sjob if (p->signtime != 0) 5411bb1e509Sjob printf("Signing time: %s\n", 5421bb1e509Sjob time2str(p->signtime)); 5434dbb22b8Sjob printf("GBR not before: %s\n", 544f5999ddfSjob time2str(p->notbefore)); 5454dbb22b8Sjob printf("GBR not after: %s\n", time2str(p->notafter)); 546714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 547714f4e3fSclaudio } 548530399e8Sjob } 54904834fbdSjob 55004834fbdSjob void 55104834fbdSjob rsc_print(const X509 *x, const struct rsc *p) 55204834fbdSjob { 55328439bbcSjob char buf1[64], buf2[64]; 55404834fbdSjob char *hash; 55504834fbdSjob int sockt; 55604834fbdSjob size_t i, j; 55704834fbdSjob 55804834fbdSjob if (outformats & FORMAT_JSON) { 55904834fbdSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 56004834fbdSjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 56104834fbdSjob x509_print(x); 56204834fbdSjob printf("\t\"aia\": \"%s\",\n", p->aia); 5631bb1e509Sjob if (p->signtime != 0) 5641bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 5651bb1e509Sjob (long long)p->signtime); 566f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 5679f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 568894936b4Sjob if (p->expires) 569894936b4Sjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 57004834fbdSjob printf("\t\"signed_with_resources\": [\n"); 57104834fbdSjob } else { 57204834fbdSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 57304834fbdSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 57404834fbdSjob x509_print(x); 57504834fbdSjob printf("Authority info access: %s\n", p->aia); 5761bb1e509Sjob if (p->signtime != 0) 5771bb1e509Sjob printf("Signing time: %s\n", 5781bb1e509Sjob time2str(p->signtime)); 5794dbb22b8Sjob printf("RSC not before: %s\n", 580f5999ddfSjob time2str(p->notbefore)); 5814dbb22b8Sjob printf("RSC not after: %s\n", time2str(p->notafter)); 5824486d057Sjob printf("Signed with resources: "); 58304834fbdSjob } 58404834fbdSjob 58504834fbdSjob for (i = 0; i < p->asz; i++) { 58604834fbdSjob switch (p->as[i].type) { 58704834fbdSjob case CERT_AS_ID: 58804834fbdSjob if (outformats & FORMAT_JSON) 58904834fbdSjob printf("\t\t{ \"asid\": %u }", p->as[i].id); 5904486d057Sjob else { 5914486d057Sjob if (i > 0) 5924486d057Sjob printf("%26s", ""); 5934486d057Sjob printf("AS: %u", p->as[i].id); 5944486d057Sjob } 59504834fbdSjob break; 59604834fbdSjob case CERT_AS_RANGE: 59704834fbdSjob if (outformats & FORMAT_JSON) 59804834fbdSjob printf("\t\t{ \"asrange\": { \"min\": %u, " 59904834fbdSjob "\"max\": %u }}", p->as[i].range.min, 60004834fbdSjob p->as[i].range.max); 6014486d057Sjob else { 6024486d057Sjob if (i > 0) 6034486d057Sjob printf("%26s", ""); 6044486d057Sjob printf("AS: %u -- %u", p->as[i].range.min, 6054486d057Sjob p->as[i].range.max); 6064486d057Sjob } 60704834fbdSjob break; 60804834fbdSjob case CERT_AS_INHERIT: 60904834fbdSjob /* inheritance isn't possible in RSC */ 61004834fbdSjob break; 61104834fbdSjob } 61204834fbdSjob if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz) 61304834fbdSjob printf(",\n"); 61404834fbdSjob else 61504834fbdSjob printf("\n"); 61604834fbdSjob } 61704834fbdSjob 61804834fbdSjob for (j = 0; j < p->ipsz; j++) { 61904834fbdSjob switch (p->ips[j].type) { 62004834fbdSjob case CERT_IP_ADDR: 62104834fbdSjob ip_addr_print(&p->ips[j].ip, 62204834fbdSjob p->ips[j].afi, buf1, sizeof(buf1)); 62304834fbdSjob if (outformats & FORMAT_JSON) 62404834fbdSjob printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1); 6254486d057Sjob else { 6264486d057Sjob if (i > 0 || j > 0) 6274486d057Sjob printf("%26s", ""); 6284486d057Sjob printf("IP: %s", buf1); 6294486d057Sjob } 63004834fbdSjob break; 63104834fbdSjob case CERT_IP_RANGE: 63204834fbdSjob sockt = (p->ips[j].afi == AFI_IPV4) ? 63304834fbdSjob AF_INET : AF_INET6; 63404834fbdSjob inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1)); 63504834fbdSjob inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2)); 63604834fbdSjob if (outformats & FORMAT_JSON) 63704834fbdSjob printf("\t\t{ \"ip_range\": { \"min\": \"%s\"" 63804834fbdSjob ", \"max\": \"%s\" }}", buf1, buf2); 6394486d057Sjob else { 6404486d057Sjob if (i > 0 || j > 0) 6414486d057Sjob printf("%26s", ""); 6424486d057Sjob printf("IP: %s -- %s", buf1, buf2); 6434486d057Sjob } 64404834fbdSjob break; 64504834fbdSjob case CERT_IP_INHERIT: 64604834fbdSjob /* inheritance isn't possible in RSC */ 64704834fbdSjob break; 64804834fbdSjob } 64904834fbdSjob if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz) 65004834fbdSjob printf(",\n"); 65104834fbdSjob else 65204834fbdSjob printf("\n"); 65304834fbdSjob } 65404834fbdSjob 65504834fbdSjob if (outformats & FORMAT_JSON) { 65604834fbdSjob printf("\t],\n"); 65704834fbdSjob printf("\t\"filenamesandhashes\": [\n"); 65804834fbdSjob } else 6594486d057Sjob printf("Filenames and hashes: "); 66004834fbdSjob 66104834fbdSjob for (i = 0; i < p->filesz; i++) { 66204834fbdSjob if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 66304834fbdSjob &hash) == -1) 66404834fbdSjob errx(1, "base64_encode failure"); 66504834fbdSjob 66604834fbdSjob if (outformats & FORMAT_JSON) { 66704834fbdSjob printf("\t\t{ \"filename\": \"%s\",", 66804834fbdSjob p->files[i].filename ? p->files[i].filename : ""); 66904834fbdSjob printf(" \"hash_digest\": \"%s\" }", hash); 67004834fbdSjob if (i + 1 < p->filesz) 67104834fbdSjob printf(","); 67204834fbdSjob printf("\n"); 67304834fbdSjob } else { 6744486d057Sjob if (i > 0) 6754486d057Sjob printf("%26s", ""); 6764486d057Sjob printf("%zu: %s (hash: %s)\n", i + 1, 6774486d057Sjob p->files[i].filename ? p->files[i].filename 6784486d057Sjob : "no filename", hash); 67904834fbdSjob } 68004834fbdSjob 68104834fbdSjob free(hash); 68204834fbdSjob } 68304834fbdSjob 68404834fbdSjob if (outformats & FORMAT_JSON) 68504834fbdSjob printf("\t],\n"); 68604834fbdSjob } 687a29ddfd5Sjob 688a29ddfd5Sjob void 689a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p) 690a29ddfd5Sjob { 691a29ddfd5Sjob size_t i; 692a29ddfd5Sjob 693a29ddfd5Sjob if (outformats & FORMAT_JSON) { 694a29ddfd5Sjob printf("\t\"type\": \"aspa\",\n"); 695a29ddfd5Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 696a29ddfd5Sjob x509_print(x); 697a29ddfd5Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 698a29ddfd5Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 6992cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 7001bb1e509Sjob if (p->signtime != 0) 7011bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 7021bb1e509Sjob (long long)p->signtime); 703f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 7049f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 7059c1f5d6bSjob if (p->expires) 7069c1f5d6bSjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 707a29ddfd5Sjob printf("\t\"customer_asid\": %u,\n", p->custasid); 708a29ddfd5Sjob printf("\t\"provider_set\": [\n"); 709a29ddfd5Sjob for (i = 0; i < p->providersz; i++) { 710a29ddfd5Sjob printf("\t\t{ \"asid\": %u", p->providers[i].as); 711a29ddfd5Sjob if (p->providers[i].afi == AFI_IPV4) 712a29ddfd5Sjob printf(", \"afi_limit\": \"ipv4\""); 713a29ddfd5Sjob if (p->providers[i].afi == AFI_IPV6) 714a29ddfd5Sjob printf(", \"afi_limit\": \"ipv6\""); 715a29ddfd5Sjob printf(" }"); 716a29ddfd5Sjob if (i + 1 < p->providersz) 717a29ddfd5Sjob printf(","); 718a29ddfd5Sjob printf("\n"); 719a29ddfd5Sjob } 720a29ddfd5Sjob printf("\t],\n"); 721a29ddfd5Sjob } else { 722a29ddfd5Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 723a29ddfd5Sjob x509_print(x); 724a29ddfd5Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 725a29ddfd5Sjob printf("Authority info access: %s\n", p->aia); 7262cf0e122Sjob printf("Subject info access: %s\n", p->sia); 7271bb1e509Sjob if (p->signtime != 0) 7281bb1e509Sjob printf("Signing time: %s\n", 7291bb1e509Sjob time2str(p->signtime)); 7304dbb22b8Sjob printf("ASPA not before: %s\n", 731f5999ddfSjob time2str(p->notbefore)); 7324dbb22b8Sjob printf("ASPA not after: %s\n", time2str(p->notafter)); 733a29ddfd5Sjob printf("Customer AS: %u\n", p->custasid); 7344486d057Sjob printf("Provider Set: "); 735a29ddfd5Sjob for (i = 0; i < p->providersz; i++) { 7364486d057Sjob if (i > 0) 7374486d057Sjob printf("%26s", ""); 7384486d057Sjob printf("AS: %d", p->providers[i].as); 739a29ddfd5Sjob switch (p->providers[i].afi) { 740a29ddfd5Sjob case AFI_IPV4: 741a29ddfd5Sjob printf(" (IPv4 only)"); 742a29ddfd5Sjob break; 743a29ddfd5Sjob case AFI_IPV6: 744a29ddfd5Sjob printf(" (IPv6 only)"); 745a29ddfd5Sjob break; 746a29ddfd5Sjob default: 747a29ddfd5Sjob break; 748a29ddfd5Sjob } 749a29ddfd5Sjob printf("\n"); 750a29ddfd5Sjob } 751a29ddfd5Sjob } 752a29ddfd5Sjob } 753ee2a33daSjob 754ee2a33daSjob static void 755ee2a33daSjob takey_print(char *name, const struct takey *t) 756ee2a33daSjob { 757ee2a33daSjob char *spki = NULL; 758ee2a33daSjob size_t i, j = 0; 759ee2a33daSjob 760ee2a33daSjob if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0) 761ee2a33daSjob errx(1, "base64_encode failed in %s", __func__); 762ee2a33daSjob 763ee2a33daSjob if (outformats & FORMAT_JSON) { 764ee2a33daSjob printf("\t\t{\n\t\t\t\"name\": \"%s\",\n", name); 765ee2a33daSjob printf("\t\t\t\"comments\": ["); 766ee2a33daSjob for (i = 0; i < t->commentsz; i++) { 767ee2a33daSjob printf("\"%s\"", t->comments[i]); 768ee2a33daSjob if (i + 1 < t->commentsz) 769ee2a33daSjob printf(", "); 770ee2a33daSjob } 771ee2a33daSjob printf("],\n"); 772ee2a33daSjob printf("\t\t\t\"uris\": ["); 773ee2a33daSjob for (i = 0; i < t->urisz; i++) { 774ee2a33daSjob printf("\"%s\"", t->uris[i]); 775ee2a33daSjob if (i + 1 < t->urisz) 776ee2a33daSjob printf(", "); 777ee2a33daSjob } 778ee2a33daSjob printf("],\n"); 779ee2a33daSjob printf("\t\t\t\"spki\": \"%s\"\n\t\t}", spki); 780ee2a33daSjob } else { 781ee2a33daSjob printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name); 782ee2a33daSjob 783ee2a33daSjob for (i = 0; i < t->commentsz; i++) { 784ee2a33daSjob printf("\t# %s\n", t->comments[i]); 785ee2a33daSjob } 786ee2a33daSjob 787ee2a33daSjob for (i = 0; i < t->urisz; i++) { 788ee2a33daSjob printf("\t%s\n\n\t", t->uris[i]); 789ee2a33daSjob } 790ee2a33daSjob 791ee2a33daSjob for (i = 0; i < strlen(spki); i++) { 792ee2a33daSjob printf("%c", spki[i]); 793ee2a33daSjob j++; 794ee2a33daSjob if (j == 64) { 795ee2a33daSjob printf("\n\t"); 796ee2a33daSjob j = 0; 797ee2a33daSjob } 798ee2a33daSjob } 799ee2a33daSjob 800ee2a33daSjob printf("\n\n"); 801ee2a33daSjob } 802ee2a33daSjob 803ee2a33daSjob free(spki); 804ee2a33daSjob } 805ee2a33daSjob 806ee2a33daSjob void 807ee2a33daSjob tak_print(const X509 *x, const struct tak *p) 808ee2a33daSjob { 809ee2a33daSjob if (outformats & FORMAT_JSON) { 810ee2a33daSjob printf("\t\"type\": \"tak\",\n"); 811ee2a33daSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 812ee2a33daSjob x509_print(x); 813ee2a33daSjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 814ee2a33daSjob printf("\t\"aia\": \"%s\",\n", p->aia); 8152cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 8161bb1e509Sjob if (p->signtime != 0) 8171bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 8181bb1e509Sjob (long long)p->signtime); 819f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 8209f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 821894936b4Sjob if (p->expires) 822894936b4Sjob printf("\t\"expires\": %lld,\n", (long long)p->expires); 823ee2a33daSjob printf("\t\"takeys\": [\n"); 824ee2a33daSjob } else { 825ee2a33daSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 826ee2a33daSjob x509_print(x); 827ee2a33daSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 828ee2a33daSjob printf("Authority info access: %s\n", p->aia); 8292cf0e122Sjob printf("Subject info access: %s\n", p->sia); 8301bb1e509Sjob if (p->signtime != 0) 8311bb1e509Sjob printf("Signing time: %s\n", 8321bb1e509Sjob time2str(p->signtime)); 8334dbb22b8Sjob printf("TAK not before: %s\n", 834f5999ddfSjob time2str(p->notbefore)); 8354dbb22b8Sjob printf("TAK not after: %s\n", time2str(p->notafter)); 836ee2a33daSjob } 837ee2a33daSjob 838ee2a33daSjob takey_print("current", p->current); 839ee2a33daSjob 840ee2a33daSjob if (p->predecessor != NULL) { 841ee2a33daSjob if (outformats & FORMAT_JSON) 842ee2a33daSjob printf(",\n"); 843ee2a33daSjob takey_print("predecessor", p->predecessor); 844ee2a33daSjob } 845ee2a33daSjob 846ee2a33daSjob if (p->successor != NULL) { 847ee2a33daSjob if (outformats & FORMAT_JSON) 848ee2a33daSjob printf(",\n"); 849ee2a33daSjob takey_print("successor", p->successor); 850ee2a33daSjob } 851ee2a33daSjob 852ee2a33daSjob if (outformats & FORMAT_JSON) 853ee2a33daSjob printf("\n\t],\n"); 854ee2a33daSjob } 855ef3f6f56Sjob 856ef3f6f56Sjob void 857ef3f6f56Sjob geofeed_print(const X509 *x, const struct geofeed *p) 858ef3f6f56Sjob { 859ef3f6f56Sjob char buf[128]; 860ef3f6f56Sjob size_t i; 861ef3f6f56Sjob 862ef3f6f56Sjob if (outformats & FORMAT_JSON) { 863ef3f6f56Sjob printf("\t\"type\": \"geofeed\",\n"); 864ef3f6f56Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 865ef3f6f56Sjob x509_print(x); 866ef3f6f56Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 867ef3f6f56Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 8681bb1e509Sjob if (p->signtime != 0) 8691bb1e509Sjob printf("\t\"signing_time\": %lld,\n", 8701bb1e509Sjob (long long)p->signtime); 871f5999ddfSjob printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore); 8729f544822Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->notafter); 873ef3f6f56Sjob printf("\t\"records\": [\n"); 874ef3f6f56Sjob } else { 875ef3f6f56Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 876ef3f6f56Sjob x509_print(x); 877ef3f6f56Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 878ef3f6f56Sjob printf("Authority info access: %s\n", p->aia); 8791bb1e509Sjob if (p->signtime != 0) 8801bb1e509Sjob printf("Signing time: %s\n", 8811bb1e509Sjob time2str(p->signtime)); 8824dbb22b8Sjob printf("Geofeed not before: %s\n", 883f5999ddfSjob time2str(p->notbefore)); 8844dbb22b8Sjob printf("Geofeed not after: %s\n", time2str(p->notafter)); 885bd19f13dSjob printf("Geofeed CSV records: "); 886ef3f6f56Sjob } 887ef3f6f56Sjob 888ef3f6f56Sjob for (i = 0; i < p->geoipsz; i++) { 889ef3f6f56Sjob if (p->geoips[i].ip->type != CERT_IP_ADDR) 890ef3f6f56Sjob continue; 891ef3f6f56Sjob 892ef3f6f56Sjob ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf, 893ef3f6f56Sjob sizeof(buf)); 894ef3f6f56Sjob if (outformats & FORMAT_JSON) 895ef3f6f56Sjob printf("\t\t{ \"prefix\": \"%s\", \"location\": \"%s\"" 896ef3f6f56Sjob "}", buf, p->geoips[i].loc); 8974486d057Sjob else { 8984486d057Sjob if (i > 0) 8994486d057Sjob printf("%26s", ""); 9004486d057Sjob printf("IP: %s (%s)", buf, p->geoips[i].loc); 9014486d057Sjob } 902ef3f6f56Sjob 903ef3f6f56Sjob if (outformats & FORMAT_JSON && i + 1 < p->geoipsz) 904ef3f6f56Sjob printf(",\n"); 905ef3f6f56Sjob else 906ef3f6f56Sjob printf("\n"); 907ef3f6f56Sjob } 908ef3f6f56Sjob 909ef3f6f56Sjob if (outformats & FORMAT_JSON) 910ef3f6f56Sjob printf("\t],\n"); 911ef3f6f56Sjob } 912