1*14d83341Sjob /* $OpenBSD: print.c,v 1.20 2022/11/16 08:57:38 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 60220c707cSclaudio strftime(buf, sizeof(buf), "%h %d %T %Y %Z", &tm); 61220c707cSclaudio return buf; 62220c707cSclaudio } 63220c707cSclaudio 64714f4e3fSclaudio void 65714f4e3fSclaudio tal_print(const struct tal *p) 66714f4e3fSclaudio { 67e911df76Sjob char *ski; 68e911df76Sjob EVP_PKEY *pk; 69e911df76Sjob RSA *r; 70e911df76Sjob const unsigned char *der; 71e911df76Sjob unsigned char *rder = NULL; 72e911df76Sjob unsigned char md[SHA_DIGEST_LENGTH]; 73e911df76Sjob int rder_len; 74714f4e3fSclaudio size_t i; 75714f4e3fSclaudio 76e911df76Sjob der = p->pkey; 77e911df76Sjob pk = d2i_PUBKEY(NULL, &der, p->pkeysz); 78e911df76Sjob if (pk == NULL) 79e911df76Sjob errx(1, "d2i_PUBKEY failed in %s", __func__); 80e911df76Sjob 81e911df76Sjob r = EVP_PKEY_get0_RSA(pk); 82e911df76Sjob if (r == NULL) 83e911df76Sjob errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__); 84e911df76Sjob if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0) 85e911df76Sjob errx(1, "i2d_RSAPublicKey failed in %s", __func__); 86e911df76Sjob 87e911df76Sjob if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL)) 88e911df76Sjob errx(1, "EVP_Digest failed in %s", __func__); 89e911df76Sjob 90e911df76Sjob ski = hex_encode(md, SHA_DIGEST_LENGTH); 91e911df76Sjob 92530399e8Sjob if (outformats & FORMAT_JSON) { 93530399e8Sjob printf("\t\"type\": \"tal\",\n"); 943b3f075aSjob printf("\t\"name\": \"%s\",\n", p->descr); 953b3f075aSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(ski)); 96530399e8Sjob printf("\t\"trust_anchor_locations\": ["); 97530399e8Sjob for (i = 0; i < p->urisz; i++) { 98530399e8Sjob printf("\"%s\"", p->uri[i]); 99530399e8Sjob if (i + 1 < p->urisz) 100530399e8Sjob printf(", "); 101530399e8Sjob } 1023b3f075aSjob printf("],\n"); 103530399e8Sjob } else { 104530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 105530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 106e911df76Sjob printf("Trust anchor locations:\n"); 107714f4e3fSclaudio for (i = 0; i < p->urisz; i++) 108e911df76Sjob printf("%5zu: %s\n", i + 1, p->uri[i]); 109530399e8Sjob } 110e911df76Sjob 111e911df76Sjob EVP_PKEY_free(pk); 112e911df76Sjob free(rder); 113e911df76Sjob free(ski); 114714f4e3fSclaudio } 115714f4e3fSclaudio 116714f4e3fSclaudio void 117530399e8Sjob x509_print(const X509 *x) 118530399e8Sjob { 119530399e8Sjob const ASN1_INTEGER *xserial; 120530399e8Sjob char *serial = NULL; 121530399e8Sjob 122530399e8Sjob xserial = X509_get0_serialNumber(x); 123530399e8Sjob if (xserial == NULL) { 124530399e8Sjob warnx("X509_get0_serialNumber failed in %s", __func__); 125530399e8Sjob goto out; 126530399e8Sjob } 127530399e8Sjob 128530399e8Sjob serial = x509_convert_seqnum(__func__, xserial); 129530399e8Sjob if (serial == NULL) { 130530399e8Sjob warnx("x509_convert_seqnum failed in %s", __func__); 131530399e8Sjob goto out; 132530399e8Sjob } 133530399e8Sjob 134530399e8Sjob if (outformats & FORMAT_JSON) { 135530399e8Sjob printf("\t\"cert_serial\": \"%s\",\n", serial); 136530399e8Sjob } else { 137530399e8Sjob printf("Certificate serial: %s\n", serial); 138530399e8Sjob } 139530399e8Sjob 140530399e8Sjob out: 141530399e8Sjob free(serial); 142530399e8Sjob } 143530399e8Sjob 144530399e8Sjob void 145714f4e3fSclaudio cert_print(const struct cert *p) 146714f4e3fSclaudio { 147530399e8Sjob size_t i, j; 148714f4e3fSclaudio char buf1[64], buf2[64]; 149714f4e3fSclaudio int sockt; 150714f4e3fSclaudio char tbuf[21]; 151714f4e3fSclaudio 152530399e8Sjob strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); 153530399e8Sjob 154530399e8Sjob if (outformats & FORMAT_JSON) { 155530399e8Sjob if (p->pubkey != NULL) 156530399e8Sjob printf("\t\"type\": \"router_key\",\n"); 157530399e8Sjob else 158530399e8Sjob printf("\t\"type\": \"ca_cert\",\n"); 159530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 160530399e8Sjob if (p->aki != NULL) 161530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 162530399e8Sjob x509_print(p->x509); 163530399e8Sjob if (p->aia != NULL) 164530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 165530399e8Sjob if (p->mft != NULL) 166530399e8Sjob printf("\t\"manifest\": \"%s\",\n", p->mft); 167530399e8Sjob if (p->repo != NULL) 168530399e8Sjob printf("\t\"carepository\": \"%s\",\n", p->repo); 169530399e8Sjob if (p->notify != NULL) 170530399e8Sjob printf("\t\"notify_url\": \"%s\",\n", p->notify); 171530399e8Sjob if (p->pubkey != NULL) 172530399e8Sjob printf("\t\"router_key\": \"%s\",\n", p->pubkey); 173530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 174530399e8Sjob printf("\t\"subordinate_resources\": [\n"); 175530399e8Sjob } else { 176714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 177714f4e3fSclaudio if (p->aki != NULL) 17867642cb5Stb printf("Authority key identifier: %s\n", 17967642cb5Stb pretty_key_id(p->aki)); 180530399e8Sjob x509_print(p->x509); 181714f4e3fSclaudio if (p->aia != NULL) 182714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 183714f4e3fSclaudio if (p->mft != NULL) 184714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 185714f4e3fSclaudio if (p->repo != NULL) 186714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 187714f4e3fSclaudio if (p->notify != NULL) 188714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 189*14d83341Sjob if (p->pubkey != NULL) { 1906530cf17Sjob printf("BGPsec ECDSA public key: %s\n", 19167642cb5Stb p->pubkey); 1926530cf17Sjob printf("Router key valid until: %s\n", tbuf); 193*14d83341Sjob } else 194*14d83341Sjob printf("Certificate valid until: %s\n", tbuf); 195714f4e3fSclaudio printf("Subordinate Resources:\n"); 196530399e8Sjob } 197714f4e3fSclaudio 198530399e8Sjob for (i = 0; i < p->asz; i++) { 199714f4e3fSclaudio switch (p->as[i].type) { 200714f4e3fSclaudio case CERT_AS_ID: 201530399e8Sjob if (outformats & FORMAT_JSON) 202530399e8Sjob printf("\t\t{ \"asid\": %u }", p->as[i].id); 203530399e8Sjob else 204530399e8Sjob printf("%5zu: AS: %u", i + 1, p->as[i].id); 205714f4e3fSclaudio break; 206714f4e3fSclaudio case CERT_AS_INHERIT: 207530399e8Sjob if (outformats & FORMAT_JSON) 208530399e8Sjob printf("\t\t{ \"asid_inherit\": \"true\" }"); 209530399e8Sjob else 210530399e8Sjob printf("%5zu: AS: inherit", i + 1); 211714f4e3fSclaudio break; 212714f4e3fSclaudio case CERT_AS_RANGE: 213530399e8Sjob if (outformats & FORMAT_JSON) 214530399e8Sjob printf("\t\t{ \"asrange\": { \"min\": %u, " 215530399e8Sjob "\"max\": %u }}", p->as[i].range.min, 216530399e8Sjob p->as[i].range.max); 217530399e8Sjob else 218530399e8Sjob printf("%5zu: AS: %u -- %u", i + 1, 219714f4e3fSclaudio p->as[i].range.min, p->as[i].range.max); 220714f4e3fSclaudio break; 221714f4e3fSclaudio } 222530399e8Sjob if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz) 223530399e8Sjob printf(",\n"); 224530399e8Sjob else 225530399e8Sjob printf("\n"); 226714f4e3fSclaudio } 227714f4e3fSclaudio 228530399e8Sjob for (j = 0; j < p->ipsz; j++) { 229530399e8Sjob switch (p->ips[j].type) { 230530399e8Sjob case CERT_IP_INHERIT: 231530399e8Sjob if (outformats & FORMAT_JSON) 232530399e8Sjob printf("\t\t{ \"ip_inherit\": \"true\" }"); 233530399e8Sjob else 234530399e8Sjob printf("%5zu: IP: inherit", i + j + 1); 235530399e8Sjob break; 236530399e8Sjob case CERT_IP_ADDR: 237530399e8Sjob ip_addr_print(&p->ips[j].ip, 238530399e8Sjob p->ips[j].afi, buf1, sizeof(buf1)); 239530399e8Sjob if (outformats & FORMAT_JSON) 240530399e8Sjob printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1); 241530399e8Sjob else 242530399e8Sjob printf("%5zu: IP: %s", i + j + 1, buf1); 243530399e8Sjob break; 244530399e8Sjob case CERT_IP_RANGE: 245530399e8Sjob sockt = (p->ips[j].afi == AFI_IPV4) ? 246530399e8Sjob AF_INET : AF_INET6; 247530399e8Sjob inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1)); 248530399e8Sjob inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2)); 249530399e8Sjob if (outformats & FORMAT_JSON) 250530399e8Sjob printf("\t\t{ \"ip_range\": { \"min\": \"%s\"" 251530399e8Sjob ", \"max\": \"%s\" }}", buf1, buf2); 252530399e8Sjob else 253530399e8Sjob printf("%5zu: IP: %s -- %s", i + j + 1, buf1, 254530399e8Sjob buf2); 255530399e8Sjob break; 256530399e8Sjob } 257530399e8Sjob if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz) 258530399e8Sjob printf(",\n"); 259530399e8Sjob else 260530399e8Sjob printf("\n"); 261530399e8Sjob } 262530399e8Sjob 263530399e8Sjob if (outformats & FORMAT_JSON) 264530399e8Sjob printf("\t],\n"); 265714f4e3fSclaudio } 266714f4e3fSclaudio 267714f4e3fSclaudio void 268220c707cSclaudio crl_print(const struct crl *p) 269220c707cSclaudio { 270220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 271220c707cSclaudio X509_REVOKED *rev; 2727cdd491fSclaudio ASN1_INTEGER *crlnum; 273220c707cSclaudio int i; 2747cdd491fSclaudio char *serial; 275220c707cSclaudio time_t t; 276220c707cSclaudio 277530399e8Sjob if (outformats & FORMAT_JSON) { 278530399e8Sjob printf("\t\"type\": \"crl\",\n"); 279530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 280530399e8Sjob } else 281220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 2827cdd491fSclaudio 2837cdd491fSclaudio crlnum = X509_CRL_get_ext_d2i(p->x509_crl, NID_crl_number, NULL, NULL); 2847cdd491fSclaudio serial = x509_convert_seqnum(__func__, crlnum); 285530399e8Sjob if (serial != NULL) { 286530399e8Sjob if (outformats & FORMAT_JSON) 287530399e8Sjob printf("\t\"crl_serial\": \"%s\",\n", serial); 288530399e8Sjob else 2897cdd491fSclaudio printf("CRL Serial Number: %s\n", serial); 290530399e8Sjob } 2917cdd491fSclaudio free(serial); 2927cdd491fSclaudio ASN1_INTEGER_free(crlnum); 2937cdd491fSclaudio 294530399e8Sjob if (outformats & FORMAT_JSON) { 295530399e8Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->issued); 296530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 297530399e8Sjob printf("\t\"revoked_certs\": [\n"); 298530399e8Sjob } else { 299220c707cSclaudio printf("CRL valid since: %s\n", time2str(p->issued)); 300220c707cSclaudio printf("CRL valid until: %s\n", time2str(p->expires)); 301530399e8Sjob printf("Revoked Certificates:\n"); 302530399e8Sjob } 303220c707cSclaudio 304220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 305220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 306220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3077cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3087cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 309220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 310530399e8Sjob if (serial != NULL) { 311530399e8Sjob if (outformats & FORMAT_JSON) { 312530399e8Sjob printf("\t\t{ \"serial\": \"%s\"", serial); 313530399e8Sjob printf(", \"date\": \"%s\" }", time2str(t)); 314530399e8Sjob if (i + 1 < sk_X509_REVOKED_num(revlist)) 315530399e8Sjob printf(","); 316530399e8Sjob printf("\n"); 317530399e8Sjob } else 318530399e8Sjob printf(" Serial: %8s Revocation Date: %s" 319530399e8Sjob "\n", serial, time2str(t)); 320530399e8Sjob } 3217cdd491fSclaudio free(serial); 322220c707cSclaudio } 323530399e8Sjob 324530399e8Sjob if (outformats & FORMAT_JSON) 325530399e8Sjob printf("\t],\n"); 326530399e8Sjob else if (i == 0) 327220c707cSclaudio printf("No Revoked Certificates\n"); 328220c707cSclaudio } 329220c707cSclaudio 330220c707cSclaudio void 331530399e8Sjob mft_print(const X509 *x, const struct mft *p) 332714f4e3fSclaudio { 333714f4e3fSclaudio size_t i; 334714f4e3fSclaudio char *hash; 335714f4e3fSclaudio 336530399e8Sjob if (outformats & FORMAT_JSON) { 337530399e8Sjob printf("\t\"type\": \"manifest\",\n"); 338530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 339530399e8Sjob x509_print(x); 340530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 341530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 3422cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 343530399e8Sjob printf("\t\"manifest_number\": \"%s\",\n", p->seqnum); 344530399e8Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->valid_since); 345530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->valid_until); 346530399e8Sjob } else { 347714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 348714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 349530399e8Sjob x509_print(x); 350714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 3512cf0e122Sjob printf("Subject info access: %s\n", p->sia); 352714f4e3fSclaudio printf("Manifest Number: %s\n", p->seqnum); 353530399e8Sjob printf("Manifest valid since: %s\n", time2str(p->valid_since)); 354530399e8Sjob printf("Manifest valid until: %s\n", time2str(p->valid_until)); 3556530cf17Sjob printf("Files and hashes:\n"); 356530399e8Sjob } 357530399e8Sjob 358714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 359530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 360530399e8Sjob printf("\t\"filesandhashes\": [\n"); 361530399e8Sjob 362714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 363714f4e3fSclaudio &hash) == -1) 364714f4e3fSclaudio errx(1, "base64_encode failure"); 365530399e8Sjob 366530399e8Sjob if (outformats & FORMAT_JSON) { 367530399e8Sjob printf("\t\t{ \"filename\": \"%s\",", p->files[i].file); 368530399e8Sjob printf(" \"hash\": \"%s\" }", hash); 369530399e8Sjob if (i + 1 < p->filesz) 370530399e8Sjob printf(","); 371530399e8Sjob printf("\n"); 372530399e8Sjob } else { 373714f4e3fSclaudio printf("%5zu: %s\n", i + 1, p->files[i].file); 374714f4e3fSclaudio printf("\thash %s\n", hash); 375530399e8Sjob } 376530399e8Sjob 377714f4e3fSclaudio free(hash); 378714f4e3fSclaudio } 379530399e8Sjob 380530399e8Sjob if (outformats & FORMAT_JSON) 381530399e8Sjob printf("\t],\n"); 382714f4e3fSclaudio } 383714f4e3fSclaudio 384714f4e3fSclaudio void 385530399e8Sjob roa_print(const X509 *x, const struct roa *p) 386714f4e3fSclaudio { 387714f4e3fSclaudio char buf[128]; 388714f4e3fSclaudio size_t i; 389714f4e3fSclaudio 390530399e8Sjob if (outformats & FORMAT_JSON) { 391530399e8Sjob printf("\t\"type\": \"roa\",\n"); 392530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 393530399e8Sjob x509_print(x); 394530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 395530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 3962cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 397530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 398530399e8Sjob } else { 399714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 400530399e8Sjob x509_print(x); 401714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 402714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4032cf0e122Sjob printf("Subject info access: %s\n", p->sia); 404220c707cSclaudio printf("ROA valid until: %s\n", time2str(p->expires)); 405714f4e3fSclaudio printf("asID: %u\n", p->asid); 4062cf0e122Sjob printf("IP address blocks:\n"); 407530399e8Sjob } 408530399e8Sjob 409714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 410530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 411530399e8Sjob printf("\t\"vrps\": [\n"); 412530399e8Sjob 413714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 414714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 415530399e8Sjob 416530399e8Sjob if (outformats & FORMAT_JSON) { 417530399e8Sjob printf("\t\t{ \"prefix\": \"%s\",", buf); 418530399e8Sjob printf(" \"asid\": %u,", p->asid); 419530399e8Sjob printf(" \"maxlen\": %hhu }", p->ips[i].maxlength); 420530399e8Sjob if (i + 1 < p->ipsz) 421530399e8Sjob printf(","); 422530399e8Sjob printf("\n"); 423530399e8Sjob } else 424530399e8Sjob printf("%5zu: %s maxlen: %hhu\n", i + 1, buf, 425530399e8Sjob p->ips[i].maxlength); 426714f4e3fSclaudio } 427530399e8Sjob 428530399e8Sjob if (outformats & FORMAT_JSON) 429530399e8Sjob printf("\t],\n"); 430714f4e3fSclaudio } 431714f4e3fSclaudio 432714f4e3fSclaudio void 433530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 434714f4e3fSclaudio { 435530399e8Sjob size_t i; 436530399e8Sjob 437530399e8Sjob if (outformats & FORMAT_JSON) { 438530399e8Sjob printf("\t\"type\": \"gbr\",\n"); 439530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 440530399e8Sjob x509_print(x); 441530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 442530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 4432cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 444530399e8Sjob printf("\t\"vcard\": \""); 445530399e8Sjob for (i = 0; i < strlen(p->vcard); i++) { 446530399e8Sjob if (p->vcard[i] == '"') 447530399e8Sjob printf("\\\""); 448530399e8Sjob if (p->vcard[i] == '\r') 449530399e8Sjob continue; 450530399e8Sjob if (p->vcard[i] == '\n') 451530399e8Sjob printf("\\r\\n"); 452530399e8Sjob else 453530399e8Sjob putchar(p->vcard[i]); 454530399e8Sjob } 455530399e8Sjob printf("\",\n"); 456530399e8Sjob } else { 457714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 458530399e8Sjob x509_print(x); 459714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 460714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 4612cf0e122Sjob printf("Subject info access: %s\n", p->sia); 462714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 463714f4e3fSclaudio } 464530399e8Sjob } 46504834fbdSjob 46604834fbdSjob void 46704834fbdSjob rsc_print(const X509 *x, const struct rsc *p) 46804834fbdSjob { 46904834fbdSjob char buf1[64], buf2[64], tbuf[21]; 47004834fbdSjob char *hash; 47104834fbdSjob int sockt; 47204834fbdSjob size_t i, j; 47304834fbdSjob 47404834fbdSjob strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); 47504834fbdSjob 47604834fbdSjob if (outformats & FORMAT_JSON) { 47704834fbdSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 47804834fbdSjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 47904834fbdSjob x509_print(x); 48004834fbdSjob printf("\t\"aia\": \"%s\",\n", p->aia); 48104834fbdSjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 48204834fbdSjob printf("\t\"signed_with_resources\": [\n"); 48304834fbdSjob } else { 48404834fbdSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 48504834fbdSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 48604834fbdSjob x509_print(x); 48704834fbdSjob printf("Authority info access: %s\n", p->aia); 48804834fbdSjob printf("Valid until: %s\n", tbuf); 48904834fbdSjob printf("Signed with resources:\n"); 49004834fbdSjob } 49104834fbdSjob 49204834fbdSjob for (i = 0; i < p->asz; i++) { 49304834fbdSjob switch (p->as[i].type) { 49404834fbdSjob case CERT_AS_ID: 49504834fbdSjob if (outformats & FORMAT_JSON) 49604834fbdSjob printf("\t\t{ \"asid\": %u }", p->as[i].id); 49704834fbdSjob else 49804834fbdSjob printf("%5zu: AS: %u", i + 1, p->as[i].id); 49904834fbdSjob break; 50004834fbdSjob case CERT_AS_RANGE: 50104834fbdSjob if (outformats & FORMAT_JSON) 50204834fbdSjob printf("\t\t{ \"asrange\": { \"min\": %u, " 50304834fbdSjob "\"max\": %u }}", p->as[i].range.min, 50404834fbdSjob p->as[i].range.max); 50504834fbdSjob else 50604834fbdSjob printf("%5zu: AS: %u -- %u", i + 1, 50704834fbdSjob p->as[i].range.min, p->as[i].range.max); 50804834fbdSjob break; 50904834fbdSjob case CERT_AS_INHERIT: 51004834fbdSjob /* inheritance isn't possible in RSC */ 51104834fbdSjob break; 51204834fbdSjob } 51304834fbdSjob if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz) 51404834fbdSjob printf(",\n"); 51504834fbdSjob else 51604834fbdSjob printf("\n"); 51704834fbdSjob } 51804834fbdSjob 51904834fbdSjob for (j = 0; j < p->ipsz; j++) { 52004834fbdSjob switch (p->ips[j].type) { 52104834fbdSjob case CERT_IP_ADDR: 52204834fbdSjob ip_addr_print(&p->ips[j].ip, 52304834fbdSjob p->ips[j].afi, buf1, sizeof(buf1)); 52404834fbdSjob if (outformats & FORMAT_JSON) 52504834fbdSjob printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1); 52604834fbdSjob else 52704834fbdSjob printf("%5zu: IP: %s", i + j + 1, buf1); 52804834fbdSjob break; 52904834fbdSjob case CERT_IP_RANGE: 53004834fbdSjob sockt = (p->ips[j].afi == AFI_IPV4) ? 53104834fbdSjob AF_INET : AF_INET6; 53204834fbdSjob inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1)); 53304834fbdSjob inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2)); 53404834fbdSjob if (outformats & FORMAT_JSON) 53504834fbdSjob printf("\t\t{ \"ip_range\": { \"min\": \"%s\"" 53604834fbdSjob ", \"max\": \"%s\" }}", buf1, buf2); 53704834fbdSjob else 53804834fbdSjob printf("%5zu: IP: %s -- %s", i + j + 1, buf1, 53904834fbdSjob buf2); 54004834fbdSjob break; 54104834fbdSjob case CERT_IP_INHERIT: 54204834fbdSjob /* inheritance isn't possible in RSC */ 54304834fbdSjob break; 54404834fbdSjob } 54504834fbdSjob if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz) 54604834fbdSjob printf(",\n"); 54704834fbdSjob else 54804834fbdSjob printf("\n"); 54904834fbdSjob } 55004834fbdSjob 55104834fbdSjob if (outformats & FORMAT_JSON) { 55204834fbdSjob printf("\t],\n"); 55304834fbdSjob printf("\t\"filenamesandhashes\": [\n"); 55404834fbdSjob } else 55504834fbdSjob printf("Filenames and hashes:\n"); 55604834fbdSjob 55704834fbdSjob for (i = 0; i < p->filesz; i++) { 55804834fbdSjob if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 55904834fbdSjob &hash) == -1) 56004834fbdSjob errx(1, "base64_encode failure"); 56104834fbdSjob 56204834fbdSjob if (outformats & FORMAT_JSON) { 56304834fbdSjob printf("\t\t{ \"filename\": \"%s\",", 56404834fbdSjob p->files[i].filename ? p->files[i].filename : ""); 56504834fbdSjob printf(" \"hash_digest\": \"%s\" }", hash); 56604834fbdSjob if (i + 1 < p->filesz) 56704834fbdSjob printf(","); 56804834fbdSjob printf("\n"); 56904834fbdSjob } else { 57004834fbdSjob printf("%5zu: %s\n", i + 1, p->files[i].filename 57104834fbdSjob ? p->files[i].filename : "no filename"); 57204834fbdSjob printf("\thash %s\n", hash); 57304834fbdSjob } 57404834fbdSjob 57504834fbdSjob free(hash); 57604834fbdSjob } 57704834fbdSjob 57804834fbdSjob if (outformats & FORMAT_JSON) 57904834fbdSjob printf("\t],\n"); 58004834fbdSjob } 581a29ddfd5Sjob 582a29ddfd5Sjob void 583a29ddfd5Sjob aspa_print(const X509 *x, const struct aspa *p) 584a29ddfd5Sjob { 585a29ddfd5Sjob size_t i; 586a29ddfd5Sjob 587a29ddfd5Sjob if (outformats & FORMAT_JSON) { 588a29ddfd5Sjob printf("\t\"type\": \"aspa\",\n"); 589a29ddfd5Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 590a29ddfd5Sjob x509_print(x); 591a29ddfd5Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 592a29ddfd5Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 5932cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 594a29ddfd5Sjob printf("\t\"customer_asid\": %u,\n", p->custasid); 595a29ddfd5Sjob printf("\t\"provider_set\": [\n"); 596a29ddfd5Sjob for (i = 0; i < p->providersz; i++) { 597a29ddfd5Sjob printf("\t\t{ \"asid\": %u", p->providers[i].as); 598a29ddfd5Sjob if (p->providers[i].afi == AFI_IPV4) 599a29ddfd5Sjob printf(", \"afi_limit\": \"ipv4\""); 600a29ddfd5Sjob if (p->providers[i].afi == AFI_IPV6) 601a29ddfd5Sjob printf(", \"afi_limit\": \"ipv6\""); 602a29ddfd5Sjob printf(" }"); 603a29ddfd5Sjob if (i + 1 < p->providersz) 604a29ddfd5Sjob printf(","); 605a29ddfd5Sjob printf("\n"); 606a29ddfd5Sjob } 607a29ddfd5Sjob printf("\t],\n"); 608a29ddfd5Sjob } else { 609a29ddfd5Sjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 610a29ddfd5Sjob x509_print(x); 611a29ddfd5Sjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 612a29ddfd5Sjob printf("Authority info access: %s\n", p->aia); 6132cf0e122Sjob printf("Subject info access: %s\n", p->sia); 614a29ddfd5Sjob printf("Customer AS: %u\n", p->custasid); 615a29ddfd5Sjob printf("Provider Set:\n"); 616a29ddfd5Sjob for (i = 0; i < p->providersz; i++) { 617a29ddfd5Sjob printf("%5zu: AS: %d", i + 1, p->providers[i].as); 618a29ddfd5Sjob switch (p->providers[i].afi) { 619a29ddfd5Sjob case AFI_IPV4: 620a29ddfd5Sjob printf(" (IPv4 only)"); 621a29ddfd5Sjob break; 622a29ddfd5Sjob case AFI_IPV6: 623a29ddfd5Sjob printf(" (IPv6 only)"); 624a29ddfd5Sjob break; 625a29ddfd5Sjob default: 626a29ddfd5Sjob break; 627a29ddfd5Sjob } 628a29ddfd5Sjob printf("\n"); 629a29ddfd5Sjob } 630a29ddfd5Sjob } 631a29ddfd5Sjob } 632ee2a33daSjob 633ee2a33daSjob static void 634ee2a33daSjob takey_print(char *name, const struct takey *t) 635ee2a33daSjob { 636ee2a33daSjob char *spki = NULL; 637ee2a33daSjob size_t i, j = 0; 638ee2a33daSjob 639ee2a33daSjob if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0) 640ee2a33daSjob errx(1, "base64_encode failed in %s", __func__); 641ee2a33daSjob 642ee2a33daSjob if (outformats & FORMAT_JSON) { 643ee2a33daSjob printf("\t\t{\n\t\t\t\"name\": \"%s\",\n", name); 644ee2a33daSjob printf("\t\t\t\"comments\": ["); 645ee2a33daSjob for (i = 0; i < t->commentsz; i++) { 646ee2a33daSjob printf("\"%s\"", t->comments[i]); 647ee2a33daSjob if (i + 1 < t->commentsz) 648ee2a33daSjob printf(", "); 649ee2a33daSjob } 650ee2a33daSjob printf("],\n"); 651ee2a33daSjob printf("\t\t\t\"uris\": ["); 652ee2a33daSjob for (i = 0; i < t->urisz; i++) { 653ee2a33daSjob printf("\"%s\"", t->uris[i]); 654ee2a33daSjob if (i + 1 < t->urisz) 655ee2a33daSjob printf(", "); 656ee2a33daSjob } 657ee2a33daSjob printf("],\n"); 658ee2a33daSjob printf("\t\t\t\"spki\": \"%s\"\n\t\t}", spki); 659ee2a33daSjob } else { 660ee2a33daSjob printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name); 661ee2a33daSjob 662ee2a33daSjob for (i = 0; i < t->commentsz; i++) { 663ee2a33daSjob printf("\t# %s\n", t->comments[i]); 664ee2a33daSjob } 665ee2a33daSjob 666ee2a33daSjob for (i = 0; i < t->urisz; i++) { 667ee2a33daSjob printf("\t%s\n\n\t", t->uris[i]); 668ee2a33daSjob } 669ee2a33daSjob 670ee2a33daSjob for (i = 0; i < strlen(spki); i++) { 671ee2a33daSjob printf("%c", spki[i]); 672ee2a33daSjob j++; 673ee2a33daSjob if (j == 64) { 674ee2a33daSjob printf("\n\t"); 675ee2a33daSjob j = 0; 676ee2a33daSjob } 677ee2a33daSjob } 678ee2a33daSjob 679ee2a33daSjob printf("\n\n"); 680ee2a33daSjob } 681ee2a33daSjob 682ee2a33daSjob free(spki); 683ee2a33daSjob } 684ee2a33daSjob 685ee2a33daSjob void 686ee2a33daSjob tak_print(const X509 *x, const struct tak *p) 687ee2a33daSjob { 688ee2a33daSjob char tbuf[21]; 689ee2a33daSjob 690ee2a33daSjob if (outformats & FORMAT_JSON) { 691ee2a33daSjob printf("\t\"type\": \"tak\",\n"); 692ee2a33daSjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 693ee2a33daSjob x509_print(x); 694ee2a33daSjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 695ee2a33daSjob printf("\t\"aia\": \"%s\",\n", p->aia); 6962cf0e122Sjob printf("\t\"sia\": \"%s\",\n", p->sia); 697ee2a33daSjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 698ee2a33daSjob printf("\t\"takeys\": [\n"); 699ee2a33daSjob } else { 700ee2a33daSjob strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); 701ee2a33daSjob printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 702ee2a33daSjob x509_print(x); 703ee2a33daSjob printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 704ee2a33daSjob printf("Authority info access: %s\n", p->aia); 7052cf0e122Sjob printf("Subject info access: %s\n", p->sia); 7066530cf17Sjob printf("TAK valid until: %s\n", tbuf); 707ee2a33daSjob } 708ee2a33daSjob 709ee2a33daSjob takey_print("current", p->current); 710ee2a33daSjob 711ee2a33daSjob if (p->predecessor != NULL) { 712ee2a33daSjob if (outformats & FORMAT_JSON) 713ee2a33daSjob printf(",\n"); 714ee2a33daSjob takey_print("predecessor", p->predecessor); 715ee2a33daSjob } 716ee2a33daSjob 717ee2a33daSjob if (p->successor != NULL) { 718ee2a33daSjob if (outformats & FORMAT_JSON) 719ee2a33daSjob printf(",\n"); 720ee2a33daSjob takey_print("successor", p->successor); 721ee2a33daSjob } 722ee2a33daSjob 723ee2a33daSjob if (outformats & FORMAT_JSON) 724ee2a33daSjob printf("\n\t],\n"); 725ee2a33daSjob } 726