pssht  latest
SSH server library written in PHP
HostBased.php
1 <?php
2 
3 /*
4 * This file is part of pssht.
5 *
6 * (c) François Poirotte <clicky@erebot.net>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 
13 
15 
20 {
22  protected $store;
23 
30  public function __construct(\fpoirotte\Pssht\KeyStore $store)
31  {
32  $this->store = $store;
33  }
34 
35  public static function getName()
36  {
37  return 'hostbased';
38  }
39 
40  public function check(
41  \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message,
42  \fpoirotte\Pssht\Transport $transport,
43  array &$context
44  ) {
45  if (!($message instanceof \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\HostBased)) {
46  throw new \InvalidArgumentException();
47  }
48 
49  return self::CHECK_OK;
50  }
51 
52  public function authenticate(
53  \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message,
54  \fpoirotte\Pssht\Transport $transport,
55  array &$context
56  ) {
57  if (!($message instanceof \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\HostBased)) {
58  throw new \InvalidArgumentException();
59  }
60 
61  $logging = \Plop\Plop::getInstance();
62  $reverse = gethostbyaddr($transport->getAddress());
63  $untrustedHost = rtrim($message->getHostname(), '.');
65  $cls = $algos->getClass('Key', $message->getAlgorithm());
66 
67  if ($cls === null || !$this->store->exists($message->getUserName(), $message->getKey())) {
68  $logging->info(
69  'Rejected host based connection from "%(ruser)s@%(rhost)s" ' .
70  '(%(ruser)s@%(reverse)s [%(address)s]) to "%(luser)s" '.
71  '(unsupported key)',
72  array(
73  'ruser' => escape($message->getRemoteUser()),
74  'luser' => escape($message->getUserName()),
75  'rhost' => escape($untrustedHost),
76  'reverse' => $reverse,
77  'address' => $transport->getAddress(),
78  )
79  );
80  return self::AUTH_REMOVE;
81  }
82 
83  $decoder = new \fpoirotte\Pssht\Wire\Decoder();
84  $decoder->getBuffer()->push($message->getKey());
85  if ($decoder->decodeString() !== $message->getAlgorithm()) {
86  // The key is not of the type claimed.
87  return self::AUTH_REJECT;
88  }
89  $key = $cls::unserialize($decoder);
90 
91  $encoder = new \fpoirotte\Pssht\Wire\Encoder();
92  $encoder->encodeString($context['DH']->getExchangeHash());
93  $encoder->encodeBytes(chr(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base::getMessageId()));
94  $encoder->encodeString($message->getUserName());
95  $encoder->encodeString($message->getServiceName());
96  $encoder->encodeString(static::getName());
97  $encoder->encodeString($message->getAlgorithm());
98  $encoder->encodeString($message->getKey());
99  $encoder->encodeString($message->getHostname());
100  $encoder->encodeString($message->getRemoteUser());
101 
102  if (!$key->check($encoder->getBuffer()->get(0), $message->getSignature())) {
103  $logging->warn(
104  'Rejected host based connection from "%(ruser)s@%(rhost)s" ' .
105  '(%(ruser)s@%(reverse)s [%(address)s]) to "%(luser)s" ' .
106  '(invalid signature)',
107  array(
108  'ruser' => escape($message->getRemoteUser()),
109  'luser' => escape($message->getUserName()),
110  'rhost' => escape($untrustedHost),
111  'reverse' => $reverse,
112  'address' => $transport->getAddress(),
113  )
114  );
115  return self::AUTH_REJECT;
116  }
117 
118  if ($reverse !== $untrustedHost) {
119  $logging->warning(
120  'Ignored reverse lookup mismatch for %(address)s (' .
121  '"%(reverse)s" vs. "%(untrusted)s")',
122  array(
123  'address' => $transport->getAddress(),
124  'reverse' => $reverse,
125  'untrusted' => escape($untrustedHost),
126  )
127  );
128  }
129 
130  if ($message->getUserName() !== $message->getRemoteUser()) {
131  $logging->warning(
132  'Rejected host based connection from "%(ruser)s@%(rhost)s" ' .
133  '(%(ruser)s@%(reverse)s [%(address)s]): ' .
134  'remote user does not match local user (%(luser)s)',
135  array(
136  'ruser' => escape($message->getRemoteUser()),
137  'luser' => escape($message->getUserName()),
138  'rhost' => escape($untrustedHost),
139  'reverse' => $reverse,
140  'address' => $transport->getAddress(),
141  )
142  );
143  return self::AUTH_REMOVE;
144  }
145 
146  $logging->info(
147  'Accepted host based connection from "%(ruser)s@%(rhost)s" ' .
148  '(%(ruser)s@%(reverse)s [%(address)s]) to "%(luser)s" ' .
149  '(using "%(algorithm)s" algorithm)',
150  array(
151  'ruser' => escape($message->getRemoteUser()),
152  'luser' => escape($message->getUserName()),
153  'rhost' => escape($untrustedHost),
154  'reverse' => $reverse,
155  'address' => $transport->getAddress(),
156  'algorithm' => escape($message->getAlgorithm()),
157  )
158  );
159  return self::AUTH_ACCEPT;
160  }
161 }
__construct(\fpoirotte\Pssht\KeyStore $store)
Definition: HostBased.php:30
check(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message,\fpoirotte\Pssht\Transport $transport, array &$context)
Definition: HostBased.php:40
$store
Store for the host keys.
Definition: HostBased.php:22
authenticate(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message,\fpoirotte\Pssht\Transport $transport, array &$context)
Definition: HostBased.php:52
static getName()
Return the name of the algorithm.
Definition: HostBased.php:35