コード例 #1
0
def init_save_csr(privkey, names, path, csrname="csr-certbot.pem"):
    """Initialize a CSR with the given private key.

    :param privkey: Key to include in the CSR
    :type privkey: :class:`certbot.le_util.Key`

    :param set names: `str` names to include in the CSR

    :param str path: Certificate save directory.

    :returns: CSR
    :rtype: :class:`certbot.le_util.CSR`

    """
    config = zope.component.getUtility(interfaces.IConfig)

    csr_pem, csr_der = make_csr(privkey.pem, names,
        must_staple=config.must_staple)

    # Save CSR
    le_util.make_or_verify_dir(path, 0o755, os.geteuid(),
                               config.strict_permissions)
    csr_f, csr_filename = le_util.unique_file(
        os.path.join(path, csrname), 0o644)
    csr_f.write(csr_pem)
    csr_f.close()

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

    return le_util.CSR(csr_filename, csr_der, "der")
コード例 #2
0
    def test_obtain_certificate(self, mock_crypto_util):
        self._mock_obtain_certificate()

        csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
        mock_crypto_util.init_save_csr.return_value = csr
        mock_crypto_util.init_save_key.return_value = mock.sentinel.key
        domains = ["example.com", "www.example.com"]

        # return_value is essentially set to (None, None) in
        # _mock_obtain_certificate(), which breaks this test.
        # Thus fixed by the next line.

        authzr = []

        for domain in domains:
            authzr.append(
                mock.MagicMock(
                    body=mock.MagicMock(
                        identifier=mock.MagicMock(
                            value=domain))))

        self.client.auth_handler.get_authorizations.return_value = authzr

        self.assertEqual(
            self.client.obtain_certificate(domains),
            (mock.sentinel.certr, mock.sentinel.chain, mock.sentinel.key, csr))

        mock_crypto_util.init_save_key.assert_called_once_with(
            self.config.rsa_key_size, self.config.key_dir)
        mock_crypto_util.init_save_csr.assert_called_once_with(
            mock.sentinel.key, domains, self.config.csr_dir)
        self._check_obtain_certificate()
コード例 #3
0
    def test_obtain_certificate_from_csr(self, mock_logger):
        self._mock_obtain_certificate()
        test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
        auth_handler = self.client.auth_handler

        authzr = auth_handler.get_authorizations(self.eg_domains, False)
        self.assertEqual(
            (mock.sentinel.certr, mock.sentinel.chain),
            self.client.obtain_certificate_from_csr(
                self.eg_domains,
                test_csr,
                authzr=authzr))
        # and that the cert was obtained correctly
        self._check_obtain_certificate()

        # Test for authzr=None
        self.assertEqual(
            (mock.sentinel.certr, mock.sentinel.chain),
            self.client.obtain_certificate_from_csr(
                self.eg_domains,
                test_csr,
                authzr=None))
        auth_handler.get_authorizations.assert_called_with(self.eg_domains)

        # Test for no auth_handler
        self.client.auth_handler = None
        self.assertRaises(
            errors.Error,
            self.client.obtain_certificate_from_csr,
            self.eg_domains,
            test_csr)
        mock_logger.warning.assert_called_once_with(mock.ANY)
コード例 #4
0
    def handle_csr(self, parsed_args):
        """Process a --csr flag."""
        if parsed_args.verb != "certonly":
            raise errors.Error("Currently, a CSR file may only be specified "
                               "when obtaining a new or replacement "
                               "via the certonly command. Please try the "
                               "certonly command instead.")

        try:
            csr = le_util.CSR(file=parsed_args.csr[0],
                              data=parsed_args.csr[1],
                              form="der")
            typ = OpenSSL.crypto.FILETYPE_ASN1
            domains = crypto_util.get_sans_from_csr(
                csr.data, OpenSSL.crypto.FILETYPE_ASN1)
        except OpenSSL.crypto.Error:
            try:
                e1 = traceback.format_exc()
                typ = OpenSSL.crypto.FILETYPE_PEM
                csr = le_util.CSR(file=parsed_args.csr[0],
                                  data=parsed_args.csr[1],
                                  form="pem")
                domains = crypto_util.get_sans_from_csr(csr.data, typ)
            except OpenSSL.crypto.Error:
                logger.debug("DER CSR parse error %s", e1)
                logger.debug("PEM CSR parse error %s", traceback.format_exc())
                raise errors.Error("Failed to parse CSR file: {0}".format(
                    parsed_args.csr[0]))

        # This is not necessary for webroot to work, however,
        # obtain_certificate_from_csr requires parsed_args.domains to be set
        for domain in domains:
            add_domains(parsed_args, domain)

        if not domains:
            # TODO: add CN to domains instead:
            raise errors.Error(
                "Unfortunately, your CSR %s needs to have a SubjectAltName for every domain"
                % parsed_args.csr[0])

        parsed_args.actual_csr = (csr, typ)
        csr_domains, config_domains = set(domains), set(parsed_args.domains)
        if csr_domains != config_domains:
            raise errors.ConfigurationError(
                "Inconsistent domain requests:\nFrom the CSR: {0}\nFrom command line/config: {1}"
                .format(", ".join(csr_domains), ", ".join(config_domains)))
コード例 #5
0
    def test_pem_csr(self):
        csrfile = test_util.vector_path('csr.pem')
        data = test_util.load_vector('csr.pem')

        self.assertEqual((
            OpenSSL.crypto.FILETYPE_PEM,
            le_util.CSR(file=csrfile, data=data, form="pem"),
            ["example.com"],
        ), self._call(csrfile, data))
コード例 #6
0
    def test_obtain_certificate_from_csr(self, mock_logger):
        self._mock_obtain_certificate()
        from certbot import cli
        test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
        mock_parsed_args = mock.MagicMock()
        # The CLI should believe that this is a certonly request, because
        # a CSR would not be allowed with other kinds of requests!
        mock_parsed_args.verb = "certonly"
        with mock.patch("certbot.client.le_util.CSR") as mock_CSR:
            mock_CSR.return_value = test_csr
            mock_parsed_args.domains = self.eg_domains[:]
            mock_parser = mock.MagicMock(cli.HelpfulArgumentParser)
            cli.HelpfulArgumentParser.handle_csr(mock_parser, mock_parsed_args)

            # Now provoke an inconsistent domains error...
            mock_parsed_args.domains.append("hippopotamus.io")
            self.assertRaises(errors.ConfigurationError,
                cli.HelpfulArgumentParser.handle_csr, mock_parser, mock_parsed_args)

            authzr = self.client.auth_handler.get_authorizations(self.eg_domains, False)

            self.assertEqual(
                (mock.sentinel.certr, mock.sentinel.chain),
                self.client.obtain_certificate_from_csr(
                    self.eg_domains,
                    test_csr,
                    authzr=authzr))
            # and that the cert was obtained correctly
            self._check_obtain_certificate()

            # Test for authzr=None
            self.assertEqual(
                (mock.sentinel.certr, mock.sentinel.chain),
                self.client.obtain_certificate_from_csr(
                    self.eg_domains,
                    test_csr,
                    authzr=None))

            self.client.auth_handler.get_authorizations.assert_called_with(
            self.eg_domains)

            # Test for no auth_handler
            self.client.auth_handler = None
            self.assertRaises(
                errors.Error,
                self.client.obtain_certificate_from_csr,
                self.eg_domains,
                test_csr)
            mock_logger.warning.assert_called_once_with(mock.ANY)
コード例 #7
0
ファイル: client.py プロジェクト: paribr/letsencrypt-1
def validate_key_csr(privkey, csr=None):
    """Validate Key and CSR files.

    Verifies that the client key and csr arguments are valid and correspond to
    one another. This does not currently check the names in the CSR due to
    the inability to read SANs from CSRs in python crypto libraries.

    If csr is left as None, only the key will be validated.

    :param privkey: Key associated with CSR
    :type privkey: :class:`certbot.le_util.Key`

    :param .le_util.CSR csr: CSR

    :raises .errors.Error: when validation fails

    """
    # TODO: Handle all of these problems appropriately
    # The client can eventually do things like prompt the user
    # and allow the user to take more appropriate actions

    # Key must be readable and valid.
    if privkey.pem and not crypto_util.valid_privkey(privkey.pem):
        raise errors.Error("The provided key is not a valid key")

    if csr:
        if csr.form == "der":
            csr_obj = OpenSSL.crypto.load_certificate_request(
                OpenSSL.crypto.FILETYPE_ASN1, csr.data)
            csr = le_util.CSR(
                csr.file,
                OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                                csr_obj), "pem")

        # If CSR is provided, it must be readable and valid.
        if csr.data and not crypto_util.valid_csr(csr.data):
            raise errors.Error("The provided CSR is not a valid CSR")

        # If both CSR and key are provided, the key must be the same key used
        # in the CSR.
        if csr.data and privkey.pem:
            if not crypto_util.csr_matches_pubkey(csr.data, privkey.pem):
                raise errors.Error("The key and CSR do not match")
コード例 #8
0
def import_csr_file(csrfile, data):
    """Import a CSR file, which can be either PEM or DER.

    :param str csrfile: CSR filename
    :param str data: contents of the CSR file

    :returns: (`OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1`,
               le_util.CSR object representing the CSR,
               list of domains requested in the CSR)
    :rtype: tuple

    """
    for form, typ in (("der", OpenSSL.crypto.FILETYPE_ASN1,),
                      ("pem", OpenSSL.crypto.FILETYPE_PEM,),):
        try:
            domains = get_names_from_csr(data, typ)
        except OpenSSL.crypto.Error:
            logger.debug("CSR parse error (form=%s, typ=%s):", form, typ)
            logger.debug(traceback.format_exc())
            continue
        return typ, le_util.CSR(file=csrfile, data=data, form=form), domains
    raise errors.Error("Failed to parse CSR file: {0}".format(csrfile))