ssl.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. """
  2. Secure Sockets Layer / Transport Layer Security.
  3. """
  4. #
  5. # Note from April 2011: cde...@gmail.com added code that parses SSL3/TLS messages
  6. # more in depth.
  7. #
  8. # Jul 2012: afleenor@google.com modified and extended SSL support further.
  9. #
  10. from pypacker import pypacker, triggerlist
  11. import logging
  12. import struct
  13. # avoid references for performance reasons
  14. unpack = struct.unpack
  15. unpack_be_h = struct.Struct(">H").unpack
  16. logger = logging.getLogger("pypacker")
  17. # SSLv3/TLS versions
  18. SSL3_V = 0x0300
  19. TLS1_V = 0x0301
  20. TLS11_V = 0x0302
  21. TLS12_V = 0x0303
  22. ssl3_versions_str = {
  23. SSL3_V : "SSL3",
  24. TLS1_V : "TLS 1.0",
  25. TLS11_V : "TLS 1.1",
  26. TLS12_V : "TLS 1.2"
  27. }
  28. # Alert levels
  29. SSL3_AD_WARNING = 1
  30. SSL3_AD_FATAL = 2
  31. alert_level_str = {
  32. SSL3_AD_WARNING : "SSL3_AD_WARNING",
  33. SSL3_AD_FATAL : "SSL3_AD_FATAL"
  34. }
  35. # SSL3 alert descriptions
  36. SSL3_AD_CLOSE_NOTIFY = 0
  37. SSL3_AD_UNEXPECTED_MESSAGE = 10 # fatal
  38. SSL3_AD_BAD_RECORD_MAC = 20 # fatal
  39. SSL3_AD_DECOMPRESSION_FAILURE = 30 # fatal
  40. SSL3_AD_HANDSHAKE_FAILURE = 40 # fatal
  41. SSL3_AD_NO_CERTIFICATE = 41
  42. SSL3_AD_BAD_CERTIFICATE = 42
  43. SSL3_AD_UNSUPPORTED_CERTIFICATE = 43
  44. SSL3_AD_CERTIFICATE_REVOKED = 44
  45. SSL3_AD_CERTIFICATE_EXPIRED = 45
  46. SSL3_AD_CERTIFICATE_UNKNOWN = 46
  47. SSL3_AD_ILLEGAL_PARAMETER = 47 # fatal
  48. # TLS1 alert descriptions
  49. TLS1_AD_DECRYPTION_FAILED = 21
  50. TLS1_AD_RECORD_OVERFLOW = 22
  51. TLS1_AD_UNKNOWN_CA = 48 # fatal
  52. TLS1_AD_ACCESS_DENIED = 49 # fatal
  53. TLS1_AD_DECODE_ERROR = 50 # fatal
  54. TLS1_AD_DECRYPT_ERROR = 51
  55. TLS1_AD_EXPORT_RESTRICTION = 60 # fatal
  56. TLS1_AD_PROTOCOL_VERSION = 70 # fatal
  57. TLS1_AD_INSUFFICIENT_SECURITY = 71 # fatal
  58. TLS1_AD_INTERNAL_ERROR = 80 # fatal
  59. TLS1_AD_USER_CANCELLED = 90
  60. TLS1_AD_NO_RENEGOTIATION = 100
  61. # /* codes 110-114 are from RFC3546 */
  62. TLS1_AD_UNSUPPORTED_EXTENSION = 110
  63. TLS1_AD_CERTIFICATE_UNOBTAINABLE = 111
  64. TLS1_AD_UNRECOGNIZED_NAME = 112
  65. TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE = 113
  66. TLS1_AD_BAD_CERTIFICATE_HASH_VALUE = 114
  67. TLS1_AD_UNKNOWN_PSK_IDENTITY = 115 # fatal
  68. # Mapping alert types to strings
  69. alert_description_str = {
  70. SSL3_AD_CLOSE_NOTIFY : "SSL3_AD_CLOSE_NOTIFY",
  71. SSL3_AD_UNEXPECTED_MESSAGE : "SSL3_AD_UNEXPECTED_MESSAGE",
  72. SSL3_AD_BAD_RECORD_MAC : "SSL3_AD_BAD_RECORD_MAC",
  73. SSL3_AD_DECOMPRESSION_FAILURE : "SSL3_AD_DECOMPRESSION_FAILURE",
  74. SSL3_AD_HANDSHAKE_FAILURE : "SSL3_AD_HANDSHAKE_FAILURE",
  75. SSL3_AD_NO_CERTIFICATE : "SSL3_AD_NO_CERTIFICATE",
  76. SSL3_AD_BAD_CERTIFICATE : "SSL3_AD_BAD_CERTIFICATE",
  77. SSL3_AD_UNSUPPORTED_CERTIFICATE : "SSL3_AD_UNSUPPORTED_CERTIFICATE",
  78. SSL3_AD_CERTIFICATE_REVOKED : "SSL3_AD_CERTIFICATE_REVOKED",
  79. SSL3_AD_CERTIFICATE_EXPIRED : "SSL3_AD_CERTIFICATE_EXPIRED",
  80. SSL3_AD_CERTIFICATE_UNKNOWN : "SSL3_AD_CERTIFICATE_UNKNOWN",
  81. SSL3_AD_ILLEGAL_PARAMETER : "SSL3_AD_ILLEGAL_PARAMETER",
  82. TLS1_AD_DECRYPTION_FAILED : "TLS1_AD_DECRYPTION_FAILED",
  83. TLS1_AD_RECORD_OVERFLOW : "TLS1_AD_RECORD_OVERFLOW",
  84. TLS1_AD_UNKNOWN_CA : "TLS1_AD_UNKNOWN_CA",
  85. TLS1_AD_ACCESS_DENIED : "TLS1_AD_ACCESS_DENIED",
  86. TLS1_AD_DECODE_ERROR : "TLS1_AD_DECODE_ERROR",
  87. TLS1_AD_DECRYPT_ERROR : "TLS1_AD_DECRYPT_ERROR",
  88. TLS1_AD_EXPORT_RESTRICTION : "TLS1_AD_EXPORT_RESTRICTION",
  89. TLS1_AD_PROTOCOL_VERSION : "TLS1_AD_PROTOCOL_VERSION",
  90. TLS1_AD_INSUFFICIENT_SECURITY : "TLS1_AD_INSUFFICIENT_SECURITY",
  91. TLS1_AD_INTERNAL_ERROR : "TLS1_AD_INTERNAL_ERROR",
  92. TLS1_AD_USER_CANCELLED : "TLS1_AD_USER_CANCELLED",
  93. TLS1_AD_NO_RENEGOTIATION : "TLS1_AD_NO_RENEGOTIATION",
  94. TLS1_AD_UNSUPPORTED_EXTENSION : "TLS1_AD_UNSUPPORTED_EXTENSION",
  95. TLS1_AD_CERTIFICATE_UNOBTAINABLE : "TLS1_AD_CERTIFICATE_UNOBTAINABLE",
  96. TLS1_AD_UNRECOGNIZED_NAME : "TLS1_AD_UNRECOGNIZED_NAME",
  97. TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE : "TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE",
  98. TLS1_AD_BAD_CERTIFICATE_HASH_VALUE : "TLS1_AD_BAD_CERTIFICATE_HASH_VALUE",
  99. TLS1_AD_UNKNOWN_PSK_IDENTITY : "TLS1_AD_UNKNOWN_PSK_IDENTITY"
  100. }
  101. # Record types
  102. RECORD_TLS_CHG_CIPHERSPEC = 20
  103. RECORD_TLS_ALERT = 21
  104. RECORD_TLS_HANDSHAKE = 22
  105. RECORD_TLS_HANDSHAKE_HELLO = 22 * 10
  106. RECORD_TLS_HANDSHAKE_DATA = 22 * 100
  107. RECORD_TLS_APPDATA = 23
  108. # Handshake types
  109. HNDS_HELLO_REQ = 0
  110. HNDS_HELLO_CLIENT = 1
  111. HNDS_HELLO_SERVER = 2
  112. HNDS_CERTIFICATE = 11
  113. HNDS_SERVER_KEY_EXCHANGE = 12
  114. HNDS_CERTIFICATE_REQ = 13
  115. HNDS_SERVER_HELLO_DONE = 14
  116. HNDS_CERT_VERIFIY = 15
  117. HNDS_CLIENT_KEY_EXCHANGE = 16
  118. HNDS_FINISHED = 20
  119. class SSL(pypacker.Packet):
  120. __hdr__ = (
  121. ("records", None, triggerlist.TriggerList),
  122. )
  123. def _dissect(self, buf):
  124. # logger.debug("parsing SSL")
  125. # parse all records out of message
  126. # possible types are Client/Sevrer Hello, Change Cipher Spec etc.
  127. records = []
  128. offset = 0
  129. dlen = len(buf)
  130. self._fragmented = False
  131. # records is the only header so it's ok to avoid lazy dissecting
  132. while offset < dlen:
  133. record_len = unpack_be_h(buf[offset + 3: offset + 5])[0]
  134. if offset + record_len > dlen:
  135. # TODO: handle fragmentation
  136. # idea: design _dissect() in a way which allows continuation
  137. # at any given start-point, eg start of a record-entry
  138. # Later call to a "reassemble([pkt1, pkt2])" can re-use
  139. # _dissect to add all other records
  140. logger.warn("possible fragmentation found")
  141. self._fragmented = True
  142. # non-parsed data becomes body content
  143. dlen = offset
  144. break
  145. record = Record(buf[offset: offset + 5 + record_len])
  146. records.append(record)
  147. offset += len(record)
  148. # logger.debug("adding records, dlen/offset at end: %d %d" % (dlen, offset))
  149. self.records.extend(records)
  150. return dlen
  151. class Record(pypacker.Packet):
  152. """
  153. SSLv3 or TLSv1+ Record layer.
  154. """
  155. __hdr__ = (
  156. ("type", "B", 0),
  157. ("version", "H", 0),
  158. ("len", "H", 0),
  159. )
  160. def __dissect(self, buf):
  161. # logger.debug("parsing TLSRecord")
  162. # TODO: check for different handshages
  163. self._init_handler(buf[0], buf[5:])
  164. return 5
  165. class Extension(pypacker.Packet):
  166. """
  167. Handshake protocol extension
  168. """
  169. __hdr__ = (
  170. ("type", "H", 0),
  171. ("len", "H", 0)
  172. )
  173. #
  174. # Record contents
  175. #
  176. class HandshakeHello(pypacker.Packet):
  177. __hdr__ = (
  178. ("type", "B", 0),
  179. # can't use struct here but:
  180. # int.from_bytes(len, "big")
  181. ("len", "3s", b"\x00" * 3),
  182. ("tlsversion", "H", 0x0301),
  183. ("random", "32s", b"\x00" * 32),
  184. ("sid_len", "B", 32),
  185. # variable length
  186. ("sid", None, b"A" * 32),
  187. ("ciphersuite", "H", 0x0035),
  188. ("compression", "B", 0),
  189. ("ext_len", "H", 0x0000),
  190. ("extensions", None, triggerlist.TriggerList),
  191. )
  192. @staticmethod
  193. def __parse_extension(buf):
  194. extensions = []
  195. offset = 0
  196. buflen = len(buf)
  197. while offset < buflen:
  198. ext_content_len = unpack(buf[offset + 2: offset + 4])
  199. ext_len = 4 + ext_content_len
  200. extensions.append(Extension(buf[offset: offset + ext_len]))
  201. offset += ext_len
  202. return extensions
  203. def _dissect(self, buf):
  204. sid_len = buf[38]
  205. offset_extlen = 38 + sid_len + 3
  206. # ext_len = unpack(buf[offset_extlen : offset_extlen+2])
  207. self._init_triggerlist("extensions", buf[offset_extlen + 2:], self.__parse_extension)
  208. class HandshakeData(pypacker.Packet):
  209. pass
  210. class ChangeCipherSpec(pypacker.Packet):
  211. pass
  212. class ApplicationData(pypacker.Packet):
  213. pass
  214. pypacker.Packet.load_handler(Record,
  215. {
  216. RECORD_TLS_CHG_CIPHERSPEC: ChangeCipherSpec,
  217. RECORD_TLS_HANDSHAKE_HELLO: HandshakeHello,
  218. RECORD_TLS_HANDSHAKE_DATA: HandshakeData,
  219. RECORD_TLS_APPDATA: ApplicationData
  220. }
  221. )