def check_certificate_status(self, order_id, order_meta, plugin_meta, barbican_meta_dto): """Check the status of a certificate request. :param order_id: ID of the order associated with this request :param order_meta: order_metadata associated with this order :param plugin_meta: data populated by previous calls for this order, in particular the request_id :param barbican_meta_dto: additional data needed to process order. :return: cm.ResultDTO """ request_id = self._get_request_id(order_id, plugin_meta, "checking") request = self._get_request(request_id) if not request: raise cm.CertificateGeneralException( u._("No request found for request_id {request_id} for " "order {order_id}").format(request_id=request_id, order_id=order_id)) request_status = request.request_status if request_status == pki.cert.CertRequestStatus.REJECTED: return cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, status_message=request.error_message) elif request_status == pki.cert.CertRequestStatus.CANCELED: return cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED) elif request_status == pki.cert.CertRequestStatus.PENDING: return cm.ResultDTO(cm.CertificateStatus.WAITING_FOR_CA) elif request_status == pki.cert.CertRequestStatus.COMPLETE: # get the cert cert_id = request.cert_id if not cert_id: raise cm.CertificateGeneralException( u._("Request {request_id} reports status_complete, but no " "cert_id has been returned").format( request_id=request_id)) cert = self._get_cert(cert_id) if not cert: raise cm.CertificateGeneralException( u._("Certificate not found for cert_id: {cert_id}").format( cert_id=cert_id)) return cm.ResultDTO(cm.CertificateStatus.CERTIFICATE_GENERATED, certificate=cert.encoded, intermediates=cert.pkcs7_cert_chain) else: raise cm.CertificateGeneralException( u._("Invalid request_status returned by CA"))
def create_ca(self, ca_create_dto): # get the parent CA from the ca list, return error if not on list parent_ca_id = ca_create_dto.parent_ca_id if not parent_ca_id: raise cert_manager.CertificateGeneralException( "No parent id passed to snake oil plugin on create_ca") parent_ca = self.cas.get(parent_ca_id) if not parent_ca: raise cert_manager.CertificateGeneralException( "Invalid parent id passed to snake oil plugin:" + parent_ca_id) # create a new ca, passing in key and issuer from the parent new_ca_id = str(uuid.uuid4()) new_cert_path = os.path.join(self.subca_directory, new_ca_id + ".cert") new_key_path = os.path.join(self.subca_directory, new_ca_id + ".key") new_chain_path = os.path.join(self.subca_directory, new_ca_id + ".chain") new_pkcs7_path = os.path.join(self.subca_directory, new_ca_id + ".p7b") parent_chain_path = parent_ca.chain_path new_ca = SnakeoilCA(cert_path=new_cert_path, key_path=new_key_path, chain_path=new_chain_path, pkcs7_path=new_pkcs7_path, name=ca_create_dto.name, subject_dn=ca_create_dto.subject_dn, signing_dn=parent_ca.subject_dn, signing_key=parent_ca.key, parent_chain_path=parent_chain_path) self.cas[new_ca_id] = new_ca expiration = (datetime.datetime.utcnow() + datetime.timedelta( days=cert_manager.CA_INFO_DEFAULT_EXPIRATION_DAYS)) return { cert_manager.INFO_NAME: new_ca.name, cert_manager.INFO_CA_SIGNING_CERT: crypto.dump_certificate(crypto.FILETYPE_PEM, new_ca.cert), cert_manager.INFO_EXPIRATION: expiration.isoformat(), cert_manager.INFO_INTERMEDIATES: new_ca.pkcs7, cert_manager.PLUGIN_CA_ID: new_ca_id }
def _process_auto_enrollment_results(self, enrollment_results, plugin_meta, barbican_meta_dto): """Process results received from Dogtag CA for auto-enrollment This processes data from enroll_cert, which submits, approves and gets the cert issued and returns as a list of CertEnrollment objects. :param enrollment_results: list of CertEnrollmentResult objects :param plugin_meta: metadata dict for storing plugin specific data :param barbican_meta_dto: object containing extra data to help process the request :return: cm.ResultDTO """ # Although it is possible to create multiple certs in an invocation # of enroll_cert, Barbican cannot handle this case. Assume # only once cert and request generated for now. enrollment_result = enrollment_results[0] request = enrollment_result.request if not request: raise cm.CertificateGeneralException( u._("No request returned in enrollment_results")) # store the request_id in the plugin metadata plugin_meta[self.REQUEST_ID] = request.request_id cert = enrollment_result.cert return self._create_dto(request.request_status, request.request_id, request.error_message, cert)
def issue_certificate_request(self, order_id, order_meta, plugin_meta, barbican_meta_dto): if barbican_meta_dto.generated_csr is not None: encoded_csr = barbican_meta_dto.generated_csr else: try: encoded_csr = base64.b64decode(order_meta['request_data']) except KeyError: return cert_manager.ResultDTO( cert_manager.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, status_message=u._("No request_data specified")) csr = crypto.load_certificate_request(crypto.FILETYPE_PEM, encoded_csr) ca_id = barbican_meta_dto.plugin_ca_id if ca_id: ca = self.cas.get(ca_id) if ca is None: raise cert_manager.CertificateGeneralException( "Invalid ca_id passed into snake oil plugin:" + ca_id) else: ca = self.ca cert_mgr = CertManager(ca) cert = cert_mgr.make_certificate(csr) cert_enc = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) return cert_manager.ResultDTO( cert_manager.CertificateStatus.CERTIFICATE_GENERATED, certificate=base64.b64encode(cert_enc), intermediates=base64.b64encode(ca.pkcs7))
def _process_enrollment_results(self, enrollment_results, plugin_meta): """Process results received from Dogtag CA for enrollment :param enrollment_results: list of CertEnrollmentResult objects :param plugin_meta: metadata dict for storing plugin specific data :return: cm.ResultDTO """ # Although it is possible to create multiple certs in an invocation # of enroll_cert, Barbican cannot handle this case. Assume # only once cert and request generated for now. enrollment_result = enrollment_results[0] request = enrollment_result.request if not request: raise cm.CertificateGeneralException( u._("No request returned in enrollment_results")) # store the request_id in the plugin metadata plugin_meta[self.REQUEST_ID] = request.request_id cert = enrollment_result.cert if not cert: request_status = request.request_status if request_status == pki.cert.CertRequestStatus.REJECTED: return cm.ResultDTO( cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, status_message=request.error_message) elif request_status == pki.cert.CertRequestStatus.CANCELED: return cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED) elif request_status == pki.cert.CertRequestStatus.PENDING: return cm.ResultDTO(cm.CertificateStatus.WAITING_FOR_CA) elif request_status == pki.cert.CertRequestStatus.COMPLETE: raise cm.CertificateGeneralException( u._("request_id {req_id} returns COMPLETE but no cert " "returned").format(req_id=request.request_id)) else: raise cm.CertificateGeneralException( u._("Invalid request_status {status} for " "request_id {request_id}").format( status=request_status, request_id=request.request_id)) return cm.ResultDTO(cm.CertificateStatus.CERTIFICATE_GENERATED, certificate=cert.encoded, intermediates=cert.pkcs7_cert_chain)
def _get_request_id(self, order_id, plugin_meta, operation): request_id = plugin_meta.get(self.REQUEST_ID, None) if not request_id: raise cm.CertificateGeneralException( u._("{request} not found for {operation} for " "order_id {order_id}").format(request=self.REQUEST_ID, operation=operation, order_id=order_id)) return request_id
def _catch_enrollment_exception(self, *args, **kwargs): try: return ca_related_function(self, *args, **kwargs) except pki.BadRequestException as e: return cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, status_message=e.message) except pki.PKIException as e: raise cm.CertificateGeneralException( u._("Exception thrown by enroll_cert: {message}").format( message=e.message))
def _create_dto(self, request_status, request_id, error_message, cert): dto = None if request_status == pki.cert.CertRequestStatus.COMPLETE: if cert is not None: # Barbican is expecting base 64 encoded PEM, so we base64 # encode below. # # Currently there is an inconsistency in what Dogtag returns # for certificates and intermediates. For certs, we return # PEM, whereas for intermediates, we return headerless PEM. # This is being addressed in Dogtag ticket: # https://fedorahosted.org/pki/ticket/1374 # # Until this is addressed, simply add the missing headers cert_chain = (CERT_HEADER + "\r\n" + cert.pkcs7_cert_chain + CERT_FOOTER) dto = cm.ResultDTO(cm.CertificateStatus.CERTIFICATE_GENERATED, certificate=base64.b64encode(cert.encoded), intermediates=base64.b64encode(cert_chain)) else: raise cm.CertificateGeneralException( u._("request_id {req_id} returns COMPLETE but no cert " "returned").format(req_id=request_id)) elif request_status == pki.cert.CertRequestStatus.REJECTED: dto = cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, status_message=error_message) elif request_status == pki.cert.CertRequestStatus.CANCELED: dto = cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED) elif request_status == pki.cert.CertRequestStatus.PENDING: dto = cm.ResultDTO(cm.CertificateStatus.WAITING_FOR_CA) else: raise cm.CertificateGeneralException( u._("Invalid request_status {status} for " "request_id {request_id}").format(status=request_status, request_id=request_id)) return dto