UNPKG

@sexycoders/libauth.js

Version:

A full service for asymetric passwordless authentication.

1,299 lines (1,227 loc) 43.5 kB
var ASSERT = require('assert'); var ASN1 = require('../../lib/asn1'); var UTIL = require('../../lib/util'); (function() { describe('asn1', function() { // TODO: add more ASN.1 coverage it('should convert an OID to DER', function() { ASSERT.equal(ASN1.oidToDer('1.2.840.113549').toHex(), '2a864886f70d'); }); it('should convert an OID from DER', function() { var der = UTIL.hexToBytes('2a864886f70d'); ASSERT.equal(ASN1.derToOid(der), '1.2.840.113549'); }); it('should convert INTEGER 0 to DER', function() { ASSERT.equal(ASN1.integerToDer(0).toHex(), '00'); }); it('should convert INTEGER 1 to DER', function() { ASSERT.equal(ASN1.integerToDer(1).toHex(), '01'); }); it('should convert INTEGER 127 to DER', function() { ASSERT.equal(ASN1.integerToDer(127).toHex(), '7f'); }); it('should convert INTEGER 128 to DER', function() { ASSERT.equal(ASN1.integerToDer(128).toHex(), '0080'); }); it('should convert INTEGER 256 to DER', function() { ASSERT.equal(ASN1.integerToDer(256).toHex(), '0100'); }); it('should convert INTEGER -128 to DER', function() { ASSERT.equal(ASN1.integerToDer(-128).toHex(), '80'); }); it('should convert INTEGER -129 to DER', function() { ASSERT.equal(ASN1.integerToDer(-129).toHex(), 'ff7f'); }); it('should convert INTEGER 32768 to DER', function() { ASSERT.equal(ASN1.integerToDer(32768).toHex(), '008000'); }); it('should convert INTEGER -32768 to DER', function() { ASSERT.equal(ASN1.integerToDer(-32768).toHex(), '8000'); }); it('should convert INTEGER -32769 to DER', function() { ASSERT.equal(ASN1.integerToDer(-32769).toHex(), 'ff7fff'); }); it('should convert INTEGER 8388608 to DER', function() { ASSERT.equal(ASN1.integerToDer(8388608).toHex(), '00800000'); }); it('should convert INTEGER -8388608 to DER', function() { ASSERT.equal(ASN1.integerToDer(-8388608).toHex(), '800000'); }); it('should convert INTEGER -8388609 to DER', function() { ASSERT.equal(ASN1.integerToDer(-8388609).toHex(), 'ff7fffff'); }); it('should convert INTEGER 2147483647 to DER', function() { ASSERT.equal(ASN1.integerToDer(2147483647).toHex(), '7fffffff'); }); it('should convert INTEGER -2147483648 to DER', function() { ASSERT.equal(ASN1.integerToDer(-2147483648).toHex(), '80000000'); }); it('should convert INTEGER 0 from DER', function() { var der = UTIL.hexToBytes('00'); ASSERT.equal(ASN1.derToInteger(der), 0); }); it('should convert INTEGER 1 from DER', function() { var der = UTIL.hexToBytes('01'); ASSERT.equal(ASN1.derToInteger(der), 1); }); it('should convert INTEGER 127 from DER', function() { var der = UTIL.hexToBytes('7f'); ASSERT.equal(ASN1.derToInteger(der), 127); }); it('should convert INTEGER 128 from DER', function() { var der = UTIL.hexToBytes('0080'); ASSERT.equal(ASN1.derToInteger(der), 128); }); it('should convert INTEGER 256 from DER', function() { var der = UTIL.hexToBytes('0100'); ASSERT.equal(ASN1.derToInteger(der), 256); }); it('should convert INTEGER -128 from DER', function() { var der = UTIL.hexToBytes('80'); ASSERT.equal(ASN1.derToInteger(der), -128); }); it('should convert INTEGER -129 from DER', function() { var der = UTIL.hexToBytes('ff7f'); ASSERT.equal(ASN1.derToInteger(der), -129); }); it('should convert INTEGER 32768 from DER', function() { var der = UTIL.hexToBytes('008000'); ASSERT.equal(ASN1.derToInteger(der), 32768); }); it('should convert INTEGER -32768 from DER', function() { var der = UTIL.hexToBytes('8000'); ASSERT.equal(ASN1.derToInteger(der), -32768); }); it('should convert INTEGER -32769 from DER', function() { var der = UTIL.hexToBytes('ff7fff'); ASSERT.equal(ASN1.derToInteger(der), -32769); }); it('should convert INTEGER 8388608 from DER', function() { var der = UTIL.hexToBytes('00800000'); ASSERT.equal(ASN1.derToInteger(der), 8388608); }); it('should convert INTEGER -8388608 from DER', function() { var der = UTIL.hexToBytes('800000'); ASSERT.equal(ASN1.derToInteger(der), -8388608); }); it('should convert INTEGER -8388609 from DER', function() { var der = UTIL.hexToBytes('ff7fffff'); ASSERT.equal(ASN1.derToInteger(der), -8388609); }); it('should convert INTEGER 2147483647 from DER', function() { var der = UTIL.hexToBytes('7fffffff'); ASSERT.equal(ASN1.derToInteger(der), 2147483647); }); it('should convert INTEGER -2147483648 from DER', function() { var der = UTIL.hexToBytes('80000000'); ASSERT.equal(ASN1.derToInteger(der), -2147483648); }); (function() { var tests = [{ in: '20110223123400', out: 1298464440000 }, { in: '20110223123400.1', out: 1298464440100 }, { in: '20110223123400.123', out: 1298464440123 }]; tests.forEach(function(test) { it('should convert local generalized time "' + test.in + '" to a Date', function() { var d = ASN1.generalizedTimeToDate(test.in); var localOffset = d.getTimezoneOffset() * 60000; ASSERT.equal(d.getTime(), test.out + localOffset); }); }); })(); (function() { var tests = [{ in: '20110223123400Z', // Wed Feb 23 12:34:00.000 UTC 2011 out: 1298464440000 }, { in: '20110223123400.1Z', // Wed Feb 23 12:34:00.100 UTC 2011 out: 1298464440100 }, { in: '20110223123400.123Z', // Wed Feb 23 12:34:00.123 UTC 2011 out: 1298464440123 }, { in: '20110223123400+0200', // Wed Feb 23 10:34:00.000 UTC 2011 out: 1298457240000 }, { in: '20110223123400.1+0200', // Wed Feb 23 10:34:00.100 UTC 2011 out: 1298457240100 }, { in: '20110223123400.123+0200', // Wed Feb 23 10:34:00.123 UTC 2011 out: 1298457240123 }, { in: '20110223123400-0200', // Wed Feb 23 14:34:00.000 UTC 2011 out: 1298471640000 }, { in: '20110223123400.1-0200', // Wed Feb 23 14:34:00.100 UTC 2011 out: 1298471640100 }, { in: '20110223123400.123-0200', // Wed Feb 23 14:34:00.123 UTC 2011 out: 1298471640123 }]; tests.forEach(function(test) { it('should convert utc generalized time "' + test.in + '" to a Date', function() { var d = ASN1.generalizedTimeToDate(test.in); ASSERT.equal(d.getTime(), test.out); }); }); })(); (function() { var tests = [{ in: 'Jan 1 1949 00:00:00 GMT', out: '19490101000000Z' }, { in: 'Jan 1 2000 00:00:00 GMT', out: '20000101000000Z' }, { in: 'Jan 1 2050 00:00:00 GMT', out: '20500101000000Z' }, { in: 'Mar 1 2100 00:00:00 GMT', out: '21000301000000Z' }]; tests.forEach(function(test) { it('should convert date "' + test.in + '" to generalized time', function() { var d = ASN1.dateToGeneralizedTime(new Date(test.in)); ASSERT.equal(d, test.out); }); }); })(); (function() { var tests = [{ in: '1102231234Z', // Wed Feb 23 12:34:00 UTC 2011 out: 1298464440000 }, { in: '1102231234+0200', // Wed Feb 23 10:34:00 UTC 2011 out: 1298457240000 }, { in: '1102231234-0200', // Wed Feb 23 14:34:00 UTC 2011 out: 1298471640000 }, { in: '110223123456Z', // Wed Feb 23 12:34:56 UTC 2011 out: 1298464496000 }, { in: '110223123456+0200', // Wed Feb 23 10:34:56 UTC 2011 out: 1298457296000 }, { in: '110223123456-0200', // Wed Feb 23 14:34:56 UTC 2011 out: 1298471696000 }, { in: '500101000000Z', out: -631152000000 }]; tests.forEach(function(test) { it('should convert utc time "' + test.in + '" to a Date', function() { var d = ASN1.utcTimeToDate(test.in); ASSERT.equal(d.getTime(), test.out); }); }); })(); (function() { var tests = [{ in: 'Sat Dec 31 1949 19:00:00 GMT-0500', out: '500101000000Z' }]; tests.forEach(function(test) { it('should convert date "' + test.in + '" to utc time', function() { var d = ASN1.dateToUtcTime(new Date(test.in)); ASSERT.equal(d, test.out); }); }); })(); (function() { // use function to avoid calling apis during setup function _asn1(str) { return function() { return ASN1.fromDer(UTIL.hexToBytes(str.replace(/ /g, ''))); }; } var tests = [{ name: 'empty strings', obj1: '', obj2: '', equal: true }, { name: 'simple strings', obj1: '\u0001', obj2: '\u0001', equal: true }, { name: 'simple strings', obj1: '\u0000', obj2: '\u0001', equal: false }, { name: 'simple arrays', obj1: ['', ''], obj2: ['', ''], equal: true }, { name: 'simple arrays', obj1: ['', ''], obj2: [''], equal: false }, { name: 'INTEGERs', obj1: _asn1('02 01 00'), obj2: _asn1('02 01 00'), equal: true }, { name: 'BER INTEGERs', obj1: _asn1('02 01 01'), obj2: _asn1('02 02 00 01'), equal: false }, { name: 'BIT STRINGs', obj1: _asn1('03 02 00 01'), obj2: _asn1('03 02 00 01'), equal: true }, { name: 'BIT STRINGs', obj1: _asn1('03 02 00 01'), obj2: _asn1('03 02 00 02'), equal: false }, { name: 'BIT STRINGs sub INTEGER', obj1: _asn1('03 04 00 02 01 01'), obj2: _asn1('03 04 00 02 01 01'), equal: true }, { name: 'mutated BIT STRINGs', obj1: _asn1('03 04 00 02 01 01'), obj2: _asn1('03 04 00 02 01 01'), mutate: function(obj1, obj2) { obj2.value[0].value = '\u0002'; }, equal: false }]; tests.forEach(function(test, index) { var name = 'should check ASN.1 ' + (test.equal ? '' : 'not ') + 'equal: ' + (test.name || '#' + index); it(name, function() { var obj1 = typeof test.obj1 === 'function' ? test.obj1() : test.obj1; var obj2 = typeof test.obj2 === 'function' ? test.obj2() : test.obj2; if(test.mutate) { test.mutate(obj1, obj2); } ASSERT.equal(ASN1.equals(obj1, obj2), test.equal); }); }); })(); (function() { // use function to avoid calling apis during setup function _asn1(str) { return function() { return ASN1.fromDer(UTIL.hexToBytes(str.replace(/ /g, ''))); }; } var tests = [{ name: 'empty string', obj: '' }, { name: 'simple string', obj: '\u0001' }, { name: 'simple array', obj: ['', ''] }, { name: 'INTEGER', obj: _asn1('02 01 00') }, { name: 'BER INTEGER', obj: _asn1('02 01 01') }, { name: 'BIT STRING', obj: _asn1('03 02 00 01') }, { name: 'BIT STRING sub INTEGER', obj: _asn1('03 04 00 02 01 01') }]; tests.forEach(function(test, index) { var name = 'should check ASN.1 copy: ' + (test.name || '#' + index); it(name, function() { var obj = typeof test.obj === 'function' ? test.obj() : test.obj; ASSERT.equal(ASN1.equals(ASN1.copy(obj), obj), true); }); }); })(); (function() { function _h2b(str) { return UTIL.hexToBytes(str.replace(/ /g, '')); } function _add(b, str) { b.putBytes(_h2b(str)); } function _asn1dump(asn1) { console.log(ASN1.prettyPrint(asn1)); console.log(JSON.stringify(asn1, null, 2)); } function _asn1TestOne(strict, throws, options) { options = options || {}; if(!('decodeBitStrings' in options)) { options.decodeBitStrings = true; } // buffer strict test var b = UTIL.createBuffer(); // init options.init(b); // bytes for round-trip comparison var bytes = b.copy().bytes(); // copy for non-strict test var bns = b.copy(); // create strict and non-strict asn1 var asn1assert = throws ? ASSERT.throws : function(f) { f(); }; var asn1; var der; asn1assert(function() { asn1 = ASN1.fromDer(b, { strict: strict, decodeBitStrings: options.decodeBitStrings }); }); // debug if(options.dump && asn1) { console.log('=== ' + (strict ? 'Strict' : 'Non Strict') + ' ==='); _asn1dump(asn1); } // basic check if(!throws) { ASSERT.ok(asn1); } // round-trip(ish) check if(!throws) { der = ASN1.toDer(asn1); if(options.roundtrip) { // byte comparisons for round-trip testing can fail due to // symantically safe changes such as changing the length encoding. // test a roundtrip for data where it makes sense. ASSERT.equal( UTIL.bytesToHex(bytes), UTIL.bytesToHex(der.bytes())); } } // validator check if(!throws && options.v) { var capture = {}; var errors = []; var asn1ok = ASN1.validate(asn1, options.v, capture, errors); ASSERT.deepEqual(errors, []); if(options.captured) { ASSERT.deepEqual(capture, options.captured); } else { ASSERT.deepEqual(capture, {}); } ASSERT.ok(asn1ok); } return { asn1: asn1, der: der }; } function _asn1Test(options) { var s = _asn1TestOne(true, options.strictThrows, options); var ns = _asn1TestOne(false, options.nonStrictThrows, options); // check asn1 equality if(s.asn1 && ns.asn1) { ASSERT.deepEqual(s.asn1, ns.asn1); } // check der equality if(s.der && ns.der) { ASSERT.equal( UTIL.bytesToHex(s.der.bytes()), UTIL.bytesToHex(ns.der.bytes())); } if(options.done) { options.done({ strict: s, nonStrict: ns }); } } it('should convert BIT STRING from DER (short,empty)', function() { _asn1Test({ init: function(b) { // BIT STRING value=none _add(b, '03 00'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: '' } }); }); it('should convert BIT STRING from DER (short,empty2)', function() { _asn1Test({ init: function(b) { // BIT STRING value=none _add(b, '03 01 00'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bitsC', captureBitStringValue: 'bitsV' }, captured: { bitsC: _h2b('00'), bitsV: '' } }); }); it('should convert BIT STRING from BER (short,invalid)', function() { _asn1Test({ init: function(b) { // BIT STRING value=partial // invalid in strict mode, non-strict will read 1 of 2 bytes _add(b, '03 02 00'); }, dump: false, roundtrip: false, strictThrows: true, nonStrictThrows: false, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { // only for non-strict mode, truncated value bits: _h2b('00') } }); }); it('should convert BIT STRING from DER (short)', function() { _asn1Test({ init: function(b) { // BIT STRING value=0110111001011101 _add(b, '03 03 00 6e 5d'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b('00 6e 5d') } }); }); it('should convert BIT STRING from DER (short2)', function() { _asn1Test({ init: function(b) { // BIT STRING value=0110111001011101 // contains an INTEGER=0x12 _add(b, '03 04 00 02 01 12'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // note captureBitStringContents used to get all bytes // 'capture' would get the value structure // 'captureAsn1' would get the value and sub-value structures captureBitStringContents: 'bits', value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int0' }] }, captured: { bits: _h2b('00 02 01 12'), int0: _h2b('12') } }); }); it('should convert BIT STRING from DER (short,unused1z)', function() { _asn1Test({ init: function(b) { // BIT STRING value=01101110010111011010111, unused=0 _add(b, '03 04 01 6e 5d ae'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b('01 6e 5d ae') } }); }); it('should convert BIT STRING from DER (short,unused6z)', function() { _asn1Test({ init: function(b) { // BIT STRING short len, value=011011100101110111, unused=000000 _add(b, '03 04 06 6e 5d c0'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b('06 6e 5d c0') } }); }); it('should convert BIT STRING from BER (short,unused6d)', function() { _asn1Test({ init: function(b) { // BIT STRING short len, value=011011100101110111, unused=100000 _add(b, '03 04 06 6e 5d e0'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b('06 6e 5d e0') } }); }); it('should convert BIT STRING from BER (long,unused6z)', function() { _asn1Test({ init: function(b) { // BIT STRING long len, value=011011100101110111, unused=000000 _add(b, '03 81 04 06 6e 5d c0'); }, dump: false, // length is compressed roundtrip: false, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b('06 6e 5d c0') } }); }); it('should convert BIT STRING from BER (unused6z)', function() { _asn1Test({ init: function(b) { // BIT STRING constructed, value=0110111001011101+11, unused=000000 _add(b, '23 09'); _add(b, '03 03 00 6e 5d'); _add(b, '03 02 06 c0'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: true, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, capture: 'bits0' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, capture: 'bits1' }] }, captured: { bits0: _h2b('00 6e 5d'), bits1: _h2b('06 c0') } }); }); it('should convert BIT STRING from BER (decode)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data that includes encapsulated // data. often used to store SEQUENCE of INTEGERs. // add bit stream of bytes using long length _add(b, '03 82 00 10'); // no padding _add(b, '00'); // sequence of two ints _add(b, '30 0D'); // add test int, long len _add(b, '02 81 04 12 34 56 78'); // add test int, short len _add(b, '02 04 87 65 43 21'); }, dump: false, decodeBitStrings: true, // long len will compress to short len roundtrip: false, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits', value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.SEQUENCE, constructed: true, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int0' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int1' }] }] }, captured: { bits: _h2b( '00' + '30 0D' + '02 81 04 12 34 56 78' + '02 04 87 65 43 21'), int0: _h2b('12 34 56 78'), int1: _h2b('87 65 43 21') } }); }); it('should convert BIT STRING from BER (no decode)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data that includes encapsulated // data. often used to store SEQUENCE of INTEGERs. // add bit stream _add(b, '03 82 00 10'); // no padding _add(b, '00'); // sequence of two ints _add(b, '30 0D'); // add test int, long len _add(b, '02 81 04 12 34 56 78'); // add test int, short len _add(b, '02 04 87 65 43 21'); }, dump: false, decodeBitStrings: false, // long length is compressed roundtrip: false, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits' }, captured: { bits: _h2b( '00' + '30 0D' + '02 81 04 12 34 56 78' + '02 04 87 65 43 21') } }); }); it('should convert BIT STRING from DER (decode2)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data that includes encapsulated // data. often used to store SEQUENCE of INTEGERs. // bit stream _add(b, '03 81 8D'); // no padding _add(b, '00'); // sequence _add(b, '30 81 89'); // int header and leading 0 _add(b, '02 81 81 00'); // 1024 bit int _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F1'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F2'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F3'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7'); // int header and 3 byte int _add(b, '02 03 01 00 01'); }, dump: false, decodeBitStrings: true, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.SEQUENCE, constructed: true, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int0' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int1' }] }] }, captured: { int0: _h2b('00' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F1' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F2' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F3' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7'), int1: _h2b('01 00 01') } }); }); it('should convert BIT STRING from DER (sig)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data similar to a signature that // could be interpreted incorrectly as encapsulated data. // add bit stream of 257 bytes _add(b, '03 82 01 01'); // no unused _add(b, '00'); // signature bits _add(b, '25 81 FD 6E D3 AB 34 45 DE AE F1 5B EC 6A FB 79'); _add(b, '14 CD 7B B2 8E 48 59 AE 89 B1 55 60 11 AB BC 7F'); _add(b, '6D 6D FE 16 22 42 AC 57 CC E9 C0 3A 8D 1E F3 C3'); _add(b, '97 C8 23 53 DE E0 34 C3 A9 43 8B 2B D9 C0 24 FF'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F9'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FA'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FB'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FD'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FE'); _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // captureBitStringContents not used to check if valude decoded capture: 'sig' }, captured: { sig: _h2b( '00' + '25 81 FD 6E D3 AB 34 45 DE AE F1 5B EC 6A FB 79' + '14 CD 7B B2 8E 48 59 AE 89 B1 55 60 11 AB BC 7F' + '6D 6D FE 16 22 42 AC 57 CC E9 C0 3A 8D 1E F3 C3' + '97 C8 23 53 DE E0 34 C3 A9 43 8B 2B D9 C0 24 FF' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F9' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FA' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FB' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FD' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FE' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF') } }); }); it('should convert BIT STRING from DER (sig2)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data similar to a signature that // could be interpreted incorrectly as encapsulated data. // add bit stream of 257 bytes _add(b, '03 82 01 01'); // no unused _add(b, '00'); // signature bits _add(b, '2B 05 9D 81 FB 07 2C CE 15 0A 39 CD D3 89 A7 83'); _add(b, '5C 99 5E B2 0D A4 E0 26 81 20 EF 5A 0F 23 46 E0'); _add(b, '46 4A 5D 7B 6A C9 4F B1 38 D5 FC 71 6A 32 06 6C'); _add(b, '68 15 9E F2 13 DB 2A 36 41 93 51 4C 98 EB 9F 32'); _add(b, '28 54 07 CE B2 05 92 A7 C8 DF 2F A1 E3 C9 9C 0A'); _add(b, 'E4 BE B3 88 17 CF 62 70 80 CD 10 B8 9B 08 E0 47'); _add(b, '61 24 12 16 C0 FC 70 D9 0A 4A 39 09 F4 51 F1 62'); _add(b, '0A 56 6B 46 C1 E2 0B FF 92 3E F5 A5 06 EE 55 0A'); _add(b, '6D FD DA 18 B9 C1 30 6E 98 CD 38 4D 9C C5 B5 6B'); _add(b, '81 19 B7 B1 19 52 5C F8 99 9D C2 EC A1 F5 96 A7'); _add(b, '66 79 A6 53 F8 17 67 64 52 F6 32 37 F4 CD 74 5A'); _add(b, '2F 59 35 06 90 6B CC F7 E6 7D 67 C4 FA 0C 7B 10'); _add(b, '05 85 E8 4F E2 0E EF A0 D4 F8 57 EB BF 2F 14 42'); _add(b, '62 01 09 08 35 5C 24 8C 0D 5D FD FA 52 58 D8 C9'); _add(b, '10 45 4F AE 15 B0 9A 82 B9 FB 17 CC E6 A0 BD BA'); _add(b, '76 BD 05 F1 70 69 43 9D 60 31 F9 F4 13 7A 8C 71'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // captureBitStringContents not used to check if valude decoded captureBitStringValue: 'bits' }, captured: { bits: _h2b( '2B 05 9D 81 FB 07 2C CE 15 0A 39 CD D3 89 A7 83' + '5C 99 5E B2 0D A4 E0 26 81 20 EF 5A 0F 23 46 E0' + '46 4A 5D 7B 6A C9 4F B1 38 D5 FC 71 6A 32 06 6C' + '68 15 9E F2 13 DB 2A 36 41 93 51 4C 98 EB 9F 32' + '28 54 07 CE B2 05 92 A7 C8 DF 2F A1 E3 C9 9C 0A' + 'E4 BE B3 88 17 CF 62 70 80 CD 10 B8 9B 08 E0 47' + '61 24 12 16 C0 FC 70 D9 0A 4A 39 09 F4 51 F1 62' + '0A 56 6B 46 C1 E2 0B FF 92 3E F5 A5 06 EE 55 0A' + '6D FD DA 18 B9 C1 30 6E 98 CD 38 4D 9C C5 B5 6B' + '81 19 B7 B1 19 52 5C F8 99 9D C2 EC A1 F5 96 A7' + '66 79 A6 53 F8 17 67 64 52 F6 32 37 F4 CD 74 5A' + '2F 59 35 06 90 6B CC F7 E6 7D 67 C4 FA 0C 7B 10' + '05 85 E8 4F E2 0E EF A0 D4 F8 57 EB BF 2F 14 42' + '62 01 09 08 35 5C 24 8C 0D 5D FD FA 52 58 D8 C9' + '10 45 4F AE 15 B0 9A 82 B9 FB 17 CC E6 A0 BD BA' + '76 BD 05 F1 70 69 43 9D 60 31 F9 F4 13 7A 8C 71') } }); }); it('should convert BIT STRING from DER (sig3)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data similar to a signature that // could be interpreted incorrectly as encapsulated data. _add(b, '03 0B'); // no unused _add(b, '00'); // signature bits with structure with bad type and length _add(b, '2B 05 9D 05 F0 F1 F2 F3 F4 F5'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // captureBitStringContents not used to check if value decoded capture: 'sig' }, captured: { sig: _h2b( '00' + '2B 05 9D 05 F0 F1 F2 F3 F4 F5') } }); }); it('should convert BIT STRING from BER (decodable sig)', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data similar to a signature that // could be interpreted as encapsulated data. data is such that // a round trip process could change the data due to INTEGER // optimization (removal of leading bytes) or length structure // compression (long to short). // add a basic bit stream "signature" with test data _add(b, '03 22'); // no unused _add(b, '00'); // everything after this point might be important bits, not ASN.1 // SEQUENCE of tests _add(b, '30 1E'); // signature bits // '02 02' prefix will be cause parsing as an integer // toDer will try to remove the extra 00. // tests the BIT STRING content/value saving feature _add(b, '02 02 00 7F'); // similar example for -1: _add(b, '02 02 FF FF'); // could extend out to any structure size: _add(b, '02 06 FF FF FF FF FF FF'); // the roundtrip issue can exist for long lengths that could // compress to short lenghts, this could be output as '02 02 01 23': _add(b, '02 81 02 01 23'); // also an issue for indefinite length structures that will // have a known length later: _add(b, '30 80'); // a few INTEGERs _add(b, '02 01 00'); _add(b, '02 01 01'); // done _add(b, '00 00'); // other examples may exist }, dump: false, // NOTE: arbitrary data can be recompacted, check saved data worked roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringValue: 'sig' }, captured: { sig: _h2b( '30 1E' + '02 02 00 7F' + '02 02 FF FF' + '02 06 FF FF FF FF FF FF' + '02 81 02 01 23' + '30 80' + '02 01 00' + '02 01 01' + '00 00') } }); }); it('should convert BIT STRING from strict DER', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data that includes encapsulated // data. include valid data that would only parse in strict // mode. _add(b, '03 06'); // no padding _add(b, '00'); // sub-BIT STRING with valid length _add(b, '03 03 00 01 02'); }, dump: false, decodeBitStrings: true, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // default capture value has structural data // check contents and value captureBitStringContents: 'bitsC', captureBitStringValue: 'bitsV' }, captured: { bitsC: _h2b('00 03 03 00 01 02'), bitsV: _h2b('03 03 00 01 02') } }); }); it('should convert BIT STRING from non-strict DER', function() { _asn1Test({ init: function(b) { // create crafted DER BIT STRING data that includes encapsulated // data. include invalid data that would only parse in non-strict // mode. ensure it is never parsed. _add(b, '03 05'); // no padding _add(b, '00'); // sub-BIT STRING with invalid length, missing a byte _add(b, '03 03 00 01'); }, dump: false, decodeBitStrings: true, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, // ensure default captures contents vs decoded structure capture: 'bits0', // check contents and value captureBitStringContents: 'bitsC', captureBitStringValue: 'bitsV' }, captured: { bits0: _h2b('00 03 03 00 01'), bitsC: _h2b('00 03 03 00 01'), bitsV: _h2b('03 03 00 01') } }); }); it('should convert indefinite length seq from BER', function() { _asn1Test({ init: function(b) { // SEQUENCE _add(b, '30 80'); // a few INTEGERs _add(b, '02 01 00'); _add(b, '02 01 01'); _add(b, '02 01 02'); // done _add(b, '00 00'); }, dump: false, // roundtrip will know the sequence length roundtrip: false, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.SEQUENCE, constructed: true, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int0' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int1' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int2' }] }, captured: { int0: _h2b('00'), int1: _h2b('01'), int2: _h2b('02') } }); }); it('should handle ASN.1 mutations', function() { _asn1Test({ init: function(b) { // BIT STRING _add(b, '03 09 00'); // SEQUENCE _add(b, '30 06'); // a few INTEGERs _add(b, '02 01 00'); _add(b, '02 01 01'); }, dump: false, // roundtrip will know the sequence length roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BITSTRING, constructed: false, captureBitStringContents: 'bits', value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.SEQUENCE, constructed: true, value: [{ tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int0' }, { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.INTEGER, constructed: false, capture: 'int1' }] }] }, captured: { bits: _h2b('00 30 06 02 01 00 02 01 01'), int0: _h2b('00'), int1: _h2b('01') }, done: function(data) { var asn1 = data.strict.asn1; // mutate asn1.value[0].value[0].value = _h2b('02'); asn1.value[0].value[1].value = _h2b('03'); // convert // must use new data vs saved BIT STRING data var der = ASN1.toDer(asn1); var expect = _h2b('03 09 00 30 06 02 01 02 02 01 03'); // compare ASSERT.equal(UTIL.bytesToHex(der), UTIL.bytesToHex(expect)); } }); }); it('should convert BMP STRING from DER', function() { _asn1Test({ init: function(b) { // BPMSTRING _add(b, '1e 08'); _add(b, '01 02 03 04 05 06 07 08'); }, dump: false, roundtrip: true, v: { tagClass: ASN1.Class.UNIVERSAL, type: ASN1.Type.BPMSTRING, constructed: false, capture: 'bits' }, captured: { bits: '\u0102\u0304\u0506\u0708' } }); }); // TODO: how minimal should INTEGERs be encoded? // .. fromDer will create the full integer // .. toDer will remove only first byte if possible it('should minimally encode INTEGERs', function() { function _test(hin, hout) { var derIn = _h2b(hin); var derOut = ASN1.toDer(ASN1.fromDer(derIn)); ASSERT.equal( UTIL.bytesToHex(derOut), UTIL.bytesToHex(_h2b(hout))); } // optimial _test('02 01 01', '02 01 01'); _test('02 01 FF', '02 01 FF'); _test('02 02 00 FF', '02 02 00 FF'); // remove leading 00s before a 0b0xxxxxxx _test('02 04 00 00 00 01', '02 03 00 00 01'); // this would be more optimal //_test('02 04 00 00 00 01', '02 01 01'); // remove leading FFs before a 0b1xxxxxxx _test('02 04 FF FF FF FF', '02 03 FF FF FF'); // this would be more optimal //_test('02 04 FF FF FF FF', '02 01 FF'); }); })(); }); })();