def test_it(self): host, port = self.server.socket.getsockname()[:2] cert = crypto_util.probe_sni(b'localhost', host=host, port=port, timeout=1) self.assertEqual(jose.ComparableX509(cert), jose.ComparableX509(self.certs[b'localhost'][1]))
def test_connect(self): socknames = self.servers.getsocknames() # connect to all addresses for sockname in socknames: host, port = sockname[:2] cert = crypto_util.probe_sni(b'localhost', host=host, port=port, timeout=1) self.assertEqual(jose.ComparableX509(cert), jose.ComparableX509(self.certs[b'localhost'][1]))
def revoke(config, unused_plugins): # TODO: coop with renewal config """Revoke a previously obtained certificate. :param config: Configuration object :type config: interfaces.IConfig :param unused_plugins: List of plugins (deprecated) :type unused_plugins: `list` of `str` :returns: `None` or string indicating error in case of error :rtype: None or str """ # For user-agent construction config.installer = config.authenticator = "None" if config.key_path is not None: # revocation by cert key logger.debug("Revoking %s using cert key %s", config.cert_path[0], config.key_path[0]) crypto_util.verify_cert_matches_priv_key(config.cert_path[0], config.key_path[0]) key = jose.JWK.load(config.key_path[1]) else: # revocation by account key logger.debug("Revoking %s using Account Key", config.cert_path[0]) acc, _ = _determine_account(config) key = acc.key acme = client.acme_from_config_key(config, key) cert = crypto_util.pyopenssl_load_certificate(config.cert_path[1])[0] logger.debug("Reason code for revocation: %s", config.reason) try: acme.revoke(jose.ComparableX509(cert), config.reason) _delete_if_appropriate(config) except acme_errors.ClientError as e: return str(e) display_ops.success_revocation(config.cert_path[0])
async def request_cert(self, csr: crypto.x509CertSignReq) -> AcmeCert: """ Request the issuance of a certificate for the given CSR. :param csr: The CSR to fulfill. :return: The newly issued x509 certificate. """ # (1) First get a list of the authorization resources in the CSR # by inspecting the SAN (we current do not look at the CN) domains = csr.get_subj_alt_dns_names() authzrs = [] for domain in domains: new_authzr = await self._client.request_domain_challenges(domain) authzrs.append(new_authzr) # (2) Convert the CSR acme_csr = jose.ComparableX509( OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, csr.to_bytes(encoding=crypto.EncodingType.PEM))) # (3) Request the Issuance acme_cert = await self._client.request_issuance(acme_csr, authzrs) py_openssl_cert = acme_cert.body.wrapped # (4) Covert the Issuance Object cert = AcmeCert(OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, py_openssl_cert), acme_uri=acme_cert.uri, issuer_uri=acme_cert.cert_chain_uri) return cert
def _check_obtain_certificate(self): self.client.auth_handler.get_authorizations.assert_called_once_with(self.eg_domains) self.acme.request_issuance.assert_called_once_with( jose.ComparableX509(OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, CSR_SAN)), self.client.auth_handler.get_authorizations()) self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr)
def issue(client, authzs, cert_output=None): """Given a list of authzs that are being processed by the server, wait for them to be ready, then request issuance of a cert with a random key for the given domains. If cert_output is provided, write the cert as a PEM file to that path.""" csr = make_csr([authz.body.identifier.value for authz in authzs]) cert_resource = None try: cert_resource, _ = client.poll_and_request_issuance( jose.ComparableX509(csr), authzs) except acme_errors.PollError as error: # If we get a PollError, pick the first failed authz and turn it into a more # useful ValidationError that contains details we can look for in tests. for authz in error.updated: updated_authz = json.loads(urllib2.urlopen(authz.uri).read()) domain = authz.body.identifier.value, for c in updated_authz['challenges']: if 'error' in c: err = c['error'] raise ValidationError(domain, err['type'], err['detail']) # If none of the authz's had an error, just re-raise. raise if cert_output is not None: pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_resource.body) with open(cert_output, 'w') as f: f.write(pem) return cert_resource
def obtain_certificate_from_csr(self, domains, csr, authzr=None): """Obtain certificate. Internal function with precondition that `domains` are consistent with identifiers present in the `csr`. :param list domains: Domain names. :param .util.CSR csr: PEM-encoded Certificate Signing Request. The key used to generate this CSR can be different than `authkey`. :param list authzr: List of :class:`acme.messages.AuthorizationResource` :returns: `.CertificateResource` and certificate chain (as returned by `.fetch_chain`). :rtype: tuple """ if self.auth_handler is None: msg = ("Unable to obtain certificate because authenticator is " "not set.") logger.warning(msg) raise errors.Error(msg) if self.account.regr is None: raise errors.Error("Please register with the ACME server first.") logger.debug("CSR: %s, domains: %s", csr, domains) if authzr is None: authzr = self.auth_handler.get_authorizations(domains) certr = self.acme.request_issuance( jose.ComparableX509( OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, csr.data)), authzr) notify = zope.component.getUtility(interfaces.IDisplay).notification retries = 0 chain = None while retries <= 1: if retries: notify( 'Failed to fetch chain, please check your network ' 'and continue', pause=True) try: chain = self.acme.fetch_chain(certr) break except acme_errors.Error: logger.debug('Failed to fetch chain', exc_info=True) retries += 1 if chain is None: raise acme_errors.Error( 'Failed to fetch chain. You should not deploy the generated ' 'certificate, please rerun the command for a new one.') return certr, chain
def _check_obtain_certificate(self): self.client.auth_handler.get_authorizations.assert_called_once_with( ["example.com", "www.example.com"]) self.network.request_issuance.assert_callend_once_with( jose.ComparableX509( M2Crypto.X509.load_request_der_string(CSR_SAN)), self.client.auth_handler.get_authorizations()) self.network().fetch_chain.assert_called_once_with(mock.sentinel.certr)
def _revoke(rawkey, rawcert): ns = ConfigNamespace(None) acme = acme_client.Client( ns.server, key=JWKRSA(key=serialization.load_pem_private_key( rawkey, password=None, backend=default_backend()))) acme.revoke( jose.ComparableX509( OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, rawcert)))
def test_revoke_with_key(self, mock_acme_client): server = 'foo.bar' self._call_no_clientmock(['--cert-path', CERT, '--key-path', KEY, '--server', server, 'revoke']) with open(KEY) as f: mock_acme_client.Client.assert_called_once_with( server, key=jose.JWK.load(f.read()), net=mock.ANY) with open(CERT) as f: cert = crypto_util.pyopenssl_load_certificate(f.read())[0] mock_revoke = mock_acme_client.Client().revoke mock_revoke.assert_called_once_with(jose.ComparableX509(cert))
def obtain_certificate(self, domains, csr=None): """Obtains a certificate from the ACME server. :meth:`.register` must be called before :meth:`.obtain_certificate` .. todo:: This function does not currently handle CSR correctly. :param set domains: domains to get a certificate :param csr: CSR must contain requested domains, the key used to generate this CSR can be different than self.authkey :type csr: :class:`CSR` :returns: Certificate, private key, and certificate chain (all PEM-encoded). :rtype: `tuple` of `str` """ if self.auth_handler is None: msg = ("Unable to obtain certificate because authenticator is " "not set.") logging.warning(msg) raise errors.LetsEncryptClientError(msg) if self.account.regr is None: raise errors.LetsEncryptClientError( "Please register with the ACME server first.") # Perform Challenges/Get Authorizations authzr = self.auth_handler.get_authorizations(domains) # Create CSR from names cert_key = crypto_util.init_save_key(self.config.rsa_key_size, self.config.key_dir) csr = crypto_util.init_save_csr(cert_key, domains, self.config.cert_dir) # Retrieve certificate certr = self.network.request_issuance( jose.ComparableX509(M2Crypto.X509.load_request_der_string( csr.data)), authzr) cert_pem = certr.body.as_pem() chain_pem = None if certr.cert_chain_uri is not None: chain_pem = self.network.fetch_chain(certr) if chain_pem is None: # XXX: just to stop RenewableCert from complaining; this is # probably not a good solution chain_pem = "" else: chain_pem = chain_pem.as_pem() return cert_pem, cert_key.pem, chain_pem
def test_it(self): max_attempts = 5 while max_attempts: max_attempts -= 1 try: cert = crypto_util.probe_sni(b'localhost', b'0.0.0.0', self.port) except errors.Error: self.assertTrue(max_attempts > 0, "Timeout!") time.sleep(1) # wait until thread starts else: self.assertEqual(jose.ComparableX509(cert), test_util.load_comparable_cert('cert.pem')) break
def revoke(args, config, unused_plugins): # TODO: coop with renewal config """Revoke a previously obtained certificate.""" if args.key_path is not None: # revocation by cert key logger.debug("Revoking %s using cert key %s", args.cert_path[0], args.key_path[0]) acme = acme_client.Client( config.server, key=jose.JWK.load(args.key_path[1])) else: # revocation by account key logger.debug("Revoking %s using Account Key", args.cert_path[0]) acc, _ = _determine_account(args, config) # pylint: disable=protected-access acme = client._acme_from_config_key(config, acc.key) acme.revoke(jose.ComparableX509(crypto_util.pyopenssl_load_certificate( args.cert_path[1])[0]))
def request_issuance(self, csr, authzrs): print("Se ejecuta request issuance") """Request issuance. :param csr: CSR :type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` :param authzrs: `list` of `.AuthorizationResource` :returns: Issued certificate :rtype: `.messages.CertificateResource` """ assert authzrs, "Authorizations list is empty" logger.debug("Requesting issuance...") # TODO: assert len(authzrs) == number of SANs #Checks if STARValidityCertbot file containing recurrent_cert_validity exists if os.path.isfile("../../STARValidityCertbot"): print "CLIENT.PY: STARValidityCertbot does exist" fileSTAR = open("../../STARValidityCertbot", "r") recurrent = True recurrent_cert_validity = int(float(fileSTAR.read())) req = messages.CertificateRequest(csr=csr, recurrent=recurrent,recurrent_cert_validity=recurrent_cert_validity) else: print "CLIENT.PY: STARValidityCertbot does NOT exist" req = messages.CertificateRequest(csr=csr) print "CSR sent to server is %s" % req content_type = DER_CONTENT_TYPE # TODO: add 'cert_type 'argument response = self.net.post( self.directory.new_cert, req, content_type=content_type, headers={'Accept': content_type}) cert_chain_uri = response.links.get('up', {}).get('url') try: uri = response.headers['Location'] file=open('/root/certId','wr+') file.write(uri) print(uri) except KeyError: raise errors.ClientError('"Location" Header missing') return messages.CertificateResource( uri=uri, authzrs=authzrs, cert_chain_uri=cert_chain_uri, body=jose.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_ASN1, response.content)))
def test_renew(self, mock_c, mock_acc_storage, mock_pd): from letsencrypt import renewer test_cert = test_util.load_vector("cert-san.pem") for kind in ALL_FOUR: os.symlink( os.path.join("..", "..", "archive", "example.org", kind + "1.pem"), getattr(self.test_rc, kind)) fill_with_sample_data(self.test_rc) with open(self.test_rc.cert, "w") as f: f.write(test_cert) # Fails because renewalparams are missing self.assertFalse(renewer.renew(self.test_rc, 1)) self.test_rc.configfile["renewalparams"] = {"some": "stuff"} # Fails because there's no authenticator specified self.assertFalse(renewer.renew(self.test_rc, 1)) self.test_rc.configfile["renewalparams"]["rsa_key_size"] = "2048" self.test_rc.configfile["renewalparams"]["server"] = "acme.example.com" self.test_rc.configfile["renewalparams"]["authenticator"] = "fake" self.test_rc.configfile["renewalparams"]["tls_sni_01_port"] = "4430" self.test_rc.configfile["renewalparams"]["http01_port"] = "1234" self.test_rc.configfile["renewalparams"]["account"] = "abcde" self.test_rc.configfile["renewalparams"]["domains"] = ["example.com"] self.test_rc.configfile["renewalparams"]["config_dir"] = "config" self.test_rc.configfile["renewalparams"]["work_dir"] = "work" self.test_rc.configfile["renewalparams"]["logs_dir"] = "logs" mock_auth = mock.MagicMock() mock_pd.PluginsRegistry.find_all.return_value = {"apache": mock_auth} # Fails because "fake" != "apache" self.assertFalse(renewer.renew(self.test_rc, 1)) self.test_rc.configfile["renewalparams"]["authenticator"] = "apache" mock_client = mock.MagicMock() # pylint: disable=star-args comparable_cert = jose.ComparableX509(CERT) mock_client.obtain_certificate.return_value = (mock.MagicMock( body=comparable_cert), [comparable_cert], mock.Mock(pem="key"), mock.sentinel.csr) mock_c.return_value = mock_client self.assertEqual(2, renewer.renew(self.test_rc, 1)) # TODO: We could also make several assertions about calls that should # have been made to the mock functions here. mock_acc_storage().load.assert_called_once_with(account_id="abcde") mock_client.obtain_certificate.return_value = (mock.sentinel.certr, [], mock.sentinel.key, mock.sentinel.csr) # This should fail because the renewal itself appears to fail self.assertFalse(renewer.renew(self.test_rc, 1))
def test_it(self): max_attempts = 5 for attempt in range(max_attempts): try: cert = crypto_util.probe_sni(b'localhost', b'0.0.0.0', self.port) except errors.Error: self.assertTrue(attempt + 1 < max_attempts, "Timeout!") time.sleep(1) # wait until thread starts else: self.assertEqual( jose.ComparableX509(cert), test_util.load_comparable_cert('rsa2048_cert.pem')) break if attempt == 0: # the first attempt is always meant to fail, so we can test # the socket failure code-path for probe_sni, as well self.thread.start()
def issue(client, authzs, cert_output=None): """Given a list of authzs that are being processed by the server, wait for them to be ready, then request issuance of a cert with a random key for the given domains. If cert_output is provided, write the cert as a PEM file to that path.""" domains = [authz.body.identifier.value for authz in authzs] pkey = OpenSSL.crypto.PKey() pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) csr = OpenSSL.crypto.X509Req() csr.add_extensions([ OpenSSL.crypto.X509Extension( 'subjectAltName', critical=False, value=', '.join('DNS:' + d for d in domains).encode()), ]) csr.set_pubkey(pkey) csr.set_version(2) csr.sign(pkey, 'sha256') cert_resource = None try: cert_resource, _ = client.poll_and_request_issuance( jose.ComparableX509(csr), authzs) except acme_errors.PollError as error: # If we get a PollError, pick the first failed authz and turn it into a more # useful ValidationError that contains details we can look for in tests. for authz in error.updated: updated_authz = json.loads(urllib2.urlopen(authz.uri).read()) domain = authz.body.identifier.value, for c in updated_authz['challenges']: if 'error' in c: err = c['error'] raise ValidationError(domain, err['type'], err['detail']) # If none of the authz's had an error, just re-raise. raise if cert_output is not None: pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_resource.body) with open(cert_output, 'w') as f: f.write(pem) return cert_resource
def request_issuance(self, csr, authzrs): """Request issuance. :param csr: CSR :type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` :param authzrs: `list` of `.AuthorizationResource` :returns: Issued certificate :rtype: `.messages.CertificateResource` """ assert authzrs, "Authorizations list is empty" logger.debug("Requesting issuance...") # TODO: assert len(authzrs) == number of SANs req = messages.CertificateRequest( csr=csr, authorizations=tuple(authzr.uri for authzr in authzrs)) content_type = self.DER_CONTENT_TYPE # TODO: add 'cert_type 'argument response = self.net.post( authzrs[0].new_cert_uri, # TODO: acme-spec #90 req, content_type=content_type, headers={'Accept': content_type}) cert_chain_uri = response.links.get('up', {}).get('url') try: uri = response.headers['Location'] except KeyError: raise errors.ClientError('"Location" Header missing') return messages.CertificateResource( uri=uri, authzrs=authzrs, cert_chain_uri=cert_chain_uri, body=jose.ComparableX509( OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, response.content)))
import unittest import Crypto.PublicKey.RSA import M2Crypto from acme import challenges from acme import errors from acme import jose from acme import other KEY = jose.HashableRSAKey( Crypto.PublicKey.RSA.importKey( pkg_resources.resource_string( 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')))) CERT = jose.ComparableX509( M2Crypto.X509.load_cert( pkg_resources.resource_filename('letsencrypt.tests', os.path.join('testdata', 'cert.pem')))) CSR = jose.ComparableX509( M2Crypto.X509.load_request( pkg_resources.resource_filename('letsencrypt.tests', os.path.join('testdata', 'csr.pem')))) CSR2 = jose.ComparableX509( M2Crypto.X509.load_request( pkg_resources.resource_filename('acme.jose', os.path.join('testdata', 'csr2.pem')))) class MessageTest(unittest.TestCase): """Tests for acme.messages.Message.""" def setUp(self): # pylint: disable=missing-docstring,too-few-public-methods
def load_csr(*names): """Load certificate request.""" loader = _guess_loader( names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1) return jose.ComparableX509(OpenSSL.crypto.load_certificate_request( loader, load_vector(*names)))
import unittest import M2Crypto import mock import requests from acme import challenges from acme import jose from acme import jws as acme_jws from acme import messages2 from letsencrypt import account from letsencrypt import errors CERT = jose.ComparableX509( M2Crypto.X509.load_cert_string( pkg_resources.resource_string(__name__, os.path.join('testdata', 'cert.pem')))) CERT2 = jose.ComparableX509( M2Crypto.X509.load_cert_string( pkg_resources.resource_string(__name__, os.path.join('testdata', 'cert-san.pem')))) CSR = jose.ComparableX509( M2Crypto.X509.load_request_string( pkg_resources.resource_string(__name__, os.path.join('testdata', 'csr.pem')))) KEY = jose.JWKRSA.load( pkg_resources.resource_string('acme.jose', os.path.join('testdata', 'rsa512_key.pem'))) KEY2 = jose.JWKRSA.load( pkg_resources.resource_string('acme.jose',
def test_dvsni(self): cert = crypto_util.probe_sni( b'localhost', *self.server.socket.getsockname()) self.assertEqual(jose.ComparableX509(cert), jose.ComparableX509(self.certs[b'localhost'][1]))