Skip to content

Commit

Permalink
Close #313: Support JWK export format of certificates
Browse files Browse the repository at this point in the history
The "x5t" and "x5t#256" properties are always present.
The "x5c" Certificate chain can be optionally selected.
  • Loading branch information
chris2511 committed Sep 13, 2024
1 parent 2e70aa6 commit 60aefea
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 9 deletions.
30 changes: 24 additions & 6 deletions lib/db_x509.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,11 @@ int db_x509::exportFlags(const QModelIndex &idx) const
if (!crt->isCA())
disable_flags |= F_CA;

pki_key *key = crt->getPubKey();
if (key && key->getKeyType() != EVP_PKEY_RSA && key->getJWKcrv().isEmpty())
disable_flags |= F_JWK;
delete key;

return disable_flags;
}

Expand Down Expand Up @@ -643,12 +648,8 @@ void db_x509::exportItems(const QModelIndexList &list,
foreach(crt, certs)
crt->writeCert(file, true);
}
} else if (xport->match_all(F_DER)) {
crt->writeCert(file, false);
} else if (xport->match_all(F_PKCS7)) {
writePKCS7(crt, file, xport->flags, list);
} else if (xport->match_all(F_PKCS12)) {
writePKCS12(crt, file, xport->match_all(F_CHAIN));
} else if (xport->match_all(F_INDEX)) {
writeIndex(file, certs);
} else if (xport->match_all(F_CAL)) {
Expand All @@ -658,10 +659,27 @@ void db_x509::exportItems(const QModelIndexList &list,
crt->icsVEVENT_ca() : crt->icsVEVENT();
}
writeVcalendar(file, vcal);
} else if (xport->match_all(F_CONFIG)) {
crt->opensslConf(file);
} else if (xport->match_all(F_TAKEY)) {
file.write(crt->getTaKey().toLatin1());
} else {
qDebug() << "exportItems: db_base";
db_base::exportItems(list, xport, file);
}
}

void db_x509::exportItem(const QModelIndex &index,
const pki_export *xport, XFile &file) const
{
pki_x509 *crt = fromIndex<pki_x509>(index);

if (xport->match_all(F_DER)) {
crt->writeCert(file, false);
} else if (xport->match_all(F_PKCS12)) {
writePKCS12(crt, file, xport->match_all(F_CHAIN));
} else if (xport->match_all(F_CONFIG)) {
crt->opensslConf(file);
} else {
db_base::exportItem(index, xport, file);
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/db_x509.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class db_x509: public db_x509super
int exportFlags(const QModelIndex &idx) const;
void exportItems(const QModelIndexList &indexes,
const pki_export *xport, XFile &file) const;
void exportItem(const QModelIndex &, const pki_export *, XFile &) const;

public slots:
void newItem();
Expand Down
2 changes: 2 additions & 0 deletions lib/pki_export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ new pki_export(17, x509, "ics", tr("vCalendar"), F_CAL,
new pki_export(18, x509, "ics", tr("CA vCalendar"), F_CAL | F_CA, tr("vCalendar expiry reminder containing all issued, valid certificates, the CA itself and the latest CRL")),
new pki_export(38, x509, "conf", tr("OpenSSL config"), F_SINGLE | F_CONFIG, tr("OpenSSL configuration file to create a certificate or request with the openssl commandline tool")),
new pki_export(39, x509, "key", tr("OpenVPN tls-auth key"), F_SINGLE | F_TAKEY, tr("The OpenVPN tls-auth key is a secret key shared between endpoints")),
new pki_export(42, x509, "jwk", tr("JSON Web Kit"), F_JWK, tr("The public key of the certificate in JSON Web Kit format with X.509 Certificate Thumbprint (x5t)")),
new pki_export(43, x509, "jwk", tr("JSON Web Kit chain"), F_JWK | F_JWK_X5C, tr("The public key of the certificate in JSON Web Kit format with X.509 Certificate Thumbprint (x5t) and certificate chain (x5c)")),

new pki_export(19, asym_key, "pem", tr("PEM public"), F_PEM | F_CLIPBOARD, tr("Text format of the public key in one PEM file")),
new pki_export(20, asym_key, "pem", tr("PEM private"), F_PEM | F_PRIVATE | F_USUAL | F_CLIPBOARD, tr("Unencrypted private key in text format")),
Expand Down
1 change: 1 addition & 0 deletions lib/pki_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum {
F_TRADITION = BIT(23),/* Traditional OpenSSL encrypted PEM */
F_UNUSABLE = BIT(24),/* Unusable certificates */
F_JWK = BIT(25),/* JSON Web Key (JWK) RFC-7517 */
F_JWK_X5C = BIT(26),/* JSON Web Key (JWK) RFC-7517 X.509 Certificate Chain */
};

class pki_export : public QObject {
Expand Down
26 changes: 24 additions & 2 deletions lib/pki_x509.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,28 @@ bool pki_x509::pem(BioByteArray &b)
return true;
}

void pki_x509::fillJWK(QJsonObject &json, const pki_export *xport) const
{
QByteArray der = i2d();
pki_key *key = getPubKey();

key->fillJWK(json, xport);
json["kid"] = getIntName();
json["x5t"] = BioByteArray(Digest(der, EVP_sha1())).base64UrlEncode();
json["x5t#256"] = BioByteArray(Digest(der, EVP_sha256())).base64UrlEncode();
if (xport->match_all(F_JWK_X5C)) {
QJsonArray x5c;
for (const pki_x509 *cert = this, *prev = nullptr;
cert && cert != prev;
prev = cert, cert = cert->getSigner())
{
x5c.append(cert->i2d_b64());
}
json["x5c"] = x5c;
}
delete key;
}

bool pki_x509::cmpIssuerAndSerial(pki_x509 *refcert)
{
bool ret = X509_issuer_and_serial_cmp(cert, refcert->cert);
Expand Down Expand Up @@ -869,7 +891,7 @@ void pki_x509::setPubKey(pki_key *key)

QString pki_x509::fingerprint(const EVP_MD *digest) const
{
return ::fingerprint(i2d_bytearray(I2D_VOID(i2d_X509), cert), digest);
return ::fingerprint(i2d(), digest);
}

bool pki_x509::checkDate()
Expand Down Expand Up @@ -918,7 +940,7 @@ int pki_x509::sigAlg() const
return X509_get_signature_nid(cert);
}

pki_x509 *pki_x509::getSigner()
pki_x509 *pki_x509::getSigner() const
{
return Store.lookupPki<pki_x509>(issuerSqlId);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/pki_x509.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@ class pki_x509 : public pki_x509super
bool isCA() const;
bool canSign() const;
void writeCert(XFile &file, bool PEM) const;
void fillJWK(QJsonObject &json, const pki_export *xport) const;
QString getIndexEntry();
bool verify(pki_x509 *signer);
bool verify_only(const pki_x509 *signer) const;
pki_key *getPubKey() const;
void setPubKey(pki_key *key);
pki_x509 *getSigner();
pki_x509 *getSigner() const;
void delSigner(pki_base *s);
QString fingerprint(const EVP_MD *digest) const;
extList getV3ext() const;
Expand Down

0 comments on commit 60aefea

Please sign in to comment.