diff options
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/asn1.js/encoders/der.js')
-rw-r--r-- | ext/node/polyfills/_crypto/crypto_browserify/asn1.js/encoders/der.js | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/encoders/der.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/encoders/der.js new file mode 100644 index 000000000..3f03ef347 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/encoders/der.js @@ -0,0 +1,348 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Fedor Indutny. All rights reserved. MIT license. + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; +import { Node } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js"; + +// Import DER constants +import * as der from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/constants/der.js"; + +export function DEREncoder(entity) { + this.enc = "der"; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); +} + +DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); +}; + +// Tree methods + +function DERNode(parent) { + Node.call(this, "der", parent); +} +// inherits(DERNode, Node); +DERNode.prototype = Object.create(Node.prototype, { + constructor: { + value: DERNode, + enumerable: false, + writable: true, + configurable: true, + }, +}); + +DERNode.prototype._encodeComposite = function encodeComposite( + tag, + primitive, + cls, + content, +) { + const encodedTag = encodeTag(tag, primitive, cls, this.reporter); + + // Short form + if (content.length < 0x80) { + const header = Buffer.alloc(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([header, content]); + } + + // Long form + // Count octets required to store length + let lenOctets = 1; + for (let i = content.length; i >= 0x100; i >>= 8) { + lenOctets++; + } + + const header = Buffer.alloc(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; + + for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) { + header[i] = j & 0xff; + } + + return this._createEncoderBuffer([header, content]); +}; + +DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === "bitstr") { + return this._createEncoderBuffer([str.unused | 0, str.data]); + } else if (tag === "bmpstr") { + const buf = Buffer.alloc(str.length * 2); + for (let i = 0; i < str.length; i++) { + buf.writeUInt16BE(str.charCodeAt(i), i * 2); + } + return this._createEncoderBuffer(buf); + } else if (tag === "numstr") { + if (!this._isNumstr(str)) { + return this.reporter.error( + "Encoding of string type: numstr supports " + + "only digits and space", + ); + } + return this._createEncoderBuffer(str); + } else if (tag === "printstr") { + if (!this._isPrintstr(str)) { + return this.reporter.error( + "Encoding of string type: printstr supports " + + "only latin upper and lower case letters, " + + "digits, space, apostrophe, left and rigth " + + "parenthesis, plus sign, comma, hyphen, " + + "dot, slash, colon, equal sign, " + + "question mark", + ); + } + return this._createEncoderBuffer(str); + } else if (/str$/.test(tag)) { + return this._createEncoderBuffer(str); + } else if (tag === "objDesc") { + return this._createEncoderBuffer(str); + } else { + return this.reporter.error( + "Encoding of string type: " + tag + + " unsupported", + ); + } +}; + +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === "string") { + if (!values) { + return this.reporter.error("string objid given, but no values map found"); + } + // deno-lint-ignore no-prototype-builtins + if (!values.hasOwnProperty(id)) { + return this.reporter.error("objid not found in values map"); + } + id = values[id].split(/[\s.]+/g); + for (let i = 0; i < id.length; i++) { + id[i] |= 0; + } + } else if (Array.isArray(id)) { + id = id.slice(); + for (let i = 0; i < id.length; i++) { + id[i] |= 0; + } + } + + if (!Array.isArray(id)) { + return this.reporter.error( + "objid() should be either array or string, " + + "got: " + JSON.stringify(id), + ); + } + + if (!relative) { + if (id[1] >= 40) { + return this.reporter.error("Second objid identifier OOB"); + } + id.splice(0, 2, id[0] * 40 + id[1]); + } + + // Count number of octets + let size = 0; + for (let i = 0; i < id.length; i++) { + let ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) { + size++; + } + } + + const objid = Buffer.alloc(size); + let offset = objid.length - 1; + for (let i = id.length - 1; i >= 0; i--) { + let ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) { + objid[offset--] = 0x80 | (ident & 0x7f); + } + } + + return this._createEncoderBuffer(objid); +}; + +function two(num) { + if (num < 10) { + return "0" + num; + } else { + return num; + } +} + +DERNode.prototype._encodeTime = function encodeTime(time, tag) { + let str; + const date = new Date(time); + + if (tag === "gentime") { + str = [ + two(date.getUTCFullYear()), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + "Z", + ].join(""); + } else if (tag === "utctime") { + str = [ + two(date.getUTCFullYear() % 100), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + "Z", + ].join(""); + } else { + this.reporter.error("Encoding " + tag + " time is not supported yet"); + } + + return this._encodeStr(str, "octstr"); +}; + +DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(""); +}; + +DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === "string") { + if (!values) { + return this.reporter.error("String int or enum given, but no values map"); + } + // deno-lint-ignore no-prototype-builtins + if (!values.hasOwnProperty(num)) { + return this.reporter.error( + "Values map doesn't contain: " + + JSON.stringify(num), + ); + } + num = values[num]; + } + + // Bignum, assume big endian + if (typeof num !== "number" && !Buffer.isBuffer(num)) { + const numArray = num.toArray(); + if (!num.sign && numArray[0] & 0x80) { + numArray.unshift(0); + } + num = Buffer.from(numArray); + } + + if (Buffer.isBuffer(num)) { + let size = num.length; + if (num.length === 0) { + size++; + } + + const out = Buffer.alloc(size); + num.copy(out); + if (num.length === 0) { + out[0] = 0; + } + return this._createEncoderBuffer(out); + } + + if (num < 0x80) { + return this._createEncoderBuffer(num); + } + + if (num < 0x100) { + return this._createEncoderBuffer([0, num]); + } + + let size = 1; + for (let i = num; i >= 0x100; i >>= 8) { + size++; + } + + const out = new Array(size); + for (let i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; + } + if (out[0] & 0x80) { + out.unshift(0); + } + + return this._createEncoderBuffer(Buffer.from(out)); +}; + +DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); +}; + +DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === "function") { + entity = entity(obj); + } + return entity._getEncoder("der").tree; +}; + +DERNode.prototype._skipDefault = function skipDefault( + dataBuffer, + reporter, + parent, +) { + const state = this._baseState; + let i; + if (state["default"] === null) { + return false; + } + + const data = dataBuffer.join(); + if (state.defaultBuffer === undefined) { + state.defaultBuffer = this._encodeValue(state["default"], reporter, parent) + .join(); + } + + if (data.length !== state.defaultBuffer.length) { + return false; + } + + for (i = 0; i < data.length; i++) { + if (data[i] !== state.defaultBuffer[i]) { + return false; + } + } + + return true; +}; + +// Utility methods + +function encodeTag(tag, primitive, cls, reporter) { + let res; + + if (tag === "seqof") { + tag = "seq"; + } else if (tag === "setof") { + tag = "set"; + } + + // deno-lint-ignore no-prototype-builtins + if (der.tagByName.hasOwnProperty(tag)) { + res = der.tagByName[tag]; + } else if (typeof tag === "number" && (tag | 0) === tag) { + res = tag; + } else { + return reporter.error("Unknown tag: " + tag); + } + + if (res >= 0x1f) { + return reporter.error("Multi-octet tag encoding unsupported"); + } + + if (!primitive) { + res |= 0x20; + } + + res |= der.tagClassByName[cls || "universal"] << 6; + + return res; +} |