Beispiel #1
0
    def challenge_factory(self, name, challenges, path):
        sni_todo = []
        # Since a single invocation of SNI challenge can satsify multiple
        # challenges. We must keep track of all the challenges it satisfies
        sni_satisfies = []

        challenge_objs = []
        challenge_obj_indicies = []
        for c in path:
            if challenges[c]["type"] == "dvsni":
                logger.info("\tDVSNI challenge for name %s." % name)
                sni_satisfies.append(c)
                sni_todo.append((str(name), str(challenges[c]["r"]),
                                 str(challenges[c]["nonce"])))

            elif challenges[c]["type"] == "recoveryToken":
                logger.info("\tRecovery Token Challenge for name: %s." % name)
                challenge_objs_indicies.append(c)
                challenge_objs.append(RecoveryToken())

            else:
                logger.fatal("Challenge not currently supported")
                sys.exit(82)

        if sni_todo:
            # SNI_Challenge can satisfy many sni challenges at once so only
            # one "challenge object" is issued for all sni_challenges
            challenge_objs.append(
                SNI_Challenge(sni_todo, os.path.abspath(self.key_file),
                              self.config))
            challenge_obj_indicies.append(sni_satisfies)
            logger.debug(sni_todo)

        return challenge_objs, challenge_obj_indicies
Beispiel #2
0
    def verify_identity(self, c):
        path = self.gen_challenge_path(c["challenges"],
                                       c.get("combinations", None))

        logger.info("Peforming the following challenges:")

        # Every indicies element is a list of integers referring to which
        # challenges in the master list the challenge object satisfies
        # Single Challenge objects that can satisfy multiple server challenges
        # mess up the order of the challenges, thus requiring the indicies
        challenge_objs, indicies = self.challenge_factory(
            self.names[0], c["challenges"], path)

        responses = [None] * len(c["challenges"])

        # Perform challenges and populate responses
        for i, c_obj in enumerate(challenge_objs):
            if not c_obj.perform():
                logger.fatal("Challenge Failed")
                sys.exit(1)
            for index in indicies[i]:
                responses[index] = c_obj.generate_response()

        logger.info("Configured Apache for challenges; \
        waiting for verification...")

        return responses, challenge_objs
    def is_expected_msg(self, msg_dict, expected, delay=3, rounds = 20):
        for i in range(rounds):
            if msg_dict["type"] == expected:
                return msg_dict

            elif msg_dict["type"] == "error":
                logger.error("%s: %s - More Info: %s" %
                             (msg_dict["error"],
                              msg_dict.get("message", ""),
                              msg_dict.get("moreInfo", "")))
                raise Exception(msg_dict["error"])

            elif msg_dict["type"] == "defer":
                logger.info("Waiting for %d seconds..." % delay)
                time.sleep(delay)
                msg_dict = self.send(self.status_request(msg_dict["token"]))
            else:
                logger.fatal("Received unexpected message")
                logger.fatal("Expected: %s" % expected)
                logger.fatal("Received: " + msg_dict)
                sys.exit(33)

        logger.error("Server has deferred past the max of %d seconds" %
                     (rounds * delay))
        return None
    def verify_identity(self, c):
        path = self.gen_challenge_path(
            c["challenges"], c.get("combinations", None))

        logger.info("Performing the following challenges:")

        # Every indicies element is a list of integers referring to which
        # challenges in the master list the challenge object satisfies
        # Single Challenge objects that can satisfy multiple server challenges
        # mess up the order of the challenges, thus requiring the indicies
        challenge_objs, indicies = self.challenge_factory(
            self.names[0], c["challenges"], path)


        responses = [None] * len(c["challenges"])

        # Perform challenges and populate responses
        for i, c_obj in enumerate(challenge_objs):
            if not c_obj.perform():
                logger.fatal("Challenge Failed")
                sys.exit(1)
            for index in indicies[i]:
                responses[index] = c_obj.generate_response()

        logger.info("Configured Apache for challenges; " +
        "waiting for verification...")

        return responses, challenge_objs
    def challenge_factory(self, name, challenges, path):
        sni_todo = []
        # Since a single invocation of SNI challenge can satisfy multiple
        # challenges. We must keep track of all the challenges it satisfies
        sni_satisfies = []

        challenge_objs = []
        challenge_obj_indicies = []
        for c in path:
            if challenges[c]["type"] == "dvsni":
                logger.info("  DVSNI challenge for name %s." % name)
                sni_satisfies.append(c)
                sni_todo.append( (str(name), str(challenges[c]["r"]),
                                  str(challenges[c]["nonce"])) )

            elif challenges[c]["type"] == "recoveryToken":
                logger.info("\tRecovery Token Challenge for name: %s." % name)
                challenge_objs_indicies.append(c)
                challenge_objs.append(RecoveryToken())

            else:
                logger.fatal("Challenge not currently supported")
                sys.exit(82)

        if sni_todo:
            # SNI_Challenge can satisfy many sni challenges at once so only
            # one "challenge object" is issued for all sni_challenges
            challenge_objs.append(SNI_Challenge(
                sni_todo, os.path.abspath(self.key_file), self.config))
            challenge_obj_indicies.append(sni_satisfies)
            logger.debug(sni_todo)

        return challenge_objs, challenge_obj_indicies
Beispiel #6
0
 def certificate_request(self, csr_der, key):
     logger.info("Preparing and sending CSR..")
     return {
         "type": "certificateRequest",
         "csr": jose.b64encode_url(csr_der),
         "signature": crypto_util.create_sig(csr_der, self.key_file)
     }
    def verify_identity(self, c):
        path = self.gen_challenge_path(
            c["challenges"], c.get("combinations", None))

        logger.info("Performing the following challenges:")

        # Every indices element is a list of integers referring to which
        # challenges in the master list the challenge object satisfies
        # Single Challenge objects that can satisfy multiple server challenges
        # mess up the order of the challenges, thus requiring the indices
        challenge_objs, indices = self.challenge_factory(
            self.names[0], c["challenges"], path)

        responses = ["null"] * len(c["challenges"])

        # Perform challenges
        for i, c_obj in enumerate(challenge_objs):
            response = "null"
            if c_obj["type"] in CONFIG.CONFIG_CHALLENGES:
                response = self.config.perform(c_obj)
            else:
                # Handle RecoveryToken type challenges
                pass

            for index in indices[i]:
                responses[index] = response

        logger.info("Configured Apache for challenges; " +
        "waiting for verification...")

        return responses, challenge_objs
Beispiel #8
0
    def list_certs_keys(self):
        list_file = CERT_KEY_BACKUP + "LIST"
        certs = []

        if not os.path.isfile(CERT_KEY_BACKUP + "LIST"):
            logger.info(
                "You don't have any certificates saved from letsencrypt")
            return

        with open(list_file, 'rb') as csvfile:
            csvreader = csv.reader(csvfile)
            for row in csvreader:
                c = crypto_util.get_cert_info(row[1])

                b_k = CERT_KEY_BACKUP + os.path.basename(row[2]) + "_" + row[0]
                b_c = CERT_KEY_BACKUP + os.path.basename(row[1]) + "_" + row[0]

                c["orig_key_file"] = row[2]
                c["orig_cert_file"] = row[1]
                c["idx"] = int(row[0])
                c["backup_key_file"] = b_k
                c["backup_cert_file"] = b_c

                certs.append(c)
        if certs:
            self.choose_certs(certs)
        else:
            display.generic_notification("There are not any trusted \
            Let's Encrypt certificates for this server.")
 def cleanup_challenges(self, challenge_objs):
     logger.info("Cleaning up challenges...")
     for c in challenge_objs:
         if c["type"] in CONFIG.CONFIG_CHALLENGES:
             self.config.cleanup()
         else:
             #Handle other cleanup if needed
             pass
Beispiel #10
0
 def cleanup_challenges(self, challenges):
     logger.info("Cleaning up challenges...")
     for chall in challenges:
         if chall["type"] in CONFIG.CONFIG_CHALLENGES:
             self.config.cleanup()
         else:
             # Handle other cleanup if needed
             pass
Beispiel #11
0
 def redirect_to_ssl(self, vhost):
     for ssl_vh in vhost:
         success, redirect_vhost = self.config.enable_redirect(ssl_vh)
         logger.info("\nRedirect vhost: " + redirect_vhost.file +
                  " - " + str(success))
         # If successful, make sure redirect site is enabled
         if success:
             self.config.enable_site(redirect_vhost)
Beispiel #12
0
 def redirect_to_ssl(self, vhost):
     for ssl_vh in vhost:
         success, redirect_vhost = self.config.enable_redirect(ssl_vh)
         logger.info("\nRedirect vhost: " + redirect_vhost.file + " - " +
                     str(success))
         # If successful, make sure redirect site is enabled
         if success:
             self.config.enable_site(redirect_vhost)
Beispiel #13
0
    def challenge_factory(self, name, challenges, path):
        """

        :param name: TODO
        :type name: TODO

        :param challanges: A list of challenges from ACME "challenge"
                           server message to be fulfilled by the client
                           in order to prove possession of the identifier.
        :type challenges: list

        :param path: List of indices from `challenges`.
        :type path: list

        :returns: A pair of TODO
        :rtype: tuple

        """
        sni_todo = []
        # Since a single invocation of SNI challenge can satisfy multiple
        # challenges. We must keep track of all the challenges it satisfies
        sni_satisfies = []

        challenge_objs = []
        challenge_obj_indices = []
        for index in path:
            chall = challenges[index]

            if chall["type"] == "dvsni":
                logger.info("  DVSNI challenge for name %s." % name)
                sni_satisfies.append(index)
                sni_todo.append(
                    (str(name), str(chall["r"]), str(chall["nonce"])))

            elif chall["type"] == "recoveryToken":
                logger.info("\tRecovery Token Challenge for name: %s." % name)
                challenge_obj_indices.append(index)
                challenge_objs.append({
                    type: "recoveryToken",
                })

            else:
                logger.fatal("Challenge not currently supported")
                sys.exit(82)

        if sni_todo:
            # SNI_Challenge can satisfy many sni challenges at once so only
            # one "challenge object" is issued for all sni_challenges
            challenge_objs.append({
                "type": "dvsni",
                "listSNITuple": sni_todo,
                "dvsni_key": os.path.abspath(self.key_file),
            })
            challenge_obj_indices.append(sni_satisfies)
            logger.debug(sni_todo)

        return challenge_objs, challenge_obj_indices
Beispiel #14
0
    def get_key_csr_pem(self, csr_return_format='der'):
        """Return key and CSR, generate if necessary.

        Returns key and CSR using provided files or generating new files
        if necessary. Both will be saved in PEM format on the
        filesystem. The CSR can optionally be returned in DER format as
        the CSR cannot be loaded back into M2Crypto.

        :param csr_return_format: If "der" returned CSR is in DER format,
                                  PEM otherwise.
        :param csr_return_format: str

        :returns: A pair of `(key, csr)`, where `key` is PEM encoded `str`
                  and `csr` is PEM/DER (depedning on `csr_return_format`
                  encoded `str`.
        :rtype: tuple

        """
        key_pem = None
        csr_pem = None
        if not self.key_file:
            key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE)
            # Save file
            le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700)
            key_f, self.key_file = le_util.unique_file(
                os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600)
            key_f.write(key_pem)
            key_f.close()
            logger.info("Generating key: %s" % self.key_file)
        else:
            try:
                key_pem = open(self.key_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open key file: %s" % self.key_file)
                sys.exit(1)

        if not self.csr_file:
            csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names)
            # Save CSR
            le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755)
            csr_f, self.csr_file = le_util.unique_file(
                os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644)
            csr_f.write(csr_pem)
            csr_f.close()
            logger.info("Creating CSR: %s" % self.csr_file)
        else:
            try:
                csr = M2Crypto.X509.load_request(self.csr_file)
                csr_pem, csr_der = csr.as_pem(), csr.as_der()
            except:
                logger.fatal("Unable to open CSR file: %s" % self.csr_file)
                sys.exit(1)

        if csr_return_format == 'der':
            return key_pem, csr_der
        else:
            return key_pem, csr_pem
    def get_key_csr_pem(self, csr_return_format='der'):
        """Return key and CSR, generate if necessary.

        Returns key and CSR using provided files or generating new files
        if necessary. Both will be saved in PEM format on the
        filesystem. The CSR can optionally be returned in DER format as
        the CSR cannot be loaded back into M2Crypto.

        :param csr_return_format: If "der" returned CSR is in DER format,
                                  PEM otherwise.
        :param csr_return_format: str

        :returns: A pair of `(key, csr)`, where `key` is PEM encoded `str`
                  and `csr` is PEM/DER (depedning on `csr_return_format`
                  encoded `str`.
        :rtype: tuple

        """
        key_pem = None
        csr_pem = None
        if not self.key_file:
            key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE)
            # Save file
            le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700)
            key_f, self.key_file = le_util.unique_file(
                os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600)
            key_f.write(key_pem)
            key_f.close()
            logger.info("Generating key: %s" % self.key_file)
        else:
            try:
                key_pem = open(self.key_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open key file: %s" % self.key_file)
                sys.exit(1)

        if not self.csr_file:
            csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names)
            # Save CSR
            le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755)
            csr_f, self.csr_file = le_util.unique_file(
                os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644)
            csr_f.write(csr_pem)
            csr_f.close()
            logger.info("Creating CSR: %s" % self.csr_file)
        else:
            try:
                csr = M2Crypto.X509.load_request(self.csr_file)
                csr_pem, csr_der = csr.as_pem(), csr.as_der()
            except:
                logger.fatal("Unable to open CSR file: %s" % self.csr_file)
                sys.exit(1)

        if csr_return_format == 'der':
            return key_pem, csr_der
        else:
            return key_pem, csr_pem
    def challenge_factory(self, name, challenges, path):
        """

        :param name: TODO
        :type name: TODO

        :param challanges: A list of challenges from ACME "challenge"
                           server message to be fulfilled by the client
                           in order to prove possession of the identifier.
        :type challenges: list

        :param path: List of indices from `challenges`.
        :type path: list

        :returns: A pair of TODO
        :rtype: tuple

        """
        sni_todo = []
        # Since a single invocation of SNI challenge can satisfy multiple
        # challenges. We must keep track of all the challenges it satisfies
        sni_satisfies = []

        challenge_objs = []
        challenge_obj_indices = []
        for index in path:
            chall = challenges[index]

            if chall["type"] == "dvsni":
                logger.info("  DVSNI challenge for name %s." % name)
                sni_satisfies.append(index)
                sni_todo.append((str(name), str(chall["r"]),
                                 str(chall["nonce"])))

            elif chall["type"] == "recoveryToken":
                logger.info("\tRecovery Token Challenge for name: %s." % name)
                challenge_obj_indices.append(index)
                challenge_objs.append({
                    type: "recoveryToken",
                })

            else:
                logger.fatal("Challenge not currently supported")
                sys.exit(82)

        if sni_todo:
            # SNI_Challenge can satisfy many sni challenges at once so only
            # one "challenge object" is issued for all sni_challenges
            challenge_objs.append({
                "type": "dvsni",
                "listSNITuple": sni_todo,
                "dvsni_key": os.path.abspath(self.key_file),
            })
            challenge_obj_indices.append(sni_satisfies)
            logger.debug(sni_todo)

        return challenge_objs, challenge_obj_indices
 def redirect_to_ssl(self, vhost):
     for ssl_vh in vhost:
      success, redirect_vhost = self.config.redirect_all_ssl(ssl_vh)
      logger.info("\nRedirect vhost: " + redirect_vhost.file +
                  " - " + str(success))
      # If successful, make sure redirect site is enabled
      if success:
          if not self.config.is_site_enabled(redirect_vhost.file):
              self.config.enable_site(redirect_vhost)
              logger.info("Enabling available site: " + redirect_vhost.file)
Beispiel #18
0
 def redirect_to_ssl(self, vhost):
     for ssl_vh in vhost:
         success, redirect_vhost = self.config.redirect_all_ssl(ssl_vh)
         logger.info("\nRedirect vhost: " + redirect_vhost.file + " - " +
                     str(success))
         # If successful, make sure redirect site is enabled
         if success:
             if not self.config.is_site_enabled(redirect_vhost.file):
                 self.config.enable_site(redirect_vhost)
                 logger.info("Enabling available site: " +
                             redirect_vhost.file)
Beispiel #19
0
    def acme_certificate(self, csr_der):
        """Handle ACME "certificate" phase.

        :param str csr_der: CSR in DER format.

        :returns: ACME "certificate" message.
        :rtype: dict

        """
        logger.info("Preparing and sending CSR..")
        return self.send_and_receive_expected(
            acme.certificate_request(csr_der, self.privkey.pem), "certificate")
Beispiel #20
0
    def acme_certificate(self, csr_der):
        """Handle ACME "certificate" phase.

        :param csr_der: CSR in DER format.
        :type csr_der: str

        :returns: ACME "certificate" message.
        :rtype: dict

        """
        logger.info("Preparing and sending CSR..")
        return self.send_and_receive_expected(
            acme.certificate_request(csr_der, self.key_file), "certificate")
Beispiel #21
0
    def cleanup_challenges(self, challenges):
        """Cleanup configuration challenges

        :param dict challenges: challenges from a challenge message

        """
        logger.info("Cleaning up challenges...")
        for chall in challenges:
            if chall["type"] in CONFIG.CONFIG_CHALLENGES:
                self.config.cleanup()
            else:
                # Handle other cleanup if needed
                pass
Beispiel #22
0
    def redirect_to_ssl(self, vhost):
        """Redirect all traffic from HTTP to HTTPS

        :param vhost: list of ssl_vhosts
        :type vhost: :class:`apache_configurator.VH`

        """
        for ssl_vh in vhost:
            success, redirect_vhost = self.config.enable_redirect(ssl_vh)
            logger.info("\nRedirect vhost: " + redirect_vhost.file +
                        " - " + str(success))
            # If successful, make sure redirect site is enabled
            if success:
                self.config.enable_site(redirect_vhost)
Beispiel #23
0
    def list_certs_keys(self):
        list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST")
        certs = []

        if not os.path.isfile(list_file):
            logger.info(
                "You don't have any certificates saved from letsencrypt")
            return

        c_sha1_vh = {}
        for (cert, _, path) in self.config.get_all_certs_keys():
            try:
                c_sha1_vh[M2Crypto.X509.load_cert(cert).get_fingerprint(
                    md='sha1')] = path
            except:
                continue

        with open(list_file, 'rb') as csvfile:
            csvreader = csv.reader(csvfile)
            for row in csvreader:
                cert = crypto_util.get_cert_info(row[1])

                b_k = os.path.join(CONFIG.CERT_KEY_BACKUP,
                                   os.path.basename(row[2]) + "_" + row[0])
                b_c = os.path.join(CONFIG.CERT_KEY_BACKUP,
                                   os.path.basename(row[1]) + "_" + row[0])

                cert.update({
                    "orig_key_file":
                    row[2],
                    "orig_cert_file":
                    row[1],
                    "idx":
                    int(row[0]),
                    "backup_key_file":
                    b_k,
                    "backup_cert_file":
                    b_c,
                    "installed":
                    c_sha1_vh.get(cert["fingerprint"], ""),
                })
                certs.append(cert)
        if certs:
            self.choose_certs(certs)
        else:
            display.generic_notification(
                "There are not any trusted Let's Encrypt "
                "certificates for this server.")
    def get_key_csr_pem(self, csr_return_format = 'der'):
        """
        Returns key and CSR using provided files or generating new files if
        necessary. Both will be saved in pem format on the filesystem.
        The CSR can optionally be returned in DER format as the CSR cannot be
        loaded back into M2Crypto.
        """
        key_pem = None
        csr_pem = None
        if not self.key_file:
            key_pem = crypto_util.make_key(RSA_KEY_SIZE)
            # Save file
            le_util.make_or_verify_dir(KEY_DIR, 0700)
            key_f, self.key_file = le_util.unique_file(
                KEY_DIR + "key-letsencrypt.pem", 0600)
            key_f.write(key_pem)
            key_f.close()
            logger.info("Generating key: %s" % self.key_file)
        else:
            try:
                key_pem = open(self.key_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open key file: %s" % self.key_file)
                sys.exit(1)

        if not self.csr_file:
            csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names)
            # Save CSR
            le_util.make_or_verify_dir(CERT_DIR, 0755)
            csr_f, self.csr_file = le_util.unique_file(
                CERT_DIR + "csr-letsencrypt.pem", 0644)
            csr_f.write(csr_pem)
            csr_f.close()
            logger.info("Creating CSR: %s" % self.csr_file)
        else:
            #TODO fix this der situation
            try:
                csr_pem = open(self.csr_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open CSR file: %s" % self.csr_file)
                sys.exit(1)

        if csr_return_format == 'der':
            return key_pem, csr_der

        return key_pem, csr_pem
Beispiel #25
0
    def get_key_csr_pem(self, csr_return_format='der'):
        """
        Returns key and CSR using provided files or generating new files if
        necessary. Both will be saved in pem format on the filesystem.
        The CSR can optionally be returned in DER format as the CSR cannot be
        loaded back into M2Crypto.
        """
        key_pem = None
        csr_pem = None
        if not self.key_file:
            key_pem = crypto_util.make_key(RSA_KEY_SIZE)
            # Save file
            le_util.make_or_verify_dir(KEY_DIR, 0700)
            key_f, self.key_file = le_util.unique_file(
                KEY_DIR + "key-letsencrypt.pem", 0600)
            key_f.write(key_pem)
            key_f.close()
            logger.info("Generating key: %s" % self.key_file)
        else:
            try:
                key_pem = open(self.key_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open key file: %s" % self.key_file)
                sys.exit(1)

        if not self.csr_file:
            csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names)
            # Save CSR
            le_util.make_or_verify_dir(CERT_DIR, 0755)
            csr_f, self.csr_file = le_util.unique_file(
                CERT_DIR + "csr-letsencrypt.pem", 0644)
            csr_f.write(csr_pem)
            csr_f.close()
            logger.info("Creating CSR: %s" % self.csr_file)
        else:
            #TODO fix this der situation
            try:
                csr_pem = open(self.csr_file).read().replace("\r", "")
            except:
                logger.fatal("Unable to open CSR file: %s" % self.csr_file)
                sys.exit(1)

        if csr_return_format == 'der':
            return key_pem, csr_der

        return key_pem, csr_pem
    def is_expected_msg(self, response, expected, delay=3, rounds=20):
        """Is reponse expected ACME message?

        :param response: ACME response message from server.
        :type response: dict

        :param expected: Name of the expected response ACME message type.
        :type expected: str

        :param delay: Number of seconds to delay before next round in case
                      of ACME "defer" response message.
        :type delay: int

        :param rounds: Number of resend attempts in case of ACME "defer"
                       reponse message.
        :type rounds: int

        :raises: Exception

        :returns: ACME response message from server.
        :rtype: dict

        """
        for _ in xrange(rounds):
            if response["type"] == expected:
                return response

            elif response["type"] == "error":
                logger.error("%s: %s - More Info: %s" %
                             (response["error"],
                              response.get("message", ""),
                              response.get("moreInfo", "")))
                raise errors.LetsEncryptClientError(response["error"])

            elif response["type"] == "defer":
                logger.info("Waiting for %d seconds..." % delay)
                time.sleep(delay)
                response = self.send(acme.status_request(response["token"]))
            else:
                logger.fatal("Received unexpected message")
                logger.fatal("Expected: %s" % expected)
                logger.fatal("Received: " + response)
                sys.exit(33)

        logger.error("Server has deferred past the max of %d seconds" %
                     (rounds * delay))
Beispiel #27
0
    def is_expected_msg(self, response, expected, delay=3, rounds=20):
        """Is reponse expected ACME message?

        :param response: ACME response message from server.
        :type response: dict

        :param expected: Name of the expected response ACME message type.
        :type expected: str

        :param delay: Number of seconds to delay before next round in case
                      of ACME "defer" response message.
        :type delay: int

        :param rounds: Number of resend attempts in case of ACME "defer"
                       reponse message.
        :type rounds: int

        :raises: Exception

        :returns: ACME response message from server.
        :rtype: dict

        """
        for _ in xrange(rounds):
            if response["type"] == expected:
                return response

            elif response["type"] == "error":
                logger.error("%s: %s - More Info: %s" %
                             (response["error"], response.get(
                                 "message", ""), response.get("moreInfo", "")))
                raise errors.LetsEncryptClientError(response["error"])

            elif response["type"] == "defer":
                logger.info("Waiting for %d seconds..." % delay)
                time.sleep(delay)
                response = self.send(acme.status_request(response["token"]))
            else:
                logger.fatal("Received unexpected message")
                logger.fatal("Expected: %s" % expected)
                logger.fatal("Received: " + response)
                sys.exit(33)

        logger.error("Server has deferred past the max of %d seconds" %
                     (rounds * delay))
Beispiel #28
0
    def init_key_csr(self):
        """Initializes privkey and csr.

        Inits key and CSR using provided files or generating new files
        if necessary. Both will be saved in PEM format on the
        filesystem. The CSR is placed into DER format to allow
        the namedtuple to easily work with the protocol.

        """
        if not self.privkey.file:
            key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE)

            # Save file
            le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700)
            key_f, key_filename = le_util.unique_file(
                os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600)
            key_f.write(key_pem)
            key_f.close()

            logger.info("Generating key: %s" % key_filename)

            self.privkey = Client.Key(key_filename, key_pem)

        if not self.csr.file:
            csr_pem, csr_der = crypto_util.make_csr(
                self.privkey.pem, self.names)

            # Save CSR
            le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755)
            csr_f, csr_filename = le_util.unique_file(
                os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644)
            csr_f.write(csr_pem)
            csr_f.close()

            logger.info("Creating CSR: %s" % csr_filename)

            self.csr = Client.CSR(csr_filename, csr_der, "der")
        elif self.csr.type != "der":
            # The user is going to pass in a pem format file
            # That is why we must conver it to der since the
            # protocol uses der exclusively.
            csr_obj = M2Crypto.X509.load_request_string(self.csr.data)
            self.csr = Client.CSR(self.csr.file, csr_obj.as_der(), "der")
Beispiel #29
0
    def list_certs_keys(self):
        """List trusted Let's Encrypt certificates."""
        list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST")
        certs = []

        if not os.path.isfile(list_file):
            logger.info(
                "You don't have any certificates saved from letsencrypt")
            return

        c_sha1_vh = {}
        for (cert, _, path) in self.config.get_all_certs_keys():
            try:
                c_sha1_vh[M2Crypto.X509.load_cert(
                    cert).get_fingerprint(md='sha1')] = path
            except:
                continue

        with open(list_file, 'rb') as csvfile:
            csvreader = csv.reader(csvfile)
            for row in csvreader:
                cert = crypto_util.get_cert_info(row[1])

                b_k = os.path.join(CONFIG.CERT_KEY_BACKUP,
                                   os.path.basename(row[2]) + "_" + row[0])
                b_c = os.path.join(CONFIG.CERT_KEY_BACKUP,
                                   os.path.basename(row[1]) + "_" + row[0])

                cert.update({
                    "orig_key_file": row[2],
                    "orig_cert_file": row[1],
                    "idx": int(row[0]),
                    "backup_key_file": b_k,
                    "backup_cert_file": b_c,
                    "installed": c_sha1_vh.get(cert["fingerprint"], ""),
                })
                certs.append(cert)
        if certs:
            self.choose_certs(certs)
        else:
            display.generic_notification(
                "There are not any trusted Let's Encrypt "
                "certificates for this server.")
    def install_certificate(self, certificate_dict, vhost):
        cert_chain_abspath = None
        cert_fd, self.cert_file = le_util.unique_file(CERT_PATH, 644)
        cert_fd.write(
            crypto_util.b64_cert_to_pem(certificate_dict["certificate"]))
        cert_fd.close()
        logger.info("Server issued certificate; certificate written to %s" %
                    self.cert_file)

        if certificate_dict.get("chain", None):
            chain_fd, chain_fn = le_util.unique_file(CHAIN_PATH, 644)
            for c in certificate_dict.get("chain", []):
                chain_fd.write(crypto_util.b64_cert_to_pem(c))
            chain_fd.close()

            logger.info("Cert chain written to %s" % chain_fn)

            # This expects a valid chain file
            cert_chain_abspath = os.path.abspath(chain_fn)

        for host in vhost:
            self.config.deploy_cert(host,
                                    os.path.abspath(self.cert_file),
                                    os.path.abspath(self.key_file),
                                    cert_chain_abspath)
            # Enable any vhost that was issued to, but not enabled
            if not host.enabled:
                logger.info("Enabling Site " + host.file)
                self.config.enable_site(host)

        # sites may have been enabled / final cleanup
        self.config.restart(quiet=self.curses)

        display.success_installation(self.names)
Beispiel #31
0
    def verify_identity(self, challenge_msg):
        """Verify identity.

        :param challenge_msg: ACME "challenge" message.
        :type challenge_msg: dict

        :returns: TODO
        :rtype: dict

        """
        path = challenge.gen_challenge_path(
            challenge_msg["challenges"], challenge_msg.get("combinations", []))

        logger.info("Performing the following challenges:")

        # Every indices element is a list of integers referring to which
        # challenges in the master list the challenge object satisfies
        # Single Challenge objects that can satisfy multiple server challenges
        # mess up the order of the challenges, thus requiring the indices
        challenge_objs, indices = self.challenge_factory(
            self.names[0], challenge_msg["challenges"], path)

        responses = ["null"] * len(challenge_msg["challenges"])

        # Perform challenges
        for i, c_obj in enumerate(challenge_objs):
            response = "null"
            if c_obj["type"] in CONFIG.CONFIG_CHALLENGES:
                response = self.config.perform(c_obj)
            else:
                # Handle RecoveryToken type challenges
                pass

            for index in indices[i]:
                responses[index] = response

        logger.info("Configured Apache for challenges; " +
                    "waiting for verification...")

        return responses, challenge_objs
Beispiel #32
0
    def install_certificate(self, certificate_dict, vhost):
        cert_chain_abspath = None
        cert_fd, self.cert_file = le_util.unique_file(CERT_PATH, 644)
        cert_fd.write(
            crypto_util.b64_cert_to_pem(certificate_dict["certificate"]))
        cert_fd.close()
        logger.info("Server issued certificate; certificate written to %s" %
                    self.cert_file)

        if certificate_dict.get("chain", None):
            chain_fd, chain_fn = le_util.unique_file(CHAIN_PATH, 644)
            for c in certificate_dict.get("chain", []):
                chain_fd.write(crypto_util.b64_cert_to_pem(c))
            chain_fd.close()

            logger.info("Cert chain written to %s" % chain_fn)

            # This expects a valid chain file
            cert_chain_abspath = os.path.abspath(chain_fn)

        for host in vhost:
            self.config.deploy_cert(host, os.path.abspath(self.cert_file),
                                    os.path.abspath(self.key_file),
                                    cert_chain_abspath)
            # Enable any vhost that was issued to, but not enabled
            if not host.enabled:
                logger.info("Enabling Site " + host.file)
                self.config.enable_site(host)

        # sites may have been enabled / final cleanup
        self.config.restart(quiet=self.curses)

        display.success_installation(self.names)
Beispiel #33
0
    def is_expected_msg(self, msg_dict, expected, delay=3, rounds=20):
        for i in range(rounds):
            if msg_dict["type"] == expected:
                return msg_dict

            elif msg_dict["type"] == "error":
                logger.error("%s: %s - More Info: %s" %
                             (msg_dict["error"], msg_dict.get(
                                 "message", ""), msg_dict.get("moreInfo", "")))
                raise Exception(msg_dict["error"])

            elif msg_dict["type"] == "defer":
                logger.info("Waiting for %d seconds..." % delay)
                time.sleep(delay)
                msg_dict = self.send(self.status_request(msg_dict["token"]))
            else:
                logger.fatal("Received unexpected message")
                logger.fatal("Expected: %s" % expected)
                logger.fatal("Received: " + msg_dict)
                sys.exit(33)

        logger.error("Server has deferred past the max of %d seconds" %
                     (rounds * delay))
        return None
    def list_certs_keys(self):
        list_file = CERT_KEY_BACKUP + "LIST"
        certs = []

        if not os.path.isfile(CERT_KEY_BACKUP + "LIST"):
            logger.info("You don't have any certificates saved from letsencrypt")
            return

        c_sha1_vh = {}
        for x in self.config.get_all_certs_keys():
            try:
                c_sha1_vh[M2Crypto.X509.load_cert(x[0]).get_fingerprint(md='sha1')] = x[2]
            except:
                continue

        with open(list_file, 'rb') as csvfile:
            csvreader = csv.reader(csvfile)
            for row in csvreader:
                c = crypto_util.get_cert_info(row[1])

                b_k = CERT_KEY_BACKUP + os.path.basename(row[2]) + "_" + row[0]
                b_c = CERT_KEY_BACKUP + os.path.basename(row[1]) + "_" + row[0]

                c["orig_key_file"] = row[2]
                c["orig_cert_file"] = row[1]
                c["idx"] = int(row[0])
                c["backup_key_file"] = b_k
                c["backup_cert_file"] = b_c
                c["installed"] = c_sha1_vh.get(c["fingerprint"], "")

                certs.append(c)
        if certs:
            self.choose_certs(certs)
        else:
            display.generic_notification("There are not any trusted \
            Let's Encrypt certificates for this server.")
 def cleanup_challenges(self, challenge_objs):
     logger.info("Cleaning up challenges...")
     for c in challenge_objs:
         c.cleanup()
Beispiel #36
0
 def cleanup_challenges(self, challenge_objs):
     logger.info("Cleaning up challenges...")
     for c in challenge_objs:
         c.cleanup()
Beispiel #37
0
    def authenticate(self, domains=[], redirect=None, eula=False):
        # Check configuration
        if not self.config.configtest():
            sys.exit(1)

        self.redirect = redirect

        # Display preview warning
        if not eula:
            with open('EULA') as f:
                if not display.generic_yesno(f.read()):
                    sys.exit(0)

        # Display screen to select domains to validate
        if domains:
            self.sanity_check_names([self.server] + domains)
            self.names = domains
        else:
            # This function adds all names
            # found within the config to self.names
            # Then filters them based on user selection
            code, self.names = display.filter_names(self.get_all_names())
            if code == display.OK:
                # TODO: Allow multiple names once it is setup
                self.names = [self.names[0]]
            else:
                sys.exit(0)

        # Display choice of CA screen
        # TODO: Use correct server depending on CA
        #choice = self.choice_of_ca()

        # Check first if mod_ssl is loaded
        if not self.config.check_ssl_loaded():
            logger.info("Loading mod_ssl into Apache Server")
            self.config.enable_mod("ssl")

        #Request Challenges
        challenge_dict = self.handle_challenge()

        # Get key and csr to perform challenges
        key_pem, csr_der = self.get_key_csr_pem()

        #Perform Challenges
        responses, challenge_objs = self.verify_identity(challenge_dict)
        # Get Authorization
        self.handle_authorization(challenge_dict, challenge_objs, responses)

        # Retrieve certificate
        certificate_dict = self.handle_certificate(csr_der)

        # Find set of virtual hosts to deploy certificates to
        vhost = self.get_virtual_hosts(self.names)

        # Install Certificate
        self.install_certificate(certificate_dict, vhost)

        # Perform optimal config changes
        self.optimize_config(vhost)

        self.config.save("Completed Augeas Authentication")

        self.store_cert_key(False)

        return
 def certificate_request(self, csr_der, key):
     logger.info("Preparing and sending CSR..")
     return {"type":"certificateRequest",
             "csr":jose.b64encode_url(csr_der),
             "signature":crypto_util.create_sig(csr_der, self.key_file)}
    def authenticate(self, domains = [], redirect = None, eula = False):
        # Check configuration
        if not self.config.configtest():
            sys.exit(1)

        self.redirect = redirect

        # Display preview warning
        if not eula:
            with open('EULA') as f:
                if not display.generic_yesno(f.read()):
                    sys.exit(0)

        # Display screen to select domains to validate
        if domains:
            self.sanity_check_names([self.server] + domains)
            self.names = domains
        else:
            # This function adds all names
            # found within the config to self.names
            # Then filters them based on user selection
            code, self.names = display.filter_names(self.get_all_names())
            if code == display.OK and self.names:
                # TODO: Allow multiple names once it is setup
                self.names = [self.names[0]]
            else:
                sys.exit(0)

        # Display choice of CA screen
        # TODO: Use correct server depending on CA
        #choice = self.choice_of_ca()

        # Check first if mod_ssl is loaded
        if not self.config.check_ssl_loaded():
            logger.info("Loading mod_ssl into Apache Server")
            self.config.enable_mod("ssl")

        #Request Challenges
        challenge_dict = self.handle_challenge()

        # Get key and csr to perform challenges
        key_pem, csr_der = self.get_key_csr_pem()

        #Perform Challenges
        responses, challenge_objs = self.verify_identity(challenge_dict)
        # Get Authorization
        self.handle_authorization(challenge_dict, challenge_objs, responses)

        # Retrieve certificate
        certificate_dict = self.handle_certificate(csr_der)


        # Find set of virtual hosts to deploy certificates to
        vhost = self.get_virtual_hosts(self.names)

        # Install Certificate
        self.install_certificate(certificate_dict, vhost)

        # Perform optimal config changes
        self.optimize_config(vhost)

        self.config.save("Completed Augeas Authentication")

        self.store_cert_key(False)

        return