var inherits = require('inherits'); var Buffer = require('buffer').Buffer; var asn1 = require('../../asn1'); var base = asn1.base; var bignum = asn1.bignum; // Import DER constants var der = asn1.constants.der; 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); }; module.exports = DEREncoder; DEREncoder.prototype.encode = function encode(data, reporter) { return this.tree._encode(data, reporter).join(); }; // Tree methods function DERNode(parent) { base.Node.call(this, 'der', parent); } inherits(DERNode, base.Node); DERNode.prototype._encodeComposite = function encodeComposite(tag, primitive, cls, content) { var encodedTag = encodeTag(tag, primitive, cls, this.reporter); // Short form if (content.length < 0x80) { var header = new Buffer(2); header[0] = encodedTag; header[1] = content.length; return this._createEncoderBuffer([ header, content ]); } // Long form // Count octets required to store length var lenOctets = 1; for (var i = content.length; i >= 0x100; i >>= 8) lenOctets++; var header = new Buffer(1 + 1 + lenOctets); header[0] = encodedTag; header[1] = 0x80 | lenOctets; for (var 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') { var buf = new Buffer(str.length * 2); for (var 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 { 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'); if (!values.hasOwnProperty(id)) return this.reporter.error('objid not found in values map'); id = values[id].split(/[\s\.]+/g); for (var i = 0; i < id.length; i++) id[i] |= 0; } else if (Array.isArray(id)) { id = id.slice(); for (var 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 var size = 0; for (var i = 0; i < id.length; i++) { var ident = id[i]; for (size++; ident >= 0x80; ident >>= 7) size++; } var objid = new Buffer(size); var offset = objid.length - 1; for (var i = id.length - 1; i >= 0; i--) { var 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) { var str; var date = new Date(time); if (tag === 'gentime') { str = [ two(date.getFullYear()), 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.getFullYear() % 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'); 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)) { var numArray = num.toArray(); if (!num.sign && numArray[0] & 0x80) { numArray.unshift(0); } num = new Buffer(numArray); } if (Buffer.isBuffer(num)) { var size = num.length; if (num.length === 0) size++; var out = new Buffer(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]); var size = 1; for (var i = num; i >= 0x100; i >>= 8) size++; var out = new Array(size); for (var i = out.length - 1; i >= 0; i--) { out[i] = num & 0xff; num >>= 8; } if(out[0] & 0x80) { out.unshift(0); } return this._createEncoderBuffer(new Buffer(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) { var state = this._baseState; var i; if (state['default'] === null) return false; var 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) { var res; if (tag === 'seqof') tag = 'seq'; else if (tag === 'setof') tag = 'set'; 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; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19553 | swellard | Move and rename clients | ||
//guest/perforce_software/helix-web-services/main/source/clients/2016.1.0/javascript/node_modules/asn1.js/lib/asn1/encoders/der.js | |||||
#1 | 18810 | tjuricek |
First-pass at JavaScript client SDK. JavaScript requires Node with Gulp to "browserfy" the library. It's the easiest way I found to use the swagger-js project; bundle up a wrapping method. There is no JavaScript reference guide. The swagger-js doesn't really document what they do very well, actually. Overall I'm not particularly impressed by swagger-js, it was hard to even figure out what the right method syntax was. We may want to invest time in doing it better. This required setting CORS response headers, which are currently defaulted to a fairly insecure setting. |