[CalendarServer-changes] [9766] CalendarServer/branches/users/cdaboo/ischedule-dkim

source_changes at macosforge.org source_changes at macosforge.org
Tue Sep 4 08:24:12 PDT 2012


Revision: 9766
          http://trac.macosforge.org/projects/calendarserver/changeset/9766
Author:   cdaboo at apple.com
Date:     2012-09-04 08:24:11 -0700 (Tue, 04 Sep 2012)
Log Message:
-----------
Update to latest iSchedule spec. Add a dkimtool to do command line key-gen, request generation, request verification.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/__init__.py
    CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/dkim.py
    CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/test/test_dkim.py

Added Paths:
-----------
    CalendarServer/branches/users/cdaboo/ischedule-dkim/calendarserver/tools/dkimtool.py

Added: CalendarServer/branches/users/cdaboo/ischedule-dkim/calendarserver/tools/dkimtool.py
===================================================================
--- CalendarServer/branches/users/cdaboo/ischedule-dkim/calendarserver/tools/dkimtool.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/ischedule-dkim/calendarserver/tools/dkimtool.py	2012-09-04 15:24:11 UTC (rev 9766)
@@ -0,0 +1,284 @@
+#!/usr/bin/env python
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from StringIO import StringIO
+from subprocess import PIPE
+from twext.web2.http_headers import Headers
+from twext.web2.stream import MemoryStream
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+from twisted.python.usage import Options
+from twistedcaldav.scheduling.ischedule.dkim import RSA256, DKIMRequest,\
+    PublicKeyLookup, DKIMVerifier, DKIMVerificationError
+import subprocess
+import sys
+from twext.web2.client.http import ClientRequest
+import rsa
+
+
+def _doKeyGeneration(options):
+    child = subprocess.Popen(
+        args=["openssl", "genrsa", str(options["key-size"]),],
+        stdout=PIPE,
+    )
+    output, status = child.communicate()
+    if status:
+        print "Failed to generate private key"
+        sys.exit(1)
+    output = output.strip()
+    if options["key"]:
+        open(options["key"], "w").write(output)
+    else:
+        print output
+    
+    child = subprocess.Popen(
+        args=["openssl", "rsa", "-pubout",],
+        stdout=PIPE,
+        stdin=PIPE,
+    )
+    output, status = child.communicate(output)
+    if status:
+        print "Failed to generate public key"
+        sys.exit(1)
+    output = output.strip()
+    if options["pub-key"]:
+        open(options["pub-key"], "w").write(output)
+    else:
+        print output
+    
+    if options["txt"]:
+        output = "".join(output.splitlines()[1:-1])
+        txt = "v=DKIM1; p=%s" % (output,)
+        print txt
+
+ at inlineCallbacks
+def _doRequest(options):
+    
+    # Parse the HTTP file
+    request = open(options["request"]).read()
+    method, uri, headers, stream = _parseRequest(request)
+
+    # Setup signing headers
+    sign_headers = options["signing"]
+    if sign_headers is None:
+        sign_headers = []
+        for hdr in ("Host", "Content-Type", "Originator", "Recipient+"):
+            if headers.hasHeader(hdr.rstrip("+")):
+                sign_headers.append(hdr)
+    else:
+        sign_headers = sign_headers.split(":")
+    
+    dkim = DKIMRequest(
+        method,
+        uri,
+        headers,
+        stream,
+        options["domain"],
+        options["selector"],
+        options["key"],
+        options["algorithm"],
+        sign_headers,
+        True,
+        True,
+        int(options["expire"]),
+    )
+    yield dkim.sign()
+
+    s = StringIO()
+    _writeRequest(dkim, s)
+    print s.getvalue()
+
+
+ at inlineCallbacks
+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)
+    
+    try:
+        yield dkim.verify()
+    except DKIMVerificationError, e:
+        print "Verification Failed: %s" % (e,)
+    else:
+        print "Verification Succeeded"
+
+
+def _parseRequest(request):
+    
+    lines = request.replace("\r\n", "\n").splitlines()
+    
+    method, uri, _ignore_version = lines.pop(0).split()
+    
+    hdrs = []
+    body = None
+    for line in lines:
+        if body is not None:
+            body.append(line)
+        elif line == "":
+            body = []
+        elif line[0] in (" ", "\t"):
+            hdrs[-1] += line
+        else:
+            hdrs.append(line)
+    
+    headers = Headers()
+    for hdr in hdrs:
+        name, value = hdr.split(':', 1)
+        headers.addRawHeader(name, value.lstrip())
+    
+    stream = MemoryStream("\r\n".join(body))
+
+    return method, uri, headers, stream 
+        
+
+def _writeRequest(request, f):
+    
+    f.write("%s %s HTTP/1.1\r\n" % (request.method, request.uri,))
+    for name, valuelist in request.headers.getAllRawHeaders():
+        for value in valuelist:
+            f.write("%s: %s\r\n" % (name, value))
+    f.write("\r\n")
+    f.write(request.stream.read())
+
+
+class PublicKeyLookup_File(PublicKeyLookup):
+    
+    method = "*"
+    pubkeyfile = None    
+        
+    def getPublicKey(self):
+        """
+        Do the key lookup using the actual lookup method.
+        """
+        return rsa.PublicKey.load_pkcs1(open(self.pubkeyfile).read())
+
+
+def usage(e=None):
+    if e:
+        print e
+        print ""
+    try:
+        DKIMToolOptions().opt_help()
+    except SystemExit:
+        pass
+    if e:
+        sys.exit(64)
+    else:
+        sys.exit(0)
+
+
+description = """Usage: dkimtool [options]
+Options:
+    -h            Print this help and exit
+
+    # Key Generation
+    --key-gen          Generate private/public key files
+    --key FILE         Private key file to create [stdout]
+    --pub-key FILE     Public key file to create [stdout]
+    --key-size SIZE    Key size [1024]
+    --txt              Also generate the public key TXT record
+    
+    # Request
+    --request FILE      An HTTP request to sign
+    --algorithm ALGO    Signature algorithm [rsa-sha256]
+    --domain DOMAIN     Signature domain [example.com]
+    --selector SELECTOR Signature selector [dkim]
+    --key FILE          Private key to use
+    --signing HEADERS   List of headers to sign [automatic]
+    --expire SECONDS    When to expire signature [no expiry]
+
+    # Verify
+    --verify FILE       An HTTP request to verify
+    --pkey   FILE       Public key to use in place of
+                        q= lookup
+
+Description:
+    This utility is for testing DKIM signed HTTP request.
+
+"""
+
+
+class DKIMToolOptions(Options):
+    """
+    Command-line options for 'calendarserver_dkimtool'
+    """
+
+    synopsis = description
+
+    optFlags = [
+        ['verbose', 'v', "Verbose logging."],
+        ['key-gen', 'g', "Generate private/public key files"],
+        ['txt',     't', "Also generate the public key TXT record"],
+    ]
+
+    optParameters = [
+        ['key',       'k', None, "Private key file to create [default: stdout]"],
+        ['pub-key',   'p', None, 'Public key file to create [default: stdout]'],
+        ['key-size',  'x', 1024, 'Key size'],
+        ['request',   'r', None, 'An HTTP request to sign'],
+        ['algorithm', 'a', RSA256, 'Signature algorithm'],
+        ['domain',    'd', 'example.com', 'Signature domain'],
+        ['selector',  's', 'dkim', 'Signature selector'],
+        ['signing',   'h', None, 'List of headers to sign [automatic]'],
+        ['expire',    'e', 3600, 'When to expire signature'],
+        ['verify',    'w', None, 'An HTTP request to verify'],
+    ]
+
+    def __init__(self):
+        super(DKIMToolOptions, self).__init__()
+        self.outputName = '-'
+
+
+ at inlineCallbacks
+def _runInReactor(fn, options):
+    
+    try:
+        yield fn(options)
+    except Exception, e:
+        print e
+    finally:
+        reactor.stop()
+
+
+def main(argv=sys.argv, stderr=sys.stderr):
+    options = DKIMToolOptions()
+    options.parseOptions(argv[1:])
+
+    if options["key-gen"]:
+        _doKeyGeneration(options)
+    elif options["request"]:
+        reactor.callLater(0, _runInReactor, _doRequest, options)
+        reactor.run()
+    elif options["verify"]:
+        reactor.callLater(0, _runInReactor, _doVerify, options)
+        reactor.run()
+    else:
+        usage("Invalid options")
+
+if __name__ == '__main__':
+    main()


Property changes on: CalendarServer/branches/users/cdaboo/ischedule-dkim/calendarserver/tools/dkimtool.py
___________________________________________________________________
Added: svn:executable
   + *

Modified: CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/__init__.py	2012-09-01 00:56:43 UTC (rev 9765)
+++ CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/__init__.py	2012-09-04 15:24:11 UTC (rev 9766)
@@ -14,6 +14,13 @@
 # limitations under the License.
 ##
 
+
 """
 iSchedule scheduling.
 """
+
+from twext.web2 import http_headers
+
+# These new HTTP headers should appear with case-preserved
+hdrs = ("iSchedule-Version", "iSchedule-Message-ID", "DKIM-Signature",)
+http_headers.casemappingify(dict([(i, i) for i in hdrs]))

Modified: CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/dkim.py
===================================================================
--- CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/dkim.py	2012-09-01 00:56:43 UTC (rev 9765)
+++ CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/dkim.py	2012-09-04 15:24:11 UTC (rev 9766)
@@ -20,11 +20,13 @@
 from twext.web2.stream import MemoryStream
 from twisted.internet.defer import inlineCallbacks, returnValue
 import base64
+import binascii
 import collections
 import hashlib
 import rsa
 import textwrap
 import time
+import uuid
 
 """
 DKIM HTTP message generation and validation,
@@ -32,7 +34,20 @@
 
 log = Logger()
 
+# DKIM/iSchedule Constants
+RSA1   = "rsa-sha1"
+RSA256 = "rsa-sha256"
+Q_DNS  = "dns/txt"
+Q_HTTP = "http/well-known"
 
+KEY_SERVICE_TYPE = "ischedule"
+
+# Headers
+DKIM_SIGNATURE = "DKIM-Signature"
+ISCHEDULE_VERSION = "iSchedule-Version"
+ISCHEDULE_VERSION_VALUE = "1.0"
+ISCHEDULE_MESSAGE_ID = "iSchedule-Message-ID"
+
 class DKIMUtils(object):
     """
     Some useful functions.
@@ -44,8 +59,8 @@
         Return hashlib function for DKIM algorithm.
         """
         return {
-            "rsa-sha1"  : hashlib.sha1,
-            "rsa-sha256": hashlib.sha256,
+            RSA1  : hashlib.sha1,
+            RSA256: hashlib.sha256,
         }[algorithm]
     
     @staticmethod
@@ -54,8 +69,8 @@
         Return RSA hash name for DKIM algorithm.
         """
         return {
-            "rsa-sha1"  : "SHA-1",
-            "rsa-sha256": "SHA-256"
+            RSA1  : "SHA-1",
+            RSA256: "SHA-256"
         }[algorithm]
 
 
@@ -95,7 +110,7 @@
         value = " ".join(value.split())
 
         # Special case DKIM-Signature: remove the b= value for signature
-        if remove_b is not None and name == "dkim-signature":
+        if remove_b is not None and name == DKIM_SIGNATURE.lower():
             pos = value.find(remove_b)
             value = value[:pos] + value[pos + len(remove_b):]
             value = " ".join(value.split())
@@ -126,6 +141,34 @@
         useHTTPKey,
         expire,
     ):
+        """
+        Create a DKIM request, which is a regular client request with the additional information needed to sign the message.
+        
+        @param method: HTTP method to use
+        @type method: C{str}
+        @param uri: request-URI
+        @type uri: C{str}
+        @param headers: request headers 
+        @type headers: L{http_headers}
+        @param stream: body data
+        @type stream: L{Stream}
+        @param domain: the signing domain
+        @type domain: C{str}
+        @param selector: the signing key selector
+        @type selector: C{str}
+        @param key_file: path to a private key file
+        @type key_file: C{str}
+        @param algorithm: the signing algorithm to use
+        @type algorithm: C{str}
+        @param sign_headers: list of header names to sign - to "over sign" a header append a "+" to the name
+        @type sign_headers: C{tuple}
+        @param useDNSKey: whether or not to add DNS TXT lookup as a key lookup option
+        @type useDNSKey: C{bool}
+        @param useHTTPKey: whether or not to add HTTP .well-known as a key lookup option
+        @type useHTTPKey: C{bool}
+        @param expire: number of seconds to expiration of signature 
+        @type expire: C{int}
+        """
         super(DKIMRequest, self).__init__(method, uri, headers, stream)
         self.domain = domain
         self.selector = selector
@@ -137,15 +180,17 @@
         
         assert self.domain
         assert self.selector
-        assert self.algorithm in ("rsa-sha1", "rsa-sha256",)
+        assert self.algorithm in (RSA1, RSA256,)
         assert useDNSKey or useHTTPKey
 
         self.hash_method = DKIMUtils.hashlib_method(self.algorithm)
         self.hash_name = DKIMUtils.hash_name(self.algorithm)
         
         self.keyMethods = []
-        if useDNSKey: self.keyMethods.append("dns/txt")
-        if useHTTPKey: self.keyMethods.append("http-well-known")
+        if useDNSKey: self.keyMethods.append(Q_DNS)
+        if useHTTPKey: self.keyMethods.append(Q_HTTP)
+        
+        self.message_id = str(uuid.uuid4())
 
 
     @inlineCallbacks
@@ -164,7 +209,7 @@
         # Complete the header
         dkim_tags[-1] = ("b", signature,)
         dkim_header = "; ".join(["%s=%s" % item for item in dkim_tags])
-        self.headers.addRawHeader("DKIM-Signature", dkim_header)
+        self.headers.addRawHeader(DKIM_SIGNATURE, dkim_header)
         
         log.debug("DKIM: Generated header: DKIM-Signature:%s" % (dkim_header,))
         log.debug("DKIM: Signed headers:\n%s" % (headers,))
@@ -194,14 +239,23 @@
         Generate the headers that are going to be signed as well as the DKIM-Signature tags.
         """
         
+        # Make sure we have the required iSchedule headers
+        self.headers.addRawHeader(ISCHEDULE_VERSION, ISCHEDULE_VERSION_VALUE)
+        self.headers.addRawHeader(ISCHEDULE_MESSAGE_ID, self.message_id)
+        self.sign_headers += (ISCHEDULE_VERSION, ISCHEDULE_MESSAGE_ID,)
+
         # Figure out all the existing headers to sign
         headers = []
         sign_headers = []
-        raw = dict([(name, values) for name, values in self.headers.getAllRawHeaders()])
+        raw = dict([(name.lower(), values) for name, values in self.headers.getAllRawHeaders()])
         for name in self.sign_headers:
-            for value in raw[name]:
+            oversign = name[-1] == "+"
+            name = name.rstrip("+")
+            for value in raw.get(name.lower(), ()):
                 headers.append(DKIMUtils.canonicalizeHeader(name, value))
                 sign_headers.append(name)
+            if oversign:
+                sign_headers.append(name)
 
         # Generate the DKIM header tags we care about
         dkim_tags = []
@@ -212,13 +266,14 @@
         dkim_tags.append(("x", self.expire,))
         dkim_tags.append(("a", self.algorithm,))
         dkim_tags.append(("q", ":".join(self.keyMethods),))
+        dkim_tags.append(("http", base64.encodestring("%s:%s" % (self.method, self.uri,)).strip()))
         dkim_tags.append(("c", "relaxed/simple",))
         dkim_tags.append(("h", ":".join(sign_headers),))
         dkim_tags.append(("bh", (yield self.bodyHash()),))
         dkim_tags.append(("b", "",))
         dkim_header = "; ".join(["%s=%s" % item for item in dkim_tags])
 
-        headers.append(DKIMUtils.canonicalizeHeader("DKIM-Signature", dkim_header))
+        headers.append(DKIMUtils.canonicalizeHeader(DKIM_SIGNATURE, dkim_header))
         headers = "".join(headers)
 
         returnValue((headers, dkim_tags,))
@@ -282,8 +337,9 @@
         try:
             rsa.verify(headers, base64.b64decode(self.dkim_tags["b"]), pubkey)
         except rsa.VerificationError:
-            log.debug("DKIM: Could not verify signature: DKIM-Signature:%s" % (self.request.headers.getRawHeaders("DKIM-Signature"),))
-            raise DKIMVerificationError("Could not verify the DKIM signature")
+            msg = "Could not verify signature"
+            log.debug("DKIM: %s: DKIM-Signature:%s" % (msg, self.request.headers.getRawHeaders(DKIM_SIGNATURE),))
+            raise DKIMVerificationError(msg)
 
         # Do body validation
         data = (yield allDataFromStream(self.request.stream))
@@ -291,8 +347,9 @@
         self.request.stream.doStartReading = None
         bh = base64.b64encode(self.hash_method(data).digest())
         if bh != self.dkim_tags["bh"]:
-            log.debug("DKIM: Could not verify body hash: DKIM-Signature:%s" % (self.request.headers.getRawHeaders("DKIM-Signature"),))
-            raise DKIMVerificationError("Could not verify the DKIM body hash")
+            msg = "Could not verify the DKIM body hash"
+            log.debug("DKIM: %s: DKIM-Signature:%s" % (msg, self.request.headers.getRawHeaders(DKIM_SIGNATURE),))
+            raise DKIMVerificationError(msg)
 
         
     def processDKIMHeader(self):
@@ -303,15 +360,17 @@
         """
         
         # Check presence of header
-        dkim = self.request.headers.getRawHeaders("DKIM-Signature")
+        dkim = self.request.headers.getRawHeaders(DKIM_SIGNATURE)
         if dkim is None:
-            log.debug("DKIM: No DKIM-Signature header present in the request")
-            raise DKIMVerificationError("No DKIM-Signature header present in the request")
+            msg = "No DKIM-Signature header present in the request"
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
         if len(dkim) != 1:
             # TODO: This might need to be changed if we ever support forwarding of iSchedule messages - the forwarder
             # might also sign the message and add its own header
-            log.debug("DKIM: Only one DKIM-Signature allowed in the request")
-            raise DKIMVerificationError("Only one DKIM-Signature allowed in the request")
+            msg = "Only one DKIM-Signature allowed in the request"
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
         dkim = dkim[0]
         log.debug("DKIM: Found header: DKIM-Signature:%s" % (dkim,))
 
@@ -319,17 +378,18 @@
         self.dkim_tags = DKIMUtils.extractTags(dkim)
         
         # Verify validity of tags
-        required_tags = ("v", "a", "b", "bh", "c", "d", "h", "s",)
+        required_tags = ("v", "a", "b", "bh", "c", "d", "h", "s", "http",)
         for tag in required_tags:
             if tag not in self.dkim_tags:
-                log.debug("DKIM: Missing DKIM-Signature tag: %s" % (tag,))
-                raise DKIMVerificationError("Missing DKIM-Signature tag: %s" % (tag,))
+                msg = "Missing DKIM-Signature tag: %s" % (tag,)
+                log.debug("DKIM: " + msg)
+                raise DKIMVerificationError(msg)
 
         check_values = {
             "v": ("1",),
-            "a": ("rsa-sha1", "rsa-sha256",),
+            "a": (RSA1, RSA256,),
             "c": ("relaxed", "relaxed/simple",),
-            "q": ("dns/txt", "http-well-known",),
+            "q": (Q_DNS, Q_HTTP,),
         }
         for tag, values in check_values.items():
             if tag not in required_tags and tag not in self.dkim_tags:
@@ -342,16 +402,41 @@
                 test = (self.dkim_tags[tag],)
             for item in test:
                 if item not in values:
-                    log.debug("DKIM: Tag: %s has incorrect value: %s" % (tag, self.dkim_tags[tag],))
-                    raise DKIMVerificationError("DKIM-Signature tag: %s has incorrect value: %s" % (tag, self.dkim_tags[tag],))
+                    msg = "Tag: %s has incorrect value: %s" % (tag, self.dkim_tags[tag],)
+                    log.debug("DKIM: " + msg)
+                    raise DKIMVerificationError(msg)
 
         # Check expiration
         if "x" in self.dkim_tags:
             diff_time = int(time.time()) - int(self.dkim_tags["x"])
             if diff_time > 0:
-                log.debug("DKIM: Signature expired: %d seconds" % (diff_time,))
-                raise DKIMVerificationError("DKIM-Signature expired: %d seconds" % (diff_time,))
+                msg = "Signature expired: %d seconds" % (diff_time,)
+                log.debug("DKIM: " + msg)
+                raise DKIMVerificationError(msg)
 
+        # Check HTTP method/request-uri
+        try:
+            http_tag = base64.decodestring(self.dkim_tags["http"])
+        except binascii.Error:
+            msg = "Tag: http is not valid base64"
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
+        try:
+            method, uri = http_tag.split(":", 1)
+        except ValueError:
+            msg = "Tag: base64-decoded http is not valid: %s" % (http_tag,)
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
+        if method != self.request.method:
+            msg = "Tag: http method does not match: %s" % (method,)
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
+        if uri != self.request.uri:
+            msg = "Tag: http request-URI does not match: %s" % (uri,)
+            log.debug("DKIM: " + msg)
+            raise DKIMVerificationError(msg)
+            
+
         # Some useful bits
         self.hash_method = DKIMUtils.hashlib_method(self.dkim_tags["a"])
         self.key_methods = self.dkim_tags["q"].split(":")
@@ -371,14 +456,15 @@
         headers = []
         for header in header_list:
             actual_headers = self.request.headers.getRawHeaders(header)
-            try:
-                headers.append((header, actual_headers[header_counter[header]],))
-            except IndexError:
-                pass
+            if actual_headers:
+                try:
+                    headers.append((header, actual_headers[header_counter[header]],))
+                except IndexError:
+                    pass
             header_counter[header] += 1
 
         # DKIM-Signature is always included at the end
-        headers.append(("DKIM-Signature", self.request.headers.getRawHeaders("DKIM-Signature")[0],))
+        headers.append((DKIM_SIGNATURE, self.request.headers.getRawHeaders(DKIM_SIGNATURE)[0],))
 
         # Now canonicalize the values
         return "".join([DKIMUtils.canonicalizeHeader(name, value, remove_b=self.dkim_tags["b"]) for name, value in headers])
@@ -391,7 +477,7 @@
         """
         
         for lookup in self.key_lookup_methods:
-            if lookup.method in self.key_methods:
+            if lookup.method in self.key_methods or lookup.method == "*":
                 pubkey = (yield lookup(self.dkim_tags).getPublicKey())
                 if pubkey is not None:
                     returnValue(pubkey)
@@ -401,7 +487,10 @@
 
 class PublicKeyLookup(object):
     """
-    Abstract base class for public key lookup methods
+    Abstract base class for public key lookup methods.
+    
+    The L{method} attribute indicated the DKIM q= lookup method that the class will support, or if set to "*",
+    the class will handle any q= value.
     """
     
     keyCache = {}
@@ -419,15 +508,15 @@
         @param useCache: whether or not to use the cache
         @type useCache: C{bool}
         """
-        key = self.getSelectorKey()
+        key = self._getSelectorKey()
         if key not in PublicKeyLookup.keyCache or not useCache:
-            pubkeys = (yield self.lookupKeys())
+            pubkeys = (yield self._lookupKeys())
             PublicKeyLookup.keyCache[key] = pubkeys
         
-        returnValue(self.selectKey())
+        returnValue(self._selectKey())
     
     
-    def getSelectorKey(self):
+    def _getSelectorKey(self):
         """
         Get a token used to uniquely identify the key being looked up. Token format will
         depend on the lookup method.
@@ -435,7 +524,7 @@
         raise NotImplementedError
         
     
-    def lookupKeys(self):
+    def _lookupKeys(self):
         """
         Do the key lookup using the actual lookup method. Return a C{list} of C{dict}
         that contains the key tag-list. Return a L{Deferred}.
@@ -443,12 +532,12 @@
         raise NotImplementedError
     
     
-    def selectKey(self):
+    def _selectKey(self):
         """
         Select a specific key from the list that best matches the DKIM-Signature tags
         """
         
-        pubkeys = PublicKeyLookup.keyCache.get(self.getSelectorKey(), [])
+        pubkeys = PublicKeyLookup.keyCache.get(self._getSelectorKey(), [])
         for pkey in pubkeys:
             # Check validity
             if pkey.get("v", "DKIM1") != "DKIM1":
@@ -464,20 +553,20 @@
                 continue
             
             # Service type
-            if pkey.get("s", "ischedule") not in ("*", "ischedule",):
+            if pkey.get("s", KEY_SERVICE_TYPE) not in ("*", KEY_SERVICE_TYPE,):
                 continue
     
             # Non-revoked key
             if len(pkey.get("p", "")) == 0:
                 continue
             
-            return self.makeKey(pkey)
+            return self._makeKey(pkey)
         
-        log.debug("DKIM: No valid public key: %s %s" % (self.getSelectorKey(), pubkeys,))
+        log.debug("DKIM: No valid public key: %s %s" % (self._getSelectorKey(), pubkeys,))
         return None
     
     
-    def makeKey(self, pkey):
+    def _makeKey(self, pkey):
         """
         Turn the key tag list into an actual RSA public key object
 
@@ -504,10 +593,10 @@
 class PublicKeyLookup_DNSTXT(PublicKeyLookup):
     
     
-    method = "dns/txt"
+    method = Q_DNS
 
 
-    def getSelectorKey(self):
+    def _getSelectorKey(self):
         """
         Get a token used to uniquely identify the key being looked up. Token format will
         depend on the lookup method.
@@ -515,7 +604,7 @@
         return "%s._domainkey.%s" % (self.dkim_tags["s"], self.dkim_tags["d"],)
         
     
-    def lookupKeys(self):
+    def _lookupKeys(self):
         """
         Do the key lookup using the actual lookup method.
         """
@@ -526,10 +615,10 @@
 class PublicKeyLookup_HTTP_WellKnown(PublicKeyLookup):
     
     
-    method = "http-well-known"
+    method = Q_HTTP
 
 
-    def getSelectorKey(self):
+    def _getSelectorKey(self):
         """
         Get a token used to uniquely identify the key being looked up. Token format will
         depend on the lookup method.
@@ -537,7 +626,7 @@
         return "https://%s/.well-known/domainkey/%s" % (self.dkim_tags["d"], self.dkim_tags["s"],)
         
     
-    def lookupKeys(self):
+    def _lookupKeys(self):
         """
         Do the key lookup using the actual lookup method.
         """

Modified: CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/test/test_dkim.py
===================================================================
--- CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/test/test_dkim.py	2012-09-01 00:56:43 UTC (rev 9765)
+++ CalendarServer/branches/users/cdaboo/ischedule-dkim/twistedcaldav/scheduling/ischedule/test/test_dkim.py	2012-09-04 15:24:11 UTC (rev 9766)
@@ -35,7 +35,7 @@
         
         keys = []
     
-        def lookupKeys(self):
+        def _lookupKeys(self):
             """
             Do the key lookup using the actual lookup method.
             """
@@ -98,12 +98,6 @@
     L{DKIMRequest} support tests.
     """
 
-    def test_valid_request(self):
-        
-        stream = MemoryStream("")
-        request = DKIMRequest("POST", "/", {}, stream, "example.com", "dkim", "/tmp/key", "rsa-sha1", ("Originator", "Recipient",), True, True, 3600)
-
-        
     @inlineCallbacks
     def test_body_hash(self):
 
@@ -143,7 +137,8 @@
             sign_this = """originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com
 content-type:%s
-dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http-well-known; c=relaxed/simple; h=Originator:Recipient; bh=%s; b=
+ischedule-version:1.0
+dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http/well-known; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient; bh=%s; b=
 """.replace("\n", "\r\n") % (headers.getRawHeaders("Content-Type")[0], str(int(time.time())), str(int(time.time() + 3600)), algorithm, bodyhash)
     
             result = request.generateSignature(sign_this)
@@ -176,8 +171,10 @@
             sign_this = """originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com
 content-type:%s
-dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http-well-known; c=relaxed/simple; h=Originator:Recipient:Content-Type; bh=%s; b=
-""".replace("\n", "\r\n") % (headers.getRawHeaders("Content-Type")[0], request.time, request.expire, algorithm, bodyhash)
+ischedule-version:1.0
+ischedule-message-id:%s
+dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http/well-known; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient:Content-Type:iSchedule-Version:iSchedule-Message-ID; bh=%s; b=
+""".replace("\n", "\r\n") % (headers.getRawHeaders("Content-Type")[0], request.message_id, request.time, request.expire, algorithm, bodyhash)
     
             self.assertEqual(result, sign_this)
 
@@ -203,15 +200,17 @@
             sign_this = """originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com
 content-type:%s
-dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http-well-known; c=relaxed/simple; h=Originator:Recipient:Content-Type; bh=%s; b=
-""".replace("\n", "\r\n") % (headers.getRawHeaders("Content-Type")[0], request.time, request.expire, algorithm, bodyhash)
+ischedule-version:1.0
+ischedule-message-id:%s
+dkim-signature:v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http/well-known; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient:Content-Type:iSchedule-Version:iSchedule-Message-ID; bh=%s; b=
+""".replace("\n", "\r\n") % (headers.getRawHeaders("Content-Type")[0], request.message_id, request.time, request.expire, algorithm, bodyhash)
             key = rsa.PrivateKey.load_pkcs1(open(self.private_keyfile).read())
             signature = base64.b64encode(rsa.sign(sign_this, key, hash_name))
     
             self.assertEqual(result, signature)
             
             # Make sure header is updated in the request
-            updated_header = "v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http-well-known; c=relaxed/simple; h=Originator:Recipient:Content-Type; bh=%s; b=%s" % (request.time, request.expire, algorithm, bodyhash, signature,)
+            updated_header = "v=1; d=example.com; s=dkim; t=%s; x=%s; a=%s; q=dns/txt:http/well-known; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient:Content-Type:iSchedule-Version:iSchedule-Message-ID; bh=%s; b=%s" % (request.time, request.expire, algorithm, bodyhash, signature,)
             self.assertEqual(request.headers.getRawHeaders("DKIM-Signature")[0], updated_header) 
 
             # Try to verify result using public key
@@ -226,7 +225,9 @@
 
     class StubRequest(object):
         
-        def __init__(self, headers, body):
+        def __init__(self, method, uri, headers, body):
+            self.method = method
+            self.uri = uri
             self.headers = Headers()
             for name, value in headers:
                 self.headers.addRawHeader(name, value)
@@ -244,25 +245,28 @@
             
             # More than one
             ((
-                ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http-well-known; c=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=relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),
+                ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; http=UE9TVDov; c=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; http=UE9TVDov; c=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=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=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=relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() + 30),)),), True,),
+            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; http=UE9TVDov; c=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; http=UE9TVDov; c=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; http=UE9TVDov; c=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=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=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=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=relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,),
+            ((("DKIM-Signature", "v=2; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; http=UE9TVDov; c=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; http=UE9TVDov; c=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; http=UE9TVDov; c=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; http=UE9TVDov; c=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; http=UE9TVDov; c=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=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; http=UE9TVDovaXNjaGVkdWxl; c=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; http=POST:/; c=relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,),
         )
         
         for headers, result in data:
-            request = self.StubRequest(headers, "")
+            request = self.StubRequest("POST", "/", headers, "")
             verifier = DKIMVerifier(request)
             if result:
                 verifier.processDKIMHeader()
@@ -279,20 +283,21 @@
             ("Content-Type", " text/calendar  ; charset =  \"utf-8\"  ", "content-type:text/calendar ; charset = \"utf-8\"\r\n"),
             ("Originator", "  mailto:user01 at example.com  ", "originator:mailto:user01 at example.com\r\n"),
             ("Recipient", "  mailto:user02 at example.com  ,\t mailto:user03 at example.com\t\t  ", "recipient:mailto:user02 at example.com , mailto:user03 at example.com\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=relaxed/simple; h=Originator:Recipient; bh=abc; b=def",
-                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Originator:Recipient; bh=abc; b=\r\n",
+                "  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def",
+                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=\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; b= def ; c=relaxed/simple; h=Originator:Recipient; bh=abc",
-                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; b= ; c=relaxed/simple; h=Originator:Recipient; bh=abc\r\n",
+                "  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 ; http=\tUE9TVDov   ; c=relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc",
+                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; b= ; http= UE9TVDov ; c=relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc\r\n",
             ),
         )
         
         for name, value, result in data:
-            request = self.StubRequest(((name, value,),), "")
+            request = self.StubRequest("POST", "/", ((name, value,),), "")
             verifier = DKIMVerifier(request)
             if name == "DKIM-Signature":
                 verifier.processDKIMHeader()
@@ -311,14 +316,16 @@
 Content-Type: text/calendar  ; charset =  "utf-8"  
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient: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:user01 at example.com
 recipient:mailto:user02 at example.com , mailto:user03 at example.com
-dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=
+ischedule-version:1.0
+dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=
 """
             ),
             # Exact count on Recipient
@@ -327,7 +334,8 @@
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\t\t  
 Recipient:\t\t  mailto:user04 at example.com  
-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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Cache-Control:no-cache
 Connection:close
 """,
@@ -335,17 +343,19 @@
 originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com , mailto:user03 at example.com
 recipient:mailto:user04 at example.com
-dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=
+ischedule-version:1.0
+dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=
 """
             ),
             # Under count on Recipient
             ("""Host:example.com
 Content-Type: text/calendar  ; charset =  "utf-8"  
+iSchedule-Version: 1.0
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\t\t  
 Recipient:\t\t  mailto:user04 at example.com  
 Recipient:\t\t  mailto:user05 at example.com  
-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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Cache-Control:no-cache
 Connection:close
 """,
@@ -353,14 +363,16 @@
 originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com , mailto:user03 at example.com
 recipient:mailto:user04 at example.com
-dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=
+ischedule-version:1.0
+dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=
 """
             ),
             # Re-ordered Content-Type
             ("""Host:example.com
+iSchedule-Version: 1.0
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Content-Type: text/calendar  ; charset =  "utf-8"  
 Cache-Control:no-cache
 Connection:close
@@ -368,14 +380,15 @@
             """content-type:text/calendar ; charset = "utf-8"
 originator:mailto:user01 at example.com
 recipient:mailto:user02 at example.com , mailto:user03 at example.com
-dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=
+ischedule-version:1.0
+dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=
 """
             ),
         )
         
         for hdrs, result in data:
             headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
-            request = self.StubRequest(headers, "")
+            request = self.StubRequest("POST", "/", headers, "")
             verifier = DKIMVerifier(request)
             verifier.processDKIMHeader()
             extracted = verifier.extractSignedHeaders()
@@ -393,7 +406,7 @@
 Content-Type: text/calendar  ; charset =  "utf-8"  
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Cache-Control:no-cache
 Connection:close
 """,
@@ -405,7 +418,7 @@
 Content-Type: text/calendar  ; charset =  "utf-8"  
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt\t\t; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Cache-Control:no-cache
 Connection:close
 """,
@@ -417,7 +430,7 @@
 Content-Type: text/calendar  ; charset =  "utf-8"  
 Originator:  mailto:user01 at example.com  
 Recipient:  mailto:user02 at example.com  ,\t mailto:user03 at example.com\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=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b=def
+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; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
 Cache-Control:no-cache
 Connection:close
 """,
@@ -428,7 +441,7 @@
         
         for hdrs, keys, result in data:
             headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
-            request = self.StubRequest(headers, "")
+            request = self.StubRequest("POST", "/", headers, "")
             TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys
             verifier = DKIMVerifier(request, key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,))
             verifier.processDKIMHeader()
@@ -621,16 +634,16 @@
             (PublicKeyLookup_DNSTXT, "dkim._domainkey.example.com"),
             (PublicKeyLookup_HTTP_WellKnown, "https://example.com/.well-known/domainkey/dkim")
         ):
-            dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+            dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
             tester = lookup(DKIMUtils.extractTags(dkim))
-            self.assertEqual(tester.getSelectorKey(), result)
+            self.assertEqual(tester._getSelectorKey(), result)
             
     
     @inlineCallbacks
     def test_get_key(self):
         
         # Valid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))]
@@ -638,7 +651,7 @@
         self.assertNotEqual(pubkey, None)
         
         # Valid with more tags
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=ischedule ; p=%s" % (self.public_key_data,))]
@@ -646,7 +659,7 @@
         self.assertNotEqual(pubkey, None)
         
         # Invalid - key type
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=dsa ; p=%s" % (self.public_key_data,))]
@@ -654,7 +667,7 @@
         self.assertEqual(pubkey, None)
         
         # Invalid - hash
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; h=sha512 ; p=%s" % (self.public_key_data,))]
@@ -662,7 +675,7 @@
         self.assertEqual(pubkey, None)
         
         # Invalid - service
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p=%s" % (self.public_key_data,))]
@@ -670,7 +683,7 @@
         self.assertEqual(pubkey, None)
         
         # Invalid - revoked
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p=")]
@@ -678,7 +691,7 @@
         self.assertEqual(pubkey, None)
         
         # Multiple valid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [
@@ -690,7 +703,7 @@
         self.assertNotEqual(pubkey, None)
         
         # Multiple - some valid, some invalid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [
@@ -703,7 +716,7 @@
         self.assertNotEqual(pubkey, None)
         
         # Multiple - invalid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [
@@ -718,7 +731,7 @@
     def test_cached_key(self):
         
         # Create cache entry
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))]
@@ -726,14 +739,14 @@
         self.assertNotEqual(pubkey, None)
         
         # Cache valid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.keys = []
         pubkey = (yield lookup.getPublicKey())
         self.assertNotEqual(pubkey, None)
         
         # Cache invalid
-        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http-well-known ; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient; bh=abc; b="
+        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
         lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
         lookup.flushCache()
         lookup.keys = []
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120904/e6e7f78a/attachment-0001.html>


More information about the calendarserver-changes mailing list