Example #1
0
    def check_certificate_status(self, order_id, order_meta, plugin_meta,
                                 barbican_meta_dto):
        """Check status of the order

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        """
        successful, error_msg, can_retry, certificate, intermediate, root = self._ca_get_order_status(order_id)

        status = cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST
        message = None

        if successful:
            if error_msg == "CANCELLED":
                status = cert.CertificateStatus.REQUEST_CANCELED
            elif error_msg == "PENDING_REISSUE":
                status = cert.CertificateStatus.WAITING_FOR_CA
            else:
                status = cert.CertificateStatus.CERTIFICATE_GENERATED
        else:
            status = cert.CertificateStatus.WAITING_FOR_CA
            message = error_msg
            return cert.ResultDTO(status=status, status_message=message)

        return cert.ResultDTO(status=status, status_message=message, certificate=certificate,
            intermediates=({"type":"INTERMEDIATE", "cert":intermediate},{"type":"ROOT", "cert":root}))
Example #2
0
    def cancel_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Cancel a certificate request.

        :param order_id: ID for the order associated with this request
        :param order_meta: order metadata fdr this request
        :param plugin_meta: data stored by plugin for further processing.
            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, "cancelling")

        try:
            review_response = self.certclient.review_request(request_id)
            self.certclient.cancel_request(request_id, review_response)

            return cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED)
        except pki.RequestNotFoundException:
            return cm.ResultDTO(
                cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                status_message=u._("no request found for this order"))
        except pki.ConflictingOperationException as e:
            return cm.ResultDTO(cm.CertificateStatus.INVALID_OPERATION,
                                status_message=e.message)
Example #3
0
    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))
Example #4
0
    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"))
Example #5
0
    def issue_certificate_request(self, order_id, order_meta, plugin_meta,
                                  barbican_meta_dto):
        """Create the initial order with CA

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        :returns: ResultDTO
        """
        successful, error_msg, can_retry = self._ca_create_order(order_id, order_meta,
                                                            plugin_meta)

        status = cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST
        message = error_msg

        if successful:
            status = cert.CertificateStatus.WAITING_FOR_CA
        elif can_retry:
            status = cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
            message = error_msg

        return cert.ResultDTO(status=status, status_message=message)
Example #6
0
    def _issue_custom_certificate_request(self, order_id, order_meta,
                                          plugin_meta):
        """Issue a custom certificate request to Dogtag CA

        For now, we assume that we are talking to the Dogtag CA that
        is deployed with the KRA back-end, and we are connected as a
        CA agent.  This means that we can use the agent convenience
        method to automatically approve the certificate request.

        :param order_id: ID of the order associated with this request
        :param order_meta: dict containing all the inputs required for a
            particular profile.  One of these must be the profile_id.
            The exact fields (both optional and mandatory) depend on the
            profile, but they will be exposed to the user in a method to
            expose syntax.  Depending on the profile, only the relevant fields
            will be populated in the request.  All others will be ignored.
        :param plugin_meta: Used to store data for status check.
        :return: cm.ResultDTO
        """
        profile_id = order_meta.get(self.PROFILE_ID, None)
        if not profile_id:
            return cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                                status_message=u._("No profile_id specified"))

        results = self.certclient.enroll_cert(profile_id, order_meta)
        return self._process_enrollment_results(results, plugin_meta)
Example #7
0
    def modify_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Modify a certificate request.

        Once a certificate request is generated, it cannot be modified.
        The only alternative is to cancel the request (if it has not already
        completed) and attempt a fresh enrolment.  That is what will be
        attempted here.
        :param order_id: ID for this order
        :param order_meta: order metadata.  It is assumed that the newly
            modified request data will be present here.
        :param plugin_meta: data stored on behalf of the plugin for further
            operations
        :param barbican_meta_dto: additional data needed to process order.
        :return: ResultDTO:
        """
        result_dto = self.cancel_certificate_request(order_id, order_meta,
                                                     plugin_meta,
                                                     barbican_meta_dto)

        if result_dto.status == cm.CertificateStatus.REQUEST_CANCELED:
            return self.issue_certificate_request(order_id, order_meta,
                                                  plugin_meta,
                                                  barbican_meta_dto)
        elif result_dto.status == cm.CertificateStatus.INVALID_OPERATION:
            return cm.ResultDTO(
                cm.CertificateStatus.INVALID_OPERATION,
                status_message=u._(
                    "Modify request: unable to cancel: "
                    "{message}").format(message=result_dto.status_message))
        else:
            # other status (ca_unavailable, client_data_issue)
            # return result from cancel operation
            return result_dto
Example #8
0
    def _issue_custom_certificate_request(self, order_id, order_meta,
                                          plugin_meta, barbican_meta_dto):
        """Issue a custom certificate request to Dogtag CA

        :param order_id: ID of the order associated with this request
        :param order_meta: dict containing all the inputs required for a
            particular profile.  One of these must be the profile_id.
            The exact fields (both optional and mandatory) depend on the
            profile, but they will be exposed to the user in a method to
            expose syntax.  Depending on the profile, only the relevant fields
            will be populated in the request.  All others will be ignored.
        :param plugin_meta: Used to store data for status check.
        :param barbican_meta_dto: Extra data to aid in processing.
        :return: cm.ResultDTO
        """
        profile_id = order_meta.get(self.PROFILE_ID, None)
        if not profile_id:
            return cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN,
                                status_message=u._("No profile_id specified"))

        # we expect the csr to be base64 encoded PEM data.  Dogtag CA expects
        # PEM data though so we need to decode it.
        updated_meta = copy.deepcopy(order_meta)
        if 'cert_request' in updated_meta:
            updated_meta['cert_request'] = base64.b64decode(
                updated_meta['cert_request'])

        return self._issue_certificate_request(profile_id, updated_meta,
                                               plugin_meta, barbican_meta_dto)
Example #9
0
    def modify_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Update the order meta-data

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        """

        """order_meta should cover:
        - CSR
        - ApproverEmail
        - order_id - the order ID that was used for the certificate
        """ 
        successful, error_msg, can_retry = self._ca_reissue_cert(order_id, order_meta, plugin_meta)
        if successful:
            status = cert.CertificateStatus.WAITING_FOR_CA
        elif can_retry:
            status = cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
        else:
            status = cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
        message = error_msg
        return cert.ResultDTO(status=status, status_message=message)
Example #10
0
    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)
Example #11
0
 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))
Example #12
0
    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 = 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)
        cert = self.cert_manager.make_certificate(csr)
        cert_enc = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
        ca_enc = crypto.dump_certificate(crypto.FILETYPE_PEM, self.ca.cert)

        return cert_manager.ResultDTO(
            cert_manager.CertificateStatus.CERTIFICATE_GENERATED,
            certificate=base64.b64encode(cert_enc),
            intermediates=base64.b64encode(ca_enc))
Example #13
0
    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
Example #14
0
    def check_certificate_status(self, order_id, order_meta, plugin_meta):
        """Check status of the order

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :returns: A :class:`ResultDTO` instance containing the result
                  populated by the plugin implementation
        :rtype: :class:`ResultDTO`
        """
        LOG.info(u._LI('Invoking check_certificate_status()'))
        return cert.ResultDTO(cert.CertificateStatus.WAITING_FOR_CA)
Example #15
0
    def cancel_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Cancel the order

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        :returns: A :class:`ResultDTO` instance containing the result
                  populated by the plugin implementation
        :rtype: :class:`ResultDTO`
        """
        LOG.info(u._LI('Invoking cancel_certificate_request()'))
        return cert.ResultDTO(cert.CertificateStatus.REQUEST_CANCELED)
Example #16
0
    def issue_certificate_request(self, order_id, order_meta, plugin_meta,
                                  barbican_meta_dto):
        """Create the initial order with CA

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        :returns: A :class:`ResultDTO` instance containing the result
                  populated by the plugin implementation
        :rtype: :class:`ResultDTO`
        """
        LOG.info('Invoking issue_certificate_request()')
        return cert.ResultDTO(cert.CertificateStatus.WAITING_FOR_CA,
                              retry_msec=MSEC_UNTIL_CHECK_STATUS)
Example #17
0
    def cancel_certificate_request(self, order_id, order_meta, plugin_meta,
                                   barbican_meta_dto):
        """Cancel the order

        :param order_id: ID associated with the order
        :param order_meta: Dict of meta-data associated with the order.
        :param plugin_meta: Plugin meta-data previously set by calls to
                            this plugin. Plugins may also update/add
                            information here which Barbican will persist
                            on their behalf.
        :param barbican_meta_dto: additional data needed to process order.
        """
        successful, error_msg, can_retry = self._ca_modify_order(order_id, "CANCEL")
        if successful:
            status = cert.CertificateStatus.REQUEST_CANCELED
        else:
            status = cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST

        return cert.ResultDTO(status=status, status_message=error_msg)
Example #18
0
 def _catch_ca_unavailable(self, *args, **kwargs):
     try:
         return ca_related_function(self, *args, **kwargs)
     except request_exceptions.RequestException:
         return cm.ResultDTO(
             cm.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST)
    def setUp(self):
        super(BaseCertificateRequestsTestCase, self).setUp()

        self.external_project_id = "56789"
        self.project = res.get_or_create_project(self.external_project_id)
        project_repo.save(self.project)

        self.barbican_meta_dto = mock.MagicMock()
        self.order_meta = {}
        self.plugin_meta = {}
        self.barbican_meta = {}
        self.result = cert_man.ResultDTO(
            cert_man.CertificateStatus.WAITING_FOR_CA
        )
        self.result_follow_on = common.FollowOnProcessingStatusDTO()

        self.cert_plugin = mock.MagicMock()
        self.cert_plugin.issue_certificate_request.return_value = self.result
        self.cert_plugin.check_certificate_status.return_value = self.result

        self.store_plugin = mock.MagicMock()

        parsed_ca = {
            'plugin_name': "cert_plugin",
            'plugin_ca_id': "XXXX",
            'name': "test ca",
            'description': 'Test CA',
            'ca_signing_certificate': 'ZZZZZ',
            'intermediates': 'YYYYY'
        }

        self.ca = models.CertificateAuthority(parsed_ca)
        ca_repo.create_from(self.ca)
        self.ca_id = self.ca.id

        # second ca for testing
        parsed_ca = {
            'plugin_name': "cert_plugin",
            'plugin_ca_id': "XXXX2",
            'name': "test ca2",
            'description': 'Test CA2',
            'ca_signing_certificate': 'ZZZZZ2',
            'intermediates': 'YYYYY2'
        }

        self.ca2 = models.CertificateAuthority(parsed_ca)
        ca_repo.create_from(self.ca2)
        self.ca_id2 = self.ca2.id

        # data for preferred CA and global preferred CA tests
        # add those to the repo in those tests
        self.pref_ca = models.PreferredCertificateAuthority(
            self.project.id,
            self.ca_id)

        self.global_pref_ca = models.PreferredCertificateAuthority(
            self.project.id,
            self.ca_id)

        # data for stored key cases
        self.private_key = models.Secret()
        self.private_key.secret_type = 'PRIVATE'
        self.private_key.project_id = self.project.id
        secret_repo.create_from(self.private_key)

        self.public_key = models.Secret()
        self.public_key.secret_type = 'PUBLIC'
        self.public_key.project_id = self.project.id
        secret_repo.create_from(self.public_key)

        self.passphrase = models.Secret()
        self.passphrase.secret_type = 'PASSPHRASE'
        self.passphrase.project_id = self.project.id
        secret_repo.create_from(self.passphrase)

        self.private_key_value = None
        self.public_key_value = "public_key"
        self.passphrase_value = None

        self.parsed_container_with_passphrase = {
            'name': 'container name',
            'type': 'rsa',
            'secret_refs': [
                {'name': 'private_key',
                 'secret_ref': 'https://localhost/secrets/' +
                               self.private_key.id},
                {'name': 'public_key',
                 'secret_ref': 'https://localhost/secrets/' +
                               self.public_key.id},
                {'name': 'private_key_passphrase',
                 'secret_ref': 'https://localhost/secrets/' +
                               self.passphrase.id}
            ]
        }

        self.parsed_container = {
            'name': 'container name',
            'type': 'rsa',
            'secret_refs': [
                {'name': 'private_key',
                 'secret_ref': 'https://localhost/secrets/' +
                               self.private_key.id},
                {'name': 'public_key',
                 'secret_ref': 'https://localhost/secrets/' +
                               self.public_key.id}
            ]
        }

        self.container_with_passphrase = models.Container(
            self.parsed_container_with_passphrase)
        self.container_with_passphrase.project_id = self.project.id
        container_repo.create_from(self.container_with_passphrase)

        self.container = models.Container(self.parsed_container)
        self.container.project_id = self.project.id
        container_repo.create_from(self.container)

        repositories.commit()

        self.stored_key_meta = {
            cert_man.REQUEST_TYPE:
            cert_man.CertificateRequestType.STORED_KEY_REQUEST,
            "container_ref":
            "https://localhost/containers/" + self.container.id,
            "subject_dn": "cn=host.example.com,ou=dev,ou=us,o=example.com"
        }

        self.order = models.Order()
        self.order.meta = self.order_meta
        self.order.project_id = self.project.id
        self.order.order_barbican_meta = self.barbican_meta
        self.order.type = 'certificate'
        order_repo.create_from(self.order)

        self._config_cert_plugin()
        self._config_store_plugin()
        self._config_cert_event_plugin()
        self._config_save_meta_plugin()
        self._config_get_meta_plugin()
        self._config_save_barbican_meta_plugin()
        self._config_get_barbican_meta_plugin()
        self._config_barbican_meta_dto()