UNPKG

@ldclabs/cose-ts

Version:

Implemented Keys, Algorithms (RFC9053), COSE (RFC9052) and CWT (RFC8392) in TypeScript.

147 lines 5.01 kB
// (c) 2023-present, LDC Labs. All rights reserved. // See the file LICENSE for licensing terms. import { KVMap, assertText, assertInt, assertBytes, assertMap } from './map'; import * as iana from './iana'; import { decodeCBOR } from './utils'; import { withTag, CwtPrefix } from './tag'; const cwtMaxClockSkewMinutes = 10; // Claims represents a set of common claims for CWT. // // Reference https://www.iana.org/assignments/cwt/cwt.xhtml export class Claims extends KVMap { static fromBytes(data) { return new Claims(decodeCBOR(data)); } constructor(kv = new Map()) { super(kv); } get iss() { return this.getText(iana.CWTClaimIss, 'iss'); } set iss(iss) { this.setParam(iana.CWTClaimIss, assertText(iss, 'iss')); } get sub() { return this.getText(iana.CWTClaimSub, 'sub'); } set sub(sub) { this.setParam(iana.CWTClaimSub, assertText(sub, 'sub')); } get aud() { return this.getText(iana.CWTClaimAud, 'aud'); } set aud(aud) { this.setParam(iana.CWTClaimAud, assertText(aud, 'aud')); } get exp() { return this.getInt(iana.CWTClaimExp, 'exp'); } set exp(exp) { this.setParam(iana.CWTClaimExp, assertInt(exp, 'exp')); } get nbf() { return this.getInt(iana.CWTClaimNbf, 'nbf'); } set nbf(nbf) { this.setParam(iana.CWTClaimNbf, assertInt(nbf, 'nbf')); } get iat() { return this.getInt(iana.CWTClaimIat, 'iat'); } set iat(iat) { this.setParam(iana.CWTClaimIat, assertInt(iat, 'iat')); } get cti() { return this.getBytes(iana.CWTClaimCti, 'cti'); } set cti(cti) { this.setParam(iana.CWTClaimCti, assertBytes(cti, 'cti')); } get cnf() { return this.getType(iana.CWTClaimCnf, assertMap, 'cnf'); } set cnf(cnf) { this.setParam(iana.CWTClaimCnf, assertMap(cnf, 'cnf')); } get scope() { return this.getText(iana.CWTClaimScope, 'scope'); } set scope(scope) { this.setParam(iana.CWTClaimScope, assertText(scope, 'scope')); } get nonce() { return this.getBytes(iana.CWTClaimNonce, 'nonce'); } set nonce(nonce) { this.setParam(iana.CWTClaimNonce, assertBytes(nonce, 'nonce')); } } export function withCWTTag(coseData) { return withTag(CwtPrefix, coseData); } export class Validator { opts; constructor(opts) { this.opts = { expectedIssuer: '', expectedAudience: '', allowMissingExpiration: false, expectIssuedInThePast: false, clockSkew: 0, fixedNow: null, ...opts }; if (this.opts.clockSkew > cwtMaxClockSkewMinutes * 60) { throw new Error(`cose-ts: clock skew cannot be greater than ${cwtMaxClockSkewMinutes} minutes`); } } // Validate validates a *Claims according to the options provided. validate(claims) { if (!(claims instanceof Claims)) { throw new TypeError('cose-ts: claims must be a Claims'); } const now_secs = this.opts.fixedNow == null ? Date.now() / 1000 : this.opts.fixedNow.getTime() / 1000; if (!claims.has(iana.CWTClaimExp)) { if (!this.opts.allowMissingExpiration) { throw new Error('cose-ts: token must have an expiration set'); } } else { const exp = claims.exp; if (exp <= 0) { throw new Error('cose-ts: token must have a positive expiration'); } if (exp + this.opts.clockSkew < now_secs) { throw new Error('cose-ts: token has expired'); } } if (claims.has(iana.CWTClaimNbf)) { const nbf = claims.nbf; if (nbf <= 0 || nbf > now_secs + this.opts.clockSkew) { throw new Error('cose-ts: token cannot be used yet'); } } if (claims.has(iana.CWTClaimIat)) { const iat = claims.iat; if (iat > now_secs + this.opts.clockSkew && this.opts.expectIssuedInThePast) { throw new Error('cose-ts: token has an invalid iat claim in the future'); } } if (this.opts.expectedIssuer !== '') { const iss = claims.has(iana.CWTClaimIss) ? claims.iss : ''; if (iss !== this.opts.expectedIssuer) { throw new Error(`cose-ts: token has an invalid iss claim, expected ${this.opts.expectedIssuer}, got ${iss}`); } } if (this.opts.expectedAudience !== '') { const aud = claims.has(iana.CWTClaimAud) ? claims.aud : ''; if (aud !== this.opts.expectedAudience) { throw new Error(`cose-ts: token has an invalid aud claim, expected ${this.opts.expectedAudience}, got ${aud}`); } } } } //# sourceMappingURL=cwt.js.map