File m2crypto-0.16-multisubject.patch of Package m2crypto
diff -up m2crypto-0.16/M2Crypto/SSL/Checker.py.multisubject m2crypto-0.16/M2Crypto/SSL/Checker.py
--- m2crypto-0.16/M2Crypto/SSL/Checker.py.multisubject 2006-03-20 20:26:28.000000000 +0100
+++ m2crypto-0.16/M2Crypto/SSL/Checker.py 2008-01-06 08:16:08.000000000 +0100
@@ -1,11 +1,11 @@
"""
-M2Crypto.SSL.Checker
+SSL peer certificate checking routines
-Copyright (c) 2004-2005 Open Source Applications Foundation.
+Copyright (c) 2004-2007 Open Source Applications Foundation.
All rights reserved.
"""
-from M2Crypto import util, EVP
+from M2Crypto import util, EVP, m2
import re
class SSLVerificationError(Exception):
@@ -75,12 +75,12 @@ class Checker:
if self.host:
hostValidationPassed = False
+ self.useSubjectAltNameOnly = False
- # XXX subjectAltName might contain multiple fields
- # subjectAltName=DNS:somehost
+ # subjectAltName=DNS:somehost[, ...]*
try:
subjectAltName = peerCert.get_ext('subjectAltName').get_value()
- if not self._match(self.host, subjectAltName, True):
+ if not self._splitSubjectAltName(self.host, subjectAltName):
raise WrongHost(expectedHost=self.host,
actualHost=subjectAltName,
fieldName='subjectAltName')
@@ -88,30 +88,74 @@ class Checker:
except LookupError:
pass
- # commonName=somehost
- if not hostValidationPassed:
- try:
- commonName = peerCert.get_subject().CN
- if not self._match(self.host, commonName):
- raise WrongHost(expectedHost=self.host,
- actualHost=commonName,
- fieldName='commonName')
- except AttributeError:
+ # commonName=somehost[, ...]*
+ if not self.useSubjectAltNameOnly and not hostValidationPassed:
+ hasCommonName = False
+ commonNames = ''
+ for entry in peerCert.get_subject().get_entries_by_nid(m2.NID_commonName):
+ hasCommonName = True
+ commonName = entry.get_data().as_text()
+ if not commonNames:
+ commonNames = commonName
+ else:
+ commonNames += ',' + commonName
+ if self._match(self.host, commonName):
+ hostValidationPassed = True
+ break
+
+ if not hasCommonName:
raise WrongCertificate('no commonName in peer certificate')
+ if not hostValidationPassed:
+ raise WrongHost(expectedHost=self.host,
+ actualHost=commonNames,
+ fieldName='commonName')
+
return True
- def _match(self, host, certHost, subjectAltName=False):
+ def _splitSubjectAltName(self, host, subjectAltName):
"""
>>> check = Checker()
- >>> check._match(host='my.example.com', certHost='DNS:my.example.com', subjectAltName=True)
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:my.example.com')
+ True
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:*.example.com')
+ True
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*.example.com')
+ True
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com')
+ False
+ >>> check.useSubjectAltNameOnly
+ True
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, othername:<unsupported>')
+ False
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, DNS:my.example.org')
+ False
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, DNS:my.example.com')
True
- >>> check._match(host='my.example.com', certHost='DNS:*.example.com', subjectAltName=True)
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:my.example.com, DNS:my.example.org')
True
- >>> check._match(host='my.example.com', certHost='DNS:m*.example.com', subjectAltName=True)
+ >>> check.useSubjectAltNameOnly
True
- >>> check._match(host='my.example.com', certHost='DNS:m*ample.com', subjectAltName=True)
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='')
False
+ >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='othername:<unsupported>')
+ False
+ >>> check.useSubjectAltNameOnly
+ False
+ """
+ self.useSubjectAltNameOnly = False
+ for certHost in subjectAltName.split(','):
+ certHost = certHost.lower().strip()
+ if certHost[:4] == 'dns:':
+ self.useSubjectAltNameOnly = True
+ if self._match(host, certHost[4:]):
+ return True
+ return False
+
+
+ def _match(self, host, certHost):
+ """
+ >>> check = Checker()
>>> check._match(host='my.example.com', certHost='my.example.com')
True
>>> check._match(host='my.example.com', certHost='*.example.com')
@@ -131,17 +175,12 @@ class Checker:
>>> check._match(host='1234', certHost='1234')
True
"""
- # XXX See RFC 2818 and 3280 for matching rules, this is not
- # XXX yet complete.
+ # XXX See RFC 2818 and 3280 for matching rules, this is may not
+ # XXX yet be complete.
host = host.lower()
certHost = certHost.lower()
- if subjectAltName:
- if certHost[:4] != 'dns:':
- return False
- certHost = certHost[4:]
-
if host == certHost:
return True
diff -up m2crypto-0.16/M2Crypto/X509.py.multisubject m2crypto-0.16/M2Crypto/X509.py
--- m2crypto-0.16/M2Crypto/X509.py.multisubject 2006-04-12 07:50:51.000000000 +0200
+++ m2crypto-0.16/M2Crypto/X509.py 2008-01-06 08:21:16.000000000 +0100
@@ -173,6 +173,8 @@ class X509_Name_Entry:
def set_object(self, asn1obj):
return m2.x509_name_entry_set_object( self.x509_name_entry, asn1obj._ptr() )
+ def get_data(self):
+ return ASN1.ASN1_String(m2.x509_name_entry_get_data(self.x509_name_entry))
def create_by_txt( self, field, type, entry, len):
return m2.x509_name_entry_create_by_txt( self.x509_name_entry._ptr(), field, type, entry, len )
@@ -241,6 +243,15 @@ class X509_Name:
def __len__(self):
return m2.x509_name_entry_count(self.x509_name)
+
+ def __getitem__(self, idx):
+ if not 0 <= idx < self.entry_count():
+ raise IndexError("index out of range")
+ return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx))
+
+ def __iter__(self):
+ for i in xrange(self.entry_count()):
+ yield self[i]
def _ptr(self):
#assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error"
@@ -253,6 +264,20 @@ class X509_Name:
def entry_count( self ):
return m2.x509_name_entry_count( self.x509_name )
+ def get_entries_by_nid(self, nid):
+ ret = []
+ lastpos = -1
+
+ while True:
+ lastpos = m2.x509_name_get_index_by_nid(self.x509_name, nid,
+ lastpos)
+ if lastpos == -1:
+ break
+
+ ret.append(self[lastpos])
+
+ return ret
+
def as_text(self, indent=0, flags=m2.XN_FLAG_COMPAT):
"""
as_text returns the name as a string.
diff -up m2crypto-0.16/SWIG/_x509.i.multisubject m2crypto-0.16/SWIG/_x509.i
--- m2crypto-0.16/SWIG/_x509.i.multisubject 2006-05-02 23:00:53.000000000 +0200
+++ m2crypto-0.16/SWIG/_x509.i 2008-01-06 08:16:08.000000000 +0100
@@ -132,6 +132,8 @@ extern int X509_NAME_add_entry_by_NID(X5
extern int X509_NAME_print_ex(BIO *, X509_NAME *, int, unsigned long);
%rename(x509_name_print_ex_fp) X509_NAME_print_ex_fp;
extern int X509_NAME_print_ex_fp(FILE *, X509_NAME *, int, unsigned long);
+%rename(x509_name_get_index_by_nid) X509_NAME_get_index_by_NID;
+extern int X509_NAME_get_index_by_NID(X509_NAME *, int, int);
%rename(x509_name_entry_new) X509_NAME_ENTRY_new;
extern X509_NAME_ENTRY *X509_NAME_ENTRY_new( void );