Exemplo n.º 1
0
def _init_ca(config):
    """
    Generate the CA certificate
    :param config:
    :return:
    """
    # Write the database
    f = open("{0!s}/index.txt".format(config.directory), "w")
    f.write("")
    f.close()

    # Write the serial file
    f = open("{0!s}/serial".format(config.directory), "w")
    f.write("1000")
    f.close()

    # create the privacy key and set accesss rights
    f = open("{0!s}/cakey.pem".format(config.directory), "w")
    f.write("")
    f.close()
    import stat
    os.chmod("{0!s}/cakey.pem".format(config.directory),
             stat.S_IRUSR | stat.S_IWUSR)
    command = "openssl genrsa -out {0!s}/cakey.pem {1!s}".format(
        config.directory, config.keysize)
    print("Running command...")
    print(command)
    args = shlex.split(command)
    p = Popen(args,
              stdout=PIPE,
              stderr=PIPE,
              cwd=config.directory,
              universal_newlines=True)
    result, error = p.communicate()
    if p.returncode != 0:  # pragma: no cover
        # Some error occurred
        raise CAError(error)

    # create the CA certificate
    command = """openssl req -config openssl.cnf -key cakey.pem \
      -new -x509 -days {ca_days!s} -sha256 -extensions v3_ca \
      -out cacert.pem -subj {ca_dn!s}""".format(ca_days=config.validity_ca,
                                                ca_dn=config.dn)
    print("Running command...")
    print(command)
    args = shlex.split(command)
    p = Popen(args,
              stdout=PIPE,
              stderr=PIPE,
              cwd=config.directory,
              universal_newlines=True)
    result, error = p.communicate()
    if p.returncode != 0:  # pragma: no cover
        # Some error occurred
        raise CAError(error)

    print("!" * 60)
    print("Please check the ownership of the private key")
    print("{0!s}/cakey.pem".format(config.directory))
    print("!" * 60)
Exemplo n.º 2
0
    def revoke_cert(self, certificate, reason=CRL_REASONS[0]):
        """
        Revoke the specified certificate. At this point only the database
        index.txt is updated.

        :param certificate: The certificate to revoke
        :type certificate: Either takes X509 object or a PEM encoded
            certificate (string)
        :param reason: One of the available reasons the certificate gets revoked
        :type reason: basestring
        :return: Returns the serial number of the revoked certificate. Otherwise
            an error is raised.
        """
        if isinstance(certificate, string_types):
            cert_obj = crypto.load_certificate(crypto.FILETYPE_PEM,
                                               certificate)
        elif type(certificate) == crypto.X509:
            cert_obj = certificate
        else:
            raise CAError("Certificate in unsupported format")

        serial = cert_obj.get_serial_number()
        serial_hex = int_to_hex(serial)
        filename = serial_hex + ".pem"
        cmd = CA_REVOKE.format(
            cakey=self.cakey,
            cacert=self.cacert,
            config=self.config.get(ATTR.OPENSSL_CNF),
            certificate="/".join(
                p for p in [self.config.get(ATTR.CERT_DIR), filename] if p),
            reason=reason)
        workingdir = self.config.get(ATTR.WORKING_DIR)
        args = shlex.split(cmd)
        p = Popen(args,
                  stdout=PIPE,
                  stderr=PIPE,
                  cwd=workingdir,
                  universal_newlines=True)
        result, error = p.communicate()
        if p.returncode != 0:  # pragma: no cover
            # Some error occurred
            raise CAError(error)

        return serial_hex
Exemplo n.º 3
0
    def create_crl(self, publish=True, check_validity=False):
        """
        Create and Publish the CRL.

        :param publish: Whether the CRL should be published at its CDPs
        :param check_validity: Onle create a new CRL, if the old one is about to
            expire. Therfore the overlap period and the remaining runtime of
            the CRL is checked. If the remaining runtime is smaller than the
            overlap period, we recreate the CRL.
        :return: the CRL location or None, if no CRL was created
        """
        crl = self.config.get(ATTR.CRL, "crl.pem")
        workingdir = self.config.get(ATTR.WORKING_DIR)
        create_new_crl = True
        ret = None
        # Check if we need to create a new CRL
        if check_validity:
            if crl.startswith("/"):
                full_path_crl = crl
            else:
                full_path_crl = workingdir + "/" + crl
            next_update = _get_crl_next_update(full_path_crl)
            if datetime.datetime.now() + \
                    datetime.timedelta(days=self.overlap) > next_update:
                log.info("We checked the overlap period and we need to create "
                         "the new CRL.")
            else:
                log.info("No need to create a new CRL, yet. Next Update: "
                         "{0!s}, overlap: {1!s}".format(
                             next_update, self.overlap))
                create_new_crl = False

        if create_new_crl:
            cmd = CA_GENERATE_CRL.format(cakey=self.cakey,
                                         cacert=self.cacert,
                                         config=self.config.get(
                                             ATTR.OPENSSL_CNF),
                                         CRL=crl)
            args = shlex.split(cmd)
            p = Popen(args,
                      stdout=PIPE,
                      stderr=PIPE,
                      cwd=workingdir,
                      universal_newlines=True)
            result, error = p.communicate()
            if p.returncode != 0:  # pragma: no cover
                # Some error occurred
                raise CAError(error)
            ret = crl

        return ret
Exemplo n.º 4
0
    def sign_request(self, csr, options=None):
        """
        Signs a certificate request with the key of the CA.

        options can be
        WorkingDir: The directory where the configuration like openssl.cnf
        can be found.
        CSRDir: The directory, where to save the certificate signing
        requests. This is relative to the WorkingDir.
        CertificateDir: The directory where to save the certificates. This is
        relative to the WorkingDir.

        :param csr: Certificate signing request
        :type csr: PEM string or SPKAC
        :param options: Additional options like the validity time or the
            template or spkac=1
        :type options: dict
        :return: Returns the certificate object
        :rtype: X509
        """
        # Sign the certificate for one year
        options = options or {}
        days = options.get("days", 365)
        spkac = options.get("spkac")
        config = options.get(
            ATTR.OPENSSL_CNF,
            self.config.get(ATTR.OPENSSL_CNF, "/etc/ssl/openssl.cnf"))
        extension = options.get("extension", "server")
        template_name = options.get("template")
        workingdir = options.get(ATTR.WORKING_DIR,
                                 self.config.get(ATTR.WORKING_DIR))
        csrdir = options.get(ATTR.CSR_DIR, self.config.get(ATTR.CSR_DIR, ""))
        certificatedir = options.get(ATTR.CERT_DIR,
                                     self.config.get(ATTR.CERT_DIR, ""))
        if workingdir:
            if not csrdir.startswith("/"):
                # No absolut path
                csrdir = workingdir + "/" + csrdir
            if not certificatedir.startswith("/"):
                certificatedir = workingdir + "/" + certificatedir

        if template_name:
            t_data = self.templates.get(template_name)
            extension = t_data.get("extensions", extension)
            days = t_data.get("days", days)

        # Determine filename from the CN of the request
        if spkac:
            common_name = re.search("CN=(.*)", csr).group(0).split('=')[1]
            csr_filename = common_name + ".txt"
            certificate_filename = common_name + ".der"
        else:
            csr_obj = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr)
            csr_filename = self._filename_from_x509(csr_obj.get_subject(),
                                                    file_extension="req")
            certificate_filename = self._filename_from_x509(
                csr_obj.get_subject(), file_extension="pem")
            #csr_extensions = csr_obj.get_extensions()
        csr_filename = csr_filename.replace(" ", "_")
        certificate_filename = certificate_filename.replace(" ", "_")
        # dump the file
        csr_filename = to_unicode(csr_filename.encode('ascii', 'ignore'))
        with open(os.path.join(csrdir, csr_filename), "w") as f:
            f.write(csr)

        # TODO: use the template name to set the days and the extension!
        if spkac:
            cmd = CA_SIGN_SPKAC.format(
                cakey=self.cakey,
                cacert=self.cacert,
                days=days,
                config=config,
                extension=extension,
                spkacfile=os.path.join(csrdir, csr_filename),
                certificate=os.path.join(certificatedir, certificate_filename))
        else:
            cmd = CA_SIGN.format(cakey=self.cakey,
                                 cacert=self.cacert,
                                 days=days,
                                 config=config,
                                 extension=extension,
                                 csrfile=os.path.join(csrdir, csr_filename),
                                 certificate=os.path.join(
                                     certificatedir, certificate_filename))
        # run the command
        args = shlex.split(cmd)
        p = Popen(args,
                  stdout=PIPE,
                  stderr=PIPE,
                  cwd=workingdir,
                  universal_newlines=True)
        result, error = p.communicate()
        if p.returncode != 0:  # pragma: no cover
            # Some error occurred
            raise CAError(error)

        with open(os.path.join(certificatedir, certificate_filename),
                  "rb") as f:
            certificate = f.read()

        # We return the cert_obj.
        if spkac:
            filetype = crypto.FILETYPE_ASN1
        else:
            filetype = crypto.FILETYPE_PEM
        cert_obj = crypto.load_certificate(filetype, certificate)
        return cert_obj
Exemplo n.º 5
0
 def _check_attributes(self):
     for req_key in [ATTR.CAKEY, ATTR.CACERT]:
         if req_key not in self.config:
             raise CAError(
                 "required argument '{0!s}' is missing.".format(req_key))
Exemplo n.º 6
0
 def _check_attributes(self):
     if "cakey" not in self.config:
         raise CAError("required argument 'cakey' is missing.")
     if "cacert" not in self.config:
         raise CAError("required argument 'cacert' is missing.")