_der.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. import typing
  5. from cryptography.utils import int_to_bytes
  6. # This module contains a lightweight DER encoder and decoder. See X.690 for the
  7. # specification. This module intentionally does not implement the more complex
  8. # BER encoding, only DER.
  9. #
  10. # Note this implementation treats an element's constructed bit as part of the
  11. # tag. This is fine for DER, where the bit is always computable from the type.
  12. CONSTRUCTED = 0x20
  13. CONTEXT_SPECIFIC = 0x80
  14. INTEGER = 0x02
  15. BIT_STRING = 0x03
  16. OCTET_STRING = 0x04
  17. NULL = 0x05
  18. OBJECT_IDENTIFIER = 0x06
  19. SEQUENCE = 0x10 | CONSTRUCTED
  20. SET = 0x11 | CONSTRUCTED
  21. PRINTABLE_STRING = 0x13
  22. UTC_TIME = 0x17
  23. GENERALIZED_TIME = 0x18
  24. class DERReader(object):
  25. def __init__(self, data):
  26. self.data = memoryview(data)
  27. def __enter__(self):
  28. return self
  29. def __exit__(self, exc_type, exc_value, tb):
  30. if exc_value is None:
  31. self.check_empty()
  32. def is_empty(self):
  33. return len(self.data) == 0
  34. def check_empty(self):
  35. if not self.is_empty():
  36. raise ValueError("Invalid DER input: trailing data")
  37. def read_byte(self) -> int:
  38. if len(self.data) < 1:
  39. raise ValueError("Invalid DER input: insufficient data")
  40. ret = self.data[0]
  41. self.data = self.data[1:]
  42. return ret
  43. def read_bytes(self, n) -> memoryview:
  44. if len(self.data) < n:
  45. raise ValueError("Invalid DER input: insufficient data")
  46. ret = self.data[:n]
  47. self.data = self.data[n:]
  48. return ret
  49. def read_any_element(self) -> typing.Tuple[int, "DERReader"]:
  50. tag = self.read_byte()
  51. # Tag numbers 31 or higher are stored in multiple bytes. No supported
  52. # ASN.1 types use such tags, so reject these.
  53. if tag & 0x1F == 0x1F:
  54. raise ValueError("Invalid DER input: unexpected high tag number")
  55. length_byte = self.read_byte()
  56. if length_byte & 0x80 == 0:
  57. # If the high bit is clear, the first length byte is the length.
  58. length = length_byte
  59. else:
  60. # If the high bit is set, the first length byte encodes the length
  61. # of the length.
  62. length_byte &= 0x7F
  63. if length_byte == 0:
  64. raise ValueError(
  65. "Invalid DER input: indefinite length form is not allowed "
  66. "in DER"
  67. )
  68. length = 0
  69. for i in range(length_byte):
  70. length <<= 8
  71. length |= self.read_byte()
  72. if length == 0:
  73. raise ValueError(
  74. "Invalid DER input: length was not minimally-encoded"
  75. )
  76. if length < 0x80:
  77. # If the length could have been encoded in short form, it must
  78. # not use long form.
  79. raise ValueError(
  80. "Invalid DER input: length was not minimally-encoded"
  81. )
  82. body = self.read_bytes(length)
  83. return tag, DERReader(body)
  84. def read_element(self, expected_tag: int) -> "DERReader":
  85. tag, body = self.read_any_element()
  86. if tag != expected_tag:
  87. raise ValueError("Invalid DER input: unexpected tag")
  88. return body
  89. def read_single_element(self, expected_tag: int) -> "DERReader":
  90. with self:
  91. return self.read_element(expected_tag)
  92. def read_optional_element(
  93. self, expected_tag: int
  94. ) -> typing.Optional["DERReader"]:
  95. if len(self.data) > 0 and self.data[0] == expected_tag:
  96. return self.read_element(expected_tag)
  97. return None
  98. def as_integer(self) -> int:
  99. if len(self.data) == 0:
  100. raise ValueError("Invalid DER input: empty integer contents")
  101. first = self.data[0]
  102. if first & 0x80 == 0x80:
  103. raise ValueError("Negative DER integers are not supported")
  104. # The first 9 bits must not all be zero or all be ones. Otherwise, the
  105. # encoding should have been one byte shorter.
  106. if len(self.data) > 1:
  107. second = self.data[1]
  108. if first == 0 and second & 0x80 == 0:
  109. raise ValueError(
  110. "Invalid DER input: integer not minimally-encoded"
  111. )
  112. return int.from_bytes(self.data, "big")
  113. def encode_der_integer(x: int) -> bytes:
  114. if not isinstance(x, int):
  115. raise ValueError("Value must be an integer")
  116. if x < 0:
  117. raise ValueError("Negative integers are not supported")
  118. n = x.bit_length() // 8 + 1
  119. return int_to_bytes(x, n)
  120. def encode_der(tag: int, *children: bytes) -> bytes:
  121. length = 0
  122. for child in children:
  123. length += len(child)
  124. chunks = [bytes([tag])]
  125. if length < 0x80:
  126. chunks.append(bytes([length]))
  127. else:
  128. length_bytes = int_to_bytes(length)
  129. chunks.append(bytes([0x80 | len(length_bytes)]))
  130. chunks.append(length_bytes)
  131. chunks.extend(children)
  132. return b"".join(chunks)