cosette
Version:
isomorphic Typescript COSE implementation
241 lines • 10.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = exports.SignatureMismatchError = exports.create = exports.Sign1Tag = exports.SignTag = exports.cbor = exports.webcrypto = void 0;
const cbor = __importStar(require("cbor-web"));
exports.cbor = cbor;
const isomorphic_webcrypto_1 = __importDefault(require("isomorphic-webcrypto"));
exports.webcrypto = isomorphic_webcrypto_1.default;
const common = __importStar(require("./common"));
const EMPTY_BUFFER = common.EMPTY_BUFFER;
const Tagged = cbor.Tagged;
exports.SignTag = 98;
exports.Sign1Tag = 18;
function doSign(SigStructure, signer, alg) {
return __awaiter(this, void 0, void 0, function* () {
let ToBeSigned = cbor.encode(SigStructure);
return yield isomorphic_webcrypto_1.default.subtle.sign(getAlgorithmParams(alg), signer.key, ToBeSigned);
});
}
function create(headers, payload, signers, options) {
return __awaiter(this, void 0, void 0, function* () {
options = options || {};
const p = common.TranslateHeaders(headers.p || {});
const u = common.TranslateHeaders(headers.u || {});
const bodyP = (p.size === 0) ? EMPTY_BUFFER : cbor.encode(p);
const p_buffer = (p.size === 0 && options.encodep === 'empty') ? EMPTY_BUFFER : cbor.encode(p);
if (Array.isArray(signers)) {
if (signers.length === 0) {
throw new Error('There has to be at least one signer');
}
if (signers.length > 1) {
throw new Error('Only one signer is supported');
}
// TODO handle multiple signers
const signer = signers[0];
const externalAAD = signer.externalAAD || EMPTY_BUFFER;
const signerPMap = common.TranslateHeaders(signer.p || {});
const signerU = common.TranslateHeaders(signer.u || {});
const alg = signerPMap.get(common.HeaderParameters.alg) || signerU.get(common.HeaderParameters.alg);
const signerP = (signerPMap.size === 0) ? EMPTY_BUFFER : cbor.encode(signerPMap);
const SigStructure = [
'Signature',
bodyP,
signerP,
externalAAD,
payload
];
const sig = yield doSign(SigStructure, signer, alg);
const signed = [p_buffer, u, payload, [[signerP, signerU, sig]]];
return cbor.encode(options.excludetag ? signed : new Tagged(exports.SignTag, signed));
}
else {
const signer = signers;
const externalAAD = signer.externalAAD || EMPTY_BUFFER;
const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
const SigStructure = [
'Signature1',
bodyP,
externalAAD,
payload
];
const sig = yield doSign(SigStructure, signer, alg);
const signed = [p_buffer, u, payload, sig];
return cbor.encodeCanonical(options.excludetag ? signed : new Tagged(exports.Sign1Tag, signed));
}
});
}
exports.create = create;
;
function getAlgorithmParams(alg) {
const cose_name = common.AlgFromTags(alg);
if (cose_name.startsWith('ES'))
return { 'name': 'ECDSA', 'hash': 'SHA-' + cose_name.slice(2) };
else if (cose_name.startsWith('RS'))
return { "name": "RSASSA-PKCS1-v1_5" };
else if (cose_name.startsWith('PS'))
return { name: "RSA-PSS", saltLength: +cose_name.slice(2) / 8 };
else
throw new Error('Unsupported algorithm, ' + cose_name);
}
function isSignatureCorrect(SigStructure, verifier, algorithmParams, sig) {
return __awaiter(this, void 0, void 0, function* () {
const ToBeSigned = cbor.encode(SigStructure);
return isomorphic_webcrypto_1.default.subtle.verify(algorithmParams, verifier.key, sig, ToBeSigned);
});
}
function getSignerAndVerifier(signers, verifierFn) {
return __awaiter(this, void 0, void 0, function* () {
let error = new Error("No signer");
for (const signer of signers) {
const kid = signer[1].get(common.HeaderParameters.kid); // TODO create constant for header locations
let [signerP, , signature] = signer;
signerP = !signerP.length ? EMPTY_BUFFER : signerP;
const signerPMap = cbor.decode(signerP);
var alg = signerPMap.get(common.HeaderParameters.alg);
const algorithmParams = getAlgorithmParams(alg);
try {
return { algorithmParams, signerP, signature, verifier: yield verifierFn(kid, algorithmParams) };
}
catch (e) {
error = e;
}
}
throw error;
});
}
function createVerifierFunction(verifier) {
if (verifier.kid == null)
throw new Error("Missing kid");
const kid_buf = new TextEncoder().encode(verifier.kid);
return (kid) => {
if (common.uint8ArrayEquals(kid_buf, kid))
return Promise.resolve(verifier);
else
throw new Error("Invalid kid");
};
}
function getCommonParameter(first, second, parameter) {
let result;
if (first.get) {
result = first.get(parameter);
}
if (!result && second.get) {
result = second.get(parameter);
}
return result;
}
/**
* Error thrown where a message signature could not be verified.
* This may mean that the message was forged.
*
* @member plaintext The decoded message, for which the signature is incorrect.
*/
class SignatureMismatchError extends Error {
constructor(plaintext) {
super(`Signature mismatch: The CBOR message ${JSON.stringify(plaintext)} has an invalid signature.`);
this.name = "SignatureMismatchError";
this.plaintext = plaintext;
}
}
exports.SignatureMismatchError = SignatureMismatchError;
/**
* Verify the COSE signature of a CBOR message.
*
* @throws {SignatureMismatchError} Will throw an exception if the signature is invalid.
* @param payload A CBOR-encoded signed message
* @param verifier The key used to check the signature
* @returns The decoded message, if the signature was correct.
*/
function verify(payload, verifierParam, options) {
return __awaiter(this, void 0, void 0, function* () {
const verifierFn = (typeof verifierParam === 'function') ? verifierParam : createVerifierFunction(verifierParam);
options = options || {};
let obj = yield cbor.decodeFirst(payload);
let type = options.defaultType ? options.defaultType : exports.SignTag;
if (obj instanceof Tagged) {
if (obj.tag !== exports.SignTag && obj.tag !== exports.Sign1Tag) {
throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
}
type = obj.tag;
obj = obj.value;
}
if (!Array.isArray(obj)) {
throw new Error('Expecting Array');
}
if (obj.length !== 4) {
throw new Error('Expecting Array of lenght 4');
}
var [p, u, plaintext, signature] = obj;
if (type === exports.SignTag && !Array.isArray(signature)) {
throw new Error('Expecting signature Array');
}
p = (!p.length) ? EMPTY_BUFFER : cbor.decodeFirstSync(p);
u = (!u.size) ? EMPTY_BUFFER : u;
if (type === exports.SignTag) {
var { algorithmParams, signerP, signature, verifier } = yield getSignerAndVerifier(signature, verifierFn);
const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
var SigStructure = [
'Signature',
p,
signerP,
externalAAD,
plaintext
];
}
else {
var alg = getCommonParameter(p, u, common.HeaderParameters.alg);
const kid = getCommonParameter(p, u, common.HeaderParameters.kid);
var algorithmParams = getAlgorithmParams(alg);
var verifier = yield verifierFn(kid, algorithmParams);
const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
var SigStructure = [
'Signature1',
p,
externalAAD,
plaintext
];
}
if (yield isSignatureCorrect(SigStructure, verifier, algorithmParams, signature)) {
return plaintext;
}
else {
throw new SignatureMismatchError(plaintext);
}
});
}
exports.verify = verify;
;
//# sourceMappingURL=sign.js.map