Exemple #1
0
 public function encode($data)
 {
     $core = $this->core;
     $extensions = $core->extensions;
     // Client
     $connIn = $core->getInDuplex();
     // Server
     $connOut = $core->getOutDuplex();
     $data = $this->encodeHeader($data);
     // ECDHE
     if ($core->cipherSuite->isECDHEEnabled()) {
         $publicKeyLen = Core::_unpack('C', $data[0]);
         $publicKey = substr($data, 1, $publicKeyLen);
         $preMaster = $extensions->call('Curve', 'calculatePreMaster', null, $publicKey);
     } else {
         // https://tools.ietf.org/html/rfc5246#section-7.4.7.1
         // Get a Premaster Secret
         $preMasterLen = Core::_unpack('n', $data[0] . $data[1]);
         $encPreMaster = substr($data, 2, $preMasterLen);
         $privateKey = $core->getConfig('private_key');
         openssl_private_decrypt($encPreMaster, $preMaster, $privateKey);
         $vMajor = Core::_unpack('C', $preMaster[0]);
         $vMinor = Core::_unpack('C', $preMaster[1]);
         list($vMajor2, $vMinor2) = $core->getVersion();
         if ($vMajor != $vMajor2 || $vMinor != $vMinor) {
             throw new TLSAlertException(Alert::create(Alert::BAD_RECORD_MAC), "Invalid protocol version in PreMaster {$vMajor} <=> {$vMajor2}, {$vMinor} <=> {$vMinor2}");
         }
     }
     $this->setKeys($preMaster, $connOut, $connIn);
 }
Exemple #2
0
 public function encode($data)
 {
     $this->level = Core::_unpack('C', $data[0]);
     $this->descCode = Core::_unpack('C', $data[1]);
     // We got alert message from peer
     $this->fromPeer = true;
 }
Exemple #3
0
 public function onEncodeClientHello($type, $data)
 {
     $core = $this->core;
     if ($type != TLSExtensions::TYPE_SIGNATURE_ALGORITHM) {
         return;
     }
     $protoVersion = $core->getProtocolVersion();
     /*
      *   Note: this extension is not meaningful for TLS versions prior to 1.2.
      * Clients MUST NOT offer it if they are offering prior versions.
      * However, even if clients do offer it, the rules specified in [TLSEXT]
      * require servers to ignore extensions they do not understand.
      */
     if ($protoVersion < 32) {
         return;
     }
     $length = Core::_unpack('n', $data[0] . $data[1]);
     $data = substr($data, 2);
     for ($i = 0; $i < $length; $i += 2) {
         $hash = Core::_unpack('C', $data[$i]);
         $sig = Core::_unpack('C', $data[$i + 1]);
         $algorithm = $hash << 8 | $sig;
         if (in_array($algorithm, self::$supportedAlgorithmList)) {
             $this->algorithm = $algorithm;
             break;
         }
     }
 }
 protected function incrementSeq()
 {
     if (is_null($this->seq)) {
         $this->seq = $this->getZeroSeq();
     }
     for ($i = 7; $i >= 0; $i--) {
         $num = Core::_unpack('C', $this->seq[$i]) + 1;
         $this->seq[$i] = Core::_pack('C', $num);
         if ($num % 256 > 0) {
             break;
         }
     }
 }
Exemple #5
0
 /**
  * Client Hello
  * https://tools.ietf.org/html/rfc5246#section-7.4.1.2
  */
 public function encode($data)
 {
     $core = $this->core;
     $connIn = $core->getInDuplex();
     $data = $this->encodeHeader($data);
     // https://tools.ietf.org/html/rfc5246#section-7.4.1.2
     $vMajor = $major = Core::_unpack('C', $data[0]);
     $vMinor = $minor = Core::_unpack('C', $data[1]);
     // Set TLS Version
     $core->setVersion($vMajor, $vMinor);
     // Get and set Client Random
     $random = substr($data, 2, 32);
     $connIn->random = $random;
     $sessionLength = Core::_unpack('C', $data[34]);
     $data = substr($data, 35);
     // SessionID if > 0
     if ($sessionLength > 0) {
         $sessionID = substr($data, 0, $sessionLength);
         $core->setSessionID($sessionID);
         $data = substr($data, $sessionLength);
     }
     $cipherLength = Core::_unpack('n', $data[0] . $data[1]);
     $data = substr($data, 2);
     $cipherIDs = [];
     // https://github.com/pornin/TestSSLServer/blob/master/Src/CipherSuite.cs
     for ($i = 0; $i < $cipherLength; $i += 2) {
         // https://tools.ietf.org/html/rfc5246#section-7.4.1.2
         $cipher1 = Core::_unpack('C', $data[$i]);
         $cipher2 = Core::_unpack('C', $data[$i + 1]);
         $cipherIDs[] = [$cipher1, $cipher2];
     }
     $this->requestCipherIDs = $cipherIDs;
     $data = substr($data, $cipherLength);
     $compressionLength = Core::_unpack('C', $data[0]);
     $compressionMethod = Core::_unpack('C', $data[1]);
     if ($compressionMethod != 0x0) {
         throw new TLSAlertException(Alert::create(Alert::HANDSHAKE_FAILURE), "compressionMethod is not null");
     }
     $core->setCompressionMethod($compressionMethod);
     // Extensions
     $extLength = Core::_unpack('n', $data[2] . $data[3]);
     $data = substr($data, 4, $extLength);
     $this->requestedExtensions = $extensions = $this->encodeExtensions($data);
     $core->extensions->onEncodeClientHello($extensions);
     $cipherID = CipherSuites::pickCipherID($core, $cipherIDs);
     if (is_null($cipherID)) {
         throw new TLSAlertException(Alert::create(Alert::INTERNAL_ERROR), "Cipher Suite not found");
     }
     $core->cipherSuite = new CipherSuites($cipherID);
 }
Exemple #6
0
 public function encode($data)
 {
     $core = $this->core;
     $data = $this->encodeHeader($data);
     $crtsLength = Core::_unpack('N', $data[0] . $data[1] . $data[2] . 0x0) >> 8;
     $crtsData = substr($data, 3, $crtsLength);
     for ($i = 0; $i < $crtsLength;) {
         $crtLength = Core::_unpack('n', $crtsData[$i + 1] . $crtsData[$i + 2]);
         if (0 >= (int) $crtLength) {
             break;
         }
         $crtDers[] = substr($crtsData, $i + 3, $crtLength);
         $i += $crtLength + 3;
     }
     $core->setCrtDers($crtDers);
 }
Exemple #7
0
 /**
  * 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;
 }
Exemple #8
0
 protected function encodeHeader($data)
 {
     $data = $this->encodeBuffer->flush() . $data;
     $this->contentType = Core::_unpack('C', $data[0]);
     $vMajor = Core::_unpack('C', $data[1]);
     $vMinor = Core::_unpack('C', $data[2]);
     $this->length = Core::_unpack('n', $data[3] . $data[4]);
     if ($this->length > $this->maxLength) {
         /*
          * A TLSCiphertext record was received that had a length more than
          * 2^14+2048 bytes, or a record decrypted to a TLSCompressed record
          * with more than 2^14+1024 bytes.
          */
         throw new TLSAlertException(Alert::create(Alert::RECORD_OVERFLOW), "Exceed max length of payload: " . strlen($data));
     }
     if ($this->length > strlen($data)) {
         $this->encodeBuffer->set($data);
         return false;
     }
     $this->payload = substr($data, 5, $this->length);
     $this->dataRest = substr($data, 5 + $this->length);
     return true;
 }
Exemple #9
0
 public function encode($data)
 {
     $core = $this->core;
     $connIn = $core->getInDuplex();
     $data = $this->encodeHeader($data);
     $vMajor = Core::_unpack('C', $data[0]);
     $vMinor = Core::_unpack('C', $data[1]);
     // Server Random
     $random = substr($data, 2, 32);
     $connIn->random = $random;
     // Session ID
     $sessionLength = Core::_unpack('C', $data[34]);
     $data = substr($data, 35);
     // SessionID if > 0
     if ($sessionLength > 0) {
         $sessionID = substr($data, 35, $sessionLength);
         $core->setSessionID($sessionID);
         $data = substr($data, $sessionLength);
     }
     $cipherID = [Core::_unpack('C', $data[0]), Core::_unpack('C', $data[1])];
     $cipherSuite = new CipherSuites($cipherID);
     if (is_null($cipherSuite)) {
         throw new TLSAlertException(Alert::create(Alert::INTERNAL_ERROR), "cipherSuite is null");
     }
     $core->cipherSuite = $cipherSuite;
     // Cipher Suite
     $core->setCompressionMethod(Core::_unpack('C', $data[2]));
     // Extensions
     if (strlen($data) < 5) {
         return;
     }
     $extLength = Core::_unpack('n', $data[3] . $data[4]);
     $data = substr($data, 5, $extLength);
     $this->requestedExtensions = $extensions = $this->encodeExtensions($data);
     $core->extensions->onEncodeServerHello($extensions);
 }
Exemple #10
0
 public function encodeServerKeyExchange($data)
 {
     // Must turn true when onEncodeServerHello is called
     //if( !$this->isUncompressed )
     //    return;
     $core = $this->core;
     $hs = HandShakeFactory::getInstance($core, HandshakeType::SERVER_KEY_EXCHANGE);
     $data = $hs->encodeHeader($data);
     $length = $hs->get('length');
     $curveType = Core::_unpack('C', $data[0]);
     if ($curveType != 0x3) {
         throw new TLSAlertException(Alert::create(Alert::INTERNAL_ERROR), "Not named curve type: " + $curveType);
     }
     $namedCurveType = Core::_unpack('n', $data[1] . $data[2]);
     if (!EcDH::isSupported($namedCurveType)) {
         throw new TLSAlertException(Alert::create(Alert::INTERNAL_ERROR), "Unknow named curve: " + $namedCurveType);
     }
     $this->namedCurveType = $namedCurveType;
     $this->ecdh = new EcDH($this->namedCurveType);
     $publicKeyLen = Core::_unpack('C', $data[3]);
     $data = substr($data, 4);
     $publicKeyBin = substr($data, 0, $publicKeyLen);
     // Calculate and set premaster
     $this->calculatePremaster($publicKeyBin);
     // TODO verify signature
 }
Exemple #11
0
 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);
     }
 }
Exemple #12
0
 public function encode($data)
 {
     $msg = Core::_unpack('C', $data[0]);
 }