weak_cryptographic_key.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # Copyright (c) 2015 VMware, Inc.
  2. #
  3. # SPDX-License-Identifier: Apache-2.0
  4. r"""
  5. =========================================
  6. B505: Test for weak cryptographic key use
  7. =========================================
  8. As computational power increases, so does the ability to break ciphers with
  9. smaller key lengths. The recommended key length size for RSA and DSA algorithms
  10. is 2048 and higher. 1024 bits and below are now considered breakable. EC key
  11. length sizes are recommended to be 224 and higher with 160 and below considered
  12. breakable. This plugin test checks for use of any key less than those limits
  13. and returns a high severity error if lower than the lower threshold and a
  14. medium severity error for those lower than the higher threshold.
  15. :Example:
  16. .. code-block:: none
  17. >> Issue: DSA key sizes below 1024 bits are considered breakable.
  18. Severity: High Confidence: High
  19. CWE: CWE-326 (https://cwe.mitre.org/data/definitions/326.html)
  20. Location: examples/weak_cryptographic_key_sizes.py:36
  21. 35 # Also incorrect: without keyword args
  22. 36 dsa.generate_private_key(512,
  23. 37 backends.default_backend())
  24. 38 rsa.generate_private_key(3,
  25. .. seealso::
  26. - https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final
  27. - https://security.openstack.org/guidelines/dg_strong-crypto.html
  28. - https://cwe.mitre.org/data/definitions/326.html
  29. .. versionadded:: 0.14.0
  30. .. versionchanged:: 1.7.3
  31. CWE information added
  32. """
  33. import bandit
  34. from bandit.core import issue
  35. from bandit.core import test_properties as test
  36. def gen_config(name):
  37. if name == "weak_cryptographic_key":
  38. return {
  39. "weak_key_size_dsa_high": 1024,
  40. "weak_key_size_dsa_medium": 2048,
  41. "weak_key_size_rsa_high": 1024,
  42. "weak_key_size_rsa_medium": 2048,
  43. "weak_key_size_ec_high": 160,
  44. "weak_key_size_ec_medium": 224,
  45. }
  46. def _classify_key_size(config, key_type, key_size):
  47. if isinstance(key_size, str):
  48. # size provided via a variable - can't process it at the moment
  49. return
  50. key_sizes = {
  51. "DSA": [
  52. (config["weak_key_size_dsa_high"], bandit.HIGH),
  53. (config["weak_key_size_dsa_medium"], bandit.MEDIUM),
  54. ],
  55. "RSA": [
  56. (config["weak_key_size_rsa_high"], bandit.HIGH),
  57. (config["weak_key_size_rsa_medium"], bandit.MEDIUM),
  58. ],
  59. "EC": [
  60. (config["weak_key_size_ec_high"], bandit.HIGH),
  61. (config["weak_key_size_ec_medium"], bandit.MEDIUM),
  62. ],
  63. }
  64. for size, level in key_sizes[key_type]:
  65. if key_size < size:
  66. return bandit.Issue(
  67. severity=level,
  68. confidence=bandit.HIGH,
  69. cwe=issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH,
  70. text="%s key sizes below %d bits are considered breakable. "
  71. % (key_type, size),
  72. )
  73. def _weak_crypto_key_size_cryptography_io(context, config):
  74. func_key_type = {
  75. "cryptography.hazmat.primitives.asymmetric.dsa."
  76. "generate_private_key": "DSA",
  77. "cryptography.hazmat.primitives.asymmetric.rsa."
  78. "generate_private_key": "RSA",
  79. "cryptography.hazmat.primitives.asymmetric.ec."
  80. "generate_private_key": "EC",
  81. }
  82. arg_position = {
  83. "DSA": 0,
  84. "RSA": 1,
  85. "EC": 0,
  86. }
  87. key_type = func_key_type.get(context.call_function_name_qual)
  88. if key_type in ["DSA", "RSA"]:
  89. key_size = (
  90. context.get_call_arg_value("key_size")
  91. or context.get_call_arg_at_position(arg_position[key_type])
  92. or 2048
  93. )
  94. return _classify_key_size(config, key_type, key_size)
  95. elif key_type == "EC":
  96. curve_key_sizes = {
  97. "SECT571K1": 571,
  98. "SECT571R1": 570,
  99. "SECP521R1": 521,
  100. "BrainpoolP512R1": 512,
  101. "SECT409K1": 409,
  102. "SECT409R1": 409,
  103. "BrainpoolP384R1": 384,
  104. "SECP384R1": 384,
  105. "SECT283K1": 283,
  106. "SECT283R1": 283,
  107. "BrainpoolP256R1": 256,
  108. "SECP256K1": 256,
  109. "SECP256R1": 256,
  110. "SECT233K1": 233,
  111. "SECT233R1": 233,
  112. "SECP224R1": 224,
  113. "SECP192R1": 192,
  114. "SECT163K1": 163,
  115. "SECT163R2": 163,
  116. }
  117. curve = context.get_call_arg_value("curve") or (
  118. len(context.call_args) > arg_position[key_type]
  119. and context.call_args[arg_position[key_type]]
  120. )
  121. key_size = curve_key_sizes[curve] if curve in curve_key_sizes else 224
  122. return _classify_key_size(config, key_type, key_size)
  123. def _weak_crypto_key_size_pycrypto(context, config):
  124. func_key_type = {
  125. "Crypto.PublicKey.DSA.generate": "DSA",
  126. "Crypto.PublicKey.RSA.generate": "RSA",
  127. "Cryptodome.PublicKey.DSA.generate": "DSA",
  128. "Cryptodome.PublicKey.RSA.generate": "RSA",
  129. }
  130. key_type = func_key_type.get(context.call_function_name_qual)
  131. if key_type:
  132. key_size = (
  133. context.get_call_arg_value("bits")
  134. or context.get_call_arg_at_position(0)
  135. or 2048
  136. )
  137. return _classify_key_size(config, key_type, key_size)
  138. @test.takes_config
  139. @test.checks("Call")
  140. @test.test_id("B505")
  141. def weak_cryptographic_key(context, config):
  142. return _weak_crypto_key_size_cryptography_io(
  143. context, config
  144. ) or _weak_crypto_key_size_pycrypto(context, config)