def test_canonicalize_header(self): """ L{DKIMVerifier.canonicalizeHeader} correctly canonicalizes headers. """ data = ( ("Content-Type", " text/calendar ; charset = \"utf-8\" ", "content-type:text/calendar ; charset = \"utf-8\"\r\n"), ("Originator", " mailto:[email protected] ", "originator:mailto:[email protected]\r\n"), ("Recipient", " mailto:[email protected] ,\t mailto:[email protected]\t\t ", "recipient:mailto:[email protected],mailto:[email protected]\r\n"), ("iSchedule-Version", " 1.0 ", "ischedule-version:1.0\r\n"), ( "DKIM-Signature", " v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a b c; b=d ef", "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a b c; b=", ), ( "DKIM-Signature", " v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; b= def ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a\t bc", "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; b= ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a bc", ), ) for name, value, result in data: verifier = DKIMVerifier(self._makeHeaders(((name, value,),)), "") if name == "DKIM-Signature": verifier.processDKIMHeader() canonicalized = DKIMUtils.canonicalizeHeader(name, value, verifier.dkim_tags if name == "DKIM-Signature" else None) self.assertEqual(canonicalized, result)
def _verify(hdrs, body, keys, result, sign_headers=("Originator", "Recipient", "Content-Type",), manipulate_request=None): for algorithm in ("rsa-sha1", "rsa-sha256",): # Create signature stream = MemoryStream(body) headers = Headers() for name, value in [hdr.split(":", 1) for hdr in hdrs.splitlines()]: headers.addRawHeader(name, value) request = DKIMRequest("POST", "/", headers, stream, "example.com", "dkim", self.private_keyfile, algorithm, sign_headers, True, True, True, 3600) yield request.sign() # Possibly munge the request after the signature is done if manipulate_request is not None: manipulate_request(request) # Verify signature TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys data = (yield allDataFromStream(request.stream)) verifier = DKIMVerifier(request.headers, data, key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,)) TestPublicKeyLookup.PublicKeyLookup_Testing({}).flushCache() try: yield verifier.verify() except Exception, e: if result: self.fail("DKIMVerifier:verify failed: %s" % (e,)) else: if not result: self.fail("DKIMVerifier:verify did not fail")
def test_extract_headers(self): """ L{DKIMVerifier.extractSignedHeaders} correctly extracts canonicalizes headers. """ data = ( # Count on Recipient ("""Host:example.com Content-Type: text/calendar ; charset = "utf-8" Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t iSchedule-Version: 1.0 DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Cache-Control:no-cache Connection:close """, """content-type:text/calendar ; charset = "utf-8" originator:mailto:[email protected] recipient:mailto:[email protected],mailto:[email protected] ischedule-version:1.0 dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=""" ), # Exact count on Recipient ("""Host:example.com Content-Type: text/calendar ; charset = "utf-8" Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t Recipient:\t\t mailto:[email protected] iSchedule-Version: 1.0 DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Cache-Control:no-cache Connection:close """, """content-type:text/calendar ; charset = "utf-8" originator:mailto:[email protected] recipient:mailto:[email protected],mailto:[email protected],mailto:[email protected] ischedule-version:1.0 dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=""" ), # Re-ordered Content-Type ("""Host:example.com iSchedule-Version: 1.0 Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Content-Type: text/calendar ; charset = "utf-8" Cache-Control:no-cache Connection:close """, """content-type:text/calendar ; charset = "utf-8" originator:mailto:[email protected] recipient:mailto:[email protected],mailto:[email protected] ischedule-version:1.0 dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=""" ), ) for hdrs, result in data: headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()] verifier = DKIMVerifier(self._makeHeaders(headers), "") verifier.processDKIMHeader() extracted = verifier.extractSignedHeaders() self.assertEqual(extracted, result.replace("\n", "\r\n"))
def test_locate_public_key(self): """ L{DKIMVerifier.locatePublicKey} correctly finds key matching headers. """ data = ( # Valid ( """Host:example.com Content-Type: text/calendar ; charset = "utf-8" Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Cache-Control:no-cache Connection:close """, [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))], True, ), # Invalid - no method ( """Host:example.com Content-Type: text/calendar ; charset = "utf-8" Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Cache-Control:no-cache Connection:close """, [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))], False, ), # Invalid - wrong algorithm ( """Host:example.com Content-Type: text/calendar ; charset = "utf-8" Originator: mailto:[email protected] Recipient: mailto:[email protected] ,\t mailto:[email protected]\t\t DKIM-Signature: v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def Cache-Control:no-cache Connection:close """, [DKIMUtils.extractTags("v=DKIM1; h=sha-1; p=%s" % (self.public_key_data,))], False, ), ) for hdrs, keys, result in data: headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()] TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys TestPublicKeyLookup.PublicKeyLookup_Testing.flushCache() verifier = DKIMVerifier(self._makeHeaders(headers), "", key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,)) verifier.processDKIMHeader() pkey = (yield verifier.locatePublicKey()) if result: self.assertTrue(pkey is not None) else: self.assertTrue(pkey is None)
def _doVerify(options): # Parse the HTTP file verify = open(os.path.expanduser(options["verify"])).read() _method, _uri, headers, body = _parseRequest(verify) # Check for local public key if options["pub-key"]: PublicKeyLookup_File.pubkeyfile = os.path.expanduser(options["pub-key"]) lookup = (PublicKeyLookup_File,) else: lookup = None dkim = DKIMVerifier(headers, body, lookup) if options["fake-time"]: dkim.time = 0 try: yield dkim.verify() except DKIMVerificationError, e: print("Verification Failed: %s" % (e,))
def _doVerify(options): # Parse the HTTP file verify = open(options["verify"]).read() method, uri, headers, stream = _parseRequest(verify) request = ClientRequest(method, uri, headers, stream) # Check for local public key if options["pub-key"]: PublicKeyLookup_File.pubkeyfile = options["pub-key"] lookup = (PublicKeyLookup_File, ) else: lookup = None dkim = DKIMVerifier(request, lookup) if options["fake-time"]: dkim.time = 0 try: yield dkim.verify() except DKIMVerificationError, e: print("Verification Failed: %s" % (e, ))
def test_valid_dkim_headers(self): """ L{DKIMVerifier.processDKIMHeader} correctly validates DKIM-Signature headers. """ data = ( # Bogus ((("DKIM-Signature", "v=1"),), False,), # More than one (( ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"), ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha256; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"), ), False,), # Valid ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), True,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def"),), True,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() + 30),)),), True,), # Invalid ((("DKIM-Signature", "v=2; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha512; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/relaxed; h=Originator:Recipient; bh=abc; b=def"),), False,), ((("DKIM-Signature", "v=1; d=example.com; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,), ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,), ) for headers, result in data: verifier = DKIMVerifier(self._makeHeaders(headers), "") if result: verifier.processDKIMHeader() else: self.assertRaises(DKIMVerificationError, verifier.processDKIMHeader)