def test_obtain_certificate_from_csr(self, unused_mock_get_utility, mock_logger): self._mock_obtain_certificate() test_csr = util.CSR(form="pem", 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)
def test_obtain_certificate(self, unused_mock_get_utility, mock_crypto_util): self._mock_obtain_certificate() csr = util.CSR(form="pem", 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 = [] # domain ordering should not be affected by authorization order for domain in reversed(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()
def init_save_csr(privkey, names, path): """Initialize a CSR with the given private key. :param privkey: Key to include in the CSR :type privkey: :class:`certbot.util.Key` :param set names: `str` names to include in the CSR :param str path: Certificate save directory. :returns: CSR :rtype: :class:`certbot.util.CSR` """ config = zope.component.getUtility(interfaces.IConfig) csr_pem = acme_crypto_util.make_csr(privkey.pem, names, must_staple=config.must_staple) # Save CSR util.make_or_verify_dir(path, 0o755, compat.os_geteuid(), config.strict_permissions) csr_f, csr_filename = util.unique_file( os.path.join(path, "csr-certbot.pem"), 0o644, "wb") with csr_f: csr_f.write(csr_pem) logger.debug("Creating CSR: %s", csr_filename) return util.CSR(csr_filename, csr_pem, "pem")
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: (`crypto.FILETYPE_PEM`, util.CSR object representing the CSR, list of domains requested in the CSR) :rtype: tuple """ PEM = crypto.FILETYPE_PEM load = crypto.load_certificate_request try: # Try to parse as DER first, then fall back to PEM. csr = load(crypto.FILETYPE_ASN1, data) except crypto.Error: try: csr = load(PEM, data) except crypto.Error: raise errors.Error("Failed to parse CSR file: {0}".format(csrfile)) domains = _get_names_from_loaded_cert_or_req(csr) # Internally we always use PEM, so re-encode as PEM before returning. data_pem = crypto.dump_certificate_request(PEM, csr) return PEM, util.CSR(file=csrfile, data=data_pem, form="pem"), domains
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`, 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, util.CSR(file=csrfile, data=data, form=form), domains raise errors.Error("Failed to parse CSR file: {0}".format(csrfile))
def test_obtain_certificate_from_csr(self, unused_mock_get_utility, mock_logger, mock_crypto_util): self._mock_obtain_certificate() test_csr = util.CSR(form="pem", file=None, data=CSR_SAN) auth_handler = self.client.auth_handler self._set_mock_from_fullchain( mock_crypto_util.cert_and_chain_from_fullchain) orderr = self.acme.new_order(test_csr.data) auth_handler.handle_authorizations(orderr, False) self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=orderr)) # and that the cert was obtained correctly self._check_obtain_certificate() # Test for orderr=None self.assertEqual((mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=None)) auth_handler.handle_authorizations.assert_called_with( self.eg_order, False) # Test for no auth_handler self.client.auth_handler = None self.assertRaises(errors.Error, self.client.obtain_certificate_from_csr, test_csr) mock_logger.warning.assert_called_once_with(mock.ANY)
def test_obtain_certificate_dry_run(self, mock_acme_crypto, mock_crypto): csr = util.CSR(form="pem", file=None, data=CSR_SAN) mock_acme_crypto.make_csr.return_value = CSR_SAN mock_crypto.make_key.return_value = mock.sentinel.key_pem key = util.Key(file=None, pem=mock.sentinel.key_pem) self._set_mock_from_fullchain( mock_crypto.cert_and_chain_from_fullchain) self.client.config.dry_run = True self._test_obtain_certificate_common(key, csr) mock_crypto.make_key.assert_called_once_with({ "type": self.config.key_type, "curve": self.config.elliptic_curve, "size": self.config.rsa_key_size, }) mock_acme_crypto.make_csr.assert_called_once_with( mock.sentinel.key_pem, self.eg_domains, self.config.must_staple) mock_crypto.init_save_key.assert_not_called() mock_crypto.init_save_csr.assert_not_called() self.assertEqual(mock_crypto.cert_and_chain_from_fullchain.call_count, 1)
def test_der_csr(self): csrfile = test_util.vector_path('csr.der') data = test_util.load_vector('csr.der') self.assertEqual(( OpenSSL.crypto.FILETYPE_ASN1, util.CSR(file=csrfile, data=data, form="der"), ["example.com"], ), self._call(csrfile, data))
def test_pem_csr(self): csrfile = test_util.vector_path('csr_512.pem') data = test_util.load_vector('csr_512.pem') self.assertEqual(( OpenSSL.crypto.FILETYPE_PEM, util.CSR(file=csrfile, data=data, form="pem"), ["Example.com"], ), self._call(csrfile, data))
def test_obtain_certificate_from_csr(self, mock_logger, mock_crypto_util): self._mock_obtain_certificate() test_csr = util.CSR(form="pem", file=None, data=CSR_SAN) auth_handler = self.client.auth_handler self._set_mock_from_fullchain( mock_crypto_util.cert_and_chain_from_fullchain) orderr = self.acme.new_order(test_csr.data) auth_handler.handle_authorizations(orderr, self.config, False) self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=orderr)) mock_crypto_util.find_chain_with_issuer.assert_not_called() # and that the cert was obtained correctly self._check_obtain_certificate() # Test that --preferred-chain results in chain selection self.config.preferred_chain = "some issuer" self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=orderr)) mock_crypto_util.find_chain_with_issuer.assert_called_once_with( [orderr.fullchain_pem] + orderr.alternative_fullchains_pem, "some issuer", True) self.config.preferred_chain = None # Test for default issuance_timeout expected_deadline = \ datetime.datetime.now() + datetime.timedelta( seconds=constants.CLI_DEFAULTS["issuance_timeout"]) self.client.obtain_certificate_from_csr(test_csr, orderr=orderr) ((_, deadline), _) = self.client.acme.finalize_order.call_args self.assertTrue( abs(expected_deadline - deadline) <= datetime.timedelta(seconds=1)) # Test for specific issuance_timeout (300 seconds) expected_deadline = \ datetime.datetime.now() + datetime.timedelta(seconds=300) self.config.issuance_timeout = 300 self.client.obtain_certificate_from_csr(test_csr, orderr=orderr) ((_, deadline), _) = self.client.acme.finalize_order.call_args self.assertTrue( abs(expected_deadline - deadline) <= datetime.timedelta(seconds=1)) # Test for orderr=None self.assertEqual((mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=None)) auth_handler.handle_authorizations.assert_called_with( self.eg_order, self.config, False) # Test for no auth_handler self.client.auth_handler = None self.assertRaises(errors.Error, self.client.obtain_certificate_from_csr, test_csr) mock_logger.error.assert_called_once_with(mock.ANY)
def init_save_csr(privkey, email, config, usage): path = config.csr_dir csr_pem = make(privkey.pem, email, usage) util.make_or_verify_dir(path, 0o755, config.strict_permissions) csr_f, csr_filename = util.unique_file( os.path.join(path, 'csr-certbot.pem'), 0o644, "wb") with csr_f: csr_f.write(csr_pem) logger.debug("Creating CSR: %s", csr_filename) return util.CSR(csr_filename, csr_pem, "pem")
def test_obtain_certificate_from_csr_retry_failed(self, mock_get_utility): self._mock_obtain_certificate() self.acme.fetch_chain.side_effect = acme_errors.Error test_csr = util.CSR(form="der", file=None, data=CSR_SAN) orderr = self.acme.new_order(test_csr.data) self.assertRaises(acme_errors.Error, self.client.obtain_certificate_from_csr, test_csr, orderr=orderr) self.assertEqual(1, mock_get_utility().notification.call_count)
def test_obtain_certificate(self, mock_crypto_util): csr = util.CSR(form="pem", 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 self._test_obtain_certificate_common(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, self.eg_domains, self.config.csr_dir)
def test_obtain_certificate_partial_success(self, mock_remove, mock_crypto_util): csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN) key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN) mock_crypto_util.init_save_csr.return_value = csr mock_crypto_util.init_save_key.return_value = key self._set_mock_from_fullchain( mock_crypto_util.cert_and_chain_from_fullchain) authzr = self._authzr_from_domains(["example.com"]) self.config.allow_subset_of_names = True self._test_obtain_certificate_common(key, csr, authzr_ret=authzr, auth_count=2) self.assertEqual(mock_crypto_util.init_save_key.call_count, 2) self.assertEqual(mock_crypto_util.init_save_csr.call_count, 2) self.assertEqual(mock_remove.call_count, 2) self.assertEqual( mock_crypto_util.cert_and_chain_from_fullchain.call_count, 1)
def test_obtain_certificate_from_csr_retry_succeeded( self, mock_get_utility): self._mock_obtain_certificate() self.acme.fetch_chain.side_effect = [ acme_errors.Error, mock.sentinel.chain ] test_csr = util.CSR(form="der", file=None, data=CSR_SAN) orderr = self.acme.new_order(test_csr.data) self.assertEqual( (mock.sentinel.certr, mock.sentinel.chain), self.client.obtain_certificate_from_csr(test_csr, orderr=orderr)) self.assertEqual(1, mock_get_utility().notification.call_count)
def test_obtain_certificate_from_csr_retry_failed(self, mock_get_utility): self._mock_obtain_certificate() self.acme.fetch_chain.side_effect = acme_errors.Error test_csr = 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.assertRaises(acme_errors.Error, self.client.obtain_certificate_from_csr, self.eg_domains, test_csr, authzr=authzr) self.assertEqual(1, mock_get_utility().notification.call_count)
def test_obtain_certificate_get_order_rejected_identifier_no_subproblems(self, mock_crypto_util): from acme import messages csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN) key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN) mock_crypto_util.generate_csr.return_value = csr mock_crypto_util.generate_key.return_value = key self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain) self._mock_obtain_certificate() authzr = self._authzr_from_domains(self.eg_domains) self.eg_order.authorizations = authzr self.client.auth_handler.handle_authorizations.return_value = authzr error = messages.Error.with_code('caa', detail='foo', title='title') self.client.acme.new_order.side_effect = error self.config.allow_subset_of_names = True self.assertRaises(messages.Error, self.client.obtain_certificate, self.eg_domains) self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 0) self.assertEqual(self.acme.new_order.call_count, 1) self.assertEqual(mock_crypto_util.generate_key.call_count, 1) self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 0)
def test_obtain_certificate_dry_run(self, mock_acme_crypto, mock_crypto): csr = util.CSR(form="pem", file=None, data=CSR_SAN) mock_acme_crypto.make_csr.return_value = CSR_SAN mock_crypto.make_key.return_value = mock.sentinel.key_pem key = util.Key(file=None, pem=mock.sentinel.key_pem) self.client.config.dry_run = True self._test_obtain_certificate_common(key, csr) mock_crypto.make_key.assert_called_once_with(self.config.rsa_key_size) mock_acme_crypto.make_csr.assert_called_once_with( mock.sentinel.key_pem, self.eg_domains, self.config.must_staple) mock_crypto.init_save_key.assert_not_called() mock_crypto.init_save_csr.assert_not_called()
def test_obtain_certificate_get_order_partial_success(self, mock_remove, mock_crypto_util): from acme import messages csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN) key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN) mock_crypto_util.generate_csr.return_value = csr mock_crypto_util.generate_key.return_value = key self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain) self._mock_obtain_certificate() authzr = self._authzr_from_domains(self.eg_domains) self.eg_order.authorizations = authzr self.client.auth_handler.handle_authorizations.return_value = authzr identifier = messages.Identifier(typ=messages.IDENTIFIER_FQDN, value='example.com') subproblem = messages.Error.with_code('caa', detail='bar', title='title', identifier=identifier) error_with_subproblems = messages.Error.with_code('malformed', detail='foo', title='title', subproblems=[subproblem]) self.client.acme.new_order.side_effect = [error_with_subproblems, mock.DEFAULT] self.config.allow_subset_of_names = True with test_util.patch_display_util(): result = self.client.obtain_certificate(self.eg_domains) self.assertEqual( result, (mock.sentinel.cert, mock.sentinel.chain, key, csr)) self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 1) self.assertEqual(self.acme.new_order.call_count, 2) successful_domains = [d for d in self.eg_domains if d != 'example.com'] self.assertEqual(mock_crypto_util.generate_key.call_count, 2) mock_crypto_util.generate_csr.assert_has_calls([ mock.call(key, self.eg_domains, self.config.csr_dir, self.config.must_staple, self.config.strict_permissions), mock.call(key, successful_domains, self.config.csr_dir, self.config.must_staple, self.config.strict_permissions)]) self.assertEqual(mock_remove.call_count, 2) self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 1)
def obtain_certificate(self, domains): """Obtains a certificate from the ACME server. `.register` must be called before `.obtain_certificate` :param list domains: domains to get a certificate :returns: certificate as PEM string, chain as PEM string, newly generated private key (`.util.Key`), and DER-encoded Certificate Signing Request (`.util.CSR`). :rtype: tuple """ # Create CSR from names if self.config.dry_run: key = util.Key(file=None, pem=crypto_util.make_key(self.config.rsa_key_size)) csr = util.CSR(file=None, form="pem", data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: key = crypto_util.init_save_key(self.config.rsa_key_size, self.config.key_dir) csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir) orderr = self._get_order_and_authorizations( csr.data, self.config.allow_subset_of_names) authzr = orderr.authorizations auth_domains = set(a.body.identifier.value for a in authzr) successful_domains = [d for d in domains if d in auth_domains] # allow_subset_of_names is currently disabled for wildcard # certificates. The reason for this and checking allow_subset_of_names # below is because successful_domains == domains is never true if # domains contains a wildcard because the ACME spec forbids identifiers # in authzs from containing a wildcard character. if self.config.allow_subset_of_names and successful_domains != domains: if not self.config.dry_run: os.remove(key.file) os.remove(csr.file) return self.obtain_certificate(successful_domains) else: cert, chain = self.obtain_certificate_from_csr(csr, orderr) return cert, chain, key, csr
def test_obtain_certificate_from_csr(self, unused_mock_get_utility, mock_logger, mock_crypto_util): self._mock_obtain_certificate() test_csr = util.CSR(form="pem", file=None, data=CSR_SAN) auth_handler = self.client.auth_handler self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain) orderr = self.acme.new_order(test_csr.data) auth_handler.handle_authorizations(orderr, False) self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr( test_csr, orderr=orderr)) mock_crypto_util.find_chain_with_issuer.assert_not_called() # and that the cert was obtained correctly self._check_obtain_certificate() # Test that --preferred-chain results in chain selection self.config.preferred_chain = "some issuer" self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr( test_csr, orderr=orderr)) mock_crypto_util.find_chain_with_issuer.assert_called_once_with( [orderr.fullchain_pem] + orderr.alternative_fullchains_pem, "some issuer", True) self.config.preferred_chain = None # Test for orderr=None self.assertEqual( (mock.sentinel.cert, mock.sentinel.chain), self.client.obtain_certificate_from_csr( test_csr, orderr=None)) auth_handler.handle_authorizations.assert_called_with(self.eg_order, False) # Test for no auth_handler self.client.auth_handler = None self.assertRaises( errors.Error, self.client.obtain_certificate_from_csr, test_csr) mock_logger.warning.assert_called_once_with(mock.ANY)
def test_obtain_certificate_dry_run_authz_deactivations_failed( self, mock_acme_crypto, mock_crypto, mock_log): from acme import messages csr = util.CSR(form="pem", file=None, data=CSR_SAN) mock_acme_crypto.make_csr.return_value = CSR_SAN mock_crypto.make_key.return_value = mock.sentinel.key_pem key = util.Key(file=None, pem=mock.sentinel.key_pem) self._set_mock_from_fullchain( mock_crypto.cert_and_chain_from_fullchain) self._mock_obtain_certificate() self.client.config.dry_run = True # Two authzs that are already valid and should get deactivated (dry run) authzrs = self._authzr_from_domains(["example.com", "www.example.com"]) for authzr in authzrs: authzr.body.status = messages.STATUS_VALID # One deactivation succeeds, one fails auth_handler = self.client.auth_handler auth_handler.deactivate_valid_authorizations.return_value = ([ authzrs[0] ], [authzrs[1]]) # Certificate should get issued despite one failed deactivation self.eg_order.authorizations = authzrs self.client.auth_handler.handle_authorizations.return_value = authzrs with test_util.patch_get_utility(): result = self.client.obtain_certificate(self.eg_domains) self.assertEqual(result, (mock.sentinel.cert, mock.sentinel.chain, key, csr)) self._check_obtain_certificate(1) # Deactivation success/failure should have been handled properly self.assertEqual( auth_handler.deactivate_valid_authorizations.call_count, 1, "Deactivate authorizations should be called") self.assertEqual( self.acme.new_order.call_count, 2, "Order should be recreated due to successfully deactivated authorizations" ) mock_log.warning.assert_called_with( "Certbot was unable to obtain fresh authorizations for" " every domain. The dry run will continue, but results" " may not be accurate.")
def test_obtain_certificate(self, mock_crypto_util): csr = util.CSR(form="pem", 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 self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain) self._test_obtain_certificate_common(mock.sentinel.key, csr) mock_crypto_util.init_save_key.assert_called_once_with( key_size=self.config.rsa_key_size, key_dir=self.config.key_dir, key_type=self.config.key_type, elliptic_curve=None, # elliptic curve is not set ) mock_crypto_util.init_save_csr.assert_called_once_with( mock.sentinel.key, self.eg_domains, self.config.csr_dir) mock_crypto_util.cert_and_chain_from_fullchain.assert_called_once_with( self.eg_order.fullchain_pem)
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.util.Key` :param .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) cert_buffer = OpenSSL.crypto.dump_certificate_request( OpenSSL.crypto.FILETYPE_PEM, csr_obj ) csr = util.CSR(csr.file, cert_buffer, "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")
def test_obtain_certificate(self, mock_crypto_util): csr = util.CSR(form="pem", file=None, data=CSR_SAN) mock_crypto_util.generate_csr.return_value = csr mock_crypto_util.generate_key.return_value = mock.sentinel.key self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain) self._test_obtain_certificate_common(mock.sentinel.key, csr) mock_crypto_util.generate_key.assert_called_once_with( key_size=self.config.rsa_key_size, key_dir=self.config.key_dir, key_type=self.config.key_type, elliptic_curve="secp256r1", strict_permissions=True, ) mock_crypto_util.generate_csr.assert_called_once_with( mock.sentinel.key, self.eg_domains, self.config.csr_dir, False, True) mock_crypto_util.cert_and_chain_from_fullchain.assert_called_once_with( self.eg_order.fullchain_pem)
def obtain_certificate(self, domains): """Obtains a certificate from the ACME server. `.register` must be called before `.obtain_certificate` :param list domains: domains to get a certificate :returns: certificate as PEM string, chain as PEM string, newly generated private key (`.util.Key`), and DER-encoded Certificate Signing Request (`.util.CSR`). :rtype: tuple """ # Create CSR from names if self.config.dry_run: key = util.Key(file=None, pem=crypto_util.make_key(self.config.rsa_key_size)) csr = util.CSR(file=None, form="pem", data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: key = crypto_util.init_save_key(self.config.rsa_key_size, self.config.key_dir) csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir) orderr = self.acme.new_order(csr.data) authzr = self.auth_handler.handle_authorizations( orderr, self.config.allow_subset_of_names) orderr = orderr.update(authorizations=authzr) auth_domains = set(a.body.identifier.value for a in authzr) successful_domains = [d for d in domains if d in auth_domains] if successful_domains != domains: if not self.config.dry_run: os.remove(key.file) os.remove(csr.file) return self.obtain_certificate(successful_domains) else: cert, chain = self.obtain_certificate_from_csr(csr, orderr) return cert, chain, key, csr
def obtain_certificate(self, domains): """Obtains a certificate from the ACME server. `.register` must be called before `.obtain_certificate` :param list domains: domains to get a certificate :returns: `.CertificateResource`, certificate chain (as returned by `.fetch_chain`), and newly generated private key (`.util.Key`) and DER-encoded Certificate Signing Request (`.util.CSR`). :rtype: tuple """ authzr = self.auth_handler.get_authorizations( domains, self.config.allow_subset_of_names) auth_domains = set(a.body.identifier.value for a in authzr) domains = [d for d in domains if d in auth_domains] # Create CSR from names if self.config.dry_run: key = util.Key(file=None, pem=crypto_util.make_key(self.config.rsa_key_size)) csr = util.CSR(file=None, form="pem", data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: key = crypto_util.init_save_key(self.config.rsa_key_size, self.config.key_dir) csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir) certr, chain = self.obtain_certificate_from_csr(domains, csr, authzr=authzr) return certr, chain, key, csr
def obtain_certificate(self, domains, old_keypath=None): """Obtains a certificate from the ACME server. `.register` must be called before `.obtain_certificate` :param list domains: domains to get a certificate :returns: certificate as PEM string, chain as PEM string, newly generated private key (`.util.Key`), and DER-encoded Certificate Signing Request (`.util.CSR`). :rtype: tuple """ # We need to determine the key path, key PEM data, CSR path, # and CSR PEM data. For a dry run, the paths are None because # they aren't permanently saved to disk. For a lineage with # --reuse-key, the key path and PEM data are derived from an # existing file. if old_keypath is not None: # We've been asked to reuse a specific existing private key. # Therefore, we'll read it now and not generate a new one in # either case below. # # We read in bytes here because the type of `key.pem` # created below is also bytes. with open(old_keypath, "rb") as f: keypath = old_keypath keypem = f.read() key: Optional[util.Key] = util.Key(file=keypath, pem=keypem) logger.info("Reusing existing private key from %s.", old_keypath) else: # The key is set to None here but will be created below. key = None key_size = self.config.rsa_key_size elliptic_curve = "secp256r1" # key-type defaults to a list, but we are only handling 1 currently if isinstance(self.config.key_type, list): self.config.key_type = self.config.key_type[0] if self.config.elliptic_curve and self.config.key_type == 'ecdsa': elliptic_curve = self.config.elliptic_curve self.config.auth_chain_path = "./chain-ecdsa.pem" self.config.auth_cert_path = "./cert-ecdsa.pem" self.config.key_path = "./key-ecdsa.pem" elif self.config.rsa_key_size and self.config.key_type.lower( ) == 'rsa': key_size = self.config.rsa_key_size # Create CSR from names if self.config.dry_run: key = key or util.Key( file=None, pem=crypto_util.make_key( bits=key_size, elliptic_curve=elliptic_curve, key_type=self.config.key_type, ), ) csr = util.CSR(file=None, form="pem", data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: key = key or crypto_util.generate_key( key_size=key_size, key_dir=self.config.key_dir, key_type=self.config.key_type, elliptic_curve=elliptic_curve, strict_permissions=self.config.strict_permissions, ) csr = crypto_util.generate_csr(key, domains, self.config.csr_dir, self.config.must_staple, self.config.strict_permissions) orderr = self._get_order_and_authorizations( csr.data, self.config.allow_subset_of_names) authzr = orderr.authorizations auth_domains = set(a.body.identifier.value for a in authzr) successful_domains = [d for d in domains if d in auth_domains] # allow_subset_of_names is currently disabled for wildcard # certificates. The reason for this and checking allow_subset_of_names # below is because successful_domains == domains is never true if # domains contains a wildcard because the ACME spec forbids identifiers # in authzs from containing a wildcard character. if self.config.allow_subset_of_names and successful_domains != domains: if not self.config.dry_run: os.remove(key.file) os.remove(csr.file) return self.obtain_certificate(successful_domains) else: cert, chain = self.obtain_certificate_from_csr(csr, orderr) return cert, chain, key, csr