import repository from arizona
[raven.git] / lib / ravenlib / crypto.py
1 import base64
2 import binascii
3 import hashlib
4 import os
5 import time
6 import xml.sax.saxutils
7
8 from sfa.trust.certificate import Certificate, Keypair
9
10 """ XXX NOTE: This file depends on SFA, so anything that uses this module will
11       also depend on SFA.
12
13         NOTE2: put non-SFA stuff somewhere else, like hash.py
14 """
15
16 def get_cert_file(key_file):
17    """ Given a the filename of a key file, try to open a cert file in the same
18        directory. If the cert file doesn't exist, then create one. This is
19        basically a helper for GeniServer/GeniClient classed from Geniwrapper,
20        but is probably obsolete now that we're using modpythonapi.
21    """
22
23    file = key_file + ".cert"
24    if (os.path.isfile(file)):
25       return file
26    else:
27       k = Keypair(filename = key_file)
28       user = os.path.basename(key_file)
29       cert = Certificate(subject=user)
30       cert.set_pubkey(k)
31       cert.set_issuer(k, user)
32       cert.sign()
33       cert.save_to_file(file)
34       return file
35
36 def keypair_to_stork_pubkey_string(k):
37    """ convert a geniwrapper private or public key into a stork public key
38        string.
39    """
40
41    keyString = k.get_pubkey_string()
42    return keyString
43
44 def keypair_to_stork_keyhash(k):
45    """ convert a geniwrapper private or public key into a stork keyhash
46    """
47
48    keyString = k.get_pubkey_string()
49    keyHash = hashlib.sha1(base64.decodestring(keyString)).hexdigest()
50    return keyHash
51
52 def compute_protected_data(src, attrs):
53    """ Creates a protected data block for a stork-style XML wrapper.
54    """
55
56    timeStamp = attrs.get("timestamp", int(time.time()))
57    duration = attrs.get("duration", 0)
58
59    protectedData = '   <HEADER TIMESTAMP="' + str(timeStamp) + '" DURATION="' + \
60                    str(duration) + '"'
61
62    if "prefix" in attrs:
63        protectedData += ' PREFIX="' + attrs["prefix"] + '"'
64
65    if "suffix" in attrs:
66        protectedData += ' SUFFIX="' + attrs["suffix"] + '"'
67
68    protectedData += '/>\n'
69
70    protectedData += '   <FILE ENCODING="escaped">'
71    protectedData += src
72    protectedData += '</FILE>\n\n'
73
74    return protectedData
75
76 def xmlsignstring(key, src, attrs={}):
77    """ Stork-compatible XML signature wrapper.
78        Using private key, encode the source data and wrap an xml
79        signature block around it.
80    """
81
82    # escape the source data so it doesn't contain XML tags or special chars
83    src = xml.sax.saxutils.escape(src)
84    protectedData = compute_protected_data(src, attrs)
85
86    hash = binascii.b2a_hex(base64.b64decode(key.sign_string(protectedData)))
87
88    dest = '<?xml version="1.0" encoding="ISO-8859-1"  standalone="yes" ?>\n\n'
89    dest += '<SIGNED_FILE SIGNEDHASH="' + hash + \
90            '" PUBLICKEY="' + key.get_pubkey_string() + \
91            '" SIGNATURE_ALGORITHM="-sha1">\n'
92    dest += protectedData
93    dest += '</SIGNED_FILE>\n'
94
95    return dest
96
97 def xmlsignfile(key, srcFn, destFn, attrs={}):
98    """ Using private key, encode the source file, wrap an XML signature block
99        around it, and write it to destFn.
100    """
101
102    srcData = open(srcFn, "r").read()
103
104    destData = xmlsignstring(key, srcData, attrs)
105
106    open(destFn, "w").write(destData)
107
108 def xmlsignfile_to_dir(key, srcFn, destDir, attrs={}):
109    """ Using private key, encode the source file, wrap an XML signature block
110        around it, and write it to the same base filename, but in the destDir
111        directory.
112    """
113
114    keyhash = keypair_to_stork_keyhash(key)
115    basename = os.path.basename(srcFn).split(".")[0]
116    ext = ".".join(os.path.basename(srcFn).split(".")[1:])
117    destFn = os.path.join(destDir, basename + "." + keyhash + "." + ext)
118    xmlsignfile(key, srcFn, destFn, attrs)