From: Scott Baker Date: Tue, 5 Aug 2008 17:36:01 +0000 (+0000) Subject: added some comments X-Git-Tag: sfa-0.9-0@14641~871 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=56a6c02d74af3cc4f61256a7d279357dede6a6ee;p=sfa.git added some comments --- diff --git a/util/cert.py b/util/cert.py index 86700e83..10be6013 100644 --- a/util/cert.py +++ b/util/cert.py @@ -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 diff --git a/util/credential.py b/util/credential.py index 1353f8ab..f5016f0e 100644 --- a/util/credential.py +++ b/util/credential.py @@ -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 diff --git a/util/gid.py b/util/gid.py index 510e849e..3f449c69 100644 --- a/util/gid.py +++ b/util/gid.py @@ -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() + diff --git a/util/rights.py b/util/rights.py index 382fb2f1..b66c35ee 100644 --- a/util/rights.py +++ b/util/rights.py @@ -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 = []