⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlsengine.as

📁 As3 Crypto is a cryptography library written in Actionscript 3 that provides several common algorith
💻 AS
📖 第 1 页 / 共 2 页
字号:
				return null;
			}
		}


		private function verifyHandshake(verifyData:ByteArray):void {
			var data:ByteArray = _securityParameters.computeVerifyData(1-_entity, _handshakePayloads);
			if (ArrayUtil.equals(verifyData, data)) {
				_state = STATE_READY;
				dispatchEvent(new TLSEvent(TLSEvent.READY));
			} else {
				throw new TLSError("Invalid Finished mac.", TLSError.bad_record_mac);
			}
		}

		private function enforceClient():Boolean {
			if (_entity == SERVER) {
				trace("Invalid state for a TLS server.");
				return false;
			}
			return true;
		}
		private function enforceServer():Boolean {
			if (_entity == CLIENT) {
				trace("Invalid state for a TLS client.");
				return false;
			}
			return true;
		}
		
		private function parseHandshakeClientKeyExchange(type:uint, length:uint, rec:ByteArray):void {
			if (_securityParameters.useRSA) {
				// skip 2 bytes for length.
				var len:uint = rec.readShort();
				var cipher:ByteArray = new ByteArray;
				rec.readBytes(cipher, 0, len);
				var preMasterSecret:ByteArray = new ByteArray;
				_config.privateKey.decrypt(cipher, preMasterSecret, len);
				_securityParameters.setPreMasterSecret(preMasterSecret);
				
				// now is a good time to get our pending states
				var o:Object = _securityParameters.getConnectionStates();
				_pendingReadState = o.read;
				_pendingWriteState = o.write;
				
			} else {
				throw new TLSError("parseHandshakeClientKeyExchange not implemented for DH modes.", TLSError.internal_error);
			}
			
		}
		
		private function parseHandshakeHello(type:uint, length:uint, rec:IDataInput):Object {
			var ret:Object;
			var ver:uint = rec.readShort();
			if (ver != TLS_VERSION) {
				throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
			}
			var random:ByteArray = new ByteArray;
			rec.readBytes(random, 0, 32);
			var session_length:uint = rec.readByte();
			var session:ByteArray = new ByteArray;
			rec.readBytes(session, 0, session_length);
			var suites:Array = [];
			if (type==HANDSHAKE_CLIENT_HELLO) {
				var suites_length:uint = rec.readShort();
				for (var i:uint=0;i<suites_length/2;i++) {
					suites.push(rec.readShort());
				}
			} else {
				suites.push(rec.readShort()); // just one winner.
			}
			var compressions:Array = [];
			if (type==HANDSHAKE_CLIENT_HELLO) {
				var comp_length:uint = rec.readByte();
				for (i=0;i<comp_length;i++) {
					compressions.push(rec.readByte());
				}
			} else {
				compressions.push(rec.readByte());
			}
			ret = {random:random, session:session, suites:suites, compressions:compressions};
			
			if (type==HANDSHAKE_CLIENT_HELLO) {
				var sofar:uint = 2+32+1+session_length+2+suites_length+1+comp_length;
				var extensions:Array = [];
				if (sofar<length) {
					// we have extensions. great.
					var ext_total_length:uint = rec.readShort();
					while (ext_total_length>0) {
						var ext_type:uint = rec.readShort();
						var ext_length:uint = rec.readShort();
						var ext_data:ByteArray = new ByteArray;
						rec.readBytes(ext_data, 0, ext_length);
						ext_total_length -= 4+ext_length;
						extensions.push({type:ext_type, length:ext_length, data:ext_data});
					}
				}
				ret.ext = extensions;
			}
			
			return ret;
		}
		
		private function sendClientHello():void {
			var rec:ByteArray = new ByteArray;
			// version
			rec.writeShort(TLS_VERSION);
			// random
			var prng:Random = new Random;
			var clientRandom:ByteArray = new ByteArray;
			prng.nextBytes(clientRandom, 32);
			_securityParameters.setClientRandom(clientRandom);
			rec.writeBytes(clientRandom,0,32);
			// session
			rec.writeByte(32);
			prng.nextBytes(rec, 32);
			// Cipher suites
			var cs:Array = _config.cipherSuites;
			rec.writeShort(2* cs.length);
			for (var i:int=0;i<cs.length;i++) {
				rec.writeShort(cs[i]);
			}
			// Compression
			cs = _config.compressions;
			rec.writeByte(cs.length);
			for (i=0;i<cs.length;i++) {
				rec.writeByte(cs[i]);
			}
			// no extensions, yet.
			rec.position = 0;
			sendHandshake(HANDSHAKE_CLIENT_HELLO, rec.length, rec);
		}
		
		private function findMatch(a1:Array, a2:Array):int {
			for (var i:int=0;i<a1.length;i++) {
				var e:uint = a1[i];
				if (a2.indexOf(e)>-1) {
					return e;
				}
			}
			return -1;
		}
		
		private function sendServerHello(v:Object):void {
			var cipher:int = findMatch(_config.cipherSuites, v.suites);
			if (cipher == -1) {
				throw new TLSError("No compatible cipher found.", TLSError.handshake_failure);
			}
			_securityParameters.setCipher(cipher);
			
			var comp:int = findMatch(_config.compressions, v.compressions);
			if (comp == 01) {
				throw new TLSError("No compatible compression method found.", TLSError.handshake_failure);
			}
			_securityParameters.setCompression(comp);
			_securityParameters.setClientRandom(v.random);

			var rec:ByteArray = new ByteArray;
			rec.writeShort(TLS_VERSION);
			var prng:Random = new Random;
			var serverRandom:ByteArray = new ByteArray;
			prng.nextBytes(serverRandom, 32);
			_securityParameters.setServerRandom(serverRandom);
			rec.writeBytes(serverRandom,0,32);
			// session
			rec.writeByte(32);
			prng.nextBytes(rec, 32);
			// Cipher suite
			rec.writeShort(v.suites[0]);
			// Compression
			rec.writeByte(v.compressions[0]);
			rec.position = 0;
			sendHandshake(HANDSHAKE_SERVER_HELLO, rec.length, rec);
		}
		private function sendCertificate():void {
			var cert:ByteArray = _config.certificate;
			if (cert == null) return; // no cert for you!
			var len:uint = cert.length;
			var len2:uint = len + 3; // this implies we only ever send 1 certificate. XXX okay for now.
			var rec:ByteArray = new ByteArray;
			rec.writeByte(len2>>16);
			rec.writeShort(len2&65535);
			rec.writeByte(len>>16);
			rec.writeShort(len&65535);
			rec.writeBytes(cert);
			rec.position = 0;
			sendHandshake(HANDSHAKE_CERTIFICATE, rec.length, rec);
		}
		private function sendServerHelloDone():void {
			var rec:ByteArray = new ByteArray;
			sendHandshake(HANDSHAKE_HELLO_DONE, rec.length, rec);
		}
		private function sendClientKeyExchange():void {
			if (_securityParameters.useRSA) {
				var p:ByteArray = new ByteArray;
				p.writeShort(TLS_VERSION);
				var prng:Random = new Random;
				prng.nextBytes(p, 46);
				p.position = 0;

				var preMasterSecret:ByteArray = new ByteArray;
				preMasterSecret.writeBytes(p, 0, p.length);
				_securityParameters.setPreMasterSecret(preMasterSecret);
				
				
				var tmp:ByteArray = new ByteArray;
				_otherCertificate.getPublicKey().encrypt(p, tmp, p.length);
				
				var rec:ByteArray = new ByteArray;
				rec.writeShort(tmp.length);
				rec.writeBytes(tmp, 0, tmp.length);
				rec.position=0;
				
				sendHandshake(HANDSHAKE_CLIENT_KEY_EXCHANGE, rec.length, rec);
				
				// now is a good time to get our pending states
				var o:Object = _securityParameters.getConnectionStates();
				_pendingReadState = o.read;
				_pendingWriteState = o.write;
				
				
			} else {
				throw new TLSError("Non-RSA Client Key Exchange not implemented.", TLSError.internal_error);
			}
		}
		private function sendFinished():void {
			var data:ByteArray = _securityParameters.computeVerifyData(_entity, _handshakePayloads);
			data.position=0;
			sendHandshake(HANDSHAKE_FINISHED, data.length, data);
		}
		private function sendHandshake(type:uint, len:uint, payload:IDataInput):void {
			var rec:ByteArray = new ByteArray;
			rec.writeByte(type);
			rec.writeByte(0);
			rec.writeShort(len);
			payload.readBytes(rec, rec.position, len);
			_handshakePayloads.writeBytes(rec, 0, rec.length);
			sendRecord(PROTOCOL_HANDSHAKE, rec);
		}
		private function sendChangeCipherSpec():void {
			var rec:ByteArray = new ByteArray;
			rec[0] = 1;
			sendRecord(PROTOCOL_CHANGE_CIPHER_SPEC, rec);
			
			// right after, switch the cipher for writing.
			_currentWriteState = _pendingWriteState;
			_pendingWriteState = null;
			
		}
		public function sendApplicationData(data:ByteArray, offset:uint=0, length:uint=0):void {
			var rec:ByteArray = new ByteArray;
			var len:uint = length;
			while (len>16384) {
				rec.position = 0;
				rec.writeBytes(data, offset, 16384);
				rec.position = 0;
				sendRecord(PROTOCOL_APPLICATION_DATA, rec);
				offset += 16384;
				len -= 16384;
			}
			rec.position = 0;
			rec.writeBytes(data, offset, len);
			rec.position = 0;
			sendRecord(PROTOCOL_APPLICATION_DATA, rec);
		}
		private function sendRecord(type:uint, payload:ByteArray):void {
			// encrypt
			payload = _currentWriteState.encrypt(type, payload);
			
			_oStream.writeByte(type);
			_oStream.writeShort(TLS_VERSION);
			_oStream.writeShort(payload.length);
			_oStream.writeBytes(payload, 0, payload.length);
			
			scheduleWrite();
		}
		
		private var _writeScheduler:uint;
		private function scheduleWrite():void {
			if (_writeScheduler!=0) return;
			_writeScheduler = setTimeout(commitWrite, 0);
		}
		private function commitWrite():void {
			clearTimeout(_writeScheduler);
			_writeScheduler = 0;
			if (_state != STATE_CLOSED) {
				dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
			}
		}
		
		private function sendClientAck():void {
			// send a client cert if we were asked for one. (although we don't support that yet. XXX)
			// send a client key exchange
			sendClientKeyExchange();
			// send a change cipher spec
			sendChangeCipherSpec();
			// send a finished
			sendFinished();
		}
		
		/**
		 * Vaguely gross function that parses a RSA key out of a certificate.
		 * 
		 * As long as that certificate looks just the way we expect it to.
		 * 
		 * @param cert: A bytearray that contains some DER-encoded goodness.
		 * 
		 */
		private function loadCertificates(certs:Array):void {
			
			var firstCert:X509Certificate = null;
			for (var i:int=0;i<certs.length;i++) {
				var x509:X509Certificate = new X509Certificate(certs[i]);
				_store.addCertificate(x509);
				if (firstCert==null) {
					firstCert = x509;
				}
			}
			
			if (firstCert.isSigned(_store, _config.CAStore)) {
				// ok, that's encouraging. now for the hostname match.
				if (_otherIdentity==null) {
					// we don't care who we're talking with. groovy.
					trace("TLS WARNING: No check made on the certificate's identity.");
					_otherCertificate = firstCert;
				} else {
					if (firstCert.getCommonName()==_otherIdentity) {
						_otherCertificate = firstCert;
					} else {
						throw new TLSError("Invalid common name: "+firstCert.getCommonName()+", expected "+_otherIdentity, TLSError.bad_certificate);
					}
				}
			} else {
				throw new TLSError("Cannot verify certificate", TLSError.bad_certificate);
			}
		}
		
		private function parseAlert(p:ByteArray):void {
			//throw new Error("Alert not implemented.");
			// 7.2
			trace("GOT ALERT! type="+p[1]);
			close();
		}
		private function parseChangeCipherSpec(p:ByteArray):void {
			p.readUnsignedByte();
			if (_pendingReadState==null) {
				throw new TLSError("Not ready to Change Cipher Spec, damnit.", TLSError.unexpected_message);
			}
			_currentReadState = _pendingReadState;
			_pendingReadState = null;
			// 7.1
		}
		private function parseApplicationData(p:ByteArray):void {
			dispatchEvent(new TLSEvent(TLSEvent.DATA, p));
		}
		
		private function handleTLSError(e:TLSError):void {
			// basic rules to keep things simple:
			// - Make a good faith attempt at notifying peers
			// - TLSErrors are always fatal.
			close(e);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -