/**
* TLSSecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SSLSecurityParameters implements ISecurityParameters {
public static const COMPRESSION_NULL:uint = 0;
private var entity:uint; private var bulkCipher:uint; private var cipherType:uint; private var keySize:uint;
private var keyMaterialLength:uint;
private var keyBlock:ByteArray;
private var IVSize:uint;
private var MAC_length:uint;
private var macAlgorithm:uint; private var hashSize:uint;
private var compression:uint; private var masterSecret:ByteArray; private var clientRandom:ByteArray; private var serverRandom:ByteArray; private var pad_1:ByteArray; private var pad_2:ByteArray; private var ignoreCNMismatch:Boolean = true;
private var trustAllCerts:Boolean = false;
private var trustSelfSigned:Boolean = false;
public static const PROTOCOL_VERSION:uint = 0x0300;
public var keyExchange:uint;
public function get version() : uint {
return PROTOCOL_VERSION;
}
public function SSLSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:ByteArray = null) {
this.entity = entity;
reset();
}
public function reset():void {
bulkCipher = BulkCiphers.NULL;
cipherType = BulkCiphers.BLOCK_CIPHER;
macAlgorithm = MACs.NULL;
compression = COMPRESSION_NULL;
masterSecret = null;
}
public function getBulkCipher():uint {
return bulkCipher;
}
public function getCipherType():uint {
return cipherType;
}
public function getMacAlgorithm():uint {
return macAlgorithm;
}
public function setCipher(cipher:uint):void {
bulkCipher = CipherSuites.getBulkCipher(cipher);
cipherType = BulkCiphers.getType(bulkCipher);
keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); IVSize = BulkCiphers.getIVSize(bulkCipher);
keyExchange = CipherSuites.getKeyExchange(cipher);
macAlgorithm = CipherSuites.getMac(cipher);
hashSize = MACs.getHashSize(macAlgorithm);
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < 48; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
public function setCompression(algo:uint):void {
compression = algo;
}
public function setPreMasterSecret(secret:ByteArray):void {
var tempHashA:ByteArray = new ByteArray(); var tempHashB:ByteArray = new ByteArray();
var shaHash:ByteArray;
var mdHash:ByteArray;
var i:int;
var j:int;
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray();
k.writeBytes(secret);
k.writeBytes(clientRandom);
k.writeBytes(serverRandom);
masterSecret = new ByteArray();
var pad_char:uint = 0x41;
for ( i = 0; i < 3; i++) {
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
tempHashB.position = 0;
tempHashB.writeBytes(secret);
tempHashB.writeBytes(shaHash);
mdHash = md.hash(tempHashB);
masterSecret.writeBytes(mdHash);
}
k.position = 0;
k.writeBytes(masterSecret);
k.writeBytes(serverRandom);
k.writeBytes(clientRandom);
keyBlock = new ByteArray();
tempHashA = new ByteArray();
tempHashB = new ByteArray();
pad_char = 0x41;
for ( i = 0; i < 16; i++) {
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
tempHashB.position = 0;
tempHashB.writeBytes(masterSecret);
tempHashB.writeBytes(shaHash, 0);
mdHash = md.hash(tempHashB);
keyBlock.writeBytes(mdHash);
}
}
public function setClientRandom(secret:ByteArray):void {
clientRandom = secret;
}
public function setServerRandom(secret:ByteArray):void {
serverRandom = secret;
}
public function get useRSA():Boolean {
return KeyExchanges.useRSA(keyExchange);
}
public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray(); var j:ByteArray = new ByteArray();
var innerKey:ByteArray;
var outerKey:ByteArray = new ByteArray();
var hashSha:ByteArray;
var hashMD:ByteArray;
var sideBytes:ByteArray = new ByteArray();
if (side == TLSEngine.CLIENT) {
sideBytes.writeUnsignedInt(0x434C4E54);
} else {
sideBytes.writeUnsignedInt(0x53525652);
}
masterSecret.position = 0;
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1, 0, 40);
innerKey = sha.hash(k);
j.writeBytes(masterSecret);
j.writeBytes(pad_2, 0, 40); j.writeBytes(innerKey);
hashSha = sha.hash(j);
k = new ByteArray();
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1);
innerKey = md.hash(k);
j = new ByteArray();
j.writeBytes(masterSecret);
j.writeBytes(pad_2); j.writeBytes(innerKey);
hashMD = md.hash(j);
outerKey.writeBytes(hashMD, 0, hashMD.length);
outerKey.writeBytes(hashSha, 0, hashSha.length);
var out:String = Hex.fromArray(outerKey);
outerKey.position = 0;
return outerKey;
}
public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
return null;
}
public function getConnectionStates():Object {
if (masterSecret != null) {
var mac_length:int = hashSize as Number;
var key_length:int = keySize as Number;
var iv_length:int = IVSize as Number;
var client_write_MAC:ByteArray = new ByteArray();
var server_write_MAC:ByteArray = new ByteArray();
var client_write_key:ByteArray = new ByteArray();
var server_write_key:ByteArray = new ByteArray();
var client_write_IV:ByteArray = new ByteArray();
var server_write_IV:ByteArray = new ByteArray();
keyBlock.position = 0;
keyBlock.readBytes(client_write_MAC, 0, mac_length);
keyBlock.readBytes(server_write_MAC, 0, mac_length);
keyBlock.readBytes(client_write_key, 0, key_length);
keyBlock.readBytes(server_write_key, 0, key_length);
keyBlock.readBytes(client_write_IV, 0, iv_length);
keyBlock.readBytes(server_write_IV, 0, iv_length);
keyBlock.position = 0;
var client_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
client_write_MAC, client_write_key, client_write_IV);
var server_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
server_write_MAC, server_write_key, server_write_IV);
if (entity == TLSEngine.CLIENT) {
return {read:server_write, write:client_write};
} else {
return {read:client_write, write:server_write};
}
} else {
return {read:new SSLConnectionState, write:new SSLConnectionState};
}
}
}
}