mirror of
https://github.com/moparisthebest/mail
synced 2024-11-25 18:32:20 -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);
|
||||
iNk++;
|
||||
}
|
||||
else if(Nk > 6 && (i % Nk == 4)) {
|
||||
else if(Nk > 6 && (i % Nk === 4)) {
|
||||
// temp = SubWord(temp)
|
||||
temp =
|
||||
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
|
||||
* 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
|
||||
* 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 output the buffer to write to.
|
||||
* @param decrypt true for decryption, false for encryption.
|
||||
* @param mode the cipher mode to use (default: 'CBC').
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
var _createCipher = function(key, iv, output, decrypt) {
|
||||
var _createCipher = function(key, iv, output, decrypt, mode) {
|
||||
var cipher = null;
|
||||
|
||||
if(!init) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
// default to CBC mode
|
||||
mode = (mode || 'CBC').toUpperCase();
|
||||
|
||||
/* 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
|
||||
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. */
|
||||
|
||||
// convert key string into byte buffer
|
||||
if(key.constructor == String &&
|
||||
(key.length == 16 || key.length == 24 || key.length == 32)) {
|
||||
if(typeof key === 'string' &&
|
||||
(key.length === 16 || key.length === 24 || key.length === 32)) {
|
||||
key = forge.util.createBuffer(key);
|
||||
}
|
||||
// convert key integer array into byte buffer
|
||||
else if(key.constructor == Array &&
|
||||
(key.length == 16 || key.length == 24 || key.length == 32)) {
|
||||
else if(forge.util.isArray(key) &&
|
||||
(key.length === 16 || key.length === 24 || key.length === 32)) {
|
||||
var tmp = key;
|
||||
var key = forge.util.createBuffer();
|
||||
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
|
||||
if(key.constructor != Array) {
|
||||
if(!forge.util.isArray(key)) {
|
||||
var tmp = key;
|
||||
key = [];
|
||||
|
||||
// key lengths of 16, 24, 32 bytes allowed
|
||||
var len = tmp.length();
|
||||
if(len == 16 || len == 24 || len == 32) {
|
||||
if(len === 16 || len === 24 || len === 32) {
|
||||
len = len >>> 2;
|
||||
for(var i = 0; i < len; ++i) {
|
||||
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
|
||||
if(key.constructor == Array &&
|
||||
(key.length == 4 || key.length == 6 || key.length == 8)) {
|
||||
// private vars for state
|
||||
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
|
||||
};
|
||||
if(!forge.util.isArray(key) ||
|
||||
!(key.length === 4 || key.length === 6 || key.length === 8)) {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the next block using CBC 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);
|
||||
}
|
||||
// (CFB/OFB/CTR always uses encryption)
|
||||
var alwaysEncrypt = (['CFB', 'OFB', 'CTR'].indexOf(mode) !== -1);
|
||||
|
||||
/* In encrypt mode, the threshold for updating a block is the
|
||||
block size. As soon as enough input is available to update
|
||||
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();
|
||||
}
|
||||
}
|
||||
// CBC mode requires padding
|
||||
var requirePadding = (mode === 'CBC');
|
||||
|
||||
// update block
|
||||
_updateBlock(_w, _inBlock, _outBlock, decrypt);
|
||||
// private vars for state
|
||||
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(decrypt) {
|
||||
// CBC mode XOR's IV (or previous block) with plaintext
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if(mode === 'CBC') {
|
||||
_op = cbcOp;
|
||||
}
|
||||
else if(mode === 'CFB') {
|
||||
_op = cfbOp;
|
||||
}
|
||||
else if(mode === 'OFB') {
|
||||
_op = ofbOp;
|
||||
}
|
||||
else if(mode === 'CTR') {
|
||||
_op = ctrOp;
|
||||
}
|
||||
else {
|
||||
throw {
|
||||
message: 'Unsupported block cipher mode of operation: "' + mode + '"'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// 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 */
|
||||
forge.aes = forge.aes || {};
|
||||
|
||||
/**
|
||||
* Creates an AES cipher object to encrypt data in CBC mode using the
|
||||
* given symmetric key. The output will be stored in the 'output' member
|
||||
* of the returned cipher.
|
||||
* Creates an AES cipher object to encrypt data using the given symmetric key.
|
||||
* The output will be stored in the 'output' member of the returned cipher.
|
||||
*
|
||||
* 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.
|
||||
@ -1053,16 +1158,16 @@ forge.aes = forge.aes || {};
|
||||
* @param key the symmetric key to use.
|
||||
* @param iv the initialization vector to use.
|
||||
* @param output the buffer to write to, null to create one.
|
||||
* @param mode the cipher mode to use (default: 'CBC').
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.aes.startEncrypting = function(key, iv, output) {
|
||||
return _createCipher(key, iv, output, false);
|
||||
forge.aes.startEncrypting = function(key, iv, output, mode) {
|
||||
return _createCipher(key, iv, output, false, mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AES cipher object to encrypt data in CBC mode using the
|
||||
* given symmetric key.
|
||||
* Creates an AES cipher object to encrypt data using the given symmetric key.
|
||||
*
|
||||
* The key may be given as a string of bytes, an array of bytes, a
|
||||
* byte buffer, or an array of 32-bit words.
|
||||
@ -1071,17 +1176,17 @@ forge.aes.startEncrypting = function(key, iv, output) {
|
||||
* output buffer.
|
||||
*
|
||||
* @param key the symmetric key to use.
|
||||
* @param mode the cipher mode to use (default: 'CBC').
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.aes.createEncryptionCipher = function(key) {
|
||||
return _createCipher(key, null, null, false);
|
||||
forge.aes.createEncryptionCipher = function(key, mode) {
|
||||
return _createCipher(key, null, null, false, mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AES cipher object to decrypt data in CBC mode using the
|
||||
* given symmetric key. The output will be stored in the 'output' member
|
||||
* of the returned cipher.
|
||||
* Creates an AES cipher object to decrypt data using the given symmetric key.
|
||||
* The output will be stored in the 'output' member of the returned cipher.
|
||||
*
|
||||
* 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.
|
||||
@ -1089,16 +1194,16 @@ forge.aes.createEncryptionCipher = function(key) {
|
||||
* @param key the symmetric key to use.
|
||||
* @param iv the initialization vector to use.
|
||||
* @param output the buffer to write to, null to create one.
|
||||
* @param mode the cipher mode to use (default: 'CBC').
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.aes.startDecrypting = function(key, iv, output) {
|
||||
return _createCipher(key, iv, output, true);
|
||||
forge.aes.startDecrypting = function(key, iv, output, mode) {
|
||||
return _createCipher(key, iv, output, true, mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AES cipher object to decrypt data in CBC mode using the
|
||||
* given symmetric key.
|
||||
* Creates an AES cipher object to decrypt data using the given symmetric key.
|
||||
*
|
||||
* The key may be given as a string of bytes, an array of bytes, a
|
||||
* byte buffer, or an array of 32-bit words.
|
||||
@ -1107,11 +1212,12 @@ forge.aes.startDecrypting = function(key, iv, output) {
|
||||
* optional output buffer.
|
||||
*
|
||||
* @param key the symmetric key to use.
|
||||
* @param mode the cipher mode to use (default: 'CBC').
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.aes.createDecryptionCipher = function(key) {
|
||||
return _createCipher(key, null, null, true);
|
||||
forge.aes.createDecryptionCipher = function(key, mode) {
|
||||
return _createCipher(key, null, null, true, mode);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1143,12 +1249,11 @@ forge.aes._updateBlock = _updateBlock;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'aes';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1157,30 +1262,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
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. */
|
||||
|
||||
// remove undefined values
|
||||
if(value.constructor == Array) {
|
||||
if(forge.util.isArray(value)) {
|
||||
var tmp = [];
|
||||
for(var i = 0; i < value.length; ++i) {
|
||||
if(value[i] !== undefined) {
|
||||
@ -210,7 +210,7 @@ asn1.create = function(tagClass, type, constructed, value) {
|
||||
tagClass: tagClass,
|
||||
type: type,
|
||||
constructed: constructed,
|
||||
composed: constructed || (value.constructor == Array),
|
||||
composed: constructed || forge.util.isArray(value),
|
||||
value: value
|
||||
};
|
||||
};
|
||||
@ -226,7 +226,7 @@ asn1.create = function(tagClass, type, constructed, value) {
|
||||
*/
|
||||
var _getValueLength = function(b) {
|
||||
var b2 = b.getByte();
|
||||
if(b2 == 0x80) {
|
||||
if(b2 === 0x80) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -249,12 +249,18 @@ var _getValueLength = function(b) {
|
||||
* Parses an asn1 object from a byte buffer in DER format.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
asn1.fromDer = function(bytes) {
|
||||
asn1.fromDer = function(bytes, strict) {
|
||||
if(strict === undefined) {
|
||||
strict = true;
|
||||
}
|
||||
|
||||
// wrap in buffer if needed
|
||||
if(bytes.constructor == String) {
|
||||
if(typeof bytes === 'string') {
|
||||
bytes = forge.util.createBuffer(bytes);
|
||||
}
|
||||
|
||||
@ -280,17 +286,21 @@ asn1.fromDer = function(bytes) {
|
||||
|
||||
// ensure there are enough bytes to get the value
|
||||
if(bytes.length() < length) {
|
||||
throw {
|
||||
message: 'Too few bytes to read ASN.1 value.',
|
||||
detail: bytes.length() + ' < ' + length
|
||||
};
|
||||
if(strict) {
|
||||
throw {
|
||||
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
|
||||
var value;
|
||||
|
||||
// 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
|
||||
// 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
|
||||
b1 = bytes.getByte();
|
||||
var tc = (b1 & 0xC0);
|
||||
if(tc === asn1.Class.UNIVERSAL ||
|
||||
tc === asn1.Class.CONTEXT_SPECIFIC) {
|
||||
if(tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC) {
|
||||
try {
|
||||
var len = _getValueLength(bytes);
|
||||
composed = (len === length - (bytes.read - read));
|
||||
@ -339,14 +348,14 @@ asn1.fromDer = function(bytes) {
|
||||
bytes.getBytes(2);
|
||||
break;
|
||||
}
|
||||
value.push(asn1.fromDer(bytes));
|
||||
value.push(asn1.fromDer(bytes, strict));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// parsing asn1 object of definite length
|
||||
var start = bytes.length();
|
||||
while(length > 0) {
|
||||
value.push(asn1.fromDer(bytes));
|
||||
value.push(asn1.fromDer(bytes, strict));
|
||||
length -= start - bytes.length();
|
||||
start = bytes.length();
|
||||
}
|
||||
@ -520,7 +529,7 @@ asn1.derToOid = function(bytes) {
|
||||
var oid;
|
||||
|
||||
// wrap in buffer if needed
|
||||
if(bytes.constructor == String) {
|
||||
if(typeof bytes === 'string') {
|
||||
bytes = forge.util.createBuffer(bytes);
|
||||
}
|
||||
|
||||
@ -678,7 +687,7 @@ asn1.generalizedTimeToDate = function(gentime) {
|
||||
var offset = 0;
|
||||
var isUTC = false;
|
||||
|
||||
if(gentime.charAt(gentime.length - 1) == 'Z') {
|
||||
if(gentime.charAt(gentime.length - 1) === 'Z') {
|
||||
isUTC = true;
|
||||
}
|
||||
|
||||
@ -701,7 +710,7 @@ asn1.generalizedTimeToDate = function(gentime) {
|
||||
}
|
||||
|
||||
// check for second fraction
|
||||
if(gentime.charAt(14) == '.') {
|
||||
if(gentime.charAt(14) === '.') {
|
||||
fff = parseFloat(gentime.substr(14), 10) * 1000;
|
||||
}
|
||||
|
||||
@ -788,7 +797,7 @@ asn1.validate = function(obj, v, capture, errors) {
|
||||
rval = true;
|
||||
|
||||
// handle sub values
|
||||
if(v.value && v.value.constructor == Array) {
|
||||
if(v.value && forge.util.isArray(v.value)) {
|
||||
var j = 0;
|
||||
for(var i = 0; rval && i < v.value.length; ++i) {
|
||||
rval = v.value[i].optional || false;
|
||||
@ -1012,12 +1021,11 @@ asn1.prettyPrint = function(obj, level, indentation) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'asn1';
|
||||
var deps = ['./util', './oids'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1026,30 +1034,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './oids'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -87,12 +87,11 @@ forge.debug.clear = function(cat, name) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'debug';
|
||||
var deps = [];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -101,30 +100,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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'], 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 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.
|
||||
*
|
||||
@ -123,9 +121,6 @@ function des_createKeys (key) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an DES cipher object.
|
||||
*
|
||||
@ -134,9 +129,8 @@ function des_createKeys (key) {
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
var _createCipher = function(key, encrypt)
|
||||
{
|
||||
if(key.constructor == String && (key.length == 8 || key.length == 24)) {
|
||||
var _createCipher = function(key, encrypt) {
|
||||
if(typeof key === 'string' && (key.length === 8 || key.length === 24)) {
|
||||
key = forge.util.createBuffer(key);
|
||||
}
|
||||
|
||||
@ -155,10 +149,10 @@ var _createCipher = function(key, encrypt)
|
||||
var _finish = false, _input = null, _output = null;
|
||||
|
||||
/* 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;
|
||||
|
||||
if(iterations == 3) {
|
||||
if(iterations === 3) {
|
||||
looping = encrypt
|
||||
? [0, 32, 2]
|
||||
: [30, -2, -2];
|
||||
@ -183,7 +177,7 @@ var _createCipher = function(key, encrypt)
|
||||
*/
|
||||
start: function(iv, output) {
|
||||
if(iv) {
|
||||
if(key.constructor == String && iv.length == 8) {
|
||||
if(typeof iv === 'string' && iv.length === 8) {
|
||||
iv = forge.util.createBuffer(iv);
|
||||
}
|
||||
|
||||
@ -221,7 +215,7 @@ var _createCipher = function(key, encrypt)
|
||||
var right = _input.getInt32();
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if(mode == 1) {
|
||||
if(mode === 1) {
|
||||
if(encrypt) {
|
||||
left ^= cbcleft;
|
||||
right ^= cbcright;
|
||||
@ -275,7 +269,7 @@ var _createCipher = function(key, encrypt)
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if(mode == 1) {
|
||||
if(mode === 1) {
|
||||
if(encrypt) {
|
||||
cbcleft = left;
|
||||
cbcright = right;
|
||||
@ -307,7 +301,7 @@ var _createCipher = function(key, encrypt)
|
||||
} else {
|
||||
// add PKCS#7 padding to block (each pad byte is the
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -362,8 +356,7 @@ forge.des = forge.des || {};
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.des.startEncrypting = function(key, iv, output)
|
||||
{
|
||||
forge.des.startEncrypting = function(key, iv, output) {
|
||||
var cipher = _createCipher(key, true);
|
||||
cipher.start(iv, output);
|
||||
return cipher;
|
||||
@ -382,8 +375,7 @@ forge.des.startEncrypting = function(key, iv, output)
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.des.createEncryptionCipher = function(key)
|
||||
{
|
||||
forge.des.createEncryptionCipher = function(key) {
|
||||
return _createCipher(key, true);
|
||||
};
|
||||
|
||||
@ -400,8 +392,7 @@ forge.des.createEncryptionCipher = function(key)
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.des.startDecrypting = function(key, iv, output)
|
||||
{
|
||||
forge.des.startDecrypting = function(key, iv, output) {
|
||||
var cipher = _createCipher(key, false);
|
||||
cipher.start(iv, output);
|
||||
return cipher;
|
||||
@ -420,8 +411,7 @@ forge.des.startDecrypting = function(key, iv, output)
|
||||
*
|
||||
* @return the cipher.
|
||||
*/
|
||||
forge.des.createDecryptionCipher = function(key)
|
||||
{
|
||||
forge.des.createDecryptionCipher = function(key) {
|
||||
return _createCipher(key, false);
|
||||
};
|
||||
|
||||
@ -429,12 +419,11 @@ forge.des.createDecryptionCipher = function(key)
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'des';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -443,30 +432,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
@ -6,15 +6,71 @@
|
||||
* Copyright 2011-2013 Digital Bazaar, Inc.
|
||||
*/
|
||||
(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',
|
||||
'./aesCipherSuites',
|
||||
'./asn1',
|
||||
'./debug',
|
||||
'./des',
|
||||
'./hmac',
|
||||
'./log',
|
||||
'./pbkdf2',
|
||||
'./pem',
|
||||
'./pkcs7',
|
||||
'./pkcs1',
|
||||
'./pkcs12',
|
||||
'./pki',
|
||||
'./prng',
|
||||
@ -26,35 +82,7 @@ var deps = [
|
||||
'./util',
|
||||
'./md',
|
||||
'./mgf1'
|
||||
];
|
||||
var cjsDefine = null;
|
||||
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;
|
||||
});
|
||||
}
|
||||
], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -45,7 +45,7 @@ hmac.create = function() {
|
||||
*/
|
||||
ctx.start = function(md, key) {
|
||||
if(md !== null) {
|
||||
if(md.constructor == String) {
|
||||
if(typeof md === 'string') {
|
||||
// create builtin message digest
|
||||
md = md.toLowerCase();
|
||||
if(md in forge.md.algorithms) {
|
||||
@ -67,11 +67,11 @@ hmac.create = function() {
|
||||
}
|
||||
else {
|
||||
// convert string into byte buffer
|
||||
if(key.constructor == String) {
|
||||
if(typeof key === 'string') {
|
||||
key = forge.util.createBuffer(key);
|
||||
}
|
||||
// convert byte array into byte buffer
|
||||
else if(key.constructor == Array) {
|
||||
else if(forge.util.isArray(key)) {
|
||||
var tmp = key;
|
||||
key = forge.util.createBuffer();
|
||||
for(var i = 0; i < tmp.length; ++i) {
|
||||
@ -153,12 +153,11 @@ hmac.create = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'hmac';
|
||||
var deps = ['./md', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -167,30 +166,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './md', './util'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -901,6 +901,9 @@ http.createRequest = function(options) {
|
||||
|
||||
// add custom headers
|
||||
var headers = options.headers || [];
|
||||
if(!forge.util.isArray(headers)) {
|
||||
headers = [headers];
|
||||
}
|
||||
for(var i = 0; i < headers.length; ++i) {
|
||||
for(var name in headers[i]) {
|
||||
request.appendField(name, headers[i][name]);
|
||||
@ -1202,7 +1205,7 @@ http.createResponse = function() {
|
||||
if(contentLength !== null && contentLength >= 0) {
|
||||
response.body = response.body || '';
|
||||
response.body += b.getBytes(contentLength);
|
||||
response.bodyReceived = (response.body.length == contentLength);
|
||||
response.bodyReceived = (response.body.length === contentLength);
|
||||
}
|
||||
// read chunked encoding
|
||||
else if(transferEncoding !== null) {
|
||||
@ -1372,7 +1375,7 @@ http.withinCookieDomain = function(url, cookie) {
|
||||
var rval = false;
|
||||
|
||||
// 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;
|
||||
|
||||
// any domain will do
|
||||
@ -1382,7 +1385,7 @@ http.withinCookieDomain = function(url, cookie) {
|
||||
// ensure domain starts with a '.'
|
||||
else if(domain.charAt(0) === '.') {
|
||||
// parse URL as necessary
|
||||
if(url.constructor == String) {
|
||||
if(typeof url === 'string') {
|
||||
url = http.parseUrl(url);
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ function bnCompareTo(a) {
|
||||
if(r != 0) return r;
|
||||
var i = this.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;
|
||||
return 0;
|
||||
}
|
||||
@ -1271,12 +1271,11 @@ forge.jsbn.BigInteger = BigInteger;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'jsbn';
|
||||
var deps = [];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1285,30 +1284,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -325,12 +325,11 @@ forge.log.consoleLogger = sConsoleLogger;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'log';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -339,30 +338,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
@ -23,12 +23,11 @@ forge.md.sha256 = forge.sha256;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'md';
|
||||
var deps = ['./md5', './sha1', './sha256'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -37,30 +36,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './md5', './sha1', './sha256'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -157,6 +157,8 @@ md5.create = function() {
|
||||
|
||||
/**
|
||||
* Starts the digest.
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.start = function() {
|
||||
md.messageLength = 0;
|
||||
@ -167,6 +169,7 @@ md5.create = function() {
|
||||
h2: 0x98BADCFE,
|
||||
h3: 0x10325476
|
||||
};
|
||||
return md;
|
||||
};
|
||||
// start digest automatically for first time
|
||||
md.start();
|
||||
@ -178,6 +181,8 @@ md5.create = function() {
|
||||
*
|
||||
* @param msg the message input to update with.
|
||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.update = function(msg, encoding) {
|
||||
if(encoding === 'utf8') {
|
||||
@ -197,6 +202,8 @@ md5.create = function() {
|
||||
if(_input.read > 2048 || _input.length() === 0) {
|
||||
_input.compact();
|
||||
}
|
||||
|
||||
return md;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -260,12 +267,11 @@ md5.create = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'md5';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -274,30 +280,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
@ -16,12 +16,11 @@ forge.mgf.mgf1 = forge.mgf1;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'mgf';
|
||||
var deps = ['./mgf1'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -30,30 +29,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './mgf1'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -57,12 +57,11 @@ mgf1.create = function(md) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'mgf1';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -71,30 +70,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
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['rsaEncryption'] = '1.2.840.113549.1.1.1';
|
||||
// Note: md2 & md4 not implemented
|
||||
//oids['1.2.840.113549.1.1.2'] = 'md2withRSAEncryption';
|
||||
//oids['md2withRSAEncryption'] = '1.2.840.113549.1.1.2';
|
||||
//oids['1.2.840.113549.1.1.3'] = 'md4withRSAEncryption';
|
||||
//oids['md4withRSAEncryption'] = '1.2.840.113549.1.1.3';
|
||||
oids['1.2.840.113549.1.1.4'] = 'md5withRSAEncryption';
|
||||
oids['md5withRSAEncryption'] = '1.2.840.113549.1.1.4';
|
||||
oids['1.2.840.113549.1.1.5'] = 'sha1withRSAEncryption';
|
||||
oids['sha1withRSAEncryption'] = '1.2.840.113549.1.1.5';
|
||||
//oids['1.2.840.113549.1.1.2'] = 'md2WithRSAEncryption';
|
||||
//oids['md2WithRSAEncryption'] = '1.2.840.113549.1.1.2';
|
||||
//oids['1.2.840.113549.1.1.3'] = 'md4WithRSAEncryption';
|
||||
//oids['md4WithRSAEncryption'] = '1.2.840.113549.1.1.3';
|
||||
oids['1.2.840.113549.1.1.4'] = 'md5WithRSAEncryption';
|
||||
oids['md5WithRSAEncryption'] = '1.2.840.113549.1.1.4';
|
||||
oids['1.2.840.113549.1.1.5'] = 'sha1WithRSAEncryption';
|
||||
oids['sha1WithRSAEncryption'] = '1.2.840.113549.1.1.5';
|
||||
oids['1.2.840.113549.1.1.7'] = 'RSAES-OAEP';
|
||||
oids['RSAES-OAEP'] = '1.2.840.113549.1.1.7';
|
||||
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';
|
||||
|
||||
// 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['friendlyName'] = '1.2.840.113549.1.9.20';
|
||||
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['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
|
||||
oids['1.2.840.113549.1.12.10.1.1'] = 'keyBag';
|
||||
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['2.5.4.11'] = 'organizationalUnitName';
|
||||
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
|
||||
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.2'] = 'keyAttributes'; // obsolete use .37 or .15
|
||||
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.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
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'oids';
|
||||
var deps = [];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -205,30 +226,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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'], 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.
|
||||
*/
|
||||
pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
||||
forge.pbkdf2 = pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
||||
// default prf to SHA-1
|
||||
if(typeof(md) === 'undefined' || md === null) {
|
||||
md = forge.md.sha1.create();
|
||||
@ -110,12 +110,11 @@ pkcs5.pbkdf2 = function(p, s, c, dkLen, md) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'pbkdf2';
|
||||
var deps = ['./hmac', './md', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -124,30 +123,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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.
|
||||
*
|
||||
* @param safeContents The SafeContents structure to search in.
|
||||
* @param attrName The name of the attribute to compare against.
|
||||
* @param attrValue The attribute value to search for.
|
||||
* @param bagType Optional bag type to narrow search by.
|
||||
* @return Array of matching bags
|
||||
* @param safeContents the SafeContents structure to search in.
|
||||
* @param attrName the name of the attribute to compare against.
|
||||
* @param attrValue the attribute value to search for.
|
||||
* @param [bagType] bag type to narrow search by.
|
||||
*
|
||||
* @return an array of matching bags.
|
||||
*/
|
||||
function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
||||
var result = [];
|
||||
@ -282,7 +283,7 @@ function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) {
|
||||
}
|
||||
|
||||
if(bag.attributes[attrName] !== undefined &&
|
||||
bag.attributes[attrName].indexOf(attrValue) >= 0) {
|
||||
bag.attributes[attrName].indexOf(attrValue) >= 0) {
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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
|
||||
var capture = {};
|
||||
var errors = [];
|
||||
@ -316,27 +327,69 @@ p12.pkcs12FromAsn1 = function(obj, password) {
|
||||
safeContents: [],
|
||||
|
||||
/**
|
||||
* Get bags with matching friendlyName attribute
|
||||
* Gets bags with matching attributes.
|
||||
*
|
||||
* @param friendlyName The friendly name to search for
|
||||
* @param bagType Optional bag type to narrow search by
|
||||
* @return Array of bags with matching friendlyName attribute
|
||||
* @param filter the attributes to filter by:
|
||||
* [localKeyId] the localKeyId to search for.
|
||||
* [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) {
|
||||
return _getBagsByAttribute(pfx.safeContents, 'friendlyName',
|
||||
friendlyName, bagType);
|
||||
getBags: function(filter) {
|
||||
var rval = {};
|
||||
|
||||
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
|
||||
* @param bagType Optional bag type to narrow search by
|
||||
* @return Array of bags with matching localKeyId attribute
|
||||
* Get bags with matching friendlyName 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) {
|
||||
return _getBagsByAttribute(pfx.safeContents, 'localKeyId',
|
||||
localKeyId, bagType);
|
||||
return _getBagsByAttribute(
|
||||
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;
|
||||
};
|
||||
|
||||
@ -422,12 +475,12 @@ p12.pkcs12FromAsn1 = function(obj, password) {
|
||||
* The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo.
|
||||
*
|
||||
* @param pfx The PKCS#12 PFX object to fill.
|
||||
* @param {String} authSafe BER-encoded AuthenticatedSafe
|
||||
* @param {String} password Password to decrypt with (optional)
|
||||
* @return void
|
||||
* @param {String} authSafe BER-encoded AuthenticatedSafe.
|
||||
* @param strict true to use strict DER decoding, false not to.
|
||||
* @param {String} password Password to decrypt with (optional).
|
||||
*/
|
||||
function _decodeAuthenticatedSafe(pfx, authSafe, password) {
|
||||
authSafe = asn1.fromDer(authSafe); /* actually it's BER encoded */
|
||||
function _decodeAuthenticatedSafe(pfx, authSafe, strict, password) {
|
||||
authSafe = asn1.fromDer(authSafe, strict); /* actually it's BER encoded */
|
||||
|
||||
if(authSafe.tagClass !== asn1.Class.UNIVERSAL ||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -537,16 +590,19 @@ function _decryptSafeContents(data, password) {
|
||||
*
|
||||
* The safeContents is a BER-encoded SEQUENCE OF SafeBag
|
||||
*
|
||||
* @param {String} safeContents BER-encoded safeContents
|
||||
* @param {String} password Password to decrypt with (optional)
|
||||
* @param {String} safeContents BER-encoded safeContents.
|
||||
* @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.
|
||||
*/
|
||||
function _decodeSafeContents(safeContents, password) {
|
||||
safeContents = asn1.fromDer(safeContents); /* actually it's BER-encoded. */
|
||||
function _decodeSafeContents(safeContents, strict, password) {
|
||||
// actually it's BER-encoded
|
||||
safeContents = asn1.fromDer(safeContents, strict);
|
||||
|
||||
if(safeContents.tagClass !== asn1.Class.UNIVERSAL ||
|
||||
safeContents.type !== asn1.Type.SEQUENCE ||
|
||||
safeContents.constructed !== true) {
|
||||
safeContents.type !== asn1.Type.SEQUENCE ||
|
||||
safeContents.constructed !== true) {
|
||||
throw {
|
||||
message: 'PKCS#12 SafeContents expected to be a ' +
|
||||
'SEQUENCE OF SafeBag'
|
||||
@ -603,7 +659,7 @@ function _decodeSafeContents(safeContents, password) {
|
||||
continue; /* Nothing more to do. */
|
||||
|
||||
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
|
||||
capture the fields. Afterwards check & store the results. */
|
||||
validator = certBagValidator;
|
||||
@ -615,8 +671,9 @@ function _decodeSafeContents(safeContents, password) {
|
||||
};
|
||||
}
|
||||
|
||||
// true=produce cert hash
|
||||
bag.cert = pki.certificateFromAsn1(
|
||||
asn1.fromDer(capture.cert), true);
|
||||
asn1.fromDer(capture.cert, strict), true);
|
||||
};
|
||||
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)
|
||||
* @return the decoded attributes
|
||||
* @param attributes SET OF PKCS12Attribute (ASN.1 object).
|
||||
*
|
||||
* @return the decoded attributes.
|
||||
*/
|
||||
function _decodeBagAttributes(attributes) {
|
||||
var decodedAttrs = {};
|
||||
|
||||
if(attributes !== undefined) {
|
||||
for(var i = 0; i < attributes.length; i ++) {
|
||||
for(var i = 0; i < attributes.length; ++i) {
|
||||
var capture = {};
|
||||
var errors = [];
|
||||
if(!asn1.validate(attributes[i], attributeValidator, capture, errors)) {
|
||||
@ -668,9 +726,9 @@ function _decodeBagAttributes(attributes) {
|
||||
// unsupported attribute type, ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -696,12 +754,13 @@ function _decodeBagAttributes(attributes) {
|
||||
* to specify a certificate chain).
|
||||
* @param password the password to use.
|
||||
* @param options:
|
||||
* encAlgorithm the encryption algorithm to use
|
||||
* algorithm the encryption algorithm to use
|
||||
* ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'.
|
||||
* count the iteration count to use.
|
||||
* saltSize the salt size to use.
|
||||
* useMac true to include a MAC, false not to, defaults to true.
|
||||
* localKeyId the local key ID to use, in hex.
|
||||
* friendlyName the friendly name to use.
|
||||
* generateLocalKeyId true to generate a random local key ID,
|
||||
* false not to, defaults to true.
|
||||
*
|
||||
@ -712,7 +771,7 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
||||
options = options || {};
|
||||
options.saltSize = options.saltSize || 8;
|
||||
options.count = options.count || 2048;
|
||||
options.encAlgorithm = options.encAlgorithm || 'aes128';
|
||||
options.algorithm = options.algorithm || options.encAlgorithm || 'aes128';
|
||||
if(!('useMac' in options)) {
|
||||
options.useMac = true;
|
||||
}
|
||||
@ -729,12 +788,27 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
||||
localKeyId = forge.util.hexToBytes(localKeyId);
|
||||
}
|
||||
else if(options.generateLocalKeyId) {
|
||||
// set localKeyId and friendlyName (if specified)
|
||||
localKeyId = forge.random.getBytes(20);
|
||||
// use SHA-1 of paired cert, if available
|
||||
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) {
|
||||
var attrs = [
|
||||
attrs.push(
|
||||
// localKeyID
|
||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||
// attrId
|
||||
@ -745,76 +819,34 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
||||
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
|
||||
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);
|
||||
}
|
||||
|
||||
// collect contents for AuthenticatedSafe
|
||||
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
|
||||
var chain = [];
|
||||
if(cert !== null) {
|
||||
if((Array.isArray && Array.isArray(cert)) || cert.constructor === Array) {
|
||||
if(forge.util.isArray(cert)) {
|
||||
chain = cert;
|
||||
}
|
||||
else {
|
||||
@ -880,6 +912,64 @@ p12.toPkcs12Asn1 = function(key, cert, password, options) {
|
||||
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
|
||||
var safe = asn1.create(
|
||||
asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, contents);
|
||||
@ -1059,20 +1149,11 @@ p12.generateKey = function(password, salt, id, iter, n, md) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'pkcs12';
|
||||
var deps = [
|
||||
'./asn1',
|
||||
'./sha1',
|
||||
'./pkcs7asn1',
|
||||
'./pki',
|
||||
'./util',
|
||||
'./random',
|
||||
'./hmac'
|
||||
];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1081,30 +1162,50 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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',
|
||||
'./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.
|
||||
*/
|
||||
p7.messageFromPem = function(pem) {
|
||||
var der = forge.pki.pemToDer(pem);
|
||||
var obj = asn1.fromDer(der);
|
||||
var msg = forge.pem.decode(pem)[0];
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
@ -47,12 +63,12 @@ p7.messageFromPem = function(pem) {
|
||||
* @return The PEM-formatted PKCS#7 message.
|
||||
*/
|
||||
p7.messageToPem = function(msg, maxline) {
|
||||
var out = asn1.toDer(msg.toAsn1());
|
||||
out = forge.util.encode64(out.getBytes(), maxline || 64);
|
||||
return (
|
||||
'-----BEGIN PKCS7-----\r\n' +
|
||||
out +
|
||||
'\r\n-----END PKCS7-----');
|
||||
// convert to ASN.1, then DER, then PEM-encode
|
||||
var pemObj = {
|
||||
type: 'PKCS7',
|
||||
body: asn1.toDer(msg.toAsn1()).getBytes()
|
||||
};
|
||||
return forge.pem.encode(pemObj, {maxline: maxline});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -266,7 +282,7 @@ var _fromAsn1 = function(msg, obj, validator) {
|
||||
|
||||
if(capture.encContent) {
|
||||
var content = '';
|
||||
if(capture.encContent.constructor === Array) {
|
||||
if(forge.util.isArray(capture.encContent)) {
|
||||
for(var i = 0; i < capture.encContent.length; ++i) {
|
||||
if(capture.encContent[i].type !== asn1.Type.OCTETSTRING) {
|
||||
throw {
|
||||
@ -289,7 +305,7 @@ var _fromAsn1 = function(msg, obj, validator) {
|
||||
|
||||
if(capture.content) {
|
||||
var content = '';
|
||||
if(capture.content.constructor === Array) {
|
||||
if(forge.util.isArray(capture.content)) {
|
||||
for(var i = 0; i < capture.content.length; ++i) {
|
||||
if(capture.content[i].type !== asn1.Type.OCTETSTRING) {
|
||||
throw {
|
||||
@ -659,20 +675,11 @@ p7.createEnvelopedData = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'pkcs7';
|
||||
var deps = [
|
||||
'./aes',
|
||||
'./asn1',
|
||||
'./des',
|
||||
'./pkcs7asn1',
|
||||
'./pki',
|
||||
'./random',
|
||||
'./util'
|
||||
];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -681,30 +688,51 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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',
|
||||
'./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 ########## */
|
||||
var name = 'pkcs7asn1';
|
||||
var deps = ['./asn1', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -360,30 +359,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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 ########## */
|
||||
function initModule(forge) {
|
||||
|
||||
var _nodejs = (typeof module === 'object' && module.exports);
|
||||
var _nodejs = (
|
||||
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||
var crypto = null;
|
||||
if(_nodejs) {
|
||||
if(!forge.disableNativeCode && _nodejs) {
|
||||
crypto = require('crypto');
|
||||
}
|
||||
|
||||
@ -393,12 +394,11 @@ prng.create = function(plugin) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'prng';
|
||||
var deps = ['./md', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -407,30 +407,41 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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 ########## */
|
||||
var name = 'pss';
|
||||
var deps = ['./random', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -217,30 +216,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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
|
||||
// available -- otherwise this source will be automatically used by the prng
|
||||
var _nodejs = (typeof module === 'object' && module.exports);
|
||||
if(!_nodejs && !(typeof window !== 'undefined' &&
|
||||
window.crypto && window.crypto.getRandomValues)) {
|
||||
var _nodejs = (
|
||||
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||
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
|
||||
// receive strong entropy asynchronously from the main thread
|
||||
@ -168,12 +169,11 @@ forge.random.getBytesSync = function(count) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'random';
|
||||
var deps = ['./aes', './md', './prng', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -182,30 +182,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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)
|
||||
*/
|
||||
forge.rc2.expandKey = function(key, effKeyBits) {
|
||||
if(key.constructor == String) {
|
||||
if(typeof key === 'string') {
|
||||
key = forge.util.createBuffer(key);
|
||||
}
|
||||
effKeyBits = effKeyBits || 128;
|
||||
@ -250,7 +250,7 @@ var createCipher = function(key, bits, encrypt)
|
||||
start: function(iv, output) {
|
||||
if(iv) {
|
||||
/* CBC mode */
|
||||
if(key.constructor == String && iv.length == 8) {
|
||||
if(typeof key === 'string' && iv.length === 8) {
|
||||
iv = forge.util.createBuffer(iv);
|
||||
}
|
||||
}
|
||||
@ -302,7 +302,7 @@ var createCipher = function(key, bits, encrypt)
|
||||
} else {
|
||||
// add PKCS#7 padding to block (each pad byte is the
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -420,12 +420,11 @@ forge.rc2.createDecryptionCipher = function(key, bits) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'rc2';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -434,30 +433,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
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
|
||||
*
|
||||
@ -9,8 +9,6 @@
|
||||
function initModule(forge) {
|
||||
/* ########## Begin module implementation ########## */
|
||||
|
||||
var _nodejs = (typeof module === 'object' && module.exports);
|
||||
|
||||
if(typeof BigInteger === 'undefined') {
|
||||
BigInteger = forge.jsbn.BigInteger;
|
||||
}
|
||||
@ -42,6 +40,7 @@ var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
|
||||
* Digest ::= OCTET STRING
|
||||
*
|
||||
* @param md the message digest object with the hash to sign.
|
||||
*
|
||||
* @return the encoded message (ready for RSA encrytion)
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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),
|
||||
* signaling whether the encryption operation is a public key operation
|
||||
* (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 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).
|
||||
*
|
||||
* @param m the message to encrypt as a byte string.
|
||||
* @param key the RSA key to use.
|
||||
* @param bt for PKCS#1 v1.5 padding, the block type to use
|
||||
* (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.
|
||||
*/
|
||||
pki.rsa.encrypt = function(m, key, bt) {
|
||||
var pub = bt;
|
||||
var eb = forge.util.createBuffer();
|
||||
var eb;
|
||||
|
||||
// get the length of the modulus in bytes
|
||||
var k = Math.ceil(key.n.bitLength() / 8);
|
||||
|
||||
if(bt !== false && bt !== true) {
|
||||
/* use PKCS#1 v1.5 padding */
|
||||
if(m.length > (k - 11)) {
|
||||
throw {
|
||||
message: 'Message is too long to encrypt.',
|
||||
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, 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);
|
||||
// legacy, default to PKCS#1 v1.5 padding
|
||||
pub = (bt === 0x02);
|
||||
eb = _encodePkcs1_v1_5(m, key, bt);
|
||||
}
|
||||
else {
|
||||
eb = forge.util.createBuffer();
|
||||
eb.putBytes(m);
|
||||
}
|
||||
|
||||
eb.putBytes(m);
|
||||
|
||||
// load encryption block as big integer 'x'
|
||||
// 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.
|
||||
*
|
||||
* 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 key the RSA key to use.
|
||||
* @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.
|
||||
*/
|
||||
@ -327,7 +289,7 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
||||
var k = Math.ceil(key.n.bitLength() / 8);
|
||||
|
||||
// error if the length of the encrypted data ED is not k
|
||||
if(ed.length != k) {
|
||||
if(ed.length !== k) {
|
||||
throw {
|
||||
message: 'Encrypted message length is invalid.',
|
||||
length: ed.length,
|
||||
@ -339,6 +301,14 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
||||
// FIXME: hex conversion inefficient, get BigInteger w/byte strings
|
||||
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
|
||||
var x = _modPow(y, key, pub);
|
||||
|
||||
@ -355,70 +325,8 @@ pki.rsa.decrypt = function(ed, key, pub, ml) {
|
||||
eb.putBytes(forge.util.hexToBytes(xhex));
|
||||
|
||||
if(ml !== false) {
|
||||
/* 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 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.'
|
||||
};
|
||||
}
|
||||
// legacy, default to PKCS#1 v1.5 padding
|
||||
return _decodePkcs1_v1_5(eb.getBytes(), key, pub);
|
||||
}
|
||||
|
||||
// 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 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.
|
||||
*/
|
||||
key.encrypt = function(data) {
|
||||
return pki.rsa.encrypt(data, key, 0x02);
|
||||
key.encrypt = function(data, scheme, schemeOptions) {
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* DigestInfo ::= SEQUENCE {
|
||||
@ -777,29 +724,51 @@ pki.rsa.setPublicKey = function(n, e) {
|
||||
* Digest ::= OCTET STRING
|
||||
*
|
||||
* 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 signature the signature to verify.
|
||||
* @param scheme signature scheme to use, undefined for PKCS#1 v1.5
|
||||
* padding style.
|
||||
* @param scheme signature verification scheme to use:
|
||||
* '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.
|
||||
*/
|
||||
key.verify = function(digest, signature, scheme) {
|
||||
// do rsa decryption
|
||||
var ml = scheme === undefined ? undefined : false;
|
||||
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;
|
||||
if(typeof scheme === 'string') {
|
||||
scheme = scheme.toUpperCase();
|
||||
}
|
||||
else {
|
||||
return scheme.verify(digest, d, key.n.bitLength());
|
||||
else if(scheme === undefined) {
|
||||
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;
|
||||
@ -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 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.
|
||||
*/
|
||||
key.decrypt = function(data) {
|
||||
return pki.rsa.decrypt(data, key, false);
|
||||
key.decrypt = function(data, scheme, schemeOptions) {
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
* RSASSA-PKCS1-v1_5. In order to generate a PSS signature, provide
|
||||
* an instance of Forge PSS object as scheme parameter.
|
||||
* RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide
|
||||
* an instance of Forge PSS object as the scheme parameter.
|
||||
*
|
||||
* @param md the message digest object with the hash to sign.
|
||||
* @param scheme signature scheme to use, undefined for PKCS#1 v1.5
|
||||
* padding style.
|
||||
* @param scheme the signature scheme to use:
|
||||
* '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.
|
||||
*/
|
||||
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 };
|
||||
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());
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* via Web Workers, or using the main thread and setImmediate.
|
||||
@ -1064,12 +1241,11 @@ function _generateKeyPair(state, options, callback) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'rsa';
|
||||
var deps = ['./asn1', './oids', './random', './util', './jsbn'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1078,30 +1254,49 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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',
|
||||
'./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.
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.start = function() {
|
||||
md.messageLength = 0;
|
||||
@ -185,6 +187,7 @@ sha1.create = function() {
|
||||
h3: 0x10325476,
|
||||
h4: 0xC3D2E1F0
|
||||
};
|
||||
return md;
|
||||
};
|
||||
// start digest automatically for first time
|
||||
md.start();
|
||||
@ -196,6 +199,8 @@ sha1.create = function() {
|
||||
*
|
||||
* @param msg the message input to update with.
|
||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.update = function(msg, encoding) {
|
||||
if(encoding === 'utf8') {
|
||||
@ -215,6 +220,8 @@ sha1.create = function() {
|
||||
if(_input.read > 2048 || _input.length() === 0) {
|
||||
_input.compact();
|
||||
}
|
||||
|
||||
return md;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -280,12 +287,11 @@ sha1.create = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'sha1';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -294,30 +300,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
@ -175,6 +175,8 @@ sha256.create = function() {
|
||||
|
||||
/**
|
||||
* Starts the digest.
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.start = function() {
|
||||
md.messageLength = 0;
|
||||
@ -189,6 +191,7 @@ sha256.create = function() {
|
||||
h6: 0x1F83D9AB,
|
||||
h7: 0x5BE0CD19
|
||||
};
|
||||
return md;
|
||||
};
|
||||
// start digest automatically for first time
|
||||
md.start();
|
||||
@ -200,6 +203,8 @@ sha256.create = function() {
|
||||
*
|
||||
* @param msg the message input to update with.
|
||||
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||
*
|
||||
* @return this digest object.
|
||||
*/
|
||||
md.update = function(msg, encoding) {
|
||||
if(encoding === 'utf8') {
|
||||
@ -219,6 +224,8 @@ sha256.create = function() {
|
||||
if(_input.read > 2048 || _input.length() === 0) {
|
||||
_input.compact();
|
||||
}
|
||||
|
||||
return md;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -290,12 +297,11 @@ sha256.create = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'sha256';
|
||||
var deps = ['./util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -304,30 +310,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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));
|
||||
});
|
||||
})();
|
||||
|
@ -292,12 +292,11 @@ net.createSocket = function(options) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'net';
|
||||
var deps = [];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -306,30 +305,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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'], 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) {
|
||||
// juggle parameters if it looks like no name is given
|
||||
if(name.constructor == Array) {
|
||||
if(forge.util.isArray(name)) {
|
||||
subrun = name;
|
||||
|
||||
// inherit parent's name
|
||||
@ -738,12 +738,11 @@ forge.task.createCondition = function() {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'task';
|
||||
var deps = ['./debug', './log', './util'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -752,30 +751,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -857,16 +681,11 @@ tls.Alert.Description = {
|
||||
|
||||
/**
|
||||
* Supported cipher suites.
|
||||
*
|
||||
* TODO: Make cipher suites modular.
|
||||
*/
|
||||
tls.CipherSuites = {
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA: [0x00,0x2f],
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA: [0x00,0x35]
|
||||
};
|
||||
tls.CipherSuites = {};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -876,8 +695,8 @@ tls.getCipherSuite = function(twoBytes) {
|
||||
var rval = null;
|
||||
for(var key in tls.CipherSuites) {
|
||||
var cs = tls.CipherSuites[key];
|
||||
if(cs[0] === twoBytes.charCodeAt(0) &&
|
||||
cs[1] === twoBytes.charCodeAt(1)) {
|
||||
if(cs.id[0] === twoBytes.charCodeAt(0) &&
|
||||
cs.id[1] === twoBytes.charCodeAt(1)) {
|
||||
rval = cs;
|
||||
break;
|
||||
}
|
||||
@ -939,7 +758,7 @@ tls.handleHelloRequest = function(c, record, length) {
|
||||
tls.parseHelloMessage = function(c, record, length) {
|
||||
var msg = null;
|
||||
|
||||
var client = (c.entity == tls.ConnectionEnd.client);
|
||||
var client = (c.entity === tls.ConnectionEnd.client);
|
||||
|
||||
// minimum of 38 bytes in message
|
||||
if(length < 38) {
|
||||
@ -1050,7 +869,7 @@ tls.parseHelloMessage = function(c, record, length) {
|
||||
|
||||
// cipher suite not supported
|
||||
if(c.session.cipherSuite === null) {
|
||||
c.error(c, {
|
||||
return c.error(c, {
|
||||
message: 'No cipher suites in common.',
|
||||
send: true,
|
||||
alert: {
|
||||
@ -1087,18 +906,6 @@ tls.createSecurityParameters = function(c, msg) {
|
||||
|
||||
// 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
|
||||
var client = (c.entity === tls.ConnectionEnd.client);
|
||||
var msgRandom = msg.random.bytes();
|
||||
@ -1109,15 +916,15 @@ tls.createSecurityParameters = function(c, msg) {
|
||||
c.session.sp = {
|
||||
entity: c.entity,
|
||||
prf_algorithm: tls.PRFAlgorithm.tls_prf_sha256,
|
||||
bulk_cipher_algorithm: tls.BulkCipherAlgorithm.aes,
|
||||
cipher_type: tls.CipherType.block,
|
||||
enc_key_length: keyLength,
|
||||
block_length: 16,
|
||||
fixed_iv_length: 16,
|
||||
record_iv_length: 16,
|
||||
mac_algorithm: tls.MACAlgorithm.hmac_sha1,
|
||||
mac_length: 20,
|
||||
mac_key_length: 20,
|
||||
bulk_cipher_algorithm: null,
|
||||
cipher_type: null,
|
||||
enc_key_length: null,
|
||||
block_length: null,
|
||||
fixed_iv_length: null,
|
||||
record_iv_length: null,
|
||||
mac_algorithm: null,
|
||||
mac_length: null,
|
||||
mac_key_length: null,
|
||||
compression_algorithm: c.session.compressionMethod,
|
||||
pre_master_secret: null,
|
||||
master_secret: null,
|
||||
@ -1277,26 +1084,28 @@ tls.handleClientHello = function(c, record, length) {
|
||||
data: tls.createCertificate(c)
|
||||
}));
|
||||
|
||||
// queue server key exchange
|
||||
tls.queue(c, tls.createRecord({
|
||||
type: tls.ContentType.handshake,
|
||||
data: tls.createServerKeyExchange(c)
|
||||
}));
|
||||
|
||||
// request client certificate if set
|
||||
if(c.verifyClient !== false) {
|
||||
// queue certificate request
|
||||
if(!c.fail) {
|
||||
// queue server key exchange
|
||||
tls.queue(c, tls.createRecord({
|
||||
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
|
||||
@ -1517,7 +1326,7 @@ tls.handleClientKeyExchange = function(c, record, length) {
|
||||
}
|
||||
else {
|
||||
var b = record.fragment;
|
||||
msg = {
|
||||
var msg = {
|
||||
enc_pre_master_secret: readVector(b, 2).getBytes()
|
||||
};
|
||||
|
||||
@ -1678,7 +1487,7 @@ tls.handleCertificateVerify = function(c, record, length) {
|
||||
var msgBytes = b.bytes();
|
||||
b.read += 4;
|
||||
|
||||
msg = {
|
||||
var msg = {
|
||||
signature: readVector(b, 2).getBytes()
|
||||
};
|
||||
|
||||
@ -1692,9 +1501,10 @@ tls.handleCertificateVerify = function(c, record, length) {
|
||||
|
||||
try {
|
||||
var cert = c.session.clientCertificate;
|
||||
b = forge.pki.rsa.decrypt(
|
||||
/*b = forge.pki.rsa.decrypt(
|
||||
msg.signature, cert.publicKey, true, verify.length);
|
||||
if(b !== verify) {
|
||||
if(b !== verify) {*/
|
||||
if(!cert.publicKey.verify(verify, msg.signature, 'NONE')) {
|
||||
throw {
|
||||
message: 'CertificateVerify signature does not match.'
|
||||
};
|
||||
@ -1781,7 +1591,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
||||
// check for custom alert info
|
||||
if(ret || ret === 0) {
|
||||
// set custom message and alert description
|
||||
if(ret.constructor == Object) {
|
||||
if(typeof ret === 'object' && !forge.util.isArray(ret)) {
|
||||
if(ret.message) {
|
||||
error.message = ret.message;
|
||||
}
|
||||
@ -1789,7 +1599,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
||||
error.alert.description = ret.alert;
|
||||
}
|
||||
}
|
||||
else if(ret.constructor == Number) {
|
||||
else if(typeof ret === 'number') {
|
||||
// set custom alert description
|
||||
error.alert.description = ret;
|
||||
}
|
||||
@ -1879,7 +1689,7 @@ tls.handleServerHelloDone = function(c, record, length) {
|
||||
* @param record the record.
|
||||
*/
|
||||
tls.handleChangeCipherSpec = function(c, record) {
|
||||
if(record.fragment.getByte() != 0x01) {
|
||||
if(record.fragment.getByte() !== 0x01) {
|
||||
c.error(c, {
|
||||
message: 'Invalid ChangeCipherSpec message received.',
|
||||
send: true,
|
||||
@ -2336,7 +2146,7 @@ var F3 = tls.handleApplicationData;
|
||||
var ctTable = [];
|
||||
ctTable[tls.ConnectionEnd.client] = [
|
||||
// CC,AL,HS,AD
|
||||
/*SHE*/[__,__,F2,__],
|
||||
/*SHE*/[__,F1,F2,__],
|
||||
/*SCE*/[__,F1,F2,__],
|
||||
/*SKE*/[__,F1,F2,__],
|
||||
/*SCR*/[__,F1,F2,__],
|
||||
@ -2350,7 +2160,7 @@ ctTable[tls.ConnectionEnd.client] = [
|
||||
// map server current expect state and content type to function
|
||||
ctTable[tls.ConnectionEnd.server] = [
|
||||
// CC,AL,HS,AD
|
||||
/*CHE*/[__,__,F2,__],
|
||||
/*CHE*/[__,F1,F2,__],
|
||||
/*CCE*/[__,F1,F2,__],
|
||||
/*CKE*/[__,F1,F2,__],
|
||||
/*CCV*/[__,F1,F2,__],
|
||||
@ -2476,7 +2286,7 @@ hsTable[tls.ConnectionEnd.server] = [
|
||||
*/
|
||||
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 are the only cipher suites implemented
|
||||
// TLS_RSA_WITH_AES_256_CBC_SHA are the only cipher suites implemented
|
||||
// at present
|
||||
|
||||
// TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with
|
||||
@ -2601,7 +2411,7 @@ tls.createConnectionState = function(c) {
|
||||
compressionState: null,
|
||||
compressFunction: function(record){return true;},
|
||||
updateSequenceNumber: function() {
|
||||
if(mode.sequenceNumber[1] == 0xFFFFFFFF) {
|
||||
if(mode.sequenceNumber[1] === 0xFFFFFFFF) {
|
||||
mode.sequenceNumber[1] = 0;
|
||||
++mode.sequenceNumber[0];
|
||||
}
|
||||
@ -2676,57 +2486,18 @@ tls.createConnectionState = function(c) {
|
||||
|
||||
// handle security parameters
|
||||
if(c.session) {
|
||||
// generate keys
|
||||
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 ?
|
||||
sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key;
|
||||
state.write.macKey = client ?
|
||||
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
|
||||
switch(sp.bulk_cipher_algorithm) {
|
||||
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.'
|
||||
};
|
||||
}
|
||||
// cipher suite setup
|
||||
c.session.cipherSuite.initConnectionState(state, c, sp);
|
||||
|
||||
// compression setup
|
||||
switch(sp.compression_algorithm) {
|
||||
@ -2787,6 +2558,9 @@ tls.createRandom = function() {
|
||||
* @return the created record.
|
||||
*/
|
||||
tls.createRecord = function(options) {
|
||||
if(!options.data) {
|
||||
return null;
|
||||
}
|
||||
var record = {
|
||||
type: options.type,
|
||||
version: {
|
||||
@ -2889,8 +2663,8 @@ tls.createClientHello = function(c) {
|
||||
var cipherSuites = forge.util.createBuffer();
|
||||
for(var i = 0; i < c.cipherSuites.length; ++i) {
|
||||
var cs = c.cipherSuites[i];
|
||||
cipherSuites.putByte(cs[0]);
|
||||
cipherSuites.putByte(cs[1]);
|
||||
cipherSuites.putByte(cs.id[0]);
|
||||
cipherSuites.putByte(cs.id[1]);
|
||||
}
|
||||
var cSuites = cipherSuites.length();
|
||||
|
||||
@ -3007,8 +2781,8 @@ tls.createServerHello = function(c) {
|
||||
rval.putByte(tls.Version.minor); // minor version
|
||||
rval.putBytes(c.session.sp.server_random); // random time + bytes
|
||||
writeVector(rval, 1, forge.util.createBuffer(sessionId));
|
||||
rval.putByte(c.session.cipherSuite[0]);
|
||||
rval.putByte(c.session.cipherSuite[1]);
|
||||
rval.putByte(c.session.cipherSuite.id[0]);
|
||||
rval.putByte(c.session.cipherSuite.id[1]);
|
||||
rval.putByte(c.session.compressionMethod);
|
||||
return rval;
|
||||
};
|
||||
@ -3051,15 +2825,31 @@ tls.createCertificate = function(c) {
|
||||
if(cert !== null) {
|
||||
try {
|
||||
// normalize cert to a chain of certificates
|
||||
if((Array.isArray && !Array.isArray(cert)) ||
|
||||
cert.constructor !== Array) {
|
||||
if(!forge.util.isArray(cert)) {
|
||||
cert = [cert];
|
||||
}
|
||||
var asn1 = null;
|
||||
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) {
|
||||
asn1 = forge.asn1.fromDer(der.bytes());
|
||||
asn1 = forge.asn1.fromDer(der.bytes(), false);
|
||||
}
|
||||
|
||||
// certificate entry is itself a vector with 3 length bytes
|
||||
@ -3078,17 +2868,17 @@ tls.createCertificate = function(c) {
|
||||
else {
|
||||
c.session.serverCertificate = cert;
|
||||
}
|
||||
}
|
||||
catch(ex) {
|
||||
c.error(c, {
|
||||
message: 'Could not send certificate list.',
|
||||
cause: ex,
|
||||
send: true,
|
||||
alert: {
|
||||
level: tls.Alert.Level.fatal,
|
||||
description: tls.Alert.Description.bad_certificate
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(ex) {
|
||||
return c.error(c, {
|
||||
message: 'Could not send certificate list.',
|
||||
cause: ex,
|
||||
send: true,
|
||||
alert: {
|
||||
level: tls.Alert.Level.fatal,
|
||||
description: tls.Alert.Description.bad_certificate
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -3259,7 +3049,7 @@ tls.getClientSignature = function(c, callback) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
b = forge.pki.rsa.encrypt(b, privateKey, 0x01);
|
||||
b = privateKey.sign(b, null);
|
||||
}
|
||||
callback(c, b);
|
||||
};
|
||||
@ -3479,6 +3269,11 @@ tls.createFinished = function(c) {
|
||||
* @param record the record to queue.
|
||||
*/
|
||||
tls.queue = function(c, record) {
|
||||
// error during record creation
|
||||
if(!record) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the record is a handshake record, update handshake hashes
|
||||
if(record.type === tls.ContentType.handshake) {
|
||||
var bytes = record.fragment.bytes();
|
||||
@ -3624,7 +3419,7 @@ tls.verifyCertificateChain = function(c, chain) {
|
||||
// call application callback
|
||||
var ret = c.verify(c, vfd, depth, chain);
|
||||
if(ret !== true) {
|
||||
if(ret.constructor === Object) {
|
||||
if(typeof ret === 'object' && !forge.util.isArray(ret)) {
|
||||
// throw custom error
|
||||
var error = {
|
||||
message: 'The application rejected the certificate.',
|
||||
@ -3654,7 +3449,7 @@ tls.verifyCertificateChain = function(c, chain) {
|
||||
}
|
||||
catch(ex) {
|
||||
// build tls error if not already customized
|
||||
if(ex.constructor !== Object) {
|
||||
if(typeof ex !== 'object' || forge.util.isArray(ex)) {
|
||||
ex = {
|
||||
send: true,
|
||||
alert: {
|
||||
@ -3771,8 +3566,7 @@ tls.createConnection = function(options) {
|
||||
var caStore = null;
|
||||
if(options.caStore) {
|
||||
// if CA store is an array, convert it to a CA store object
|
||||
if((Array.isArray && Array.isArray(options.caStore)) ||
|
||||
options.caStore.constructor == Array) {
|
||||
if(forge.util.isArray(options.caStore)) {
|
||||
caStore = forge.pki.createCaStore(options.caStore);
|
||||
}
|
||||
else {
|
||||
@ -3788,8 +3582,9 @@ tls.createConnection = function(options) {
|
||||
var cipherSuites = options.cipherSuites || null;
|
||||
if(cipherSuites === null) {
|
||||
cipherSuites = [];
|
||||
cipherSuites.push(tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA);
|
||||
cipherSuites.push(tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA);
|
||||
for(var key in tls.CipherSuites) {
|
||||
cipherSuites.push(tls.CipherSuites[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// set default entity
|
||||
@ -3934,8 +3729,8 @@ tls.createConnection = function(options) {
|
||||
};
|
||||
|
||||
// check record version
|
||||
if(c.record.version.major != tls.Version.major ||
|
||||
c.record.version.minor != tls.Version.minor) {
|
||||
if(c.record.version.major !== tls.Version.major ||
|
||||
c.record.version.minor !== tls.Version.minor) {
|
||||
c.error(c, {
|
||||
message: 'Incompatible TLS version.',
|
||||
send: true,
|
||||
@ -4198,14 +3993,18 @@ tls.createConnection = function(options) {
|
||||
/* TLS API */
|
||||
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
|
||||
forge.tls.prf_tls1 = prf_TLS1;
|
||||
|
||||
// expose TLS alerts
|
||||
forge.tls.Alert = tls.Alert;
|
||||
|
||||
// expose cipher suites
|
||||
forge.tls.CipherSuites = tls.CipherSuites;
|
||||
// expost sha1 hmac method
|
||||
forge.tls.hmac_sha1 = hmac_sha1;
|
||||
|
||||
// expose session cache creation
|
||||
forge.tls.createSessionCache = tls.createSessionCache;
|
||||
@ -4313,20 +4112,11 @@ forge.tls.createConnection = tls.createConnection;
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'tls';
|
||||
var deps = [
|
||||
'./aes',
|
||||
'./asn1',
|
||||
'./hmac',
|
||||
'./md',
|
||||
'./pki',
|
||||
'./random',
|
||||
'./util'
|
||||
];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -4335,30 +4125,49 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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',
|
||||
'./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 ########## */
|
||||
var name = 'tlssocket';
|
||||
var deps = ['./tls'];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -268,30 +267,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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', './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.
|
||||
*
|
||||
@ -64,16 +69,19 @@ util.ByteBuffer.prototype.length = function() {
|
||||
* @return true if this buffer is empty, false if not.
|
||||
*/
|
||||
util.ByteBuffer.prototype.isEmpty = function() {
|
||||
return (this.data.length - this.read) === 0;
|
||||
return this.length() <= 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a byte in this buffer.
|
||||
*
|
||||
* @param b the byte to put.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putByte = function(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 n the number of bytes of value b to put.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.fillWithByte = function(b, n) {
|
||||
b = String.fromCharCode(b);
|
||||
@ -95,53 +105,68 @@ util.ByteBuffer.prototype.fillWithByte = function(b, n) {
|
||||
}
|
||||
}
|
||||
this.data = d;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts bytes in this buffer.
|
||||
*
|
||||
* @param bytes the bytes (as a UTF-8 encoded string) to put.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putBytes = function(bytes) {
|
||||
this.data += bytes;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a UTF-16 encoded string into this buffer.
|
||||
*
|
||||
* @param str the string to put.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putString = function(str) {
|
||||
this.data += util.encodeUtf8(str);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 16-bit integer in this buffer in big-endian order.
|
||||
*
|
||||
* @param i the 16-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt16 = function(i) {
|
||||
this.data +=
|
||||
String.fromCharCode(i >> 8 & 0xFF) +
|
||||
String.fromCharCode(i & 0xFF);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 24-bit integer in this buffer in big-endian order.
|
||||
*
|
||||
* @param i the 24-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt24 = function(i) {
|
||||
this.data +=
|
||||
String.fromCharCode(i >> 16 & 0xFF) +
|
||||
String.fromCharCode(i >> 8 & 0xFF) +
|
||||
String.fromCharCode(i & 0xFF);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 32-bit integer in this buffer in big-endian order.
|
||||
*
|
||||
* @param i the 32-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt32 = function(i) {
|
||||
this.data +=
|
||||
@ -149,35 +174,44 @@ util.ByteBuffer.prototype.putInt32 = function(i) {
|
||||
String.fromCharCode(i >> 16 & 0xFF) +
|
||||
String.fromCharCode(i >> 8 & 0xFF) +
|
||||
String.fromCharCode(i & 0xFF);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 16-bit integer in this buffer in little-endian order.
|
||||
*
|
||||
* @param i the 16-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt16Le = function(i) {
|
||||
this.data +=
|
||||
String.fromCharCode(i & 0xFF) +
|
||||
String.fromCharCode(i >> 8 & 0xFF);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 24-bit integer in this buffer in little-endian order.
|
||||
*
|
||||
* @param i the 24-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt24Le = function(i) {
|
||||
this.data +=
|
||||
String.fromCharCode(i & 0xFF) +
|
||||
String.fromCharCode(i >> 8 & 0xFF) +
|
||||
String.fromCharCode(i >> 16 & 0xFF);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts a 32-bit integer in this buffer in little-endian order.
|
||||
*
|
||||
* @param i the 32-bit integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt32Le = function(i) {
|
||||
this.data +=
|
||||
@ -185,6 +219,7 @@ util.ByteBuffer.prototype.putInt32Le = function(i) {
|
||||
String.fromCharCode(i >> 8 & 0xFF) +
|
||||
String.fromCharCode(i >> 16 & 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 n the number of bits in the integer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putInt = function(i, n) {
|
||||
do {
|
||||
@ -199,15 +236,19 @@ util.ByteBuffer.prototype.putInt = function(i, n) {
|
||||
this.data += String.fromCharCode((i >> n) & 0xFF);
|
||||
}
|
||||
while(n > 0);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts the given buffer into this buffer.
|
||||
*
|
||||
* @param buffer the buffer to put into this one.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.putBuffer = function(buffer) {
|
||||
this.data += buffer.getBytes();
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -320,7 +361,7 @@ util.ByteBuffer.prototype.getInt32Le = function() {
|
||||
util.ByteBuffer.prototype.getInt = function(n) {
|
||||
var rval = 0;
|
||||
do {
|
||||
rval = (rval << n) + this.data.charCodeAt(this.read++);
|
||||
rval = (rval << 8) + this.data.charCodeAt(this.read++);
|
||||
n -= 8;
|
||||
}
|
||||
while(n > 0);
|
||||
@ -383,11 +424,14 @@ util.ByteBuffer.prototype.at = function(i) {
|
||||
*
|
||||
* @param i the byte index.
|
||||
* @param b the byte to put.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.setAt = function(i, b) {
|
||||
this.data = this.data.substr(0, this.read + i) +
|
||||
String.fromCharCode(b) +
|
||||
this.data.substr(this.read + i + 1);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -412,31 +456,40 @@ util.ByteBuffer.prototype.copy = function() {
|
||||
|
||||
/**
|
||||
* Compacts this buffer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.compact = function() {
|
||||
if(this.read > 0) {
|
||||
this.data = this.data.slice(this.read);
|
||||
this.read = 0;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears this buffer.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.clear = function() {
|
||||
this.data = '';
|
||||
this.read = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortens this buffer by triming bytes off of the end of this buffer.
|
||||
*
|
||||
* @param count the number of bytes to trim off.
|
||||
*
|
||||
* @return this buffer.
|
||||
*/
|
||||
util.ByteBuffer.prototype.truncate = function(count) {
|
||||
var len = Math.max(0, this.length() - count);
|
||||
this.data = this.data.substr(this.read, len);
|
||||
this.read = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1152,7 +1205,8 @@ util.getQueryVariables = function(query) {
|
||||
if(!(key in rval)) {
|
||||
rval[key] = [];
|
||||
}
|
||||
if(val !== null) {
|
||||
// disallow overriding object prototype keys
|
||||
if(!(key in Object.prototype) && val !== null) {
|
||||
rval[key].push(unescape(val));
|
||||
}
|
||||
}
|
||||
@ -1535,12 +1589,11 @@ util.formatSize = function(size) {
|
||||
|
||||
/* ########## Begin module wrapper ########## */
|
||||
var name = 'util';
|
||||
var deps = [];
|
||||
var nodeDefine = null;
|
||||
if(typeof define !== 'function') {
|
||||
// NodeJS -> AMD
|
||||
if(typeof module === 'object' && module.exports) {
|
||||
nodeDefine = function(ids, factory) {
|
||||
var nodeJS = true;
|
||||
define = function(ids, factory) {
|
||||
factory(require, module);
|
||||
};
|
||||
}
|
||||
@ -1549,30 +1602,40 @@ if(typeof define !== 'function') {
|
||||
if(typeof forge === 'undefined') {
|
||||
forge = {};
|
||||
}
|
||||
initModule(forge);
|
||||
return initModule(forge);
|
||||
}
|
||||
}
|
||||
// AMD
|
||||
if(nodeDefine || typeof define === 'function') {
|
||||
// define module AMD style
|
||||
(nodeDefine || define)(['require', 'module'].concat(deps),
|
||||
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);
|
||||
}
|
||||
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'], function() {
|
||||
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
});
|
||||
})();
|
||||
|
@ -235,7 +235,7 @@ xhrApi.getCookie = function(name, path, domain) {
|
||||
if(rval === null) {
|
||||
rval = cookie;
|
||||
}
|
||||
else if(rval.constructor != Array) {
|
||||
else if(!forge.util.isArray(rval)) {
|
||||
rval = [rval, cookie];
|
||||
}
|
||||
else {
|
||||
@ -689,8 +689,8 @@ xhrApi.create = function(options) {
|
||||
_state.response = null;
|
||||
|
||||
// 6. if state is DONE or UNSENT, or if OPENED and send flag is false
|
||||
if(xhr.readyState == DONE || xhr.readyState == UNSENT ||
|
||||
(xhr.readyState == OPENED && !_state.sendFlag)) {
|
||||
if(xhr.readyState === DONE || xhr.readyState === UNSENT ||
|
||||
(xhr.readyState === OPENED && !_state.sendFlag)) {
|
||||
// 7. set ready state to unsent
|
||||
xhr.readyState = UNSENT;
|
||||
}
|
||||
@ -741,8 +741,8 @@ xhrApi.create = function(options) {
|
||||
if(_state.response !== null) {
|
||||
if(header in _state.response.fields) {
|
||||
rval = _state.response.fields[header];
|
||||
if(rval.constructor == Array) {
|
||||
rval = rval.join();
|
||||
if(forge.util.isArray(rval)) {
|
||||
rval = rval.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,13 @@ require(['../../src/require-config'], function() {
|
||||
|
||||
function startTests() {
|
||||
require(['test/unit/forge-test',
|
||||
'test/unit/aes-test',
|
||||
'test/unit/rsa-test',
|
||||
'test/unit/lawnchair-dao-test',
|
||||
'test/unit/keychain-dao-test',
|
||||
'test/unit/crypto-test',
|
||||
'test/unit/devicestorage-dao-test',
|
||||
'test/unit/email-dao-test'
|
||||
'test/unit/aes-test',
|
||||
'test/unit/rsa-test',
|
||||
'test/unit/lawnchair-dao-test',
|
||||
'test/unit/keychain-dao-test',
|
||||
'test/unit/crypto-test',
|
||||
'test/unit/devicestorage-dao-test',
|
||||
'test/unit/email-dao-test'
|
||||
], function() {
|
||||
//Tests loaded, run tests
|
||||
QUnit.start();
|
||||
|
Loading…
Reference in New Issue
Block a user