Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.
(self, banner: Optional['Banner'], kex: Optional['SSH2_Kex'])
| 332 | |
| 333 | |
| 334 | def evaluate(self, banner: Optional['Banner'], kex: Optional['SSH2_Kex']) -> Tuple[bool, List[Dict[str, str]], str]: |
| 335 | '''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.''' |
| 336 | |
| 337 | ret = True |
| 338 | |
| 339 | banner_str = str(banner) |
| 340 | if (self._banner is not None) and (banner_str != self._banner): |
| 341 | ret = False |
| 342 | self._append_error('Banner', [self._banner], None, [banner_str]) |
| 343 | |
| 344 | # All subsequent tests require a valid kex, so end here if we don't have one. |
| 345 | if kex is None: |
| 346 | error_list, error_str = self._get_errors() |
| 347 | return ret, error_list, error_str |
| 348 | |
| 349 | if (self._compressions is not None) and (kex.server.compression != self._compressions): |
| 350 | ret = False |
| 351 | self._append_error('Compression', self._compressions, None, kex.server.compression) |
| 352 | |
| 353 | # If a list of optional host keys was given in the policy, remove any of its entries from the list retrieved from the server. This allows us to do an exact comparison with the expected list below. |
| 354 | pruned_host_keys = kex.key_algorithms |
| 355 | if self._optional_host_keys is not None: |
| 356 | pruned_host_keys = [x for x in kex.key_algorithms if x not in self._optional_host_keys] |
| 357 | |
| 358 | # Check host keys. |
| 359 | if self._host_keys is not None: |
| 360 | # If the policy allows subsets and re-ordered algorithms... |
| 361 | if self._allow_algorithm_subset_and_reordering: |
| 362 | for hostkey_t in kex.key_algorithms: |
| 363 | if hostkey_t not in self._host_keys: |
| 364 | ret = False |
| 365 | self._append_error('Host keys', self._host_keys, self._optional_host_keys, kex.key_algorithms) |
| 366 | break |
| 367 | # The policy requires exact matching of algorithms. |
| 368 | elif pruned_host_keys != self._host_keys: |
| 369 | ret = False |
| 370 | self._append_error('Host keys', self._host_keys, self._optional_host_keys, kex.key_algorithms) |
| 371 | |
| 372 | # Check host key sizes. |
| 373 | if self._hostkey_sizes is not None: |
| 374 | hostkey_types = list(self._hostkey_sizes.keys()) |
| 375 | hostkey_types.sort() # Sorted to make testing output repeatable. |
| 376 | for hostkey_type in hostkey_types: |
| 377 | expected_hostkey_size = cast(int, self._hostkey_sizes[hostkey_type]['hostkey_size']) |
| 378 | server_host_keys = kex.host_keys() |
| 379 | if hostkey_type in server_host_keys: |
| 380 | actual_hostkey_size = cast(int, server_host_keys[hostkey_type]['hostkey_size']) |
| 381 | if (self._allow_larger_keys and actual_hostkey_size < expected_hostkey_size) or \ |
| 382 | (not self._allow_larger_keys and actual_hostkey_size != expected_hostkey_size): |
| 383 | ret = False |
| 384 | self._append_error('Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)]) |
| 385 | |
| 386 | # If we have expected CA signatures set, check them against what the server returned. |
| 387 | if self._hostkey_sizes is not None and len(cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])) > 0 and cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) > 0: |
| 388 | expected_ca_key_type = cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type']) |
| 389 | expected_ca_key_size = cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) |
| 390 | actual_ca_key_type = cast(str, server_host_keys[hostkey_type]['ca_key_type']) |
| 391 | actual_ca_key_size = cast(int, server_host_keys[hostkey_type]['ca_key_size']) |