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 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); } }