Utility code for parsing pfx format certificates

Parses ber/der encoded files
Navigates through pkcs format pfx files
Decryptes password-encoded regions
Surfaces x509 and rsa private key data
This commit is contained in:
Louis DeJardin 2012-02-28 14:48:20 -08:00
Родитель 923bf05f3d
Коммит 3be6c05364
12 изменённых файлов: 861 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,206 @@
var util = require('util');
var EventEmitter = require( 'events' ).EventEmitter;
var Der = {
Decoder: Decoder,
Formatter: Formatter,
INTEGER: 'UNIVERSAL-primative-2',
BIT_STRING: 'UNIVERSAL-primative-3',
OCTET_STRING: 'UNIVERSAL-primative-4',
OBJECT_IDENTIFIER: 'UNIVERSAL-primative-6',
SEQUENCE: 'UNIVERSAL-constructed-10',
BMPString: 'UNIVERSAL-primative-1e',
CONTEXT_CONSTRUCTED_0: 'context-constructed-0',
CONTEXT_PRIMATIVE_0: 'context-primative-0',
dumpBuffer: dumpBuffer,
};
function Decoder(options) {
EventEmitter.call(this);
options = options || {};
this.formatter = options.formatter || Der.defaultFormatter;
}
util.inherits(Decoder, EventEmitter);
Decoder.prototype.parse = function(buffer) {
var cumulative = [];
var cursor = new Cursor(buffer);
while (cursor) {
var next = cursor.next();
this.formatter.format(next.element);
this.emit('element', next.element);
cumulative.push(next.element);
cursor = next.cursor;
}
this.emit('end', cumulative);
return cumulative;
}
Decoder.prototype.verify = function(message, actual, expected) {
var passed = true;
if (arguments.length == 2) {
passed = actual;
}
else {
passed = actual == expected;
}
if (!passed) {
throw new Exception(message);
}
}
function Cursor(buffer) {
this.buffer = buffer;
}
Cursor.prototype.next = function() {
var element = {};
var buffer = this.buffer;
var offset = 0;
var type = buffer[offset++];
element.tagClass = (type >> 6) & 0x03;
element.tagConstructed = (type >> 5) & 0x01;
var tagNumber = (type >> 0) & 0x1f;
if (tagNumber == 0x15) {
tagNumber = 0;
var tagNumberLast = buffer[offset++];
while(tagNumberLast & 0x80) {
tagNumber = (tagNumber << 7) + (tagNumberLast & 0x1f);
tagNumberLast = buffer[offset++];
}
tagNumber = (tagNumber << 7) + tagNumberLast;
}
element.tagNumber = tagNumber;
element.tag =
['UNIVERSAL', 'APPLICATION', 'context', 'PRIVATE'][element.tagClass] +
['-primative-','-constructed-'][element.tagConstructed] +
element.tagNumber.toString(16);
var length = buffer[offset++];
if ((length & 0x80) == 0x80 ) {
var lengthBytes = length & 0x7f;
length = 0;
while(lengthBytes--) {
length = length * 0x100 + buffer[offset++];
}
}
element.length = length;
if (length < 0) {
throw new Error('oob');
}
element.buffer = buffer.slice(offset, offset + length);
var slice1 = buffer.slice(offset + length);
var result = {element: element};
if (slice1.length) {
result.cursor = new Cursor(slice1);
}
return result;
}
function Formatter() {
EventEmitter.call(this);
}
util.inherits(Formatter, EventEmitter);
Formatter.prototype.format = function(element) {
this.emit(element.tag, element);
}
Der.defaultFormatter = new Formatter();
Der.defaultFormatter.on(Der.INTEGER, function(element) {
element.value = 0;
for(var offset = 0; offset != element.buffer.length; ++offset) {
element.value = (element.value << 8) + element.buffer[offset];
}
});
Der.defaultFormatter.on(Der.OBJECT_IDENTIFIER, function(element) {
var values = [0];
var scan = element.buffer.length;
var offset = 0;
var cumulative = 0;
while (scan--) {
var octet = element.buffer[offset++];
if (octet & 0x80) {
cumulative = (cumulative << 7) + (octet & 0x7f);
}
else {
values.push((cumulative << 7) + octet);
cumulative = 0;
}
}
values[0] = (values[1] / 40) >> 0;
values[1] = values[1] - values[0] * 40;
element.values = values;
element.value = values.join('.');
});
Der.defaultFormatter.on(Der.BIT_STRING, function(element) {
element.value = element.buffer;
});
Der.defaultFormatter.on(Der.OCTET_STRING, function(element) {
element.value = element.buffer;
});
Der.defaultFormatter.on(Der.BMPString, function(element) {
var swap = new Buffer(element.buffer.length);
for(var index = 0; index+1 < element.buffer.length; index += 2) {
swap[index] = element.buffer[index + 1];
swap[index+1] = element.buffer[index];
}
element.value = swap.toString('ucs2');
});
function dumpBuffer(buffer, oid) {
oid = oid || {};
var dec = new Decoder();
var leading = '. ';
dec.on('element', function(element) {
var value = util.inspect((element.value == null) ? '' : element.value );
if (value.length > 50){
value = value.substr(0, 50);
}
if (element.tag == Der.OBJECT_IDENTIFIER) {
value = value + ' ' + oid[element.value];
}
console.log('%s%s[%d] %s', leading, element.tag, element.length, value);
var old = leading;
leading = leading + '. ';
if (element.tagConstructed ||
element.tag == Der.OCTET_STRING ||
element.tag == Der.BIT_STRING ||
element.tag == Der.CONTEXT_0) {
try {
element.children = dec.parse(element.buffer);
}
catch(err) {
console.log(leading + '!!' + err.toString());
}
}
leading = old;
});
dec.parse(buffer);
}
exports = module.exports = Der;

Просмотреть файл

@ -0,0 +1,428 @@
var der = require('./der');
var util = require('util');
var assert = require('assert');
var crypto = require('crypto');
var Decoder = der.Decoder;
var Pkcs = {
PfxDecoder: PfxDecoder,
oid: {
'1.2.840.113549.1':'pkcs',
'1.2.840.113549.1.1':'pkcs1',
'1.2.840.113549.1.1.1':'RSA encryption',
'1.2.840.113549.1.7':'pkcs7',
'1.2.840.113549.1.7.1':'data',
'1.2.840.113549.1.7.6':'encryptedData',
'1.2.840.113549.1.9':'pkcs9',
'1.2.840.113549.1.9.20':'friendlyName',
'1.2.840.113549.1.9.21':'localKeyId',
'1.2.840.113549.1.9.22':'certTypes',
'1.2.840.113549.1.9.22.1':'x509Certificate',
'1.2.840.113549.1.12':'pkcs12',
'1.2.840.113549.1.12.1':'Password-Based Encryption identifiers',
'1.2.840.113549.1.12.1.3':'pbeWithSHAAnd3-KeyTripleDES-CBC',
'1.2.840.113549.1.12.1.6':'pbeWithSHAAnd40BitRC2-CBC',
'1.2.840.113549.1.12.10.1':'Bag Types',
'1.2.840.113549.1.12.10.1.2':'pkcs-8ShroudedKeyBag',
'1.2.840.113549.1.12.10.1.3':'certBag',
'1.3.6.1.4.1.311.17.1':'pkcs-12-key-provider-name-attr',
},
};
function PfxDecoder() {
var self = this;
Decoder.call(self);
var pdu = new PfxPduDecoder();
self.on('element', function(element) {
pdu.parse(element.buffer);
});
pdu.on('cert', function(cert) {
self.emit('cert', cert);
});
pdu.on('key', function(key) {
self.emit('key', key);
});
}
util.inherits(PfxDecoder, Decoder);
function PfxPduDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
var authSafe = new PfxContentInfoDecoder();
var authSafeItems = new PfxContentBagDecoder();
var safeBag = new PfxSafeBagDecoder();
self.on('end', function(elements) {
authSafe.parse(elements[1].buffer);
});
authSafe.on('data', function(data) {
authSafeItems.parse(data);
});
authSafeItems.on('data', function(data) {
safeBag.parse(data);
});
safeBag.on('cert', function(cert) {
self.emit('cert', cert);
});
safeBag.on('key', function(key) {
self.emit('key', key);
});
}
util.inherits(PfxPduDecoder, Decoder);
function PfxContentBagDecoder() {
var self = this;
Decoder.call(self);
var itemDecoder = new PfxContentInfoDecoder();
itemDecoder.on('data', function(data) {
self.emit('data', data);
});
self.on('element', function(element) {
assert.equal(element.tag, der.SEQUENCE);
itemDecoder.parse(element.buffer);
});
}
util.inherits(PfxContentBagDecoder, Decoder);
function PfxContentInfoDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
var encryptedData = new PfxEncryptedDataDecoder();
encryptedData.on('data', function(data) {
self.emit('data', data);
});
self.on('end', function(elements) {
assert.equal(elements[0].tag, der.OBJECT_IDENTIFIER);
var oid = elements[0].value;
if (Pkcs.oid[oid] == 'data') {
assert.equal(elements.length, 2);
assert.equal(elements[1].tag, der.CONTEXT_CONSTRUCTED_0);
elements = generic.parse(elements[1].buffer);
assert.equal(elements.length, 1);
assert.equal(elements[0].tag, der.OCTET_STRING);
elements = generic.parse(elements[0].buffer);
for(var index = 0; index != elements.length; ++index) {
assert.equal(elements[index].tag, der.SEQUENCE);
self.emit('data', elements[index].buffer);
}
}
else if (Pkcs.oid[oid] == 'encryptedData') {
assert.equal(elements[1].tag, der.CONTEXT_CONSTRUCTED_0);
elements = generic.parse(elements[1].buffer);
assert.equal(elements.length, 1);
assert.equal(elements[0].tag, der.SEQUENCE);
elements = generic.parse(elements[0].buffer);
assert.equal(elements.length, 2);
assert.equal(elements[0].tag, der.INTEGER);
assert.equal(elements[0].value, 0);
assert.equal(elements[1].tag, der.SEQUENCE);
encryptedData.parse(elements[1].buffer);
}
else {
throw new Error('Unknown AuthenticatedSafe oid ' + oid);
}
});
}
util.inherits(PfxContentInfoDecoder, Decoder);
function PfxEncryptedDataDecoder() {
var self = this;
Decoder.call(self);
var algorithmDecoder = new PfxAlgorithmDecoder();
var generic = new Decoder();
self.on('end', function(elements) {
assert.equal(elements.length, 3);
assert.equal(elements[0].tag, der.OBJECT_IDENTIFIER);
assert.equal(elements[1].tag, der.SEQUENCE);
assert.equal(elements[2].tag, der.CONTEXT_PRIMATIVE_0);
var algorithm = algorithmDecoder.parse(elements[1].buffer);
var cipher = algorithm.createCipher(null);
var data1 = cipher.update(elements[2].buffer.toString('binary'));
var data2 = cipher.final();
var data = new Buffer(data1 + data2, 'binary');
elements = generic.parse(data);
for(var index = 0; index != elements.length; ++index) {
assert.equal(elements[index].tag, der.SEQUENCE);
self.emit('data', elements[index].buffer);
}
});
}
util.inherits(PfxEncryptedDataDecoder, Decoder);
function PfxAlgorithmDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
self.on('end', function(elements) {
assert.equal(elements.length, 2);
assert.equal(elements[0].tag, der.OBJECT_IDENTIFIER);
assert.equal(elements[1].tag, der.SEQUENCE);
var arguments = generic.parse(elements[1].buffer);
assert.equal(arguments.length, 2);
assert.equal(arguments[0].tag, der.OCTET_STRING);
assert.equal(arguments[1].tag, der.INTEGER);
var algorithmOid = elements[0].value;
var salt = arguments[0].value;
var iterations = arguments[1].value;
var algorithmName = Pkcs.oid[algorithmOid];
if (algorithmName == 'pbeWithSHAAnd40BitRC2-CBC') {
elements.createCipher = function(password) {
var key = createPkcs12Info(password, salt, 5, iterations, 1);
var iv = createPkcs12Info(password, salt, 8, iterations, 2);
return crypto.createDecipheriv('rc2-40-cbc', key.toString('binary'), iv.toString('binary'));
};
}
else if (algorithmName == 'pbeWithSHAAnd3-KeyTripleDES-CBC') {
elements.createCipher = function(password) {
var key = createPkcs12Info(password, salt, 24, iterations, 1);
var iv = createPkcs12Info(password, salt, 8, iterations, 2);
return crypto.createDecipheriv('des-ede3-cbc', key.toString('binary'), iv.toString('binary'));
};
}
else {
throw new Error('Unknown algorithmId ' + bagId);
}
});
}
util.inherits(PfxAlgorithmDecoder, Decoder);
function PfxSafeBagDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
var pkcs8ShroudedKeyBag = new PfxPkcs8ShroudedKeyBagDecoder();
var certBag = new PfxCertBagDecoder();
certBag.on('cert', function(cert){self.emit('cert', cert);});
pkcs8ShroudedKeyBag.on('key', function(key){self.emit('key', key);});
self.on('element', function(element) {
assert.equal(element.tag, der.SEQUENCE);
var elements = generic.parse(element.buffer);
assert.equal(elements[0].tag, der.OBJECT_IDENTIFIER);
var bagId = elements[0].value;
if (Pkcs.oid[bagId] == 'pkcs-8ShroudedKeyBag') {
assert.equal(elements[1].tag, der.CONTEXT_CONSTRUCTED_0);
elements = generic.parse(elements[1].buffer);
assert.equal(elements[0].tag, der.SEQUENCE);
pkcs8ShroudedKeyBag.parse(elements[0].buffer);
}
else if (Pkcs.oid[bagId] == 'certBag') {
assert.equal(elements[1].tag, der.CONTEXT_CONSTRUCTED_0);
elements = generic.parse(elements[1].buffer);
assert.equal(elements[0].tag, der.SEQUENCE);
certBag.parse(elements[0].buffer);
}
else {
throw new Error('Unknown SafeBag bagId ' + bagId);
}
});
}
util.inherits(PfxSafeBagDecoder, Decoder);
function PfxPkcs8ShroudedKeyBagDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
var algorithmDecoder = new PfxAlgorithmDecoder();
self.on('end', function(elements) {
assert.equal(elements.length, 2);
assert.equal(elements[0].tag, der.SEQUENCE);
assert.equal(elements[1].tag, der.OCTET_STRING);
var algorithm = algorithmDecoder.parse(elements[0].buffer);
var cipher = algorithm.createCipher(null);
var data1 = cipher.update(elements[1].buffer.toString('binary'));
var data2 = cipher.final();
var data = new Buffer(data1 + data2, 'binary');
elements = generic.parse(data);
for(var index = 0; index != elements.length; ++index) {
assert.equal(elements[index].tag, der.SEQUENCE);
var fields = generic.parse(elements[index].buffer);
assert.equal(fields.length, 3);
assert.equal(fields[0].tag, der.INTEGER);
assert.equal(fields[1].tag, der.SEQUENCE);
fields[1].fields = generic.parse(fields[1].buffer);
assert.equal(fields[1].fields[0].tag, der.OBJECT_IDENTIFIER);
assert.equal(fields[2].tag, der.OCTET_STRING);
self.emit('key', {
type: fields[1].fields[0].value,
buffer: fields[2].buffer,
});
}
});
}
util.inherits(PfxPkcs8ShroudedKeyBagDecoder, Decoder);
function PfxCertBagDecoder() {
var self = this;
Decoder.call(self);
var generic = new Decoder();
self.on('end', function(elements) {
assert.equal(elements[0].tag, der.OBJECT_IDENTIFIER);
var certId = elements[0].value;
var certValue = elements[1].value;
if (Pkcs.oid[certId] == 'x509Certificate') {
assert.equal(elements[1].tag, der.CONTEXT_CONSTRUCTED_0);
elements = generic.parse(elements[1].buffer);
assert.equal(elements[0].tag, der.OCTET_STRING);
self.emit('cert', {
type: certId,
buffer: elements[0].buffer,
});
}
else {
throw new Error('Unknown CertBag certId ' + certId);
}
});
}
util.inherits(PfxCertBagDecoder, Decoder);
function createPkcs12Info(password, salt, keyLength, iterations, id) {
var digestLength = 20; // sha-1 digest size constant
var inputBytes = 64; // pkcs12 constant for sha-1
var idString = new Buffer(inputBytes);
for(var index = 0; index != idString.length; ++index) {
idString[index] = id;
}
var saltString = new Buffer(strangeLength(salt.length, inputBytes));
fillBuffer(salt, saltString);
var passwordString = null;
if (password == null || password.length == 0) {
passwordString = new Buffer(0);
}
else {
passwordString = new Buffer(strangeLength(password.length, inputBytes));
fillBuffer(password, passwordString);
}
var inputString = new Buffer(saltString.length + passwordString.length);
saltString.copy(inputString);
passwordString.copy(inputString, saltString.length);
var blocks = strangeLength(keyLength, digestLength) / digestLength;
var outputString = new Buffer(digestLength);
var holdString = new Buffer(inputBytes);
var dataString = new Buffer(blocks * digestLength);
var offset = 0;
for(var block = 0; block != blocks; ++block) {
outputString = digestIterations(idString, inputString, iterations);
outputString.copy(dataString, offset);
offset += outputString.length;
if (block != blocks - 1) {
fillBuffer(outputString, holdString);
createInputString(inputString, holdString, holdString);
}
}
var info = new Buffer(keyLength);
dataString.copy(info, 0, 0, keyLength);
return info;
}
function digestIterations(idString, inputString, iterations) {
var hash = crypto.createHash('sha1');
hash.update(idString);
hash.update(inputString);
// console.log('Digest D (length %d):', idString.length);
// console.log(idString);
// console.log('Digest I (length %d):', inputString.length);
// console.log(inputString);
var outputString = new Buffer(hash.digest('base64'),'base64');
for(var iteration = 1; iteration != iterations; ++iteration) {
hash = crypto.createHash('sha1');
hash.update(outputString);
outputString = new Buffer(hash.digest('base64'), 'base64');
}
// console.log(outputString);
return outputString;
}
function createInputString(oldInput, addedInput) {
var inputSize = addedInput.length;
var passes = (oldInput.length / inputSize) >> 0;
var offset = 0;
for (var pass = 0; pass != passes; ++pass) {
var carry = 1;
for (var scan = 0; scan != inputSize; ++scan) {
var index = inputSize - scan - 1;
var value = oldInput[index + offset] + addedInput[index] + carry;
oldInput[index + offset] = value & 0xff;
carry = value >> 8;
}
offset += inputSize;
}
}
function strangeLength(length, blockSize) {
return blockSize * (((length+blockSize-1)/blockSize) >> 0);
}
function fillBuffer(source, target) {
var sourceLength = source.length;
var targetLength = target.length;
var targetStart = 0;
while (targetStart + sourceLength <= targetLength) {
source.copy(target, targetStart);
targetStart += sourceLength;
}
// console.log('source.copy %d %d', targetStart, targetLength);
if (targetLength != targetStart) {
source.copy(target, targetStart, 0, targetLength - targetStart);
}
//console.log('fillBuffer');
//console.log(source);
//console.log(target);
}
exports = module.exports = Pkcs;

73
npm-debug.log Normal file
Просмотреть файл

@ -0,0 +1,73 @@
info it worked if it ends with ok
verbose cli [ 'node', '/usr/bin/npm', 'test' ]
info using npm@1.0.17
info using node@v0.4.11
verbose config file /Users/louis/.npmrc
verbose config file /usr/etc/npmrc
silly testEngine { name: 'azure',
silly testEngine author: { name: 'Microsoft Corporation' },
silly testEngine version: '0.5.2',
silly testEngine description: 'Windows Azure Client Library for node',
silly testEngine tags: [ 'azure', 'sdk' ],
silly testEngine keywords: [ 'node', 'azure' ],
silly testEngine main: './lib/azure.js',
silly testEngine engines: { node: '>= 0.4.7' },
silly testEngine licenses:
silly testEngine [ { type: 'Apache',
silly testEngine url: 'http://www.apache.org/licenses/LICENSE-2.0' } ],
silly testEngine dependencies:
silly testEngine { xml2js: '>= 0.1.11',
silly testEngine sax: '>= 0.1.1',
silly testEngine qs: '>= 0.3.1',
silly testEngine log: '>= 1.2.0',
silly testEngine xmlbuilder: '>= 0.3.1',
silly testEngine mime: '>= 1.2.4',
silly testEngine dateformat: '1.0.2-1.2.3',
silly testEngine underscore: '>= 1.3.1',
silly testEngine 'underscore.string': '>= 2.0.0' },
silly testEngine devDependencies: { mocha: '*', jshint: '*' },
silly testEngine homepage: 'http://github.com/WindowsAzure/azure-sdk-for-node',
silly testEngine repository:
silly testEngine { type: 'git',
silly testEngine url: 'git@github.com:WindowsAzure/azure-sdk-for-node.git' },
silly testEngine bugs: { url: 'http://github.com/WindowsAzure/azure-sdk-for-node/issues' },
silly testEngine scripts:
silly testEngine { test: 'node test/runtests.js',
silly testEngine jshint: 'node test/runjshint.js',
silly testEngine extendedtests: 'node test/runextendedtests.js' },
silly testEngine _npmJsonOpts:
silly testEngine { file: '/Users/louis/projects/azure-sdk-for-node-pr/package.json',
silly testEngine wscript: false,
silly testEngine contributors: false,
silly testEngine serverjs: false },
silly testEngine _id: 'azure@0.5.2',
silly testEngine _engineSupported: true,
silly testEngine _npmVersion: '1.0.17',
silly testEngine _nodeVersion: 'v0.4.11',
silly testEngine _defaultsLoaded: true }
verbose caching /Users/louis/projects/azure-sdk-for-node-pr/package.json
verbose loadDefaults azure@0.5.2
verbose run-script [ 'pretest', 'test', 'posttest' ]
info pretest azure@0.5.2
info test azure@0.5.2
verbose unsafe-perm in lifecycle true
silly exec sh "-c" "node test/runtests.js"
info azure@0.5.2 Failed to exec test script
ERR! azure@0.5.2 test: `node test/runtests.js`
ERR! `sh "-c" "node test/runtests.js"` failed with 9
ERR!
ERR! Failed at the azure@0.5.2 test script.
ERR! This is most likely a problem with the azure package,
ERR! not with npm itself.
ERR! Tell the author that this fails on your system:
ERR! node test/runtests.js
ERR! You can get their info via:
ERR! npm owner ls azure
ERR! There is likely additional logging output above.
ERR!
ERR! System Darwin 11.3.0
ERR! command "node" "/usr/bin/npm" "test"
ERR! cwd /Users/louis/projects/azure-sdk-for-node-pr
ERR! node -v v0.4.11
ERR! npm -v 1.0.17
verbose exit [ 1, true ]

Просмотреть файл

@ -19,4 +19,7 @@ services/table/tableservice-tests.js
util/atomhandler-tests.js
util/iso8061date-tests.js
util/util-tests.js
util/certificates/der.decoder.js
util/certificates/der.decoder.pfx.root.js
util/certificates/pkcs.filedecoder.js
azure-tests.js

Просмотреть файл

@ -0,0 +1,13 @@
MIICXQIBAAKBgQCju6PLddelT+nIMm07GQwmYa/eZ2JWbsmt2gotSCqM7asFp425
gxSK4jqhhT62UPpqDBEwvQ+fYkVv3RV0r9ReuZGv12NoS4fXsQgqO17lHA7Od0Kd
2yNwJjKh44MxPKDt2o8iQMyZE0zlHnEFNpsP4COLTDNC6ljEEu5bk8uPsQIDAQAB
AoGAVZmpFZsDZfr0l2S9tLLwpjRWNOlKATQkno6q2WesT0eGLQufTciY+c8ypfU6
hyio8r5iUl/VhhdjhAtKx1mRpiotftHo/eYf8rtsrnprOnWG0bWjLjtIoMbcxGn2
J3bN6LJmbJMjDs0eJ3KnTu646F3nDUw2oGAwmpzKXA1KAP0CQQDRvQhxk2D3Pehs
HvG665u2pB5ipYQngEFlZO7RHJZzJOZEWSLuuMqaF/7pTfA5jiBvWqCgJeCRRInL
21ru4dlPAkEAx9jj7BgKn5TYnMoBSSe0afjsV9oApVpN1Nacb1YDtCwy+scp3++s
nFxlv98wxIlSdpwMUn+AUWfjiWR7Tu/G/wJBAJ/KjwZIrFVxewP0x2ILYsTRYLzz
MS4PDsO7FB+I0i7DbBOifXS2oNSpd3I0CNMwrxFnUHzynpbOStVfN3ZL5w0CQQCa
pwFahxBRhkJKsxhjoFJBX9yl75JoY4Wvm5Tbo9ih6UJaRx3kqfkN14L2BKYcsZgb
KY9vmDOYy6iNfjDeWTfJAkBkfPUb8oTJ/nSP5zN6sqGxSY4krc4xLxpRmxoJ8HL2
XfhqXkTzbU13RX9JJ/NZ8vQN9Vm2NhxRGJocQkmcdVtJ

Просмотреть файл

@ -0,0 +1,16 @@
MIIC5TCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQQFADBcMQswCQYDVQQGEwJBVTET
MBEGA1UECBMKUXVlZW5zbGFuZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQx
HDAaBgNVBAMTE1Rlc3QgUENBICgxMDI0IGJpdCkwHhcNOTkxMjAyMjEzODUxWhcN
MDUwNzEwMjEzODUxWjBbMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFu
ZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxGzAZBgNVBAMTElRlc3QgQ0Eg
KDEwMjQgYml0KTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAo7ujy3XXpU/p
yDJtOxkMJmGv3mdiVm7JrdoKLUgqjO2rBaeNuYMUiuI6oYU+tlD6agwRML0Pn2JF
b90VdK/UXrmRr9djaEuH17EIKjte5RwOzndCndsjcCYyoeODMTyg7dqPIkDMmRNM
5R5xBTabD+Aji0wzQupYxBLuW5PLj7ECAwEAAaOBtzCBtDAdBgNVHQ4EFgQU1WWA
U42mkhi3ecgey1dsJjU61+UwgYQGA1UdIwR9MHuAFE0RaEcrj18q1dw+G6nJbsTW
R213oWCkXjBcMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG
A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxHDAaBgNVBAMTE1Rlc3QgUENBICgxMDI0
IGJpdCmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBb39BRphHL
6aRAQyymsvBvPSCiG9+kR0R1L23aTpNbhXp2BebyFjbEQYZc2kWGiKKcHkNECA35
3d4LoqUlVey8DFyafOIJd9hxdZfg+rxlHMxnL7uCJRmx9+xB411Jtsol9/wg1uCK
sleGpgB4j8cG2SVCz7V2MNZNK+d5QCnR7A==

Двоичные данные
test/util/certificates/client-x509-rsa.pfx Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,25 @@
var der = require('./der');
var fs = require('fs');
require('should');
suite('der', function(){
suite('decoder', function() {
test('should have one root element', function(done) {
fs.readFile('test/util/certificates/ca-cert-x509.base64', function(err,data) {
if (err) {
return done(err);
}
var buffer = new Buffer(data.toString('ascii'), 'base64');
var dec = new der.Decoder();
var elements = dec.parse(buffer);
elements.should.have.length(1);
done();
});
});
});
});

Просмотреть файл

@ -0,0 +1,59 @@
var der = require('./der');
var fs = require('fs');
require('should');
suite('der', function(){
suite('decoder-pfx-root', function() {
var dec = new der.Decoder();
function readAndDecode(filename, callback) {
fs.readFile(filename, function(err,data) {
if (err) {
return callback(err);
}
var elements = dec.parse(data);
callback(null, elements);
});
}
test('should have one root element', function(done) {
readAndDecode('test/util/certificates/client-x509-rsa.pfx', function(err,elements) {
if (err) {
return done(err);
}
elements.should.have.length(1);
done();
});
});
test('should have two or three children', function(done) {
readAndDecode('test/util/certificates/client-x509-rsa.pfx', function(err,elements) {
if (err) {
return done(err);
}
var children = dec.parse(elements[0].buffer);
children.length.should.be.within(2,3);
done();
});
});
test('should have version number 3 and a sequence', function(done) {
readAndDecode('test/util/certificates/client-x509-rsa.pfx', function(err,elements) {
if (err) {
return done(err);
}
elements[0].should.have.property('tag', der.SEQUENCE);
var children = dec.parse(elements[0].buffer);
children[0].should.have.property('tag', der.INTEGER);
children[0].should.have.property('value', 3);
children[1].should.have.property('tag', der.SEQUENCE);
done();
});
});
});
});

Просмотреть файл

@ -0,0 +1 @@
module.exports = require('../../../lib/util/certificates/der.js');

Просмотреть файл

@ -0,0 +1,36 @@
var der = require('./der');
var pkcs = require('./pkcs');
var PfxDecoder = pkcs.PfxDecoder;
var fs = require('fs');
require('should');
suite('pkcs', function() {
suite('filedecoder', function() {
test('should run and produce a cert and a key', function(done) {
fs.readFile('test/util/certificates/client-x509-rsa.pfx', function(err, data) {
if (err) {
return done(err);
}
var pfx = new PfxDecoder();
var pfxCert = null;
pfx.on('cert', function(cert){
pfxCert = cert;
});
var pfxKey = null;
pfx.on('key', function(key){
pfxKey = key;
});
var elements = pfx.parse(data);
(pfxCert == null).should.be.false;
(pfxKey == null).should.be.false;
done();
});
});
});
});

Просмотреть файл

@ -0,0 +1 @@
module.exports = require('../../../lib/util/certificates/pkcs.js');