def register(self, new_reg=None): """Register. :param .NewRegistration new_reg: :returns: Registration Resource. :rtype: `.RegistrationResource` :raises .UnexpectedUpdate: """ new_reg = messages.NewRegistration() if new_reg is None else new_reg assert isinstance(new_reg, messages.NewRegistration) response = self.net.post(self.directory[new_reg], new_reg) # TODO: handle errors assert response.status_code == http_client.CREATED # "Instance of 'Field' has no key/contact member" bug: # pylint: disable=no-member regr = self._regr_from_response(response) if (regr.body.key != self.key.public_key() or regr.body.contact != new_reg.contact): raise errors.UnexpectedUpdate(regr) return regr
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.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') # 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)
def register(self, new_reg=None): self._registered = True if new_reg is None: new_reg = messages.NewRegistration() self.regr = messages.RegistrationResource(body=messages.Registration( contact=new_reg.contact, agreement=new_reg.agreement)) return succeed(self.regr)
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', }) 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')
def _monkeypatch_register(self, new_reg=None): new_reg = new_reg or messages.NewRegistration() response = self.net.post(self.directory[new_reg], new_reg, check_response=False) loc = None if response.status_code == client.http_client.CONFLICT and response.headers.get( 'Location'): reg = messages.UpdateRegistration() loc = response.headers.get('Location') response = self.net.post(loc, reg) return self._regr_from_response(response, uri=loc)
def registerNewAccount(conf, key): """ Attempt to create a new account on the ACME server with the key. No problem if it fails because this kye is already used. """ LOG.info("Registering with ACME server with the new key") newReg = messages.NewRegistration(contact=tuple(conf['info']), key=key.public_key()) acme_client = client.Client(conf['directory'], key) registration_resource = acme_client.register(newReg) LOG.info("Agreeing on the TOS on your behalf") acme_client.agree_to_tos(registration_resource)
def create_registration(): global privkey, regr privkey = rsa.generate_private_key(public_exponent=65537, key_size=BITS, backend=default_backend()) key = jose.JWKRSA(key=privkey) net = ClientNetwork(key) directory = net.get(DIRECTORY_URL).json() acme = client.ClientV2(directory, net) regbody = dict( messages.Registration(contact=('mailto:[email protected]', ), terms_of_service_agreed=True, key=key.public_key())) #NEED TO SAVE REGBODY VARIABLE TO FILE regr = acme.new_account(messages.NewRegistration(**regbody))
def register(self, new_reg=None): """Register. :param .NewRegistration new_reg: :returns: Registration Resource. :rtype: `.RegistrationResource` """ new_reg = messages.NewRegistration() if new_reg is None else new_reg response = self._post(self.directory[new_reg], new_reg) # TODO: handle errors assert response.status_code == http_client.CREATED # "Instance of 'Field' has no key/contact member" bug: return self._regr_from_response(response)
def register(self, new_reg=None): """ Create a new registration with the ACME server. :param ~acme.messages.NewRegistration new_reg: The registration message to use, or ``None`` to construct one. :return: The registration resource. :rtype: Deferred[`~acme.messages.RegistrationResource`] """ if new_reg is None: new_reg = messages.NewRegistration() action = LOG_ACME_REGISTER(registration=new_reg) with action.context(): return (DeferredContext( self.update_registration( new_reg, uri=self.directory[new_reg])).addErrback( self._maybe_registered, new_reg).addCallback( tap(lambda r: action.add_success_fields( registration=r))).addActionFinish())
def _get_or_create_account(self): """Register account if not already done, else just return ACME client updated with existing account""" logger.info("Registering account...") ca_key = serialization.load_pem_private_key( data=self.account_key.read_bytes(), password=None, backend=default_backend(), ) acc_key = jose.JWKRSA(key=ca_key) # Register account and accept TOS client_network = client.ClientNetwork(acc_key, user_agent=USER_AGENT) directory = messages.Directory.from_json(client_network.get(self.ca_api + '/directory').json()) client_acme = client.ClientV2(directory=directory, net=client_network) try: # Creates account with contact information. # Terms of Service URL is in client_acme.directory.meta.terms_of_service client_acme.new_account( messages.NewRegistration.from_data( email=self.contact_email, terms_of_service_agreed=True, ) ) logger.info("New account successfully created!") except errors.ConflictError: logger.info("Account already registered!") # retrieve existing account information account_registration = messages.NewRegistration(key=acc_key.public_key(), only_return_existing=True) # TODO migrate to public API when available in ACME module # reproduce code of client_acme.new_account but without throwing exception when account already exists response = client_acme._post(directory['newAccount'], account_registration) account_info = client_acme._regr_from_response(response) # assign registration information to existing client client_acme.net.account = account_info return client_acme
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)