Example #1
0
 protected static function unserializeSub(\fpoirotte\Pssht\Wire\Decoder $decoder)
 {
     $signature = $decoder->decodeBoolean();
     $algorithm = $decoder->decodeString();
     $res = array($algorithm, $decoder->decodeString());
     if ($signature === true) {
         $decoder2 = new \fpoirotte\Pssht\Wire\Decoder(new \fpoirotte\Pssht\Buffer($decoder->decodeString()));
         if ($decoder2->decodeString() !== $algorithm) {
             throw new \InvalidArgumentException();
         }
         $res[] = $decoder2->decodeString();
     }
     return $res;
 }
Example #2
0
 public static function loadPublic($b64)
 {
     $decoder = new \fpoirotte\Pssht\Wire\Decoder();
     $decoder->getBuffer()->push(base64_decode($b64));
     $type = $decoder->decodeString();
     if ($type !== static::getName()) {
         throw new \InvalidArgumentException();
     }
     $pk = $decoder->decodeString();
     if ($pk === null) {
         throw new \InvalidArgumentException();
     }
     return new static(gmp_init(bin2hex($pk), 16));
 }
Example #3
0
 /**
  * Try to read and handle a single SSH message.
  *
  *  \retval bool
  *      \b true if a message was successfully read and handled,
  *      \b false otherwise.
  *
  *  \note
  *      Depending on the circumstances, messages may be successfully
  *      read but left unhandled (eg. because the message was incomplete).
  *      In such cases, the message will be reinjected and \b false
  *      returned, making it possible for a future call to this method
  *      to handle the (full) message again.
  */
 public function readMessage()
 {
     $logging = \Plop\Plop::getInstance();
     // Initial state: expect the client's identification string.
     if (!isset($this->context['identity']['client'])) {
         return $this->handlers[256]->handle(null, $this->decoder, $this, $this->context);
     }
     $blockSize = max($this->decryptor->getBlockSize(), 8);
     // See http://api.libssh.org/rfc/PROTOCOL
     // for more information on EtM (Encrypt-then-MAC).
     if ($this->inMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) {
         $encPayload = $this->decoder->getBuffer()->get(4);
         if ($encPayload === null) {
             return false;
         }
         $unencrypted = $encPayload;
     } elseif ($this->decryptor instanceof \fpoirotte\Pssht\AEADInterface) {
         $encPayload = $this->decoder->getBuffer()->get(4);
         if ($encPayload === null) {
             return false;
         }
         $unencrypted = $this->decryptor->decrypt($this->inSeqNo, $encPayload);
         $this->decoder->getBuffer()->unget($encPayload);
         $encPayload = '';
     } else {
         $encPayload = $this->decoder->getBuffer()->get($blockSize);
         if ($encPayload === null) {
             return false;
         }
         $unencrypted = $this->decryptor->decrypt($this->inSeqNo, $encPayload);
     }
     $buffer = new \fpoirotte\Pssht\Buffer($unencrypted);
     $decoder = new \fpoirotte\Pssht\Wire\Decoder($buffer);
     $packetLength = $decoder->decodeUint32();
     // Read the rest of the message.
     if ($this->inMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) {
         // Only the main payload remains.
         $toRead = $packetLength;
     } elseif ($this->decryptor instanceof \fpoirotte\Pssht\AEADInterface) {
         // packet length (authenticated data)
         // + encrypted payload
         // + authentication tag (AT)
         $toRead = 4 + $packetLength + $this->decryptor->getSize();
     } else {
         $toRead = 4 - $blockSize + $packetLength;
     }
     if ($toRead < 0) {
         throw new \RuntimeException();
     }
     $unencrypted2 = '';
     if ($toRead !== 0) {
         $encPayload2 = $this->decoder->getBuffer()->get($toRead);
         if ($encPayload2 === null) {
             $this->decoder->getBuffer()->unget($encPayload);
             return false;
         }
         $unencrypted2 = $this->decryptor->decrypt($this->inSeqNo, $encPayload2);
         if ($unencrypted2 === null) {
             return false;
         }
         $buffer->push($unencrypted2);
     }
     $paddingLength = ord($decoder->decodeBytes());
     $payload = $decoder->decodeBytes($packetLength - $paddingLength - 1);
     $padding = $decoder->decodeBytes($paddingLength);
     // If a MAC is in use.
     $macSize = $this->inMAC->getSize();
     $actualMAC = '';
     if ($macSize > 0) {
         $actualMAC = $this->decoder->getBuffer()->get($macSize);
         if ($actualMAC === null) {
             $this->decoder->getBuffer()->unget($encPayload2)->unget($encPayload);
             return false;
         }
         if ($this->inMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) {
             // $encPayload actually contains packet length (in plaintext).
             $macData = $encPayload . $encPayload2;
         } else {
             $macData = $unencrypted . $unencrypted2;
         }
         $expectedMAC = $this->inMAC->compute($this->inSeqNo, (string) substr($macData, 0, $packetLength + 4));
         if ($expectedMAC !== $actualMAC) {
             throw new \RuntimeException();
         }
     }
     if (!isset($packetLength, $paddingLength, $payload, $padding, $actualMAC)) {
         $this->decoder->getBuffer()->unget($actualMAC)->unget($encPayload2)->unget($encPayload);
         $logging->error('Something went wrong during decoding');
         return false;
     }
     $payload = $this->uncompressor->update($payload);
     $decoder = new \fpoirotte\Pssht\Wire\Decoder(new \fpoirotte\Pssht\Buffer($payload));
     $msgType = ord($decoder->decodeBytes(1));
     $logging->debug('Received payload: %s', array(\escape($payload)));
     $res = true;
     if (isset($this->handlers[$msgType])) {
         $handler = $this->handlers[$msgType];
         $logging->debug('Calling %(handler)s with message type #%(msgType)d', array('handler' => get_class($handler) . '::handle', 'msgType' => $msgType));
         try {
             $res = $handler->handle($msgType, $decoder, $this, $this->context);
         } catch (\fpoirotte\Pssht\Messages\DISCONNECT $e) {
             if ($e->getCode() !== 0) {
                 $this->writeMessage($e);
             }
             throw $e;
         }
     } else {
         $logging->warn('Unimplemented message type (%d)', array($msgType));
         $response = new \fpoirotte\Pssht\Messages\UNIMPLEMENTED($this->inSeqNo);
         $this->writeMessage($response);
     }
     $this->inSeqNo = ++$this->inSeqNo & 0xffffffff;
     return $res;
 }
Example #4
0
 protected static function unserializeSub(\fpoirotte\Pssht\Wire\Decoder $decoder)
 {
     $algorithm = $decoder->decodeString();
     $res = array($algorithm, $decoder->decodeString(), $decoder->decodeString(), $decoder->decodeString());
     // Special handling for signature.
     $decoder2 = new \fpoirotte\Pssht\Wire\Decoder(new \fpoirotte\Pssht\Buffer($decoder->decodeString()));
     if ($decoder2->decodeString() !== $algorithm) {
         throw new \InvalidArgumentException();
     }
     $res[] = $decoder2->decodeString();
     return $res;
 }