import repository from arizona
[raven.git] / apps / ravenpublish / crypto.py
1 import base64
2 import binascii
3 import os
4 import sha
5 import time
6 import xml.sax.saxutils
7
8 from sfa.trust.certificate import Certificate, Keypair
9
10 def get_cert_file(key_file):
11    """ Given a the filename of a key file, try to open a cert file in the same
12        directory. If the cert file doesn't exist, then create one. This is
13        basically a helper for GeniServer/GeniClient classed from Geniwrapper,
14        but is probably obsolete now that we're using modpythonapi.
15    """
16
17    file = key_file + ".cert"
18    if (os.path.isfile(file)):
19       return file
20    else:
21       k = Keypair(filename = key_file)
22       user = os.path.basename(key_file)
23       cert = Certificate(subject=user)
24       cert.set_pubkey(k)
25       cert.set_issuer(k, user)
26       cert.sign()
27       cert.save_to_file(file)
28       return file
29
30 def get_file_hash(fn):
31     """ get the SHA-1 hash of a file
32     """
33
34     return sha.new(open(fn,"rb").read()).hexdigest()
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 = sha.new(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)