""" x509v3.py - basic classes for X.509v3 extensions (c) by Michael Stroeder This module is distributed under the terms of the GPL (GNU GENERAL PUBLIC LICENSE) Version 2 (see http://www.gnu.org/copyleft/gpl.html) $Id: x509v3.py,v 1.12 2003/08/21 08:47:30 michael Exp $ """ # Python standard lib import sys, string # Pisces from pisces import asn1 # mspki itself import util, asn1helper, x509 _ESCAPE_HTML_CHARS=list('&<>":={}()') _ESCAPE_HTML_CHARS_TRANS = [ (c,'&#%d;' % ord(c)) for c in _ESCAPE_HTML_CHARS ] def escapeHTML(s): """ Escape all characters with a special meaning in HTML to appropriate character tags """ for c,e in _ESCAPE_HTML_CHARS_TRANS: s = s.replace(c,e) return s def htmlize(e): """Display certificate extension object e with HTML""" if hasattr(e,'__html__'): return e.__html__() else: return escapeHTML(str(e)) class Extension(asn1.Sequence): """ Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING } """ def __init__(self,val): asn1.Sequence.__init__(self,val) self.extnId = self.val[0] if len(self.val)==3: self.critical,evo = self.val[1],self.val[2] elif len(self.val)==2: self.critical,evo = None,self.val[1] else: raise ValueError, 'X.509v3 extension field has length %d' % len(self.val) if oidreg.has_key(repr(self.extnId)): try: self.extnValue = oidreg[repr(self.extnId)](asn1.parse(evo.val)) except: # If parsing known extension fails fall-back to generic parsing self.extnValue = asn1.parse(evo.val) else: self.extnValue = asn1.parse(evo.val) def __repr__(self): if hasattr(self,'extnValue'): extnValue_repr = repr(self.extnValue) else: extnValue_repr = '' return '<%s.%s: %s: %s%s>' % ( self.__class__.__module__, self.__class__.__name__, self.extnId, repr(self.extnValue), ' (CRITICAL)'*(self.critical==1) ) def __html__(self): if hasattr(self,'extnValue'): if hasattr(self.extnValue,'__html__'): extnValue_html = self.extnValue.__html__() else: extnValue_html = escapeHTML(str(self.extnValue)) else: extnValue_html = '' return '
%s (%s)
%s
' % ( self.extnValue.__class__.__name__, str(self.extnId), extnValue_html ) class Extensions(asn1.Sequence): """ Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension """ def __init__(self,val): for i in range(len(val)): val[i]=Extension(val[i]) asn1.Sequence.__init__(self,val) class Certificate(x509.Certificate): """ Class for X.509v3 certificates with extensions Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING } TBSCertificate ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, serialNumber CertificateSerialNumber, signature AlgorithmIdentifier, issuer Name, validity Validity, subject Name, subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 extensions [3] EXPLICIT Extensions OPTIONAL -- If present, version shall be v3 } """ def extensions(self): if int(self.version())<3: return None """Extract X.509v3 extensions""" for i in self.tbsCertificate[self.__tbsoffset__+6:len(self.tbsCertificate)]: if hasattr(i,'tag') and i.tag==3: return Extensions(i.val) return None class CRL(x509.CRL): """ Class for X.509v2 CRLs with extensions CertificateList ::= SEQUENCE { tbsCertList TBSCertList, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING } TBSCertList ::= SEQUENCE { version Version OPTIONAL, -- if present, shall be v2 signature AlgorithmIdentifier, issuer Name, thisUpdate Time, nextUpdate Time OPTIONAL, revokedCertificates SEQUENCE OF SEQUENCE { userCertificate CertificateSerialNumber, revocationDate Time, crlEntryExtensions Extensions OPTIONAL -- if present, shall be v2 } OPTIONAL, crlExtensions [0] EXPLICIT Extensions OPTIONAL -- if present, shall be v2 } """ def crlExtensions(self): for i in self.tbsCertList[self.__tbsoffset__+5:len(self.tbsCertList)]: if hasattr(i,'tag') and i.tag==0: return Extensions(i.val) return None # now pull all oidreg's in other modules holding classes # for various X.509v3 extension import pkix, nsext, vendorext oidreg = { # PKIX extensions '2.5.29.9':pkix.SubjectDirectoryAttributes, '2.5.29.10':pkix.BasicConstraints, '2.5.29.14':pkix.SubjectKeyIdentifier, '2.5.29.15':pkix.KeyUsage, '2.5.29.16':pkix.PrivateKeyUsagePeriod, '2.5.29.17':pkix.SubjectAltName, '2.5.29.18':pkix.IssuerAltName, '2.5.29.19':pkix.BasicConstraints, '2.5.29.20':pkix.cRLNumber, '2.5.29.28':pkix.issuingDistributionPoint, '2.5.29.31':pkix.cRLDistributionPoints, '2.5.29.32':pkix.certificatePolicies, '2.5.29.35':pkix.AuthorityKeyIdentifier, '2.5.29.36':pkix.PolicyConstraints, '2.5.29.37':pkix.extendedKeyUsage, '1.3.6.1.5.5.7.1.1':pkix.AuthorityInfoAccessSyntax, # Netscape extensions '2.16.840.1.113730.1.1':nsext.nsCertType, '2.16.840.1.113730.1.2':nsext.nsBaseUrl, '2.16.840.1.113730.1.3':nsext.nsRevocationUrl, '2.16.840.1.113730.1.4':nsext.nsCaRevocationUrl, '2.16.840.1.113730.1.7':nsext.nsRenewalUrl, '2.16.840.1.113730.1.8':nsext.nsCaPolicyUrl, '2.16.840.1.113730.1.12':nsext.nsSslServerName, '2.16.840.1.113730.1.13':nsext.nsComment, # Entrust extensions '1.2.840.113533.7.65.0':vendorext.entrustVersInfo, # Verisign extensions '2.16.840.1.113733.1.6.3':vendorext.verisignCZAG, }