tsig_python_test.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. # Copyright (C) 2011 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. import base64, sys, time, unittest
  16. from pydnspp import *
  17. from testutil import *
  18. from pyunittests_util import fix_current_time
  19. # bit-wise constant flags to configure DNS header flags for test
  20. # messages.
  21. QR_FLAG = 0x1
  22. AA_FLAG = 0x2
  23. RD_FLAG = 0x4
  24. COMMON_EXPECTED_MAC = b"\x22\x70\x26\xad\x29\x7b\xee\xe7\x21\xce\x6c\x6f\xff\x1e\x9e\xf3"
  25. DUMMY_DATA = b"\xdd" * 100
  26. class TSIGContextTest(unittest.TestCase):
  27. tsig_key = TSIGKey('www.example.com:SFuWd/q99SzF8Yzd1QbB9g==')
  28. def setUp(self):
  29. # make sure we don't use faked time unless explicitly do so in tests
  30. fix_current_time(None)
  31. self.qid = 0x2d65
  32. self.test_name = Name("www.example.com")
  33. self.tsig_ctx = TSIGContext(self.tsig_key)
  34. self.tsig_verify_ctx = TSIGContext(self.tsig_key)
  35. self.keyring = TSIGKeyRing()
  36. self.message = Message(Message.RENDER)
  37. self.renderer = MessageRenderer()
  38. self.test_class = RRClass.IN
  39. self.test_ttl = RRTTL(86400)
  40. self.secret = base64.b64decode(b"SFuWd/q99SzF8Yzd1QbB9g==")
  41. self.tsig_ctx = TSIGContext(TSIGKey(self.test_name,
  42. TSIGKey.HMACMD5_NAME,
  43. self.secret))
  44. self.badkey_name = Name("badkey.example.com")
  45. self.dummy_record = TSIGRecord(self.badkey_name,
  46. TSIG("hmac-md5.sig-alg.reg.int. " + \
  47. "1302890362 300 0 11621 " + \
  48. "0 0"))
  49. def tearDown(self):
  50. # reset any faked current time setting (it would affect other tests)
  51. fix_current_time(None)
  52. # Note: intentionally use camelCase so that we can easily copy-paste
  53. # corresponding C++ tests.
  54. def createMessageAndSign(self, id, qname, ctx, message_flags=RD_FLAG,
  55. qtype=RRType.A, answer_data=None,
  56. answer_type=None, add_question=True,
  57. rcode=Rcode.NOERROR):
  58. self.message.clear(Message.RENDER)
  59. self.message.set_qid(id)
  60. self.message.set_opcode(Opcode.QUERY)
  61. self.message.set_rcode(rcode)
  62. if (message_flags & QR_FLAG) != 0:
  63. self.message.set_header_flag(Message.HEADERFLAG_QR)
  64. if (message_flags & AA_FLAG) != 0:
  65. self.message.set_header_flag(Message.HEADERFLAG_AA)
  66. if (message_flags & RD_FLAG) != 0:
  67. self.message.set_header_flag(Message.HEADERFLAG_RD)
  68. if add_question:
  69. self.message.add_question(Question(qname, self.test_class, qtype))
  70. if answer_data is not None:
  71. if answer_type is None:
  72. answer_type = qtype
  73. answer_rrset = RRset(qname, self.test_class, answer_type,
  74. self.test_ttl)
  75. answer_rrset.add_rdata(Rdata(answer_type, self.test_class,
  76. answer_data))
  77. self.message.add_rrset(Message.SECTION_ANSWER, answer_rrset)
  78. self.renderer.clear()
  79. self.message.to_wire(self.renderer)
  80. if ctx.get_state() == TSIGContext.STATE_INIT:
  81. expected_new_state = TSIGContext.STATE_SENT_REQUEST
  82. else:
  83. expected_new_state = TSIGContext.STATE_SENT_RESPONSE
  84. tsig = ctx.sign(id, self.renderer.get_data())
  85. return tsig
  86. # Note: intentionally use camelCase so that we can easily copy-paste
  87. # corresponding C++ tests.
  88. def createMessageFromFile(self, file):
  89. self.message.clear(Message.PARSE)
  90. self.received_data = read_wire_data(file)
  91. self.message.from_wire(self.received_data)
  92. # Note: intentionally use camelCase so that we can easily copy-paste
  93. # corresponding C++ tests.
  94. def commonSignChecks(self, tsig, expected_qid, expected_timesigned,
  95. expected_mac, expected_error=0,
  96. expected_otherdata=None,
  97. expected_algorithm=TSIGKey.HMACMD5_NAME):
  98. tsig_rdata = tsig.get_rdata()
  99. self.assertEqual(expected_algorithm, tsig_rdata.get_algorithm())
  100. self.assertEqual(expected_timesigned, tsig_rdata.get_timesigned())
  101. self.assertEqual(300, tsig_rdata.get_fudge())
  102. self.assertEqual(expected_mac, tsig_rdata.get_mac())
  103. self.assertEqual(expected_qid, tsig_rdata.get_original_id())
  104. self.assertEqual(expected_error, tsig_rdata.get_error())
  105. self.assertEqual(expected_otherdata, tsig_rdata.get_other_data())
  106. def test_initial_state(self):
  107. # Until signing or verifying, the state should be INIT
  108. self.assertEqual(TSIGContext.STATE_INIT, self.tsig_ctx.get_state())
  109. # And there should be no error code.
  110. self.assertEqual(TSIGError(Rcode.NOERROR), self.tsig_ctx.get_error())
  111. # No message signed yet
  112. self.assertRaises(TSIGContextError, self.tsig_ctx.last_had_signature)
  113. # Note: intentionally use camelCase so that we can easily copy-paste
  114. # corresponding C++ tests.
  115. def commonVerifyChecks(self, ctx, record, data, expected_error,
  116. expected_new_state=\
  117. TSIGContext.STATE_VERIFIED_RESPONSE,
  118. last_should_throw=False):
  119. self.assertEqual(expected_error, ctx.verify(record, data))
  120. self.assertEqual(expected_error, ctx.get_error())
  121. self.assertEqual(expected_new_state, ctx.get_state())
  122. if last_should_throw:
  123. self.assertRaises(TSIGContextError, ctx.last_had_signature)
  124. else:
  125. self.assertEqual(record is not None,
  126. ctx.last_had_signature())
  127. def test_from_keyring(self):
  128. # Construct a TSIG context with an empty key ring. Key shouldn't be
  129. # found, and the BAD_KEY error should be recorded.
  130. ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
  131. self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
  132. self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
  133. # check get_error() doesn't cause ref leak. Note: we can't
  134. # realiably do this check for get_state(), as it returns an integer
  135. # object, which could have many references
  136. self.assertEqual(1, sys.getrefcount(ctx.get_error()))
  137. # Add a matching key (we don't use the secret so leave it empty), and
  138. # construct it again. This time it should be constructed with a valid
  139. # key.
  140. self.keyring.add(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME, b""))
  141. ctx = TSIGContext(self.test_name, TSIGKey.HMACMD5_NAME, self.keyring)
  142. self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
  143. self.assertEqual(TSIGError.NOERROR, ctx.get_error())
  144. # Similar to the first case except that the key ring isn't empty but
  145. # it doesn't contain a matching key.
  146. ctx = TSIGContext(self.test_name, TSIGKey.HMACSHA1_NAME, self.keyring)
  147. self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
  148. self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
  149. ctx = TSIGContext(Name("different-key.example"),
  150. TSIGKey.HMACMD5_NAME, self.keyring)
  151. self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
  152. self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
  153. # "Unknown" algorithm name will result in BADKEY, too.
  154. ctx = TSIGContext(self.test_name, Name("unknown.algorithm"),
  155. self.keyring)
  156. self.assertEqual(TSIGContext.STATE_INIT, ctx.get_state())
  157. self.assertEqual(TSIGError.BAD_KEY, ctx.get_error())
  158. def test_sign(self):
  159. fix_current_time(0x4da8877a)
  160. tsig = self.createMessageAndSign(self.qid, self.test_name,
  161. self.tsig_ctx)
  162. self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
  163. # Same test as sign, but specifying the key name with upper-case (i.e.
  164. # non canonical) characters. The digest must be the same. It should
  165. # actually be ensured at the level of TSIGKey, but we confirm that at
  166. # this level, too.
  167. def test_sign_using_uppercase_keyname(self):
  168. fix_current_time(0x4da8877a)
  169. cap_ctx = TSIGContext(TSIGKey(Name("WWW.EXAMPLE.COM"),
  170. TSIGKey.HMACMD5_NAME, self.secret))
  171. tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
  172. self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
  173. # Same as the previous test, but for the algorithm name.
  174. def test_sign_using_uppercase_algorithm_name(self):
  175. fix_current_time(0x4da8877a)
  176. cap_ctx = TSIGContext(TSIGKey(self.test_name,
  177. Name("HMAC-md5.SIG-alg.REG.int"),
  178. self.secret))
  179. tsig = self.createMessageAndSign(self.qid, self.test_name, cap_ctx)
  180. self.commonSignChecks(tsig, self.qid, 0x4da8877a, COMMON_EXPECTED_MAC)
  181. # Sign the message using the actual time, and check the accuracy of it.
  182. # We cannot reasonably predict the expected MAC, so don't bother to
  183. # check it.
  184. def test_sign_at_actual_time(self):
  185. now = int(time.time())
  186. tsig = self.createMessageAndSign(self.qid, self.test_name,
  187. self.tsig_ctx)
  188. tsig_rdata = tsig.get_rdata()
  189. # Check the resulted time signed is in the range of [now, now + 5]
  190. self.assertTrue(now <= tsig_rdata.get_timesigned())
  191. self.assertTrue(now + 5 >= tsig_rdata.get_timesigned())
  192. def test_bad_data(self):
  193. self.assertRaises(TypeError, self.tsig_ctx.sign, None, 10)
  194. def test_verify_bad_data(self):
  195. # the data must at least hold the DNS message header and the specified
  196. # TSIG.
  197. bad_len = 12 + self.dummy_record.get_length() - 1
  198. self.assertRaises(InvalidParameter, self.tsig_ctx.verify,
  199. self.dummy_record, DUMMY_DATA[:bad_len])
  200. def test_sign_using_hmacsha1(self):
  201. fix_current_time(0x4dae7d5f)
  202. secret = base64.b64decode(b"MA+QDhXbyqUak+qnMFyTyEirzng=")
  203. sha1_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACSHA1_NAME,
  204. secret))
  205. qid = 0x0967
  206. expected_mac = b"\x41\x53\x40\xc7\xda\xf8\x24\xed\x68\x4e\xe5\x86" + \
  207. b"\xf7\xb5\xa6\x7a\x2f\xeb\xc0\xd3"
  208. tsig = self.createMessageAndSign(qid, self.test_name, sha1_ctx)
  209. self.commonSignChecks(tsig, qid, 0x4dae7d5f, expected_mac,
  210. 0, None, TSIGKey.HMACSHA1_NAME)
  211. def test_verify_then_sign_response(self):
  212. fix_current_time(0x4da8877a)
  213. self.createMessageFromFile("message_toWire2.wire")
  214. self.commonVerifyChecks(self.tsig_verify_ctx,
  215. self.message.get_tsig_record(),
  216. self.received_data, TSIGError.NOERROR,
  217. TSIGContext.STATE_RECEIVED_REQUEST)
  218. tsig = self.createMessageAndSign(self.qid, self.test_name,
  219. self.tsig_verify_ctx,
  220. QR_FLAG|AA_FLAG|RD_FLAG,
  221. RRType.A, "192.0.2.1")
  222. expected_mac = b"\x8f\xcd\xa6\x6a\x7c\xd1\xa3\xb9\x94\x8e\xb1\x86" + \
  223. b"\x9d\x38\x4a\x9f"
  224. self.commonSignChecks(tsig, self.qid, 0x4da8877a, expected_mac)
  225. def test_verify_uppercase_names(self):
  226. fix_current_time(0x4da8877a)
  227. self.createMessageFromFile("tsig_verify9.wire")
  228. self.commonVerifyChecks(self.tsig_verify_ctx,
  229. self.message.get_tsig_record(),
  230. self.received_data, TSIGError.NOERROR,
  231. TSIGContext.STATE_RECEIVED_REQUEST)
  232. def test_verify_forward_message(self):
  233. fix_current_time(0x4da8877a)
  234. self.createMessageFromFile("tsig_verify6.wire")
  235. self.commonVerifyChecks(self.tsig_verify_ctx,
  236. self.message.get_tsig_record(),
  237. self.received_data, TSIGError.NOERROR,
  238. TSIGContext.STATE_RECEIVED_REQUEST)
  239. def test_sign_continuation(self):
  240. fix_current_time(0x4da8e951)
  241. axfr_qid = 0x3410
  242. zone_name = Name("example.com")
  243. tsig = self.createMessageAndSign(axfr_qid, zone_name, self.tsig_ctx,
  244. 0, RRType.AXFR)
  245. received_data = read_wire_data("tsig_verify1.wire")
  246. self.commonVerifyChecks(self.tsig_verify_ctx, tsig, received_data,
  247. TSIGError.NOERROR,
  248. TSIGContext.STATE_RECEIVED_REQUEST)
  249. tsig = self.createMessageAndSign(axfr_qid, zone_name,
  250. self.tsig_verify_ctx,
  251. AA_FLAG|QR_FLAG, RRType.AXFR,
  252. "ns.example.com. root.example.com." +\
  253. " 2011041503 7200 3600 2592000 1200",
  254. RRType.SOA)
  255. received_data = read_wire_data("tsig_verify2.wire")
  256. self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
  257. TSIGError.NOERROR)
  258. expected_mac = b"\x10\x24\x58\xf7\xf6\x2d\xdd\x7d\x63\x8d\x74" +\
  259. b"\x60\x34\x13\x09\x68"
  260. tsig = self.createMessageAndSign(axfr_qid, zone_name,
  261. self.tsig_verify_ctx,
  262. AA_FLAG|QR_FLAG, RRType.AXFR,
  263. "ns.example.com.", RRType.NS,
  264. False)
  265. self.commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac)
  266. received_data = read_wire_data("tsig_verify3.wire")
  267. self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
  268. TSIGError.NOERROR)
  269. def test_badtime_response(self):
  270. fix_current_time(0x4da8b9d6)
  271. test_qid = 0x7fc4
  272. tsig = self.createMessageAndSign(test_qid, self.test_name,
  273. self.tsig_ctx, 0, RRType.SOA)
  274. # "advance the clock" and try validating, which should fail due to
  275. # BADTIME
  276. fix_current_time(0x4da8be86)
  277. self.commonVerifyChecks(self.tsig_verify_ctx, tsig, DUMMY_DATA,
  278. TSIGError.BAD_TIME,
  279. TSIGContext.STATE_RECEIVED_REQUEST)
  280. # make and sign a response in the context of TSIG error.
  281. tsig = self.createMessageAndSign(test_qid, self.test_name,
  282. self.tsig_verify_ctx,
  283. QR_FLAG, RRType.SOA, None, None,
  284. True, Rcode.NOTAUTH)
  285. expected_otherdata = b"\x00\x00\x4d\xa8\xbe\x86"
  286. expected_mac = b"\xd4\xb0\x43\xf6\xf4\x44\x95\xec\x8a\x01\x26" +\
  287. b"\x0e\x39\x15\x9d\x76"
  288. self.commonSignChecks(tsig, self.message.get_qid(), 0x4da8b9d6,
  289. expected_mac,
  290. 18, # error: BADTIME
  291. expected_otherdata)
  292. def test_badtime_response2(self):
  293. fix_current_time(0x4da8b9d6)
  294. tsig = self.createMessageAndSign(self.qid, self.test_name,
  295. self.tsig_ctx, 0, RRType.SOA)
  296. # "rewind the clock" and try validating, which should fail due to
  297. # BADTIME
  298. fix_current_time(0x4da8b9d6 - 600)
  299. self.commonVerifyChecks(self.tsig_verify_ctx, tsig, DUMMY_DATA,
  300. TSIGError.BAD_TIME,
  301. TSIGContext.STATE_RECEIVED_REQUEST)
  302. # Test various boundary conditions. We intentionally use the magic
  303. # number of 300 instead of the constant variable for testing.
  304. # In the okay cases, signature is not correct, but it's sufficient to
  305. # check the error code isn't BADTIME for the purpose of this test.
  306. def test_badtime_boundaries(self):
  307. fix_current_time(0x4da8b9d6)
  308. tsig = self.createMessageAndSign(self.qid, self.test_name,
  309. self.tsig_ctx, 0, RRType.SOA)
  310. fix_current_time(0x4da8b9d6 + 301)
  311. self.assertEqual(TSIGError.BAD_TIME,
  312. self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
  313. fix_current_time(0x4da8b9d6 + 300)
  314. self.assertNotEqual(TSIGError.BAD_TIME,
  315. self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
  316. fix_current_time(0x4da8b9d6 - 301)
  317. self.assertEqual(TSIGError.BAD_TIME,
  318. self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
  319. fix_current_time(0x4da8b9d6 - 300)
  320. self.assertNotEqual(TSIGError.BAD_TIME,
  321. self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
  322. def test_badtime_overflow(self):
  323. fix_current_time(200)
  324. tsig = self.createMessageAndSign(self.qid, self.test_name,
  325. self.tsig_ctx, 0, RRType.SOA)
  326. # This should be in the okay range, but since "200 - fudge" overflows
  327. # and we compare them as 64-bit unsigned integers, it results in a
  328. # false positive (we intentionally accept that).
  329. fix_current_time(100)
  330. self.assertEqual(TSIGError.BAD_TIME,
  331. self.tsig_verify_ctx.verify(tsig, DUMMY_DATA))
  332. def test_badsig_response(self):
  333. fix_current_time(0x4da8877a)
  334. # Try to sign a simple message with bogus secret. It should fail
  335. # with BADSIG.
  336. self.createMessageFromFile("message_toWire2.wire")
  337. bad_ctx = TSIGContext(TSIGKey(self.test_name, TSIGKey.HMACMD5_NAME,
  338. DUMMY_DATA))
  339. self.commonVerifyChecks(bad_ctx, self.message.get_tsig_record(),
  340. self.received_data, TSIGError.BAD_SIG,
  341. TSIGContext.STATE_RECEIVED_REQUEST)
  342. # Sign the same message (which doesn't matter for this test) with the
  343. # context of "checked state".
  344. tsig = self.createMessageAndSign(self.qid, self.test_name, bad_ctx)
  345. self.commonSignChecks(tsig, self.message.get_qid(), 0x4da8877a, None,
  346. 16) # 16: BADSIG
  347. def test_badkey_response(self):
  348. # A similar test as badsigResponse but for BADKEY
  349. fix_current_time(0x4da8877a)
  350. tsig_ctx = TSIGContext(self.badkey_name, TSIGKey.HMACMD5_NAME,
  351. self.keyring)
  352. self.commonVerifyChecks(tsig_ctx, self.dummy_record, DUMMY_DATA,
  353. TSIGError.BAD_KEY,
  354. TSIGContext.STATE_RECEIVED_REQUEST)
  355. sig = self.createMessageAndSign(self.qid, self.test_name, tsig_ctx)
  356. self.assertEqual(self.badkey_name, sig.get_name())
  357. self.commonSignChecks(sig, self.qid, 0x4da8877a, None, 17) # 17: BADKEY
  358. def test_badkey_for_response(self):
  359. # "BADKEY" case for a response to a signed message
  360. self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
  361. self.commonVerifyChecks(self.tsig_ctx, self.dummy_record, DUMMY_DATA,
  362. TSIGError.BAD_KEY,
  363. TSIGContext.STATE_SENT_REQUEST)
  364. # A similar case with a different algorithm
  365. dummy_record = TSIGRecord(self.test_name,
  366. TSIG("hmac-sha1. 1302890362 300 0 "
  367. "11621 0 0"))
  368. self.commonVerifyChecks(self.tsig_ctx, dummy_record, DUMMY_DATA,
  369. TSIGError.BAD_KEY,
  370. TSIGContext.STATE_SENT_REQUEST)
  371. # According to RFC2845 4.6, if TSIG verification fails the client
  372. # should discard that message and wait for another signed response.
  373. # This test emulates that situation.
  374. def test_badsig_then_validate(self):
  375. fix_current_time(0x4da8877a)
  376. self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
  377. self.createMessageFromFile("tsig_verify4.wire")
  378. self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
  379. self.received_data, TSIGError.BAD_SIG,
  380. TSIGContext.STATE_SENT_REQUEST)
  381. self.createMessageFromFile("tsig_verify5.wire")
  382. self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
  383. self.received_data, TSIGError.NOERROR,
  384. TSIGContext.STATE_VERIFIED_RESPONSE)
  385. # Similar to the previous test, but the first response doesn't contain
  386. # TSIG.
  387. def test_nosig_then_validate(self):
  388. fix_current_time(0x4da8877a)
  389. self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
  390. self.commonVerifyChecks(self.tsig_ctx, None, DUMMY_DATA,
  391. TSIGError.FORMERR, TSIGContext.STATE_SENT_REQUEST,
  392. True)
  393. self.createMessageFromFile("tsig_verify5.wire")
  394. self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
  395. self.received_data, TSIGError.NOERROR,
  396. TSIGContext.STATE_VERIFIED_RESPONSE)
  397. # Similar to the previous test, but the first response results in BADTIME.
  398. def test_badtime_then_validate(self):
  399. fix_current_time(0x4da8877a)
  400. tsig = self.createMessageAndSign(self.qid, self.test_name,
  401. self.tsig_ctx)
  402. # "advance the clock" and try validating, which should fail due to
  403. # BADTIME
  404. fix_current_time(0x4da8877a + 600)
  405. self.commonVerifyChecks(self.tsig_ctx, tsig, DUMMY_DATA,
  406. TSIGError.BAD_TIME, TSIGContext.STATE_SENT_REQUEST)
  407. # revert the clock again.
  408. fix_current_time(0x4da8877a)
  409. self.createMessageFromFile("tsig_verify5.wire")
  410. self.commonVerifyChecks(self.tsig_ctx, self.message.get_tsig_record(),
  411. self.received_data, TSIGError.NOERROR,
  412. TSIGContext.STATE_VERIFIED_RESPONSE)
  413. # We don't allow empty MAC unless the TSIG error is BADSIG or BADKEY.
  414. def test_empty_mac(self):
  415. fix_current_time(0x4da8877a)
  416. self.createMessageFromFile("tsig_verify7.wire")
  417. self.commonVerifyChecks(self.tsig_verify_ctx,
  418. self.message.get_tsig_record(),
  419. self.received_data,
  420. TSIGError.BAD_SIG,
  421. TSIGContext.STATE_RECEIVED_REQUEST)
  422. # If the empty MAC comes with a BADKEY error, the error is passed
  423. # transparently.
  424. self.createMessageFromFile("tsig_verify8.wire")
  425. self.commonVerifyChecks(self.tsig_verify_ctx,
  426. self.message.get_tsig_record(),
  427. self.received_data,
  428. TSIGError.BAD_KEY,
  429. TSIGContext.STATE_RECEIVED_REQUEST)
  430. # Once the context is used for sending a signed response, it shouldn't
  431. # be used for further verification.
  432. def test_verify_after_sendresponse(self):
  433. fix_current_time(0x4da8877a)
  434. self.createMessageFromFile("message_toWire2.wire")
  435. self.tsig_verify_ctx.verify(self.message.get_tsig_record(),
  436. self.received_data)
  437. self.assertEqual(TSIGContext.STATE_RECEIVED_REQUEST,
  438. self.tsig_verify_ctx.get_state())
  439. self.createMessageAndSign(self.qid, self.test_name,
  440. self.tsig_verify_ctx,
  441. QR_FLAG|AA_FLAG|RD_FLAG, RRType.A,
  442. "192.0.2.1")
  443. self.assertEqual(TSIGContext.STATE_SENT_RESPONSE,
  444. self.tsig_verify_ctx.get_state())
  445. # Now trying further verification.
  446. self.createMessageFromFile("message_toWire2.wire")
  447. self.assertRaises(TSIGContextError, self.tsig_verify_ctx.verify,
  448. self.message.get_tsig_record(), self.received_data)
  449. # Likewise, once the context verifies a response, it shouldn't for
  450. # signing any more.
  451. def test_sign_after_verified(self):
  452. fix_current_time(0x4da8877a)
  453. self.createMessageAndSign(self.qid, self.test_name, self.tsig_ctx)
  454. self.createMessageFromFile("tsig_verify5.wire")
  455. self.tsig_ctx.verify(self.message.get_tsig_record(),
  456. self.received_data)
  457. self.assertEqual(TSIGContext.STATE_VERIFIED_RESPONSE,
  458. self.tsig_ctx.get_state())
  459. # Now trying further signing.
  460. self.assertRaises(TSIGContextError, self.createMessageAndSign,
  461. self.qid, self.test_name, self.tsig_ctx)
  462. # Too short MAC should be rejected.
  463. # Note: when we implement RFC4635-based checks, the error code will
  464. # (probably) be FORMERR.
  465. def test_too_short_mac(self):
  466. fix_current_time(0x4da8877a)
  467. self.createMessageFromFile("tsig_verify10.wire")
  468. self.commonVerifyChecks(self.tsig_verify_ctx,
  469. self.message.get_tsig_record(),
  470. self.received_data, TSIGError.BAD_SIG,
  471. TSIGContext.STATE_RECEIVED_REQUEST)
  472. if __name__ == '__main__':
  473. unittest.main()