public function setOutput(Core $core) { $alert = $this->alert; if ($alert->fromPeer()) { return; } $recordOut = $core->getOutDuplex()->getRecord(); $payload = $alert->decode(); $this->output = $recordOut->set('contentType', ContentType::ALERT)->set('payload', $payload)->decode(); }
public function decode() { $core = $this->core; $extensions = $core->extensions; $connOut = $core->getOutDuplex(); $sessionID = $core->getSessionID(); list($vMajor, $vMinor) = $core->getVersion(); // Set server random $connOut->random = Core::getRandom(32); $sessionLength = strlen($sessionID); $data = Core::_pack('C', $vMajor) . Core::_pack('C', $vMinor) . $connOut->random . Core::_pack('C', $sessionLength); if ($sessionLength > 0) { $data .= $sessionID; } $cipherSuite = $core->cipherSuite; list($cipher1, $cipher2) = $cipherSuite->getID(); $data .= Core::_pack('C', $cipher1) . Core::_pack('C', $cipher2); // Compression method length $data .= Core::_pack('C', 0x0); $extData = $extensions->onDecodeServerHello(); if (strlen($extData) > 0) { $data .= Core::_pack('n', strlen($extData)) . $extData; } $this->msgType = 2; $this->length = strlen($data); return $this->getBinHeader() . $data; }
public function decode() { $core = $this->core; list($vMajor, $vMinor) = $core->getVersion(); // Client $connOut = $core->getOutDuplex(); // Server $connIn = $core->getInDuplex(); // ECDHE if ($core->cipherSuite->isECDHEEnabled()) { $extensions = $core->extensions; $data = $extensions->call('Curve', 'decodeClientKeyExchange', ''); $preMaster = $extensions->call('Curve', 'getPremaster', null); } else { $preMaster = Core::_pack('C', $vMajor) . Core::_pack('C', $vMinor) . Core::getRandom(46); $crtDers = $core->getCrtDers(); $publicKey = X509::getPublicKey($crtDers); openssl_public_encrypt($preMaster, $encPreMaster, $publicKey); $data = Core::_pack('n', strlen($encPreMaster)) . $encPreMaster; } // Set Master Secret, IV and MAC $this->setKeys($preMaster, $connIn, $connOut); $this->msgType = HandshakeType::CLIENT_KEY_EXCHANGE; $this->length = strlen($data); return $this->getBinHeader() . $data; }
protected static function getZeroSeq() { $seq = []; for ($i = 0; $i < 8; $i++) { $seq[$i] = Core::_pack('C', 0); } return $seq; }
public function onDecodeClientHello() { $sigData = ''; foreach (self::$supportedAlgorithmList as $algorithm) { $sigData .= Core::_pack('C', $algorithm >> 8) . Core::_pack('C', $algorithm & 0xff); } $sigData = Core::_pack('n', strlen($sigData)) . $sigData; $this->extType = TLSExtensions::TYPE_SIGNATURE_ALGORITHM; $this->length = strlen($sigData); $data = $this->decodeHeader() . $sigData; return $data; }
public function decode() { $core = $this->core; $crtDers = $core->getCrtDers(); $crtData = ''; foreach ($crtDers as $crtDer) { $crtLength = strlen($crtDer); // Cert Length $crtData .= Core::_pack('C', 0x0) . Core::_pack('n', $crtLength) . $crtDer; } $data = Core::_pack('C', 0x0) . Core::_pack('n', strlen($crtData)) . $crtData; $this->msgType = HandshakeType::CERTIFICATE; $this->length = strlen($data); return $this->getBinHeader() . $data; }
/** * for Client Hello and Server Hello */ protected function encodeExtensions($data) { $extensions = []; for ($j = 0; $j < strlen($data);) { $extType = Core::_unpack('n', $data[$j] . $data[$j + 1]); $extDataLen = Core::_unpack('n', $data[$j + 2] . $data[$j + 3]); if (0 == $extDataLen) { $j += 2 + 2; continue; } $extData = substr($data, $j + 4, $extDataLen); $j += 2 + 2 + $extDataLen; $extensions[] = ['type' => $extType, 'data' => $extData]; } return $extensions; }
public static function decodeCipherList() { $data = ''; foreach (self::$enabledCipherSuites as $val) { $data .= Core::_pack('C', $val >> 8) . Core::_pack('C', $val & 0xff); } return $data; }
public function encodeHandshake($payload) { $core = $this->core; // Incomming Record $recordIn = $core->getInDuplex()->getRecord(); // Outgoing Record $recordOut = $core->getOutDuplex()->getRecord(); // Buffer to send $bufferOut = $core->getBufferOut(); // Extension $extensions = $core->extensions; if ($core->isHandshaked) { throw new TLSAlertException(Alert::create(Alert::UNEXPECTED_MESSAGE), "Handshake message received after handshake is complete"); } /* * https://tools.ietf.org/html/rfc5246#section-7.4 * * Get Handshake Msg type */ $handshakeType = Core::_unpack('C', $payload[0]); if ($this->expectedHandshakeType != $handshakeType) { throw new TLSAlertException(Alert::create(Alert::UNEXPECTED_MESSAGE), "Unexpected handshake message: {$handshakeType} <=> " . $this->expectedHandshakeType); } $handshake = HandshakeFactory::getInstance($core, $handshakeType); $handshake->encode($payload); $this->content = $handshake; switch ($this->expectedHandshakeType) { case HandshakeType::SERVER_HELLO: $this->expectedHandshakeType = HandshakeType::CERTIFICATE; break; case HandshakeType::CERTIFICATE: if ($core->cipherSuite->isECDHEEnabled()) { $this->expectedHandshakeType = HandshakeType::SERVER_KEY_EXCHANGE; } else { $this->expectedHandshakeType = HandshakeType::SERVER_HELLO_DONE; } break; case HandshakeType::SERVER_KEY_EXCHANGE: $this->expectedHandshakeType = HandshakeType::SERVER_HELLO_DONE; break; case HandshakeType::SERVER_HELLO_DONE: // =========================================== // Send Client Key Exchange // =========================================== $clientKeyExchange = HandshakeFactory::getInstance($core, HandshakeType::CLIENT_KEY_EXCHANGE); $bufferOut->set($this->decodeContent($clientKeyExchange->decode(), ContentType::HANDSHAKE)); // =========================================== // Send Change Cipher Spec // =========================================== $changeCipherSpec = new ChangeCipherSpec(); $bufferOut->append($this->decodeContent($changeCipherSpec->decode(), ContentType::CHANGE_CIPHER_SPEC)); // Enable encryption $recordOut->cipherChanged(); // =========================================== // Send Client finished // =========================================== $clientFinished = HandShakeFactory::getInstance($core, HandshakeType::FINISHED); $bufferOut->append($this->decodeContent($clientFinished->decode(), ContentType::HANDSHAKE)); $this->expectedHandshakeType = HandshakeType::FINISHED; break; case HandshakeType::FINISHED: $core->isHandshaked = true; break; } if (strlen($payload) > $handshake->get('length')) { $payload = substr($payload, $handshake->get('length')); $this->encodeHandshake($payload); } }
public function decode() { return Core::_pack('C', $this->level) . Core::_pack('C', $this->descCode); }
public function getPublicKey() { $privateKey = $this->getPrivateKey(); $this->publicKey = $publicKey = $privateKey->getPublicKey(); $publicPoint = $publicKey->getPoint(); // Convert to binary - Uncompressed $publicKeyBin = Core::_pack('C', 0x4) . gmp_export($publicPoint->getX(), 1, GMP_BIG_ENDIAN) . gmp_export($publicPoint->getY(), 1, GMP_BIG_ENDIAN); return $publicKeyBin; }
public function calculateMAC() { $conn = $this->conn; $core = $conn->getCore(); $cipherSuite = $core->cipherSuite; list($vMajor, $vMinor) = $core->getVersion(); if (is_null($this->seq)) { $this->seq = self::getZeroSeq(); } $secretMAC = $conn->MAC; $contentType = Core::_pack('C', $this->contentType); $major = Core::_pack('C', $vMajor); $minor = Core::_pack('C', $vMinor); $length = Core::_pack('n', strlen($this->payload)); /* * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 * * The MAC is generated as: * * MAC(MAC_write_key, seq_num + * TLSCompressed.type + * TLSCompressed.version + * TLSCompressed.length + * TLSCompressed.fragment); */ $concat = implode('', $this->seq) . $contentType . $major . $minor . $length . $this->payload; //$macStr = $cipherSuite->hashHmac($concat, $secretMAC, false ); $mac = $cipherSuite->hashHmac($concat, $secretMAC); return $mac; }
/** * Additional Authentication Data */ public function getAAD($length) { $conn = $this->conn; $core = $conn->getCore(); $cipherSuite = $core->cipherSuite; list($vMajor, $vMinor) = $core->getVersion(); if (is_null($this->seq)) { $this->seq = self::getZeroSeq(); } $contentType = Core::_pack('C', $this->contentType); $major = Core::_pack('C', $vMajor); $minor = Core::_pack('C', $vMinor); $length = Core::_pack('n', $length); /* * https://tools.ietf.org/html/rfc5246#section-6.2.3.3 * * additional_data = seq_num + TLSCompressed.type + * TLSCompressed.version + TLSCompressed.length; * */ $concat = implode('', $this->seq) . $contentType . $major . $minor . $length; return $concat; }
public function decode() { $core = $this->core; $connOut = $core->getOutDuplex(); list($vMajor, $vMinor) = $core->getVersion(); // Set client random $connOut->random = Core::getRandom(32); // Set TLS Version $data = Core::_pack('C', $vMajor) . Core::_pack('C', $vMinor); // Client Random $data .= $connOut->random; // Session ID - no session $data .= Core::_pack('C', 0x0); // Cipher Suite $cipherSuiteList = CipherSuites::decodeCipherList(); $data .= Core::_pack('n', strlen($cipherSuiteList)) . $cipherSuiteList; // Compression method $data .= Core::_pack('C', 0x1) . Core::_pack('C', $core->getCompressionMethod()); // Extension Length //$data .= Core::_pack('n', 0x00); $extensionData = $core->extensions->onDecodeClientHello(); $data .= Core::_pack('n', strlen($extensionData)) . $extensionData; $this->msgType = HandshakeType::CLIENT_HELLO; $this->length = strlen($data); return $this->getBinHeader() . $data; }
public function decode() { return Core::_pack('C', 0x1); }
protected function decodeHeader() { // MsgType $header = Core::_pack('C', 0) . Core::_pack('C', $this->extType) . Core::_pack('n', $this->length); return $header; }
public function decodeServerKeyExchange() { $core = $this->core; $extensions = $core->extensions; $protoVersion = $core->getProtocolVersion(); /* * ECCurveType * * We only support named curves, which is 0x03 * * enum { explicit_prime (1), explicit_char2 (2), * named_curve (3), reserved(248..255) } ECCurveType; */ $data = Core::_pack('C', 0x3); // Named curve type $data .= Core::_pack('n', $this->namedCurveType); // ECDH Public Key $this->ecdh = new EcDH($this->namedCurveType); $dataPublicKey = $this->ecdh->getPublicKey(); $data .= Core::_pack('C', strlen($dataPublicKey)) . $dataPublicKey; /* * Signature * * https://tools.ietf.org/html/rfc4492 Page 19 * signed_params: A hash of the params, with the signature appropriate * to that hash applied. The private key corresponding to the * certified public key in the server's Certificate message is used * for signing. * * ServerKeyExchange.signed_params.sha_hash * SHA(ClientHello.random + ServerHello.random + * ServerKeyExchange.params); */ $connIn = $core->getInDuplex(); $connOut = $core->getOutDuplex(); $dataSign = $connIn->random . $connOut->random . $data; $signature = $extensions->call('SignatureAlgorithm', 'getSignature', null, $dataSign); if ($protoVersion >= 32) { // Signature Hash Alogorithm // [null, null] never happens list($hash, $sig) = $extensions->call('SignatureAlgorithm', 'getAlgorithm', [null, null]); $data .= Core::_pack('C', $hash) . Core::_pack('C', $sig); } // Append signature $data .= Core::_pack('n', strlen($signature)) . $signature; $hs = HandShakeFactory::getInstance($core, HandshakeType::SERVER_KEY_EXCHANGE); $hs->setMsgType(HandshakeType::SERVER_KEY_EXCHANGE); $hs->set('length', strlen($data)); return $hs->getBinHeader() . $data; }
public function decode() { $core = $this->getCore(); list($vMajor, $vMinor) = $core->getVersion(); // type $data = Core::_pack('C', $this->contentType) . Core::_pack('C', $vMajor) . Core::_pack('C', $vMinor) . Core::_pack('n', $this->length) . $this->payload; // Handshake if ($this->contentType == ContentType::HANDSHAKE && !$this->conn->isCipherChanged) { $core->countHandshakeMessages($this->payload); } $this->reset(); return $data; }