src/usr.sbin/rpki-client/print.c

946 lines
25 KiB
C
Raw Normal View History

/* $OpenBSD: print.c,v 1.38 2023/04/26 18:17:50 tb Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <openssl/evp.h>
#include "extern.h"
static const char *
pretty_key_id(const char *hex)
{
static char buf[128]; /* bigger than SHA_DIGEST_LENGTH * 3 */
size_t i;
for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) {
if (i % 3 == 2)
buf[i] = ':';
else
buf[i] = *hex++;
}
if (i == sizeof(buf))
memcpy(buf + sizeof(buf) - 4, "...", 4);
else
buf[i] = '\0';
return buf;
}
char *
time2str(time_t t)
{
static char buf[64];
struct tm tm;
if (gmtime_r(&t, &tm) == NULL)
return "could not convert time";
strftime(buf, sizeof(buf), "%a %d %b %Y %T %z", &tm);
return buf;
}
void
tal_print(const struct tal *p)
{
char *ski;
EVP_PKEY *pk;
RSA *r;
const unsigned char *der;
unsigned char *rder = NULL;
unsigned char md[SHA_DIGEST_LENGTH];
int rder_len;
size_t i;
der = p->pkey;
pk = d2i_PUBKEY(NULL, &der, p->pkeysz);
if (pk == NULL)
errx(1, "d2i_PUBKEY failed in %s", __func__);
r = EVP_PKEY_get0_RSA(pk);
if (r == NULL)
errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__);
if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0)
errx(1, "i2d_RSAPublicKey failed in %s", __func__);
if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL))
errx(1, "EVP_Digest failed in %s", __func__);
ski = hex_encode(md, SHA_DIGEST_LENGTH);
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"tal\",\n");
printf("\t\"name\": \"%s\",\n", p->descr);
printf("\t\"ski\": \"%s\",\n", pretty_key_id(ski));
printf("\t\"trust_anchor_locations\": [");
for (i = 0; i < p->urisz; i++) {
printf("\"%s\"", p->uri[i]);
if (i + 1 < p->urisz)
printf(", ");
}
printf("],\n");
} else {
printf("Trust anchor name: %s\n", p->descr);
printf("Subject key identifier: %s\n", pretty_key_id(ski));
printf("Trust anchor locations: ");
for (i = 0; i < p->urisz; i++) {
if (i > 0)
printf("%26s", "");
printf("%s\n", p->uri[i]);
}
}
EVP_PKEY_free(pk);
free(rder);
free(ski);
}
void
x509_print(const X509 *x)
{
const ASN1_INTEGER *xserial;
const X509_NAME *xissuer;
char *issuer = NULL;
char *serial = NULL;
if ((xissuer = X509_get_issuer_name(x)) == NULL) {
warnx("X509_get_issuer_name failed");
goto out;
}
if ((issuer = X509_NAME_oneline(xissuer, NULL, 0)) == NULL) {
warnx("X509_NAME_oneline failed");
goto out;
}
if ((xserial = X509_get0_serialNumber(x)) == NULL) {
warnx("X509_get0_serialNumber failed");
goto out;
}
if ((serial = x509_convert_seqnum(__func__, xserial)) == NULL)
goto out;
if (outformats & FORMAT_JSON) {
printf("\t\"cert_issuer\": \"%s\",\n", issuer);
printf("\t\"cert_serial\": \"%s\",\n", serial);
} else {
printf("Certificate issuer: %s\n", issuer);
printf("Certificate serial: %s\n", serial);
}
out:
free(issuer);
free(serial);
}
void
cert_print(const struct cert *p)
{
size_t i, j;
char buf1[64], buf2[64];
int sockt;
if (outformats & FORMAT_JSON) {
if (p->pubkey != NULL)
printf("\t\"type\": \"router_key\",\n");
else
printf("\t\"type\": \"ca_cert\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
if (p->aki != NULL)
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
x509_print(p->x509);
if (p->aia != NULL)
printf("\t\"aia\": \"%s\",\n", p->aia);
if (p->mft != NULL)
printf("\t\"manifest\": \"%s\",\n", p->mft);
if (p->repo != NULL)
printf("\t\"carepository\": \"%s\",\n", p->repo);
if (p->notify != NULL)
printf("\t\"notify_url\": \"%s\",\n", p->notify);
if (p->pubkey != NULL)
printf("\t\"router_key\": \"%s\",\n", p->pubkey);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
printf("\t\"subordinate_resources\": [\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
if (p->aki != NULL)
printf("Authority key identifier: %s\n",
pretty_key_id(p->aki));
x509_print(p->x509);
if (p->aia != NULL)
printf("Authority info access: %s\n", p->aia);
if (p->mft != NULL)
printf("Manifest: %s\n", p->mft);
if (p->repo != NULL)
printf("caRepository: %s\n", p->repo);
if (p->notify != NULL)
printf("Notify URL: %s\n", p->notify);
if (p->pubkey != NULL) {
printf("BGPsec ECDSA public key: %s\n",
p->pubkey);
printf("Router key not before: %s\n",
time2str(p->notbefore));
printf("Router key not after: %s\n",
time2str(p->notafter));
} else {
printf("Certificate not before: %s\n",
time2str(p->notbefore));
printf("Certificate not after: %s\n",
time2str(p->notafter));
}
printf("Subordinate resources: ");
}
for (i = 0; i < p->asz; i++) {
switch (p->as[i].type) {
case CERT_AS_ID:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"asid\": %u }", p->as[i].id);
else {
if (i > 0)
printf("%26s", "");
printf("AS: %u", p->as[i].id);
}
break;
case CERT_AS_INHERIT:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"asid_inherit\": \"true\" }");
else {
if (i > 0)
printf("%26s", "");
printf("AS: inherit");
}
break;
case CERT_AS_RANGE:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"asrange\": { \"min\": %u, "
"\"max\": %u }}", p->as[i].range.min,
p->as[i].range.max);
else {
if (i > 0)
printf("%26s", "");
printf("AS: %u -- %u", p->as[i].range.min,
p->as[i].range.max);
}
break;
}
if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz)
printf(",\n");
else
printf("\n");
}
for (j = 0; j < p->ipsz; j++) {
switch (p->ips[j].type) {
case CERT_IP_INHERIT:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"ip_inherit\": \"true\" }");
else {
if (i > 0 || j > 0)
printf("%26s", "");
printf("IP: inherit");
}
break;
case CERT_IP_ADDR:
ip_addr_print(&p->ips[j].ip,
p->ips[j].afi, buf1, sizeof(buf1));
if (outformats & FORMAT_JSON)
printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1);
else {
if (i > 0 || j > 0)
printf("%26s", "");
printf("IP: %s", buf1);
}
break;
case CERT_IP_RANGE:
sockt = (p->ips[j].afi == AFI_IPV4) ?
AF_INET : AF_INET6;
inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1));
inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2));
if (outformats & FORMAT_JSON)
printf("\t\t{ \"ip_range\": { \"min\": \"%s\""
", \"max\": \"%s\" }}", buf1, buf2);
else {
if (i > 0 || j > 0)
printf("%26s", "");
printf("IP: %s -- %s", buf1, buf2);
}
break;
}
if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz)
printf(",\n");
else
printf("\n");
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
}
void
crl_print(const struct crl *p)
{
STACK_OF(X509_REVOKED) *revlist;
X509_REVOKED *rev;
ASN1_INTEGER *crlnum;
X509_NAME *xissuer;
int i;
char *issuer, *serial;
time_t t;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"crl\",\n");
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
} else
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
xissuer = X509_CRL_get_issuer(p->x509_crl);
issuer = X509_NAME_oneline(xissuer, NULL, 0);
crlnum = X509_CRL_get_ext_d2i(p->x509_crl, NID_crl_number, NULL, NULL);
serial = x509_convert_seqnum(__func__, crlnum);
if (issuer != NULL && serial != NULL) {
if (outformats & FORMAT_JSON) {
printf("\t\"crl_issuer\": \"%s\",\n", issuer);
printf("\t\"crl_serial\": \"%s\",\n", serial);
} else {
printf("CRL issuer: %s\n", issuer);
printf("CRL serial number: %s\n", serial);
}
}
free(issuer);
free(serial);
ASN1_INTEGER_free(crlnum);
if (outformats & FORMAT_JSON) {
printf("\t\"valid_since\": %lld,\n", (long long)p->lastupdate);
printf("\t\"valid_until\": %lld,\n", (long long)p->nextupdate);
printf("\t\"revoked_certs\": [\n");
} else {
printf("CRL last update: %s\n",
time2str(p->lastupdate));
printf("CRL next update: %s\n",
time2str(p->nextupdate));
printf("Revoked Certificates:\n");
}
revlist = X509_CRL_get_REVOKED(p->x509_crl);
for (i = 0; i < sk_X509_REVOKED_num(revlist); i++) {
rev = sk_X509_REVOKED_value(revlist, i);
serial = x509_convert_seqnum(__func__,
X509_REVOKED_get0_serialNumber(rev));
x509_get_time(X509_REVOKED_get0_revocationDate(rev), &t);
if (serial != NULL) {
if (outformats & FORMAT_JSON) {
printf("\t\t{ \"serial\": \"%s\"", serial);
printf(", \"date\": \"%s\" }", time2str(t));
if (i + 1 < sk_X509_REVOKED_num(revlist))
printf(",");
printf("\n");
} else
printf("%25s Serial: %8s Revocation Date: %s"
"\n", "", serial, time2str(t));
}
free(serial);
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
else if (i == 0)
printf("No Revoked Certificates\n");
}
void
mft_print(const X509 *x, const struct mft *p)
{
size_t i;
char *hash;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"manifest\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
printf("\t\"sia\": \"%s\",\n", p->sia);
printf("\t\"manifest_number\": \"%s\",\n", p->seqnum);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->thisupdate);
printf("\t\"valid_until\": %lld,\n", (long long)p->nextupdate);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
x509_print(x);
printf("Authority info access: %s\n", p->aia);
printf("Subject info access: %s\n", p->sia);
printf("Manifest number: %s\n", p->seqnum);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("Manifest this update: %s\n", time2str(p->thisupdate));
printf("Manifest next update: %s\n", time2str(p->nextupdate));
printf("Files and hashes: ");
}
for (i = 0; i < p->filesz; i++) {
if (i == 0 && outformats & FORMAT_JSON)
printf("\t\"filesandhashes\": [\n");
if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
&hash) == -1)
errx(1, "base64_encode failure");
if (outformats & FORMAT_JSON) {
printf("\t\t{ \"filename\": \"%s\",", p->files[i].file);
printf(" \"hash\": \"%s\" }", hash);
if (i + 1 < p->filesz)
printf(",");
printf("\n");
} else {
if (i > 0)
printf("%26s", "");
printf("%zu: %s (hash: %s)\n", i + 1, p->files[i].file,
hash);
}
free(hash);
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
}
void
roa_print(const X509 *x, const struct roa *p)
{
char buf[128];
size_t i;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"roa\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
printf("\t\"sia\": \"%s\",\n", p->sia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
x509_print(x);
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
printf("Authority info access: %s\n", p->aia);
printf("Subject info access: %s\n", p->sia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("ROA not before: %s\n",
time2str(p->notbefore));
printf("ROA not after: %s\n", time2str(p->notafter));
printf("asID: %u\n", p->asid);
printf("IP address blocks: ");
}
for (i = 0; i < p->ipsz; i++) {
if (i == 0 && outformats & FORMAT_JSON)
printf("\t\"vrps\": [\n");
ip_addr_print(&p->ips[i].addr,
p->ips[i].afi, buf, sizeof(buf));
if (outformats & FORMAT_JSON) {
printf("\t\t{ \"prefix\": \"%s\",", buf);
printf(" \"asid\": %u,", p->asid);
printf(" \"maxlen\": %hhu }", p->ips[i].maxlength);
if (i + 1 < p->ipsz)
printf(",");
printf("\n");
} else {
if (i > 0)
printf("%26s", "");
printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength);
}
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
}
void
gbr_print(const X509 *x, const struct gbr *p)
{
size_t i;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"gbr\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
printf("\t\"sia\": \"%s\",\n", p->sia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
printf("\t\"vcard\": \"");
for (i = 0; i < strlen(p->vcard); i++) {
if (p->vcard[i] == '"')
printf("\\\"");
if (p->vcard[i] == '\r')
continue;
if (p->vcard[i] == '\n')
printf("\\r\\n");
else
putchar(p->vcard[i]);
}
printf("\",\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
x509_print(x);
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
printf("Authority info access: %s\n", p->aia);
printf("Subject info access: %s\n", p->sia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("GBR not before: %s\n",
time2str(p->notbefore));
printf("GBR not after: %s\n", time2str(p->notafter));
printf("vcard:\n%s", p->vcard);
}
}
void
rsc_print(const X509 *x, const struct rsc *p)
{
char buf1[64], buf2[64];
char *hash;
int sockt;
size_t i, j;
if (outformats & FORMAT_JSON) {
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
x509_print(x);
printf("\t\"aia\": \"%s\",\n", p->aia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
printf("\t\"signed_with_resources\": [\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
x509_print(x);
printf("Authority info access: %s\n", p->aia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("RSC not before: %s\n",
time2str(p->notbefore));
printf("RSC not after: %s\n", time2str(p->notafter));
printf("Signed with resources: ");
}
for (i = 0; i < p->asz; i++) {
switch (p->as[i].type) {
case CERT_AS_ID:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"asid\": %u }", p->as[i].id);
else {
if (i > 0)
printf("%26s", "");
printf("AS: %u", p->as[i].id);
}
break;
case CERT_AS_RANGE:
if (outformats & FORMAT_JSON)
printf("\t\t{ \"asrange\": { \"min\": %u, "
"\"max\": %u }}", p->as[i].range.min,
p->as[i].range.max);
else {
if (i > 0)
printf("%26s", "");
printf("AS: %u -- %u", p->as[i].range.min,
p->as[i].range.max);
}
break;
case CERT_AS_INHERIT:
/* inheritance isn't possible in RSC */
break;
}
if (outformats & FORMAT_JSON && i + 1 < p->asz + p->ipsz)
printf(",\n");
else
printf("\n");
}
for (j = 0; j < p->ipsz; j++) {
switch (p->ips[j].type) {
case CERT_IP_ADDR:
ip_addr_print(&p->ips[j].ip,
p->ips[j].afi, buf1, sizeof(buf1));
if (outformats & FORMAT_JSON)
printf("\t\t{ \"ip_prefix\": \"%s\" }", buf1);
else {
if (i > 0 || j > 0)
printf("%26s", "");
printf("IP: %s", buf1);
}
break;
case CERT_IP_RANGE:
sockt = (p->ips[j].afi == AFI_IPV4) ?
AF_INET : AF_INET6;
inet_ntop(sockt, p->ips[j].min, buf1, sizeof(buf1));
inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2));
if (outformats & FORMAT_JSON)
printf("\t\t{ \"ip_range\": { \"min\": \"%s\""
", \"max\": \"%s\" }}", buf1, buf2);
else {
if (i > 0 || j > 0)
printf("%26s", "");
printf("IP: %s -- %s", buf1, buf2);
}
break;
case CERT_IP_INHERIT:
/* inheritance isn't possible in RSC */
break;
}
if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz)
printf(",\n");
else
printf("\n");
}
if (outformats & FORMAT_JSON) {
printf("\t],\n");
printf("\t\"filenamesandhashes\": [\n");
} else
printf("Filenames and hashes: ");
for (i = 0; i < p->filesz; i++) {
if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
&hash) == -1)
errx(1, "base64_encode failure");
if (outformats & FORMAT_JSON) {
printf("\t\t{ \"filename\": \"%s\",",
p->files[i].filename ? p->files[i].filename : "");
printf(" \"hash_digest\": \"%s\" }", hash);
if (i + 1 < p->filesz)
printf(",");
printf("\n");
} else {
if (i > 0)
printf("%26s", "");
printf("%zu: %s (hash: %s)\n", i + 1,
p->files[i].filename ? p->files[i].filename
: "no filename", hash);
}
free(hash);
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
}
static void
aspa_implicit_afi(const struct aspa *a)
{
size_t i;
size_t v4cnt = 0, v6cnt = 0;
for (i = 0; i < a->providersz; i++) {
switch (a->providers[i].afi) {
case AFI_IPV4:
v4cnt++;
break;
case AFI_IPV6:
v6cnt++;
break;
default:
return;
}
}
if (outformats & FORMAT_JSON) {
if (a->providersz == v4cnt)
printf("\t\t{ \"asid\": 0, \"afi_limit\": \"ipv6\" },\n");
if (a->providersz == v6cnt)
printf("\t\t{ \"asid\": 0, \"afi_limit\": \"ipv4\" },\n");
} else {
if (a->providersz == v4cnt)
printf("%25s AS: 0 (IPv6 only)\n", "");
if (a->providersz == v6cnt)
printf("%25s AS: 0 (IPv4 only)\n", "");
}
}
void
aspa_print(const X509 *x, const struct aspa *p)
{
size_t i;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"aspa\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
printf("\t\"sia\": \"%s\",\n", p->sia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
printf("\t\"customer_asid\": %u,\n", p->custasid);
printf("\t\"provider_set\": [\n");
aspa_implicit_afi(p);
for (i = 0; i < p->providersz; i++) {
printf("\t\t{ \"asid\": %u", p->providers[i].as);
if (p->providers[i].afi == AFI_IPV4)
printf(", \"afi_limit\": \"ipv4\"");
if (p->providers[i].afi == AFI_IPV6)
printf(", \"afi_limit\": \"ipv6\"");
printf(" }");
if (i + 1 < p->providersz)
printf(",");
printf("\n");
}
printf("\t],\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
x509_print(x);
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
printf("Authority info access: %s\n", p->aia);
printf("Subject info access: %s\n", p->sia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("ASPA not before: %s\n",
time2str(p->notbefore));
printf("ASPA not after: %s\n", time2str(p->notafter));
printf("Customer ASID: %u\n", p->custasid);
printf("Provider set: ");
for (i = 0; i < p->providersz; i++) {
if (i > 0)
printf("%26s", "");
printf("AS: %d", p->providers[i].as);
switch (p->providers[i].afi) {
case AFI_IPV4:
printf(" (IPv4 only)");
break;
case AFI_IPV6:
printf(" (IPv6 only)");
break;
default:
break;
}
printf("\n");
}
aspa_implicit_afi(p);
}
}
static void
takey_print(char *name, const struct takey *t)
{
char *spki = NULL;
size_t i, j = 0;
if (base64_encode(t->pubkey, t->pubkeysz, &spki) != 0)
errx(1, "base64_encode failed in %s", __func__);
if (outformats & FORMAT_JSON) {
printf("\t\t{\n\t\t\t\"name\": \"%s\",\n", name);
printf("\t\t\t\"comments\": [");
for (i = 0; i < t->commentsz; i++) {
printf("\"%s\"", t->comments[i]);
if (i + 1 < t->commentsz)
printf(", ");
}
printf("],\n");
printf("\t\t\t\"uris\": [");
for (i = 0; i < t->urisz; i++) {
printf("\"%s\"", t->uris[i]);
if (i + 1 < t->urisz)
printf(", ");
}
printf("],\n");
printf("\t\t\t\"spki\": \"%s\"\n\t\t}", spki);
} else {
printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name);
for (i = 0; i < t->commentsz; i++) {
printf("\t# %s\n", t->comments[i]);
}
for (i = 0; i < t->urisz; i++) {
printf("\t%s\n\n\t", t->uris[i]);
}
for (i = 0; i < strlen(spki); i++) {
printf("%c", spki[i]);
j++;
if (j == 64) {
printf("\n\t");
j = 0;
}
}
printf("\n\n");
}
free(spki);
}
void
tak_print(const X509 *x, const struct tak *p)
{
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"tak\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
printf("\t\"sia\": \"%s\",\n", p->sia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
if (p->expires)
printf("\t\"expires\": %lld,\n", (long long)p->expires);
printf("\t\"takeys\": [\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
x509_print(x);
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
printf("Authority info access: %s\n", p->aia);
printf("Subject info access: %s\n", p->sia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("TAK not before: %s\n",
time2str(p->notbefore));
printf("TAK not after: %s\n", time2str(p->notafter));
}
takey_print("current", p->current);
if (p->predecessor != NULL) {
if (outformats & FORMAT_JSON)
printf(",\n");
takey_print("predecessor", p->predecessor);
}
if (p->successor != NULL) {
if (outformats & FORMAT_JSON)
printf(",\n");
takey_print("successor", p->successor);
}
if (outformats & FORMAT_JSON)
printf("\n\t],\n");
}
void
geofeed_print(const X509 *x, const struct geofeed *p)
{
char buf[128];
size_t i;
if (outformats & FORMAT_JSON) {
printf("\t\"type\": \"geofeed\",\n");
printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
x509_print(x);
printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
printf("\t\"aia\": \"%s\",\n", p->aia);
if (p->signtime != 0)
printf("\t\"signing_time\": %lld,\n",
(long long)p->signtime);
printf("\t\"valid_since\": %lld,\n", (long long)p->notbefore);
printf("\t\"valid_until\": %lld,\n", (long long)p->notafter);
printf("\t\"records\": [\n");
} else {
printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
x509_print(x);
printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
printf("Authority info access: %s\n", p->aia);
if (p->signtime != 0)
printf("Signing time: %s\n",
time2str(p->signtime));
printf("Geofeed not before: %s\n",
time2str(p->notbefore));
printf("Geofeed not after: %s\n", time2str(p->notafter));
printf("Geofeed CSV records: ");
}
for (i = 0; i < p->geoipsz; i++) {
if (p->geoips[i].ip->type != CERT_IP_ADDR)
continue;
ip_addr_print(&p->geoips[i].ip->ip, p->geoips[i].ip->afi, buf,
sizeof(buf));
if (outformats & FORMAT_JSON)
printf("\t\t{ \"prefix\": \"%s\", \"location\": \"%s\""
"}", buf, p->geoips[i].loc);
else {
if (i > 0)
printf("%26s", "");
printf("IP: %s (%s)", buf, p->geoips[i].loc);
}
if (outformats & FORMAT_JSON && i + 1 < p->geoipsz)
printf(",\n");
else
printf("\n");
}
if (outformats & FORMAT_JSON)
printf("\t],\n");
}