Use this to create/sign/interact with OADA developer certificates and any other keys or signatures in the OADA and Trellis ecosystems.
# If you want command-line tool:
yarn global add @oada/certs
# If you just want to use the JS libs in your project:
yarn add @oada/certs
cd domain_folder
oada-certs --create-keys
oada-certs
NOTE: default is to look in the current folder for signing keys
# creates signed_software_statement.js in current folder
oada-certs --signkey="./some_path_to_privatekey_pem" --sign=./some_path_to_unsigned_cert.js
# If you are hosting signing key with a jku:
oada-certs --signkey="./some_path_to_privatekey_pem" --signjku="https://some.jku.url" --signkid="someKeyIdAtThatJKU" --sign="./path_to_unsigned_cert.js"
# Note: caching is in-memory and therefore unused here
oada-certs --validate="signed_software_statement.js"
# If there are errors, they will print here. It will
# also tell you if the certificate is trusted
import * as oadacerts from '@oada/certs';
// If you don't pass a jku, it puts the public jwk for the
// sign key into the JWT automatically
try {
const signed_jwt_cert = await oadacerts.sign(payload, signkey, {
jku: 'https://url.to.some.jwkset',
kid: 'someKeyidInThatSet',
});
} catch (error: unknown) {
console.log(error, 'Error in signing certificate');
}
// Returns a promise:
const { trusted, payload, valid, details } = await oadacerts.validate(
signed_jwt_cert
);
// trusted = true if cert was signed by key on a trusted list
// payload = JSON object that is the decoded client certificate
// valid = true if cert was decodable with a correct signature
// details = array of details about the validation process to help with debugging a cert
// NOTE: if the certificate is untrusted, it cannot use a jku in the signature,
// it must use a jwk to be considered valid. This avoids fetching potentially malicious URL's.
// Self-explanatory utilities for working with JWK key sets (jwks):
oadacerts.jwksUtils.isJWK(key);
oadacerts.jwksUtils.isJWKset(set);
oadacerts.jwksUtils.findJWK(kid, jwks);
// jwkForSignature attempts to figure out the correct public JWK to use in
// validating a given signature. Uses an intelligent cache for remote-hosted
// jwk's.
// What makes this function tricky is the "hint":
// It was designed to make it simple to say something like:
// "hint: I looked up the JKU ot JWK on the signature, and it was from a trusted source."
// (i.e. hint = truthy),
// and it's truthy value is then either the JWKS (object) from the trusted source,
// or the jku (string) of the trusted source's jwks
// or
// "hint: I looked at my trusted sources and this one doesn't have a jwk or jku that matches."
// (i.e. hint === false)
// which means "just use the header on the signature because I have no outside reference that verifies it"
//
// - If boolean false, use the jku from the jose header and if no jku then use jose's jwk
// - If boolean true, throw error (it should have been either an object or a string)
// - If string, assume string is a jku uri, go get that URI and then check jose's jwk against it
// - If object and looks like a jwks, look for jose's jwk in the set
// - If object and looks like a jwk, compare that jwk with jose's jwk
const jwk = oadacerts.jwksUtils.jwkForSignature(jwt, hint, { timeout: 1000 });
Generates a JWT with the given payload, signed with the given key. Key should be a JWK, but it can also be a PEM string.
payload
required: The JSON payload to sign in the JWT.key
required: JWK private key to sign with. If this is a string instead of a JWK, it is assumed to be a PEM string.options
optional: If you need to specify a givenkid
(key id) andjku
(JWK set URL) because your key is trusted, you can pass them here inoptions.header
.options.header
is passed tojose.JWS.createSign
.
sig
required: the signed JWT to validateoptions
optional:options.timeout
(default: 1000 ms): How long to wait on remote URL requests.options.trustedListCacheTime
(default: 3600 sec): How long to use immediately use the cached value for the trusted list before waiting on the request to finish.options.additionalTrustedListURIs
: Any additional URLs (array of strings) to include in the search for a trusted key.options.disableDefaultTrustedListURI
: Only use the additionalTrustedListURI's, not the default one.
Returns { trusted, payload, valid, header, details }
trusted
:true|false
: true if signing key was on the trusted listpayload
: the decoded payloadvalid
:true|false
: true if the JWT was a valid JWT and the signature matched, says nothing about whether it was trusted.details
: array of strings about the validation process that can be helpful for debugging.
Exports the core TRUSTED_LIST_URI
string for convenience as a property on the validate function.
Mainly for testing, you can clear the internal in-memory cache for all trusted lists with this function.
Return true
if set
looks like a JWK set (jwks
)
Return true
if key
looks like a jwk
.
Search for the given kid
(key id) in the jwks
(JWK set)
Given a JWT, decode the header, payload, and signature without verifying them.
Returns { header, payload, signature }
Returns to you the JWK necessary to validate a given JWT. Described above in detail in the javascript example.
Mainly for testing, clear the internal JWK key cache (i.e. previous jku
-based keys that it has looked up). This is not the trusted list cache.
Returns the JWK cache to you if you want to see it. Mainly for testing.
Eliminates the oldest entry from the JWK cache. Mainly for testing.
Returns { public, private }
. Both are JWK's. You can use private
to sign things.
Given a private JWK, return the corresponding public key as a JWK.
Exports the internally-used node-jose
module for convenience.