k8s-set-context/node_modules/jose/lib/help/ecdsa_signatures.js
2021-12-07 13:18:08 -05:00

181 lines
4.9 KiB
JavaScript

const MAX_OCTET = 0x80
const CLASS_UNIVERSAL = 0
const PRIMITIVE_BIT = 0x20
const TAG_SEQ = 0x10
const TAG_INT = 0x02
const ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6)
const ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6)
const getParamSize = keySize => ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1)
const paramBytesForAlg = {
ES256: getParamSize(256),
ES256K: getParamSize(256),
ES384: getParamSize(384),
ES512: getParamSize(521)
}
const countPadding = (buf, start, stop) => {
let padding = 0
while (start + padding < stop && buf[start + padding] === 0) {
++padding
}
const needsSign = buf[start + padding] >= MAX_OCTET
if (needsSign) {
--padding
}
return padding
}
module.exports.derToJose = (signature, alg) => {
if (!Buffer.isBuffer(signature)) {
throw new TypeError('ECDSA signature must be a Buffer')
}
if (!paramBytesForAlg[alg]) {
throw new Error(`Unknown algorithm "${alg}"`)
}
const paramBytes = paramBytesForAlg[alg]
// the DER encoded param should at most be the param size, plus a padding
// zero, since due to being a signed integer
const maxEncodedParamLength = paramBytes + 1
const inputLength = signature.length
let offset = 0
if (signature[offset++] !== ENCODED_TAG_SEQ) {
throw new Error('Could not find expected "seq"')
}
let seqLength = signature[offset++]
if (seqLength === (MAX_OCTET | 1)) {
seqLength = signature[offset++]
}
if (inputLength - offset < seqLength) {
throw new Error(`"seq" specified length of ${seqLength}", only ${inputLength - offset}" remaining`)
}
if (signature[offset++] !== ENCODED_TAG_INT) {
throw new Error('Could not find expected "int" for "r"')
}
const rLength = signature[offset++]
if (inputLength - offset - 2 < rLength) {
throw new Error(`"r" specified length of "${rLength}", only "${inputLength - offset - 2}" available`)
}
if (maxEncodedParamLength < rLength) {
throw new Error(`"r" specified length of "${rLength}", max of "${maxEncodedParamLength}" is acceptable`)
}
const rOffset = offset
offset += rLength
if (signature[offset++] !== ENCODED_TAG_INT) {
throw new Error('Could not find expected "int" for "s"')
}
const sLength = signature[offset++]
if (inputLength - offset !== sLength) {
throw new Error(`"s" specified length of "${sLength}", expected "${inputLength - offset}"`)
}
if (maxEncodedParamLength < sLength) {
throw new Error(`"s" specified length of "${sLength}", max of "${maxEncodedParamLength}" is acceptable`)
}
const sOffset = offset
offset += sLength
if (offset !== inputLength) {
throw new Error(`Expected to consume entire buffer, but "${inputLength - offset}" bytes remain`)
}
const rPadding = paramBytes - rLength
const sPadding = paramBytes - sLength
const dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength)
for (offset = 0; offset < rPadding; ++offset) {
dst[offset] = 0
}
signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength)
offset = paramBytes
for (const o = offset; offset < o + sPadding; ++offset) {
dst[offset] = 0
}
signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength)
return dst
}
module.exports.joseToDer = (signature, alg) => {
if (!Buffer.isBuffer(signature)) {
throw new TypeError('ECDSA signature must be a Buffer')
}
if (!paramBytesForAlg[alg]) {
throw new TypeError(`Unknown algorithm "${alg}"`)
}
const paramBytes = paramBytesForAlg[alg]
const signatureBytes = signature.length
if (signatureBytes !== paramBytes * 2) {
throw new Error(`"${alg}" signatures must be "${paramBytes * 2}" bytes, saw "${signatureBytes}"`)
}
const rPadding = countPadding(signature, 0, paramBytes)
const sPadding = countPadding(signature, paramBytes, signature.length)
const rLength = paramBytes - rPadding
const sLength = paramBytes - sPadding
const rsBytes = 1 + 1 + rLength + 1 + 1 + sLength
const shortLength = rsBytes < MAX_OCTET
const dst = Buffer.allocUnsafe((shortLength ? 2 : 3) + rsBytes)
let offset = 0
dst[offset++] = ENCODED_TAG_SEQ
if (shortLength) {
// Bit 8 has value "0"
// bits 7-1 give the length.
dst[offset++] = rsBytes
} else {
// Bit 8 of first octet has value "1"
// bits 7-1 give the number of additional length octets.
dst[offset++] = MAX_OCTET | 1 // eslint-disable-line no-tabs
// length, base 256
dst[offset++] = rsBytes & 0xff
}
dst[offset++] = ENCODED_TAG_INT
dst[offset++] = rLength
if (rPadding < 0) {
dst[offset++] = 0
offset += signature.copy(dst, offset, 0, paramBytes)
} else {
offset += signature.copy(dst, offset, rPadding, paramBytes)
}
dst[offset++] = ENCODED_TAG_INT
dst[offset++] = sLength
if (sPadding < 0) {
dst[offset++] = 0
signature.copy(dst, offset, paramBytes)
} else {
signature.copy(dst, offset, paramBytes + sPadding)
}
return dst
}