<commit_before>"""ndg_httpsclient - module containing SSL peer verification class.
"""
__author__ = "<NAME> (STFC)"
__date__ = "09/12/11"
__copyright__ = "(C) 2012 Science and Technology Facilities Council"
__license__ = "BSD - see LICENSE file in top-level directory"
__contact__ = "<EMAIL>"
__revision__ = '$Id$'
import re
import logging
log = logging.getLogger(__name__)

try:
    from ndg.httpsclient.subj_alt_name import SubjectAltName
    from pyasn1.codec.der import decoder as der_decoder
    subj_alt_name_support = True
except ImportError, e:
    subj_alt_name_support = False

class ServerSSLCertVerification(object):
    """Check server identity.  If hostname doesn't match, allow match of
    host's Distinguished Name against server DN setting"""
    DN_LUT = {
        'commonName':               'CN',
        'organisationalUnitName':   'OU',
        'organisation':             'O',
        'countryName':              'C',
        'emailAddress':             'EMAILADDRESS',
        'localityName':             'L',
        'stateOrProvinceName':      'ST',
        'streetAddress':            'STREET',
        'domainComponent':          'DC',
        'userid':                   'UID'
    }
    SUBJ_ALT_NAME_EXT_NAME = 'subjectAltName'
    PARSER_RE_STR = '/(%s)=' % '|'.join(DN_LUT.keys() + DN_LUT.values())
    PARSER_RE = re.compile(PARSER_RE_STR)

    __slots__ = ('__hostname', '__certDN', '__subj_alt_name_match')

    def __init__(self, certDN=None, hostname=None, subj_alt_name_match=True):
        """Override parent class __init__ to enable setting of certDN
        setting

        @type certDN: string
        @param certDN: Set the expected Distinguished Name of the
        server to avoid errors matching hostnames.  This is useful
        where the hostname is not fully qualified
        @type hostname: string
        @param hostname: hostname to match against peer certificate 
        subjectAltNames or subject common name
        @type subj_alt_name_match: bool
        @param subj_alt_name_match: flag to enable/disable matching of hostname
        against peer certificate subjectAltNames.  Nb. A setting of True will 
        be ignored if the pyasn1 package is not installed
        """
        self.__certDN = None
        self.__hostname = None

        if certDN is not None:
            self.certDN = certDN

        if hostname is not None:
            self.hostname = hostname
        
        if subj_alt_name_match:
            if not subj_alt_name_support:
                log.warning('Overriding "subj_alt_name_match" keyword setting: '
                            'peer verification with subjectAltNames is disabled')
                self.__subj_alt_name_match = False
                
            self.__subj_alt_name_match = True
        else:
            log.debug('Disabling peer verification with subject '
                      'subjectAltNames!')
            self.__subj_alt_name_match = False

    def __call__(self, connection, peerCert, errorStatus, errorDepth,
                 preverifyOK):
        """Verify server certificate

        @type connection: OpenSSL.SSL.Connection
        @param connection: SSL connection object
        @type peerCert: basestring
        @param peerCert: server host certificate as OpenSSL.crypto.X509
        instance
        @type errorStatus: int
        @param errorStatus: error status passed from caller.  This is the value
        returned by the OpenSSL C function X509_STORE_CTX_get_error().  Look-up
        x509_vfy.h in the OpenSSL source to get the meanings of the different
        codes.  PyOpenSSL doesn't help you!
        @type errorDepth: int
        @param errorDepth: a non-negative integer representing where in the
        certificate chain the error occurred. If it is zero it occured in the
        end entity certificate, one if it is the certificate which signed the
        end entity certificate and so on.

        @type preverifyOK: int
        @param preverifyOK: the error status - 0 = Error, 1 = OK of the current
        SSL context irrespective of any verification checks done here.  If this
        function yields an OK status, it should enforce the preverifyOK value
        so that any error set upstream overrides and is honoured.<commit_msg>Fix to SubjectAltNames support check - should only be enabled if pyasn1 is installed.<commit_after>"""ndg_httpsclient - module containing SSL peer verification class.
"""
__author__ = "<NAME> (STFC)"
__date__ = "09/12/11"
__copyright__ = "(C) 2012 Science and Technology Facilities Council"
__license__ = "BSD - see LICENSE file in top-level directory"
__contact__ = "<EMAIL>"
__revision__ = '$Id$'
import re
import logging
log = logging.getLogger(__name__)

try:
    from ndg.httpsclient.subj_alt_name import SubjectAltName
    from pyasn1.codec.der import decoder as der_decoder
    SUBJ_ALT_NAME_SUPPORT = True
except ImportError, e:
    SUBJ_ALT_NAME_SUPPORT = False
    SUBJ_ALT_NAME_SUPPORT_MSG = (
        'SubjectAltName support is disabled - check pyasn1 package '
        'installation to enable'
    )
    import warnings
    warnings.warn(SUBJ_ALT_NAME_SUPPORT_MSG)


class ServerSSLCertVerification(object):
    """Check server identity.  If hostname doesn't match, allow match of
    host's Distinguished Name against server DN setting"""
    DN_LUT = {
        'commonName':               'CN',
        'organisationalUnitName':   'OU',
        'organisation':             'O',
        'countryName':              'C',
        'emailAddress':             'EMAILADDRESS',
        'localityName':             'L',
        'stateOrProvinceName':      'ST',
        'streetAddress':            'STREET',
        'domainComponent':          'DC',
        'userid':                   'UID'
    }
    SUBJ_ALT_NAME_EXT_NAME = 'subjectAltName'
    PARSER_RE_STR = '/(%s)=' % '|'.join(DN_LUT.keys() + DN_LUT.values())
    PARSER_RE = re.compile(PARSER_RE_STR)

    __slots__ = ('__hostname', '__certDN', '__subj_alt_name_match')

    def __init__(self, certDN=None, hostname=None, subj_alt_name_match=True):
        """Override parent class __init__ to enable setting of certDN
        setting

        @type certDN: string
        @param certDN: Set the expected Distinguished Name of the
        server to avoid errors matching hostnames.  This is useful
        where the hostname is not fully qualified
        @type hostname: string
        @param hostname: hostname to match against peer certificate 
        subjectAltNames or subject common name
        @type subj_alt_name_match: bool
        @param subj_alt_name_match: flag to enable/disable matching of hostname
        against peer certificate subjectAltNames.  Nb. A setting of True will 
        be ignored if the pyasn1 package is not installed
        """
        self.__certDN = None
        self.__hostname = None

        if certDN is not None:
            self.certDN = certDN

        if hostname is not None:
            self.hostname = hostname
        
        if subj_alt_name_match:
            if not SUBJ_ALT_NAME_SUPPORT:
                log.warning('Overriding "subj_alt_name_match" keyword setting: '
                            'peer verification with subjectAltNames is disabled')
                self.__subj_alt_name_match = False
            else:    
                self.__subj_alt_name_match = True
        else:
            log.debug('Disabling peer verification with subject '
                      'subjectAltNames!')
            self.__subj_alt_name_match = False

    def __call__(self, connection, peerCert, errorStatus, errorDepth,
                 preverifyOK):
        """Verify server certificate

        @type connection: OpenSSL.SSL.Connection
        @param connection: SSL connection object
        @type peerCert: basestring
        @param peerCert: server host certificate as OpenSSL.crypto.X509
        instance
        @type errorStatus: int
        @param errorStatus: error status passed from caller.  This is the value
        returned by the OpenSSL C function X509_STORE_CTX_get_error().  Look-up
        x509_vfy.h in the OpenSSL source to get the meanings of the different
        codes.  PyOpenSSL doesn't help you!
        @type errorDepth: int
        @param errorDepth: a non-negative integer representing where in the
        certificate chain the error occurred. If it is zero it occured in the
        end entity certificate, one if it is the certificate which signed the
        end entity certificate and so on.

        @type preverifyOK: int
        @param preverifyOK: the error status - 0 = Error, 1 = OK of the current
        SSL context irrespective of any verification checks done here.  If this
        function yields an OK status, it should enforce the preverifyOK value
        so that any error set upstream overrides and is honoured.
{'fraction_non_alphanumeric': 0.06790750141003948, 'fraction_numerical': 0.0054145516074450084, 'mean_word_length': 2.3995398773006134, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5655837', 'n_tokens_mistral': 2459, 'n_tokens_neox': 2386, 'n_words': 828}