node-webtokens
Version:
Simple, opinionated implementation of JWS and JWE compact serialization
79 lines (75 loc) • 2.7 kB
JavaScript
const ERR_MSG = 'Could not extract parameters from DER signature';
exports.derToConcat = (signature, size) => {
let offset = 0;
if (signature[offset++] !== 0x30) throw new Error(ERR_MSG);
let seqLength = signature[offset++];
if (seqLength === 0x81) seqLength = signature[offset++];
if (seqLength > signature.length - offset || signature[offset++] !== 0x02) {
throw new Error(ERR_MSG);
}
let rLength = signature[offset++];
if (rLength > signature.length - offset - 2 || rLength > size + 1) {
throw new Error(ERR_MSG);
}
let rOffset = offset;
offset += rLength;
if (signature[offset++] !== 0x02) throw new Error(ERR_MSG);
let sLength = signature[offset++];
if (sLength !== signature.length - offset || sLength > size + 1) {
throw new Error(ERR_MSG);
}
let sOffset = offset;
offset += sLength;
if (offset !== signature.length) throw new Error(ERR_MSG);
let rPadding = size - rLength;
let sPadding = size - sLength;
let dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength);
for (offset = 0; offset < rPadding; offset++) dst[offset] = 0;
let rPad = Math.max(-rPadding, 0);
signature.copy(dst, offset, rOffset + rPad, rOffset + rLength);
offset = size;
for (let o = offset; offset < o + sPadding; offset++) dst[offset] = 0;
let sPad = Math.max(-sPadding, 0);
signature.copy(dst, offset, sOffset + sPad, sOffset + sLength);
return dst;
}
exports.concatToDer = (signature, size) => {
let rPadding = countPadding(signature, 0, size);
let sPadding = countPadding(signature, size, signature.length);
let rLength = size - rPadding;
let sLength = size - sPadding;
let rsBytes = rLength + sLength + 4;
let shortLength = rsBytes < 0x80;
let dst = Buffer.allocUnsafe((shortLength ? 2 : 3) + rsBytes);
let offset = 0;
dst[offset++] = 0x30;
if (shortLength) {
dst[offset++] = rsBytes;
} else {
dst[offset++] = 0x81;
dst[offset++] = rsBytes & 0xFF;
}
dst[offset++] = 0x02;
dst[offset++] = rLength;
if (rPadding < 0) {
dst[offset++] = 0;
offset += signature.copy(dst, offset, 0, size);
} else {
offset += signature.copy(dst, offset, rPadding, size);
}
dst[offset++] = 0x02;
dst[offset++] = sLength;
if (sPadding < 0) {
dst[offset++] = 0;
signature.copy(dst, offset, size);
} else {
signature.copy(dst, offset, size + sPadding);
}
return dst;
}
function countPadding(buf, start, stop) {
let padding = 0;
while (start + padding < stop && buf[start + padding] === 0) padding++;
let needsSign = buf[start + padding] >= 0x80;
return needsSign ? --padding : padding;
}