mirror of
https://github.com/moparisthebest/mail
synced 2025-02-16 15:10:10 -05:00
update and test forge ~0.1.14
This commit is contained in:
parent
9ad79f640f
commit
79b297e624
569
src/lib/aes.js
569
src/lib/aes.js
@ -447,7 +447,7 @@ var expandKey = function(key, decrypt) {
|
|||||||
sbox[temp >>> 24] ^ (rcon[iNk] << 24);
|
sbox[temp >>> 24] ^ (rcon[iNk] << 24);
|
||||||
iNk++;
|
iNk++;
|
||||||
}
|
}
|
||||||
else if(Nk > 6 && (i % Nk == 4)) {
|
else if(Nk > 6 && (i % Nk === 4)) {
|
||||||
// temp = SubWord(temp)
|
// temp = SubWord(temp)
|
||||||
temp =
|
temp =
|
||||||
sbox[temp >>> 24] << 24 ^
|
sbox[temp >>> 24] << 24 ^
|
||||||
@ -798,7 +798,7 @@ var _updateBlock = function(w, input, output, decrypt) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AES cipher object. CBC (cipher-block-chaining) mode will be
|
* Creates an AES cipher object. CBC (cipher-block-chaining) mode will be
|
||||||
* used.
|
* used by default, the other supported modes are: CFB.
|
||||||
*
|
*
|
||||||
* The key and iv may be given as a string of bytes, an array of bytes, a
|
* The key and iv may be given as a string of bytes, an array of bytes, a
|
||||||
* byte buffer, or an array of 32-bit words. If an iv is provided, then
|
* byte buffer, or an array of 32-bit words. If an iv is provided, then
|
||||||
@ -809,29 +809,33 @@ var _updateBlock = function(w, input, output, decrypt) {
|
|||||||
* @param iv the initialization vector to start with, null not to start.
|
* @param iv the initialization vector to start with, null not to start.
|
||||||
* @param output the buffer to write to.
|
* @param output the buffer to write to.
|
||||||
* @param decrypt true for decryption, false for encryption.
|
* @param decrypt true for decryption, false for encryption.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
var _createCipher = function(key, iv, output, decrypt) {
|
var _createCipher = function(key, iv, output, decrypt, mode) {
|
||||||
var cipher = null;
|
var cipher = null;
|
||||||
|
|
||||||
if(!init) {
|
if(!init) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default to CBC mode
|
||||||
|
mode = (mode || 'CBC').toUpperCase();
|
||||||
|
|
||||||
/* Note: The key may be a string of bytes, an array of bytes, a byte
|
/* Note: The key may be a string of bytes, an array of bytes, a byte
|
||||||
buffer, or an array of 32-bit integers. If the key is in bytes, then
|
buffer, or an array of 32-bit integers. If the key is in bytes, then
|
||||||
it must be 16, 24, or 32 bytes in length. If it is in 32-bit
|
it must be 16, 24, or 32 bytes in length. If it is in 32-bit
|
||||||
integers, it must be 4, 6, or 8 integers long. */
|
integers, it must be 4, 6, or 8 integers long. */
|
||||||
|
|
||||||
// convert key string into byte buffer
|
// convert key string into byte buffer
|
||||||
if(key.constructor == String &&
|
if(typeof key === 'string' &&
|
||||||
(key.length == 16 || key.length == 24 || key.length == 32)) {
|
(key.length === 16 || key.length === 24 || key.length === 32)) {
|
||||||
key = forge.util.createBuffer(key);
|
key = forge.util.createBuffer(key);
|
||||||
}
|
}
|
||||||
// convert key integer array into byte buffer
|
// convert key integer array into byte buffer
|
||||||
else if(key.constructor == Array &&
|
else if(forge.util.isArray(key) &&
|
||||||
(key.length == 16 || key.length == 24 || key.length == 32)) {
|
(key.length === 16 || key.length === 24 || key.length === 32)) {
|
||||||
var tmp = key;
|
var tmp = key;
|
||||||
var key = forge.util.createBuffer();
|
var key = forge.util.createBuffer();
|
||||||
for(var i = 0; i < tmp.length; ++i) {
|
for(var i = 0; i < tmp.length; ++i) {
|
||||||
@ -840,13 +844,13 @@ var _createCipher = function(key, iv, output, decrypt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert key byte buffer into 32-bit integer array
|
// convert key byte buffer into 32-bit integer array
|
||||||
if(key.constructor != Array) {
|
if(!forge.util.isArray(key)) {
|
||||||
var tmp = key;
|
var tmp = key;
|
||||||
key = [];
|
key = [];
|
||||||
|
|
||||||
// key lengths of 16, 24, 32 bytes allowed
|
// key lengths of 16, 24, 32 bytes allowed
|
||||||
var len = tmp.length();
|
var len = tmp.length();
|
||||||
if(len == 16 || len == 24 || len == 32) {
|
if(len === 16 || len === 24 || len === 32) {
|
||||||
len = len >>> 2;
|
len = len >>> 2;
|
||||||
for(var i = 0; i < len; ++i) {
|
for(var i = 0; i < len; ++i) {
|
||||||
key.push(tmp.getInt32());
|
key.push(tmp.getInt32());
|
||||||
@ -855,197 +859,298 @@ var _createCipher = function(key, iv, output, decrypt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// key must be an array of 32-bit integers by now
|
// key must be an array of 32-bit integers by now
|
||||||
if(key.constructor == Array &&
|
if(!forge.util.isArray(key) ||
|
||||||
(key.length == 4 || key.length == 6 || key.length == 8)) {
|
!(key.length === 4 || key.length === 6 || key.length === 8)) {
|
||||||
// private vars for state
|
return cipher;
|
||||||
var _w = expandKey(key, decrypt);
|
}
|
||||||
var _blockSize = Nb << 2;
|
|
||||||
var _input;
|
|
||||||
var _output;
|
|
||||||
var _inBlock;
|
|
||||||
var _outBlock;
|
|
||||||
var _prev;
|
|
||||||
var _finish;
|
|
||||||
cipher = {
|
|
||||||
// output from AES (either encrypted or decrypted bytes)
|
|
||||||
output: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
// (CFB/OFB/CTR always uses encryption)
|
||||||
* Updates the next block using CBC mode.
|
var alwaysEncrypt = (['CFB', 'OFB', 'CTR'].indexOf(mode) !== -1);
|
||||||
*
|
|
||||||
* @param input the buffer to read from.
|
|
||||||
*/
|
|
||||||
cipher.update = function(input) {
|
|
||||||
if(!_finish) {
|
|
||||||
// not finishing, so fill the input buffer with more input
|
|
||||||
_input.putBuffer(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In encrypt mode, the threshold for updating a block is the
|
// CBC mode requires padding
|
||||||
block size. As soon as enough input is available to update
|
var requirePadding = (mode === 'CBC');
|
||||||
a block, encryption may occur. In decrypt mode, we wait for
|
|
||||||
2 blocks to be available or for the finish flag to be set
|
|
||||||
with only 1 block available. This is done so that the output
|
|
||||||
buffer will not be populated with padding bytes at the end
|
|
||||||
of the decryption -- they can be truncated before returning
|
|
||||||
from finish(). */
|
|
||||||
var threshold = decrypt && !_finish ? _blockSize << 1 : _blockSize;
|
|
||||||
while(_input.length() >= threshold) {
|
|
||||||
// get next block
|
|
||||||
if(decrypt) {
|
|
||||||
for(var i = 0; i < Nb; ++i) {
|
|
||||||
_inBlock[i] = _input.getInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// CBC mode XOR's IV (or previous block) with plaintext
|
|
||||||
for(var i = 0; i < Nb; ++i) {
|
|
||||||
_inBlock[i] = _prev[i] ^ _input.getInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update block
|
// private vars for state
|
||||||
_updateBlock(_w, _inBlock, _outBlock, decrypt);
|
var _w = expandKey(key, decrypt && !alwaysEncrypt);
|
||||||
|
var _blockSize = Nb << 2;
|
||||||
|
var _input;
|
||||||
|
var _output;
|
||||||
|
var _inBlock;
|
||||||
|
var _outBlock;
|
||||||
|
var _prev;
|
||||||
|
var _finish;
|
||||||
|
var _op;
|
||||||
|
cipher = {
|
||||||
|
// output from AES (either encrypted or decrypted bytes)
|
||||||
|
output: null
|
||||||
|
};
|
||||||
|
|
||||||
// write output, save previous ciphered block
|
if(mode === 'CBC') {
|
||||||
if(decrypt) {
|
_op = cbcOp;
|
||||||
// CBC mode XOR's IV (or previous block) with plaintext
|
}
|
||||||
for(var i = 0; i < Nb; ++i) {
|
else if(mode === 'CFB') {
|
||||||
_output.putInt32(_prev[i] ^ _outBlock[i]);
|
_op = cfbOp;
|
||||||
}
|
}
|
||||||
_prev = _inBlock.slice(0);
|
else if(mode === 'OFB') {
|
||||||
}
|
_op = ofbOp;
|
||||||
else {
|
}
|
||||||
for(var i = 0; i < Nb; ++i) {
|
else if(mode === 'CTR') {
|
||||||
_output.putInt32(_outBlock[i]);
|
_op = ctrOp;
|
||||||
}
|
}
|
||||||
_prev = _outBlock;
|
else {
|
||||||
}
|
throw {
|
||||||
}
|
message: 'Unsupported block cipher mode of operation: "' + mode + '"'
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finishes encrypting or decrypting.
|
|
||||||
*
|
|
||||||
* @param pad a padding function to use, null for default,
|
|
||||||
* signature(blockSize, buffer, decrypt).
|
|
||||||
*
|
|
||||||
* @return true if successful, false on error.
|
|
||||||
*/
|
|
||||||
cipher.finish = function(pad) {
|
|
||||||
var rval = true;
|
|
||||||
|
|
||||||
if(!decrypt) {
|
|
||||||
if(pad) {
|
|
||||||
rval = pad(_blockSize, _input, decrypt);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// add PKCS#7 padding to block (each pad byte is the
|
|
||||||
// value of the number of pad bytes)
|
|
||||||
var padding = (_input.length() == _blockSize) ?
|
|
||||||
_blockSize : (_blockSize - _input.length());
|
|
||||||
_input.fillWithByte(padding, padding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rval) {
|
|
||||||
// do final update
|
|
||||||
_finish = true;
|
|
||||||
cipher.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(decrypt) {
|
|
||||||
// check for error: input data not a multiple of blockSize
|
|
||||||
rval = (_input.length() === 0);
|
|
||||||
if(rval) {
|
|
||||||
if(pad) {
|
|
||||||
rval = pad(_blockSize, _output, decrypt);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// ensure padding byte count is valid
|
|
||||||
var len = _output.length();
|
|
||||||
var count = _output.at(len - 1);
|
|
||||||
if(count > (Nb << 2)) {
|
|
||||||
rval = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// trim off padding bytes
|
|
||||||
_output.truncate(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts or restarts the encryption or decryption process, whichever
|
|
||||||
* was previously configured.
|
|
||||||
*
|
|
||||||
* The iv may be given as a string of bytes, an array of bytes, a
|
|
||||||
* byte buffer, or an array of 32-bit words.
|
|
||||||
*
|
|
||||||
* @param iv the initialization vector to use, null to reuse the
|
|
||||||
* last ciphered block from a previous update().
|
|
||||||
* @param output the output the buffer to write to, null to create one.
|
|
||||||
*/
|
|
||||||
cipher.start = function(iv, output) {
|
|
||||||
// if IV is null, reuse block from previous encryption/decryption
|
|
||||||
iv = iv || _prev.slice(0);
|
|
||||||
|
|
||||||
/* Note: The IV may be a string of bytes, an array of bytes, a
|
|
||||||
byte buffer, or an array of 32-bit integers. If the IV is in
|
|
||||||
bytes, then it must be Nb (16) bytes in length. If it is in
|
|
||||||
32-bit integers, then it must be 4 integers long. */
|
|
||||||
|
|
||||||
// convert iv string into byte buffer
|
|
||||||
if(iv.constructor == String && iv.length == 16) {
|
|
||||||
iv = forge.util.createBuffer(iv);
|
|
||||||
}
|
|
||||||
// convert iv byte array into byte buffer
|
|
||||||
else if(iv.constructor == Array && iv.length == 16) {
|
|
||||||
var tmp = iv;
|
|
||||||
var iv = forge.util.createBuffer();
|
|
||||||
for(var i = 0; i < 16; ++i) {
|
|
||||||
iv.putByte(tmp[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert iv byte buffer into 32-bit integer array
|
|
||||||
if(iv.constructor != Array) {
|
|
||||||
var tmp = iv;
|
|
||||||
iv = new Array(4);
|
|
||||||
iv[0] = tmp.getInt32();
|
|
||||||
iv[1] = tmp.getInt32();
|
|
||||||
iv[2] = tmp.getInt32();
|
|
||||||
iv[3] = tmp.getInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set private vars
|
|
||||||
_input = forge.util.createBuffer();
|
|
||||||
_output = output || forge.util.createBuffer();
|
|
||||||
_prev = iv.slice(0);
|
|
||||||
_inBlock = new Array(Nb);
|
|
||||||
_outBlock = new Array(Nb);
|
|
||||||
_finish = false;
|
|
||||||
cipher.output = _output;
|
|
||||||
};
|
|
||||||
if(iv !== null) {
|
|
||||||
cipher.start(iv, output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the next block according to the cipher mode.
|
||||||
|
*
|
||||||
|
* @param input the buffer to read from.
|
||||||
|
*/
|
||||||
|
cipher.update = function(input) {
|
||||||
|
if(!_finish) {
|
||||||
|
// not finishing, so fill the input buffer with more input
|
||||||
|
_input.putBuffer(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do cipher operation while input contains full blocks or if finishing
|
||||||
|
while(_input.length() >= _blockSize || (_input.length() > 0 && _finish)) {
|
||||||
|
_op();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes encrypting or decrypting.
|
||||||
|
*
|
||||||
|
* @param pad a padding function to use in CBC mode, null for default,
|
||||||
|
* signature(blockSize, buffer, decrypt).
|
||||||
|
*
|
||||||
|
* @return true if successful, false on error.
|
||||||
|
*/
|
||||||
|
cipher.finish = function(pad) {
|
||||||
|
var rval = true;
|
||||||
|
|
||||||
|
// get # of bytes that won't fill a block
|
||||||
|
var overflow = _input.length() % _blockSize;
|
||||||
|
|
||||||
|
if(!decrypt) {
|
||||||
|
if(pad) {
|
||||||
|
rval = pad(_blockSize, _input, decrypt);
|
||||||
|
}
|
||||||
|
else if(requirePadding) {
|
||||||
|
// add PKCS#7 padding to block (each pad byte is the
|
||||||
|
// value of the number of pad bytes)
|
||||||
|
var padding = (_input.length() === _blockSize) ?
|
||||||
|
_blockSize : (_blockSize - _input.length());
|
||||||
|
_input.fillWithByte(padding, padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rval) {
|
||||||
|
// do final update
|
||||||
|
_finish = true;
|
||||||
|
cipher.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(decrypt) {
|
||||||
|
if(requirePadding) {
|
||||||
|
// check for error: input data not a multiple of blockSize
|
||||||
|
rval = (overflow === 0);
|
||||||
|
}
|
||||||
|
if(rval) {
|
||||||
|
if(pad) {
|
||||||
|
rval = pad(_blockSize, _output, decrypt);
|
||||||
|
}
|
||||||
|
else if(requirePadding) {
|
||||||
|
// ensure padding byte count is valid
|
||||||
|
var len = _output.length();
|
||||||
|
var count = _output.at(len - 1);
|
||||||
|
if(count > (Nb << 2)) {
|
||||||
|
rval = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// trim off padding bytes
|
||||||
|
_output.truncate(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle stream mode truncation if padding not set
|
||||||
|
if(!requirePadding && !pad && overflow > 0) {
|
||||||
|
_output.truncate(_blockSize - overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts or restarts the encryption or decryption process, whichever
|
||||||
|
* was previously configured.
|
||||||
|
*
|
||||||
|
* The iv may be given as a string of bytes, an array of bytes, a
|
||||||
|
* byte buffer, or an array of 32-bit words.
|
||||||
|
*
|
||||||
|
* @param iv the initialization vector to use, null to reuse the
|
||||||
|
* last ciphered block from a previous update().
|
||||||
|
* @param output the output the buffer to write to, null to create one.
|
||||||
|
*/
|
||||||
|
cipher.start = function(iv, output) {
|
||||||
|
// if IV is null, reuse block from previous encryption/decryption
|
||||||
|
if(iv === null) {
|
||||||
|
iv = _prev.slice(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: The IV may be a string of bytes, an array of bytes, a
|
||||||
|
byte buffer, or an array of 32-bit integers. If the IV is in
|
||||||
|
bytes, then it must be Nb (16) bytes in length. If it is in
|
||||||
|
32-bit integers, then it must be 4 integers long. */
|
||||||
|
|
||||||
|
// convert iv string into byte buffer
|
||||||
|
if(typeof iv === 'string' && iv.length === 16) {
|
||||||
|
iv = forge.util.createBuffer(iv);
|
||||||
|
}
|
||||||
|
// convert iv byte array into byte buffer
|
||||||
|
else if(forge.util.isArray(iv) && iv.length === 16) {
|
||||||
|
var tmp = iv;
|
||||||
|
var iv = forge.util.createBuffer();
|
||||||
|
for(var i = 0; i < 16; ++i) {
|
||||||
|
iv.putByte(tmp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert iv byte buffer into 32-bit integer array
|
||||||
|
if(!forge.util.isArray(iv)) {
|
||||||
|
var tmp = iv;
|
||||||
|
iv = new Array(4);
|
||||||
|
iv[0] = tmp.getInt32();
|
||||||
|
iv[1] = tmp.getInt32();
|
||||||
|
iv[2] = tmp.getInt32();
|
||||||
|
iv[3] = tmp.getInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set private vars
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_output = output || forge.util.createBuffer();
|
||||||
|
_prev = iv.slice(0);
|
||||||
|
_inBlock = new Array(Nb);
|
||||||
|
_outBlock = new Array(Nb);
|
||||||
|
_finish = false;
|
||||||
|
cipher.output = _output;
|
||||||
|
|
||||||
|
// CFB/OFB/CTR uses IV as first input
|
||||||
|
if(['CFB', 'OFB', 'CTR'].indexOf(mode) !== -1) {
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_inBlock[i] = _prev[i];
|
||||||
|
}
|
||||||
|
_prev = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(iv !== null) {
|
||||||
|
cipher.start(iv, output);
|
||||||
|
}
|
||||||
return cipher;
|
return cipher;
|
||||||
|
|
||||||
|
// block cipher mode operations:
|
||||||
|
|
||||||
|
function cbcOp() {
|
||||||
|
// get next block
|
||||||
|
if(decrypt) {
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_inBlock[i] = _input.getInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// CBC XOR's IV (or previous block) with plaintext
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_inBlock[i] = _prev[i] ^ _input.getInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update block
|
||||||
|
_updateBlock(_w, _inBlock, _outBlock, decrypt);
|
||||||
|
|
||||||
|
// write output, save previous ciphered block
|
||||||
|
if(decrypt) {
|
||||||
|
// CBC XOR's IV (or previous block) with ciphertext
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_output.putInt32(_prev[i] ^ _outBlock[i]);
|
||||||
|
}
|
||||||
|
_prev = _inBlock.slice(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_output.putInt32(_outBlock[i]);
|
||||||
|
}
|
||||||
|
_prev = _outBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cfbOp() {
|
||||||
|
// update block (CFB always uses encryption mode)
|
||||||
|
_updateBlock(_w, _inBlock, _outBlock, false);
|
||||||
|
|
||||||
|
// get next input
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_inBlock[i] = _input.getInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR input with output
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
var result = _inBlock[i] ^ _outBlock[i];
|
||||||
|
if(!decrypt) {
|
||||||
|
// update next input block when encrypting
|
||||||
|
_inBlock[i] = result;
|
||||||
|
}
|
||||||
|
_output.putInt32(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ofbOp() {
|
||||||
|
// update block (OFB always uses encryption mode)
|
||||||
|
_updateBlock(_w, _inBlock, _outBlock, false);
|
||||||
|
|
||||||
|
// get next input
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_inBlock[i] = _input.getInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR input with output and update next input
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_output.putInt32(_inBlock[i] ^ _outBlock[i]);
|
||||||
|
_inBlock[i] = _outBlock[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ctrOp() {
|
||||||
|
// update block (CTR always uses encryption mode)
|
||||||
|
_updateBlock(_w, _inBlock, _outBlock, false);
|
||||||
|
|
||||||
|
// increment counter (input block)
|
||||||
|
for(var i = Nb - 1; i >= 0; --i) {
|
||||||
|
if(_inBlock[i] === 0xFFFFFFFF) {
|
||||||
|
_inBlock[i] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++_inBlock[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR input with output
|
||||||
|
for(var i = 0; i < Nb; ++i) {
|
||||||
|
_output.putInt32(_input.getInt32() ^ _outBlock[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* AES API */
|
/* AES API */
|
||||||
forge.aes = forge.aes || {};
|
forge.aes = forge.aes || {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AES cipher object to encrypt data in CBC mode using the
|
* Creates an AES cipher object to encrypt data using the given symmetric key.
|
||||||
* given symmetric key. The output will be stored in the 'output' member
|
* The output will be stored in the 'output' member of the returned cipher.
|
||||||
* of the returned cipher.
|
|
||||||
*
|
*
|
||||||
* The key and iv may be given as a string of bytes, an array of bytes,
|
* The key and iv may be given as a string of bytes, an array of bytes,
|
||||||
* a byte buffer, or an array of 32-bit words.
|
* a byte buffer, or an array of 32-bit words.
|
||||||
@ -1053,16 +1158,16 @@ forge.aes = forge.aes || {};
|
|||||||
* @param key the symmetric key to use.
|
* @param key the symmetric key to use.
|
||||||
* @param iv the initialization vector to use.
|
* @param iv the initialization vector to use.
|
||||||
* @param output the buffer to write to, null to create one.
|
* @param output the buffer to write to, null to create one.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.aes.startEncrypting = function(key, iv, output) {
|
forge.aes.startEncrypting = function(key, iv, output, mode) {
|
||||||
return _createCipher(key, iv, output, false);
|
return _createCipher(key, iv, output, false, mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AES cipher object to encrypt data in CBC mode using the
|
* Creates an AES cipher object to encrypt data using the given symmetric key.
|
||||||
* given symmetric key.
|
|
||||||
*
|
*
|
||||||
* The key may be given as a string of bytes, an array of bytes, a
|
* The key may be given as a string of bytes, an array of bytes, a
|
||||||
* byte buffer, or an array of 32-bit words.
|
* byte buffer, or an array of 32-bit words.
|
||||||
@ -1071,17 +1176,17 @@ forge.aes.startEncrypting = function(key, iv, output) {
|
|||||||
* output buffer.
|
* output buffer.
|
||||||
*
|
*
|
||||||
* @param key the symmetric key to use.
|
* @param key the symmetric key to use.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.aes.createEncryptionCipher = function(key) {
|
forge.aes.createEncryptionCipher = function(key, mode) {
|
||||||
return _createCipher(key, null, null, false);
|
return _createCipher(key, null, null, false, mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AES cipher object to decrypt data in CBC mode using the
|
* Creates an AES cipher object to decrypt data using the given symmetric key.
|
||||||
* given symmetric key. The output will be stored in the 'output' member
|
* The output will be stored in the 'output' member of the returned cipher.
|
||||||
* of the returned cipher.
|
|
||||||
*
|
*
|
||||||
* The key and iv may be given as a string of bytes, an array of bytes,
|
* The key and iv may be given as a string of bytes, an array of bytes,
|
||||||
* a byte buffer, or an array of 32-bit words.
|
* a byte buffer, or an array of 32-bit words.
|
||||||
@ -1089,16 +1194,16 @@ forge.aes.createEncryptionCipher = function(key) {
|
|||||||
* @param key the symmetric key to use.
|
* @param key the symmetric key to use.
|
||||||
* @param iv the initialization vector to use.
|
* @param iv the initialization vector to use.
|
||||||
* @param output the buffer to write to, null to create one.
|
* @param output the buffer to write to, null to create one.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.aes.startDecrypting = function(key, iv, output) {
|
forge.aes.startDecrypting = function(key, iv, output, mode) {
|
||||||
return _createCipher(key, iv, output, true);
|
return _createCipher(key, iv, output, true, mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AES cipher object to decrypt data in CBC mode using the
|
* Creates an AES cipher object to decrypt data using the given symmetric key.
|
||||||
* given symmetric key.
|
|
||||||
*
|
*
|
||||||
* The key may be given as a string of bytes, an array of bytes, a
|
* The key may be given as a string of bytes, an array of bytes, a
|
||||||
* byte buffer, or an array of 32-bit words.
|
* byte buffer, or an array of 32-bit words.
|
||||||
@ -1107,11 +1212,12 @@ forge.aes.startDecrypting = function(key, iv, output) {
|
|||||||
* optional output buffer.
|
* optional output buffer.
|
||||||
*
|
*
|
||||||
* @param key the symmetric key to use.
|
* @param key the symmetric key to use.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.aes.createDecryptionCipher = function(key) {
|
forge.aes.createDecryptionCipher = function(key, mode) {
|
||||||
return _createCipher(key, null, null, true);
|
return _createCipher(key, null, null, true, mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1143,12 +1249,11 @@ forge.aes._updateBlock = _updateBlock;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'aes';
|
var name = 'aes';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1157,30 +1262,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
309
src/lib/aesCipherSuites.js
Normal file
309
src/lib/aesCipherSuites.js
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/**
|
||||||
|
* A Javascript implementation of AES Cipher Suites for TLS.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2013 Digital Bazaar, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var tls = forge.tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported cipher suites.
|
||||||
|
*/
|
||||||
|
tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = {
|
||||||
|
id: [0x00,0x2f],
|
||||||
|
name: 'TLS_RSA_WITH_AES_128_CBC_SHA',
|
||||||
|
initSecurityParameters: function(sp) {
|
||||||
|
sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
|
||||||
|
sp.cipher_type = tls.CipherType.block;
|
||||||
|
sp.enc_key_length = 16;
|
||||||
|
sp.block_length = 16;
|
||||||
|
sp.fixed_iv_length = 16;
|
||||||
|
sp.record_iv_length = 16;
|
||||||
|
sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
|
||||||
|
sp.mac_length = 20;
|
||||||
|
sp.mac_key_length = 20;
|
||||||
|
},
|
||||||
|
initConnectionState: initConnectionState
|
||||||
|
};
|
||||||
|
tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = {
|
||||||
|
id: [0x00,0x35],
|
||||||
|
name: 'TLS_RSA_WITH_AES_256_CBC_SHA',
|
||||||
|
initSecurityParameters: function(sp) {
|
||||||
|
sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
|
||||||
|
sp.cipher_type = tls.CipherType.block;
|
||||||
|
sp.enc_key_length = 32;
|
||||||
|
sp.block_length = 16;
|
||||||
|
sp.fixed_iv_length = 16;
|
||||||
|
sp.record_iv_length = 16;
|
||||||
|
sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
|
||||||
|
sp.mac_length = 20;
|
||||||
|
sp.mac_key_length = 20;
|
||||||
|
},
|
||||||
|
initConnectionState: initConnectionState
|
||||||
|
};
|
||||||
|
|
||||||
|
function initConnectionState(state, c, sp) {
|
||||||
|
var client = (c.entity === forge.tls.ConnectionEnd.client);
|
||||||
|
|
||||||
|
// cipher setup
|
||||||
|
state.read.cipherState = {
|
||||||
|
init: false,
|
||||||
|
cipher: forge.aes.createDecryptionCipher(client ?
|
||||||
|
sp.keys.server_write_key : sp.keys.client_write_key),
|
||||||
|
iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV
|
||||||
|
};
|
||||||
|
state.write.cipherState = {
|
||||||
|
init: false,
|
||||||
|
cipher: forge.aes.createEncryptionCipher(client ?
|
||||||
|
sp.keys.client_write_key : sp.keys.server_write_key),
|
||||||
|
iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV
|
||||||
|
};
|
||||||
|
state.read.cipherFunction = decrypt_aes_cbc_sha1;
|
||||||
|
state.write.cipherFunction = encrypt_aes_cbc_sha1;
|
||||||
|
|
||||||
|
// MAC setup
|
||||||
|
state.read.macLength = state.write.macLength = sp.mac_length;
|
||||||
|
state.read.macFunction = state.write.macFunction = tls.hmac_sha1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the TLSCompressed record into a TLSCipherText record using AES
|
||||||
|
* in CBC mode.
|
||||||
|
*
|
||||||
|
* @param record the TLSCompressed record to encrypt.
|
||||||
|
* @param s the ConnectionState to use.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function encrypt_aes_cbc_sha1(record, s) {
|
||||||
|
var rval = false;
|
||||||
|
|
||||||
|
// append MAC to fragment, update sequence number
|
||||||
|
var mac = s.macFunction(s.macKey, s.sequenceNumber, record);
|
||||||
|
record.fragment.putBytes(mac);
|
||||||
|
s.updateSequenceNumber();
|
||||||
|
|
||||||
|
// TLS 1.1 & 1.2 use an explicit IV every time to protect against
|
||||||
|
// CBC attacks
|
||||||
|
var iv;
|
||||||
|
if(record.version.minor > 1) {
|
||||||
|
iv = forge.random.getBytes(16);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// use the pre-generated IV when initializing for TLS 1.0, otherwise use
|
||||||
|
// the residue from the previous encryption
|
||||||
|
iv = s.cipherState.init ? null : s.cipherState.iv;
|
||||||
|
}
|
||||||
|
s.cipherState.init = true;
|
||||||
|
|
||||||
|
// start cipher
|
||||||
|
var cipher = s.cipherState.cipher;
|
||||||
|
cipher.start(iv);
|
||||||
|
|
||||||
|
// TLS 1.1 & 1.2 write IV into output
|
||||||
|
if(record.version.minor > 1) {
|
||||||
|
cipher.output.putBytes(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do encryption (default padding is appropriate)
|
||||||
|
cipher.update(record.fragment);
|
||||||
|
if(cipher.finish(encrypt_aes_cbc_sha1_padding)) {
|
||||||
|
// set record fragment to encrypted output
|
||||||
|
record.fragment = cipher.output;
|
||||||
|
record.length = record.fragment.length();
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles padding for aes_cbc_sha1 in encrypt mode.
|
||||||
|
*
|
||||||
|
* @param blockSize the block size.
|
||||||
|
* @param input the input buffer.
|
||||||
|
* @param decrypt true in decrypt mode, false in encrypt mode.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) {
|
||||||
|
/* The encrypted data length (TLSCiphertext.length) is one more than the sum
|
||||||
|
of SecurityParameters.block_length, TLSCompressed.length,
|
||||||
|
SecurityParameters.mac_length, and padding_length.
|
||||||
|
|
||||||
|
The padding may be any length up to 255 bytes long, as long as it results in
|
||||||
|
the TLSCiphertext.length being an integral multiple of the block length.
|
||||||
|
Lengths longer than necessary might be desirable to frustrate attacks on a
|
||||||
|
protocol based on analysis of the lengths of exchanged messages. Each uint8
|
||||||
|
in the padding data vector must be filled with the padding length value.
|
||||||
|
|
||||||
|
The padding length should be such that the total size of the
|
||||||
|
GenericBlockCipher structure is a multiple of the cipher's block length.
|
||||||
|
Legal values range from zero to 255, inclusive. This length specifies the
|
||||||
|
length of the padding field exclusive of the padding_length field itself.
|
||||||
|
|
||||||
|
This is slightly different from PKCS#7 because the padding value is 1
|
||||||
|
less than the actual number of padding bytes if you include the
|
||||||
|
padding_length uint8 itself as a padding byte. */
|
||||||
|
if(!decrypt) {
|
||||||
|
// get the number of padding bytes required to reach the blockSize and
|
||||||
|
// subtract 1 for the padding value (to make room for the padding_length
|
||||||
|
// uint8)
|
||||||
|
var padding = blockSize - (input.length() % blockSize);
|
||||||
|
input.fillWithByte(padding - 1, padding);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles padding for aes_cbc_sha1 in decrypt mode.
|
||||||
|
*
|
||||||
|
* @param blockSize the block size.
|
||||||
|
* @param output the output buffer.
|
||||||
|
* @param decrypt true in decrypt mode, false in encrypt mode.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) {
|
||||||
|
var rval = true;
|
||||||
|
if(decrypt) {
|
||||||
|
/* The last byte in the output specifies the number of padding bytes not
|
||||||
|
including itself. Each of the padding bytes has the same value as that
|
||||||
|
last byte (known as the padding_length). Here we check all padding
|
||||||
|
bytes to ensure they have the value of padding_length even if one of
|
||||||
|
them is bad in order to ward-off timing attacks. */
|
||||||
|
var len = output.length();
|
||||||
|
var paddingLength = output.last();
|
||||||
|
for(var i = len - 1 - paddingLength; i < len - 1; ++i) {
|
||||||
|
rval = rval && (output.at(i) == paddingLength);
|
||||||
|
}
|
||||||
|
if(rval) {
|
||||||
|
// trim off padding bytes and last padding length byte
|
||||||
|
output.truncate(paddingLength + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a TLSCipherText record into a TLSCompressed record using
|
||||||
|
* AES in CBC mode.
|
||||||
|
*
|
||||||
|
* @param record the TLSCipherText record to decrypt.
|
||||||
|
* @param s the ConnectionState to use.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function decrypt_aes_cbc_sha1(record, s) {
|
||||||
|
var rval = false;
|
||||||
|
|
||||||
|
// TODO: TLS 1.1 & 1.2 use an explicit IV every time to protect against
|
||||||
|
// CBC attacks
|
||||||
|
//var iv = record.fragment.getBytes(16);
|
||||||
|
|
||||||
|
// use pre-generated IV when initializing for TLS 1.0, otherwise use the
|
||||||
|
// residue from the previous decryption
|
||||||
|
var iv = s.cipherState.init ? null : s.cipherState.iv;
|
||||||
|
s.cipherState.init = true;
|
||||||
|
|
||||||
|
// start cipher
|
||||||
|
var cipher = s.cipherState.cipher;
|
||||||
|
cipher.start(iv);
|
||||||
|
|
||||||
|
// do decryption
|
||||||
|
cipher.update(record.fragment);
|
||||||
|
rval = cipher.finish(decrypt_aes_cbc_sha1_padding);
|
||||||
|
|
||||||
|
// even if decryption fails, keep going to minimize timing attacks
|
||||||
|
|
||||||
|
// decrypted data:
|
||||||
|
// first (len - 20) bytes = application data
|
||||||
|
// last 20 bytes = MAC
|
||||||
|
var macLen = s.macLength;
|
||||||
|
|
||||||
|
// create a zero'd out mac
|
||||||
|
var mac = '';
|
||||||
|
for(var i = 0; i < macLen; ++i) {
|
||||||
|
mac += String.fromCharCode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get fragment and mac
|
||||||
|
var len = cipher.output.length();
|
||||||
|
if(len >= macLen) {
|
||||||
|
record.fragment = cipher.output.getBytes(len - macLen);
|
||||||
|
mac = cipher.output.getBytes(macLen);
|
||||||
|
}
|
||||||
|
// bad data, but get bytes anyway to try to keep timing consistent
|
||||||
|
else {
|
||||||
|
record.fragment = cipher.output.getBytes();
|
||||||
|
}
|
||||||
|
record.fragment = forge.util.createBuffer(record.fragment);
|
||||||
|
record.length = record.fragment.length();
|
||||||
|
|
||||||
|
// see if data integrity checks out, update sequence number
|
||||||
|
var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record);
|
||||||
|
s.updateSequenceNumber();
|
||||||
|
rval = (mac2 === mac) && rval;
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'aesCipherSuites';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// <script>
|
||||||
|
else {
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './aes', './tls'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
104
src/lib/asn1.js
104
src/lib/asn1.js
@ -196,7 +196,7 @@ asn1.create = function(tagClass, type, constructed, value) {
|
|||||||
according to the ASN.1 data type. */
|
according to the ASN.1 data type. */
|
||||||
|
|
||||||
// remove undefined values
|
// remove undefined values
|
||||||
if(value.constructor == Array) {
|
if(forge.util.isArray(value)) {
|
||||||
var tmp = [];
|
var tmp = [];
|
||||||
for(var i = 0; i < value.length; ++i) {
|
for(var i = 0; i < value.length; ++i) {
|
||||||
if(value[i] !== undefined) {
|
if(value[i] !== undefined) {
|
||||||
@ -210,7 +210,7 @@ asn1.create = function(tagClass, type, constructed, value) {
|
|||||||
tagClass: tagClass,
|
tagClass: tagClass,
|
||||||
type: type,
|
type: type,
|
||||||
constructed: constructed,
|
constructed: constructed,
|
||||||
composed: constructed || (value.constructor == Array),
|
composed: constructed || forge.util.isArray(value),
|
||||||
value: value
|
value: value
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -226,7 +226,7 @@ asn1.create = function(tagClass, type, constructed, value) {
|
|||||||
*/
|
*/
|
||||||
var _getValueLength = function(b) {
|
var _getValueLength = function(b) {
|
||||||
var b2 = b.getByte();
|
var b2 = b.getByte();
|
||||||
if(b2 == 0x80) {
|
if(b2 === 0x80) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,12 +249,18 @@ var _getValueLength = function(b) {
|
|||||||
* Parses an asn1 object from a byte buffer in DER format.
|
* Parses an asn1 object from a byte buffer in DER format.
|
||||||
*
|
*
|
||||||
* @param bytes the byte buffer to parse from.
|
* @param bytes the byte buffer to parse from.
|
||||||
|
* @param strict true to be strict when checking value lengths, false to
|
||||||
|
* allow truncated values (default: true).
|
||||||
*
|
*
|
||||||
* @return the parsed asn1 object.
|
* @return the parsed asn1 object.
|
||||||
*/
|
*/
|
||||||
asn1.fromDer = function(bytes) {
|
asn1.fromDer = function(bytes, strict) {
|
||||||
|
if(strict === undefined) {
|
||||||
|
strict = true;
|
||||||
|
}
|
||||||
|
|
||||||
// wrap in buffer if needed
|
// wrap in buffer if needed
|
||||||
if(bytes.constructor == String) {
|
if(typeof bytes === 'string') {
|
||||||
bytes = forge.util.createBuffer(bytes);
|
bytes = forge.util.createBuffer(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,17 +286,21 @@ asn1.fromDer = function(bytes) {
|
|||||||
|
|
||||||
// ensure there are enough bytes to get the value
|
// ensure there are enough bytes to get the value
|
||||||
if(bytes.length() < length) {
|
if(bytes.length() < length) {
|
||||||
throw {
|
if(strict) {
|
||||||
message: 'Too few bytes to read ASN.1 value.',
|
throw {
|
||||||
detail: bytes.length() + ' < ' + length
|
message: 'Too few bytes to read ASN.1 value.',
|
||||||
};
|
detail: bytes.length() + ' < ' + length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Note: be lenient with truncated values
|
||||||
|
length = bytes.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare to get value
|
// prepare to get value
|
||||||
var value;
|
var value;
|
||||||
|
|
||||||
// constructed flag is bit 6 (32 = 0x20) of the first byte
|
// constructed flag is bit 6 (32 = 0x20) of the first byte
|
||||||
var constructed = ((b1 & 0x20) == 0x20);
|
var constructed = ((b1 & 0x20) === 0x20);
|
||||||
|
|
||||||
// determine if the value is composed of other ASN.1 objects (if its
|
// determine if the value is composed of other ASN.1 objects (if its
|
||||||
// constructed it will be and if its a BITSTRING it may be)
|
// constructed it will be and if its a BITSTRING it may be)
|
||||||
@ -311,8 +321,7 @@ asn1.fromDer = function(bytes) {
|
|||||||
// and the length is valid, assume we've got an ASN.1 object
|
// and the length is valid, assume we've got an ASN.1 object
|
||||||
b1 = bytes.getByte();
|
b1 = bytes.getByte();
|
||||||
var tc = (b1 & 0xC0);
|
var tc = (b1 & 0xC0);
|
||||||
if(tc === asn1.Class.UNIVERSAL ||
|
if(tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC) {
|
||||||
tc === asn1.Class.CONTEXT_SPECIFIC) {
|
|
||||||
try {
|
try {
|
||||||
var len = _getValueLength(bytes);
|
var len = _getValueLength(bytes);
|
||||||
composed = (len === length - (bytes.read - read));
|
composed = (len === length - (bytes.read - read));
|
||||||
@ -339,14 +348,14 @@ asn1.fromDer = function(bytes) {
|
|||||||
bytes.getBytes(2);
|
bytes.getBytes(2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
value.push(asn1.fromDer(bytes));
|
value.push(asn1.fromDer(bytes, strict));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// parsing asn1 object of definite length
|
// parsing asn1 object of definite length
|
||||||
var start = bytes.length();
|
var start = bytes.length();
|
||||||
while(length > 0) {
|
while(length > 0) {
|
||||||
value.push(asn1.fromDer(bytes));
|
value.push(asn1.fromDer(bytes, strict));
|
||||||
length -= start - bytes.length();
|
length -= start - bytes.length();
|
||||||
start = bytes.length();
|
start = bytes.length();
|
||||||
}
|
}
|
||||||
@ -520,7 +529,7 @@ asn1.derToOid = function(bytes) {
|
|||||||
var oid;
|
var oid;
|
||||||
|
|
||||||
// wrap in buffer if needed
|
// wrap in buffer if needed
|
||||||
if(bytes.constructor == String) {
|
if(typeof bytes === 'string') {
|
||||||
bytes = forge.util.createBuffer(bytes);
|
bytes = forge.util.createBuffer(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +687,7 @@ asn1.generalizedTimeToDate = function(gentime) {
|
|||||||
var offset = 0;
|
var offset = 0;
|
||||||
var isUTC = false;
|
var isUTC = false;
|
||||||
|
|
||||||
if(gentime.charAt(gentime.length - 1) == 'Z') {
|
if(gentime.charAt(gentime.length - 1) === 'Z') {
|
||||||
isUTC = true;
|
isUTC = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,7 +710,7 @@ asn1.generalizedTimeToDate = function(gentime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for second fraction
|
// check for second fraction
|
||||||
if(gentime.charAt(14) == '.') {
|
if(gentime.charAt(14) === '.') {
|
||||||
fff = parseFloat(gentime.substr(14), 10) * 1000;
|
fff = parseFloat(gentime.substr(14), 10) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +797,7 @@ asn1.validate = function(obj, v, capture, errors) {
|
|||||||
rval = true;
|
rval = true;
|
||||||
|
|
||||||
// handle sub values
|
// handle sub values
|
||||||
if(v.value && v.value.constructor == Array) {
|
if(v.value && forge.util.isArray(v.value)) {
|
||||||
var j = 0;
|
var j = 0;
|
||||||
for(var i = 0; rval && i < v.value.length; ++i) {
|
for(var i = 0; rval && i < v.value.length; ++i) {
|
||||||
rval = v.value[i].optional || false;
|
rval = v.value[i].optional || false;
|
||||||
@ -1012,12 +1021,11 @@ asn1.prettyPrint = function(obj, level, indentation) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'asn1';
|
var name = 'asn1';
|
||||||
var deps = ['./util', './oids'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1026,30 +1034,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util', './oids'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -87,12 +87,11 @@ forge.debug.clear = function(cat, name) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'debug';
|
var name = 'debug';
|
||||||
var deps = [];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -101,30 +100,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -39,8 +39,6 @@ var spfunction6 = [0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x204
|
|||||||
var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002];
|
var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002];
|
||||||
var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000];
|
var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create necessary sub keys.
|
* Create necessary sub keys.
|
||||||
*
|
*
|
||||||
@ -123,9 +121,6 @@ function des_createKeys (key) {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an DES cipher object.
|
* Creates an DES cipher object.
|
||||||
*
|
*
|
||||||
@ -134,9 +129,8 @@ function des_createKeys (key) {
|
|||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
var _createCipher = function(key, encrypt)
|
var _createCipher = function(key, encrypt) {
|
||||||
{
|
if(typeof key === 'string' && (key.length === 8 || key.length === 24)) {
|
||||||
if(key.constructor == String && (key.length == 8 || key.length == 24)) {
|
|
||||||
key = forge.util.createBuffer(key);
|
key = forge.util.createBuffer(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +149,10 @@ var _createCipher = function(key, encrypt)
|
|||||||
var _finish = false, _input = null, _output = null;
|
var _finish = false, _input = null, _output = null;
|
||||||
|
|
||||||
/* Set up the loops for single and triple DES. */
|
/* Set up the loops for single and triple DES. */
|
||||||
var iterations = keys.length == 32 ? 3 : 9; // single or triple des
|
var iterations = keys.length === 32 ? 3 : 9; // single or triple des
|
||||||
var looping;
|
var looping;
|
||||||
|
|
||||||
if(iterations == 3) {
|
if(iterations === 3) {
|
||||||
looping = encrypt
|
looping = encrypt
|
||||||
? [0, 32, 2]
|
? [0, 32, 2]
|
||||||
: [30, -2, -2];
|
: [30, -2, -2];
|
||||||
@ -183,7 +177,7 @@ var _createCipher = function(key, encrypt)
|
|||||||
*/
|
*/
|
||||||
start: function(iv, output) {
|
start: function(iv, output) {
|
||||||
if(iv) {
|
if(iv) {
|
||||||
if(key.constructor == String && iv.length == 8) {
|
if(typeof iv === 'string' && iv.length === 8) {
|
||||||
iv = forge.util.createBuffer(iv);
|
iv = forge.util.createBuffer(iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +215,7 @@ var _createCipher = function(key, encrypt)
|
|||||||
var right = _input.getInt32();
|
var right = _input.getInt32();
|
||||||
|
|
||||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||||
if(mode == 1) {
|
if(mode === 1) {
|
||||||
if(encrypt) {
|
if(encrypt) {
|
||||||
left ^= cbcleft;
|
left ^= cbcleft;
|
||||||
right ^= cbcright;
|
right ^= cbcright;
|
||||||
@ -275,7 +269,7 @@ var _createCipher = function(key, encrypt)
|
|||||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||||
|
|
||||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||||
if(mode == 1) {
|
if(mode === 1) {
|
||||||
if(encrypt) {
|
if(encrypt) {
|
||||||
cbcleft = left;
|
cbcleft = left;
|
||||||
cbcright = right;
|
cbcright = right;
|
||||||
@ -307,7 +301,7 @@ var _createCipher = function(key, encrypt)
|
|||||||
} else {
|
} else {
|
||||||
// add PKCS#7 padding to block (each pad byte is the
|
// add PKCS#7 padding to block (each pad byte is the
|
||||||
// value of the number of pad bytes)
|
// value of the number of pad bytes)
|
||||||
var padding = (_input.length() == 8) ? 8 : (8 - _input.length());
|
var padding = (_input.length() === 8) ? 8 : (8 - _input.length());
|
||||||
_input.fillWithByte(padding, padding);
|
_input.fillWithByte(padding, padding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,8 +356,7 @@ forge.des = forge.des || {};
|
|||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.des.startEncrypting = function(key, iv, output)
|
forge.des.startEncrypting = function(key, iv, output) {
|
||||||
{
|
|
||||||
var cipher = _createCipher(key, true);
|
var cipher = _createCipher(key, true);
|
||||||
cipher.start(iv, output);
|
cipher.start(iv, output);
|
||||||
return cipher;
|
return cipher;
|
||||||
@ -382,8 +375,7 @@ forge.des.startEncrypting = function(key, iv, output)
|
|||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.des.createEncryptionCipher = function(key)
|
forge.des.createEncryptionCipher = function(key) {
|
||||||
{
|
|
||||||
return _createCipher(key, true);
|
return _createCipher(key, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -400,8 +392,7 @@ forge.des.createEncryptionCipher = function(key)
|
|||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.des.startDecrypting = function(key, iv, output)
|
forge.des.startDecrypting = function(key, iv, output) {
|
||||||
{
|
|
||||||
var cipher = _createCipher(key, false);
|
var cipher = _createCipher(key, false);
|
||||||
cipher.start(iv, output);
|
cipher.start(iv, output);
|
||||||
return cipher;
|
return cipher;
|
||||||
@ -420,8 +411,7 @@ forge.des.startDecrypting = function(key, iv, output)
|
|||||||
*
|
*
|
||||||
* @return the cipher.
|
* @return the cipher.
|
||||||
*/
|
*/
|
||||||
forge.des.createDecryptionCipher = function(key)
|
forge.des.createDecryptionCipher = function(key) {
|
||||||
{
|
|
||||||
return _createCipher(key, false);
|
return _createCipher(key, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -429,12 +419,11 @@ forge.des.createDecryptionCipher = function(key)
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'des';
|
var name = 'des';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -443,30 +432,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -6,15 +6,71 @@
|
|||||||
* Copyright 2011-2013 Digital Bazaar, Inc.
|
* Copyright 2011-2013 Digital Bazaar, Inc.
|
||||||
*/
|
*/
|
||||||
(function() {
|
(function() {
|
||||||
var deps = [
|
var name = 'forge';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// <script>
|
||||||
|
else {
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
// set to true to disable native code if even it's available
|
||||||
|
forge = {disableNativeCode: false};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
});
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge;
|
||||||
|
};
|
||||||
|
// set to true to disable native code if even it's available
|
||||||
|
module.exports.disableNativeCode = false;
|
||||||
|
module.exports(module.exports);
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
'./aes',
|
'./aes',
|
||||||
|
'./aesCipherSuites',
|
||||||
'./asn1',
|
'./asn1',
|
||||||
'./debug',
|
'./debug',
|
||||||
'./des',
|
'./des',
|
||||||
'./hmac',
|
'./hmac',
|
||||||
'./log',
|
'./log',
|
||||||
'./pbkdf2',
|
'./pbkdf2',
|
||||||
|
'./pem',
|
||||||
'./pkcs7',
|
'./pkcs7',
|
||||||
|
'./pkcs1',
|
||||||
'./pkcs12',
|
'./pkcs12',
|
||||||
'./pki',
|
'./pki',
|
||||||
'./prng',
|
'./prng',
|
||||||
@ -26,35 +82,7 @@ var deps = [
|
|||||||
'./util',
|
'./util',
|
||||||
'./md',
|
'./md',
|
||||||
'./mgf1'
|
'./mgf1'
|
||||||
];
|
], function() {
|
||||||
var cjsDefine = null;
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
if(typeof define !== 'function') {
|
});
|
||||||
// CommonJS -> AMD
|
|
||||||
if(typeof module === 'object' && module.exports) {
|
|
||||||
cjsDefine = function(ids, factory) {
|
|
||||||
module.exports = factory.apply(null, ids.map(function(id) {
|
|
||||||
return require(id);
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// <script>
|
|
||||||
else {
|
|
||||||
if(typeof forge === 'undefined') {
|
|
||||||
forge = {};
|
|
||||||
}
|
|
||||||
initModule(forge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// AMD
|
|
||||||
if(cjsDefine || typeof define === 'function') {
|
|
||||||
// define module AMD style
|
|
||||||
(cjsDefine || define)(deps, function() {
|
|
||||||
var forge = {};
|
|
||||||
var mods = Array.prototype.slice.call(arguments);
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
@ -45,7 +45,7 @@ hmac.create = function() {
|
|||||||
*/
|
*/
|
||||||
ctx.start = function(md, key) {
|
ctx.start = function(md, key) {
|
||||||
if(md !== null) {
|
if(md !== null) {
|
||||||
if(md.constructor == String) {
|
if(typeof md === 'string') {
|
||||||
// create builtin message digest
|
// create builtin message digest
|
||||||
md = md.toLowerCase();
|
md = md.toLowerCase();
|
||||||
if(md in forge.md.algorithms) {
|
if(md in forge.md.algorithms) {
|
||||||
@ -67,11 +67,11 @@ hmac.create = function() {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// convert string into byte buffer
|
// convert string into byte buffer
|
||||||
if(key.constructor == String) {
|
if(typeof key === 'string') {
|
||||||
key = forge.util.createBuffer(key);
|
key = forge.util.createBuffer(key);
|
||||||
}
|
}
|
||||||
// convert byte array into byte buffer
|
// convert byte array into byte buffer
|
||||||
else if(key.constructor == Array) {
|
else if(forge.util.isArray(key)) {
|
||||||
var tmp = key;
|
var tmp = key;
|
||||||
key = forge.util.createBuffer();
|
key = forge.util.createBuffer();
|
||||||
for(var i = 0; i < tmp.length; ++i) {
|
for(var i = 0; i < tmp.length; ++i) {
|
||||||
@ -153,12 +153,11 @@ hmac.create = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'hmac';
|
var name = 'hmac';
|
||||||
var deps = ['./md', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -167,30 +166,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -901,6 +901,9 @@ http.createRequest = function(options) {
|
|||||||
|
|
||||||
// add custom headers
|
// add custom headers
|
||||||
var headers = options.headers || [];
|
var headers = options.headers || [];
|
||||||
|
if(!forge.util.isArray(headers)) {
|
||||||
|
headers = [headers];
|
||||||
|
}
|
||||||
for(var i = 0; i < headers.length; ++i) {
|
for(var i = 0; i < headers.length; ++i) {
|
||||||
for(var name in headers[i]) {
|
for(var name in headers[i]) {
|
||||||
request.appendField(name, headers[i][name]);
|
request.appendField(name, headers[i][name]);
|
||||||
@ -1202,7 +1205,7 @@ http.createResponse = function() {
|
|||||||
if(contentLength !== null && contentLength >= 0) {
|
if(contentLength !== null && contentLength >= 0) {
|
||||||
response.body = response.body || '';
|
response.body = response.body || '';
|
||||||
response.body += b.getBytes(contentLength);
|
response.body += b.getBytes(contentLength);
|
||||||
response.bodyReceived = (response.body.length == contentLength);
|
response.bodyReceived = (response.body.length === contentLength);
|
||||||
}
|
}
|
||||||
// read chunked encoding
|
// read chunked encoding
|
||||||
else if(transferEncoding !== null) {
|
else if(transferEncoding !== null) {
|
||||||
@ -1372,7 +1375,7 @@ http.withinCookieDomain = function(url, cookie) {
|
|||||||
var rval = false;
|
var rval = false;
|
||||||
|
|
||||||
// cookie may be null, a cookie object, or a domain string
|
// cookie may be null, a cookie object, or a domain string
|
||||||
var domain = (cookie === null || cookie.constructor == String) ?
|
var domain = (cookie === null || typeof cookie === 'string') ?
|
||||||
cookie : cookie.domain;
|
cookie : cookie.domain;
|
||||||
|
|
||||||
// any domain will do
|
// any domain will do
|
||||||
@ -1382,7 +1385,7 @@ http.withinCookieDomain = function(url, cookie) {
|
|||||||
// ensure domain starts with a '.'
|
// ensure domain starts with a '.'
|
||||||
else if(domain.charAt(0) === '.') {
|
else if(domain.charAt(0) === '.') {
|
||||||
// parse URL as necessary
|
// parse URL as necessary
|
||||||
if(url.constructor == String) {
|
if(typeof url === 'string') {
|
||||||
url = http.parseUrl(url);
|
url = http.parseUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ function bnCompareTo(a) {
|
|||||||
if(r != 0) return r;
|
if(r != 0) return r;
|
||||||
var i = this.t;
|
var i = this.t;
|
||||||
r = i-a.t;
|
r = i-a.t;
|
||||||
if(r != 0) return r;
|
if(r != 0) return (this.s<0)?-r:r;
|
||||||
while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r;
|
while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1271,12 +1271,11 @@ forge.jsbn.BigInteger = BigInteger;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'jsbn';
|
var name = 'jsbn';
|
||||||
var deps = [];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1285,30 +1284,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -325,12 +325,11 @@ forge.log.consoleLogger = sConsoleLogger;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'log';
|
var name = 'log';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -339,30 +338,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -23,12 +23,11 @@ forge.md.sha256 = forge.sha256;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'md';
|
var name = 'md';
|
||||||
var deps = ['./md5', './sha1', './sha256'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -37,30 +36,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './md5', './sha1', './sha256'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -157,6 +157,8 @@ md5.create = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the digest.
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.start = function() {
|
md.start = function() {
|
||||||
md.messageLength = 0;
|
md.messageLength = 0;
|
||||||
@ -167,6 +169,7 @@ md5.create = function() {
|
|||||||
h2: 0x98BADCFE,
|
h2: 0x98BADCFE,
|
||||||
h3: 0x10325476
|
h3: 0x10325476
|
||||||
};
|
};
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
// start digest automatically for first time
|
// start digest automatically for first time
|
||||||
md.start();
|
md.start();
|
||||||
@ -178,6 +181,8 @@ md5.create = function() {
|
|||||||
*
|
*
|
||||||
* @param msg the message input to update with.
|
* @param msg the message input to update with.
|
||||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.update = function(msg, encoding) {
|
md.update = function(msg, encoding) {
|
||||||
if(encoding === 'utf8') {
|
if(encoding === 'utf8') {
|
||||||
@ -197,6 +202,8 @@ md5.create = function() {
|
|||||||
if(_input.read > 2048 || _input.length() === 0) {
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
_input.compact();
|
_input.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,12 +267,11 @@ md5.create = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'md5';
|
var name = 'md5';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -274,30 +280,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -16,12 +16,11 @@ forge.mgf.mgf1 = forge.mgf1;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'mgf';
|
var name = 'mgf';
|
||||||
var deps = ['./mgf1'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -30,30 +29,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './mgf1'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -57,12 +57,11 @@ mgf1.create = function(md) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'mgf1';
|
var name = 'mgf1';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -71,30 +70,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
115
src/lib/oids.js
115
src/lib/oids.js
@ -16,14 +16,14 @@ var oids = forge.pki.oids = forge.oids = forge.oids || {};
|
|||||||
oids['1.2.840.113549.1.1.1'] = 'rsaEncryption';
|
oids['1.2.840.113549.1.1.1'] = 'rsaEncryption';
|
||||||
oids['rsaEncryption'] = '1.2.840.113549.1.1.1';
|
oids['rsaEncryption'] = '1.2.840.113549.1.1.1';
|
||||||
// Note: md2 & md4 not implemented
|
// Note: md2 & md4 not implemented
|
||||||
//oids['1.2.840.113549.1.1.2'] = 'md2withRSAEncryption';
|
//oids['1.2.840.113549.1.1.2'] = 'md2WithRSAEncryption';
|
||||||
//oids['md2withRSAEncryption'] = '1.2.840.113549.1.1.2';
|
//oids['md2WithRSAEncryption'] = '1.2.840.113549.1.1.2';
|
||||||
//oids['1.2.840.113549.1.1.3'] = 'md4withRSAEncryption';
|
//oids['1.2.840.113549.1.1.3'] = 'md4WithRSAEncryption';
|
||||||
//oids['md4withRSAEncryption'] = '1.2.840.113549.1.1.3';
|
//oids['md4WithRSAEncryption'] = '1.2.840.113549.1.1.3';
|
||||||
oids['1.2.840.113549.1.1.4'] = 'md5withRSAEncryption';
|
oids['1.2.840.113549.1.1.4'] = 'md5WithRSAEncryption';
|
||||||
oids['md5withRSAEncryption'] = '1.2.840.113549.1.1.4';
|
oids['md5WithRSAEncryption'] = '1.2.840.113549.1.1.4';
|
||||||
oids['1.2.840.113549.1.1.5'] = 'sha1withRSAEncryption';
|
oids['1.2.840.113549.1.1.5'] = 'sha1WithRSAEncryption';
|
||||||
oids['sha1withRSAEncryption'] = '1.2.840.113549.1.1.5';
|
oids['sha1WithRSAEncryption'] = '1.2.840.113549.1.1.5';
|
||||||
oids['1.2.840.113549.1.1.7'] = 'RSAES-OAEP';
|
oids['1.2.840.113549.1.1.7'] = 'RSAES-OAEP';
|
||||||
oids['RSAES-OAEP'] = '1.2.840.113549.1.1.7';
|
oids['RSAES-OAEP'] = '1.2.840.113549.1.1.7';
|
||||||
oids['1.2.840.113549.1.1.8'] = 'mgf1';
|
oids['1.2.840.113549.1.1.8'] = 'mgf1';
|
||||||
@ -65,6 +65,23 @@ oids['1.2.840.113549.1.7.6'] = 'encryptedData';
|
|||||||
oids['encryptedData'] = '1.2.840.113549.1.7.6';
|
oids['encryptedData'] = '1.2.840.113549.1.7.6';
|
||||||
|
|
||||||
// pkcs#9 oids
|
// pkcs#9 oids
|
||||||
|
oids['1.2.840.113549.1.9.1'] = 'emailAddress';
|
||||||
|
oids['emailAddress'] = '1.2.840.113549.1.9.1';
|
||||||
|
oids['1.2.840.113549.1.9.2'] = 'unstructuredName';
|
||||||
|
oids['unstructuredName'] = '1.2.840.113549.1.9.2';
|
||||||
|
oids['1.2.840.113549.1.9.3'] = 'contentType';
|
||||||
|
oids['contentType'] = '1.2.840.113549.1.9.3';
|
||||||
|
oids['1.2.840.113549.1.9.4'] = 'messageDigest';
|
||||||
|
oids['messageDigest'] = '1.2.840.113549.1.9.4';
|
||||||
|
oids['1.2.840.113549.1.9.5'] = 'signingTime';
|
||||||
|
oids['signingTime'] = '1.2.840.113549.1.9.5';
|
||||||
|
oids['1.2.840.113549.1.9.6'] = 'counterSignature';
|
||||||
|
oids['counterSignature'] = '1.2.840.113549.1.9.6';
|
||||||
|
oids['1.2.840.113549.1.9.7'] = 'challengePassword';
|
||||||
|
oids['challengePassword'] = '1.2.840.113549.1.9.7';
|
||||||
|
oids['1.2.840.113549.1.9.8'] = 'unstructuredAddress';
|
||||||
|
oids['unstructuredAddress'] = '1.2.840.113549.1.9.8';
|
||||||
|
|
||||||
oids['1.2.840.113549.1.9.20'] = 'friendlyName';
|
oids['1.2.840.113549.1.9.20'] = 'friendlyName';
|
||||||
oids['friendlyName'] = '1.2.840.113549.1.9.20';
|
oids['friendlyName'] = '1.2.840.113549.1.9.20';
|
||||||
oids['1.2.840.113549.1.9.21'] = 'localKeyId';
|
oids['1.2.840.113549.1.9.21'] = 'localKeyId';
|
||||||
@ -72,13 +89,6 @@ oids['localKeyId'] = '1.2.840.113549.1.9.21';
|
|||||||
oids['1.2.840.113549.1.9.22.1'] = 'x509Certificate';
|
oids['1.2.840.113549.1.9.22.1'] = 'x509Certificate';
|
||||||
oids['x509Certificate'] = '1.2.840.113549.1.9.22.1';
|
oids['x509Certificate'] = '1.2.840.113549.1.9.22.1';
|
||||||
|
|
||||||
oids['1.2.840.113549.1.9.4'] = 'messageDigest';
|
|
||||||
oids['messageDigest'] = '1.2.840.113549.1.9.4';
|
|
||||||
oids['1.2.840.113549.1.9.3'] = 'contentType';
|
|
||||||
oids['contentType'] = '1.2.840.113549.1.9.3';
|
|
||||||
oids['1.2.840.113549.1.9.5'] = 'signingTime';
|
|
||||||
oids['signingTime'] = '1.2.840.113549.1.9.5';
|
|
||||||
|
|
||||||
// pkcs#12 safe bags
|
// pkcs#12 safe bags
|
||||||
oids['1.2.840.113549.1.12.10.1.1'] = 'keyBag';
|
oids['1.2.840.113549.1.12.10.1.1'] = 'keyBag';
|
||||||
oids['keyBag'] = '1.2.840.113549.1.12.10.1.1';
|
oids['keyBag'] = '1.2.840.113549.1.12.10.1.1';
|
||||||
@ -137,10 +147,10 @@ oids['2.5.4.10'] = 'organizationName';
|
|||||||
oids['organizationName'] = '2.5.4.10';
|
oids['organizationName'] = '2.5.4.10';
|
||||||
oids['2.5.4.11'] = 'organizationalUnitName';
|
oids['2.5.4.11'] = 'organizationalUnitName';
|
||||||
oids['organizationalUnitName'] = '2.5.4.11';
|
oids['organizationalUnitName'] = '2.5.4.11';
|
||||||
oids['1.2.840.113549.1.9.1'] = 'emailAddress';
|
|
||||||
oids['emailAddress'] = '1.2.840.113549.1.9.1';
|
|
||||||
|
|
||||||
// X.509 extension OIDs
|
// X.509 extension OIDs
|
||||||
|
oids['2.16.840.1.113730.1.1'] = 'nsCertType';
|
||||||
|
oids['nsCertType'] = '2.16.840.1.113730.1.1';
|
||||||
oids['2.5.29.1'] = 'authorityKeyIdentifier'; // deprecated, use .35
|
oids['2.5.29.1'] = 'authorityKeyIdentifier'; // deprecated, use .35
|
||||||
oids['2.5.29.2'] = 'keyAttributes'; // obsolete use .37 or .15
|
oids['2.5.29.2'] = 'keyAttributes'; // obsolete use .37 or .15
|
||||||
oids['2.5.29.3'] = 'certificatePolicies'; // deprecated, use .32
|
oids['2.5.29.3'] = 'certificatePolicies'; // deprecated, use .32
|
||||||
@ -187,16 +197,27 @@ oids['extKeyUsage'] = '2.5.29.37';
|
|||||||
oids['2.5.29.46'] = 'freshestCRL';
|
oids['2.5.29.46'] = 'freshestCRL';
|
||||||
oids['2.5.29.54'] = 'inhibitAnyPolicy';
|
oids['2.5.29.54'] = 'inhibitAnyPolicy';
|
||||||
|
|
||||||
|
// extKeyUsage purposes
|
||||||
|
oids['1.3.6.1.5.5.7.3.1'] = 'serverAuth';
|
||||||
|
oids['serverAuth'] = '1.3.6.1.5.5.7.3.1';
|
||||||
|
oids['1.3.6.1.5.5.7.3.2'] = 'clientAuth';
|
||||||
|
oids['clientAuth'] = '1.3.6.1.5.5.7.3.2';
|
||||||
|
oids['1.3.6.1.5.5.7.3.3'] = 'codeSigning';
|
||||||
|
oids['codeSigning'] = '1.3.6.1.5.5.7.3.3';
|
||||||
|
oids['1.3.6.1.5.5.7.3.4'] = 'emailProtection';
|
||||||
|
oids['emailProtection'] = '1.3.6.1.5.5.7.3.4';
|
||||||
|
oids['1.3.6.1.5.5.7.3.8'] = 'timeStamping';
|
||||||
|
oids['timeStamping'] = '1.3.6.1.5.5.7.3.8';
|
||||||
|
|
||||||
} // end module implementation
|
} // end module implementation
|
||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'oids';
|
var name = 'oids';
|
||||||
var deps = [];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -205,30 +226,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -25,7 +25,7 @@ var pkcs5 = forge.pkcs5 = forge.pkcs5 || {};
|
|||||||
*
|
*
|
||||||
* @return the derived key, as a string of bytes.
|
* @return the derived key, as a string of bytes.
|
||||||
*/
|
*/
|
||||||
pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
forge.pbkdf2 = pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
||||||
// default prf to SHA-1
|
// default prf to SHA-1
|
||||||
if(typeof(md) === 'undefined' || md === null) {
|
if(typeof(md) === 'undefined' || md === null) {
|
||||||
md = forge.md.sha1.create();
|
md = forge.md.sha1.create();
|
||||||
@ -110,12 +110,11 @@ pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'pbkdf2';
|
var name = 'pbkdf2';
|
||||||
var deps = ['./hmac', './md', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -124,30 +123,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './hmac', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
301
src/lib/pem.js
Normal file
301
src/lib/pem.js
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms.
|
||||||
|
*
|
||||||
|
* See: RFC 1421.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Digital Bazaar, Inc.
|
||||||
|
*
|
||||||
|
* A Forge PEM object has the following fields:
|
||||||
|
*
|
||||||
|
* type: identifies the type of message (eg: "RSA PRIVATE KEY").
|
||||||
|
*
|
||||||
|
* procType: identifies the type of processing performed on the message,
|
||||||
|
* it has two subfields: version and type, eg: 4,ENCRYPTED.
|
||||||
|
*
|
||||||
|
* contentDomain: identifies the type of content in the message, typically
|
||||||
|
* only uses the value: "RFC822".
|
||||||
|
*
|
||||||
|
* dekInfo: identifies the message encryption algorithm and mode and includes
|
||||||
|
* any parameters for the algorithm, it has two subfields: algorithm and
|
||||||
|
* parameters, eg: DES-CBC,F8143EDE5960C597.
|
||||||
|
*
|
||||||
|
* headers: contains all other PEM encapsulated headers -- where order is
|
||||||
|
* significant (for pairing data like recipient ID + key info).
|
||||||
|
*
|
||||||
|
* body: the binary-encoded body.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for pem API
|
||||||
|
var pem = forge.pem = forge.pem || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes (serializes) the given PEM object.
|
||||||
|
*
|
||||||
|
* @param msg the PEM message object to encode.
|
||||||
|
* @param options the options to use:
|
||||||
|
* maxline the maximum characters per line for the body, (default: 64).
|
||||||
|
*
|
||||||
|
* @return the PEM-formatted string.
|
||||||
|
*/
|
||||||
|
pem.encode = function(msg, options) {
|
||||||
|
options = options || {};
|
||||||
|
var rval = '-----BEGIN ' + msg.type + '-----\r\n';
|
||||||
|
|
||||||
|
// encode special headers
|
||||||
|
var header;
|
||||||
|
if(msg.procType) {
|
||||||
|
header = {
|
||||||
|
name: 'Proc-Type',
|
||||||
|
values: [String(msg.procType.version), msg.procType.type]
|
||||||
|
};
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
if(msg.contentDomain) {
|
||||||
|
header = {name: 'Content-Domain', values: [msg.contentDomain]};
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
if(msg.dekInfo) {
|
||||||
|
header = {name: 'DEK-Info', values: [msg.dekInfo.algorithm]};
|
||||||
|
if(msg.dekInfo.parameters) {
|
||||||
|
header.values.push(msg.dekInfo.parameters);
|
||||||
|
}
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.headers) {
|
||||||
|
// encode all other headers
|
||||||
|
for(var i = 0; i < msg.headers.length; ++i) {
|
||||||
|
rval += foldHeader(msg.headers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate header
|
||||||
|
if(msg.procType) {
|
||||||
|
rval += '\r\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add body
|
||||||
|
rval += forge.util.encode64(msg.body, options.maxline || 64) + '\r\n';
|
||||||
|
|
||||||
|
rval += '-----END ' + msg.type + '-----\r\n';
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes (deserializes) all PEM messages found in the given string.
|
||||||
|
*
|
||||||
|
* @param str the PEM-formatted string to decode.
|
||||||
|
*
|
||||||
|
* @return the PEM message objects in an array.
|
||||||
|
*/
|
||||||
|
pem.decode = function(str) {
|
||||||
|
var rval = [];
|
||||||
|
|
||||||
|
// split string into PEM messages
|
||||||
|
var rMessage = /\s*-----BEGIN ([A-Z0-9- ]+)-----\r?\n([\x21-\x7e\s]+?(?:\r?\n\r?\n))?([:A-Za-z0-9+\/=\s]+?)-----END \1-----/g;
|
||||||
|
var rHeader = /([\x21-\x7e]+):\s*([\x21-\x7e\s^:]+)/;
|
||||||
|
var rCRLF = /\r?\n/;
|
||||||
|
var match;
|
||||||
|
while(true) {
|
||||||
|
match = rMessage.exec(str);
|
||||||
|
if(!match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
type: match[1],
|
||||||
|
procType: null,
|
||||||
|
contentDomain: null,
|
||||||
|
dekInfo: null,
|
||||||
|
headers: [],
|
||||||
|
body: forge.util.decode64(match[3])
|
||||||
|
};
|
||||||
|
rval.push(msg);
|
||||||
|
|
||||||
|
// no headers
|
||||||
|
if(!match[2]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse headers
|
||||||
|
var lines = match[2].split(rCRLF);
|
||||||
|
var li = 0;
|
||||||
|
while(match && li < lines.length) {
|
||||||
|
// get line, trim any rhs whitespace
|
||||||
|
var line = lines[li].replace(/\s+$/, '');
|
||||||
|
|
||||||
|
// RFC2822 unfold any following folded lines
|
||||||
|
for(var nl = li + 1; nl < lines.length; ++nl) {
|
||||||
|
var next = lines[nl];
|
||||||
|
if(!/\s/.test(next[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line += next;
|
||||||
|
li = nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse header
|
||||||
|
match = line.match(rHeader);
|
||||||
|
if(match) {
|
||||||
|
var header = {name: match[1], values: []};
|
||||||
|
var values = match[2].split(',');
|
||||||
|
for(var vi = 0; vi < values.length; ++vi) {
|
||||||
|
header.values.push(ltrim(values[vi]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proc-Type must be the first header
|
||||||
|
if(!msg.procType) {
|
||||||
|
if(header.name !== 'Proc-Type') {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid PEM formatted message. The first ' +
|
||||||
|
'encapsulated header must be "Proc-Type".'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(header.values.length !== 2) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid PEM formatted message. The "Proc-Type" ' +
|
||||||
|
'header must have two subfields.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
msg.procType = {version: values[0], type: values[1]};
|
||||||
|
}
|
||||||
|
// special-case Content-Domain
|
||||||
|
else if(!msg.contentDomain && header.name === 'Content-Domain') {
|
||||||
|
msg.contentDomain = values[0] || '';
|
||||||
|
}
|
||||||
|
// special-case DEK-Info
|
||||||
|
else if(!msg.dekInfo && header.name === 'DEK-Info') {
|
||||||
|
if(header.values.length === 0) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid PEM formatted message. The "DEK-Info" ' +
|
||||||
|
'header must have at least one subfield.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
msg.dekInfo = {algorithm: values[0], parameters: values[1] || null};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg.headers.push(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++li;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.procType === 'ENCRYPTED' && !msg.dekInfo) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid PEM formatted message. The "DEK-Info" ' +
|
||||||
|
'header must be present if "Proc-Type" is "ENCRYPTED".'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rval.length === 0) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid PEM formatted message.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
function foldHeader(header) {
|
||||||
|
var rval = header.name + ': ';
|
||||||
|
|
||||||
|
// ensure values with CRLF are folded
|
||||||
|
var values = [];
|
||||||
|
for(var i = 0; i < header.values.length; ++i) {
|
||||||
|
values.push(header.values[i].replace(/^(\S+\r\n)/, function(match, $1) {
|
||||||
|
return ' ' + $1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
rval += values.join(',') + '\r\n';
|
||||||
|
|
||||||
|
// do folding
|
||||||
|
var length = 0;
|
||||||
|
var candidate = -1;
|
||||||
|
for(var i = 0; i < rval.length; ++i, ++length) {
|
||||||
|
if(length > 65 && candidate !== -1) {
|
||||||
|
var insert = rval[candidate];
|
||||||
|
if(insert === ',') {
|
||||||
|
++candidate;
|
||||||
|
rval = rval.substr(0, candidate) + '\r\n ' + rval.substr(candidate);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rval = rval.substr(0, candidate) +
|
||||||
|
'\r\n' + insert + rval.substr(candidate + 1);
|
||||||
|
}
|
||||||
|
length = (i - candidate - 1);
|
||||||
|
candidate = -1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else if(rval[i] === ' ' || rval[i] === '\t' || rval[i] === ',') {
|
||||||
|
candidate = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ltrim(str) {
|
||||||
|
return str.replace(/^\s+/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pem';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// <script>
|
||||||
|
else {
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
315
src/lib/pkcs1.js
Normal file
315
src/lib/pkcs1.js
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/**
|
||||||
|
* Partial implementation of PKCS#1 v2.2: RSA-OEAP
|
||||||
|
*
|
||||||
|
* Modified but based on the following MIT and BSD licensed code:
|
||||||
|
*
|
||||||
|
* https://github.com/kjur/jsjws/blob/master/rsa.js:
|
||||||
|
*
|
||||||
|
* The 'jsjws'(JSON Web Signature JavaScript Library) License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Kenji Urushima
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain:
|
||||||
|
*
|
||||||
|
* RSAES-OAEP.js
|
||||||
|
* $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $
|
||||||
|
* JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002)
|
||||||
|
* Copyright (C) Ellis Pritchard, Guardian Unlimited 2003.
|
||||||
|
* Contact: ellis@nukinetics.com
|
||||||
|
* Distributed under the BSD License.
|
||||||
|
*
|
||||||
|
* Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125
|
||||||
|
*
|
||||||
|
* @author Evan Jones (http://evanjones.ca/)
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for PKCS#1 API
|
||||||
|
var pkcs1 = forge.pkcs1 = forge.pkcs1 || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the given RSAES-OAEP message (M) using key, with optional label (L)
|
||||||
|
* and seed.
|
||||||
|
*
|
||||||
|
* This method does not perform RSA encryption, it only encodes the message
|
||||||
|
* using RSAES-OAEP.
|
||||||
|
*
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param message the message to encode.
|
||||||
|
* @param options the options to use:
|
||||||
|
* label an optional label to use.
|
||||||
|
* seed the seed to use.
|
||||||
|
* md the message digest object to use, undefined for SHA-1.
|
||||||
|
*
|
||||||
|
* @return the encoded message bytes.
|
||||||
|
*/
|
||||||
|
pkcs1.encode_rsa_oaep = function(key, message, options) {
|
||||||
|
// parse arguments
|
||||||
|
var label = undefined;
|
||||||
|
var seed = undefined;
|
||||||
|
var md = undefined;
|
||||||
|
// legacy args (label, seed, md)
|
||||||
|
if(typeof options === 'string') {
|
||||||
|
label = options;
|
||||||
|
seed = arguments[3] || undefined;
|
||||||
|
md = arguments[4] || undefined;
|
||||||
|
}
|
||||||
|
else if(options) {
|
||||||
|
label = options.label || undefined;
|
||||||
|
seed = options.seed || undefined;
|
||||||
|
md = options.md || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to SHA-1 message digest
|
||||||
|
if(!md) {
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
md.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute length in bytes and check output
|
||||||
|
var keyLength = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
var maxLength = keyLength - 2 * md.digestLength - 2;
|
||||||
|
if(message.length > maxLength) {
|
||||||
|
throw {
|
||||||
|
message: 'RSAES-OAEP input message length is too long.',
|
||||||
|
length: message.length,
|
||||||
|
maxLength: maxLength
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!label) {
|
||||||
|
label = '';
|
||||||
|
}
|
||||||
|
md.update(label, 'raw');
|
||||||
|
var lHash = md.digest();
|
||||||
|
|
||||||
|
var PS = '';
|
||||||
|
var PS_length = maxLength - message.length;
|
||||||
|
for (var i = 0; i < PS_length; i++) {
|
||||||
|
PS += '\x00';
|
||||||
|
}
|
||||||
|
|
||||||
|
var DB = lHash.getBytes() + PS + '\x01' + message;
|
||||||
|
|
||||||
|
if(!seed) {
|
||||||
|
seed = forge.random.getBytes(md.digestLength);
|
||||||
|
}
|
||||||
|
else if(seed.length !== md.digestLength) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid RSAES-OAEP seed. The seed length must match the ' +
|
||||||
|
'digest length.',
|
||||||
|
seedLength: seed.length,
|
||||||
|
digestLength: md.digestLength
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, md);
|
||||||
|
var maskedDB = forge.util.xorBytes(DB, dbMask, DB.length);
|
||||||
|
|
||||||
|
var seedMask = rsa_mgf1(maskedDB, md.digestLength, md);
|
||||||
|
var maskedSeed = forge.util.xorBytes(seed, seedMask, seed.length);
|
||||||
|
|
||||||
|
// return encoded message
|
||||||
|
return '\x00' + maskedSeed + maskedDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the given RSAES-OAEP encoded message (EM) using key, with optional
|
||||||
|
* label (L).
|
||||||
|
*
|
||||||
|
* This method does not perform RSA decryption, it only decodes the message
|
||||||
|
* using RSAES-OAEP.
|
||||||
|
*
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param em the encoded message to decode.
|
||||||
|
* @param label an optional label to use.
|
||||||
|
* @param md the message digest object to use, undefined for SHA-1.
|
||||||
|
*
|
||||||
|
* @return the decoded message bytes.
|
||||||
|
*/
|
||||||
|
pkcs1.decode_rsa_oaep = function(key, em, options) {
|
||||||
|
// parse args
|
||||||
|
var label = undefined;
|
||||||
|
var md = undefined;
|
||||||
|
// legacy args
|
||||||
|
if(typeof options === 'string') {
|
||||||
|
label = options;
|
||||||
|
md = arguments[3] || undefined;
|
||||||
|
}
|
||||||
|
else if(options) {
|
||||||
|
label = options.label || undefined;
|
||||||
|
md = options.md || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute length in bytes
|
||||||
|
var keyLength = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
|
if(em.length !== keyLength) {
|
||||||
|
throw {
|
||||||
|
message: 'RSAES-OAEP encoded message length is invalid.',
|
||||||
|
length: em.length,
|
||||||
|
expectedLength: keyLength
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to SHA-1 message digest
|
||||||
|
if(md === undefined) {
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
md.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keyLength < 2 * md.digestLength + 2) {
|
||||||
|
throw {
|
||||||
|
message: 'RSAES-OAEP key is too short for the hash function.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!label) {
|
||||||
|
label = '';
|
||||||
|
}
|
||||||
|
md.update(label, 'raw');
|
||||||
|
var lHash = md.digest().getBytes();
|
||||||
|
|
||||||
|
// split the message into its parts
|
||||||
|
var y = em.charAt(0);
|
||||||
|
var maskedSeed = em.substring(1, md.digestLength + 1);
|
||||||
|
var maskedDB = em.substring(1 + md.digestLength);
|
||||||
|
|
||||||
|
var seedMask = rsa_mgf1(maskedDB, md.digestLength, md);
|
||||||
|
var seed = forge.util.xorBytes(maskedSeed, seedMask, maskedSeed.length);
|
||||||
|
|
||||||
|
var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, md);
|
||||||
|
var db = forge.util.xorBytes(maskedDB, dbMask, maskedDB.length);
|
||||||
|
|
||||||
|
var lHashPrime = db.substring(0, md.digestLength);
|
||||||
|
|
||||||
|
// constant time check that all values match what is expected
|
||||||
|
var error = (y !== '\x00');
|
||||||
|
|
||||||
|
// constant time check lHash vs lHashPrime
|
||||||
|
for(var i = 0; i < md.digestLength; ++i) {
|
||||||
|
error |= (lHash.charAt(i) !== lHashPrime.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// "constant time" find the 0x1 byte separating the padding (zeros) from the
|
||||||
|
// message
|
||||||
|
// TODO: It must be possible to do this in a better/smarter way?
|
||||||
|
var in_ps = 1;
|
||||||
|
var index = md.digestLength;
|
||||||
|
for(var j = md.digestLength; j < db.length; j++) {
|
||||||
|
var code = db.charCodeAt(j);
|
||||||
|
|
||||||
|
var is_0 = (code & 0x1) ^ 0x1;
|
||||||
|
|
||||||
|
// non-zero if not 0 or 1 in the ps section
|
||||||
|
var error_mask = in_ps ? 0xfffe : 0x0000;
|
||||||
|
error |= (code & error_mask);
|
||||||
|
|
||||||
|
// latch in_ps to zero after we find 0x1
|
||||||
|
in_ps = in_ps & is_0;
|
||||||
|
index += in_ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error || db.charCodeAt(index) !== 0x1) {
|
||||||
|
throw {
|
||||||
|
message: 'Invalid RSAES-OAEP padding.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.substring(index + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
function rsa_mgf1(seed, maskLength, hash) {
|
||||||
|
var t = '';
|
||||||
|
var count = Math.ceil(maskLength / hash.digestLength);
|
||||||
|
for(var i = 0; i < count; ++i) {
|
||||||
|
var c = String.fromCharCode(
|
||||||
|
(i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
|
||||||
|
hash.start();
|
||||||
|
hash.update(seed + c);
|
||||||
|
t += hash.digest().getBytes();
|
||||||
|
}
|
||||||
|
return t.substring(0, maskLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pkcs1';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// <script>
|
||||||
|
else {
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util', './random', './sha1'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
@ -265,11 +265,12 @@ var certBagValidator = {
|
|||||||
*
|
*
|
||||||
* The search can optionally be narrowed by a certain bag type.
|
* The search can optionally be narrowed by a certain bag type.
|
||||||
*
|
*
|
||||||
* @param safeContents The SafeContents structure to search in.
|
* @param safeContents the SafeContents structure to search in.
|
||||||
* @param attrName The name of the attribute to compare against.
|
* @param attrName the name of the attribute to compare against.
|
||||||
* @param attrValue The attribute value to search for.
|
* @param attrValue the attribute value to search for.
|
||||||
* @param bagType Optional bag type to narrow search by.
|
* @param [bagType] bag type to narrow search by.
|
||||||
* @return Array of matching bags
|
*
|
||||||
|
* @return an array of matching bags.
|
||||||
*/
|
*/
|
||||||
function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
||||||
var result = [];
|
var result = [];
|
||||||
@ -282,7 +283,7 @@ function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(bag.attributes[attrName] !== undefined &&
|
if(bag.attributes[attrName] !== undefined &&
|
||||||
bag.attributes[attrName].indexOf(attrValue) >= 0) {
|
bag.attributes[attrName].indexOf(attrValue) >= 0) {
|
||||||
result.push(bag);
|
result.push(bag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,11 +296,21 @@ function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
|||||||
* Converts a PKCS#12 PFX in ASN.1 notation into a PFX object.
|
* Converts a PKCS#12 PFX in ASN.1 notation into a PFX object.
|
||||||
*
|
*
|
||||||
* @param obj The PKCS#12 PFX in ASN.1 notation.
|
* @param obj The PKCS#12 PFX in ASN.1 notation.
|
||||||
* @param {String} password Password to decrypt with (optional)
|
* @param strict true to use strict DER decoding, false not to (default: true).
|
||||||
|
* @param {String} password Password to decrypt with (optional).
|
||||||
*
|
*
|
||||||
* @return PKCS#12 PFX object.
|
* @return PKCS#12 PFX object.
|
||||||
*/
|
*/
|
||||||
p12.pkcs12FromAsn1 = function(obj, password) {
|
p12.pkcs12FromAsn1 = function(obj, strict, password) {
|
||||||
|
// handle args
|
||||||
|
if(typeof strict === 'string') {
|
||||||
|
password = strict;
|
||||||
|
strict = true;
|
||||||
|
}
|
||||||
|
else if(strict === undefined) {
|
||||||
|
strict = true;
|
||||||
|
}
|
||||||
|
|
||||||
// validate PFX and capture data
|
// validate PFX and capture data
|
||||||
var capture = {};
|
var capture = {};
|
||||||
var errors = [];
|
var errors = [];
|
||||||
@ -316,27 +327,69 @@ p12.pkcs12FromAsn1 = function(obj, password) {
|
|||||||
safeContents: [],
|
safeContents: [],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bags with matching friendlyName attribute
|
* Gets bags with matching attributes.
|
||||||
*
|
*
|
||||||
* @param friendlyName The friendly name to search for
|
* @param filter the attributes to filter by:
|
||||||
* @param bagType Optional bag type to narrow search by
|
* [localKeyId] the localKeyId to search for.
|
||||||
* @return Array of bags with matching friendlyName attribute
|
* [localKeyIdHex] the localKeyId in hex to search for.
|
||||||
|
* [friendlyName] the friendly name to search for.
|
||||||
|
* [bagType] bag type to narrow each attribute search by.
|
||||||
|
*
|
||||||
|
* @return a map of attribute type to an array of matching bags.
|
||||||
*/
|
*/
|
||||||
getBagsByFriendlyName: function(friendlyName, bagType) {
|
getBags: function(filter) {
|
||||||
return _getBagsByAttribute(pfx.safeContents, 'friendlyName',
|
var rval = {};
|
||||||
friendlyName, bagType);
|
|
||||||
|
var localKeyId;
|
||||||
|
if('localKeyId' in filter) {
|
||||||
|
localKeyId = filter.localKeyId;
|
||||||
|
}
|
||||||
|
else if('localKeyIdHex' in filter) {
|
||||||
|
localKeyId = forge.util.hexToBytes(filter.localKeyIdHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localKeyId !== undefined) {
|
||||||
|
rval.localKeyId = _getBagsByAttribute(
|
||||||
|
pfx.safeContents, 'localKeyId',
|
||||||
|
localKeyId, filter.bagType);
|
||||||
|
}
|
||||||
|
if('friendlyName' in filter) {
|
||||||
|
rval.friendlyName = _getBagsByAttribute(
|
||||||
|
pfx.safeContents, 'friendlyName',
|
||||||
|
filter.friendlyName, filter.bagType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bags with matching localKeyId attribute
|
* DEPRECATED: use getBags() instead.
|
||||||
*
|
*
|
||||||
* @param localKeyId The localKeyId name to search for
|
* Get bags with matching friendlyName attribute.
|
||||||
* @param bagType Optional bag type to narrow search by
|
*
|
||||||
* @return Array of bags with matching localKeyId attribute
|
* @param friendlyName the friendly name to search for.
|
||||||
|
* @param [bagType] bag type to narrow search by.
|
||||||
|
*
|
||||||
|
* @return an array of bags with matching friendlyName attribute.
|
||||||
|
*/
|
||||||
|
getBagsByFriendlyName: function(friendlyName, bagType) {
|
||||||
|
return _getBagsByAttribute(
|
||||||
|
pfx.safeContents, 'friendlyName', friendlyName, bagType);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: use getBags() instead.
|
||||||
|
*
|
||||||
|
* Get bags with matching localKeyId attribute.
|
||||||
|
*
|
||||||
|
* @param localKeyId the localKeyId to search for.
|
||||||
|
* @param [bagType] bag type to narrow search by.
|
||||||
|
*
|
||||||
|
* @return an array of bags with matching localKeyId attribute.
|
||||||
*/
|
*/
|
||||||
getBagsByLocalKeyId: function(localKeyId, bagType) {
|
getBagsByLocalKeyId: function(localKeyId, bagType) {
|
||||||
return _getBagsByAttribute(pfx.safeContents, 'localKeyId',
|
return _getBagsByAttribute(
|
||||||
localKeyId, bagType);
|
pfx.safeContents, 'localKeyId', localKeyId, bagType);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -412,7 +465,7 @@ p12.pkcs12FromAsn1 = function(obj, password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_decodeAuthenticatedSafe(pfx, data.value, password);
|
_decodeAuthenticatedSafe(pfx, data.value, strict, password);
|
||||||
return pfx;
|
return pfx;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -422,12 +475,12 @@ p12.pkcs12FromAsn1 = function(obj, password) {
|
|||||||
* The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo.
|
* The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo.
|
||||||
*
|
*
|
||||||
* @param pfx The PKCS#12 PFX object to fill.
|
* @param pfx The PKCS#12 PFX object to fill.
|
||||||
* @param {String} authSafe BER-encoded AuthenticatedSafe
|
* @param {String} authSafe BER-encoded AuthenticatedSafe.
|
||||||
* @param {String} password Password to decrypt with (optional)
|
* @param strict true to use strict DER decoding, false not to.
|
||||||
* @return void
|
* @param {String} password Password to decrypt with (optional).
|
||||||
*/
|
*/
|
||||||
function _decodeAuthenticatedSafe(pfx, authSafe, password) {
|
function _decodeAuthenticatedSafe(pfx, authSafe, strict, password) {
|
||||||
authSafe = asn1.fromDer(authSafe); /* actually it's BER encoded */
|
authSafe = asn1.fromDer(authSafe, strict); /* actually it's BER encoded */
|
||||||
|
|
||||||
if(authSafe.tagClass !== asn1.Class.UNIVERSAL ||
|
if(authSafe.tagClass !== asn1.Class.UNIVERSAL ||
|
||||||
authSafe.type !== asn1.Type.SEQUENCE ||
|
authSafe.type !== asn1.Type.SEQUENCE ||
|
||||||
@ -485,7 +538,7 @@ function _decodeAuthenticatedSafe(pfx, authSafe, password) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.safeBags = _decodeSafeContents(safeContents, password);
|
obj.safeBags = _decodeSafeContents(safeContents, strict, password);
|
||||||
pfx.safeContents.push(obj);
|
pfx.safeContents.push(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,16 +590,19 @@ function _decryptSafeContents(data, password) {
|
|||||||
*
|
*
|
||||||
* The safeContents is a BER-encoded SEQUENCE OF SafeBag
|
* The safeContents is a BER-encoded SEQUENCE OF SafeBag
|
||||||
*
|
*
|
||||||
* @param {String} safeContents BER-encoded safeContents
|
* @param {String} safeContents BER-encoded safeContents.
|
||||||
* @param {String} password Password to decrypt with (optional)
|
* @param strict true to use strict DER decoding, false not to.
|
||||||
|
* @param {String} password Password to decrypt with (optional).
|
||||||
|
*
|
||||||
* @return {Array} Array of Bag objects.
|
* @return {Array} Array of Bag objects.
|
||||||
*/
|
*/
|
||||||
function _decodeSafeContents(safeContents, password) {
|
function _decodeSafeContents(safeContents, strict, password) {
|
||||||
safeContents = asn1.fromDer(safeContents); /* actually it's BER-encoded. */
|
// actually it's BER-encoded
|
||||||
|
safeContents = asn1.fromDer(safeContents, strict);
|
||||||
|
|
||||||
if(safeContents.tagClass !== asn1.Class.UNIVERSAL ||
|
if(safeContents.tagClass !== asn1.Class.UNIVERSAL ||
|
||||||
safeContents.type !== asn1.Type.SEQUENCE ||
|
safeContents.type !== asn1.Type.SEQUENCE ||
|
||||||
safeContents.constructed !== true) {
|
safeContents.constructed !== true) {
|
||||||
throw {
|
throw {
|
||||||
message: 'PKCS#12 SafeContents expected to be a ' +
|
message: 'PKCS#12 SafeContents expected to be a ' +
|
||||||
'SEQUENCE OF SafeBag'
|
'SEQUENCE OF SafeBag'
|
||||||
@ -603,7 +659,7 @@ function _decodeSafeContents(safeContents, password) {
|
|||||||
continue; /* Nothing more to do. */
|
continue; /* Nothing more to do. */
|
||||||
|
|
||||||
case pki.oids.certBag:
|
case pki.oids.certBag:
|
||||||
/* A PkCS#12 certBag can wrap both X.509 and sdsi certificates.
|
/* A PKCS#12 certBag can wrap both X.509 and sdsi certificates.
|
||||||
Therefore put the SafeBag content through another validator to
|
Therefore put the SafeBag content through another validator to
|
||||||
capture the fields. Afterwards check & store the results. */
|
capture the fields. Afterwards check & store the results. */
|
||||||
validator = certBagValidator;
|
validator = certBagValidator;
|
||||||
@ -615,8 +671,9 @@ function _decodeSafeContents(safeContents, password) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// true=produce cert hash
|
||||||
bag.cert = pki.certificateFromAsn1(
|
bag.cert = pki.certificateFromAsn1(
|
||||||
asn1.fromDer(capture.cert), true);
|
asn1.fromDer(capture.cert, strict), true);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -644,16 +701,17 @@ function _decodeSafeContents(safeContents, password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode PKCS#12 SET OF PKCS12Attribute into JavaScript object
|
* Decode PKCS#12 SET OF PKCS12Attribute into JavaScript object.
|
||||||
*
|
*
|
||||||
* @param attributes SET OF PKCS12Attribute (ASN.1 object)
|
* @param attributes SET OF PKCS12Attribute (ASN.1 object).
|
||||||
* @return the decoded attributes
|
*
|
||||||
|
* @return the decoded attributes.
|
||||||
*/
|
*/
|
||||||
function _decodeBagAttributes(attributes) {
|
function _decodeBagAttributes(attributes) {
|
||||||
var decodedAttrs = {};
|
var decodedAttrs = {};
|
||||||
|
|
||||||
if(attributes !== undefined) {
|
if(attributes !== undefined) {
|
||||||
for(var i = 0; i < attributes.length; i ++) {
|
for(var i = 0; i < attributes.length; ++i) {
|
||||||
var capture = {};
|
var capture = {};
|
||||||
var errors = [];
|
var errors = [];
|
||||||
if(!asn1.validate(attributes[i], attributeValidator, capture, errors)) {
|
if(!asn1.validate(attributes[i], attributeValidator, capture, errors)) {
|
||||||
@ -668,9 +726,9 @@ function _decodeBagAttributes(attributes) {
|
|||||||
// unsupported attribute type, ignore.
|
// unsupported attribute type, ignore.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedAttrs[pki.oids[oid]] = [];
|
decodedAttrs[pki.oids[oid]] = [];
|
||||||
for(var j = 0; j < capture.values.length; j ++) {
|
for(var j = 0; j < capture.values.length; ++j) {
|
||||||
decodedAttrs[pki.oids[oid]].push(capture.values[j].value);
|
decodedAttrs[pki.oids[oid]].push(capture.values[j].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,12 +754,13 @@ function _decodeBagAttributes(attributes) {
|
|||||||
* to specify a certificate chain).
|
* to specify a certificate chain).
|
||||||
* @param password the password to use.
|
* @param password the password to use.
|
||||||
* @param options:
|
* @param options:
|
||||||
* encAlgorithm the encryption algorithm to use
|
* algorithm the encryption algorithm to use
|
||||||
* ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'.
|
* ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'.
|
||||||
* count the iteration count to use.
|
* count the iteration count to use.
|
||||||
* saltSize the salt size to use.
|
* saltSize the salt size to use.
|
||||||
* useMac true to include a MAC, false not to, defaults to true.
|
* useMac true to include a MAC, false not to, defaults to true.
|
||||||
* localKeyId the local key ID to use, in hex.
|
* localKeyId the local key ID to use, in hex.
|
||||||
|
* friendlyName the friendly name to use.
|
||||||
* generateLocalKeyId true to generate a random local key ID,
|
* generateLocalKeyId true to generate a random local key ID,
|
||||||
* false not to, defaults to true.
|
* false not to, defaults to true.
|
||||||
*
|
*
|
||||||
@ -712,7 +771,7 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
|||||||
options = options || {};
|
options = options || {};
|
||||||
options.saltSize = options.saltSize || 8;
|
options.saltSize = options.saltSize || 8;
|
||||||
options.count = options.count || 2048;
|
options.count = options.count || 2048;
|
||||||
options.encAlgorithm = options.encAlgorithm || 'aes128';
|
options.algorithm = options.algorithm || options.encAlgorithm || 'aes128';
|
||||||
if(!('useMac' in options)) {
|
if(!('useMac' in options)) {
|
||||||
options.useMac = true;
|
options.useMac = true;
|
||||||
}
|
}
|
||||||
@ -729,12 +788,27 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
|||||||
localKeyId = forge.util.hexToBytes(localKeyId);
|
localKeyId = forge.util.hexToBytes(localKeyId);
|
||||||
}
|
}
|
||||||
else if(options.generateLocalKeyId) {
|
else if(options.generateLocalKeyId) {
|
||||||
// set localKeyId and friendlyName (if specified)
|
// use SHA-1 of paired cert, if available
|
||||||
localKeyId = forge.random.getBytes(20);
|
if(cert) {
|
||||||
|
var pairedCert = forge.util.isArray(cert) ? cert[0] : cert;
|
||||||
|
if(typeof pairedCert === 'string') {
|
||||||
|
pairedCert = pki.certificateFromPem(pairedCert);
|
||||||
|
}
|
||||||
|
var sha1 = forge.md.sha1.create();
|
||||||
|
sha1.update(asn1.toDer(pki.certificateToAsn1(pairedCert)).getBytes());
|
||||||
|
localKeyId = sha1.digest().getBytes();
|
||||||
|
}
|
||||||
|
// FIXME: consider using SHA-1 of public key (which can be generated
|
||||||
|
// from private key components)
|
||||||
|
// generate random bytes
|
||||||
|
else {
|
||||||
|
localKeyId = forge.random.getBytes(20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var attrs = [];
|
||||||
if(localKeyId !== null) {
|
if(localKeyId !== null) {
|
||||||
var attrs = [
|
attrs.push(
|
||||||
// localKeyID
|
// localKeyID
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
// attrId
|
// attrId
|
||||||
@ -745,76 +819,34 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
|||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
|
||||||
localKeyId)
|
localKeyId)
|
||||||
])
|
])
|
||||||
])
|
]));
|
||||||
];
|
}
|
||||||
|
if('friendlyName' in options) {
|
||||||
|
attrs.push(
|
||||||
|
// friendlyName
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// attrId
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(pki.oids['friendlyName']).getBytes()),
|
||||||
|
// attrValues
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BMPSTRING, false,
|
||||||
|
options.friendlyName)
|
||||||
|
])
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attrs.length > 0) {
|
||||||
bagAttrs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs);
|
bagAttrs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect contents for AuthenticatedSafe
|
// collect contents for AuthenticatedSafe
|
||||||
var contents = [];
|
var contents = [];
|
||||||
|
|
||||||
// create safe contents for private key
|
|
||||||
var keyBag = null;
|
|
||||||
if(key !== null) {
|
|
||||||
// SafeBag
|
|
||||||
var pkAsn1 = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(key));
|
|
||||||
if(password === null) {
|
|
||||||
// no encryption
|
|
||||||
keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
|
||||||
// bagId
|
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
|
||||||
asn1.oidToDer(pki.oids['keyBag']).getBytes()),
|
|
||||||
// bagValue
|
|
||||||
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
|
||||||
// PrivateKeyInfo
|
|
||||||
pkAsn1
|
|
||||||
]),
|
|
||||||
// bagAttributes (OPTIONAL)
|
|
||||||
bagAttrs
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// encrypted PrivateKeyInfo
|
|
||||||
keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
|
||||||
// bagId
|
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
|
||||||
asn1.oidToDer(pki.oids['pkcs8ShroudedKeyBag']).getBytes()),
|
|
||||||
// bagValue
|
|
||||||
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
|
||||||
// EncryptedPrivateKeyInfo
|
|
||||||
pki.encryptPrivateKeyInfo(pkAsn1, password, options)
|
|
||||||
]),
|
|
||||||
// bagAttributes (OPTIONAL)
|
|
||||||
bagAttrs
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SafeContents
|
|
||||||
var keySafeContents =
|
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [keyBag]);
|
|
||||||
|
|
||||||
// ContentInfo
|
|
||||||
var keyCI =
|
|
||||||
// PKCS#7 ContentInfo
|
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
|
||||||
// contentType
|
|
||||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
|
||||||
// OID for the content type is 'data'
|
|
||||||
asn1.oidToDer(pki.oids['data']).getBytes()),
|
|
||||||
// content
|
|
||||||
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
|
||||||
asn1.create(
|
|
||||||
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
|
|
||||||
asn1.toDer(keySafeContents).getBytes())
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
contents.push(keyCI);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create safe bag(s) for certificate chain
|
// create safe bag(s) for certificate chain
|
||||||
var chain = [];
|
var chain = [];
|
||||||
if(cert !== null) {
|
if(cert !== null) {
|
||||||
if((Array.isArray && Array.isArray(cert)) || cert.constructor === Array) {
|
if(forge.util.isArray(cert)) {
|
||||||
chain = cert;
|
chain = cert;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -880,6 +912,64 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
|||||||
contents.push(certCI);
|
contents.push(certCI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create safe contents for private key
|
||||||
|
var keyBag = null;
|
||||||
|
if(key !== null) {
|
||||||
|
// SafeBag
|
||||||
|
var pkAsn1 = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(key));
|
||||||
|
if(password === null) {
|
||||||
|
// no encryption
|
||||||
|
keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// bagId
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(pki.oids['keyBag']).getBytes()),
|
||||||
|
// bagValue
|
||||||
|
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
||||||
|
// PrivateKeyInfo
|
||||||
|
pkAsn1
|
||||||
|
]),
|
||||||
|
// bagAttributes (OPTIONAL)
|
||||||
|
bagAttrs
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// encrypted PrivateKeyInfo
|
||||||
|
keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// bagId
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(pki.oids['pkcs8ShroudedKeyBag']).getBytes()),
|
||||||
|
// bagValue
|
||||||
|
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
||||||
|
// EncryptedPrivateKeyInfo
|
||||||
|
pki.encryptPrivateKeyInfo(pkAsn1, password, options)
|
||||||
|
]),
|
||||||
|
// bagAttributes (OPTIONAL)
|
||||||
|
bagAttrs
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SafeContents
|
||||||
|
var keySafeContents =
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [keyBag]);
|
||||||
|
|
||||||
|
// ContentInfo
|
||||||
|
var keyCI =
|
||||||
|
// PKCS#7 ContentInfo
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// contentType
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
// OID for the content type is 'data'
|
||||||
|
asn1.oidToDer(pki.oids['data']).getBytes()),
|
||||||
|
// content
|
||||||
|
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
|
||||||
|
asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
|
||||||
|
asn1.toDer(keySafeContents).getBytes())
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
contents.push(keyCI);
|
||||||
|
}
|
||||||
|
|
||||||
// create AuthenticatedSafe by stringing together the contents
|
// create AuthenticatedSafe by stringing together the contents
|
||||||
var safe = asn1.create(
|
var safe = asn1.create(
|
||||||
asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, contents);
|
asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, contents);
|
||||||
@ -1059,20 +1149,11 @@ p12.generateKey = function(password, salt, id, iter, n, md) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'pkcs12';
|
var name = 'pkcs12';
|
||||||
var deps = [
|
|
||||||
'./asn1',
|
|
||||||
'./sha1',
|
|
||||||
'./pkcs7asn1',
|
|
||||||
'./pki',
|
|
||||||
'./util',
|
|
||||||
'./random',
|
|
||||||
'./hmac'
|
|
||||||
];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1081,30 +1162,50 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./asn1',
|
||||||
|
'./sha1',
|
||||||
|
'./pkcs7asn1',
|
||||||
|
'./pki',
|
||||||
|
'./util',
|
||||||
|
'./random',
|
||||||
|
'./hmac'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
114
src/lib/pkcs7.js
114
src/lib/pkcs7.js
@ -33,8 +33,24 @@ var p7 = forge.pkcs7 = forge.pkcs7 || {};
|
|||||||
* @return the PKCS#7 message.
|
* @return the PKCS#7 message.
|
||||||
*/
|
*/
|
||||||
p7.messageFromPem = function(pem) {
|
p7.messageFromPem = function(pem) {
|
||||||
var der = forge.pki.pemToDer(pem);
|
var msg = forge.pem.decode(pem)[0];
|
||||||
var obj = asn1.fromDer(der);
|
|
||||||
|
if(msg.type !== 'PKCS7') {
|
||||||
|
throw {
|
||||||
|
message: 'Could not convert PKCS#7 message from PEM; PEM header type ' +
|
||||||
|
'is not "PKCS#7".',
|
||||||
|
headerType: msg.type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
throw {
|
||||||
|
message: 'Could not convert PKCS#7 message from PEM; PEM is encrypted.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert DER to ASN.1 object
|
||||||
|
var obj = asn1.fromDer(msg.body);
|
||||||
|
|
||||||
return p7.messageFromAsn1(obj);
|
return p7.messageFromAsn1(obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,12 +63,12 @@ p7.messageFromPem = function(pem) {
|
|||||||
* @return The PEM-formatted PKCS#7 message.
|
* @return The PEM-formatted PKCS#7 message.
|
||||||
*/
|
*/
|
||||||
p7.messageToPem = function(msg, maxline) {
|
p7.messageToPem = function(msg, maxline) {
|
||||||
var out = asn1.toDer(msg.toAsn1());
|
// convert to ASN.1, then DER, then PEM-encode
|
||||||
out = forge.util.encode64(out.getBytes(), maxline || 64);
|
var pemObj = {
|
||||||
return (
|
type: 'PKCS7',
|
||||||
'-----BEGIN PKCS7-----\r\n' +
|
body: asn1.toDer(msg.toAsn1()).getBytes()
|
||||||
out +
|
};
|
||||||
'\r\n-----END PKCS7-----');
|
return forge.pem.encode(pemObj, {maxline: maxline});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,7 +282,7 @@ var _fromAsn1 = function(msg, obj, validator) {
|
|||||||
|
|
||||||
if(capture.encContent) {
|
if(capture.encContent) {
|
||||||
var content = '';
|
var content = '';
|
||||||
if(capture.encContent.constructor === Array) {
|
if(forge.util.isArray(capture.encContent)) {
|
||||||
for(var i = 0; i < capture.encContent.length; ++i) {
|
for(var i = 0; i < capture.encContent.length; ++i) {
|
||||||
if(capture.encContent[i].type !== asn1.Type.OCTETSTRING) {
|
if(capture.encContent[i].type !== asn1.Type.OCTETSTRING) {
|
||||||
throw {
|
throw {
|
||||||
@ -289,7 +305,7 @@ var _fromAsn1 = function(msg, obj, validator) {
|
|||||||
|
|
||||||
if(capture.content) {
|
if(capture.content) {
|
||||||
var content = '';
|
var content = '';
|
||||||
if(capture.content.constructor === Array) {
|
if(forge.util.isArray(capture.content)) {
|
||||||
for(var i = 0; i < capture.content.length; ++i) {
|
for(var i = 0; i < capture.content.length; ++i) {
|
||||||
if(capture.content[i].type !== asn1.Type.OCTETSTRING) {
|
if(capture.content[i].type !== asn1.Type.OCTETSTRING) {
|
||||||
throw {
|
throw {
|
||||||
@ -659,20 +675,11 @@ p7.createEnvelopedData = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'pkcs7';
|
var name = 'pkcs7';
|
||||||
var deps = [
|
|
||||||
'./aes',
|
|
||||||
'./asn1',
|
|
||||||
'./des',
|
|
||||||
'./pkcs7asn1',
|
|
||||||
'./pki',
|
|
||||||
'./random',
|
|
||||||
'./util'
|
|
||||||
];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -681,30 +688,51 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./aes',
|
||||||
|
'./asn1',
|
||||||
|
'./des',
|
||||||
|
'./pem',
|
||||||
|
'./pkcs7asn1',
|
||||||
|
'./pki',
|
||||||
|
'./random',
|
||||||
|
'./util'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -346,12 +346,11 @@ p7v.recipientInfoValidator = {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'pkcs7asn1';
|
var name = 'pkcs7asn1';
|
||||||
var deps = ['./asn1', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -360,30 +359,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './asn1', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
1637
src/lib/pki.js
1637
src/lib/pki.js
File diff suppressed because it is too large
Load Diff
@ -11,9 +11,10 @@
|
|||||||
/* ########## Begin module implementation ########## */
|
/* ########## Begin module implementation ########## */
|
||||||
function initModule(forge) {
|
function initModule(forge) {
|
||||||
|
|
||||||
var _nodejs = (typeof module === 'object' && module.exports);
|
var _nodejs = (
|
||||||
|
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||||
var crypto = null;
|
var crypto = null;
|
||||||
if(_nodejs) {
|
if(!forge.disableNativeCode && _nodejs) {
|
||||||
crypto = require('crypto');
|
crypto = require('crypto');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,12 +394,11 @@ prng.create = function(plugin) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'prng';
|
var name = 'prng';
|
||||||
var deps = ['./md', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -407,30 +407,41 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -203,12 +203,11 @@ pss.create = function(hash, mgf, sLen) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'pss';
|
var name = 'pss';
|
||||||
var deps = ['./random', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -217,30 +216,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './random', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -70,9 +70,10 @@ var _ctx = forge.prng.create(prng_aes);
|
|||||||
|
|
||||||
// add other sources of entropy only if window.crypto.getRandomValues is not
|
// add other sources of entropy only if window.crypto.getRandomValues is not
|
||||||
// available -- otherwise this source will be automatically used by the prng
|
// available -- otherwise this source will be automatically used by the prng
|
||||||
var _nodejs = (typeof module === 'object' && module.exports);
|
var _nodejs = (
|
||||||
if(!_nodejs && !(typeof window !== 'undefined' &&
|
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||||
window.crypto && window.crypto.getRandomValues)) {
|
if(forge.disableNativeCode || (!_nodejs && !(typeof window !== 'undefined' &&
|
||||||
|
window.crypto && window.crypto.getRandomValues))) {
|
||||||
|
|
||||||
// if this is a web worker, do not use weak entropy, instead register to
|
// if this is a web worker, do not use weak entropy, instead register to
|
||||||
// receive strong entropy asynchronously from the main thread
|
// receive strong entropy asynchronously from the main thread
|
||||||
@ -168,12 +169,11 @@ forge.random.getBytesSync = function(count) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'random';
|
var name = 'random';
|
||||||
var deps = ['./aes', './md', './prng', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -182,30 +182,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './aes', './md', './prng', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -74,7 +74,7 @@ forge.rc2 = forge.rc2 || {};
|
|||||||
* @return the expanded RC2 key (ByteBuffer of 128 bytes)
|
* @return the expanded RC2 key (ByteBuffer of 128 bytes)
|
||||||
*/
|
*/
|
||||||
forge.rc2.expandKey = function(key, effKeyBits) {
|
forge.rc2.expandKey = function(key, effKeyBits) {
|
||||||
if(key.constructor == String) {
|
if(typeof key === 'string') {
|
||||||
key = forge.util.createBuffer(key);
|
key = forge.util.createBuffer(key);
|
||||||
}
|
}
|
||||||
effKeyBits = effKeyBits || 128;
|
effKeyBits = effKeyBits || 128;
|
||||||
@ -250,7 +250,7 @@ var createCipher = function(key, bits, encrypt)
|
|||||||
start: function(iv, output) {
|
start: function(iv, output) {
|
||||||
if(iv) {
|
if(iv) {
|
||||||
/* CBC mode */
|
/* CBC mode */
|
||||||
if(key.constructor == String && iv.length == 8) {
|
if(typeof key === 'string' && iv.length === 8) {
|
||||||
iv = forge.util.createBuffer(iv);
|
iv = forge.util.createBuffer(iv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +302,7 @@ var createCipher = function(key, bits, encrypt)
|
|||||||
} else {
|
} else {
|
||||||
// add PKCS#7 padding to block (each pad byte is the
|
// add PKCS#7 padding to block (each pad byte is the
|
||||||
// value of the number of pad bytes)
|
// value of the number of pad bytes)
|
||||||
var padding = (_input.length() == 8) ? 8 : (8 - _input.length());
|
var padding = (_input.length() === 8) ? 8 : (8 - _input.length());
|
||||||
_input.fillWithByte(padding, padding);
|
_input.fillWithByte(padding, padding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,12 +420,11 @@ forge.rc2.createDecryptionCipher = function(key, bits) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'rc2';
|
var name = 'rc2';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -434,30 +433,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
553
src/lib/rsa.js
553
src/lib/rsa.js
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Javascript implementation of a basic RSA algorithms.
|
* Javascript implementation of basic RSA algorithms.
|
||||||
*
|
*
|
||||||
* @author Dave Longley
|
* @author Dave Longley
|
||||||
*
|
*
|
||||||
@ -9,8 +9,6 @@
|
|||||||
function initModule(forge) {
|
function initModule(forge) {
|
||||||
/* ########## Begin module implementation ########## */
|
/* ########## Begin module implementation ########## */
|
||||||
|
|
||||||
var _nodejs = (typeof module === 'object' && module.exports);
|
|
||||||
|
|
||||||
if(typeof BigInteger === 'undefined') {
|
if(typeof BigInteger === 'undefined') {
|
||||||
BigInteger = forge.jsbn.BigInteger;
|
BigInteger = forge.jsbn.BigInteger;
|
||||||
}
|
}
|
||||||
@ -42,6 +40,7 @@ var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
|
|||||||
* Digest ::= OCTET STRING
|
* Digest ::= OCTET STRING
|
||||||
*
|
*
|
||||||
* @param md the message digest object with the hash to sign.
|
* @param md the message digest object with the hash to sign.
|
||||||
|
*
|
||||||
* @return the encoded message (ready for RSA encrytion)
|
* @return the encoded message (ready for RSA encrytion)
|
||||||
*/
|
*/
|
||||||
var emsaPkcs1v15encode = function(md) {
|
var emsaPkcs1v15encode = function(md) {
|
||||||
@ -206,85 +205,45 @@ var _modPow = function(x, key, pub) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NOTE: THIS METHOD IS DEPRECATED, use 'sign' on a private key object or
|
||||||
|
* 'encrypt' on a public key object instead.
|
||||||
|
*
|
||||||
* Performs RSA encryption.
|
* Performs RSA encryption.
|
||||||
*
|
*
|
||||||
* The parameter bt controls whether to put padding bytes before the
|
* The parameter bt controls whether to put padding bytes before the
|
||||||
* message passed in. Set bt to either true or false to disable padding
|
* message passed in. Set bt to either true or false to disable padding
|
||||||
* completely (in order to handle e.g. EMSA-PSS encoding seperately before),
|
* completely (in order to handle e.g. EMSA-PSS encoding seperately before),
|
||||||
* signaling whether the encryption operation is a public key operation
|
* signaling whether the encryption operation is a public key operation
|
||||||
* (i.e. encrypting data) or not, i.e. private key operation (data signing).
|
* (i.e. encrypting data) or not, i.e. private key operation (data signing).
|
||||||
*
|
*
|
||||||
* For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01
|
* For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01
|
||||||
* (for signing) or 0x02 (for encryption). The key operation mode (private
|
* (for signing) or 0x02 (for encryption). The key operation mode (private
|
||||||
* or public) is derived from this flag in that case).
|
* or public) is derived from this flag in that case).
|
||||||
*
|
*
|
||||||
* @param m the message to encrypt as a byte string.
|
* @param m the message to encrypt as a byte string.
|
||||||
* @param key the RSA key to use.
|
* @param key the RSA key to use.
|
||||||
* @param bt for PKCS#1 v1.5 padding, the block type to use
|
* @param bt for PKCS#1 v1.5 padding, the block type to use
|
||||||
* (0x01 for private key, 0x02 for public),
|
* (0x01 for private key, 0x02 for public),
|
||||||
* to disable padding: true = public key, false = private key
|
* to disable padding: true = public key, false = private key.
|
||||||
|
*
|
||||||
* @return the encrypted bytes as a string.
|
* @return the encrypted bytes as a string.
|
||||||
*/
|
*/
|
||||||
pki.rsa.encrypt = function(m, key, bt) {
|
pki.rsa.encrypt = function(m, key, bt) {
|
||||||
var pub = bt;
|
var pub = bt;
|
||||||
var eb = forge.util.createBuffer();
|
var eb;
|
||||||
|
|
||||||
// get the length of the modulus in bytes
|
// get the length of the modulus in bytes
|
||||||
var k = Math.ceil(key.n.bitLength() / 8);
|
var k = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
if(bt !== false && bt !== true) {
|
if(bt !== false && bt !== true) {
|
||||||
/* use PKCS#1 v1.5 padding */
|
// legacy, default to PKCS#1 v1.5 padding
|
||||||
if(m.length > (k - 11)) {
|
pub = (bt === 0x02);
|
||||||
throw {
|
eb = _encodePkcs1_v1_5(m, key, bt);
|
||||||
message: 'Message is too long to encrypt.',
|
}
|
||||||
length: m.length,
|
else {
|
||||||
max: (k - 11)
|
eb = forge.util.createBuffer();
|
||||||
};
|
eb.putBytes(m);
|
||||||
}
|
|
||||||
|
|
||||||
/* A block type BT, a padding string PS, and the data D shall be
|
|
||||||
formatted into an octet string EB, the encryption block:
|
|
||||||
|
|
||||||
EB = 00 || BT || PS || 00 || D
|
|
||||||
|
|
||||||
The block type BT shall be a single octet indicating the structure of
|
|
||||||
the encryption block. For this version of the document it shall have
|
|
||||||
value 00, 01, or 02. For a private-key operation, the block type
|
|
||||||
shall be 00 or 01. For a public-key operation, it shall be 02.
|
|
||||||
|
|
||||||
The padding string PS shall consist of k-3-||D|| octets. For block
|
|
||||||
type 00, the octets shall have value 00; for block type 01, they
|
|
||||||
shall have value FF; and for block type 02, they shall be
|
|
||||||
pseudorandomly generated and nonzero. This makes the length of the
|
|
||||||
encryption block EB equal to k. */
|
|
||||||
|
|
||||||
// build the encryption block
|
|
||||||
eb.putByte(0x00);
|
|
||||||
eb.putByte(bt);
|
|
||||||
|
|
||||||
// create the padding, get key type
|
|
||||||
var padNum = k - 3 - m.length;
|
|
||||||
var padByte;
|
|
||||||
if(bt === 0x00 || bt === 0x01) {
|
|
||||||
pub = false;
|
|
||||||
padByte = (bt === 0x00) ? 0x00 : 0xFF;
|
|
||||||
for(var i = 0; i < padNum; ++i) {
|
|
||||||
eb.putByte(padByte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pub = true;
|
|
||||||
for(var i = 0; i < padNum; ++i) {
|
|
||||||
padByte = Math.floor(Math.random() * 255) + 1;
|
|
||||||
eb.putByte(padByte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// zero followed by message
|
|
||||||
eb.putByte(0x00);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eb.putBytes(m);
|
|
||||||
|
|
||||||
// load encryption block as big integer 'x'
|
// load encryption block as big integer 'x'
|
||||||
// FIXME: hex conversion inefficient, get BigInteger w/byte strings
|
// FIXME: hex conversion inefficient, get BigInteger w/byte strings
|
||||||
@ -308,6 +267,9 @@ pki.rsa.encrypt = function(m, key, bt) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NOTE: THIS METHOD IS DEPRECATED, use 'decrypt' on a private key object or
|
||||||
|
* 'verify' on a public key object instead.
|
||||||
|
*
|
||||||
* Performs RSA decryption.
|
* Performs RSA decryption.
|
||||||
*
|
*
|
||||||
* The parameter ml controls whether to apply PKCS#1 v1.5 padding
|
* The parameter ml controls whether to apply PKCS#1 v1.5 padding
|
||||||
@ -318,7 +280,7 @@ pki.rsa.encrypt = function(m, key, bt) {
|
|||||||
* @param ed the encrypted data to decrypt in as a byte string.
|
* @param ed the encrypted data to decrypt in as a byte string.
|
||||||
* @param key the RSA key to use.
|
* @param key the RSA key to use.
|
||||||
* @param pub true for a public key operation, false for private.
|
* @param pub true for a public key operation, false for private.
|
||||||
* @param ml the message length, if known. false to disable padding.
|
* @param ml the message length, if known, false to disable padding.
|
||||||
*
|
*
|
||||||
* @return the decrypted message as a byte string.
|
* @return the decrypted message as a byte string.
|
||||||
*/
|
*/
|
||||||
@ -327,7 +289,7 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
|||||||
var k = Math.ceil(key.n.bitLength() / 8);
|
var k = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
// error if the length of the encrypted data ED is not k
|
// error if the length of the encrypted data ED is not k
|
||||||
if(ed.length != k) {
|
if(ed.length !== k) {
|
||||||
throw {
|
throw {
|
||||||
message: 'Encrypted message length is invalid.',
|
message: 'Encrypted message length is invalid.',
|
||||||
length: ed.length,
|
length: ed.length,
|
||||||
@ -339,6 +301,14 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
|||||||
// FIXME: hex conversion inefficient, get BigInteger w/byte strings
|
// FIXME: hex conversion inefficient, get BigInteger w/byte strings
|
||||||
var y = new BigInteger(forge.util.createBuffer(ed).toHex(), 16);
|
var y = new BigInteger(forge.util.createBuffer(ed).toHex(), 16);
|
||||||
|
|
||||||
|
// y must be less than the modulus or it wasn't the result of
|
||||||
|
// a previous mod operation (encryption) using that modulus
|
||||||
|
if(y.compareTo(key.n) >= 0) {
|
||||||
|
throw {
|
||||||
|
message: 'Encrypted message is invalid.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// do RSA decryption
|
// do RSA decryption
|
||||||
var x = _modPow(y, key, pub);
|
var x = _modPow(y, key, pub);
|
||||||
|
|
||||||
@ -355,70 +325,8 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
|||||||
eb.putBytes(forge.util.hexToBytes(xhex));
|
eb.putBytes(forge.util.hexToBytes(xhex));
|
||||||
|
|
||||||
if(ml !== false) {
|
if(ml !== false) {
|
||||||
/* It is an error if any of the following conditions occurs:
|
// legacy, default to PKCS#1 v1.5 padding
|
||||||
|
return _decodePkcs1_v1_5(eb.getBytes(), key, pub);
|
||||||
1. The encryption block EB cannot be parsed unambiguously.
|
|
||||||
2. The padding string PS consists of fewer than eight octets
|
|
||||||
or is inconsisent with the block type BT.
|
|
||||||
3. The decryption process is a public-key operation and the block
|
|
||||||
type BT is not 00 or 01, or the decryption process is a
|
|
||||||
private-key operation and the block type is not 02.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// parse the encryption block
|
|
||||||
var first = eb.getByte();
|
|
||||||
var bt = eb.getByte();
|
|
||||||
if(first !== 0x00 ||
|
|
||||||
(pub && bt !== 0x00 && bt !== 0x01) ||
|
|
||||||
(!pub && bt != 0x02) ||
|
|
||||||
(pub && bt === 0x00 && typeof(ml) === 'undefined')) {
|
|
||||||
throw {
|
|
||||||
message: 'Encryption block is invalid.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var padNum = 0;
|
|
||||||
if(bt === 0x00) {
|
|
||||||
// check all padding bytes for 0x00
|
|
||||||
padNum = k - 3 - ml;
|
|
||||||
for(var i = 0; i < padNum; ++i) {
|
|
||||||
if(eb.getByte() !== 0x00) {
|
|
||||||
throw {
|
|
||||||
message: 'Encryption block is invalid.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(bt === 0x01) {
|
|
||||||
// find the first byte that isn't 0xFF, should be after all padding
|
|
||||||
padNum = 0;
|
|
||||||
while(eb.length() > 1) {
|
|
||||||
if(eb.getByte() !== 0xFF) {
|
|
||||||
--eb.read;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++padNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(bt === 0x02) {
|
|
||||||
// look for 0x00 byte
|
|
||||||
padNum = 0;
|
|
||||||
while(eb.length() > 1) {
|
|
||||||
if(eb.getByte() === 0x00) {
|
|
||||||
--eb.read;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++padNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// zero must be 0x00 and padNum must be (k - 3 - message length)
|
|
||||||
var zero = eb.getByte();
|
|
||||||
if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) {
|
|
||||||
throw {
|
|
||||||
message: 'Encryption block is invalid.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return message
|
// return message
|
||||||
@ -749,24 +657,63 @@ pki.rsa.setPublicKey = function(n, e) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts the given data with this public key.
|
* Encrypts the given data with this public key. Newer applications
|
||||||
|
* should use the 'RSA-OAEP' decryption scheme, 'RSAES-PKCS1-V1_5' is for
|
||||||
|
* legacy applications.
|
||||||
*
|
*
|
||||||
* @param data the byte string to encrypt.
|
* @param data the byte string to encrypt.
|
||||||
|
* @param scheme the encryption scheme to use:
|
||||||
|
* 'RSAES-PKCS1-V1_5' (default),
|
||||||
|
* 'RSA-OAEP',
|
||||||
|
* 'RAW', 'NONE', or null to perform raw RSA encryption.
|
||||||
|
* @param schemeOptions any scheme-specific options.
|
||||||
*
|
*
|
||||||
* @return the encrypted byte string.
|
* @return the encrypted byte string.
|
||||||
*/
|
*/
|
||||||
key.encrypt = function(data) {
|
key.encrypt = function(data, scheme, schemeOptions) {
|
||||||
return pki.rsa.encrypt(data, key, 0x02);
|
if(typeof scheme === 'string') {
|
||||||
|
scheme = scheme.toUpperCase();
|
||||||
|
}
|
||||||
|
else if(scheme === undefined) {
|
||||||
|
scheme = 'RSAES-PKCS1-V1_5';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scheme === 'RSAES-PKCS1-V1_5') {
|
||||||
|
scheme = {
|
||||||
|
encode: function(m, key, pub) {
|
||||||
|
return _encodePkcs1_v1_5(m, key, 0x02).getBytes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') {
|
||||||
|
scheme = {
|
||||||
|
encode: function(m, key) {
|
||||||
|
return forge.pkcs1.encode_rsa_oaep(key, m, schemeOptions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) {
|
||||||
|
scheme = { encode: function(e) { return e; } };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw {
|
||||||
|
message: 'Unsupported encryption scheme: "' + scheme + '".'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// do scheme-based encoding then rsa encryption
|
||||||
|
var e = scheme.encode(data, key, true);
|
||||||
|
return pki.rsa.encrypt(e, key, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies the given signature against the given digest.
|
* Verifies the given signature against the given digest.
|
||||||
*
|
*
|
||||||
* PKCS#1 supports multiple (currently two) signature schemes:
|
* PKCS#1 supports multiple (currently two) signature schemes:
|
||||||
* RSASSA-PKCS1-v1_5 and RSASSA-PSS.
|
* RSASSA-PKCS1-V1_5 and RSASSA-PSS.
|
||||||
*
|
*
|
||||||
* By default this implementation uses the "old scheme", i.e.
|
* By default this implementation uses the "old scheme", i.e.
|
||||||
* RSASSA-PKCS1-v1_5, in which case once RSA-decrypted, the
|
* RSASSA-PKCS1-V1_5, in which case once RSA-decrypted, the
|
||||||
* signature is an OCTET STRING that holds a DigestInfo.
|
* signature is an OCTET STRING that holds a DigestInfo.
|
||||||
*
|
*
|
||||||
* DigestInfo ::= SEQUENCE {
|
* DigestInfo ::= SEQUENCE {
|
||||||
@ -777,29 +724,51 @@ pki.rsa.setPublicKey = function(n, e) {
|
|||||||
* Digest ::= OCTET STRING
|
* Digest ::= OCTET STRING
|
||||||
*
|
*
|
||||||
* To perform PSS signature verification, provide an instance
|
* To perform PSS signature verification, provide an instance
|
||||||
* of Forge PSS object as scheme parameter.
|
* of Forge PSS object as the scheme parameter.
|
||||||
*
|
*
|
||||||
* @param digest the message digest hash to compare against the signature.
|
* @param digest the message digest hash to compare against the signature.
|
||||||
* @param signature the signature to verify.
|
* @param signature the signature to verify.
|
||||||
* @param scheme signature scheme to use, undefined for PKCS#1 v1.5
|
* @param scheme signature verification scheme to use:
|
||||||
* padding style.
|
* 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5,
|
||||||
|
* a Forge PSS object for RSASSA-PSS,
|
||||||
|
* 'NONE' or null for none, DigestInfo will not be expected, but
|
||||||
|
* PKCS#1 v1.5 padding will still be used.
|
||||||
|
*
|
||||||
* @return true if the signature was verified, false if not.
|
* @return true if the signature was verified, false if not.
|
||||||
*/
|
*/
|
||||||
key.verify = function(digest, signature, scheme) {
|
key.verify = function(digest, signature, scheme) {
|
||||||
// do rsa decryption
|
if(typeof scheme === 'string') {
|
||||||
var ml = scheme === undefined ? undefined : false;
|
scheme = scheme.toUpperCase();
|
||||||
var d = pki.rsa.decrypt(signature, key, true, ml);
|
|
||||||
|
|
||||||
if(scheme === undefined) {
|
|
||||||
// d is ASN.1 BER-encoded DigestInfo
|
|
||||||
var obj = asn1.fromDer(d);
|
|
||||||
|
|
||||||
// compare the given digest to the decrypted one
|
|
||||||
return digest === obj.value[1].value;
|
|
||||||
}
|
}
|
||||||
else {
|
else if(scheme === undefined) {
|
||||||
return scheme.verify(digest, d, key.n.bitLength());
|
scheme = 'RSASSA-PKCS1-V1_5';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(scheme === 'RSASSA-PKCS1-V1_5') {
|
||||||
|
scheme = {
|
||||||
|
verify: function(digest, d) {
|
||||||
|
// remove padding
|
||||||
|
d = _decodePkcs1_v1_5(d, key, true);
|
||||||
|
// d is ASN.1 BER-encoded DigestInfo
|
||||||
|
var obj = asn1.fromDer(d);
|
||||||
|
// compare the given digest to the decrypted one
|
||||||
|
return digest === obj.value[1].value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) {
|
||||||
|
scheme = {
|
||||||
|
verify: function(digest, d) {
|
||||||
|
// remove padding
|
||||||
|
d = _decodePkcs1_v1_5(d, key, true);
|
||||||
|
return digest === d;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// do rsa decryption w/o any decoding, then verify -- which does decoding
|
||||||
|
var d = pki.rsa.decrypt(signature, key, true, false);
|
||||||
|
return scheme.verify(digest, d, key.n.bitLength());
|
||||||
};
|
};
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
@ -833,39 +802,94 @@ pki.rsa.setPrivateKey = function(n, e, d, p, q, dP, dQ, qInv) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts the given data with this private key.
|
* Decrypts the given data with this private key. The decryption scheme
|
||||||
|
* must match the one used to encrypt the data.
|
||||||
*
|
*
|
||||||
* @param data the byte string to decrypt.
|
* @param data the byte string to decrypt.
|
||||||
|
* @param scheme the decryption scheme to use:
|
||||||
|
* 'RSAES-PKCS1-V1_5' (default),
|
||||||
|
* 'RSA-OAEP',
|
||||||
|
* 'RAW', 'NONE', or null to perform raw RSA decryption.
|
||||||
|
* @param schemeOptions any scheme-specific options.
|
||||||
*
|
*
|
||||||
* @return the decrypted byte string.
|
* @return the decrypted byte string.
|
||||||
*/
|
*/
|
||||||
key.decrypt = function(data) {
|
key.decrypt = function(data, scheme, schemeOptions) {
|
||||||
return pki.rsa.decrypt(data, key, false);
|
if(typeof scheme === 'string') {
|
||||||
|
scheme = scheme.toUpperCase();
|
||||||
|
}
|
||||||
|
else if(scheme === undefined) {
|
||||||
|
scheme = 'RSAES-PKCS1-V1_5';
|
||||||
|
}
|
||||||
|
|
||||||
|
// do rsa decryption w/o any decoding
|
||||||
|
var d = pki.rsa.decrypt(data, key, false, false);
|
||||||
|
|
||||||
|
if(scheme === 'RSAES-PKCS1-V1_5') {
|
||||||
|
scheme = { decode: _decodePkcs1_v1_5 };
|
||||||
|
}
|
||||||
|
else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') {
|
||||||
|
scheme = {
|
||||||
|
decode: function(d, key) {
|
||||||
|
return forge.pkcs1.decode_rsa_oaep(key, d, schemeOptions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) {
|
||||||
|
scheme = { decode: function(d) { return d; } };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw {
|
||||||
|
message: 'Unsupported encryption scheme: "' + scheme + '".'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode according to scheme
|
||||||
|
return scheme.decode(d, key, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs the given digest, producing a signature.
|
* Signs the given digest, producing a signature.
|
||||||
*
|
*
|
||||||
* PKCS#1 supports multiple (currently two) signature schemes:
|
* PKCS#1 supports multiple (currently two) signature schemes:
|
||||||
* RSASSA-PKCS1-v1_5 and RSASSA-PSS.
|
* RSASSA-PKCS1-V1_5 and RSASSA-PSS.
|
||||||
*
|
*
|
||||||
* By default this implementation uses the "old scheme", i.e.
|
* By default this implementation uses the "old scheme", i.e.
|
||||||
* RSASSA-PKCS1-v1_5. In order to generate a PSS signature, provide
|
* RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide
|
||||||
* an instance of Forge PSS object as scheme parameter.
|
* an instance of Forge PSS object as the scheme parameter.
|
||||||
*
|
*
|
||||||
* @param md the message digest object with the hash to sign.
|
* @param md the message digest object with the hash to sign.
|
||||||
* @param scheme signature scheme to use, undefined for PKCS#1 v1.5
|
* @param scheme the signature scheme to use:
|
||||||
* padding style.
|
* 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5,
|
||||||
|
* a Forge PSS object for RSASSA-PSS,
|
||||||
|
* 'NONE' or null for none, DigestInfo will not be used but
|
||||||
|
* PKCS#1 v1.5 padding will still be used.
|
||||||
|
*
|
||||||
* @return the signature as a byte string.
|
* @return the signature as a byte string.
|
||||||
*/
|
*/
|
||||||
key.sign = function(md, scheme) {
|
key.sign = function(md, scheme) {
|
||||||
var bt = false; /* private key operation */
|
/* Note: The internal implementation of RSA operations is being
|
||||||
|
transitioned away from a PKCS#1 v1.5 hard-coded scheme. Some legacy
|
||||||
|
code like the use of an encoding block identifier 'bt' will eventually
|
||||||
|
be removed. */
|
||||||
|
|
||||||
if(scheme === undefined) {
|
// private key operation
|
||||||
|
var bt = false;
|
||||||
|
|
||||||
|
if(typeof scheme === 'string') {
|
||||||
|
scheme = scheme.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scheme === undefined || scheme === 'RSASSA-PKCS1-V1_5') {
|
||||||
scheme = { encode: emsaPkcs1v15encode };
|
scheme = { encode: emsaPkcs1v15encode };
|
||||||
bt = 0x01;
|
bt = 0x01;
|
||||||
}
|
}
|
||||||
|
else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) {
|
||||||
|
scheme = { encode: function() { return md; } };
|
||||||
|
bt = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode and then encrypt
|
||||||
var d = scheme.encode(md, key.n.bitLength());
|
var d = scheme.encode(md, key.n.bitLength());
|
||||||
return pki.rsa.encrypt(d, key, bt);
|
return pki.rsa.encrypt(d, key, bt);
|
||||||
};
|
};
|
||||||
@ -873,6 +897,159 @@ pki.rsa.setPrivateKey = function(n, e, d, p, q, dP, dQ, qInv) {
|
|||||||
return key;
|
return key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a message using PKCS#1 v1.5 padding.
|
||||||
|
*
|
||||||
|
* @param m the message to encode.
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param bt the block type to use, i.e. either 0x01 (for signing) or 0x02
|
||||||
|
* (for encryption).
|
||||||
|
*
|
||||||
|
* @return the padded byte buffer.
|
||||||
|
*/
|
||||||
|
function _encodePkcs1_v1_5(m, key, bt) {
|
||||||
|
var eb = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// get the length of the modulus in bytes
|
||||||
|
var k = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
|
/* use PKCS#1 v1.5 padding */
|
||||||
|
if(m.length > (k - 11)) {
|
||||||
|
throw {
|
||||||
|
message: 'Message is too long for PKCS#1 v1.5 padding.',
|
||||||
|
length: m.length,
|
||||||
|
max: (k - 11)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A block type BT, a padding string PS, and the data D shall be
|
||||||
|
formatted into an octet string EB, the encryption block:
|
||||||
|
|
||||||
|
EB = 00 || BT || PS || 00 || D
|
||||||
|
|
||||||
|
The block type BT shall be a single octet indicating the structure of
|
||||||
|
the encryption block. For this version of the document it shall have
|
||||||
|
value 00, 01, or 02. For a private-key operation, the block type
|
||||||
|
shall be 00 or 01. For a public-key operation, it shall be 02.
|
||||||
|
|
||||||
|
The padding string PS shall consist of k-3-||D|| octets. For block
|
||||||
|
type 00, the octets shall have value 00; for block type 01, they
|
||||||
|
shall have value FF; and for block type 02, they shall be
|
||||||
|
pseudorandomly generated and nonzero. This makes the length of the
|
||||||
|
encryption block EB equal to k. */
|
||||||
|
|
||||||
|
// build the encryption block
|
||||||
|
eb.putByte(0x00);
|
||||||
|
eb.putByte(bt);
|
||||||
|
|
||||||
|
// create the padding
|
||||||
|
var padNum = k - 3 - m.length;
|
||||||
|
var padByte;
|
||||||
|
// private key op
|
||||||
|
if(bt === 0x00 || bt === 0x01) {
|
||||||
|
padByte = (bt === 0x00) ? 0x00 : 0xFF;
|
||||||
|
for(var i = 0; i < padNum; ++i) {
|
||||||
|
eb.putByte(padByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// public key op
|
||||||
|
else {
|
||||||
|
for(var i = 0; i < padNum; ++i) {
|
||||||
|
padByte = Math.floor(Math.random() * 255) + 1;
|
||||||
|
eb.putByte(padByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero followed by message
|
||||||
|
eb.putByte(0x00);
|
||||||
|
eb.putBytes(m);
|
||||||
|
|
||||||
|
return eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a message using PKCS#1 v1.5 padding.
|
||||||
|
*
|
||||||
|
* @param em the message to decode.
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param pub true if the key is a public key, false if it is private.
|
||||||
|
* @param ml the message length, if specified.
|
||||||
|
*
|
||||||
|
* @return the decoded bytes.
|
||||||
|
*/
|
||||||
|
function _decodePkcs1_v1_5(em, key, pub, ml) {
|
||||||
|
// get the length of the modulus in bytes
|
||||||
|
var k = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
|
/* It is an error if any of the following conditions occurs:
|
||||||
|
|
||||||
|
1. The encryption block EB cannot be parsed unambiguously.
|
||||||
|
2. The padding string PS consists of fewer than eight octets
|
||||||
|
or is inconsisent with the block type BT.
|
||||||
|
3. The decryption process is a public-key operation and the block
|
||||||
|
type BT is not 00 or 01, or the decryption process is a
|
||||||
|
private-key operation and the block type is not 02.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// parse the encryption block
|
||||||
|
var eb = forge.util.createBuffer(em);
|
||||||
|
var first = eb.getByte();
|
||||||
|
var bt = eb.getByte();
|
||||||
|
if(first !== 0x00 ||
|
||||||
|
(pub && bt !== 0x00 && bt !== 0x01) ||
|
||||||
|
(!pub && bt != 0x02) ||
|
||||||
|
(pub && bt === 0x00 && typeof(ml) === 'undefined')) {
|
||||||
|
throw {
|
||||||
|
message: 'Encryption block is invalid.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var padNum = 0;
|
||||||
|
if(bt === 0x00) {
|
||||||
|
// check all padding bytes for 0x00
|
||||||
|
padNum = k - 3 - ml;
|
||||||
|
for(var i = 0; i < padNum; ++i) {
|
||||||
|
if(eb.getByte() !== 0x00) {
|
||||||
|
throw {
|
||||||
|
message: 'Encryption block is invalid.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(bt === 0x01) {
|
||||||
|
// find the first byte that isn't 0xFF, should be after all padding
|
||||||
|
padNum = 0;
|
||||||
|
while(eb.length() > 1) {
|
||||||
|
if(eb.getByte() !== 0xFF) {
|
||||||
|
--eb.read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++padNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(bt === 0x02) {
|
||||||
|
// look for 0x00 byte
|
||||||
|
padNum = 0;
|
||||||
|
while(eb.length() > 1) {
|
||||||
|
if(eb.getByte() === 0x00) {
|
||||||
|
--eb.read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++padNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero must be 0x00 and padNum must be (k - 3 - message length)
|
||||||
|
var zero = eb.getByte();
|
||||||
|
if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) {
|
||||||
|
throw {
|
||||||
|
message: 'Encryption block is invalid.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return eb.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the key-generation algorithm asynchronously, either in the background
|
* Runs the key-generation algorithm asynchronously, either in the background
|
||||||
* via Web Workers, or using the main thread and setImmediate.
|
* via Web Workers, or using the main thread and setImmediate.
|
||||||
@ -1064,12 +1241,11 @@ function _generateKeyPair(state, options, callback) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'rsa';
|
var name = 'rsa';
|
||||||
var deps = ['./asn1', './oids', './random', './util', './jsbn'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1078,30 +1254,49 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./asn1',
|
||||||
|
'./oids',
|
||||||
|
'./random',
|
||||||
|
'./util',
|
||||||
|
'./jsbn',
|
||||||
|
'./pkcs1'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -174,6 +174,8 @@ sha1.create = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the digest.
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.start = function() {
|
md.start = function() {
|
||||||
md.messageLength = 0;
|
md.messageLength = 0;
|
||||||
@ -185,6 +187,7 @@ sha1.create = function() {
|
|||||||
h3: 0x10325476,
|
h3: 0x10325476,
|
||||||
h4: 0xC3D2E1F0
|
h4: 0xC3D2E1F0
|
||||||
};
|
};
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
// start digest automatically for first time
|
// start digest automatically for first time
|
||||||
md.start();
|
md.start();
|
||||||
@ -196,6 +199,8 @@ sha1.create = function() {
|
|||||||
*
|
*
|
||||||
* @param msg the message input to update with.
|
* @param msg the message input to update with.
|
||||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.update = function(msg, encoding) {
|
md.update = function(msg, encoding) {
|
||||||
if(encoding === 'utf8') {
|
if(encoding === 'utf8') {
|
||||||
@ -215,6 +220,8 @@ sha1.create = function() {
|
|||||||
if(_input.read > 2048 || _input.length() === 0) {
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
_input.compact();
|
_input.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,12 +287,11 @@ sha1.create = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'sha1';
|
var name = 'sha1';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -294,30 +300,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -175,6 +175,8 @@ sha256.create = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the digest.
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.start = function() {
|
md.start = function() {
|
||||||
md.messageLength = 0;
|
md.messageLength = 0;
|
||||||
@ -189,6 +191,7 @@ sha256.create = function() {
|
|||||||
h6: 0x1F83D9AB,
|
h6: 0x1F83D9AB,
|
||||||
h7: 0x5BE0CD19
|
h7: 0x5BE0CD19
|
||||||
};
|
};
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
// start digest automatically for first time
|
// start digest automatically for first time
|
||||||
md.start();
|
md.start();
|
||||||
@ -200,6 +203,8 @@ sha256.create = function() {
|
|||||||
*
|
*
|
||||||
* @param msg the message input to update with.
|
* @param msg the message input to update with.
|
||||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
*/
|
*/
|
||||||
md.update = function(msg, encoding) {
|
md.update = function(msg, encoding) {
|
||||||
if(encoding === 'utf8') {
|
if(encoding === 'utf8') {
|
||||||
@ -219,6 +224,8 @@ sha256.create = function() {
|
|||||||
if(_input.read > 2048 || _input.length() === 0) {
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
_input.compact();
|
_input.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -290,12 +297,11 @@ sha256.create = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'sha256';
|
var name = 'sha256';
|
||||||
var deps = ['./util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -304,30 +310,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -292,12 +292,11 @@ net.createSocket = function(options) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'net';
|
var name = 'net';
|
||||||
var deps = [];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -306,30 +305,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -258,7 +258,7 @@ Task.prototype.next = function(name, subrun) {
|
|||||||
*/
|
*/
|
||||||
Task.prototype.parallel = function(name, subrun) {
|
Task.prototype.parallel = function(name, subrun) {
|
||||||
// juggle parameters if it looks like no name is given
|
// juggle parameters if it looks like no name is given
|
||||||
if(name.constructor == Array) {
|
if(forge.util.isArray(name)) {
|
||||||
subrun = name;
|
subrun = name;
|
||||||
|
|
||||||
// inherit parent's name
|
// inherit parent's name
|
||||||
@ -738,12 +738,11 @@ forge.task.createCondition = function() {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'task';
|
var name = 'task';
|
||||||
var deps = ['./debug', './log', './util'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -752,30 +751,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './debug', './log', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
499
src/lib/tls.js
499
src/lib/tls.js
@ -439,182 +439,6 @@ var inflate = function(c, record, s) {
|
|||||||
return rval;
|
return rval;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypts the TLSCompressed record into a TLSCipherText record using AES-128
|
|
||||||
* in CBC mode.
|
|
||||||
*
|
|
||||||
* @param record the TLSCompressed record to encrypt.
|
|
||||||
* @param s the ConnectionState to use.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure.
|
|
||||||
*/
|
|
||||||
var encrypt_aes_128_cbc_sha1 = function(record, s) {
|
|
||||||
var rval = false;
|
|
||||||
|
|
||||||
// append MAC to fragment, update sequence number
|
|
||||||
var mac = s.macFunction(s.macKey, s.sequenceNumber, record);
|
|
||||||
record.fragment.putBytes(mac);
|
|
||||||
s.updateSequenceNumber();
|
|
||||||
|
|
||||||
// TODO: TLS 1.1 & 1.2 use an explicit IV every time to protect against
|
|
||||||
// CBC attacks
|
|
||||||
// var iv = forge.random.getBytes(16);
|
|
||||||
|
|
||||||
// use the pre-generated IV when initializing for TLS 1.0, otherwise use the
|
|
||||||
// residue from the previous encryption
|
|
||||||
var iv = s.cipherState.init ? null : s.cipherState.iv;
|
|
||||||
s.cipherState.init = true;
|
|
||||||
|
|
||||||
// start cipher
|
|
||||||
var cipher = s.cipherState.cipher;
|
|
||||||
cipher.start(iv);
|
|
||||||
|
|
||||||
// TODO: TLS 1.1 & 1.2 write IV into output
|
|
||||||
//cipher.output.putBytes(iv);
|
|
||||||
|
|
||||||
// do encryption (default padding is appropriate)
|
|
||||||
cipher.update(record.fragment);
|
|
||||||
if(cipher.finish(encrypt_aes_128_cbc_sha1_padding)) {
|
|
||||||
// set record fragment to encrypted output
|
|
||||||
record.fragment = cipher.output;
|
|
||||||
record.length = record.fragment.length();
|
|
||||||
rval = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles padding for aes_128_cbc_sha1 in encrypt mode.
|
|
||||||
*
|
|
||||||
* @param blockSize the block size.
|
|
||||||
* @param input the input buffer.
|
|
||||||
* @param decrypt true in decrypt mode, false in encrypt mode.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure.
|
|
||||||
*/
|
|
||||||
var encrypt_aes_128_cbc_sha1_padding = function(blockSize, input, decrypt) {
|
|
||||||
/* The encrypted data length (TLSCiphertext.length) is one more than the sum
|
|
||||||
of SecurityParameters.block_length, TLSCompressed.length,
|
|
||||||
SecurityParameters.mac_length, and padding_length.
|
|
||||||
|
|
||||||
The padding may be any length up to 255 bytes long, as long as it results in
|
|
||||||
the TLSCiphertext.length being an integral multiple of the block length.
|
|
||||||
Lengths longer than necessary might be desirable to frustrate attacks on a
|
|
||||||
protocol based on analysis of the lengths of exchanged messages. Each uint8
|
|
||||||
in the padding data vector must be filled with the padding length value.
|
|
||||||
|
|
||||||
The padding length should be such that the total size of the
|
|
||||||
GenericBlockCipher structure is a multiple of the cipher's block length.
|
|
||||||
Legal values range from zero to 255, inclusive. This length specifies the
|
|
||||||
length of the padding field exclusive of the padding_length field itself.
|
|
||||||
|
|
||||||
This is slightly different from PKCS#7 because the padding value is 1
|
|
||||||
less than the actual number of padding bytes if you include the
|
|
||||||
padding_length uint8 itself as a padding byte. */
|
|
||||||
if(!decrypt) {
|
|
||||||
// get the number of padding bytes required to reach the blockSize and
|
|
||||||
// subtract 1 to make room for the padding_length uint8 but add it during
|
|
||||||
// fillWithByte
|
|
||||||
var padding = (input.length() == blockSize) ?
|
|
||||||
(blockSize - 1) : (blockSize - input.length() - 1);
|
|
||||||
input.fillWithByte(padding, padding + 1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles padding for aes_128_cbc_sha1 in decrypt mode.
|
|
||||||
*
|
|
||||||
* @param blockSize the block size.
|
|
||||||
* @param output the output buffer.
|
|
||||||
* @param decrypt true in decrypt mode, false in encrypt mode.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure.
|
|
||||||
*/
|
|
||||||
var decrypt_aes_128_cbc_sha1_padding = function(blockSize, output, decrypt) {
|
|
||||||
var rval = true;
|
|
||||||
if(decrypt) {
|
|
||||||
/* The last byte in the output specifies the number of padding bytes not
|
|
||||||
including itself. Each of the padding bytes has the same value as that
|
|
||||||
last byte (known as the padding_length). Here we check all padding
|
|
||||||
bytes to ensure they have the value of padding_length even if one of
|
|
||||||
them is bad in order to ward-off timing attacks. */
|
|
||||||
var len = output.length();
|
|
||||||
var paddingLength = output.last();
|
|
||||||
for(var i = len - 1 - paddingLength; i < len - 1; ++i) {
|
|
||||||
rval = rval && (output.at(i) == paddingLength);
|
|
||||||
}
|
|
||||||
if(rval) {
|
|
||||||
// trim off padding bytes and last padding length byte
|
|
||||||
output.truncate(paddingLength + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts a TLSCipherText record into a TLSCompressed record using
|
|
||||||
* AES-128 in CBC mode.
|
|
||||||
*
|
|
||||||
* @param record the TLSCipherText record to decrypt.
|
|
||||||
* @param s the ConnectionState to use.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure.
|
|
||||||
*/
|
|
||||||
var decrypt_aes_128_cbc_sha1 = function(record, s) {
|
|
||||||
var rval = false;
|
|
||||||
|
|
||||||
// TODO: TLS 1.1 & 1.2 use an explicit IV every time to protect against
|
|
||||||
// CBC attacks
|
|
||||||
//var iv = record.fragment.getBytes(16);
|
|
||||||
|
|
||||||
// use pre-generated IV when initializing for TLS 1.0, otherwise use the
|
|
||||||
// residue from the previous decryption
|
|
||||||
var iv = s.cipherState.init ? null : s.cipherState.iv;
|
|
||||||
s.cipherState.init = true;
|
|
||||||
|
|
||||||
// start cipher
|
|
||||||
var cipher = s.cipherState.cipher;
|
|
||||||
cipher.start(iv);
|
|
||||||
|
|
||||||
// do decryption
|
|
||||||
cipher.update(record.fragment);
|
|
||||||
rval = cipher.finish(decrypt_aes_128_cbc_sha1_padding);
|
|
||||||
|
|
||||||
// even if decryption fails, keep going to minimize timing attacks
|
|
||||||
|
|
||||||
// decrypted data:
|
|
||||||
// first (len - 20) bytes = application data
|
|
||||||
// last 20 bytes = MAC
|
|
||||||
var macLen = s.macLength;
|
|
||||||
|
|
||||||
// create a zero'd out mac
|
|
||||||
var mac = '';
|
|
||||||
for(var i = 0; i < macLen; ++i) {
|
|
||||||
mac += String.fromCharCode(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get fragment and mac
|
|
||||||
var len = cipher.output.length();
|
|
||||||
if(len >= macLen) {
|
|
||||||
record.fragment = cipher.output.getBytes(len - macLen);
|
|
||||||
mac = cipher.output.getBytes(macLen);
|
|
||||||
}
|
|
||||||
// bad data, but get bytes anyway to try to keep timing consistent
|
|
||||||
else {
|
|
||||||
record.fragment = cipher.output.getBytes();
|
|
||||||
}
|
|
||||||
record.fragment = forge.util.createBuffer(record.fragment);
|
|
||||||
record.length = record.fragment.length();
|
|
||||||
|
|
||||||
// see if data integrity checks out, update sequence number
|
|
||||||
var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record);
|
|
||||||
s.updateSequenceNumber();
|
|
||||||
rval = (mac2 === mac) && rval;
|
|
||||||
return rval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a TLS variable-length vector from a byte buffer.
|
* Reads a TLS variable-length vector from a byte buffer.
|
||||||
*
|
*
|
||||||
@ -857,16 +681,11 @@ tls.Alert.Description = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported cipher suites.
|
* Supported cipher suites.
|
||||||
*
|
|
||||||
* TODO: Make cipher suites modular.
|
|
||||||
*/
|
*/
|
||||||
tls.CipherSuites = {
|
tls.CipherSuites = {};
|
||||||
TLS_RSA_WITH_AES_128_CBC_SHA: [0x00,0x2f],
|
|
||||||
TLS_RSA_WITH_AES_256_CBC_SHA: [0x00,0x35]
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a supported cipher suite from 2 bytes.
|
* Gets a supported cipher suite from its 2 byte ID.
|
||||||
*
|
*
|
||||||
* @param twoBytes two bytes in a string.
|
* @param twoBytes two bytes in a string.
|
||||||
*
|
*
|
||||||
@ -876,8 +695,8 @@ tls.getCipherSuite = function(twoBytes) {
|
|||||||
var rval = null;
|
var rval = null;
|
||||||
for(var key in tls.CipherSuites) {
|
for(var key in tls.CipherSuites) {
|
||||||
var cs = tls.CipherSuites[key];
|
var cs = tls.CipherSuites[key];
|
||||||
if(cs[0] === twoBytes.charCodeAt(0) &&
|
if(cs.id[0] === twoBytes.charCodeAt(0) &&
|
||||||
cs[1] === twoBytes.charCodeAt(1)) {
|
cs.id[1] === twoBytes.charCodeAt(1)) {
|
||||||
rval = cs;
|
rval = cs;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -939,7 +758,7 @@ tls.handleHelloRequest = function(c, record, length) {
|
|||||||
tls.parseHelloMessage = function(c, record, length) {
|
tls.parseHelloMessage = function(c, record, length) {
|
||||||
var msg = null;
|
var msg = null;
|
||||||
|
|
||||||
var client = (c.entity == tls.ConnectionEnd.client);
|
var client = (c.entity === tls.ConnectionEnd.client);
|
||||||
|
|
||||||
// minimum of 38 bytes in message
|
// minimum of 38 bytes in message
|
||||||
if(length < 38) {
|
if(length < 38) {
|
||||||
@ -1050,7 +869,7 @@ tls.parseHelloMessage = function(c, record, length) {
|
|||||||
|
|
||||||
// cipher suite not supported
|
// cipher suite not supported
|
||||||
if(c.session.cipherSuite === null) {
|
if(c.session.cipherSuite === null) {
|
||||||
c.error(c, {
|
return c.error(c, {
|
||||||
message: 'No cipher suites in common.',
|
message: 'No cipher suites in common.',
|
||||||
send: true,
|
send: true,
|
||||||
alert: {
|
alert: {
|
||||||
@ -1087,18 +906,6 @@ tls.createSecurityParameters = function(c, msg) {
|
|||||||
|
|
||||||
// TODO: handle other options from server when more supported
|
// TODO: handle other options from server when more supported
|
||||||
|
|
||||||
// only AES CBC is presently supported, so just change the key length based
|
|
||||||
// on the chosen cipher suite
|
|
||||||
var keyLength;
|
|
||||||
switch(c.session.cipherSuite) {
|
|
||||||
case tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA:
|
|
||||||
keyLength = 16;
|
|
||||||
break;
|
|
||||||
case tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA:
|
|
||||||
keyLength = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get client and server randoms
|
// get client and server randoms
|
||||||
var client = (c.entity === tls.ConnectionEnd.client);
|
var client = (c.entity === tls.ConnectionEnd.client);
|
||||||
var msgRandom = msg.random.bytes();
|
var msgRandom = msg.random.bytes();
|
||||||
@ -1109,15 +916,15 @@ tls.createSecurityParameters = function(c, msg) {
|
|||||||
c.session.sp = {
|
c.session.sp = {
|
||||||
entity: c.entity,
|
entity: c.entity,
|
||||||
prf_algorithm: tls.PRFAlgorithm.tls_prf_sha256,
|
prf_algorithm: tls.PRFAlgorithm.tls_prf_sha256,
|
||||||
bulk_cipher_algorithm: tls.BulkCipherAlgorithm.aes,
|
bulk_cipher_algorithm: null,
|
||||||
cipher_type: tls.CipherType.block,
|
cipher_type: null,
|
||||||
enc_key_length: keyLength,
|
enc_key_length: null,
|
||||||
block_length: 16,
|
block_length: null,
|
||||||
fixed_iv_length: 16,
|
fixed_iv_length: null,
|
||||||
record_iv_length: 16,
|
record_iv_length: null,
|
||||||
mac_algorithm: tls.MACAlgorithm.hmac_sha1,
|
mac_algorithm: null,
|
||||||
mac_length: 20,
|
mac_length: null,
|
||||||
mac_key_length: 20,
|
mac_key_length: null,
|
||||||
compression_algorithm: c.session.compressionMethod,
|
compression_algorithm: c.session.compressionMethod,
|
||||||
pre_master_secret: null,
|
pre_master_secret: null,
|
||||||
master_secret: null,
|
master_secret: null,
|
||||||
@ -1277,26 +1084,28 @@ tls.handleClientHello = function(c, record, length) {
|
|||||||
data: tls.createCertificate(c)
|
data: tls.createCertificate(c)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// queue server key exchange
|
if(!c.fail) {
|
||||||
tls.queue(c, tls.createRecord({
|
// queue server key exchange
|
||||||
type: tls.ContentType.handshake,
|
|
||||||
data: tls.createServerKeyExchange(c)
|
|
||||||
}));
|
|
||||||
|
|
||||||
// request client certificate if set
|
|
||||||
if(c.verifyClient !== false) {
|
|
||||||
// queue certificate request
|
|
||||||
tls.queue(c, tls.createRecord({
|
tls.queue(c, tls.createRecord({
|
||||||
type: tls.ContentType.handshake,
|
type: tls.ContentType.handshake,
|
||||||
data: tls.createCertificateRequest(c)
|
data: tls.createServerKeyExchange(c)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// request client certificate if set
|
||||||
|
if(c.verifyClient !== false) {
|
||||||
|
// queue certificate request
|
||||||
|
tls.queue(c, tls.createRecord({
|
||||||
|
type: tls.ContentType.handshake,
|
||||||
|
data: tls.createCertificateRequest(c)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// queue server hello done
|
||||||
|
tls.queue(c, tls.createRecord({
|
||||||
|
type: tls.ContentType.handshake,
|
||||||
|
data: tls.createServerHelloDone(c)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue server hello done
|
|
||||||
tls.queue(c, tls.createRecord({
|
|
||||||
type: tls.ContentType.handshake,
|
|
||||||
data: tls.createServerHelloDone(c)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send records
|
// send records
|
||||||
@ -1517,7 +1326,7 @@ tls.handleClientKeyExchange = function(c, record, length) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var b = record.fragment;
|
var b = record.fragment;
|
||||||
msg = {
|
var msg = {
|
||||||
enc_pre_master_secret: readVector(b, 2).getBytes()
|
enc_pre_master_secret: readVector(b, 2).getBytes()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1678,7 +1487,7 @@ tls.handleCertificateVerify = function(c, record, length) {
|
|||||||
var msgBytes = b.bytes();
|
var msgBytes = b.bytes();
|
||||||
b.read += 4;
|
b.read += 4;
|
||||||
|
|
||||||
msg = {
|
var msg = {
|
||||||
signature: readVector(b, 2).getBytes()
|
signature: readVector(b, 2).getBytes()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1692,9 +1501,10 @@ tls.handleCertificateVerify = function(c, record, length) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
var cert = c.session.clientCertificate;
|
var cert = c.session.clientCertificate;
|
||||||
b = forge.pki.rsa.decrypt(
|
/*b = forge.pki.rsa.decrypt(
|
||||||
msg.signature, cert.publicKey, true, verify.length);
|
msg.signature, cert.publicKey, true, verify.length);
|
||||||
if(b !== verify) {
|
if(b !== verify) {*/
|
||||||
|
if(!cert.publicKey.verify(verify, msg.signature, 'NONE')) {
|
||||||
throw {
|
throw {
|
||||||
message: 'CertificateVerify signature does not match.'
|
message: 'CertificateVerify signature does not match.'
|
||||||
};
|
};
|
||||||
@ -1781,7 +1591,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
|||||||
// check for custom alert info
|
// check for custom alert info
|
||||||
if(ret || ret === 0) {
|
if(ret || ret === 0) {
|
||||||
// set custom message and alert description
|
// set custom message and alert description
|
||||||
if(ret.constructor == Object) {
|
if(typeof ret === 'object' && !forge.util.isArray(ret)) {
|
||||||
if(ret.message) {
|
if(ret.message) {
|
||||||
error.message = ret.message;
|
error.message = ret.message;
|
||||||
}
|
}
|
||||||
@ -1789,7 +1599,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
|||||||
error.alert.description = ret.alert;
|
error.alert.description = ret.alert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(ret.constructor == Number) {
|
else if(typeof ret === 'number') {
|
||||||
// set custom alert description
|
// set custom alert description
|
||||||
error.alert.description = ret;
|
error.alert.description = ret;
|
||||||
}
|
}
|
||||||
@ -1879,7 +1689,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
|||||||
* @param record the record.
|
* @param record the record.
|
||||||
*/
|
*/
|
||||||
tls.handleChangeCipherSpec = function(c, record) {
|
tls.handleChangeCipherSpec = function(c, record) {
|
||||||
if(record.fragment.getByte() != 0x01) {
|
if(record.fragment.getByte() !== 0x01) {
|
||||||
c.error(c, {
|
c.error(c, {
|
||||||
message: 'Invalid ChangeCipherSpec message received.',
|
message: 'Invalid ChangeCipherSpec message received.',
|
||||||
send: true,
|
send: true,
|
||||||
@ -2336,7 +2146,7 @@ var F3 = tls.handleApplicationData;
|
|||||||
var ctTable = [];
|
var ctTable = [];
|
||||||
ctTable[tls.ConnectionEnd.client] = [
|
ctTable[tls.ConnectionEnd.client] = [
|
||||||
// CC,AL,HS,AD
|
// CC,AL,HS,AD
|
||||||
/*SHE*/[__,__,F2,__],
|
/*SHE*/[__,F1,F2,__],
|
||||||
/*SCE*/[__,F1,F2,__],
|
/*SCE*/[__,F1,F2,__],
|
||||||
/*SKE*/[__,F1,F2,__],
|
/*SKE*/[__,F1,F2,__],
|
||||||
/*SCR*/[__,F1,F2,__],
|
/*SCR*/[__,F1,F2,__],
|
||||||
@ -2350,7 +2160,7 @@ ctTable[tls.ConnectionEnd.client] = [
|
|||||||
// map server current expect state and content type to function
|
// map server current expect state and content type to function
|
||||||
ctTable[tls.ConnectionEnd.server] = [
|
ctTable[tls.ConnectionEnd.server] = [
|
||||||
// CC,AL,HS,AD
|
// CC,AL,HS,AD
|
||||||
/*CHE*/[__,__,F2,__],
|
/*CHE*/[__,F1,F2,__],
|
||||||
/*CCE*/[__,F1,F2,__],
|
/*CCE*/[__,F1,F2,__],
|
||||||
/*CKE*/[__,F1,F2,__],
|
/*CKE*/[__,F1,F2,__],
|
||||||
/*CCV*/[__,F1,F2,__],
|
/*CCV*/[__,F1,F2,__],
|
||||||
@ -2476,7 +2286,7 @@ hsTable[tls.ConnectionEnd.server] = [
|
|||||||
*/
|
*/
|
||||||
tls.generateKeys = function(c, sp) {
|
tls.generateKeys = function(c, sp) {
|
||||||
// TLS_RSA_WITH_AES_128_CBC_SHA (required to be compliant with TLS 1.2) &
|
// TLS_RSA_WITH_AES_128_CBC_SHA (required to be compliant with TLS 1.2) &
|
||||||
// TLS_RSA_WITH_AES_128_CBC_SHA are the only cipher suites implemented
|
// TLS_RSA_WITH_AES_256_CBC_SHA are the only cipher suites implemented
|
||||||
// at present
|
// at present
|
||||||
|
|
||||||
// TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with
|
// TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with
|
||||||
@ -2601,7 +2411,7 @@ tls.createConnectionState = function(c) {
|
|||||||
compressionState: null,
|
compressionState: null,
|
||||||
compressFunction: function(record){return true;},
|
compressFunction: function(record){return true;},
|
||||||
updateSequenceNumber: function() {
|
updateSequenceNumber: function() {
|
||||||
if(mode.sequenceNumber[1] == 0xFFFFFFFF) {
|
if(mode.sequenceNumber[1] === 0xFFFFFFFF) {
|
||||||
mode.sequenceNumber[1] = 0;
|
mode.sequenceNumber[1] = 0;
|
||||||
++mode.sequenceNumber[0];
|
++mode.sequenceNumber[0];
|
||||||
}
|
}
|
||||||
@ -2676,57 +2486,18 @@ tls.createConnectionState = function(c) {
|
|||||||
|
|
||||||
// handle security parameters
|
// handle security parameters
|
||||||
if(c.session) {
|
if(c.session) {
|
||||||
// generate keys
|
|
||||||
var sp = c.session.sp;
|
var sp = c.session.sp;
|
||||||
sp.keys = tls.generateKeys(c, sp);
|
c.session.cipherSuite.initSecurityParameters(sp);
|
||||||
|
|
||||||
// mac setup
|
// generate keys
|
||||||
|
sp.keys = tls.generateKeys(c, sp);
|
||||||
state.read.macKey = client ?
|
state.read.macKey = client ?
|
||||||
sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key;
|
sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key;
|
||||||
state.write.macKey = client ?
|
state.write.macKey = client ?
|
||||||
sp.keys.client_write_MAC_key : sp.keys.server_write_MAC_key;
|
sp.keys.client_write_MAC_key : sp.keys.server_write_MAC_key;
|
||||||
state.read.macLength = state.write.macLength = sp.mac_length;
|
|
||||||
switch(sp.mac_algorithm) {
|
|
||||||
case tls.MACAlgorithm.hmac_sha1:
|
|
||||||
state.read.macFunction = state.write.macFunction = hmac_sha1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw {
|
|
||||||
message: 'Unsupported MAC algorithm.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// cipher setup
|
// cipher suite setup
|
||||||
switch(sp.bulk_cipher_algorithm) {
|
c.session.cipherSuite.initConnectionState(state, c, sp);
|
||||||
case tls.BulkCipherAlgorithm.aes:
|
|
||||||
state.read.cipherState = {
|
|
||||||
init: false,
|
|
||||||
cipher: forge.aes.createDecryptionCipher(client ?
|
|
||||||
sp.keys.server_write_key : sp.keys.client_write_key),
|
|
||||||
iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV
|
|
||||||
};
|
|
||||||
state.write.cipherState = {
|
|
||||||
init: false,
|
|
||||||
cipher: forge.aes.createEncryptionCipher(client ?
|
|
||||||
sp.keys.client_write_key : sp.keys.server_write_key),
|
|
||||||
iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV
|
|
||||||
};
|
|
||||||
state.read.cipherFunction = decrypt_aes_128_cbc_sha1;
|
|
||||||
state.write.cipherFunction = encrypt_aes_128_cbc_sha1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw {
|
|
||||||
message: 'Unsupported cipher algorithm.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
switch(sp.cipher_type) {
|
|
||||||
case tls.CipherType.block:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw {
|
|
||||||
message: 'Unsupported cipher type.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// compression setup
|
// compression setup
|
||||||
switch(sp.compression_algorithm) {
|
switch(sp.compression_algorithm) {
|
||||||
@ -2787,6 +2558,9 @@ tls.createRandom = function() {
|
|||||||
* @return the created record.
|
* @return the created record.
|
||||||
*/
|
*/
|
||||||
tls.createRecord = function(options) {
|
tls.createRecord = function(options) {
|
||||||
|
if(!options.data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
var record = {
|
var record = {
|
||||||
type: options.type,
|
type: options.type,
|
||||||
version: {
|
version: {
|
||||||
@ -2889,8 +2663,8 @@ tls.createClientHello = function(c) {
|
|||||||
var cipherSuites = forge.util.createBuffer();
|
var cipherSuites = forge.util.createBuffer();
|
||||||
for(var i = 0; i < c.cipherSuites.length; ++i) {
|
for(var i = 0; i < c.cipherSuites.length; ++i) {
|
||||||
var cs = c.cipherSuites[i];
|
var cs = c.cipherSuites[i];
|
||||||
cipherSuites.putByte(cs[0]);
|
cipherSuites.putByte(cs.id[0]);
|
||||||
cipherSuites.putByte(cs[1]);
|
cipherSuites.putByte(cs.id[1]);
|
||||||
}
|
}
|
||||||
var cSuites = cipherSuites.length();
|
var cSuites = cipherSuites.length();
|
||||||
|
|
||||||
@ -3007,8 +2781,8 @@ tls.createServerHello = function(c) {
|
|||||||
rval.putByte(tls.Version.minor); // minor version
|
rval.putByte(tls.Version.minor); // minor version
|
||||||
rval.putBytes(c.session.sp.server_random); // random time + bytes
|
rval.putBytes(c.session.sp.server_random); // random time + bytes
|
||||||
writeVector(rval, 1, forge.util.createBuffer(sessionId));
|
writeVector(rval, 1, forge.util.createBuffer(sessionId));
|
||||||
rval.putByte(c.session.cipherSuite[0]);
|
rval.putByte(c.session.cipherSuite.id[0]);
|
||||||
rval.putByte(c.session.cipherSuite[1]);
|
rval.putByte(c.session.cipherSuite.id[1]);
|
||||||
rval.putByte(c.session.compressionMethod);
|
rval.putByte(c.session.compressionMethod);
|
||||||
return rval;
|
return rval;
|
||||||
};
|
};
|
||||||
@ -3051,15 +2825,31 @@ tls.createCertificate = function(c) {
|
|||||||
if(cert !== null) {
|
if(cert !== null) {
|
||||||
try {
|
try {
|
||||||
// normalize cert to a chain of certificates
|
// normalize cert to a chain of certificates
|
||||||
if((Array.isArray && !Array.isArray(cert)) ||
|
if(!forge.util.isArray(cert)) {
|
||||||
cert.constructor !== Array) {
|
|
||||||
cert = [cert];
|
cert = [cert];
|
||||||
}
|
}
|
||||||
var asn1 = null;
|
var asn1 = null;
|
||||||
for(var i = 0; i < cert.length; ++i) {
|
for(var i = 0; i < cert.length; ++i) {
|
||||||
var der = forge.pki.pemToDer(cert);
|
var msg = forge.pem.decode(cert[i])[0];
|
||||||
|
if(msg.type !== 'CERTIFICATE' &&
|
||||||
|
msg.type !== 'X509 CERTIFICATE' &&
|
||||||
|
msg.type !== 'TRUSTED CERTIFICATE') {
|
||||||
|
throw {
|
||||||
|
message: 'Could not convert certificate from PEM; PEM header ' +
|
||||||
|
'type is not "CERTIFICATE", "X509 CERTIFICATE", or ' +
|
||||||
|
'"TRUSTED CERTIFICATE".',
|
||||||
|
headerType: msg.type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
throw {
|
||||||
|
message: 'Could not convert certificate from PEM; PEM is encrypted.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var der = forge.util.createBuffer(msg.body);
|
||||||
if(asn1 === null) {
|
if(asn1 === null) {
|
||||||
asn1 = forge.asn1.fromDer(der.bytes());
|
asn1 = forge.asn1.fromDer(der.bytes(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// certificate entry is itself a vector with 3 length bytes
|
// certificate entry is itself a vector with 3 length bytes
|
||||||
@ -3078,17 +2868,17 @@ tls.createCertificate = function(c) {
|
|||||||
else {
|
else {
|
||||||
c.session.serverCertificate = cert;
|
c.session.serverCertificate = cert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(ex) {
|
catch(ex) {
|
||||||
c.error(c, {
|
return c.error(c, {
|
||||||
message: 'Could not send certificate list.',
|
message: 'Could not send certificate list.',
|
||||||
cause: ex,
|
cause: ex,
|
||||||
send: true,
|
send: true,
|
||||||
alert: {
|
alert: {
|
||||||
level: tls.Alert.Level.fatal,
|
level: tls.Alert.Level.fatal,
|
||||||
description: tls.Alert.Description.bad_certificate
|
description: tls.Alert.Description.bad_certificate
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3259,7 +3049,7 @@ tls.getClientSignature = function(c, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b = forge.pki.rsa.encrypt(b, privateKey, 0x01);
|
b = privateKey.sign(b, null);
|
||||||
}
|
}
|
||||||
callback(c, b);
|
callback(c, b);
|
||||||
};
|
};
|
||||||
@ -3479,6 +3269,11 @@ tls.createFinished = function(c) {
|
|||||||
* @param record the record to queue.
|
* @param record the record to queue.
|
||||||
*/
|
*/
|
||||||
tls.queue = function(c, record) {
|
tls.queue = function(c, record) {
|
||||||
|
// error during record creation
|
||||||
|
if(!record) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if the record is a handshake record, update handshake hashes
|
// if the record is a handshake record, update handshake hashes
|
||||||
if(record.type === tls.ContentType.handshake) {
|
if(record.type === tls.ContentType.handshake) {
|
||||||
var bytes = record.fragment.bytes();
|
var bytes = record.fragment.bytes();
|
||||||
@ -3624,7 +3419,7 @@ tls.verifyCertificateChain = function(c, chain) {
|
|||||||
// call application callback
|
// call application callback
|
||||||
var ret = c.verify(c, vfd, depth, chain);
|
var ret = c.verify(c, vfd, depth, chain);
|
||||||
if(ret !== true) {
|
if(ret !== true) {
|
||||||
if(ret.constructor === Object) {
|
if(typeof ret === 'object' && !forge.util.isArray(ret)) {
|
||||||
// throw custom error
|
// throw custom error
|
||||||
var error = {
|
var error = {
|
||||||
message: 'The application rejected the certificate.',
|
message: 'The application rejected the certificate.',
|
||||||
@ -3654,7 +3449,7 @@ tls.verifyCertificateChain = function(c, chain) {
|
|||||||
}
|
}
|
||||||
catch(ex) {
|
catch(ex) {
|
||||||
// build tls error if not already customized
|
// build tls error if not already customized
|
||||||
if(ex.constructor !== Object) {
|
if(typeof ex !== 'object' || forge.util.isArray(ex)) {
|
||||||
ex = {
|
ex = {
|
||||||
send: true,
|
send: true,
|
||||||
alert: {
|
alert: {
|
||||||
@ -3771,8 +3566,7 @@ tls.createConnection = function(options) {
|
|||||||
var caStore = null;
|
var caStore = null;
|
||||||
if(options.caStore) {
|
if(options.caStore) {
|
||||||
// if CA store is an array, convert it to a CA store object
|
// if CA store is an array, convert it to a CA store object
|
||||||
if((Array.isArray && Array.isArray(options.caStore)) ||
|
if(forge.util.isArray(options.caStore)) {
|
||||||
options.caStore.constructor == Array) {
|
|
||||||
caStore = forge.pki.createCaStore(options.caStore);
|
caStore = forge.pki.createCaStore(options.caStore);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3788,8 +3582,9 @@ tls.createConnection = function(options) {
|
|||||||
var cipherSuites = options.cipherSuites || null;
|
var cipherSuites = options.cipherSuites || null;
|
||||||
if(cipherSuites === null) {
|
if(cipherSuites === null) {
|
||||||
cipherSuites = [];
|
cipherSuites = [];
|
||||||
cipherSuites.push(tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA);
|
for(var key in tls.CipherSuites) {
|
||||||
cipherSuites.push(tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA);
|
cipherSuites.push(tls.CipherSuites[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set default entity
|
// set default entity
|
||||||
@ -3934,8 +3729,8 @@ tls.createConnection = function(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// check record version
|
// check record version
|
||||||
if(c.record.version.major != tls.Version.major ||
|
if(c.record.version.major !== tls.Version.major ||
|
||||||
c.record.version.minor != tls.Version.minor) {
|
c.record.version.minor !== tls.Version.minor) {
|
||||||
c.error(c, {
|
c.error(c, {
|
||||||
message: 'Incompatible TLS version.',
|
message: 'Incompatible TLS version.',
|
||||||
send: true,
|
send: true,
|
||||||
@ -4198,14 +3993,18 @@ tls.createConnection = function(options) {
|
|||||||
/* TLS API */
|
/* TLS API */
|
||||||
forge.tls = forge.tls || {};
|
forge.tls = forge.tls || {};
|
||||||
|
|
||||||
|
// expose non-functions
|
||||||
|
for(var key in tls) {
|
||||||
|
if(typeof tls[key] !== 'function') {
|
||||||
|
forge.tls[key] = tls[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// expose prf_tls1 for testing
|
// expose prf_tls1 for testing
|
||||||
forge.tls.prf_tls1 = prf_TLS1;
|
forge.tls.prf_tls1 = prf_TLS1;
|
||||||
|
|
||||||
// expose TLS alerts
|
// expost sha1 hmac method
|
||||||
forge.tls.Alert = tls.Alert;
|
forge.tls.hmac_sha1 = hmac_sha1;
|
||||||
|
|
||||||
// expose cipher suites
|
|
||||||
forge.tls.CipherSuites = tls.CipherSuites;
|
|
||||||
|
|
||||||
// expose session cache creation
|
// expose session cache creation
|
||||||
forge.tls.createSessionCache = tls.createSessionCache;
|
forge.tls.createSessionCache = tls.createSessionCache;
|
||||||
@ -4313,20 +4112,11 @@ forge.tls.createConnection = tls.createConnection;
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'tls';
|
var name = 'tls';
|
||||||
var deps = [
|
|
||||||
'./aes',
|
|
||||||
'./asn1',
|
|
||||||
'./hmac',
|
|
||||||
'./md',
|
|
||||||
'./pki',
|
|
||||||
'./random',
|
|
||||||
'./util'
|
|
||||||
];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -4335,30 +4125,49 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./asn1',
|
||||||
|
'./hmac',
|
||||||
|
'./md',
|
||||||
|
'./pem',
|
||||||
|
'./pki',
|
||||||
|
'./random',
|
||||||
|
'./util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -254,12 +254,11 @@ forge.tls.wrapSocket = function(options) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'tlssocket';
|
var name = 'tlssocket';
|
||||||
var deps = ['./tls'];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -268,30 +267,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './tls'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
119
src/lib/util.js
119
src/lib/util.js
@ -37,6 +37,11 @@ else {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define isArray
|
||||||
|
util.isArray = Array.isArray || function(x) {
|
||||||
|
return Object.prototype.toString.call(x) === '[object Array]';
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a byte buffer.
|
* Constructor for a byte buffer.
|
||||||
*
|
*
|
||||||
@ -64,16 +69,19 @@ util.ByteBuffer.prototype.length = function() {
|
|||||||
* @return true if this buffer is empty, false if not.
|
* @return true if this buffer is empty, false if not.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.isEmpty = function() {
|
util.ByteBuffer.prototype.isEmpty = function() {
|
||||||
return (this.data.length - this.read) === 0;
|
return this.length() <= 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a byte in this buffer.
|
* Puts a byte in this buffer.
|
||||||
*
|
*
|
||||||
* @param b the byte to put.
|
* @param b the byte to put.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putByte = function(b) {
|
util.ByteBuffer.prototype.putByte = function(b) {
|
||||||
this.data += String.fromCharCode(b);
|
this.data += String.fromCharCode(b);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,6 +89,8 @@ util.ByteBuffer.prototype.putByte = function(b) {
|
|||||||
*
|
*
|
||||||
* @param b the byte to put.
|
* @param b the byte to put.
|
||||||
* @param n the number of bytes of value b to put.
|
* @param n the number of bytes of value b to put.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.fillWithByte = function(b, n) {
|
util.ByteBuffer.prototype.fillWithByte = function(b, n) {
|
||||||
b = String.fromCharCode(b);
|
b = String.fromCharCode(b);
|
||||||
@ -95,53 +105,68 @@ util.ByteBuffer.prototype.fillWithByte = function(b, n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.data = d;
|
this.data = d;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts bytes in this buffer.
|
* Puts bytes in this buffer.
|
||||||
*
|
*
|
||||||
* @param bytes the bytes (as a UTF-8 encoded string) to put.
|
* @param bytes the bytes (as a UTF-8 encoded string) to put.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putBytes = function(bytes) {
|
util.ByteBuffer.prototype.putBytes = function(bytes) {
|
||||||
this.data += bytes;
|
this.data += bytes;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a UTF-16 encoded string into this buffer.
|
* Puts a UTF-16 encoded string into this buffer.
|
||||||
*
|
*
|
||||||
* @param str the string to put.
|
* @param str the string to put.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putString = function(str) {
|
util.ByteBuffer.prototype.putString = function(str) {
|
||||||
this.data += util.encodeUtf8(str);
|
this.data += util.encodeUtf8(str);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 16-bit integer in this buffer in big-endian order.
|
* Puts a 16-bit integer in this buffer in big-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 16-bit integer.
|
* @param i the 16-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt16 = function(i) {
|
util.ByteBuffer.prototype.putInt16 = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
String.fromCharCode(i >> 8 & 0xFF) +
|
String.fromCharCode(i >> 8 & 0xFF) +
|
||||||
String.fromCharCode(i & 0xFF);
|
String.fromCharCode(i & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 24-bit integer in this buffer in big-endian order.
|
* Puts a 24-bit integer in this buffer in big-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 24-bit integer.
|
* @param i the 24-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt24 = function(i) {
|
util.ByteBuffer.prototype.putInt24 = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
String.fromCharCode(i >> 16 & 0xFF) +
|
String.fromCharCode(i >> 16 & 0xFF) +
|
||||||
String.fromCharCode(i >> 8 & 0xFF) +
|
String.fromCharCode(i >> 8 & 0xFF) +
|
||||||
String.fromCharCode(i & 0xFF);
|
String.fromCharCode(i & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 32-bit integer in this buffer in big-endian order.
|
* Puts a 32-bit integer in this buffer in big-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 32-bit integer.
|
* @param i the 32-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt32 = function(i) {
|
util.ByteBuffer.prototype.putInt32 = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
@ -149,35 +174,44 @@ util.ByteBuffer.prototype.putInt32 = function(i) {
|
|||||||
String.fromCharCode(i >> 16 & 0xFF) +
|
String.fromCharCode(i >> 16 & 0xFF) +
|
||||||
String.fromCharCode(i >> 8 & 0xFF) +
|
String.fromCharCode(i >> 8 & 0xFF) +
|
||||||
String.fromCharCode(i & 0xFF);
|
String.fromCharCode(i & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 16-bit integer in this buffer in little-endian order.
|
* Puts a 16-bit integer in this buffer in little-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 16-bit integer.
|
* @param i the 16-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt16Le = function(i) {
|
util.ByteBuffer.prototype.putInt16Le = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
String.fromCharCode(i & 0xFF) +
|
String.fromCharCode(i & 0xFF) +
|
||||||
String.fromCharCode(i >> 8 & 0xFF);
|
String.fromCharCode(i >> 8 & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 24-bit integer in this buffer in little-endian order.
|
* Puts a 24-bit integer in this buffer in little-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 24-bit integer.
|
* @param i the 24-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt24Le = function(i) {
|
util.ByteBuffer.prototype.putInt24Le = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
String.fromCharCode(i & 0xFF) +
|
String.fromCharCode(i & 0xFF) +
|
||||||
String.fromCharCode(i >> 8 & 0xFF) +
|
String.fromCharCode(i >> 8 & 0xFF) +
|
||||||
String.fromCharCode(i >> 16 & 0xFF);
|
String.fromCharCode(i >> 16 & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts a 32-bit integer in this buffer in little-endian order.
|
* Puts a 32-bit integer in this buffer in little-endian order.
|
||||||
*
|
*
|
||||||
* @param i the 32-bit integer.
|
* @param i the 32-bit integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt32Le = function(i) {
|
util.ByteBuffer.prototype.putInt32Le = function(i) {
|
||||||
this.data +=
|
this.data +=
|
||||||
@ -185,6 +219,7 @@ util.ByteBuffer.prototype.putInt32Le = function(i) {
|
|||||||
String.fromCharCode(i >> 8 & 0xFF) +
|
String.fromCharCode(i >> 8 & 0xFF) +
|
||||||
String.fromCharCode(i >> 16 & 0xFF) +
|
String.fromCharCode(i >> 16 & 0xFF) +
|
||||||
String.fromCharCode(i >> 24 & 0xFF);
|
String.fromCharCode(i >> 24 & 0xFF);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,6 +227,8 @@ util.ByteBuffer.prototype.putInt32Le = function(i) {
|
|||||||
*
|
*
|
||||||
* @param i the n-bit integer.
|
* @param i the n-bit integer.
|
||||||
* @param n the number of bits in the integer.
|
* @param n the number of bits in the integer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putInt = function(i, n) {
|
util.ByteBuffer.prototype.putInt = function(i, n) {
|
||||||
do {
|
do {
|
||||||
@ -199,15 +236,19 @@ util.ByteBuffer.prototype.putInt = function(i, n) {
|
|||||||
this.data += String.fromCharCode((i >> n) & 0xFF);
|
this.data += String.fromCharCode((i >> n) & 0xFF);
|
||||||
}
|
}
|
||||||
while(n > 0);
|
while(n > 0);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the given buffer into this buffer.
|
* Puts the given buffer into this buffer.
|
||||||
*
|
*
|
||||||
* @param buffer the buffer to put into this one.
|
* @param buffer the buffer to put into this one.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.putBuffer = function(buffer) {
|
util.ByteBuffer.prototype.putBuffer = function(buffer) {
|
||||||
this.data += buffer.getBytes();
|
this.data += buffer.getBytes();
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,7 +361,7 @@ util.ByteBuffer.prototype.getInt32Le = function() {
|
|||||||
util.ByteBuffer.prototype.getInt = function(n) {
|
util.ByteBuffer.prototype.getInt = function(n) {
|
||||||
var rval = 0;
|
var rval = 0;
|
||||||
do {
|
do {
|
||||||
rval = (rval << n) + this.data.charCodeAt(this.read++);
|
rval = (rval << 8) + this.data.charCodeAt(this.read++);
|
||||||
n -= 8;
|
n -= 8;
|
||||||
}
|
}
|
||||||
while(n > 0);
|
while(n > 0);
|
||||||
@ -383,11 +424,14 @@ util.ByteBuffer.prototype.at = function(i) {
|
|||||||
*
|
*
|
||||||
* @param i the byte index.
|
* @param i the byte index.
|
||||||
* @param b the byte to put.
|
* @param b the byte to put.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.setAt = function(i, b) {
|
util.ByteBuffer.prototype.setAt = function(i, b) {
|
||||||
this.data = this.data.substr(0, this.read + i) +
|
this.data = this.data.substr(0, this.read + i) +
|
||||||
String.fromCharCode(b) +
|
String.fromCharCode(b) +
|
||||||
this.data.substr(this.read + i + 1);
|
this.data.substr(this.read + i + 1);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,31 +456,40 @@ util.ByteBuffer.prototype.copy = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Compacts this buffer.
|
* Compacts this buffer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.compact = function() {
|
util.ByteBuffer.prototype.compact = function() {
|
||||||
if(this.read > 0) {
|
if(this.read > 0) {
|
||||||
this.data = this.data.slice(this.read);
|
this.data = this.data.slice(this.read);
|
||||||
this.read = 0;
|
this.read = 0;
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears this buffer.
|
* Clears this buffer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.clear = function() {
|
util.ByteBuffer.prototype.clear = function() {
|
||||||
this.data = '';
|
this.data = '';
|
||||||
this.read = 0;
|
this.read = 0;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortens this buffer by triming bytes off of the end of this buffer.
|
* Shortens this buffer by triming bytes off of the end of this buffer.
|
||||||
*
|
*
|
||||||
* @param count the number of bytes to trim off.
|
* @param count the number of bytes to trim off.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
*/
|
*/
|
||||||
util.ByteBuffer.prototype.truncate = function(count) {
|
util.ByteBuffer.prototype.truncate = function(count) {
|
||||||
var len = Math.max(0, this.length() - count);
|
var len = Math.max(0, this.length() - count);
|
||||||
this.data = this.data.substr(this.read, len);
|
this.data = this.data.substr(this.read, len);
|
||||||
this.read = 0;
|
this.read = 0;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1152,7 +1205,8 @@ util.getQueryVariables = function(query) {
|
|||||||
if(!(key in rval)) {
|
if(!(key in rval)) {
|
||||||
rval[key] = [];
|
rval[key] = [];
|
||||||
}
|
}
|
||||||
if(val !== null) {
|
// disallow overriding object prototype keys
|
||||||
|
if(!(key in Object.prototype) && val !== null) {
|
||||||
rval[key].push(unescape(val));
|
rval[key].push(unescape(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1535,12 +1589,11 @@ util.formatSize = function(size) {
|
|||||||
|
|
||||||
/* ########## Begin module wrapper ########## */
|
/* ########## Begin module wrapper ########## */
|
||||||
var name = 'util';
|
var name = 'util';
|
||||||
var deps = [];
|
|
||||||
var nodeDefine = null;
|
|
||||||
if(typeof define !== 'function') {
|
if(typeof define !== 'function') {
|
||||||
// NodeJS -> AMD
|
// NodeJS -> AMD
|
||||||
if(typeof module === 'object' && module.exports) {
|
if(typeof module === 'object' && module.exports) {
|
||||||
nodeDefine = function(ids, factory) {
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
factory(require, module);
|
factory(require, module);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1549,30 +1602,40 @@ if(typeof define !== 'function') {
|
|||||||
if(typeof forge === 'undefined') {
|
if(typeof forge === 'undefined') {
|
||||||
forge = {};
|
forge = {};
|
||||||
}
|
}
|
||||||
initModule(forge);
|
return initModule(forge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AMD
|
// AMD
|
||||||
if(nodeDefine || typeof define === 'function') {
|
var deps;
|
||||||
// define module AMD style
|
var defineFunc = function(require, module) {
|
||||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
module.exports = function(forge) {
|
||||||
function(require, module) {
|
var mods = deps.map(function(dep) {
|
||||||
module.exports = function(forge) {
|
return require(dep);
|
||||||
var mods = deps.map(function(dep) {
|
}).concat(initModule);
|
||||||
return require(dep);
|
// handle circular dependencies
|
||||||
}).concat(initModule);
|
forge = forge || {};
|
||||||
// handle circular dependencies
|
forge.defined = forge.defined || {};
|
||||||
forge = forge || {};
|
if(forge.defined[name]) {
|
||||||
forge.defined = forge.defined || {};
|
|
||||||
if(forge.defined[name]) {
|
|
||||||
return forge[name];
|
|
||||||
}
|
|
||||||
forge.defined[name] = true;
|
|
||||||
for(var i = 0; i < mods.length; ++i) {
|
|
||||||
mods[i](forge);
|
|
||||||
}
|
|
||||||
return forge[name];
|
return forge[name];
|
||||||
};
|
}
|
||||||
});
|
forge.defined[name] = true;
|
||||||
}
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -235,7 +235,7 @@ xhrApi.getCookie = function(name, path, domain) {
|
|||||||
if(rval === null) {
|
if(rval === null) {
|
||||||
rval = cookie;
|
rval = cookie;
|
||||||
}
|
}
|
||||||
else if(rval.constructor != Array) {
|
else if(!forge.util.isArray(rval)) {
|
||||||
rval = [rval, cookie];
|
rval = [rval, cookie];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -689,8 +689,8 @@ xhrApi.create = function(options) {
|
|||||||
_state.response = null;
|
_state.response = null;
|
||||||
|
|
||||||
// 6. if state is DONE or UNSENT, or if OPENED and send flag is false
|
// 6. if state is DONE or UNSENT, or if OPENED and send flag is false
|
||||||
if(xhr.readyState == DONE || xhr.readyState == UNSENT ||
|
if(xhr.readyState === DONE || xhr.readyState === UNSENT ||
|
||||||
(xhr.readyState == OPENED && !_state.sendFlag)) {
|
(xhr.readyState === OPENED && !_state.sendFlag)) {
|
||||||
// 7. set ready state to unsent
|
// 7. set ready state to unsent
|
||||||
xhr.readyState = UNSENT;
|
xhr.readyState = UNSENT;
|
||||||
}
|
}
|
||||||
@ -741,8 +741,8 @@ xhrApi.create = function(options) {
|
|||||||
if(_state.response !== null) {
|
if(_state.response !== null) {
|
||||||
if(header in _state.response.fields) {
|
if(header in _state.response.fields) {
|
||||||
rval = _state.response.fields[header];
|
rval = _state.response.fields[header];
|
||||||
if(rval.constructor == Array) {
|
if(forge.util.isArray(rval)) {
|
||||||
rval = rval.join();
|
rval = rval.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,13 @@ require(['../../src/require-config'], function() {
|
|||||||
|
|
||||||
function startTests() {
|
function startTests() {
|
||||||
require(['test/unit/forge-test',
|
require(['test/unit/forge-test',
|
||||||
'test/unit/aes-test',
|
'test/unit/aes-test',
|
||||||
'test/unit/rsa-test',
|
'test/unit/rsa-test',
|
||||||
'test/unit/lawnchair-dao-test',
|
'test/unit/lawnchair-dao-test',
|
||||||
'test/unit/keychain-dao-test',
|
'test/unit/keychain-dao-test',
|
||||||
'test/unit/crypto-test',
|
'test/unit/crypto-test',
|
||||||
'test/unit/devicestorage-dao-test',
|
'test/unit/devicestorage-dao-test',
|
||||||
'test/unit/email-dao-test'
|
'test/unit/email-dao-test'
|
||||||
], function() {
|
], function() {
|
||||||
//Tests loaded, run tests
|
//Tests loaded, run tests
|
||||||
QUnit.start();
|
QUnit.start();
|
||||||
|
Loading…
Reference in New Issue
Block a user