asyncssh 2.15.0__tar.gz → 2.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. {asyncssh-2.15.0 → asyncssh-2.16.0}/CONTRIBUTING.rst +9 -10
  2. {asyncssh-2.15.0/asyncssh.egg-info → asyncssh-2.16.0}/PKG-INFO +1 -1
  3. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/config.py +7 -5
  4. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/connection.py +189 -21
  5. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/cipher.py +48 -30
  6. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/x509.py +2 -1
  7. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/logging.py +22 -12
  8. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/misc.py +13 -0
  9. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/saslprep.py +4 -2
  10. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/sftp.py +11 -13
  11. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/version.py +1 -1
  12. {asyncssh-2.15.0 → asyncssh-2.16.0/asyncssh.egg-info}/PKG-INFO +1 -1
  13. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/changes.rst +37 -0
  14. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_config.py +7 -1
  15. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_connection.py +131 -1
  16. {asyncssh-2.15.0 → asyncssh-2.16.0}/.coveragerc +0 -0
  17. {asyncssh-2.15.0 → asyncssh-2.16.0}/.github/workflows/run_tests.yml +0 -0
  18. {asyncssh-2.15.0 → asyncssh-2.16.0}/.gitignore +0 -0
  19. {asyncssh-2.15.0 → asyncssh-2.16.0}/.readthedocs.yaml +0 -0
  20. {asyncssh-2.15.0 → asyncssh-2.16.0}/COPYRIGHT +0 -0
  21. {asyncssh-2.15.0 → asyncssh-2.16.0}/LICENSE +0 -0
  22. {asyncssh-2.15.0 → asyncssh-2.16.0}/MANIFEST.in +0 -0
  23. {asyncssh-2.15.0 → asyncssh-2.16.0}/README.rst +0 -0
  24. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/__init__.py +0 -0
  25. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/agent.py +0 -0
  26. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/agent_unix.py +0 -0
  27. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/agent_win32.py +0 -0
  28. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/asn1.py +0 -0
  29. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/auth.py +0 -0
  30. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/auth_keys.py +0 -0
  31. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/channel.py +0 -0
  32. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/client.py +0 -0
  33. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/compression.py +0 -0
  34. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/constants.py +0 -0
  35. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/__init__.py +0 -0
  36. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/chacha.py +0 -0
  37. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/dh.py +0 -0
  38. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/dsa.py +0 -0
  39. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/ec.py +0 -0
  40. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/ec_params.py +0 -0
  41. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/ed.py +0 -0
  42. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/kdf.py +0 -0
  43. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/misc.py +0 -0
  44. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/rsa.py +0 -0
  45. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/sntrup.py +0 -0
  46. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/crypto/umac.py +0 -0
  47. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/dsa.py +0 -0
  48. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/ecdsa.py +0 -0
  49. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/eddsa.py +0 -0
  50. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/editor.py +0 -0
  51. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/encryption.py +0 -0
  52. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/forward.py +0 -0
  53. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/gss.py +0 -0
  54. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/gss_unix.py +0 -0
  55. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/gss_win32.py +0 -0
  56. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/kex.py +0 -0
  57. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/kex_dh.py +0 -0
  58. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/kex_rsa.py +0 -0
  59. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/keysign.py +0 -0
  60. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/known_hosts.py +0 -0
  61. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/listener.py +0 -0
  62. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/mac.py +0 -0
  63. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/packet.py +0 -0
  64. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/pattern.py +0 -0
  65. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/pbe.py +0 -0
  66. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/pkcs11.py +0 -0
  67. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/process.py +0 -0
  68. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/public_key.py +0 -0
  69. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/py.typed +0 -0
  70. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/rsa.py +0 -0
  71. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/scp.py +0 -0
  72. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/server.py +0 -0
  73. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/session.py +0 -0
  74. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/sk.py +0 -0
  75. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/sk_ecdsa.py +0 -0
  76. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/sk_eddsa.py +0 -0
  77. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/socks.py +0 -0
  78. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/stream.py +0 -0
  79. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/subprocess.py +0 -0
  80. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/tuntap.py +0 -0
  81. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh/x11.py +0 -0
  82. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh.egg-info/SOURCES.txt +0 -0
  83. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh.egg-info/dependency_links.txt +0 -0
  84. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh.egg-info/requires.txt +0 -0
  85. {asyncssh-2.15.0 → asyncssh-2.16.0}/asyncssh.egg-info/top_level.txt +0 -0
  86. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/_templates/sidebarbottom.html +0 -0
  87. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/_templates/sidebartop.html +0 -0
  88. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/api.rst +0 -0
  89. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/conf.py +0 -0
  90. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/contributing.rst +0 -0
  91. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/index.rst +0 -0
  92. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/requirements.txt +0 -0
  93. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/rftheme/layout.html +0 -0
  94. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/rftheme/static/rftheme.css_t +0 -0
  95. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/rftheme/theme.conf +0 -0
  96. {asyncssh-2.15.0 → asyncssh-2.16.0}/docs/rtd-req.txt +0 -0
  97. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/callback_client.py +0 -0
  98. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/callback_client2.py +0 -0
  99. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/callback_client3.py +0 -0
  100. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/callback_math_server.py +0 -0
  101. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/chat_server.py +0 -0
  102. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/check_exit_status.py +0 -0
  103. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/chroot_sftp_server.py +0 -0
  104. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/direct_client.py +0 -0
  105. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/direct_server.py +0 -0
  106. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/editor.py +0 -0
  107. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/gather_results.py +0 -0
  108. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/listening_client.py +0 -0
  109. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/local_forwarding_client.py +0 -0
  110. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/local_forwarding_client2.py +0 -0
  111. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/local_forwarding_server.py +0 -0
  112. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/math_client.py +0 -0
  113. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/math_server.py +0 -0
  114. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/redirect_input.py +0 -0
  115. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/redirect_local_pipe.py +0 -0
  116. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/redirect_remote_pipe.py +0 -0
  117. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/redirect_server.py +0 -0
  118. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/remote_forwarding_client.py +0 -0
  119. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/remote_forwarding_client2.py +0 -0
  120. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/remote_forwarding_server.py +0 -0
  121. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/reverse_client.py +0 -0
  122. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/reverse_server.py +0 -0
  123. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/scp_client.py +0 -0
  124. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/set_environment.py +0 -0
  125. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/set_terminal.py +0 -0
  126. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/sftp_client.py +0 -0
  127. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/show_environment.py +0 -0
  128. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/show_terminal.py +0 -0
  129. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_cert_server.py +0 -0
  130. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_client.py +0 -0
  131. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_keyed_server.py +0 -0
  132. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_scp_server.py +0 -0
  133. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_server.py +0 -0
  134. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/simple_sftp_server.py +0 -0
  135. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/stream_direct_client.py +0 -0
  136. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/stream_direct_server.py +0 -0
  137. {asyncssh-2.15.0 → asyncssh-2.16.0}/examples/stream_listening_client.py +0 -0
  138. {asyncssh-2.15.0 → asyncssh-2.16.0}/mypy.ini +0 -0
  139. {asyncssh-2.15.0 → asyncssh-2.16.0}/pylintrc +0 -0
  140. {asyncssh-2.15.0 → asyncssh-2.16.0}/setup.cfg +0 -0
  141. {asyncssh-2.15.0 → asyncssh-2.16.0}/setup.py +0 -0
  142. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/__init__.py +0 -0
  143. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/gss_stub.py +0 -0
  144. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/gssapi_stub.py +0 -0
  145. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/keysign_stub.py +0 -0
  146. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/pkcs11_stub.py +0 -0
  147. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/server.py +0 -0
  148. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/sk_stub.py +0 -0
  149. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/sspi_stub.py +0 -0
  150. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_agent.py +0 -0
  151. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_asn1.py +0 -0
  152. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_auth.py +0 -0
  153. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_auth_keys.py +0 -0
  154. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_channel.py +0 -0
  155. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_compression.py +0 -0
  156. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_connection_auth.py +0 -0
  157. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_editor.py +0 -0
  158. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_encryption.py +0 -0
  159. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_forward.py +0 -0
  160. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_kex.py +0 -0
  161. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_known_hosts.py +0 -0
  162. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_logging.py +0 -0
  163. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_mac.py +0 -0
  164. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_packet.py +0 -0
  165. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_pkcs11.py +0 -0
  166. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_process.py +0 -0
  167. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_public_key.py +0 -0
  168. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_saslprep.py +0 -0
  169. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_sftp.py +0 -0
  170. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_sk.py +0 -0
  171. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_stream.py +0 -0
  172. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_subprocess.py +0 -0
  173. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_tuntap.py +0 -0
  174. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_x11.py +0 -0
  175. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/test_x509.py +0 -0
  176. {asyncssh-2.15.0 → asyncssh-2.16.0}/tests/util.py +0 -0
  177. {asyncssh-2.15.0 → asyncssh-2.16.0}/tox.ini +0 -0
@@ -68,19 +68,18 @@ contributors list.
68
68
  Branches
69
69
  --------
70
70
 
71
- There are two long-lived branches in AsyncSSH at the moment:
71
+ There are two long-lived branches in AsyncSSH:
72
72
 
73
73
  * The master branch is intended to contain the latest stable version
74
74
  of the code. All official versions of AsyncSSH are released from
75
75
  this branch, and each release has a corresponding tag added
76
- matching its release number. Bug fixes and simple improvements
77
- may be checked directly into this branch, but most new features
78
- will be added to the develop branch first.
79
-
80
- * The develop branch is intended to contain features for developers
81
- to test before they are ready to be added to an official release.
82
- APIs in the develop branch may be subject to change until they
83
- are migrated back to master, and there's no guarantee of backward
76
+ matching its release number.
77
+
78
+ * The develop branch is intended to contain new features and bug fixes
79
+ ready to be tested before being added to an official release. APIs
80
+ in the develop branch may be subject to change until they are
81
+ migrated back to master, and there's no guarantee of backward
84
82
  compatibility in this branch. However, pulling from this branch
85
83
  will provide early access to new functionality and a chance to
86
- influence this functionality before it is released.
84
+ influence this functionality before it is released. Also, all
85
+ pull requests should be submitted against this branch.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: asyncssh
3
- Version: 2.15.0
3
+ Version: 2.16.0
4
4
  Summary: AsyncSSH: Asynchronous SSHv2 client and server library
5
5
  Home-page: http://asyncssh.timeheart.net
6
6
  Author: Ron Frederick
@@ -321,11 +321,15 @@ class SSHConfig:
321
321
 
322
322
  args = []
323
323
  loption = ''
324
+ allow_equal = True
324
325
 
325
326
  for i, arg in enumerate(split_args, 1):
326
327
  if arg.startswith('='):
327
328
  if len(arg) > 1:
328
329
  args.append(arg[1:])
330
+ elif not allow_equal:
331
+ args.extend(split_args[i-1:])
332
+ break
329
333
  elif arg.endswith('='):
330
334
  args.append(arg[:-1])
331
335
  elif '=' in arg:
@@ -337,9 +341,7 @@ class SSHConfig:
337
341
 
338
342
  if i == 1:
339
343
  loption = args.pop(0).lower()
340
- elif i > 1 and loption not in self._conditionals:
341
- args.extend(split_args[i:])
342
- break
344
+ allow_equal = loption in self._conditionals
343
345
 
344
346
  if loption in self._no_split:
345
347
  args = [line.lstrip()[len(loption):].strip()]
@@ -423,7 +425,7 @@ class SSHClientConfig(SSHConfig):
423
425
  """Settings from an OpenSSH client config file"""
424
426
 
425
427
  _conditionals = {'host', 'match'}
426
- _no_split = {'remotecommand'}
428
+ _no_split = {'proxycommand', 'remotecommand'}
427
429
  _percent_expand = {'CertificateFile', 'IdentityAgent',
428
430
  'IdentityFile', 'ProxyCommand', 'RemoteCommand'}
429
431
 
@@ -557,7 +559,7 @@ class SSHClientConfig(SSHConfig):
557
559
  ('PKCS11Provider', SSHConfig._set_string),
558
560
  ('PreferredAuthentications', SSHConfig._set_string),
559
561
  ('Port', SSHConfig._set_int),
560
- ('ProxyCommand', SSHConfig._set_string_list),
562
+ ('ProxyCommand', SSHConfig._set_string),
561
563
  ('ProxyJump', SSHConfig._set_string),
562
564
  ('PubkeyAuthentication', SSHConfig._set_bool),
563
565
  ('RekeyLimit', SSHConfig._set_rekey_limits),
@@ -115,7 +115,7 @@ from .misc import ProtocolNotSupported, ServiceNotAvailable
115
115
  from .misc import TermModesArg, TermSizeArg
116
116
  from .misc import async_context_manager, construct_disc_error
117
117
  from .misc import get_symbol_names, ip_address, map_handler_name
118
- from .misc import parse_byte_count, parse_time_interval
118
+ from .misc import parse_byte_count, parse_time_interval, split_args
119
119
 
120
120
  from .packet import Boolean, Byte, NameList, String, UInt32, PacketDecodeError
121
121
  from .packet import SSHPacket, SSHPacketHandler, SSHPacketLogger
@@ -185,6 +185,10 @@ _ProtocolFactory = Union[_ClientFactory, _ServerFactory]
185
185
  _Conn = TypeVar('_Conn', bound='SSHConnection')
186
186
  _Options = TypeVar('_Options', bound='SSHConnectionOptions')
187
187
 
188
+ _ServerHostKeysHandler = Optional[Callable[[List[SSHKey], List[SSHKey],
189
+ List[SSHKey], List[SSHKey]],
190
+ MaybeAwait[None]]]
191
+
188
192
  class _TunnelProtocol(Protocol):
189
193
  """Base protocol for connections to tunnel SSH over"""
190
194
 
@@ -227,7 +231,7 @@ _GlobalRequest = Tuple[Optional[_PacketHandler], SSHPacket, bool]
227
231
  _GlobalRequestResult = Tuple[int, SSHPacket]
228
232
  _KeyOrCertOptions = Mapping[str, object]
229
233
  _ListenerArg = Union[bool, SSHListener]
230
- _ProxyCommand = Optional[Sequence[str]]
234
+ _ProxyCommand = Optional[Union[str, Sequence[str]]]
231
235
  _RequestPTY = Union[bool, str]
232
236
 
233
237
  _TCPServerHandlerFactory = Callable[[str, int], SSHSocketSessionFactory]
@@ -1068,7 +1072,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
1068
1072
  self._set_keepalive_timer()
1069
1073
  self.create_task(self._make_keepalive_request())
1070
1074
 
1071
- def _force_close(self, exc: Optional[BaseException]) -> None:
1075
+ def _force_close(self, exc: Optional[Exception]) -> None:
1072
1076
  """Force this connection to close immediately"""
1073
1077
 
1074
1078
  if not self._transport:
@@ -1309,7 +1313,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
1309
1313
  error_logger = self.logger
1310
1314
 
1311
1315
  error_logger.debug1('Uncaught exception', exc_info=exc_info)
1312
- self._force_close(exc_info[1])
1316
+ self._force_close(cast(Exception, exc_info[1]))
1313
1317
 
1314
1318
  def session_started(self) -> None:
1315
1319
  """Handle session start when opening tunneled SSH connection"""
@@ -1995,6 +1999,11 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
1995
1999
  not self._waiter.cancelled():
1996
2000
  self._waiter.set_result(None)
1997
2001
  self._wait = None
2002
+ return
2003
+
2004
+ # This method is only in SSHServerConnection
2005
+ # pylint: disable=no-member
2006
+ cast(SSHServerConnection, self).send_server_host_keys()
1998
2007
 
1999
2008
  def send_channel_open_confirmation(self, send_chan: int, recv_chan: int,
2000
2009
  recv_window: int, recv_pktsize: int,
@@ -2012,6 +2021,13 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
2012
2021
  self.send_packet(MSG_CHANNEL_OPEN_FAILURE, UInt32(send_chan),
2013
2022
  UInt32(code), String(reason), String(lang))
2014
2023
 
2024
+ def _send_global_request(self, request: bytes, *args: bytes,
2025
+ want_reply: bool = False) -> None:
2026
+ """Send a global request"""
2027
+
2028
+ self.send_packet(MSG_GLOBAL_REQUEST, String(request),
2029
+ Boolean(want_reply), *args)
2030
+
2015
2031
  async def _make_global_request(self, request: bytes,
2016
2032
  *args: bytes) -> Tuple[int, SSHPacket]:
2017
2033
  """Send a global request and wait for the response"""
@@ -2024,8 +2040,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
2024
2040
 
2025
2041
  self._global_request_waiters.append(waiter)
2026
2042
 
2027
- self.send_packet(MSG_GLOBAL_REQUEST, String(request),
2028
- Boolean(True), *args)
2043
+ self._send_global_request(request, *args, want_reply=True)
2029
2044
 
2030
2045
  return await waiter
2031
2046
 
@@ -3266,6 +3281,8 @@ class SSHClientConnection(SSHConnection):
3266
3281
  self._server_host_key_algs: Optional[Sequence[bytes]] = None
3267
3282
  self._server_host_key: Optional[SSHKey] = None
3268
3283
 
3284
+ self._server_host_keys_handler = options.server_host_keys_handler
3285
+
3269
3286
  self._username = options.username
3270
3287
  self._password = options.password
3271
3288
 
@@ -3580,6 +3597,8 @@ class SSHClientConnection(SSHConnection):
3580
3597
  self._get_agent_keys = False
3581
3598
 
3582
3599
  if self._get_pkcs11_keys:
3600
+ assert self._pkcs11_provider is not None
3601
+
3583
3602
  pkcs11_keys = await self._loop.run_in_executor(
3584
3603
  None, load_pkcs11_keys, self._pkcs11_provider, self._pkcs11_pin)
3585
3604
 
@@ -3924,6 +3943,80 @@ class SSHClientConnection(SSHConnection):
3924
3943
  raise ChannelOpenError(OPEN_CONNECT_FAILED,
3925
3944
  'Auth agent forwarding disabled')
3926
3945
 
3946
+ def _process_hostkeys_00_at_openssh_dot_com_global_request(
3947
+ self, packet: SSHPacket) -> None:
3948
+ """Process a list of accepted server host keys"""
3949
+
3950
+ self.create_task(self._finish_hostkeys(packet))
3951
+
3952
+ async def _finish_hostkeys(self, packet: SSHPacket) -> None:
3953
+ """Finish processing hostkeys global request"""
3954
+
3955
+ if not self._server_host_keys_handler:
3956
+ self.logger.debug1('Ignoring server host key message: no handler')
3957
+ self._report_global_response(False)
3958
+ return
3959
+
3960
+ if self._trusted_host_keys is None:
3961
+ self.logger.info('Server host key not verified: handler disabled')
3962
+ self._report_global_response(False)
3963
+ return
3964
+
3965
+ added = []
3966
+ removed = list(self._trusted_host_keys)
3967
+ retained = []
3968
+ revoked = []
3969
+ prove = []
3970
+
3971
+ while packet:
3972
+ try:
3973
+ key_data = packet.get_string()
3974
+ key = decode_ssh_public_key(key_data)
3975
+
3976
+ if key in self._revoked_host_keys:
3977
+ revoked.append(key)
3978
+ elif key in self._trusted_host_keys:
3979
+ retained.append(key)
3980
+ removed.remove(key)
3981
+ else:
3982
+ prove.append((key, String(key_data)))
3983
+ except KeyImportError:
3984
+ pass
3985
+
3986
+ if prove:
3987
+ pkttype, packet = await self._make_global_request(
3988
+ b'hostkeys-prove-00@openssh.com',
3989
+ b''.join(key_str for _, key_str in prove))
3990
+
3991
+ if pkttype == MSG_REQUEST_SUCCESS:
3992
+ prefix = String('hostkeys-prove-00@openssh.com') + \
3993
+ String(self._session_id)
3994
+
3995
+ for key, key_str in prove:
3996
+ sig = packet.get_string()
3997
+
3998
+ if key.verify(prefix + key_str, sig):
3999
+ added.append(key)
4000
+ else:
4001
+ self.logger.debug1('Server host key validation failed')
4002
+ else:
4003
+ self.logger.debug1('Server host key prove request failed')
4004
+
4005
+ packet.check_end()
4006
+
4007
+ self.logger.info(f'Server host key report: {len(added)} added, '
4008
+ f'{len(removed)} removed, {len(retained)} retained, '
4009
+ f'{len(revoked)} revoked')
4010
+
4011
+ result = self._server_host_keys_handler(added, removed,
4012
+ retained, revoked)
4013
+
4014
+ if inspect.isawaitable(result):
4015
+ assert result is not None
4016
+ await result
4017
+
4018
+ self._report_global_response(True)
4019
+
3927
4020
  async def attach_x11_listener(self, chan: SSHClientChannel[AnyStr],
3928
4021
  display: Optional[str],
3929
4022
  auth_path: Optional[str],
@@ -4139,7 +4232,7 @@ class SSHClientConnection(SSHConnection):
4139
4232
  if env:
4140
4233
  try:
4141
4234
  if isinstance(env, list):
4142
- new_env.update((item.split('=', 2) for item in env))
4235
+ new_env.update((item.split('=', 1) for item in env))
4143
4236
  else:
4144
4237
  new_env.update(cast(Mapping[str, str], env))
4145
4238
  except ValueError:
@@ -5594,6 +5687,7 @@ class SSHServerConnection(SSHConnection):
5594
5687
  self._options = options
5595
5688
 
5596
5689
  self._server_host_keys = options.server_host_keys
5690
+ self._all_server_host_keys = options.all_server_host_keys
5597
5691
  self._server_host_key_algs = list(options.server_host_keys.keys())
5598
5692
  self._known_client_hosts = options.known_client_hosts
5599
5693
  self._trust_client_host = options.trust_client_host
@@ -5719,6 +5813,17 @@ class SSHServerConnection(SSHConnection):
5719
5813
 
5720
5814
  return self._server_host_key
5721
5815
 
5816
+ def send_server_host_keys(self) -> None:
5817
+ """Send list of available server host keys"""
5818
+
5819
+ if self._all_server_host_keys:
5820
+ self.logger.info('Sending server host keys')
5821
+
5822
+ keys = [String(key) for key in self._all_server_host_keys.keys()]
5823
+ self._send_global_request(b'hostkeys-00@openssh.com', *keys)
5824
+ else:
5825
+ self.logger.info('Sending server host keys disabled')
5826
+
5722
5827
  def gss_kex_auth_supported(self) -> bool:
5723
5828
  """Return whether GSS key exchange authentication is supported"""
5724
5829
 
@@ -6425,6 +6530,26 @@ class SSHServerConnection(SSHConnection):
6425
6530
 
6426
6531
  return chan, session
6427
6532
 
6533
+ def _process_hostkeys_prove_00_at_openssh_dot_com_global_request(
6534
+ self, packet: SSHPacket) -> None:
6535
+ """Prove the server has private keys for all requested host keys"""
6536
+
6537
+ prefix = String('hostkeys-prove-00@openssh.com') + \
6538
+ String(self._session_id)
6539
+
6540
+ signatures = []
6541
+
6542
+ while packet:
6543
+ try:
6544
+ key_data = packet.get_string()
6545
+ key = self._all_server_host_keys[key_data]
6546
+ signatures.append(String(key.sign(prefix + String(key_data))))
6547
+ except (KeyError, KeyImportError):
6548
+ self._report_global_response(False)
6549
+ return
6550
+
6551
+ self._report_global_response(b''.join(signatures))
6552
+
6428
6553
  async def attach_x11_listener(self, chan: SSHServerChannel[AnyStr],
6429
6554
  auth_proto: bytes, auth_data: bytes,
6430
6555
  screen: int) -> Optional[str]:
@@ -7019,11 +7144,13 @@ class SSHConnectionOptions(Options):
7019
7144
  self.tunnel = tunnel if tunnel != () else config.get('ProxyJump')
7020
7145
  self.passphrase = passphrase
7021
7146
 
7147
+ if proxy_command == ():
7148
+ proxy_command = cast(Optional[str], config.get('ProxyCommand'))
7149
+
7022
7150
  if isinstance(proxy_command, str):
7023
- proxy_command = shlex.split(proxy_command)
7151
+ proxy_command = split_args(proxy_command)
7024
7152
 
7025
- self.proxy_command = proxy_command if proxy_command != () else \
7026
- cast(Sequence[str], config.get('ProxyCommand'))
7153
+ self.proxy_command = proxy_command
7027
7154
 
7028
7155
  self.family = cast(int, family if family != () else
7029
7156
  config.get('AddressFamily', socket.AF_UNSPEC))
@@ -7178,6 +7305,17 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7178
7305
  caution, as it can result in a host key mismatch
7179
7306
  if the client trusts only a subset of the host
7180
7307
  keys the server might return.
7308
+ :param server_host_keys_handler: (optional)
7309
+ A `callable` or coroutine handler function which if set will be
7310
+ called when a global request from the server is received which
7311
+ provides an updated list of server host keys. The handler takes
7312
+ four arguments (added, removed, retained, and revoked), each of
7313
+ which is a list of SSHKey public keys, reflecting differences
7314
+ between what the server reported and what is currently matching
7315
+ in known_hosts.
7316
+
7317
+ .. note:: This handler will only be called when known
7318
+ host checking is enabled and the check succeeded.
7181
7319
  :param x509_trusted_certs: (optional)
7182
7320
  A list of certificates which should be trusted for X.509 server
7183
7321
  certificate authentication. If no trusted certificates are
@@ -7513,6 +7651,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7513
7651
  :type known_hosts: *see* :ref:`SpecifyingKnownHosts`
7514
7652
  :type host_key_alias: `str`
7515
7653
  :type server_host_key_algs: `str` or `list` of `str`
7654
+ :type server_host_keys_handler: `callable` or coroutine
7516
7655
  :type x509_trusted_certs: *see* :ref:`SpecifyingCertificates`
7517
7656
  :type x509_trusted_cert_paths: `list` of `str`
7518
7657
  :type x509_purposes: *see* :ref:`SpecifyingX509Purposes`
@@ -7542,7 +7681,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7542
7681
  :type agent_identities:
7543
7682
  *see* :ref:`SpecifyingPublicKeys` and :ref:`SpecifyingCertificates`
7544
7683
  :type agent_forwarding: `bool`
7545
- :type pkcs11_provider: `str`
7684
+ :type pkcs11_provider: `str` or `None`
7546
7685
  :type pkcs11_pin: `str`
7547
7686
  :type client_version: `str`
7548
7687
  :type kex_algs: `str` or `list` of `str`
@@ -7583,6 +7722,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7583
7722
  known_hosts: KnownHostsArg
7584
7723
  host_key_alias: Optional[str]
7585
7724
  server_host_key_algs: Union[str, Sequence[str]]
7725
+ server_host_keys_handler: _ServerHostKeysHandler
7586
7726
  username: str
7587
7727
  password: Optional[str]
7588
7728
  client_host_keysign: Optional[str]
@@ -7602,7 +7742,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7602
7742
  agent_path: Optional[str]
7603
7743
  agent_identities: Optional[Sequence[bytes]]
7604
7744
  agent_forward_path: Optional[str]
7605
- pkcs11_provider: Optional[FilePath]
7745
+ pkcs11_provider: Optional[str]
7606
7746
  pkcs11_pin: Optional[str]
7607
7747
  command: Optional[str]
7608
7748
  subsystem: Optional[str]
@@ -7650,6 +7790,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7650
7790
  known_hosts: KnownHostsArg = (),
7651
7791
  host_key_alias: DefTuple[Optional[str]] = (),
7652
7792
  server_host_key_algs: _AlgsArg = (),
7793
+ server_host_keys_handler: _ServerHostKeysHandler = None,
7653
7794
  username: DefTuple[str] = (), password: Optional[str] = None,
7654
7795
  client_host_keysign: DefTuple[KeySignPath] = (),
7655
7796
  client_host_keys: Optional[_ClientKeysArg] = None,
@@ -7668,7 +7809,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7668
7809
  agent_path: DefTuple[Optional[str]] = (),
7669
7810
  agent_identities: DefTuple[Optional[IdentityListArg]] = (),
7670
7811
  agent_forwarding: DefTuple[bool] = (),
7671
- pkcs11_provider: DefTuple[Optional[FilePath]] = (),
7812
+ pkcs11_provider: DefTuple[Optional[str]] = (),
7672
7813
  pkcs11_pin: Optional[str] = None,
7673
7814
  command: DefTuple[Optional[str]] = (),
7674
7815
  subsystem: Optional[str] = None, env: DefTuple[_Env] = (),
@@ -7758,6 +7899,8 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7758
7899
  _select_host_key_algs(server_host_key_algs,
7759
7900
  cast(DefTuple[str], config.get('HostKeyAlgorithms', ())), [])
7760
7901
 
7902
+ self.server_host_keys_handler = server_host_keys_handler
7903
+
7761
7904
  self.username = saslprep(cast(str, username if username != () else
7762
7905
  config.get('User', local_username)))
7763
7906
 
@@ -7823,9 +7966,9 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7823
7966
 
7824
7967
  if pkcs11_provider == ():
7825
7968
  pkcs11_provider = \
7826
- cast(Optional[FilePath], config.get('PKCS11Provider'))
7969
+ cast(Optional[str], config.get('PKCS11Provider'))
7827
7970
 
7828
- pkcs11_provider: Optional[FilePath]
7971
+ pkcs11_provider: Optional[str]
7829
7972
 
7830
7973
  if ignore_encrypted == ():
7831
7974
  ignore_encrypted = client_keys == ()
@@ -7933,6 +8076,20 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
7933
8076
  :param server_host_certs: (optional)
7934
8077
  A list of optional certificates which can be paired with the
7935
8078
  provided server host keys.
8079
+ :param send_server_host_keys: (optional)
8080
+ Whether or not to send a list of the allowed server host keys
8081
+ for clients to use to update their known hosts like for the
8082
+ server.
8083
+
8084
+ .. note:: Enabling this option will allow multiple server
8085
+ host keys of the same type to be configured. Only
8086
+ the first key of each type will be actively used
8087
+ during key exchange, but the others will be
8088
+ reported as reserved keys that clients should
8089
+ begin to trust, to allow for future key rotation.
8090
+ If this option is disabled, specifying multiple
8091
+ server host keys of the same type is treated as
8092
+ a configuration error.
7936
8093
  :param passphrase: (optional)
7937
8094
  The passphrase to use to decrypt server host keys if they are
7938
8095
  encrypted, or a `callable` or coroutine which takes a filename
@@ -8174,6 +8331,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8174
8331
  :type family: `socket.AF_UNSPEC`, `socket.AF_INET`, or `socket.AF_INET6`
8175
8332
  :type server_host_keys: *see* :ref:`SpecifyingPrivateKeys`
8176
8333
  :type server_host_certs: *see* :ref:`SpecifyingCertificates`
8334
+ :type send_server_host_keys: `bool`
8177
8335
  :type passphrase: `str` or `bytes`
8178
8336
  :type known_client_hosts: *see* :ref:`SpecifyingKnownHosts`
8179
8337
  :type trust_client_host: `bool`
@@ -8227,6 +8385,8 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8227
8385
  server_factory: _ServerFactory
8228
8386
  server_version: bytes
8229
8387
  server_host_keys: 'OrderedDict[bytes, SSHKeyPair]'
8388
+ all_server_host_keys: 'OrderedDict[bytes, SSHKeyPair]'
8389
+ send_server_host_keys: bool
8230
8390
  known_client_hosts: KnownHostsArg
8231
8391
  trust_client_host: bool
8232
8392
  authorized_client_keys: DefTuple[Optional[SSHAuthorizedKeys]]
@@ -8283,6 +8443,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8283
8443
  keepalive_count_max: DefTuple[int] = (),
8284
8444
  server_host_keys: KeyPairListArg = (),
8285
8445
  server_host_certs: CertListArg = (),
8446
+ send_server_host_keys: bool = False,
8286
8447
  passphrase: Optional[BytesOrStr] = None,
8287
8448
  known_client_hosts: KnownHostsArg = None,
8288
8449
  trust_client_host: bool = False,
@@ -8354,14 +8515,21 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8354
8515
  server_host_certs, loop=loop)
8355
8516
 
8356
8517
  self.server_host_keys = OrderedDict()
8518
+ self.all_server_host_keys = OrderedDict()
8357
8519
 
8358
8520
  for keypair in server_keys:
8359
8521
  for alg in keypair.host_key_algorithms:
8360
- if alg in self.server_host_keys:
8361
- raise ValueError('Multiple keys of type %s found' %
8362
- alg.decode('ascii'))
8522
+ if alg in self.server_host_keys and not send_server_host_keys:
8523
+ raise ValueError('Multiple keys of type '
8524
+ f'{alg.decode("ascii")} found: '
8525
+ 'Enable send_server_host_keys to '
8526
+ 'allow reserved keys to be configured')
8527
+
8528
+ if alg not in self.server_host_keys:
8529
+ self.server_host_keys[alg] = keypair
8363
8530
 
8364
- self.server_host_keys[alg] = keypair
8531
+ if send_server_host_keys:
8532
+ self.all_server_host_keys[keypair.public_data] = keypair
8365
8533
 
8366
8534
  self.known_client_hosts = known_client_hosts
8367
8535
  self.trust_client_host = trust_client_host
@@ -9058,7 +9226,7 @@ async def create_server(server_factory: _ServerFactory,
9058
9226
  async def get_server_host_key(
9059
9227
  host = '', port: DefTuple[int] = (), *,
9060
9228
  tunnel: DefTuple[_TunnelConnector] = (),
9061
- proxy_command: DefTuple[str] = (), family: DefTuple[int] = (),
9229
+ proxy_command: DefTuple[_ProxyCommand] = (), family: DefTuple[int] = (),
9062
9230
  flags: int = 0, local_addr: DefTuple[HostPort] = (),
9063
9231
  sock: Optional[socket.socket] = None,
9064
9232
  client_version: DefTuple[BytesOrStr] = (),
@@ -9202,7 +9370,7 @@ async def get_server_host_key(
9202
9370
  async def get_server_auth_methods(
9203
9371
  host = '', port: DefTuple[int] = (), username: DefTuple[str] = (), *,
9204
9372
  tunnel: DefTuple[_TunnelConnector] = (),
9205
- proxy_command: DefTuple[str] = (), family: DefTuple[int] = (),
9373
+ proxy_command: DefTuple[_ProxyCommand] = (), family: DefTuple[int] = (),
9206
9374
  flags: int = 0, local_addr: DefTuple[HostPort] = (),
9207
9375
  sock: Optional[socket.socket] = None,
9208
9376
  client_version: DefTuple[BytesOrStr] = (),
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2021 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2014-2024 by Ron Frederick <ronf@timeheart.net> and others.
2
2
  #
3
3
  # This program and the accompanying materials are made available under
4
4
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -20,22 +20,23 @@
20
20
 
21
21
  """A shim around PyCA for accessing symmetric ciphers needed by AsyncSSH"""
22
22
 
23
+ from types import ModuleType
23
24
  from typing import Any, MutableMapping, Optional, Tuple
24
25
  import warnings
25
26
 
26
27
  from cryptography.exceptions import InvalidTag
27
28
  from cryptography.hazmat.primitives.ciphers import Cipher, CipherContext
28
29
  from cryptography.hazmat.primitives.ciphers.aead import AESGCM
29
- from cryptography.hazmat.primitives.ciphers.algorithms import AES, ARC4
30
- from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES
31
30
  from cryptography.hazmat.primitives.ciphers.modes import CBC, CTR
32
31
 
33
- with warnings.catch_warnings():
34
- warnings.simplefilter('ignore')
32
+ import cryptography.hazmat.primitives.ciphers.algorithms as _algs
33
+
34
+ _decrepit_algs: Optional[ModuleType]
35
35
 
36
- from cryptography.hazmat.primitives.ciphers.algorithms import Blowfish
37
- from cryptography.hazmat.primitives.ciphers.algorithms import CAST5
38
- from cryptography.hazmat.primitives.ciphers.algorithms import SEED
36
+ try:
37
+ import cryptography.hazmat.decrepit.ciphers.algorithms as _decrepit_algs
38
+ except ImportError:
39
+ _decrepit_algs = None
39
40
 
40
41
 
41
42
  _CipherAlgs = Tuple[Any, Any, int]
@@ -140,27 +141,44 @@ def get_cipher_params(cipher_name: str) -> _CipherParams:
140
141
 
141
142
 
142
143
  _cipher_alg_list = (
143
- ('aes128-cbc', AES, CBC, 0, 16, 16, 16),
144
- ('aes192-cbc', AES, CBC, 0, 24, 16, 16),
145
- ('aes256-cbc', AES, CBC, 0, 32, 16, 16),
146
- ('aes128-ctr', AES, CTR, 0, 16, 16, 16),
147
- ('aes192-ctr', AES, CTR, 0, 24, 16, 16),
148
- ('aes256-ctr', AES, CTR, 0, 32, 16, 16),
149
- ('aes128-gcm', None, None, 0, 16, 12, 16),
150
- ('aes256-gcm', None, None, 0, 32, 12, 16),
151
- ('arcfour', ARC4, None, 0, 16, 1, 1),
152
- ('arcfour40', ARC4, None, 0, 5, 1, 1),
153
- ('arcfour128', ARC4, None, 1536, 16, 1, 1),
154
- ('arcfour256', ARC4, None, 1536, 32, 1, 1),
155
- ('blowfish-cbc', Blowfish, CBC, 0, 16, 8, 8),
156
- ('cast128-cbc', CAST5, CBC, 0, 16, 8, 8),
157
- ('des-cbc', TripleDES, CBC, 0, 8, 8, 8),
158
- ('des2-cbc', TripleDES, CBC, 0, 16, 8, 8),
159
- ('des3-cbc', TripleDES, CBC, 0, 24, 8, 8),
160
- ('seed-cbc', SEED, CBC, 0, 16, 16, 16)
144
+ ('aes128-cbc', 'AES', CBC, 0, 16, 16, 16),
145
+ ('aes192-cbc', 'AES', CBC, 0, 24, 16, 16),
146
+ ('aes256-cbc', 'AES', CBC, 0, 32, 16, 16),
147
+ ('aes128-ctr', 'AES', CTR, 0, 16, 16, 16),
148
+ ('aes192-ctr', 'AES', CTR, 0, 24, 16, 16),
149
+ ('aes256-ctr', 'AES', CTR, 0, 32, 16, 16),
150
+ ('aes128-gcm', None, None, 0, 16, 12, 16),
151
+ ('aes256-gcm', None, None, 0, 32, 12, 16),
152
+ ('arcfour', 'ARC4', None, 0, 16, 1, 1),
153
+ ('arcfour40', 'ARC4', None, 0, 5, 1, 1),
154
+ ('arcfour128', 'ARC4', None, 1536, 16, 1, 1),
155
+ ('arcfour256', 'ARC4', None, 1536, 32, 1, 1),
156
+ ('blowfish-cbc', 'Blowfish', CBC, 0, 16, 8, 8),
157
+ ('cast128-cbc', 'CAST5', CBC, 0, 16, 8, 8),
158
+ ('des-cbc', 'TripleDES', CBC, 0, 8, 8, 8),
159
+ ('des2-cbc', 'TripleDES', CBC, 0, 16, 8, 8),
160
+ ('des3-cbc', 'TripleDES', CBC, 0, 24, 8, 8),
161
+ ('seed-cbc', 'SEED', CBC, 0, 16, 16, 16)
161
162
  )
162
163
 
163
- for _cipher_name, _cipher, _mode, _initial_bytes, \
164
- _key_size, _iv_size, _block_size in _cipher_alg_list:
165
- _cipher_algs[_cipher_name] = (_cipher, _mode, _initial_bytes)
166
- register_cipher(_cipher_name, _key_size, _iv_size, _block_size)
164
+ with warnings.catch_warnings():
165
+ warnings.simplefilter('ignore')
166
+
167
+ for _cipher_name, _alg, _mode, _initial_bytes, \
168
+ _key_size, _iv_size, _block_size in _cipher_alg_list:
169
+ if _alg:
170
+ try:
171
+ _cipher = getattr(_algs, _alg)
172
+ except AttributeError as exc: # pragma: no cover
173
+ if _decrepit_algs:
174
+ try:
175
+ _cipher = getattr(_decrepit_algs, _alg)
176
+ except AttributeError:
177
+ raise exc from None
178
+ else:
179
+ raise
180
+ else:
181
+ _cipher = None
182
+
183
+ _cipher_algs[_cipher_name] = (_cipher, _mode, _initial_bytes)
184
+ register_cipher(_cipher_name, _key_size, _iv_size, _block_size)
@@ -404,7 +404,8 @@ def generate_x509_certificate(signing_key: PyCAKey, key: PyCAKey,
404
404
  except KeyError:
405
405
  raise ValueError('Unknown hash algorithm') from None
406
406
 
407
- cert = builder.sign(cast(PyCAPrivateKey, signing_key), hash_alg)
407
+ cert = builder.sign(cast(PyCAPrivateKey, signing_key),
408
+ hash_alg) # type: ignore
408
409
  data = cert.public_bytes(Encoding.DER)
409
410
 
410
411
  return X509Certificate(cert, data)