aboutsummaryrefslogtreecommitdiff
path: root/pow/POW-0.7/lib/pkix.py
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2007-07-07 17:04:37 +0000
committerRob Austein <sra@hactrn.net>2007-07-07 17:04:37 +0000
commited43d040bf72c2b8eb9d2cec3444556761b3c606 (patch)
tree57d47ba90cd2c6672f32f0a514c47058e23e3f90 /pow/POW-0.7/lib/pkix.py
parent2d5c53975e6ddaec9ac3d49a70278fcdd584273d (diff)
Add pow
svn path=/pow/POW-0.7/PKG-INFO; revision=722
Diffstat (limited to 'pow/POW-0.7/lib/pkix.py')
-rwxr-xr-xpow/POW-0.7/lib/pkix.py1685
1 files changed, 1685 insertions, 0 deletions
diff --git a/pow/POW-0.7/lib/pkix.py b/pow/POW-0.7/lib/pkix.py
new file mode 100755
index 00000000..9d2b7ca5
--- /dev/null
+++ b/pow/POW-0.7/lib/pkix.py
@@ -0,0 +1,1685 @@
+#*****************************************************************************#
+#* *#
+#* Copyright (c) 2002, Peter Shannon *#
+#* All rights reserved. *#
+#* *#
+#* Redistribution and use in source and binary forms, with or without *#
+#* modification, are permitted provided that the following conditions *#
+#* are met: *#
+#* *#
+#* * Redistributions of source code must retain the above *#
+#* copyright notice, this list of conditions and the following *#
+#* disclaimer. *#
+#* *#
+#* * Redistributions in binary form must reproduce the above *#
+#* copyright notice, this list of conditions and the following *#
+#* disclaimer in the documentation and/or other materials *#
+#* provided with the distribution. *#
+#* *#
+#* * The name of the contributors may be used to endorse or promote *#
+#* products derived from this software without specific prior *#
+#* written permission. *#
+#* *#
+#* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *#
+#* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *#
+#* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *#
+#* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS *#
+#* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *#
+#* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *#
+#* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *#
+#* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *#
+#* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *#
+#* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *#
+#* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *#
+#* *#
+#*****************************************************************************#
+
+import types, time, pprint, cStringIO, POW, _der
+from _simpledb import OidData as _OidData
+from _der import *
+
+DEBUG = 0
+
+_oidData = _OidData()
+obj2oid = _oidData.obj2oid
+oid2obj = _oidData.oid2obj
+
+_fragments = []
+
+def _docset():
+ return _der._docset() + _fragments
+
+def _addFragment(frag):
+ global _fragments
+ _fragments.append(frag)
+
+_addFragment('''
+<modulefunction>
+ <header>
+ <name>utc2time</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This is a helper function for turning a UTCTime string into an
+ integer. It isn't built into the encoder since the various
+ functions which are used to manipulate the tm structure are
+ notoriously unreliable.
+ </para>
+ </body>
+</modulefunction>
+''')
+def utc2time(val):
+ 'der encoded value not including tag or length'
+ if not isinstance(val, types.StringType):
+ raise DerError, 'argument should be a string'
+ t = time.strptime(val, '%y%m%d%H%M%SZ')
+ return int(time.mktime(t))
+
+_addFragment('''
+<modulefunction>
+ <header>
+ <name>time2utc</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This is a helper function for turning an integer into a
+ UTCTime string. It isn't built into the encoder since the
+ various functions which are used to manipulate the tm structure
+ are notoriously unreliable.
+ </para>
+ </body>
+</modulefunction>
+''')
+def time2utc(val):
+ 'numerical time value like time_t'
+ val = int(val)
+ t = time.gmtime(val)
+ return time.strftime('%y%m%d%H%M%SZ', t)
+
+_addFragment('''
+<modulefunction>
+ <header>
+ <name>gen2time</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This is a helper function for turning a GeneralizedTime string into an
+ integer. It isn't built into the encoder since the various
+ functions which are used to manipulate the tm structure are
+ notoriously unreliable.
+ </para>
+ </body>
+</modulefunction>
+''')
+def gen2Time(val):
+ 'der encoded value not including tag or length'
+ if not isinstance(val, types.StringType):
+ raise DerError, 'argument should be a string'
+ t = time.strptime(val, '%Y%m%d%H%M%SZ')
+ return int(time.mktime(t))
+
+_addFragment('''
+<modulefunction>
+ <header>
+ <name>time2gen</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This is a helper function for turning an integer into a
+ GeneralizedTime string. It isn't built into the encoder since the
+ various functions which are used to manipulate the tm structure
+ are notoriously unreliable.
+ </para>
+ </body>
+</modulefunction>
+''')
+def time2gen(val):
+ 'numerical time value like time_t'
+ val = int(val)
+ t = time.gmtime(val)
+ return time.strftime('%Y%m%d%H%M%SZ', t)
+
+_addFragment('''
+<method>
+ <header>
+ <name>ip42oct</name>
+ <parameter>ip</parameter>
+ </header>
+ <body>
+ <para>
+ <parameter>ip</parameter> should be a list or tuple of integers,
+ from 0 to 256.
+ </para>
+ <example>
+ <title>Setting <classname>IpAddress</classname></title>
+ <programlisting>
+ ip = IpAddress()
+ ip.set( ip42oct(192, 168, 0, 231) )
+ </programlisting>
+ </example>
+ </body>
+</method>
+''')
+def ip42oct(val0, val1, val2, val3):
+ return chr(val0) + chr(val1) + chr(val2) + chr(val3)
+
+_addFragment('''
+<method>
+ <header>
+ <name>oct2ip4</name>
+ <parameter>val</parameter>
+ </header>
+ <body>
+ <para>
+ Returns a tuple of 4 integers, from 0 to 256.
+ </para>
+ </body>
+</method>
+''')
+def oct2ip4(val):
+ if not isinstance(val, types.StringType) or len(val) != 4:
+ raise DerError, 'parameter should be string of 4 characters'
+ return ( ord(val[0]), ord(val[1]), ord(val[2]), ord(val[3]) )
+
+#---------- certificate support ----------#
+class TbsCertificate(Sequence):
+ def __init__(self, optional=0, default=''):
+
+ self.version = Integer()
+ self.explicitVersion = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.version, 0, 'oAMCAQA=\n' )
+
+ self.serial = Integer()
+ self.signature = AlgorithmIdentifier()
+ self.issuer = Name()
+ self.subject = Name()
+ self.subjectPublicKeyInfo = SubjectPublicKeyInfo()
+
+ self.validity = Validity()
+
+ self.issuerUniqueID = BitString(1)
+ self.issuerUniqueID.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 1 )
+ self.subjectUniqueID = BitString(1)
+ self.subjectUniqueID.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 2 )
+
+ self.extensions = Extensions()
+ self.explicitExtensions = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 3, self.extensions, 1 )
+
+ contents = [
+ self.explicitVersion,
+ self.serial,
+ self.signature,
+ self.issuer,
+ self.validity,
+ self.subject,
+ self.subjectPublicKeyInfo,
+ self.issuerUniqueID,
+ self.subjectUniqueID,
+ self.explicitExtensions
+ ]
+
+ Sequence.__init__(self, contents, optional, default)
+
+class Validity(Sequence):
+ def __init__(self, optional=0, default=''):
+ Time = lambda : Choice({ 'generalTime' : GeneralizedTime(), 'utcTime' : UtcTime() })
+ self.notBefore = Time()
+ self.notAfter = Time()
+ contents = [self.notBefore, self.notAfter]
+ Sequence.__init__(self, contents, optional, default)
+
+class DirectoryString(Choice):
+ def __init__(self, optional=0, default=''):
+ choices = { 'teletexString' : T61String(),
+ 'printableString' : PrintableString(),
+ 'universalString' : UniversalString(),
+ 'bmpString' : BmpString(),
+ 'utf8String' : Utf8String() }
+
+ Choice.__init__(self, choices, optional, default)
+
+class AttributeTypeAndValue(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.type = Oid()
+ self.dirstr = DirectoryString()
+ contents = [ self.type, self.dirstr ]
+ Sequence.__init__(self, contents, optional, default)
+
+class RelativeDistinguishedName(SetOf):
+ def __init__(self, optional=0, default=''):
+ SetOf.__init__(self, AttributeTypeAndValue, optional, default)
+
+class Name(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, RelativeDistinguishedName, optional, default)
+
+class AlgorithmIdentifier(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.algorithm = Oid()
+ self.parameters = Null()
+ contents = [self.algorithm, self.parameters]
+ Sequence.__init__(self, contents, optional, default)
+
+class SubjectPublicKeyInfo(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.algorithmId = AlgorithmIdentifier()
+ self.subjectPublicKey = AltBitString()
+ contents = [ self.algorithmId, self.subjectPublicKey ]
+ Sequence.__init__(self, contents, optional, default)
+
+class Extensions(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, Extension, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>Certificate</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <example>
+ <title>Setting <classname>Certificate</classname></title>
+ <programlisting>
+ rsa = POW.Asymmetric()
+ cert = POW.pkix.Certificate()
+ cert.setVersion(1)
+ cert.setSerial(5)
+
+ name = ( (( o2i('countryName'), ('printableString', 'GB') ),),
+ (( o2i('stateOrProvinceName'), ('printableString', 'Hertfordshire') ),),
+ (( o2i('organizationName'), ('printableString', 'The House') ),),
+ (( o2i('commonName'), ('printableString', 'Client') ),) )
+
+ cert.setIssuer(name)
+ cert.setSubject(name)
+
+ now = POW.pkix.time2gen( time.time() )
+ then = POW.pkix.time2gen(time.time() + 60*60*24*365*12)
+ cert.setNotBefore( ('generalTime', now) )
+ cert.setNotAfter( ( 'generalTime', then) )
+ cert.setIssuerUniqueID((1,0,1,0))
+ cert.setSubjectUniqueID((1,0,0,1))
+ cert.sign(rsa, POW.MD5_DIGEST)
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+
+class Certificate(Sequence):
+
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>Certificate</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ self.tbs = TbsCertificate()
+ self.signatureAlgorithm = AlgorithmIdentifier()
+ self.signatureValue = AltBitString()
+ contents = [ self.tbs, self.signatureAlgorithm, self.signatureValue ]
+ Sequence.__init__(self, contents, optional, default)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setVersion</name>
+ <parameter>version</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Integer</classname> object. 0
+ indicates a version 1 certificate, 1 a version 2 certificate and 2 a
+ version 3 certificate.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setVersion(self, version):
+ self.tbs.version.set(version)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getVersion</name>
+ </header>
+ <body>
+ <para>
+ This function returns whatever the version object is set to,
+ this should be 0, 1 or 2.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getVersion(self):
+ return self.tbs.version.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setSerial</name>
+ <parameter>serial</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Integer</classname> object.
+ No two certificates issued should ever have the same serial
+ number.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setSerial(self, serial):
+ self.tbs.serial.set(serial)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getVersion</name>
+ </header>
+ <body>
+ <para>
+ This function returns whatever the serial object is set to.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getSerial(self):
+ return self.tbs.serial.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setIssuer</name>
+ <parameter>names</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Name</classname> object.
+ See <classname>Certificate</classname> class for an example.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setIssuer(self, issuer):
+ self.tbs.issuer.set(issuer)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getIssuer</name>
+ </header>
+ <body>
+ <para>
+ This function returns a complex tuple containing other tuples.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getIssuer(self):
+ return self.tbs.issuer.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setSubject</name>
+ <parameter>names</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Name</classname> object.
+ See <classname>Certificate</classname> class for an example.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setSubject(self, subject):
+ self.tbs.subject.set(subject)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getSubject</name>
+ </header>
+ <body>
+ <para>
+ This function returns a complex tuple containing other tuples.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getSubject(self):
+ return self.tbs.subject.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setNotBefore</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets a <classname>Choice</classname> object.
+ It can be either a <classname>GeneralTime</classname> or
+ <classname>UTCTime</classname> object. The functions
+ <function>gen2time</function>, <function>utc2time</function>,
+ <function>time2gen</function> and <function>time2utc</function>
+ can be used to convert to and from integer times and their
+ string representation.
+ </para>
+ <example>
+ <title><function>setNotBefore</function> method usage</title>
+ <programlisting>
+ cert = POW.pkix.Certificate()
+ now = POW.pkix.time2gen( time.time() )
+ cert.setNotBefore( ('generalTime', now) )
+ </programlisting>
+ </example>
+ </body>
+ </method>
+ ''')
+ def setNotBefore(self, nb):
+ self.tbs.validity.notBefore.set(nb)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getNotBefore</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple indicating which type of time was
+ stored and its value. See <function>setNotBefore</function> for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getNotBefore(self):
+ return self.tbs.validity.notBefore.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setNotAfter</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets a <classname>Choice</classname> object.
+ See <function>setNotBefore</function> for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setNotAfter(self, na):
+ self.tbs.validity.notAfter.set(na)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getNotAfter</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple indicating which type of time was
+ stored and its value. See <function>setNotBefore</function> for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getNotAfter(self):
+ return self.tbs.validity.notAfter.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setIssuerUniqueID</name>
+ <parameter>id</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets a <classname>BitString</classname> object.
+ This is part of the X509v2 standard and is quite poorly
+ regarded in general, its use is not recommended. It is set
+ using the normal <classname>BitString</classname> method, that
+ is with a sequence of true/false objects.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setIssuerUniqueID(self, id):
+ self.tbs.issuerUniqueID.set(id)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getIssuerUniqueID</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple of integers, 1 or 0.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getIssuerUniqueID(self):
+ return self.tbs.issuerUniqueID.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setSubjectUniqueID</name>
+ <parameter>id</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets a <classname>BitString</classname> object.
+ This is part of the X509v2 standard and is quite poorly
+ regarded in general, its use is not recommended. It is set
+ using the normal <classname>BitString</classname> method, that
+ is with a sequence of true/false objects.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setSubjectUniqueID(self, id):
+ self.tbs.subjectUniqueID.set(id)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getSubjectUniqueID</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple of integers, 1 or 0.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getSubjectUniqueID(self):
+ return self.tbs.subjectUniqueID.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>setExtensions</name>
+ <parameter>extns</parameter>
+ </header>
+ <body>
+ <para>
+ This method sets an <classname>Extensions</classname> object,
+ defined as SEQUENCE OF Extension. The parameter
+ <parameter>extns</parameter> should consist of a list or tuple
+ of values suitable to set an extension. See the extension
+ class for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setExtensions(self, extns):
+ self.tbs.extensions.set(extns)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>getExtensions</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple of
+ <classname>Extension</classname> values. See
+ <classname>Extension</classname> for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getExtensions(self):
+ return self.tbs.extensions.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>sign</name>
+ <parameter>rsa</parameter>
+ <parameter>digestType</parameter>
+ </header>
+ <body>
+ <para>
+ This function updates structured of the
+ <classname>Certificate</classname> and
+ <constant>tbs</constant> as appropriate and performs the
+ specified digest on the <constant>tbs</constant> and set
+ <constant>signedText</constant> to signed the digest.
+ </para>
+ </body>
+ </method>
+ ''')
+ def sign(self, rsa, digestType):
+ signatureMap = { POW.MD2_DIGEST : (1, 2, 840, 113549, 1, 1, 2), # md2WithRSAEncryption
+ POW.MD5_DIGEST : (1, 2, 840, 113549, 1, 1, 4), # md5WithRSAEncryption
+ POW.SHA_DIGEST : (1, 3, 14, 3, 2, 15), # shaWithRSAEncryption
+ POW.SHA1_DIGEST : (1, 2, 840, 113549, 1, 1, 5), # sha1withRSAEncryption
+ POW.RIPEMD160_DIGEST : (1, 2, 840, 113549, 1, 1, 6) } # ripemd160WithRSAEncryption
+
+ self.tbs.subjectPublicKeyInfo.set( (((1, 2, 840, 113549, 1, 1, 1), None), rsa.derWrite(POW.RSA_PUBLIC_KEY) ) )
+ self.tbs.signature.set( [signatureMap[digestType], None] )
+ digest = POW.Digest(digestType)
+ digest.update( self.tbs.toString() )
+ signedText = rsa.sign( digest.digest(), digestType )
+ self.signatureAlgorithm.set( [signatureMap[digestType], None] )
+ self.signatureValue.set(signedText)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>verify</name>
+ <parameter>rsa</parameter>
+ </header>
+ <body>
+ <para>
+ This function works out what kind of digest was used to
+ during signing, calculates the digest of
+ <constant>tbs</constant> and verifies the envelope using the
+ key.
+ </para>
+ </body>
+ </method>
+ ''')
+ def verify(self, rsa):
+ signatureMap = { (1, 2, 840, 113549, 1, 1, 2) : POW.MD2_DIGEST, # md2WithRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 4) : POW.MD5_DIGEST, # md5WithRSAEncryption
+ (1, 3, 14, 3, 2, 15) : POW.SHA_DIGEST, # shaWithRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 5) : POW.SHA1_DIGEST, # sha1withRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 6) : POW.RIPEMD160_DIGEST } # ripemd160WithRSAEncryption
+
+ digestOid = self.signatureAlgorithm.get()[0]
+ digestType = signatureMap[digestOid]
+
+ digest = POW.Digest(digestType)
+ digest.update( self.tbs.toString() )
+ return rsa.verify( self.signatureValue.get(), digest.digest(), digestType )
+
+#---------- certificate support ----------#
+#---------- CRL ----------#
+
+class RevokedCertificate(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.userCertificate = Integer()
+ self.revocationDate = Choice( { 'generalTime' : GeneralizedTime(), 'utcTime' : UtcTime() } )
+ self.crlEntryExtensions = Extensions(1)
+ contents = [ self.userCertificate, self.revocationDate, self.crlEntryExtensions ]
+ Sequence.__init__(self, contents, optional, default)
+
+class RevokedCertificates(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, RevokedCertificate, optional, default)
+
+class TbsCertList(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.version = Integer(1)
+ self.signature = AlgorithmIdentifier()
+ self.issuer = Name()
+ self.thisUpdate = Choice( { 'generalTime' : GeneralizedTime(), 'utcTime' : UtcTime() } )
+ self.nextUpdate = Choice( { 'generalTime' : GeneralizedTime(), 'utcTime' : UtcTime() }, 1 )
+ self.revokedCertificates = RevokedCertificates(1)
+ self.crlExtensions = Extensions()
+ self.explicitCrlExtensions = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.crlExtensions, 1 )
+ contents = [ self.version,
+ self.signature,
+ self.issuer,
+ self.thisUpdate,
+ self.nextUpdate,
+ self.revokedCertificates,
+ self.explicitCrlExtensions ]
+ Sequence.__init__(self, contents, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>CertificateList</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <example>
+ <title>Setting <classname>CertificateList</classname></title>
+ <programlisting>
+ now = POW.pkix.time2gen( time.time() )
+ then = POW.pkix.time2gen(time.time() + 60*60*24*365*12)
+ rsa = POW.Asymmetric()
+
+ crl = POW.pkix.CertificateList()
+ crl.setThisUpdate( ('generalTime', now ) )
+
+ name = ( (( o2i('countryName'), ('printableString', 'GB') ),),
+ (( o2i('stateOrProvinceName'), ('printableString', 'Hertfordshire') ),),
+ (( o2i('organizationName'), ('printableString', 'The House') ),),
+ (( o2i('commonName'), ('printableString', 'Client') ),) )
+
+ myRevocations = (
+ (1, ('generalTime', now), ()),
+ (2, ('generalTime', now), ()),
+ (3, ('generalTime', now), (( o2i('cRLReason'), 0, 1),))
+ )
+
+ crl.setIssuer(name)
+ crl.setRevokedCertificates( myRevocations )
+
+ crl.sign(rsa, POW.MD5_DIGEST)
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class CertificateList(Sequence):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>CertificateList</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ self.tbs = TbsCertList()
+ self.signatureAlgorithm = AlgorithmIdentifier()
+ self.signature = AltBitString()
+ contents = [self.tbs, self.signatureAlgorithm, self.signature]
+ Sequence.__init__(self, contents, optional, default)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>setVersion</name>
+ <parameter>version</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Integer</classname> object. 0
+ indicates a version 1 CRL, and 1 a version 2 CRL.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setVersion(self, version):
+ self.tbs.version.set(version)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getVersion</name>
+ </header>
+ <body>
+ <para>
+ This function returns whatever the version object is set to,
+ this should be 0, 1 or 2.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getVersion(self):
+ return self.tbs.version.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>setIssuer</name>
+ <parameter>names</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets an <classname>Name</classname> object.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setIssuer(self, issuer):
+ self.tbs.issuer.set(issuer)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getIssuer</name>
+ </header>
+ <body>
+ <para>
+ This function returns a complex tuple containing other tuples.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getIssuer(self):
+ return self.tbs.issuer.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>setThisUpdate</memberof>
+ <name>setNotBefore</name>
+ <parameter>time</parameter>
+ </header>
+ <body>
+ <para>
+ This function sets a <classname>Choice</classname> object.
+ It can be either a <classname>GeneralTime</classname> or
+ <classname>UTCTime</classname> object. The functions
+ <function>gen2time</function>, <function>utc2time</function>,
+ <function>time2gen</function> and <function>time2utc</function>
+ can be used to convert to and from integer times and their
+ string representation.
+ </para>
+ <example>
+ <title><function>setNotBefore</function> method usage</title>
+ <programlisting>
+ crl = POW.pkix.CertificateList()
+ now = POW.pkix.time2gen( time.time() )
+ crl.setNotBefore( ('generalTime', now) )
+ </programlisting>
+ </example>
+ </body>
+ </method>
+ ''')
+ def setThisUpdate(self, nu):
+ self.tbs.thisUpdate.set(nu)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getThisUpdate</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple containing two strings. The first
+ is either 'utcTime' or 'generalTime' and the second is the time
+ value as a string.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getThisUpdate(self):
+ return self.tbs.thisUpdate.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>setNextUpdate</name>
+ </header>
+ <body>
+ <para>
+ See set <function>setThisUpdate</function>.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setNextUpdate(self, nu):
+ self.tbs.nextUpdate.set(nu)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getNextUpdate</name>
+ </header>
+ <body>
+ <para>
+ See set <function>getThisUpdate</function>.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getNextUpdate(self):
+ return self.tbs.nextUpdate.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>setExtensions</name>
+ <parameter>extns</parameter>
+ </header>
+ <body>
+ <para>
+ This method sets an <classname>Extensions</classname> object,
+ defined as SEQUENCE OF Extension. The parameter
+ <parameter>extns</parameter> should consist of a list or tuple
+ of values suitable to set an extension. See the extension
+ class for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setExtensions(self, extns):
+ self.tbs.crlExtensions.set(extns)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getExtensions</name>
+ </header>
+ <body>
+ <para>
+ This function returns a tuple of
+ <classname>Extension</classname> values. See
+ <classname>Extension</classname> for details.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getExtensions(self):
+ return self.tbs.crlExtensions.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>setRevokedCertificates</name>
+ </header>
+ <body>
+ <para>
+ This function sets a sequence of
+ <classname>revokedCertificate</classname> objects.
+ This object is optional. See
+ <classname>CertificateList</classname> for an example of its
+ use.
+ </para>
+ </body>
+ </method>
+ ''')
+ def setRevokedCertificates(self, rc):
+ self.tbs.revokedCertificates.set(rc)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>getRevokedCertificates</name>
+ </header>
+ <body>
+ <para>
+ This function return a sequence of
+ <classname>revokedCertificate</classname> objects or None.
+ </para>
+ </body>
+ </method>
+ ''')
+ def getRevokedCertificates(self):
+ return self.tbs.revokedCertificates.get()
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Certificate</memberof>
+ <name>sign</name>
+ </header>
+ <body>
+ <para>
+ This function updates structured of the
+ <classname>certificateList</classname> and
+ <classname>tBSCertList</classname> as appropriate, performs the
+ specified digest on the <classname>tBSCertList</classname> and sets
+ <constant>signedValue</constant> to signed the digest.
+ </para>
+ </body>
+ </method>
+ ''')
+ def sign(self, rsa, digestType):
+ signatureMap = { POW.MD2_DIGEST : (1, 2, 840, 113549, 1, 1, 2), # md2WithRSAEncryption
+ POW.MD5_DIGEST : (1, 2, 840, 113549, 1, 1, 4), # md5WithRSAEncryption
+ POW.SHA_DIGEST : (1, 3, 14, 3, 2, 15), # shaWithRSAEncryption
+ POW.SHA1_DIGEST : (1, 2, 840, 113549, 1, 1, 5), # sha1withRSAEncryption
+ POW.RIPEMD160_DIGEST : (1, 2, 840, 113549, 1, 1, 6) } # ripemd160WithRSAEncryption
+
+ self.tbs.signature.set( [signatureMap[digestType], None] )
+ digest = POW.Digest(digestType)
+ digest.update( self.tbs.toString() )
+ signedText = rsa.sign( digest.digest(), digestType )
+ self.signatureAlgorithm.set( [signatureMap[digestType], None] )
+ self.signature.set(signedText)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>CertificateList</memberof>
+ <name>verify</name>
+ </header>
+ <body>
+ <para>
+ This function works out what kind of digest was used to during
+ signing, calculates the digest of
+ <classname>tBSCertList</classname> and verifies the
+ <constant>signedText</constant> using the key.
+ </para>
+ </body>
+ </method>
+ ''')
+ def verify(self, rsa):
+ signatureMap = { (1, 2, 840, 113549, 1, 1, 2) : POW.MD2_DIGEST, # md2WithRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 4) : POW.MD5_DIGEST, # md5WithRSAEncryption
+ (1, 3, 14, 3, 2, 15) : POW.SHA_DIGEST, # shaWithRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 5) : POW.SHA1_DIGEST, # sha1withRSAEncryption
+ (1, 2, 840, 113549, 1, 1, 6) : POW.RIPEMD160_DIGEST } # ripemd160WithRSAEncryption
+
+ digestOid = self.signatureAlgorithm.get()[0]
+ digestType = signatureMap[digestOid]
+
+ digest = POW.Digest(digestType)
+ digest.update( self.tbs.toString() )
+ return rsa.verify( self.signature.get(), digest.digest(), digestType )
+
+#---------- CRL ----------#
+#---------- GeneralNames object support ----------#
+class OtherName(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.typeId = Oid()
+ self.any = Any()
+ contents = [self.typeId, self.any]
+ Sequence.__init__(self, contents, optional, default)
+
+class EdiPartyName(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.nameAssigner = DirectoryString()
+ self.partyName = DirectoryString()
+ self.explicitNameAssigner = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.nameAssigner, 1 )
+ self.explicitPartyName = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 1, self.partyName )
+ contents = [ self.explicitNameAssigner, self.explicitPartyName ]
+ Sequence.__init__(self, contents, optional, default)
+
+class IpAddress(OctetString):
+ pass
+
+class GeneralName(Choice):
+ def __init__(self, optional=0, default=''):
+
+ otherName = OtherName()
+ otherName.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 0 )
+ rfc822Name = IA5String()
+ rfc822Name.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 1 )
+ dnsName = IA5String()
+ dnsName.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 2 )
+ directoryName = Name()
+ explicitDirectoryName = Explicit( CLASS_CONTEXT, FORM_CONSTRUCTED, 4, directoryName)
+ ediPartyName = EdiPartyName()
+ ediPartyName.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 5 )
+ uri = IA5String()
+ uri.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 6 )
+ ipAddress = IpAddress()
+ ipAddress.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 7 )
+ registeredId = Oid()
+ registeredId.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 8 )
+
+ choices = { 'otherName' : otherName ,
+ 'rfc822Name' : rfc822Name ,
+ 'dNSName' : dnsName ,
+ 'directoryName' : explicitDirectoryName ,
+ 'ediPartyName' : ediPartyName ,
+ 'uri' : uri ,
+ 'iPAddress' : ipAddress ,
+ 'registeredId' : registeredId }
+
+ Choice.__init__(self, choices, optional, default)
+
+class GeneralNames(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, GeneralName, optional, default)
+
+#---------- GeneralNames object support ----------#
+#---------- extensions ----------#
+
+_addFragment('''
+<class>
+ <header>
+ <name>BasicConstraints</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <para>
+ This little extension has recently caused plenty of problems for
+ several large organisations. It consist of a
+ <classname>Boolean</classname> and an
+ <classname>Integer</classname>. The first indicates if the owner
+ is a CA, the second indicates how long a chain of CAs you should
+ trust which the subject of this certificate trusts.
+ </para>
+ <example>
+ <title>Setting <classname>BasicConstraints</classname></title>
+ <programlisting>
+ bc = BasicConstraints()
+ bc.set( (1, 1) )
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class BasicConstraints(Sequence):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>BasicConstraints</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ self.ca = Boolean(0, 'AQEA\n')
+ self.pathLenConstraint = Integer(1)
+ contents = [self.ca, self.pathLenConstraint]
+ Sequence.__init__(self, contents, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>KeyUsage</name>
+ <super>BitString</super>
+ </header>
+</class>
+''')
+class KeyUsage(BitString):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>SubjectAltName</name>
+ <super>GeneralNames</super>
+ </header>
+</class>
+''')
+class SubjectAltName(GeneralNames):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>IssuerAltName</name>
+ <super>GeneralNames</super>
+ </header>
+</class>
+''')
+class IssuerAltName(GeneralNames):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>SubjectKeyIdentifier</name>
+ <super>OctetString</super>
+ </header>
+</class>
+''')
+class SubjectKeyIdentifier(OctetString):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>AuthorityKeyIdentifier</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <para>
+ </para>
+ <example>
+ <title>Setting <classname>AuthorityKeyIdentifier</classname></title>
+ <programlisting>
+ id = AuthorityKeyIdentifier()
+ authdigest = POW.Digest( POW.SHA1_DIGEST )
+ authdigest.update(rsa.derWrite(POW.RSA_PUBLIC_KEY))
+ keyHash = authdigest.digest()
+ id.set( (keyHash, None, None) )
+ </programlisting>
+ </example>
+ </body>
+
+</class>
+''')
+class AuthorityKeyIdentifier(Sequence):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>AuthorityKeyIdentifier</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ self.keyIdentifier = OctetString(1)
+ self.keyIdentifier.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 0 )
+ self.authorityCertIssuer = GeneralNames(1)
+ self.authorityCertIssuer.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 1 )
+ self.authorityCertSerialNumber = Integer(1)
+ self.authorityCertSerialNumber.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 2 )
+ contents = [self.keyIdentifier, self.authorityCertIssuer, self.authorityCertSerialNumber]
+ Sequence.__init__(self, contents, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>PrivateKeyUsagePeriod</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <example>
+ <title>Setting <classname>PrivateKeyUsagePeriod</classname></title>
+ <programlisting>
+ period = PrivateKeyUsagePeriod()
+ period.set( ( time2gen( time.time() ), None) )
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class PrivateKeyUsagePeriod(Sequence):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>PrivateKeyUsagePeriod</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ self.notBefore = GeneralizedTime()
+ self.notBefore.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 0 )
+ self.notAfter = GeneralizedTime()
+ self.notAfter.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 1 )
+ contents = [self.notBefore, self.notAfter]
+ Sequence.__init__(self, contents, optional, default)
+
+class DisplayText(Choice):
+ def __init__(self, optional=0, default=''):
+ choices = { 'visibleString' : VisibleString(),
+ 'bmpString' : BmpString(),
+ 'utf8String' : Utf8String() }
+
+ Choice.__init__(self, choices, optional, default)
+
+class NoticeNumbers(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, Integer, optional, default)
+
+class NoticeReference(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.organization = DisplayText()
+ self.noticeNumbers = NoticeNumbers()
+ contents = [self.organization, self.noticeNumbers]
+ Sequence.__init__(self, contents, optional, default)
+
+class UserNotice(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.noticeRef = NoticeReference(1)
+ self.explicitText = DisplayText(1)
+ contents = [self.noticeRef, self.explicitText]
+ Sequence.__init__(self, contents, optional, default)
+
+class Qualifier(Choice):
+ def __init__(self, optional=0, default=''):
+ choices = { 'cPSuri' : IA5String(),
+ 'userNotice' : UserNotice() }
+
+ Choice.__init__(self, choices, optional, default)
+
+class PolicyQualifierInfo(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.policyQualifierId = Oid()
+ self.qualifier = Qualifier()
+ contents = [self.policyQualifierId, self.qualifier]
+ Sequence.__init__(self, contents, optional, default)
+
+class PolicyQualifiers(SequenceOf):
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, PolicyQualifierInfo, optional, default)
+
+class PolicyInformation(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.policyIdentifier = Oid()
+ self.policyQualifiers = PolicyQualifiers(1)
+ contents = [self.policyIdentifier, self.policyQualifiers]
+ Sequence.__init__(self, contents, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>CertificatePolicies</name>
+ <super>SequenceOf</super>
+ </header>
+ <body>
+ <example>
+ <title>Setting <classname>CertificatePolicies</classname></title>
+ <programlisting>
+ data = (
+ ( o2i('id-cti-ets-proofOfReceipt'), (
+ (o2i('cps'), ('cPSuri', 'http://www.p-s.org.uk/policies/policy1')),
+ (o2i('unotice'), ( 'userNotice',
+ ((('visibleString', 'The House'),(1,2,3)),
+ ('visibleString', 'We guarentee nothing')))),
+ )),
+ ( o2i('id-cti-ets-proofOfOrigin'), (
+ (o2i('cps'), ('cPSuri', 'http://www.p-s.org.uk/policies/policy2')),
+ ))
+ )
+ policies = CertificatePolicies()
+ policies.set( data )
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class CertificatePolicies(SequenceOf):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>CertificatePolicies</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, PolicyInformation, optional, default)
+
+class DistributionPointName(Choice):
+ def __init__(self, optional=0, default=''):
+ fullName = GeneralNames()
+ fullName.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 0 )
+ nameRelativeToCRLIssuer = RelativeDistinguishedName()
+ nameRelativeToCRLIssuer.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 1 )
+
+ choices = { 'fullName' : fullName,
+ 'nameRelativeToCRLIssuer ' : nameRelativeToCRLIssuer }
+
+ Choice.__init__(self, choices, optional, default)
+
+class DistributionPoint(Sequence):
+ def __init__(self, optional=0, default=''):
+ self.distributionPoint = DistributionPointName(1)
+ self.explicitDistributionPoint = Explicit(CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.distributionPoint)
+ self.reasons = BitString(1)
+ self.reasons.implied( CLASS_CONTEXT, FORM_PRIMITIVE, 1 )
+ self.cRLIssuer = GeneralNames(1)
+ self.cRLIssuer.implied( CLASS_CONTEXT, FORM_CONSTRUCTED, 2 )
+ contents = [self.explicitDistributionPoint, self.reasons, self.cRLIssuer]
+ Sequence.__init__(self, contents, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>CRLDistrobutionPoints</name>
+ <super>SequenceOf</super>
+ </header>
+ <body>
+ <example>
+ <title>Setting <classname>CRLDistrobutionPoints</classname></title>
+ <programlisting>
+ n1 = ('directoryName',
+ ( (( o2i('countryName'), ('printableString', 'UK') ),),
+ (( o2i('stateOrProvinceName'), ('printableString', 'Herts') ),),
+ (( o2i('organizationName'), ('printableString', 'The House') ),),
+ (( o2i('commonName'), ('printableString', 'Shannon Works') ),) ) )
+
+ n2 = ('iPAddress', POW.pkix.ip42oct(192,168,100,51))
+
+ data = ( ( ('fullName',(n1, n2)), (1,1,1,1,1), (n1,) ), )
+ points = CRLDistrobutionPoints()
+ points.set( data )
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class CRLDistributionPoints(SequenceOf):
+ _addFragment('''
+ <constructor>
+ <header>
+ <memberof>CRLDistrobutionPoints</memberof>
+ <parameter>optional=0</parameter>
+ <parameter>default=''</parameter>
+ </header>
+ </constructor>
+ ''')
+ def __init__(self, optional=0, default=''):
+ SequenceOf.__init__(self, DistributionPoint, optional, default)
+
+_addFragment('''
+<class>
+ <header>
+ <name>CrlNumber</name>
+ <super>Integer</super>
+ </header>
+</class>
+''')
+class CrlNumber(Integer):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>DeltaCrlIndicator</name>
+ <super>Integer</super>
+ </header>
+</class>
+''')
+class DeltaCrlIndicator(Integer):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>InvalidityDate</name>
+ <super>GeneralizedTime</super>
+ </header>
+</class>
+''')
+class InvalidityDate(GeneralizedTime):
+ pass
+
+_addFragment('''
+<class>
+ <header>
+ <name>CrlReason</name>
+ <super>Enum</super>
+ </header>
+</class>
+''')
+class CrlReason(Enum):
+ pass
+
+#---------- X509 extensions ----------#
+
+_addFragment('''
+<class>
+ <header>
+ <name>Extension</name>
+ <super>Sequence</super>
+ </header>
+ <body>
+ <para>
+ This class is a useful little object. It is set by passing three
+ values: an oid, an integer(a boolean really) and a value. The
+ boolean indicates if this extension is critical. The value is
+ used to set the extension once it has been created. The oid
+ is used to create the correct object which, to be fully supported it must
+ be one of these:
+ <simplelist>
+ <member><classname>basicConstraints</classname></member>
+ <member><classname>subjectAltName</classname></member>
+ <member><classname>issuerAltName</classname></member>
+ <member><classname>authorityKeyIdentifier</classname></member>
+ <member><classname>privateKeyUsagePeriod</classname></member>
+ <member><classname>certificatePolicies</classname></member>
+ <member><classname>cRLDistributionPoints</classname></member>
+ <member><classname>subjectKeyIdentifier</classname></member>
+ <member><classname>keyUsage</classname></member>
+ <member><classname>crlNumber</classname></member>
+ <member><classname>deltaCrlIndicator</classname></member>
+ <member><classname>invalidityDate</classname></member>
+ <member><classname>crlReason</classname></member>
+ </simplelist>
+ </para>
+ <example>
+ <title>Setting <classname>Extension</classname></title>
+ <programlisting>
+ extn = Extension()
+ email = ('rfc822Name', 'peter_shannon@yahoo.com')
+ extn.set( (obj2oid('subjectAltName'),1, (email,)) )
+ </programlisting>
+ </example>
+ </body>
+</class>
+''')
+class Extension(Sequence):
+
+ classMap = {
+ (2, 5, 29, 19) : BasicConstraints,
+ (2, 5, 29, 17) : SubjectAltName,
+ (2, 5, 29, 18) : IssuerAltName,
+ (2, 5, 29, 35) : AuthorityKeyIdentifier,
+ (2, 5, 29, 16) : PrivateKeyUsagePeriod,
+ (2, 5, 29, 32) : CertificatePolicies,
+ (2, 5, 29, 31) : CRLDistributionPoints,
+ (2, 5, 29, 14) : SubjectKeyIdentifier,
+ (2, 5, 29, 15) : KeyUsage,
+ (2, 5, 29, 20) : CrlNumber,
+ (2, 5, 29, 27) : DeltaCrlIndicator,
+ (2, 5, 29, 24) : InvalidityDate,
+ (2, 5, 29, 21) : CrlReason,
+ }
+# Missing -- fix later
+# extendedKeyUsage
+# privateKeyUsagePeriod
+# policyMappings
+# nameConstraints
+# policyConstraints
+# subjectDirectoryAttributes
+# authorityInfoAccess
+# instructionCode
+# issuingDistrobutionPoint
+
+ def __init__(self, optional=0, default=''):
+ self.extnID = Oid()
+ self.critical = Boolean(0, 'AQEA\n')
+ self.extnValue = OctetString()
+ contents = [self.extnID, self.critical, self.extnValue]
+ Sequence.__init__(self, contents, optional, default)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Extension</memberof>
+ <name>set</name>
+ <parameter>values</parameter>
+ </header>
+ <body>
+ <para>
+ <parameter>values</parameter> should be a sequence of three
+ values, the oid, critical marker and a value to set the
+ extension. If an unknown oid is passed to this function it
+ will raise an exception. <parameter>critical</parameter> is a
+ boolean. <parameter>value</parameter> will be used to set the
+ extension after it has been created.
+ </para>
+ </body>
+ </method>
+ ''')
+ def set(self, (oid, critical, val) ):
+ self.extnID.set( oid )
+ self.critical.set( critical )
+
+ extnObj = None
+ if self.classMap.has_key(oid):
+ extnObj = self.classMap[oid]()
+ else:
+ if not (isinstance(oid, types.TupleType) or isinstance(oid, types.ListType)):
+ raise DerError, 'the oid should be specified as a sequence of integers'
+ else:
+ raise DerError, 'unkown object extension %s' % oid
+
+ try:
+ extnObj.set( val )
+ self.extnValue.set( extnObj.toString() )
+ except DerError, e:
+ raise DerError, 'failed to set %s, with:\n\t%s\nresulting in:\n\t%s' % (oid, val, `e`)
+
+ _addFragment('''
+ <method>
+ <header>
+ <memberof>Extension</memberof>
+ <name>get</name>
+ </header>
+ <body>
+ <para>
+ There are several ways this function might fail to decode an
+ extension. Firstly if the extension was marked critical but if
+ the oid cannot be mapped to a class or If a failure occurs decoding the
+ <constant>extnValue</constant>, an exception will be raised.
+ If a failure occurred and the extension was not marked critical it
+ will return a tuple like this: <constant>(oid, critical,
+ ())</constant>. If no failures occur a tuple will be returned,
+ containg the oid, critical and extension values.
+ </para>
+ </body>
+ </method>
+ ''')
+ def get(self):
+ oid = self.extnID.get()
+ critical = self.critical.get()
+
+ if self.classMap.has_key(oid):
+ extnObj = self.classMap[oid]()
+ else:
+ if critical:
+ raise DerError, 'failed to read critical extension %s' % oid
+ else:
+ return (name, critical, ())
+
+ try:
+ extnObj = self.classMap[oid]()
+ extnObj.fromString(self.extnValue.get())
+ value = extnObj.get()
+ except:
+ if critical:
+ raise DerError, 'failed to read critical extension %s' % name
+ else:
+ return (oid, critical, ())
+
+ return (oid, critical, value)
+
+