def _regr_from_response(cls, response, uri=None, terms_of_service=None): if 'terms-of-service' in response.links: terms_of_service = response.links['terms-of-service']['url'] return messages.RegistrationResource( body=messages.Registration.from_json(response.json()), uri=response.headers.get('Location', uri), terms_of_service=terms_of_service)
def setUp(self): self.response = mock.MagicMock( ok=True, status_code=http_client.OK, headers={}, links={}) self.net = mock.MagicMock() self.net.post.return_value = self.response self.net.get.return_value = self.response self.directory = messages.Directory({ messages.NewRegistration: 'https://www.letsencrypt-demo.org/acme/new-reg', messages.Revocation: 'https://www.letsencrypt-demo.org/acme/revoke-cert', messages.NewAuthorization: 'https://www.letsencrypt-demo.org/acme/new-authz', }) from acme.client import Client self.client = Client( directory=self.directory, key=KEY, alg=jose.RS256, net=self.net) self.identifier = messages.Identifier( typ=messages.IDENTIFIER_FQDN, value='example.com') # Registration self.contact = ('mailto:[email protected]', 'tel:+12025551212') reg = messages.Registration( contact=self.contact, key=KEY.public_key()) self.new_reg = messages.NewRegistration(**dict(reg)) self.regr = messages.RegistrationResource( body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1', new_authzr_uri='https://www.letsencrypt-demo.org/acme/new-reg', terms_of_service='https://www.letsencrypt-demo.org/tos') # Authorization authzr_uri = 'https://www.letsencrypt-demo.org/acme/authz/1' challb = messages.ChallengeBody( uri=(authzr_uri + '/1'), status=messages.STATUS_VALID, chall=challenges.DNS(token=jose.b64decode( 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA'))) self.challr = messages.ChallengeResource( body=challb, authzr_uri=authzr_uri) self.authz = messages.Authorization( identifier=messages.Identifier( typ=messages.IDENTIFIER_FQDN, value='example.com'), challenges=(challb,), combinations=None) self.authzr = messages.AuthorizationResource( body=self.authz, uri=authzr_uri, new_cert_uri='https://www.letsencrypt-demo.org/acme/new-cert') # Request issuance self.certr = messages.CertificateResource( body=messages_test.CERT, authzrs=(self.authzr,), uri='https://www.letsencrypt-demo.org/acme/cert/1', cert_chain_uri='https://www.letsencrypt-demo.org/ca') # Reason code for revocation self.rsn = 1
def setUp(self): self.verify_ssl = mock.MagicMock() self.wrap_in_jws = mock.MagicMock(return_value=mock.sentinel.wrapped) from acme.client import Client self.net = Client( new_reg_uri='https://www.letsencrypt-demo.org/acme/new-reg', key=KEY, alg=jose.RS256, verify_ssl=self.verify_ssl) self.nonce = jose.b64encode('Nonce') self.net._nonces.add(self.nonce) # pylint: disable=protected-access self.response = mock.MagicMock(ok=True, status_code=httplib.OK) self.response.headers = {} self.response.links = {} self.post = mock.MagicMock(return_value=self.response) self.get = mock.MagicMock(return_value=self.response) self.identifier = messages.Identifier(typ=messages.IDENTIFIER_FQDN, value='example.com') # Registration self.contact = ('mailto:[email protected]', 'tel:+12025551212') reg = messages.Registration(contact=self.contact, key=KEY.public(), recovery_token='t') self.regr = messages.RegistrationResource( body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1', new_authzr_uri='https://www.letsencrypt-demo.org/acme/new-reg', terms_of_service='https://www.letsencrypt-demo.org/tos') # Authorization authzr_uri = 'https://www.letsencrypt-demo.org/acme/authz/1' challb = messages.ChallengeBody(uri=(authzr_uri + '/1'), status=messages.STATUS_VALID, chall=challenges.DNS(token='foo')) self.challr = messages.ChallengeResource(body=challb, authzr_uri=authzr_uri) self.authz = messages.Authorization(identifier=messages.Identifier( typ=messages.IDENTIFIER_FQDN, value='example.com'), challenges=(challb, ), combinations=None) self.authzr = messages.AuthorizationResource( body=self.authz, uri=authzr_uri, new_cert_uri='https://www.letsencrypt-demo.org/acme/new-cert') # Request issuance self.certr = messages.CertificateResource( body=messages_test.CERT, authzrs=(self.authzr, ), uri='https://www.letsencrypt-demo.org/acme/cert/1', cert_chain_uri='https://www.letsencrypt-demo.org/ca')
def setUp(self): zope.component.provideUtility(display_util.FileDisplay(sys.stdout)) self.accounts_dir = tempfile.mkdtemp("accounts") self.account_keys_dir = os.path.join(self.accounts_dir, "keys") os.makedirs(self.account_keys_dir, 0o700) self.config = mock.MagicMock( accounts_dir=self.accounts_dir, account_keys_dir=self.account_keys_dir, server="certbot-demo.org") self.key = KEY self.acc1 = account.Account(messages.RegistrationResource( uri=None, new_authzr_uri=None, body=messages.Registration.from_data( email="*****@*****.**")), self.key) self.acc2 = account.Account(messages.RegistrationResource( uri=None, new_authzr_uri=None, body=messages.Registration.from_data( email="*****@*****.**", phone="phone")), self.key)
def setUp(self): self.tmp = tempfile.mkdtemp() self.config = mock.MagicMock( accounts_dir=os.path.join(self.tmp, "accounts")) from certbot.account import AccountFileStorage self.storage = AccountFileStorage(self.config) from certbot.account import Account self.acc = Account(regr=messages.RegistrationResource( uri=None, body=messages.Registration()), key=KEY)
def setUp(self): super().setUp() display_obj.set_display(display_obj.FileDisplay(sys.stdout, False)) self.account_keys_dir = os.path.join(self.tempdir, "keys") filesystem.makedirs(self.account_keys_dir, 0o700) self.config = mock.MagicMock( accounts_dir=self.tempdir, account_keys_dir=self.account_keys_dir, server="certbot-demo.org") self.key = KEY self.acc1 = account.Account(messages.RegistrationResource( uri=None, body=messages.Registration.from_data( email="*****@*****.**")), self.key) self.acc2 = account.Account(messages.RegistrationResource( uri=None, body=messages.Registration.from_data( email="*****@*****.**", phone="phone")), self.key)
def setUp(self): super(SubscriptionTest, self).setUp() self.account = account.Account( regr=messages.RegistrationResource( uri=None, body=messages.Registration(), new_authzr_uri='hi'), key=_KEY, meta=account.Account.Meta( creation_host='test.certbot.org', creation_dt=datetime.datetime( 2015, 7, 4, 14, 4, 10, tzinfo=pytz.UTC))) self.config.email = '*****@*****.**' self.config.eff_email = None
def _cb_parse_registration_response(self, response, uri=None): """ Parse a new or update registration response from the server. """ links = _parse_header_links(response) terms_of_service = None if u'terms-of-service' in links: terms_of_service = links[u'terms-of-service'][u'url'] return (response.json().addCallback( lambda body: messages.RegistrationResource( body=messages.Registration.from_json(body), uri=self._maybe_location(response, uri), terms_of_service=terms_of_service)))
def enroll(self, csr): """ enroll certificate """ self.logger.debug('CAhandler.enroll()') csr_pem = '-----BEGIN CERTIFICATE REQUEST-----\n{0}\n-----END CERTIFICATE REQUEST-----\n'.format(textwrap.fill(str(b64_url_recode(self.logger, csr)), 64)) cert_bundle = None error = None cert_raw = None poll_indentifier = None key = None try: self.logger.debug('CAhandler.enroll() opening key') with open(self.keyfile, "r") as keyf: key = josepy.JWKRSA.json_loads(keyf.read()) net = client.ClientNetwork(key) directory = messages.Directory.from_json(net.get(self.url).json()) acmeclient = client.ClientV2(directory, net=net) reg = messages.Registration.from_data(key=key, terms_of_service_agreed=True) regr = messages.RegistrationResource(uri="{}/account/{}".format(self.url, self.account), body=reg) self.logger.debug('CAhandler.enroll() checking remote registration status') regr = acmeclient.query_registration(regr) if regr.body.status != "valid": raise Exception("Bad ACME account: " + str(regr.body.error)) self.logger.debug('CAhandler.enroll() issuing signing order') self.logger.debug('CAhandler.enroll() CSR: ' + str(csr_pem)) order = acmeclient.new_order(csr_pem) self.logger.debug('CAhandler.enroll() polling for certificate') order = acmeclient.poll_and_finalize(order) if not order.fullchain_pem: raise Exception("Error getting certificate: " + str(order.error)) self.logger.debug('CAhandler.enroll() successful') cert_bundle = str(order.fullchain_pem) cert_raw = str(base64.b64encode(crypto.dump_certificate(crypto.FILETYPE_ASN1, crypto.load_certificate(crypto.FILETYPE_PEM, cert_bundle))), 'utf-8') except Exception as e: self.logger.error(str(e)) error = str(e) finally: del key self.logger.debug('Certificate.enroll() ended') return(error, cert_bundle, cert_raw, poll_indentifier)
def wildcard_revoke(cert_pem,account): #Check if registrar exists if account not in os.listdir(REG_DIRECTORY): print "This account does not exists, register it first with new_account.py" sys.exit(1) #Load files from disk with open(REG_DIRECTORY + "/" + account + "/private.key", "rb") as key_file: privkey = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) with open(REG_DIRECTORY + "/" + account + "/reguri.txt", "r") as reguri_file: reg_uri = reguri_file.read() #Compose registration resource (regr) key = jose.JWKRSA(key=privkey) regr = messages.RegistrationResource( body=messages.Registration( key=key.public_key()), uri = reg_uri) #Init ACME net = ClientNetwork(key) directory = net.get(DIRECTORY_URL).json() acme = client.ClientV2(directory, net) #Check if registration is valid if acme.query_registration(regr).body.status == u'valid': print "Registration valid" else: print "Registration invalid" sys.exit(1) #Deserialize key from variable cert = jose.ComparableX509(OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_pem)) #Try to revoke cert, return false on error or revoked-already state try: revokation = acme.revoke(cert,1) except messages.Error,acme_exc: if str(acme_exc) == str("urn:ietf:params:acme:error:alreadyRevoked :: Certificate already revoked"): return ["Certificate already revoked",False] else: return [acme_exc, False]
def setUp(self): super(AccountFileStorageTest, self).setUp() from certbot._internal.account import AccountFileStorage self.storage = AccountFileStorage(self.config) from certbot._internal.account import Account new_authzr_uri = "hi" self.acc = Account(regr=messages.RegistrationResource( uri=None, body=messages.Registration(), new_authzr_uri=new_authzr_uri), key=KEY) self.mock_client = mock.MagicMock() self.mock_client.directory.new_authz = new_authzr_uri
def _regr_from_response(cls, response, uri=None, new_authzr_uri=None, terms_of_service=None): if 'terms-of-service' in response.links: terms_of_service = response.links['terms-of-service']['url'] if 'next' in response.links: new_authzr_uri = response.links['next']['url'] if new_authzr_uri is None: raise errors.ClientError('"next" link missing') return messages.RegistrationResource( body=messages.Registration.from_json(response.json()), uri=response.headers.get('Location', uri), new_authzr_uri=new_authzr_uri, terms_of_service=terms_of_service)
def _update_regr(self, account, acme, dir_path): # type: (Account, ClientBase, str) -> None with open(self._regr_path(dir_path), "w") as regr_file: regr = account.regr # If we have a value for new-authz, save it for forwards # compatibility with older versions of Certbot. If we don't # have a value for new-authz, this is an ACMEv2 directory where # an older version of Certbot won't work anyway. if hasattr(acme.directory, "new-authz"): regr = RegistrationResourceWithNewAuthzrURI( new_authzr_uri=acme.directory.new_authz, body={}, uri=regr.uri) else: regr = messages.RegistrationResource(body={}, uri=regr.uri) regr_file.write(regr.json_dumps())
def setUp(self): self.tmp = tempfile.mkdtemp() self.config = mock.MagicMock( accounts_dir=os.path.join(self.tmp, "accounts")) from certbot.account import AccountFileStorage self.storage = AccountFileStorage(self.config) from certbot.account import Account new_authzr_uri = "hi" self.acc = Account( regr=messages.RegistrationResource( uri=None, body=messages.Registration(), new_authzr_uri=new_authzr_uri), key=KEY) self.mock_client = mock.MagicMock() self.mock_client.directory.new_authz = new_authzr_uri
def create(cls, email, base_path=BASEPATH, directory_url=DIRECTORY_URL): """Creates a new ACME Account using the specified email as point of contact""" ret = ACMEAccount(base_path=base_path, directory_url=directory_url) new_reg = messages.NewRegistration.from_data( email=email, terms_of_service_agreed=True) acme = cls._get_acme_client(ret.jkey, directory_url=directory_url) try: regr = acme.new_account(new_reg) except errors.Error as account_error: raise ACMEError('Unable to create ACME account') from account_error except requests.exceptions.RequestException as request_error: raise ACMETransportError( 'Unable to create ACME account') from request_error ret.regr = messages.RegistrationResource(body=regr.body, uri=regr.uri) return ret
def test_new_account_v2(self): directory = messages.Directory({ "newAccount": 'https://www.letsencrypt-demo.org/acme/new-account', }) from acme.client import ClientV2 client = ClientV2(directory, self.net) self.response.status_code = http_client.CREATED self.response.json.return_value = self.regr.body.to_json() self.response.headers['Location'] = self.regr.uri self.regr = messages.RegistrationResource( body=messages.Registration(contact=self.contact, key=KEY.public_key()), uri='https://www.letsencrypt-demo.org/acme/reg/1') self.assertEqual(self.regr, client.new_account(self.regr))
def revoke(self, _cert, _rev_reason, _rev_date): """ revoke certificate """ self.logger.debug('CAhandler.revoke()') certpem = '-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n'.format(textwrap.fill(str(b64_url_recode(self.logger, _cert)), 64)) cert = josepy.ComparableX509(crypto.load_certificate(crypto.FILETYPE_PEM, certpem)) code = 200 message = None detail = None try: self.logger.debug('CAhandler.revoke() opening key') with open(self.keyfile, "r") as keyf: key = josepy.JWKRSA.json_loads(keyf.read()) net = client.ClientNetwork(key) directory = messages.Directory.from_json(net.get(self.url).json()) acmeclient = client.ClientV2(directory, net=net) reg = messages.Registration.from_data(key=key, terms_of_service_agreed=True) regr = messages.RegistrationResource(uri="{}/account/{}".format(self.url, self.account), body=reg) self.logger.debug('CAhandler.revoke() checking remote registration status') regr = acmeclient.query_registration(regr) if regr.body.status != "valid": raise Exception("Bad ACME account: " + str(regr.body.error)) self.logger.debug('CAhandler.revoke() issuing revocation order') acmeclient.revoke(cert, 1) self.logger.debug('CAhandler.revoke() successfull') except Exception as e: self.logger.error(str(e)) code = 500 message = 'urn:ietf:params:acme:error:serverInternal' detail = str(e) finally: del key self.logger.debug('Certificate.revoke() ended') return(code, message, detail)
def get_acme_client(conf, domain_conf): """ ACME Client """ account_key = load_letsencrypt_account_key(conf, domain_conf['account_uri']) a_key = jose.JWKRSA(key=account_key) net = client.ClientNetwork(a_key) directory_acme = messages.Directory.from_json( net.get(domain_conf['directory']).json()) client_acme = client.ClientV2(directory_acme, net) if not domain_conf['account_uri']: LOG.debug("Registering with ACME server with the new account key") new_reg = messages.NewRegistration.from_data( email=(', '.join(domain_conf['contact'])), terms_of_service_agreed=True) registration_resource = client_acme.new_account(new_reg) domain_conf['account_uri'] = registration_resource.uri LOG.debug("Write Account URI '%s' into Config file ", domain_conf['account_uri']) new_domain_conf = yaml.dump(domain_conf, default_flow_style=False) save_to_s3(conf, conf['config_file'], new_domain_conf) else: registration = messages.Registration(key=a_key, contact=tuple( domain_conf['contact'])) registration_resource = messages.RegistrationResource( body=registration, uri=domain_conf['account_uri']) LOG.debug( "Update the regristration: {0}".format(registration_resource)) registration_resource = client_acme.query_registration( registration_resource) net.account = registration_resource return client_acme
def _parse_regr_response(self, response, uri=None, new_authzr_uri=None, terms_of_service=None): """ Parse a registration response from the server. """ links = _parse_header_links(response) if u'terms-of-service' in links: terms_of_service = links[u'terms-of-service'][u'url'] if u'next' in links: new_authzr_uri = links[u'next'][u'url'] if new_authzr_uri is None: raise errors.ClientError('"next" link missing') return (response.json().addCallback( lambda body: messages.RegistrationResource( body=messages.Registration.from_json(body), uri=self._maybe_location(response, uri=uri), new_authzr_uri=new_authzr_uri, terms_of_service=terms_of_service)))
def setUp(self): super().setUp() from certbot._internal.account import AccountFileStorage self.storage = AccountFileStorage(self.config) from certbot._internal.account import Account new_authzr_uri = "hi" meta = Account.Meta(creation_host="test.example.org", creation_dt=datetime.datetime(2021, 1, 5, 14, 4, 10, tzinfo=pytz.UTC)) self.acc = Account(regr=messages.RegistrationResource( uri=None, body=messages.Registration(), new_authzr_uri=new_authzr_uri), key=KEY, meta=meta) self.mock_client = mock.MagicMock() self.mock_client.directory.new_authz = new_authzr_uri
async def connect(cls, directory: str, key: crypto.PrivateKey, *, loop: _T_AIO_LOOP = None) -> 'AsyncmeClient': """ Connect to an ACME server. :param directory: The URI of the ACME server's directory. :param key: Private key used for interacting with the ACME server. :param loop: Event loop. :return: A new instance of ``AsyncmeClient`` which has been registered against the given ACME server, if the key has not already been registered. """ # Determine the JWS 'alg' Type for the Given Key # RSA if key.algorithm is crypto.KeyAlgorithmType.RSA: if key.size / 8 == 256: alg = jose.jwa.RS256 elif key.size / 8 == 384: alg = jose.jwa.RS384 elif key.size / 8 == 512: alg = jose.jwa.RS512 else: raise ValueError("RSA key size of {} " "is unsupported".format(key.size)) # ECDSA elif key.algorithm is crypto.KeyAlgorithmType.ECDSA: if key.size == 256: alg = jose.jwa.ES256 elif key.size == 384: alg = jose.jwa.ES384 elif key.size == 521: alg = jose.jwa.ES512 else: raise ValueError("ECDSA key size of {} " "is unsupported".format(key.size)) # Other else: raise ValueError("Unsupported private key type, must " "be RSA or ECDSA") # Convert Key password = os.urandom(255) acme_key = jose.JWKRSA(key=serialization.load_der_private_key( key.to_bytes(encoding=crypto.EncodingType.DER, password=password), password, default_backend())) # Get Async. Loop loop = loop or asyncio.get_event_loop() # Instantiate Underlying Client # (and make the initial connection to the ACME server) try: client = await ExecutorClient.connect( directory=directory, key=acme_key, alg=alg, net=ExtendedNetwork( key=acme_key, alg=alg, user_agent='asyncme-python-{}'.format(ASYNCME_VERSION)), loop=loop) except TypeError: raise ValueError("Invalid ACME directory given") # Client Registration try: regr = await client.register() except errors.Error as e: # The upstream client currently has no way to "recover" a lost # registration resource, thus we must resort to the tactics below. if "key is already in use" in str(e): LOG.debug("Key already in use: attempting to recover " "registration resource.") # (1) Send a Post in Attempt to Register the Client # and Get a 409 Back in Response with Location # Header set. post = functools.partial(client.net.post, client.directory['new-reg'], messages.NewRegistration(), checked=False) response = await loop.run_in_executor(None, post) assert response.status_code == 409 # (2) Manually create a new Registration Resource and # send an empty registration update. # (per draft-ietf-acme-acme-03#section-6.2) regr = messages.RegistrationResource( uri=response.headers.get("location")) # Empty Update regr = await client._send_recv_regr( regr, body=messages.UpdateRegistration()) else: raise RuntimeError(e) return cls(client, regr)
def revoke(self, _cert, _rev_reason, _rev_date): """ revoke certificate """ self.logger.debug('CAhandler.revoke()') user_key = None code = 500 message = 'urn:ietf:params:acme:error:serverInternal' detail = None try: certpem = '-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n'.format( textwrap.fill(str(b64_url_recode(self.logger, _cert)), 64)) cert = josepy.ComparableX509( crypto.load_certificate(crypto.FILETYPE_PEM, certpem)) if os.path.exists(self.keyfile): user_key = self._user_key_load() net = client.ClientNetwork(user_key) if user_key: directory = messages.Directory.from_json( net.get('{0}{1}'.format( self.url, self.path_dic['directory_path'])).json()) acmeclient = client.ClientV2(directory, net=net) reg = messages.NewRegistration.from_data( key=user_key, email=self.email, terms_of_service_agreed=True, only_return_existing=True) if not self.account: self._account_lookup(acmeclient, reg, directory) if self.account: regr = messages.RegistrationResource( uri="{0}{1}{2}".format(self.url, self.path_dic['acct_path'], self.account), body=reg) self.logger.debug( 'CAhandler.revoke() checking remote registration status' ) regr = acmeclient.query_registration(regr) if regr.body.status == "valid": self.logger.debug( 'CAhandler.revoke() issuing revocation order') acmeclient.revoke(cert, 1) self.logger.debug('CAhandler.revoke() successfull') code = 200 message = None else: self.logger.error( 'CAhandler.enroll: Bad ACME account: {0}'.format( regr.body.error)) detail = 'Bad ACME account: {0}'.format( regr.body.error) else: self.logger.error( 'CAhandler.revoke(): could not find account key and lookup at acme-endpoint failed.' ) detail = 'account lookup failed' else: self.logger.error( 'CAhandler.revoke(): could not load user_key {0}'.format( self.keyfile)) detail = 'Internal Error' except Exception as err: self.logger.error('CAhandler.enroll: error: {0}'.format(err)) detail = str(err) finally: del user_key self.logger.debug('Certificate.revoke() ended') return (code, message, detail)
def enroll(self, csr): """ enroll certificate """ # pylint: disable=R0915 self.logger.debug('CAhandler.enroll()') csr_pem = '-----BEGIN CERTIFICATE REQUEST-----\n{0}\n-----END CERTIFICATE REQUEST-----\n'.format( textwrap.fill(str(b64_url_recode(self.logger, csr)), 64)) cert_bundle = None error = None cert_raw = None poll_indentifier = None user_key = None # check CN and SAN against black/whitlist result = self._csr_check(csr) if result: try: user_key = self._user_key_load() net = client.ClientNetwork(user_key) directory = messages.Directory.from_json( net.get('{0}{1}'.format( self.url, self.path_dic['directory_path'])).json()) acmeclient = client.ClientV2(directory, net=net) reg = messages.Registration.from_data( key=user_key, terms_of_service_agreed=True) if self.account: regr = messages.RegistrationResource( uri="{0}{1}{2}".format(self.url, self.path_dic['acct_path'], self.account), body=reg) self.logger.debug( 'CAhandler.enroll(): checking remote registration status' ) regr = acmeclient.query_registration(regr) else: # new account or existing account with missing account id regr = self._account_register(acmeclient, user_key, directory) if regr.body.status == "valid": self.logger.debug( 'CAhandler.enroll() issuing signing order') self.logger.debug('CAhandler.enroll() CSR: ' + str(csr_pem)) order = acmeclient.new_order(csr_pem) # query challenges for authzr in list(order.authorizations): (challenge_name, challenge_content, challenge) = self._http_challenge_info( authzr, user_key) if challenge_name and challenge_content: # store challenge in database to allow challenge validation self._challenge_store(challenge_name, challenge_content) _auth_response = acmeclient.answer_challenge( challenge, challenge.chall.response(user_key) ) # lgtm [py/unused-local-variable] self.logger.debug( 'CAhandler.enroll() polling for certificate') order = acmeclient.poll_and_finalize(order) if order.fullchain_pem: self.logger.debug('CAhandler.enroll() successful') cert_bundle = str(order.fullchain_pem) cert_raw = str( base64.b64encode( crypto.dump_certificate( crypto.FILETYPE_ASN1, crypto.load_certificate( crypto.FILETYPE_PEM, cert_bundle))), 'utf-8') else: # raise Exception("Error getting certificate: " + str(order.error)) self.logger.error( 'CAhandler.enroll: Error getting certificate: {0}'. format(order.error)) error = 'Error getting certificate: {0}'.format( order.error) else: self.logger.error( 'CAhandler.enroll: Bad ACME account: {0}'.format( regr.body.error)) error = 'Bad ACME account: {0}'.format(regr.body.error) # raise Exception("Bad ACME account: " + str(regr.body.error)) except Exception as err: self.logger.error('CAhandler.enroll: error: {0}'.format(err)) error = str(err) finally: del user_key else: error = 'CSR rejected. Either CN or SANs are not allowed by policy' self.logger.error( 'CAhandler.enroll: CSR rejected. Either CN or SANs are not allowed by policy.' ) self.logger.debug('Certificate.enroll() ended') return (error, cert_bundle, cert_raw, poll_indentifier)
import josepy as jose from acme import client as acme_client from acme import errors as acme_errors from acme import messages DIRECTORY = os.getenv('DIRECTORY', 'http://localhost:4000/directory') if len(sys.argv) != 2: print("Usage: python deactivate.py private_key.pem") sys.exit(1) data = open(sys.argv[1], "r").read() key = jose.JWKRSA( key=serialization.load_pem_private_key(data, None, default_backend())) net = acme_client.ClientNetwork(key, verify_ssl=False, user_agent="acme account deactivator") client = acme_client.Client(DIRECTORY, key=key, net=net) try: # We expect this to fail and give us a Conflict response with a Location # header pointing at the account's URL. client.register() except acme_errors.ConflictError as e: location = e.location if location is None: raise "Key was not previously registered (but now is)." client.deactivate_registration(messages.RegistrationResource(uri=location))
def setUp(self): self.config = mock.MagicMock(config_dir="/etc/letsencrypt") reg = messages.Registration.from_data(email="*****@*****.**") reg = reg.update(recovery_token="ECCENTRIC INVISIBILITY RHINOCEROS") self.acc = mock.MagicMock(regr=messages.RegistrationResource( uri=None, new_authzr_uri=None, body=reg))
def run_acme_reg_to_finish(domain, regr_uri, accnt_key, site_key, csr, tmp_chall_dict, directory_url): accnt_key = jose.JWKRSA(key=accnt_key) acme = client.Client(directory_url, accnt_key) msg = messages.RegistrationResource(uri=regr_uri) regr = acme.query_registration(msg) log.info('Auto-accepting TOS: %s from: %s', regr.terms_of_service, directory_url) acme.agree_to_tos(regr) authzr = acme.request_challenges( identifier=messages.Identifier(typ=messages.IDENTIFIER_FQDN, value=domain)) log.debug('Created auth client %s', authzr) def get_http_challenge(x, y): return y if isinstance(y.chall, challenges.HTTP01) else x challb = reduce(get_http_challenge, authzr.body.challenges, None) chall_tok = challb.chall.validation(accnt_key) v = chall_tok.split('.')[0] log.info('Exposing challenge on %s', v) tmp_chall_dict.set(v, ChallTok(chall_tok)) test_path = 'http://localhost:8082{}'.format(challb.path) local_req = Request(test_path, headers={'Host': domain}) log.debug('Testing local url path: %s', test_path) try: resp = urlopen(local_req) t = resp.read().decode('utf-8').strip() if t != chall_tok: raise ValueError except (IOError, ValueError): log.info('Resolving challenge locally failed. ACME request will fail. %s', test_path) raise cr = acme.answer_challenge(challb, challb.chall.response(accnt_key)) log.debug('Acme CA responded to challenge request with: %s', cr) try: # Wrap this step and log the failure particularly here because this is # the expected point of failure for applications that are not reachable # from the public internet. cert_res, _ = acme.poll_and_request_issuance(jose.util.ComparableX509(csr), (authzr,)) # NOTE pylint disabled due to spurious reporting. See docs: # https://letsencrypt.readthedocs.io/projects/acme/en/latest/api/jose/util.html#acme.jose.util.ComparableX509 # pylint: disable=no-member cert_str = cert_res.body._dump(FILETYPE_PEM) except messages.Error as error: log.err("Failed in request issuance step %s", error) raise chain_certs = acme.fetch_chain(cert_res) # The chain certs returned by the LE CA will always have at least one # intermediate cert. Other certificate authorities that run ACME may # behave differently, but we aren't using them. chain_str = dump_certificate(FILETYPE_PEM, chain_certs[0]) # pylint: disable=no-member expr_date = convert_asn1_date(cert_res.body.wrapped.get_notAfter()) log.info('Retrieved cert using ACME that expires on %s', expr_date) return cert_str, chain_str
def setUp(self): self.config = mock.MagicMock(config_dir="/etc/letsencrypt") reg = messages.Registration.from_data(email="*****@*****.**") self.acc = mock.MagicMock(regr=messages.RegistrationResource( uri=None, new_authzr_uri=None, body=reg))
def wildcard_request(cn, account): def dns_check_ns1(): recieved_data_dup = [] recieved_data = [] ns1_resolver = dns.resolver.Resolver() #ns1_resolver.nameservers = ['130.193.8.82','2a03:b780::1:1'] ns1_resolver.nameservers = ['173.245.58.51'] for data in validation_data: domainname = data[1] #challenge = data[0] answers = ns1_resolver.query(domainname, 'txt') for rdata in answers: recieved_data_dup.append( [str(rdata).replace('"', ''), domainname]) #Deduplication of ns records (in case of more cnames) for i in recieved_data_dup: if i not in recieved_data: recieved_data.append(i) # print sorted(recieved_data) # print sorted(validation_data) if sorted(validation_data) == sorted(recieved_data): return True else: return False #Check if CN is valid domain domain_regex = re.compile( "^([a-zA-Z0-9]([\-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)*([a-zA-Z0-9]([\-a-zA-Z0-9]{0,61}[a-zA-Z0-9])+\.)([a-zA-Z0-9]+([\-a-zA-Z0-9]{0,61}[a-zA-Z])+)$" ) if not domain_regex.match(cn): print 'First argument is not valid CN' sys.exit(1) #Check if registrar exists if account not in os.listdir(REG_DIRECTORY): print "This account does not exists, register it first with new_account.py" sys.exit(1) #Load files from disk with open(REG_DIRECTORY + "/" + account + "/private.key", "rb") as key_file: privkey = serialization.load_pem_private_key(key_file.read(), password=None, backend=default_backend()) with open(REG_DIRECTORY + "/" + account + "/reguri.txt", "r") as reguri_file: reg_uri = reguri_file.read() #Compose regr key = jose.JWKRSA(key=privkey) regr = messages.RegistrationResource( body=messages.Registration(key=key.public_key()), uri=reg_uri) #Init ACME net = ClientNetwork(key) directory = net.get(DIRECTORY_URL).json() acme = client.ClientV2(directory, net) #Check if registration is valid if acme.query_registration(regr).body.status == u'valid': print "Registration valid" else: print "Registration invalid" sys.exit(1) #Generate private key for certificate pkey = OpenSSL.crypto.PKey() pkey.generate_key(OpenSSL.crypto.TYPE_RSA, BITS) #Serialize key for output pkey_printable = OpenSSL.crypto.dump_privatekey( OpenSSL.crypto.FILETYPE_PEM, pkey, cipher=None, passphrase=None) #Compose request for acme req = crypto_util.make_csr( OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, pkey), [cn, '*.' + cn]) #begin order orderr = acme.new_order(req) validation_data = [] for authr in orderr.authorizations: for chalr in authr.body.challenges: if type(chalr.chall) == type(challenges.DNS01()): validation_data.append([ str(chalr.chall.validation(key)), chalr.chall.validation_domain_name(cn) ]) #print validation_data #Now, call DNS writing function to apply challenges dns_apply(cn, validation_data) #Check if DNS is valid on our server sys.stdin.readline() #DEBUG: wait for manual DNS input limiter = 2 while not dns_check_ns1(): if limiter != 0: print "DNS records are not correct, trying again in few seconds" limiter = limiter - 1 time.sleep(5) else: print "DNS are not correct even after several tries. Aborting" sys.exit(1) for authr in orderr.authorizations: for chalr in authr.body.challenges: if type(chalr.chall) == type(challenges.DNS01()): try: acme.answer_challenge(chalr, challenges.DNS01Response()) except: print chalr.chall.encode( 'token' ) + " already answered (challenge failed, you have to generate new one)" #After filling DNS and waiting for propagation, finalize order try: res = acme.poll_and_finalize(orderr) finally: dns_remove(cn) #logging.info(res) cert = x509.load_pem_x509_certificate(str(res.fullchain_pem), default_backend()) output_data = { 'wildcard': { 'cn': cn, 'private_key': str(pkey_printable), 'certificate': str(res.fullchain_pem), 'expiration': cert.not_valid_after.strftime( "%x %X" ) #Locale-specific time+date representation. Edit to your need } } print json.dumps(output_data)