__init__.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from typing import Dict, Tuple, Type
  2. import dns._features
  3. import dns.name
  4. from dns.dnssecalgs.base import GenericPrivateKey
  5. from dns.dnssectypes import Algorithm
  6. from dns.exception import UnsupportedAlgorithm
  7. from dns.rdtypes.ANY.DNSKEY import DNSKEY
  8. # pyright: reportPossiblyUnboundVariable=false
  9. if dns._features.have("dnssec"):
  10. from dns.dnssecalgs.dsa import PrivateDSA, PrivateDSANSEC3SHA1
  11. from dns.dnssecalgs.ecdsa import PrivateECDSAP256SHA256, PrivateECDSAP384SHA384
  12. from dns.dnssecalgs.eddsa import PrivateED448, PrivateED25519
  13. from dns.dnssecalgs.rsa import (
  14. PrivateRSAMD5,
  15. PrivateRSASHA1,
  16. PrivateRSASHA1NSEC3SHA1,
  17. PrivateRSASHA256,
  18. PrivateRSASHA512,
  19. )
  20. _have_cryptography = True
  21. else:
  22. _have_cryptography = False
  23. AlgorithmPrefix = bytes | dns.name.Name | None
  24. algorithms: Dict[Tuple[Algorithm, AlgorithmPrefix], Type[GenericPrivateKey]] = {}
  25. if _have_cryptography:
  26. # pylint: disable=possibly-used-before-assignment
  27. algorithms.update(
  28. {
  29. (Algorithm.RSAMD5, None): PrivateRSAMD5,
  30. (Algorithm.DSA, None): PrivateDSA,
  31. (Algorithm.RSASHA1, None): PrivateRSASHA1,
  32. (Algorithm.DSANSEC3SHA1, None): PrivateDSANSEC3SHA1,
  33. (Algorithm.RSASHA1NSEC3SHA1, None): PrivateRSASHA1NSEC3SHA1,
  34. (Algorithm.RSASHA256, None): PrivateRSASHA256,
  35. (Algorithm.RSASHA512, None): PrivateRSASHA512,
  36. (Algorithm.ECDSAP256SHA256, None): PrivateECDSAP256SHA256,
  37. (Algorithm.ECDSAP384SHA384, None): PrivateECDSAP384SHA384,
  38. (Algorithm.ED25519, None): PrivateED25519,
  39. (Algorithm.ED448, None): PrivateED448,
  40. }
  41. )
  42. def get_algorithm_cls(
  43. algorithm: int | str, prefix: AlgorithmPrefix = None
  44. ) -> Type[GenericPrivateKey]:
  45. """Get Private Key class from Algorithm.
  46. *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
  47. Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
  48. Returns a ``dns.dnssecalgs.GenericPrivateKey``
  49. """
  50. algorithm = Algorithm.make(algorithm)
  51. cls = algorithms.get((algorithm, prefix))
  52. if cls:
  53. return cls
  54. raise UnsupportedAlgorithm(
  55. f'algorithm "{Algorithm.to_text(algorithm)}" not supported by dnspython'
  56. )
  57. def get_algorithm_cls_from_dnskey(dnskey: DNSKEY) -> Type[GenericPrivateKey]:
  58. """Get Private Key class from DNSKEY.
  59. *dnskey*, a ``DNSKEY`` to get Algorithm class for.
  60. Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
  61. Returns a ``dns.dnssecalgs.GenericPrivateKey``
  62. """
  63. prefix: AlgorithmPrefix = None
  64. if dnskey.algorithm == Algorithm.PRIVATEDNS:
  65. prefix, _ = dns.name.from_wire(dnskey.key, 0)
  66. elif dnskey.algorithm == Algorithm.PRIVATEOID:
  67. length = int(dnskey.key[0])
  68. prefix = dnskey.key[0 : length + 1]
  69. return get_algorithm_cls(dnskey.algorithm, prefix)
  70. def register_algorithm_cls(
  71. algorithm: int | str,
  72. algorithm_cls: Type[GenericPrivateKey],
  73. name: dns.name.Name | str | None = None,
  74. oid: bytes | None = None,
  75. ) -> None:
  76. """Register Algorithm Private Key class.
  77. *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
  78. *algorithm_cls*: A `GenericPrivateKey` class.
  79. *name*, an optional ``dns.name.Name`` or ``str``, for for PRIVATEDNS algorithms.
  80. *oid*: an optional BER-encoded `bytes` for PRIVATEOID algorithms.
  81. Raises ``ValueError`` if a name or oid is specified incorrectly.
  82. """
  83. if not issubclass(algorithm_cls, GenericPrivateKey):
  84. raise TypeError("Invalid algorithm class")
  85. algorithm = Algorithm.make(algorithm)
  86. prefix: AlgorithmPrefix = None
  87. if algorithm == Algorithm.PRIVATEDNS:
  88. if name is None:
  89. raise ValueError("Name required for PRIVATEDNS algorithms")
  90. if isinstance(name, str):
  91. name = dns.name.from_text(name)
  92. prefix = name
  93. elif algorithm == Algorithm.PRIVATEOID:
  94. if oid is None:
  95. raise ValueError("OID required for PRIVATEOID algorithms")
  96. prefix = bytes([len(oid)]) + oid
  97. elif name:
  98. raise ValueError("Name only supported for PRIVATEDNS algorithm")
  99. elif oid:
  100. raise ValueError("OID only supported for PRIVATEOID algorithm")
  101. algorithms[(algorithm, prefix)] = algorithm_cls