1*530399e8Sjob /* $OpenBSD: print.c,v 1.8 2022/04/20 10:46:20 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 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 93*530399e8Sjob if (outformats & FORMAT_JSON) { 94*530399e8Sjob printf("\t\"type\": \"tal\",\n"); 95*530399e8Sjob printf("\t\"name\": %s\n", p->descr); 96*530399e8Sjob printf("\t\"ski\": %s\n", pretty_key_id(ski)); 97*530399e8Sjob printf("\t\"trust_anchor_locations\": ["); 98*530399e8Sjob for (i = 0; i < p->urisz; i++) { 99*530399e8Sjob printf("\"%s\"", p->uri[i]); 100*530399e8Sjob if (i + 1 < p->urisz) 101*530399e8Sjob printf(", "); 102*530399e8Sjob } 103*530399e8Sjob printf("]\n"); 104*530399e8Sjob 105*530399e8Sjob } else { 106*530399e8Sjob printf("Trust anchor name: %s\n", p->descr); 107*530399e8Sjob printf("Subject key identifier: %s\n", pretty_key_id(ski)); 108e911df76Sjob printf("Trust anchor locations:\n"); 109714f4e3fSclaudio for (i = 0; i < p->urisz; i++) 110e911df76Sjob printf("%5zu: %s\n", i + 1, p->uri[i]); 111*530399e8Sjob } 112e911df76Sjob 113e911df76Sjob EVP_PKEY_free(pk); 114e911df76Sjob free(rder); 115e911df76Sjob free(ski); 116714f4e3fSclaudio } 117714f4e3fSclaudio 118714f4e3fSclaudio void 119*530399e8Sjob x509_print(const X509 *x) 120*530399e8Sjob { 121*530399e8Sjob const ASN1_INTEGER *xserial; 122*530399e8Sjob char *serial = NULL; 123*530399e8Sjob 124*530399e8Sjob xserial = X509_get0_serialNumber(x); 125*530399e8Sjob if (xserial == NULL) { 126*530399e8Sjob warnx("X509_get0_serialNumber failed in %s", __func__); 127*530399e8Sjob goto out; 128*530399e8Sjob } 129*530399e8Sjob 130*530399e8Sjob serial = x509_convert_seqnum(__func__, xserial); 131*530399e8Sjob if (serial == NULL) { 132*530399e8Sjob warnx("x509_convert_seqnum failed in %s", __func__); 133*530399e8Sjob goto out; 134*530399e8Sjob } 135*530399e8Sjob 136*530399e8Sjob if (outformats & FORMAT_JSON) { 137*530399e8Sjob printf("\t\"cert_serial\": \"%s\",\n", serial); 138*530399e8Sjob } else { 139*530399e8Sjob printf("Certificate serial: %s\n", serial); 140*530399e8Sjob } 141*530399e8Sjob 142*530399e8Sjob out: 143*530399e8Sjob free(serial); 144*530399e8Sjob } 145*530399e8Sjob 146*530399e8Sjob void 147714f4e3fSclaudio cert_print(const struct cert *p) 148714f4e3fSclaudio { 149*530399e8Sjob size_t i, j; 150714f4e3fSclaudio char buf1[64], buf2[64]; 151714f4e3fSclaudio int sockt; 152714f4e3fSclaudio char tbuf[21]; 153714f4e3fSclaudio 154*530399e8Sjob strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); 155*530399e8Sjob 156*530399e8Sjob if (outformats & FORMAT_JSON) { 157*530399e8Sjob if (p->pubkey != NULL) 158*530399e8Sjob printf("\t\"type\": \"router_key\",\n"); 159*530399e8Sjob else 160*530399e8Sjob printf("\t\"type\": \"ca_cert\",\n"); 161*530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 162*530399e8Sjob if (p->aki != NULL) 163*530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 164*530399e8Sjob x509_print(p->x509); 165*530399e8Sjob if (p->aia != NULL) 166*530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 167*530399e8Sjob if (p->mft != NULL) 168*530399e8Sjob printf("\t\"manifest\": \"%s\",\n", p->mft); 169*530399e8Sjob if (p->repo != NULL) 170*530399e8Sjob printf("\t\"carepository\": \"%s\",\n", p->repo); 171*530399e8Sjob if (p->notify != NULL) 172*530399e8Sjob printf("\t\"notify_url\": \"%s\",\n", p->notify); 173*530399e8Sjob if (p->pubkey != NULL) 174*530399e8Sjob printf("\t\"router_key\": \"%s\",\n", p->pubkey); 175*530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 176*530399e8Sjob printf("\t\"subordinate_resources\": [\n"); 177*530399e8Sjob } else { 178714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 179714f4e3fSclaudio if (p->aki != NULL) 180714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 181*530399e8Sjob x509_print(p->x509); 182714f4e3fSclaudio if (p->aia != NULL) 183714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 184714f4e3fSclaudio if (p->mft != NULL) 185714f4e3fSclaudio printf("Manifest: %s\n", p->mft); 186714f4e3fSclaudio if (p->repo != NULL) 187714f4e3fSclaudio printf("caRepository: %s\n", p->repo); 188714f4e3fSclaudio if (p->notify != NULL) 189714f4e3fSclaudio printf("Notify URL: %s\n", p->notify); 190714f4e3fSclaudio if (p->pubkey != NULL) 191714f4e3fSclaudio printf("BGPsec P-256 ECDSA public key: %s\n", p->pubkey); 192714f4e3fSclaudio printf("Valid until: %s\n", tbuf); 193714f4e3fSclaudio printf("Subordinate Resources:\n"); 194*530399e8Sjob } 195714f4e3fSclaudio 196*530399e8Sjob for (i = 0; i < p->asz; i++) { 197714f4e3fSclaudio switch (p->as[i].type) { 198714f4e3fSclaudio case CERT_AS_ID: 199*530399e8Sjob if (outformats & FORMAT_JSON) 200*530399e8Sjob printf("\t\t{ \"asid\": %u }", p->as[i].id); 201*530399e8Sjob else 202*530399e8Sjob printf("%5zu: AS: %u", i + 1, p->as[i].id); 203714f4e3fSclaudio break; 204714f4e3fSclaudio case CERT_AS_INHERIT: 205*530399e8Sjob if (outformats & FORMAT_JSON) 206*530399e8Sjob printf("\t\t{ \"asid_inherit\": \"true\" }"); 207*530399e8Sjob else 208*530399e8Sjob printf("%5zu: AS: inherit", i + 1); 209714f4e3fSclaudio break; 210714f4e3fSclaudio case CERT_AS_RANGE: 211*530399e8Sjob if (outformats & FORMAT_JSON) 212*530399e8Sjob printf("\t\t{ \"asrange\": { \"min\": %u, " 213*530399e8Sjob "\"max\": %u }}", p->as[i].range.min, 214*530399e8Sjob p->as[i].range.max); 215*530399e8Sjob else 216*530399e8Sjob printf("%5zu: AS: %u -- %u", i + 1, 217714f4e3fSclaudio p->as[i].range.min, p->as[i].range.max); 218714f4e3fSclaudio break; 219714f4e3fSclaudio } 220*530399e8Sjob if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz) 221*530399e8Sjob printf(",\n"); 222*530399e8Sjob else 223*530399e8Sjob printf("\n"); 224714f4e3fSclaudio } 225714f4e3fSclaudio 226*530399e8Sjob for (j = 0; j < p->ipsz; j++) { 227*530399e8Sjob switch (p->ips[j].type) { 228*530399e8Sjob case CERT_IP_INHERIT: 229*530399e8Sjob if (outformats & FORMAT_JSON) 230*530399e8Sjob printf("\t\t{ \"ip_inherit\": \"true\" }"); 231*530399e8Sjob else 232*530399e8Sjob printf("%5zu: IP: inherit", i + j + 1); 233*530399e8Sjob break; 234*530399e8Sjob case CERT_IP_ADDR: 235*530399e8Sjob ip_addr_print(&p->ips[j].ip, 236*530399e8Sjob p->ips[j].afi, buf1, sizeof(buf1)); 237*530399e8Sjob if (outformats & FORMAT_JSON) 238*530399e8Sjob printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1); 239*530399e8Sjob else 240*530399e8Sjob printf("%5zu: IP: %s", i + j + 1, buf1); 241*530399e8Sjob break; 242*530399e8Sjob case CERT_IP_RANGE: 243*530399e8Sjob sockt = (p->ips[j].afi == AFI_IPV4) ? 244*530399e8Sjob AF_INET : AF_INET6; 245*530399e8Sjob inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1)); 246*530399e8Sjob inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2)); 247*530399e8Sjob if (outformats & FORMAT_JSON) 248*530399e8Sjob printf("\t\t{ \"ip_range\": { \"min\": \"%s\"" 249*530399e8Sjob ", \"max\": \"%s\" }}", buf1, buf2); 250*530399e8Sjob else 251*530399e8Sjob printf("%5zu: IP: %s -- %s", i + j + 1, buf1, 252*530399e8Sjob buf2); 253*530399e8Sjob break; 254*530399e8Sjob } 255*530399e8Sjob if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz) 256*530399e8Sjob printf(",\n"); 257*530399e8Sjob else 258*530399e8Sjob printf("\n"); 259*530399e8Sjob } 260*530399e8Sjob 261*530399e8Sjob if (outformats & FORMAT_JSON) 262*530399e8Sjob printf("\t],\n"); 263714f4e3fSclaudio } 264714f4e3fSclaudio 265714f4e3fSclaudio void 266220c707cSclaudio crl_print(const struct crl *p) 267220c707cSclaudio { 268220c707cSclaudio STACK_OF(X509_REVOKED) *revlist; 269220c707cSclaudio X509_REVOKED *rev; 2707cdd491fSclaudio ASN1_INTEGER *crlnum; 271220c707cSclaudio int i; 2727cdd491fSclaudio char *serial; 273220c707cSclaudio time_t t; 274220c707cSclaudio 275*530399e8Sjob if (outformats & FORMAT_JSON) { 276*530399e8Sjob printf("\t\"type\": \"crl\",\n"); 277*530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 278*530399e8Sjob } else 279220c707cSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 2807cdd491fSclaudio 2817cdd491fSclaudio crlnum = X509_CRL_get_ext_d2i(p->x509_crl, NID_crl_number, NULL, NULL); 2827cdd491fSclaudio serial = x509_convert_seqnum(__func__, crlnum); 283*530399e8Sjob if (serial != NULL) { 284*530399e8Sjob if (outformats & FORMAT_JSON) 285*530399e8Sjob printf("\t\"crl_serial\": \"%s\",\n", serial); 286*530399e8Sjob else 2877cdd491fSclaudio printf("CRL Serial Number: %s\n", serial); 288*530399e8Sjob } 2897cdd491fSclaudio free(serial); 2907cdd491fSclaudio ASN1_INTEGER_free(crlnum); 2917cdd491fSclaudio 292*530399e8Sjob if (outformats & FORMAT_JSON) { 293*530399e8Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->issued); 294*530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 295*530399e8Sjob printf("\t\"revoked_certs\": [\n"); 296*530399e8Sjob } else { 297220c707cSclaudio printf("CRL valid since: %s\n", time2str(p->issued)); 298220c707cSclaudio printf("CRL valid until: %s\n", time2str(p->expires)); 299*530399e8Sjob printf("Revoked Certificates:\n"); 300*530399e8Sjob } 301220c707cSclaudio 302220c707cSclaudio revlist = X509_CRL_get_REVOKED(p->x509_crl); 303220c707cSclaudio for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) { 304220c707cSclaudio rev = sk_X509_REVOKED_value(revlist, i); 3057cdd491fSclaudio serial = x509_convert_seqnum(__func__, 3067cdd491fSclaudio X509_REVOKED_get0_serialNumber(rev)); 307220c707cSclaudio x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t); 308*530399e8Sjob if (serial != NULL) { 309*530399e8Sjob if (outformats & FORMAT_JSON) { 310*530399e8Sjob printf("\t\t{ \"serial\": \"%s\"", serial); 311*530399e8Sjob printf(", \"date\": \"%s\" }", time2str(t)); 312*530399e8Sjob if (i + 1 < sk_X509_REVOKED_num(revlist)) 313*530399e8Sjob printf(","); 314*530399e8Sjob printf("\n"); 315*530399e8Sjob } else 316*530399e8Sjob printf(" Serial: %8s Revocation Date: %s" 317*530399e8Sjob "\n", serial, time2str(t)); 318*530399e8Sjob } 3197cdd491fSclaudio free(serial); 320220c707cSclaudio } 321*530399e8Sjob 322*530399e8Sjob if (outformats & FORMAT_JSON) 323*530399e8Sjob printf("\t],\n"); 324*530399e8Sjob else if (i == 0) 325220c707cSclaudio printf("No Revoked Certificates\n"); 326220c707cSclaudio } 327220c707cSclaudio 328220c707cSclaudio void 329*530399e8Sjob mft_print(const X509 *x, const struct mft *p) 330714f4e3fSclaudio { 331714f4e3fSclaudio size_t i; 332714f4e3fSclaudio char *hash; 333714f4e3fSclaudio 334*530399e8Sjob if (outformats & FORMAT_JSON) { 335*530399e8Sjob printf("\t\"type\": \"manifest\",\n"); 336*530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 337*530399e8Sjob x509_print(x); 338*530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 339*530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 340*530399e8Sjob printf("\t\"manifest_number\": \"%s\",\n", p->seqnum); 341*530399e8Sjob printf("\t\"valid_since\": %lld,\n", (long long)p->valid_since); 342*530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->valid_until); 343*530399e8Sjob } else { 344714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 345714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 346*530399e8Sjob x509_print(x); 347714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 348714f4e3fSclaudio printf("Manifest Number: %s\n", p->seqnum); 349*530399e8Sjob printf("Manifest valid since: %s\n", time2str(p->valid_since)); 350*530399e8Sjob printf("Manifest valid until: %s\n", time2str(p->valid_until)); 351*530399e8Sjob } 352*530399e8Sjob 353714f4e3fSclaudio for (i = 0; i < p->filesz; i++) { 354*530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 355*530399e8Sjob printf("\t\"filesandhashes\": [\n"); 356*530399e8Sjob 357714f4e3fSclaudio if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), 358714f4e3fSclaudio &hash) == -1) 359714f4e3fSclaudio errx(1, "base64_encode failure"); 360*530399e8Sjob 361*530399e8Sjob if (outformats & FORMAT_JSON) { 362*530399e8Sjob printf("\t\t{ \"filename\": \"%s\",", p->files[i].file); 363*530399e8Sjob printf(" \"hash\": \"%s\" }", hash); 364*530399e8Sjob if (i + 1 < p->filesz) 365*530399e8Sjob printf(","); 366*530399e8Sjob printf("\n"); 367*530399e8Sjob } else { 368714f4e3fSclaudio printf("%5zu: %s\n", i + 1, p->files[i].file); 369714f4e3fSclaudio printf("\thash %s\n", hash); 370*530399e8Sjob } 371*530399e8Sjob 372714f4e3fSclaudio free(hash); 373714f4e3fSclaudio } 374*530399e8Sjob 375*530399e8Sjob if (outformats & FORMAT_JSON) 376*530399e8Sjob printf("\t],\n"); 377*530399e8Sjob 378*530399e8Sjob 379714f4e3fSclaudio } 380714f4e3fSclaudio 381714f4e3fSclaudio void 382*530399e8Sjob roa_print(const X509 *x, const struct roa *p) 383714f4e3fSclaudio { 384714f4e3fSclaudio char buf[128]; 385714f4e3fSclaudio size_t i; 386714f4e3fSclaudio 387*530399e8Sjob if (outformats & FORMAT_JSON) { 388*530399e8Sjob printf("\t\"type\": \"roa\",\n"); 389*530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 390*530399e8Sjob x509_print(x); 391*530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 392*530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 393*530399e8Sjob printf("\t\"valid_until\": %lld,\n", (long long)p->expires); 394*530399e8Sjob } else { 395714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 396*530399e8Sjob x509_print(x); 397714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 398714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 399220c707cSclaudio printf("ROA valid until: %s\n", time2str(p->expires)); 400714f4e3fSclaudio printf("asID: %u\n", p->asid); 401*530399e8Sjob } 402*530399e8Sjob 403714f4e3fSclaudio for (i = 0; i < p->ipsz; i++) { 404*530399e8Sjob if (i == 0 && outformats & FORMAT_JSON) 405*530399e8Sjob printf("\t\"vrps\": [\n"); 406*530399e8Sjob 407714f4e3fSclaudio ip_addr_print(&p->ips[i].addr, 408714f4e3fSclaudio p->ips[i].afi, buf, sizeof(buf)); 409*530399e8Sjob 410*530399e8Sjob if (outformats & FORMAT_JSON) { 411*530399e8Sjob printf("\t\t{ \"prefix\": \"%s\",", buf); 412*530399e8Sjob printf(" \"asid\": %u,", p->asid); 413*530399e8Sjob printf(" \"maxlen\": %hhu }", p->ips[i].maxlength); 414*530399e8Sjob if (i + 1 < p->ipsz) 415*530399e8Sjob printf(","); 416*530399e8Sjob printf("\n"); 417*530399e8Sjob } else 418*530399e8Sjob printf("%5zu: %s maxlen: %hhu\n", i + 1, buf, 419*530399e8Sjob p->ips[i].maxlength); 420714f4e3fSclaudio } 421*530399e8Sjob 422*530399e8Sjob if (outformats & FORMAT_JSON) 423*530399e8Sjob printf("\t],\n"); 424714f4e3fSclaudio } 425714f4e3fSclaudio 426714f4e3fSclaudio void 427*530399e8Sjob gbr_print(const X509 *x, const struct gbr *p) 428714f4e3fSclaudio { 429*530399e8Sjob size_t i; 430*530399e8Sjob 431*530399e8Sjob if (outformats & FORMAT_JSON) { 432*530399e8Sjob printf("\t\"type\": \"gbr\",\n"); 433*530399e8Sjob printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski)); 434*530399e8Sjob x509_print(x); 435*530399e8Sjob printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); 436*530399e8Sjob printf("\t\"aia\": \"%s\",\n", p->aia); 437*530399e8Sjob printf("\t\"vcard\": \""); 438*530399e8Sjob for (i = 0; i < strlen(p->vcard); i++) { 439*530399e8Sjob if (p->vcard[i] == '"') 440*530399e8Sjob printf("\\\""); 441*530399e8Sjob if (p->vcard[i] == '\r') 442*530399e8Sjob continue; 443*530399e8Sjob if (p->vcard[i] == '\n') 444*530399e8Sjob printf("\\r\\n"); 445*530399e8Sjob else 446*530399e8Sjob putchar(p->vcard[i]); 447*530399e8Sjob } 448*530399e8Sjob printf("\",\n"); 449*530399e8Sjob } else { 450714f4e3fSclaudio printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); 451*530399e8Sjob x509_print(x); 452714f4e3fSclaudio printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); 453714f4e3fSclaudio printf("Authority info access: %s\n", p->aia); 454714f4e3fSclaudio printf("vcard:\n%s", p->vcard); 455714f4e3fSclaudio } 456*530399e8Sjob } 457