def test_iri_to_uri(self): self.assertEqual( b'ldap://ldap.e-szigno.hu/CN=Microsec%20e-Szigno%20Root%20CA,OU=e-Szigno%20CA,' b'O=Microsec%20Ltd.,L=Budapest,C=HU?certificateRevocationList;binary', util.iri_to_uri( 'ldap://ldap.e-szigno.hu/CN=Microsec e-Szigno Root CA,' 'OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU?certificateRevocationList;binary' ) ) self.assertEqual( b'ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%202009,' b'O=D-Trust%20GmbH,C=DE?certificaterevocationlist', util.iri_to_uri( 'ldap://directory.d-trust.net/CN=D-TRUST Root Class 3 CA 2 2009,' 'O=D-Trust GmbH,C=DE?certificaterevocationlist' ) ) self.assertEqual( b'ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%20EV%202009,' b'O=D-Trust%20GmbH,C=DE?certificaterevocationlist', util.iri_to_uri( 'ldap://directory.d-trust.net/CN=D-TRUST Root Class 3 CA 2 EV 2009,' 'O=D-Trust GmbH,C=DE?certificaterevocationlist' ) )
def _grab_crl(user_agent, url, timeout): """ Fetches a CRL and parses it :param user_agent: A unicode string of the user agent to use when fetching the URL :param url: A unicode string of the URL to fetch the CRL from :param timeout: The number of seconds after which an HTTP request should timeout :return: An asn1crypto.crl.CertificateList object """ if sys.version_info < (3,): url = util.iri_to_uri(url) request = Request(url) request.add_header(b'Accept', b'application/pkix-crl') request.add_header(b'User-Agent', user_agent.encode('iso-8859-1')) response = urlopen(request, None, timeout) data = response.read() if pem.detect(data): _, _, data = pem.unarmor(data) return crl.CertificateList.load(data)
def fetch_certs(certificate_list, user_agent=None, timeout=10): """ Fetches certificates from the authority information access extension of an asn1crypto.crl.CertificateList object and places them into the cert registry. :param certificate_list: An asn1crypto.crl.CertificateList object :param user_agent: The HTTP user agent to use when requesting the CRL. If None, a default is used in the format "certvalidation 1.0.0". :param timeout: The number of seconds after which an HTTP request should timeout :raises: urllib.error.URLError/urllib2.URLError - when a URL/HTTP error occurs socket.error - when a socket error occurs :return: A list of any asn1crypto.x509.Certificate objects that were fetched """ output = [] if user_agent is None: user_agent = 'certvalidator %s' % __version__ elif not isinstance(user_agent, str_cls): raise TypeError('user_agent must be a unicode string, not %s' % type_name(user_agent)) for url in certificate_list.issuer_cert_urls: if sys.version_info < (3,): url = util.iri_to_uri(url) request = Request(url) request.add_header(b'Accept', b'application/pkix-cert,application/pkcs7-mime') request.add_header(b'User-Agent', user_agent.encode('iso-8859-1')) response = urlopen(request, None, timeout) content_type = response.headers['Content-Type'].strip() response_data = response.read() if content_type == 'application/pkix-cert': output.append(x509.Certificate.load(response_data)) elif content_type == 'application/pkcs7-mime': signed_data = cms.SignedData.load(response_data) if isinstance(signed_data['certificates'], cms.CertificateSet): for cert_choice in signed_data['certificates']: if cert_choice.name == 'certificate': output.append(cert_choice.chosen) else: raise ValueError('Unknown content type of %s when fetching issuer certificate for CRL' % repr(content_type)) return output
def __init__(self, url): """ Wrapper that converts IRI's to URI's before passing to super, and automatically adds the Host header :param url: A unicode string of the URL to request """ super(Request, self).__init__(util.iri_to_uri(url)) self.add_header('Host', self.get_host().decode('ascii').split(":")[0])
def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): """ Wrapper for the ``__init__`` method of urllib that converts IRI's to URI's before setting the url attribute. :param url str: Valid URL :param data str: Data to send to the server or None :param headers dict: Dictionary containing [header type]: [header value] items :param origin_req_host str: Host name or IP address of the original request that was initiated :param unverifiable bool: Indicates whether the request is unverifiable, as defined by RFC 2965. """ url = util.iri_to_uri(url) _Request.__init__(self, url, data, headers, origin_req_host, unverifiable)
def fetch(cert, issuer, hash_algo='sha1', nonce=True, user_agent=None, timeout=10): """ Fetches an OCSP response for a certificate :param cert: An asn1cyrpto.x509.Certificate object to get an OCSP reponse for :param issuer: An asn1crypto.x509.Certificate object that is the issuer of cert :param hash_algo: A unicode string of "sha1" or "sha256" :param nonce: A boolean - if the nonce extension should be used to prevent replay attacks :param user_agent: The HTTP user agent to use when requesting the OCSP response. If None, a default is used in the format "certvalidation 1.0.0". :param timeout: The number of seconds after which an HTTP request should timeout :raises: urllib.error.URLError/urllib2.URLError - when a URL/HTTP error occurs socket.error - when a socket error occurs :return: An asn1crypto.ocsp.OCSPResponse object """ if not isinstance(cert, x509.Certificate): raise TypeError('cert must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(cert)) if not isinstance(issuer, x509.Certificate): raise TypeError('issuer must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(issuer)) if hash_algo not in set(['sha1', 'sha256']): raise ValueError('hash_algo must be one of "sha1", "sha256", not %s' % repr(hash_algo)) if not isinstance(nonce, bool): raise TypeError('nonce must be a bool, not %s' % type_name(nonce)) if user_agent is None: user_agent = 'certvalidator %s' % __version__ elif not isinstance(user_agent, str_cls): raise TypeError('user_agent must be a unicode string, not %s' % type_name(user_agent)) cert_id = ocsp.CertId({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': hash_algo}), 'issuer_name_hash': getattr(cert.issuer, hash_algo), 'issuer_key_hash': getattr(issuer.public_key, hash_algo), 'serial_number': cert.serial_number, }) request = ocsp.Request({ 'req_cert': cert_id, }) tbs_request = ocsp.TBSRequest({ 'request_list': ocsp.Requests([request]), }) if nonce: nonce_extension = ocsp.TBSRequestExtension({ 'extn_id': 'nonce', 'critical': False, 'extn_value': core.OctetString(core.OctetString(os.urandom(16)).dump()) }) tbs_request['request_extensions'] = ocsp.TBSRequestExtensions([nonce_extension]) ocsp_request = ocsp.OCSPRequest({ 'tbs_request': tbs_request, }) last_e = None for ocsp_url in cert.ocsp_urls: try: if sys.version_info < (3,): ocsp_url = util.iri_to_uri(ocsp_url) request = Request(ocsp_url) _add_header(request, 'Accept', 'application/ocsp-response') _add_header(request, 'Content-Type', 'application/ocsp-request') _add_header(request, 'User-Agent', user_agent) response = urlopen(request, ocsp_request.dump(), timeout) ocsp_response = ocsp.OCSPResponse.load(response.read()) request_nonce = ocsp_request.nonce_value response_nonce = ocsp_response.nonce_value if request_nonce and response_nonce and request_nonce.native != response_nonce.native: raise errors.OCSPValidationError( 'Unable to verify OCSP response since the request and response nonces do not match' ) return ocsp_response except (URLError) as e: last_e = e raise last_e
def fetch(cert, issuer, hash_algo='sha1', nonce=True, user_agent=None, timeout=10): """ Fetches an OCSP response for a certificate :param cert: An asn1cyrpto.x509.Certificate object to get an OCSP reponse for :param issuer: An asn1crypto.x509.Certificate object that is the issuer of cert :param hash_algo: A unicode string of "sha1" or "sha256" :param nonce: A boolean - if the nonce extension should be used to prevent replay attacks :param user_agent: The HTTP user agent to use when requesting the OCSP response. If None, a default is used in the format "certvalidation 1.0.0". :param timeout: The number of seconds after which an HTTP request should timeout :raises: urllib.error.URLError/urllib2.URLError - when a URL/HTTP error occurs socket.error - when a socket error occurs :return: An asn1crypto.ocsp.OCSPResponse object """ if not isinstance(cert, x509.Certificate): raise TypeError( 'cert must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(cert)) if not isinstance(issuer, x509.Certificate): raise TypeError( 'issuer must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(issuer)) if hash_algo not in set(['sha1', 'sha256']): raise ValueError('hash_algo must be one of "sha1", "sha256", not %s' % repr(hash_algo)) if not isinstance(nonce, bool): raise TypeError('nonce must be a bool, not %s' % type_name(nonce)) if user_agent is None: user_agent = 'certvalidator %s' % __version__ elif not isinstance(user_agent, str_cls): raise TypeError('user_agent must be a unicode string, not %s' % type_name(user_agent)) cert_id = ocsp.CertId({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': hash_algo}), 'issuer_name_hash': getattr(cert.issuer, hash_algo), 'issuer_key_hash': getattr(issuer.public_key, hash_algo), 'serial_number': cert.serial_number, }) request = ocsp.Request({ 'req_cert': cert_id, }) tbs_request = ocsp.TBSRequest({ 'request_list': ocsp.Requests([request]), }) if nonce: nonce_extension = ocsp.TBSRequestExtension({ 'extn_id': 'nonce', 'critical': False, 'extn_value': core.OctetString(core.OctetString(os.urandom(16)).dump()) }) tbs_request['request_extensions'] = ocsp.TBSRequestExtensions( [nonce_extension]) ocsp_request = ocsp.OCSPRequest({ 'tbs_request': tbs_request, }) last_e = None for ocsp_url in cert.ocsp_urls: try: if sys.version_info < (3, ): ocsp_url = util.iri_to_uri(ocsp_url) request = Request(ocsp_url) _add_header(request, 'Accept', 'application/ocsp-response') _add_header(request, 'Content-Type', 'application/ocsp-request') _add_header(request, 'User-Agent', user_agent) response = urlopen(request, ocsp_request.dump(), timeout) ocsp_response = ocsp.OCSPResponse.load(response.read()) request_nonce = ocsp_request.nonce_value response_nonce = ocsp_response.nonce_value if request_nonce and response_nonce and request_nonce.native != response_nonce.native: raise errors.OCSPValidationError( 'Unable to verify OCSP response since the request and response nonces do not match' ) return ocsp_response except (URLError) as e: last_e = e raise last_e