added some comments
authorScott Baker <bakers@cs.arizona.edu>
Tue, 5 Aug 2008 17:36:01 +0000 (17:36 +0000)
committerScott Baker <bakers@cs.arizona.edu>
Tue, 5 Aug 2008 17:36:01 +0000 (17:36 +0000)
util/cert.py
util/credential.py
util/gid.py
util/rights.py

index 86700e8..10be601 100644 (file)
@@ -1,16 +1,32 @@
+# cert.py
+#
+# a general purpose class for dealing with certificates
+#
+# this class serves as an interface between a lower-level X.509 certificate
+# library such as pyOpenSSL or M2Crypto. Currently both of these libraries
+# are being used due to lack of functionality in pyOpenSSL and some apparant
+# bugs in M2Crypto
+
 from OpenSSL import crypto
 import M2Crypto
 from M2Crypto import X509
 from M2Crypto import EVP
 
+# Keypair
+#
+# represents a private/public key pair, or a public key
+
 class Keypair:
    key = None       # public/private keypair
    m2key = None     # public key (m2crypto format)
 
-   def __init__(self, create=False):
+   def __init__(self, create=False, string=None, filename=None):
       if create:
          self.create()
-      pass
+      if string:
+         self.load_from_string(string)
+      if filename:
+         self.load_from_file(filename)
 
    def create(self):
       self.key = crypto.PKey()
@@ -38,6 +54,19 @@ class Keypair:
    def get_openssl_pkey(self):
       return self.key
 
+   def is_same(self, pkey):
+      return self.as_pem() == pkey.as_pem()
+
+# Certificate
+#
+# Represents an X.509 certificate. Support is included for a list of
+# certificates by use of a "parent" member. See load_from_string() and
+# save_to_string() for insight into how a recursive chain of certs is
+# serialized.
+#
+# Certificates support an application-defined "data" field, which is
+# stored in the subjectAltName field of the X.509 certificate.
+
 class Certificate:
    digest = "md5"
 
@@ -63,12 +92,15 @@ class Certificate:
        self.cert.gmtime_adj_notBefore(0)
        self.cert.gmtime_adj_notAfter(60*60*24*365*5) # five years
 
+   def load_from_pyopenssl_x509(self, x509):
+       self.cert = x509
+
    def load_from_string(self, string):
        # if it is a chain of multiple certs, then split off the first one and
        # load it
        parts = string.split("-----parent-----", 1)
        self.cert = crypto.load_certificate(crypto.FILETYPE_PEM, parts[0])
-       
+
        # if there are more certs, then create a parent and let the parent load
        # itself from the remainder of the string
        if len(parts) > 1:
@@ -147,7 +179,7 @@ class Certificate:
        self.cert.add_extensions([ext])
 
    def get_extension(self, name):
-       # pyOpenSSL does not have a way to get certificates
+       # pyOpenSSL does not have a way to get extensions
        m2x509 = X509.load_cert_string(self.save_to_string())
        value = m2x509.get_ext(name).get_value()
        return value
@@ -196,6 +228,9 @@ class Certificate:
        # except:
        #   return 0
 
+   def is_pubkey(self, pkey):
+       return self.get_pubkey().is_same(pkey)
+
    def is_signed_by_cert(self, cert):
        k = cert.get_pubkey()
        result = self.verify(k)
@@ -208,8 +243,15 @@ class Certificate:
         return self.parent
 
    def verify_chain(self, trusted_certs = None):
+        # Verify a chain of certificates. Each certificate must be signed by
+        # the public key contained in it's parent. The chain is recursed
+        # until a certificate is found that is signed by a trusted root.
+
+        # TODO: verify expiration time
+
         # if this cert is signed by a trusted_cert, then we are set
         for trusted_cert in trusted_certs:
+            # TODO: verify expiration of trusted_cert ?
             if self.is_signed_by_cert(trusted_cert):
                 #print self.get_subject(), "is signed by a root"
                 return True
index 1353f8a..f5016f0 100644 (file)
@@ -1,3 +1,10 @@
+# credential.py
+#
+# implements GENI credentials
+#
+# Credentials are layered on top of certificates, and are essentially a
+# certificate that stores a tuple of parameters.
+
 from cert import *
 from rights import *
 from gid import *
@@ -5,6 +12,10 @@ import xmlrpclib
 
 # Credential is a tuple:
 #     (GIDCaller, GIDObject, LifeTime, Privileges, Delegate)
+#
+# These fields are encoded using xmlrpc into the subjectAltName field of the
+# x509 certificate. Note: Call encode() once the fields have been filled in
+# to perform this encoding.
 
 class Credential(Certificate):
     uuid = None
index 510e849..3f449c6 100644 (file)
@@ -1,3 +1,7 @@
+# gid.py
+#
+# implements GENI GID
+
 from cert import *
 import uuid
 import xmlrpclib
@@ -47,9 +51,21 @@ class GID(Certificate):
             dict = xmlrpclib.loads(self.get_data())[0][0]
         else:
             dict = {}
-            
+
         self.uuid = dict.get("uuid", None)
         self.hrn = dict.get("hrn", None)
 
+    # XXX: I may have decided not to use this
+    def get_cache_key(self):
+        return self.get_cache_uuid() + self.get_cache_name()
+
+    # XXX: I may have decided not to use this
+    def get_cache_uuid(self):
+        return self.get_uuid()
+
+    # XXX: I may have decided not to use this
+    def get_cache_name(self):
+        return self.get_name()
+
 
 
index 382fb2f..b66c35e 100644 (file)
@@ -1,3 +1,11 @@
+# rights.py
+#
+# support for privileges according to GENI specification
+
+# privilege_table:
+#
+# a list of priviliges and what operations are allowed per privilege
+
 privilege_table = {"authority": ["*"],
                    "refresh": ["remove", "update"],
                    "resolve": ["resolve", "list", "getcredential"],
@@ -8,6 +16,8 @@ privilege_table = {"authority": ["*"],
                    "info": ["listslices", "listcomponentresources", "getsliceresources"],
                    "ma": ["*"]}
 
+# a "Right" is a single privilege.
+
 class Right:
    def __init__(self, kind):
       self.kind = kind
@@ -23,6 +33,8 @@ class Right:
 
       return (op_name.lower() in allowed_ops)
 
+# a "RightList" is a list of privileges
+
 class RightList:
     def __init__(self, string=None):
         self.rights = []