374 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			374 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2017 Joyent, Inc.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = Identity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var assert = require('assert-plus');
							 | 
						||
| 
								 | 
							
								var algs = require('./algs');
							 | 
						||
| 
								 | 
							
								var crypto = require('crypto');
							 | 
						||
| 
								 | 
							
								var Fingerprint = require('./fingerprint');
							 | 
						||
| 
								 | 
							
								var Signature = require('./signature');
							 | 
						||
| 
								 | 
							
								var errs = require('./errors');
							 | 
						||
| 
								 | 
							
								var util = require('util');
							 | 
						||
| 
								 | 
							
								var utils = require('./utils');
							 | 
						||
| 
								 | 
							
								var asn1 = require('asn1');
							 | 
						||
| 
								 | 
							
								var Buffer = require('safer-buffer').Buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
								var DNS_NAME_RE = /^([*]|[a-z0-9][a-z0-9\-]{0,62})(?:\.([*]|[a-z0-9][a-z0-9\-]{0,62}))*$/i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var oids = {};
							 | 
						||
| 
								 | 
							
								oids.cn = '2.5.4.3';
							 | 
						||
| 
								 | 
							
								oids.o = '2.5.4.10';
							 | 
						||
| 
								 | 
							
								oids.ou = '2.5.4.11';
							 | 
						||
| 
								 | 
							
								oids.l = '2.5.4.7';
							 | 
						||
| 
								 | 
							
								oids.s = '2.5.4.8';
							 | 
						||
| 
								 | 
							
								oids.c = '2.5.4.6';
							 | 
						||
| 
								 | 
							
								oids.sn = '2.5.4.4';
							 | 
						||
| 
								 | 
							
								oids.postalCode = '2.5.4.17';
							 | 
						||
| 
								 | 
							
								oids.serialNumber = '2.5.4.5';
							 | 
						||
| 
								 | 
							
								oids.street = '2.5.4.9';
							 | 
						||
| 
								 | 
							
								oids.x500UniqueIdentifier = '2.5.4.45';
							 | 
						||
| 
								 | 
							
								oids.role = '2.5.4.72';
							 | 
						||
| 
								 | 
							
								oids.telephoneNumber = '2.5.4.20';
							 | 
						||
| 
								 | 
							
								oids.description = '2.5.4.13';
							 | 
						||
| 
								 | 
							
								oids.dc = '0.9.2342.19200300.100.1.25';
							 | 
						||
| 
								 | 
							
								oids.uid = '0.9.2342.19200300.100.1.1';
							 | 
						||
| 
								 | 
							
								oids.mail = '0.9.2342.19200300.100.1.3';
							 | 
						||
| 
								 | 
							
								oids.title = '2.5.4.12';
							 | 
						||
| 
								 | 
							
								oids.gn = '2.5.4.42';
							 | 
						||
| 
								 | 
							
								oids.initials = '2.5.4.43';
							 | 
						||
| 
								 | 
							
								oids.pseudonym = '2.5.4.65';
							 | 
						||
| 
								 | 
							
								oids.emailAddress = '1.2.840.113549.1.9.1';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var unoids = {};
							 | 
						||
| 
								 | 
							
								Object.keys(oids).forEach(function (k) {
							 | 
						||
| 
								 | 
							
									unoids[oids[k]] = k;
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function Identity(opts) {
							 | 
						||
| 
								 | 
							
									var self = this;
							 | 
						||
| 
								 | 
							
									assert.object(opts, 'options');
							 | 
						||
| 
								 | 
							
									assert.arrayOfObject(opts.components, 'options.components');
							 | 
						||
| 
								 | 
							
									this.components = opts.components;
							 | 
						||
| 
								 | 
							
									this.componentLookup = {};
							 | 
						||
| 
								 | 
							
									this.components.forEach(function (c) {
							 | 
						||
| 
								 | 
							
										if (c.name && !c.oid)
							 | 
						||
| 
								 | 
							
											c.oid = oids[c.name];
							 | 
						||
| 
								 | 
							
										if (c.oid && !c.name)
							 | 
						||
| 
								 | 
							
											c.name = unoids[c.oid];
							 | 
						||
| 
								 | 
							
										if (self.componentLookup[c.name] === undefined)
							 | 
						||
| 
								 | 
							
											self.componentLookup[c.name] = [];
							 | 
						||
| 
								 | 
							
										self.componentLookup[c.name].push(c);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									if (this.componentLookup.cn && this.componentLookup.cn.length > 0) {
							 | 
						||
| 
								 | 
							
										this.cn = this.componentLookup.cn[0].value;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									assert.optionalString(opts.type, 'options.type');
							 | 
						||
| 
								 | 
							
									if (opts.type === undefined) {
							 | 
						||
| 
								 | 
							
										if (this.components.length === 1 &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn.length === 1 &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {
							 | 
						||
| 
								 | 
							
											this.type = 'host';
							 | 
						||
| 
								 | 
							
											this.hostname = this.componentLookup.cn[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.dc &&
							 | 
						||
| 
								 | 
							
										    this.components.length === this.componentLookup.dc.length) {
							 | 
						||
| 
								 | 
							
											this.type = 'host';
							 | 
						||
| 
								 | 
							
											this.hostname = this.componentLookup.dc.map(
							 | 
						||
| 
								 | 
							
											    function (c) {
							 | 
						||
| 
								 | 
							
												return (c.value);
							 | 
						||
| 
								 | 
							
											}).join('.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.uid &&
							 | 
						||
| 
								 | 
							
										    this.components.length ===
							 | 
						||
| 
								 | 
							
										    this.componentLookup.uid.length) {
							 | 
						||
| 
								 | 
							
											this.type = 'user';
							 | 
						||
| 
								 | 
							
											this.uid = this.componentLookup.uid[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.cn &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn.length === 1 &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {
							 | 
						||
| 
								 | 
							
											this.type = 'host';
							 | 
						||
| 
								 | 
							
											this.hostname = this.componentLookup.cn[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.uid &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.uid.length === 1) {
							 | 
						||
| 
								 | 
							
											this.type = 'user';
							 | 
						||
| 
								 | 
							
											this.uid = this.componentLookup.uid[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.mail &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.mail.length === 1) {
							 | 
						||
| 
								 | 
							
											this.type = 'email';
							 | 
						||
| 
								 | 
							
											this.email = this.componentLookup.mail[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (this.componentLookup.cn &&
							 | 
						||
| 
								 | 
							
										    this.componentLookup.cn.length === 1) {
							 | 
						||
| 
								 | 
							
											this.type = 'user';
							 | 
						||
| 
								 | 
							
											this.uid = this.componentLookup.cn[0].value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											this.type = 'unknown';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										this.type = opts.type;
							 | 
						||
| 
								 | 
							
										if (this.type === 'host')
							 | 
						||
| 
								 | 
							
											this.hostname = opts.hostname;
							 | 
						||
| 
								 | 
							
										else if (this.type === 'user')
							 | 
						||
| 
								 | 
							
											this.uid = opts.uid;
							 | 
						||
| 
								 | 
							
										else if (this.type === 'email')
							 | 
						||
| 
								 | 
							
											this.email = opts.email;
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
											throw (new Error('Unknown type ' + this.type));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.prototype.toString = function () {
							 | 
						||
| 
								 | 
							
									return (this.components.map(function (c) {
							 | 
						||
| 
								 | 
							
										var n = c.name.toUpperCase();
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										n = n.replace(/=/g, '\\=');
							 | 
						||
| 
								 | 
							
										var v = c.value;
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										v = v.replace(/,/g, '\\,');
							 | 
						||
| 
								 | 
							
										return (n + '=' + v);
							 | 
						||
| 
								 | 
							
									}).join(', '));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.prototype.get = function (name, asArray) {
							 | 
						||
| 
								 | 
							
									assert.string(name, 'name');
							 | 
						||
| 
								 | 
							
									var arr = this.componentLookup[name];
							 | 
						||
| 
								 | 
							
									if (arr === undefined || arr.length === 0)
							 | 
						||
| 
								 | 
							
										return (undefined);
							 | 
						||
| 
								 | 
							
									if (!asArray && arr.length > 1)
							 | 
						||
| 
								 | 
							
										throw (new Error('Multiple values for attribute ' + name));
							 | 
						||
| 
								 | 
							
									if (!asArray)
							 | 
						||
| 
								 | 
							
										return (arr[0].value);
							 | 
						||
| 
								 | 
							
									return (arr.map(function (c) {
							 | 
						||
| 
								 | 
							
										return (c.value);
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.prototype.toArray = function (idx) {
							 | 
						||
| 
								 | 
							
									return (this.components.map(function (c) {
							 | 
						||
| 
								 | 
							
										return ({
							 | 
						||
| 
								 | 
							
											name: c.name,
							 | 
						||
| 
								 | 
							
											value: c.value
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * These are from X.680 -- PrintableString allowed chars are in section 37.4
							 | 
						||
| 
								 | 
							
								 * table 8. Spec for IA5Strings is "1,6 + SPACE + DEL" where 1 refers to
							 | 
						||
| 
								 | 
							
								 * ISO IR #001 (standard ASCII control characters) and 6 refers to ISO IR #006
							 | 
						||
| 
								 | 
							
								 * (the basic ASCII character set).
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/* JSSTYLED */
							 | 
						||
| 
								 | 
							
								var NOT_PRINTABLE = /[^a-zA-Z0-9 '(),+.\/:=?-]/;
							 | 
						||
| 
								 | 
							
								/* JSSTYLED */
							 | 
						||
| 
								 | 
							
								var NOT_IA5 = /[^\x00-\x7f]/;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.prototype.toAsn1 = function (der, tag) {
							 | 
						||
| 
								 | 
							
									der.startSequence(tag);
							 | 
						||
| 
								 | 
							
									this.components.forEach(function (c) {
							 | 
						||
| 
								 | 
							
										der.startSequence(asn1.Ber.Constructor | asn1.Ber.Set);
							 | 
						||
| 
								 | 
							
										der.startSequence();
							 | 
						||
| 
								 | 
							
										der.writeOID(c.oid);
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * If we fit in a PrintableString, use that. Otherwise use an
							 | 
						||
| 
								 | 
							
										 * IA5String or UTF8String.
							 | 
						||
| 
								 | 
							
										 *
							 | 
						||
| 
								 | 
							
										 * If this identity was parsed from a DN, use the ASN.1 types
							 | 
						||
| 
								 | 
							
										 * from the original representation (otherwise this might not
							 | 
						||
| 
								 | 
							
										 * be a full match for the original in some validators).
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if (c.asn1type === asn1.Ber.Utf8String ||
							 | 
						||
| 
								 | 
							
										    c.value.match(NOT_IA5)) {
							 | 
						||
| 
								 | 
							
											var v = Buffer.from(c.value, 'utf8');
							 | 
						||
| 
								 | 
							
											der.writeBuffer(v, asn1.Ber.Utf8String);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else if (c.asn1type === asn1.Ber.IA5String ||
							 | 
						||
| 
								 | 
							
										    c.value.match(NOT_PRINTABLE)) {
							 | 
						||
| 
								 | 
							
											der.writeString(c.value, asn1.Ber.IA5String);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											var type = asn1.Ber.PrintableString;
							 | 
						||
| 
								 | 
							
											if (c.asn1type !== undefined)
							 | 
						||
| 
								 | 
							
												type = c.asn1type;
							 | 
						||
| 
								 | 
							
											der.writeString(c.value, type);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										der.endSequence();
							 | 
						||
| 
								 | 
							
										der.endSequence();
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									der.endSequence();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function globMatch(a, b) {
							 | 
						||
| 
								 | 
							
									if (a === '**' || b === '**')
							 | 
						||
| 
								 | 
							
										return (true);
							 | 
						||
| 
								 | 
							
									var aParts = a.split('.');
							 | 
						||
| 
								 | 
							
									var bParts = b.split('.');
							 | 
						||
| 
								 | 
							
									if (aParts.length !== bParts.length)
							 | 
						||
| 
								 | 
							
										return (false);
							 | 
						||
| 
								 | 
							
									for (var i = 0; i < aParts.length; ++i) {
							 | 
						||
| 
								 | 
							
										if (aParts[i] === '*' || bParts[i] === '*')
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
										if (aParts[i] !== bParts[i])
							 | 
						||
| 
								 | 
							
											return (false);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return (true);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.prototype.equals = function (other) {
							 | 
						||
| 
								 | 
							
									if (!Identity.isIdentity(other, [1, 0]))
							 | 
						||
| 
								 | 
							
										return (false);
							 | 
						||
| 
								 | 
							
									if (other.components.length !== this.components.length)
							 | 
						||
| 
								 | 
							
										return (false);
							 | 
						||
| 
								 | 
							
									for (var i = 0; i < this.components.length; ++i) {
							 | 
						||
| 
								 | 
							
										if (this.components[i].oid !== other.components[i].oid)
							 | 
						||
| 
								 | 
							
											return (false);
							 | 
						||
| 
								 | 
							
										if (!globMatch(this.components[i].value,
							 | 
						||
| 
								 | 
							
										    other.components[i].value)) {
							 | 
						||
| 
								 | 
							
											return (false);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return (true);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.forHost = function (hostname) {
							 | 
						||
| 
								 | 
							
									assert.string(hostname, 'hostname');
							 | 
						||
| 
								 | 
							
									return (new Identity({
							 | 
						||
| 
								 | 
							
										type: 'host',
							 | 
						||
| 
								 | 
							
										hostname: hostname,
							 | 
						||
| 
								 | 
							
										components: [ { name: 'cn', value: hostname } ]
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.forUser = function (uid) {
							 | 
						||
| 
								 | 
							
									assert.string(uid, 'uid');
							 | 
						||
| 
								 | 
							
									return (new Identity({
							 | 
						||
| 
								 | 
							
										type: 'user',
							 | 
						||
| 
								 | 
							
										uid: uid,
							 | 
						||
| 
								 | 
							
										components: [ { name: 'uid', value: uid } ]
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.forEmail = function (email) {
							 | 
						||
| 
								 | 
							
									assert.string(email, 'email');
							 | 
						||
| 
								 | 
							
									return (new Identity({
							 | 
						||
| 
								 | 
							
										type: 'email',
							 | 
						||
| 
								 | 
							
										email: email,
							 | 
						||
| 
								 | 
							
										components: [ { name: 'mail', value: email } ]
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.parseDN = function (dn) {
							 | 
						||
| 
								 | 
							
									assert.string(dn, 'dn');
							 | 
						||
| 
								 | 
							
									var parts = [''];
							 | 
						||
| 
								 | 
							
									var idx = 0;
							 | 
						||
| 
								 | 
							
									var rem = dn;
							 | 
						||
| 
								 | 
							
									while (rem.length > 0) {
							 | 
						||
| 
								 | 
							
										var m;
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										if ((m = /^,/.exec(rem)) !== null) {
							 | 
						||
| 
								 | 
							
											parts[++idx] = '';
							 | 
						||
| 
								 | 
							
											rem = rem.slice(m[0].length);
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										} else if ((m = /^\\,/.exec(rem)) !== null) {
							 | 
						||
| 
								 | 
							
											parts[idx] += ',';
							 | 
						||
| 
								 | 
							
											rem = rem.slice(m[0].length);
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										} else if ((m = /^\\./.exec(rem)) !== null) {
							 | 
						||
| 
								 | 
							
											parts[idx] += m[0];
							 | 
						||
| 
								 | 
							
											rem = rem.slice(m[0].length);
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										} else if ((m = /^[^\\,]+/.exec(rem)) !== null) {
							 | 
						||
| 
								 | 
							
											parts[idx] += m[0];
							 | 
						||
| 
								 | 
							
											rem = rem.slice(m[0].length);
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											throw (new Error('Failed to parse DN'));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var cmps = parts.map(function (c) {
							 | 
						||
| 
								 | 
							
										c = c.trim();
							 | 
						||
| 
								 | 
							
										var eqPos = c.indexOf('=');
							 | 
						||
| 
								 | 
							
										while (eqPos > 0 && c.charAt(eqPos - 1) === '\\')
							 | 
						||
| 
								 | 
							
											eqPos = c.indexOf('=', eqPos + 1);
							 | 
						||
| 
								 | 
							
										if (eqPos === -1) {
							 | 
						||
| 
								 | 
							
											throw (new Error('Failed to parse DN'));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										/*JSSTYLED*/
							 | 
						||
| 
								 | 
							
										var name = c.slice(0, eqPos).toLowerCase().replace(/\\=/g, '=');
							 | 
						||
| 
								 | 
							
										var value = c.slice(eqPos + 1);
							 | 
						||
| 
								 | 
							
										return ({ name: name, value: value });
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									return (new Identity({ components: cmps }));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.fromArray = function (components) {
							 | 
						||
| 
								 | 
							
									assert.arrayOfObject(components, 'components');
							 | 
						||
| 
								 | 
							
									components.forEach(function (cmp) {
							 | 
						||
| 
								 | 
							
										assert.object(cmp, 'component');
							 | 
						||
| 
								 | 
							
										assert.string(cmp.name, 'component.name');
							 | 
						||
| 
								 | 
							
										if (!Buffer.isBuffer(cmp.value) &&
							 | 
						||
| 
								 | 
							
										    !(typeof (cmp.value) === 'string')) {
							 | 
						||
| 
								 | 
							
											throw (new Error('Invalid component value'));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									return (new Identity({ components: components }));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.parseAsn1 = function (der, top) {
							 | 
						||
| 
								 | 
							
									var components = [];
							 | 
						||
| 
								 | 
							
									der.readSequence(top);
							 | 
						||
| 
								 | 
							
									var end = der.offset + der.length;
							 | 
						||
| 
								 | 
							
									while (der.offset < end) {
							 | 
						||
| 
								 | 
							
										der.readSequence(asn1.Ber.Constructor | asn1.Ber.Set);
							 | 
						||
| 
								 | 
							
										var after = der.offset + der.length;
							 | 
						||
| 
								 | 
							
										der.readSequence();
							 | 
						||
| 
								 | 
							
										var oid = der.readOID();
							 | 
						||
| 
								 | 
							
										var type = der.peek();
							 | 
						||
| 
								 | 
							
										var value;
							 | 
						||
| 
								 | 
							
										switch (type) {
							 | 
						||
| 
								 | 
							
										case asn1.Ber.PrintableString:
							 | 
						||
| 
								 | 
							
										case asn1.Ber.IA5String:
							 | 
						||
| 
								 | 
							
										case asn1.Ber.OctetString:
							 | 
						||
| 
								 | 
							
										case asn1.Ber.T61String:
							 | 
						||
| 
								 | 
							
											value = der.readString(type);
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case asn1.Ber.Utf8String:
							 | 
						||
| 
								 | 
							
											value = der.readString(type, true);
							 | 
						||
| 
								 | 
							
											value = value.toString('utf8');
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case asn1.Ber.CharacterString:
							 | 
						||
| 
								 | 
							
										case asn1.Ber.BMPString:
							 | 
						||
| 
								 | 
							
											value = der.readString(type, true);
							 | 
						||
| 
								 | 
							
											value = value.toString('utf16le');
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											throw (new Error('Unknown asn1 type ' + type));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										components.push({ oid: oid, asn1type: type, value: value });
							 | 
						||
| 
								 | 
							
										der._offset = after;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									der._offset = end;
							 | 
						||
| 
								 | 
							
									return (new Identity({
							 | 
						||
| 
								 | 
							
										components: components
							 | 
						||
| 
								 | 
							
									}));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity.isIdentity = function (obj, ver) {
							 | 
						||
| 
								 | 
							
									return (utils.isCompatible(obj, Identity, ver));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * API versions for Identity:
							 | 
						||
| 
								 | 
							
								 * [1,0] -- initial ver
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								Identity.prototype._sshpkApiVersion = [1, 0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Identity._oldVersionDetect = function (obj) {
							 | 
						||
| 
								 | 
							
									return ([1, 0]);
							 | 
						||
| 
								 | 
							
								};
							 |