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:
Родитель
923bf05f3d
Коммит
3be6c05364
|
@ -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;
|
|
@ -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==
|
Двоичный файл не отображается.
|
@ -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');
|
Загрузка…
Ссылка в новой задаче