diff options
author | Rob Austein <sra@hactrn.net> | 2007-07-07 17:04:37 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2007-07-07 17:04:37 +0000 |
commit | ed43d040bf72c2b8eb9d2cec3444556761b3c606 (patch) | |
tree | 57d47ba90cd2c6672f32f0a514c47058e23e3f90 /pow/POW-0.7/lib/pkix.py | |
parent | 2d5c53975e6ddaec9ac3d49a70278fcdd584273d (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-x | pow/POW-0.7/lib/pkix.py | 1685 |
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) + + |