def test_serialize_request(self): req_bytes = load_vectors_from_file(filename=os.path.join( "x509", "ocsp", "req-sha1.der"), loader=lambda data: data.read(), mode="rb") req = ocsp.load_der_ocsp_request(req_bytes) assert req.public_bytes(serialization.Encoding.DER) == req_bytes
def test_serialize_request(self): req_bytes = load_vectors_from_file( filename=os.path.join("x509", "ocsp", "req-sha1.der"), loader=lambda data: data.read(), mode="rb" ) req = ocsp.load_der_ocsp_request(req_bytes) assert req.public_bytes(serialization.Encoding.DER) == req_bytes
def do_POST(self): request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False) issuer_key = serialization.load_pem_private_key( request.content, None, default_backend()) request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False) issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend()) try: content_len = int(self.headers.getheader('content-length', 0)) except AttributeError: content_len = int(self.headers.get('Content-Length')) ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len)) response = requests.get('{0}/cert-status-by-serial/{1}'.format( PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')), verify=False) if not response.ok: ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.UNAUTHORIZED) else: data = response.json() now = datetime.datetime.utcnow() cert = x509.load_pem_x509_certificate(data['Certificate'].encode(), default_backend()) if data['Status'] != 'Revoked': ocsp_status = ocsp.OCSPCertStatus.GOOD revocation_time = None revocation_reason = None else: ocsp_status = ocsp.OCSPCertStatus.REVOKED revocation_reason = x509.ReasonFlags.unspecified # "... +0000 UTC" => "+0000" revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt']) revocation_time = parser.parse(revoked_at) ocsp_response = ocsp.OCSPResponseBuilder().add_response( cert=cert, issuer=issuer_cert, algorithm=hashes.SHA1(), cert_status=ocsp_status, this_update=now, next_update=now + datetime.timedelta(hours=1), revocation_time=revocation_time, revocation_reason=revocation_reason).responder_id( ocsp.OCSPResponderEncoding.NAME, issuer_cert).sign(issuer_key, hashes.SHA256()) self.send_response(200) self.end_headers() self.wfile.write(ocsp_response.public_bytes( serialization.Encoding.DER))
def ocsp_response(id=None): ''' payload could be found in - request.data - path :param id: :return: ''' payload = request.data or id if not payload: # @todo return invalid ocsp response return "This OCSP Endpoint" req = ocsp.load_der_ocsp_request(payload) cert = Certificate.objects(serial_number=str(req.serial_number)).get() ca_cert = Certificate.objects(id=cert.pid).get() builder = ocsp.OCSPResponseBuilder() if cert.revoked: builder = builder.add_response(cert=cert.cert, issuer=ca_cert.cert, algorithm=hashes.SHA1(), cert_status=ocsp.OCSPCertStatus.REVOKED, this_update=datetime.utcnow(), next_update=datetime.utcnow(), revocation_time=cert.revoked_at, revocation_reason=None) else: builder = builder.add_response(cert=cert.cert, issuer=ca_cert.cert, algorithm=hashes.SHA1(), cert_status=ocsp.OCSPCertStatus.GOOD, this_update=datetime.utcnow(), next_update=datetime.utcnow(), revocation_time=None, revocation_reason=None) builder = builder.responder_id(ocsp.OCSPResponderEncoding.HASH, ca_cert.cert) response_object = builder.sign(ca_cert.key, hashes.SHA256()) response = make_response( response_object.public_bytes(serialization.Encoding.DER)) response.headers['Content-Type'] = 'application/ocsp-response' return response
def cert_status_response(req): ocsp_req = ocsp.load_der_ocsp_request(req) try: sn = str(ocsp_req.serial_number) record = Record.query.filter_by(sn=sn).one() if record.revoked_at: status = ocsp.OCSPCertStatus.REVOKED revocation_time = record.revoked_at if record.reason: revocation_reason = REASON_FLAGS[record.reason] else: revocation_reason = ReasonFlags.unspecified else: status = ocsp.OCSPCertStatus.GOOD revocation_time, revocation_reason = None, None except NoResultFound: raise RuntimeError('Unknown certificate.') cert: Certificate = load_pem_x509_certificate(data=record.cert, backend=default_backend()) issuer = app.config['ISSUERS'][record.issuer_sn] responder_cert = app.config['CERT'] responder_key = app.config['KEY'] builder = ocsp.OCSPResponseBuilder() builder = builder.add_response( cert=cert, issuer=issuer, algorithm=ocsp_req.hash_algorithm, cert_status=status, this_update=datetime.datetime.now(), next_update=None, revocation_time=revocation_time, revocation_reason=revocation_reason).responder_id( ocsp.OCSPResponderEncoding.HASH, responder_cert) response = builder.sign(responder_key, hashes.SHA256()) return response.public_bytes(serialization.Encoding.DER)
def test_bad_request(self): with pytest.raises(ValueError): ocsp.load_der_ocsp_request(b"invalid")
def _get_ocsp_response(data, pebble_urlopen, log): try: ocsp_request = ocsp.load_der_ocsp_request(data) except Exception: log('Error while decoding OCSP request') return ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.MALFORMED_REQUEST) log('OCSP request for certificate # {0}'.format( ocsp_request.serial_number)) # Process possible extensions nonce = None for ext in ocsp_request.extensions: if isinstance(ext.value, x509.OCSPNonce): nonce = ext.value.nonce continue if ext.critical: return ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.MALFORMED_REQUEST) # Determine issuer root_count = int(os.environ.get('PEBBLE_ALTERNATE_ROOTS') or '0') + 1 for root in range(root_count): req, intermediate, intermediate_key = _get_sample_request_for_root( root, ocsp_request.hash_algorithm, pebble_urlopen) if req.issuer_key_hash == ocsp_request.issuer_key_hash and req.issuer_name_hash == ocsp_request.issuer_name_hash: log('Identified intermediate certificate {0}'.format( intermediate.subject)) break intermediate = None intermediate_key = None if intermediate is None or intermediate_key is None: log(ocsp_request.issuer_key_hash, ocsp_request.issuer_name_hash) log('Cannot identify intermediate certificate') return ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.UNAUTHORIZED) serial_hex = hex(ocsp_request.serial_number)[2:] if len(serial_hex) % 2 == 1: serial_hex = '0' + serial_hex try: url = pebble_urlopen("/cert-status-by-serial/{0}".format(serial_hex)) except urllib.error.HTTPError as e: if e.code == 404: log('Unknown certificate with # {0}'.format( ocsp_request.serial_number)) return ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.UNAUTHORIZED) raise data = json.loads(url.read()) log('Pebble result on certificate:', json.dumps(data, sort_keys=True, indent=2)) cert = x509.load_pem_x509_certificate(data['Certificate'].encode('utf-8'), backend=default_backend()) now = datetime.datetime.now() if data['Status'] == 'Revoked': cert_status = ocsp.OCSPCertStatus.REVOKED revoked_at = data.get('RevokedAt') if revoked_at is not None: revoked_at = ' '.join( revoked_at.split(' ')[:2]) # remove time zones if '.' in revoked_at: revoked_at = revoked_at[:revoked_at.index( '.')] # remove milli- or nanoseconds revoked_at = datetime.datetime.strptime(revoked_at, '%Y-%m-%d %H:%M:%S') revocation_time = revoked_at, revocation_reason = RECOVATION_REASONS.get( data.get('Reason'), x509.ReasonFlags.unspecified) elif data['Status'] == 'Valid': cert_status = ocsp.OCSPCertStatus.GOOD revocation_time = None revocation_reason = None else: log('Unknown certificate status "{0}"'.format(data['Status'])) return ocsp.OCSPResponseBuilder.build_unsuccessful( ocsp.OCSPResponseStatus.INTERNAL_ERROR) response = ocsp.OCSPResponseBuilder() response = response.add_response(cert=cert, issuer=intermediate, algorithm=ocsp_request.hash_algorithm, cert_status=cert_status, this_update=now, next_update=None, revocation_time=revocation_time, revocation_reason=revocation_reason) response = response.responder_id(ocsp.OCSPResponderEncoding.HASH, intermediate) if nonce is not None: response = response.add_extension(x509.OCSPNonce(nonce), False) return response.sign(intermediate_key, hashes.SHA256())
def process_ocsp_request(self, data: bytes) -> HttpResponse: """Process OCSP request data.""" try: ocsp_req = ocsp.load_der_ocsp_request(data) except Exception as e: # pylint: disable=broad-except; we really need to catch everything here log.exception(e) return self.malformed_request() # Fail if there are any critical extensions that we do not understand for ext in ocsp_req.extensions: if ext.critical and not isinstance(ext.value, OCSPNonce): # pragma: no cover # It seems impossible to get cryptography to create such a request, so it's not tested return self.malformed_request() # Get CA and certificate try: ca = self.get_ca() except CertificateAuthority.DoesNotExist: log.error("%s: Certificate Authority could not be found.", self.ca) return self.fail() try: cert = self.get_cert(ca, int_to_hex(ocsp_req.serial_number)) except Certificate.DoesNotExist: log.warning("OCSP request for unknown cert received.") return self.fail() except CertificateAuthority.DoesNotExist: log.warning("OCSP request for unknown CA received.") return self.fail() # get key/cert for OCSP responder try: responder_key = self.get_responder_key() responder_cert = self.get_responder_cert() except Exception: # pylint: disable=broad-except; we really need to catch everything here log.error("Could not read responder key/cert.") return self.fail() # get the certificate status if cert.revoked: status = ocsp.OCSPCertStatus.REVOKED else: status = ocsp.OCSPCertStatus.GOOD now = datetime.utcnow() builder = ocsp.OCSPResponseBuilder() expires = datetime.utcnow() + timedelta(seconds=self.expires) builder = builder.add_response( cert=cert.pub.loaded, issuer=ca.pub.loaded, algorithm=hashes.SHA1(), cert_status=status, this_update=now, next_update=expires, revocation_time=cert.get_revocation_time(), revocation_reason=cert.get_revocation_reason(), ).responder_id(ocsp.OCSPResponderEncoding.HASH, responder_cert) # Add the responder cert to the response, necessary because we (so far) always use delegate # certificates builder = builder.certificates([responder_cert]) # Add OCSP nonce if present try: nonce = ocsp_req.extensions.get_extension_for_class(OCSPNonce) builder = builder.add_extension(nonce.value, critical=nonce.critical) except ExtensionNotFound: pass response = builder.sign(responder_key, hashes.SHA256()) return self.http_response(response.public_bytes(Encoding.DER))
#!/bin/python3 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.hashes import SHA1 from cryptography.x509 import load_pem_x509_certificate, ocsp import base64 #OCSP cert1 = open("pubkey.crt", "r") authority1 = open("pubkey.crt", "r") cert = cert1.read().encode() authority = authority1.read().encode() certloader = load_pem_x509_certificate(cert, default_backend()) authorityloader = load_pem_x509_certificate(authority, default_backend()) builder = ocsp.OCSPRequestBuilder() builder = builder.add_certificate(certloader, authorityloader, SHA1()) prereq = builder.build() request = base64.b64encode(prereq.public_bytes(serialization.Encoding.DER)) #Load the request: ocsp_req = ocsp.load_der_ocsp_request(request) #E.g. show serial print(ocsp_req.serial_number) #Response ocsp_resp = ocsp.load_der_ocsp_response(request)