def test_rsa_key(self): """ Passing ``u'rsa'`` results in an RSA private key. """ key1 = generate_private_key(u'rsa') self.assertThat(key1, IsInstance(rsa.RSAPrivateKey)) key2 = generate_private_key(u'rsa') self.assertThat(key2, IsInstance(rsa.RSAPrivateKey)) self.assertThat(key1.public_key().public_numbers(), Not(Equals(key2.public_key().public_numbers())))
def test_rsa_key(self): """ Passing ``u'rsa'`` results in an RSA private key. """ key1 = generate_private_key(u'rsa') self.assertThat(key1, IsInstance(rsa.RSAPrivateKey)) key2 = generate_private_key(u'rsa') self.assertThat(key2, IsInstance(rsa.RSAPrivateKey)) self.assertThat( key1.public_key().public_numbers(), Not(Equals(key2.public_key().public_numbers())))
def test_rsa_key(self): """ Passing ``u'rsa'`` results in an RSA private key. """ key1 = generate_private_key(u'rsa') self.assertIsInstance(key1,rsa.RSAPrivateKey) key2 = generate_private_key(u'rsa') self.assertIsInstance(key2, rsa.RSAPrivateKey) self.assertNotEqual( key1.public_key().public_numbers(), key2.public_key().public_numbers() )
def generate_wildcard_pem_bytes(): """ Generate a wildcard (subject name '*') self-signed certificate valid for 10 years. https://cryptography.io/en/latest/x509/tutorial/#creating-a-self-signed-certificate :return: Bytes representation of the PEM certificate data """ key = generate_private_key(u'rsa') name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'*')]) cert = (x509.CertificateBuilder().issuer_name(name).subject_name( name).not_valid_before(datetime.today() - timedelta( days=1)).not_valid_after(datetime.now() + timedelta(days=3650)).serial_number( int(uuid.uuid4())).public_key( key.public_key()).sign( private_key=key, algorithm=hashes.SHA256(), backend=default_backend())) return b''.join((key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()), cert.public_bytes(serialization.Encoding.PEM)))
def _parse(reactor, directory, pemdir, *args, **kwargs): """ Parse a txacme endpoint description. :param reactor: The Twisted reactor. :param directory: ``twisted.python.url.URL`` for the ACME directory to use for issuing certs. :param str pemdir: The path to the certificate directory to use. """ onstore_scripts = kwargs.pop('onstore', 'false').lower().startswith('t') def colon_join(items): return ':'.join([item.replace(':', '\\:') for item in items]) sub = colon_join(list(args) + ['='.join(item) for item in kwargs.items()]) pem_path = FilePath(pemdir).asTextMode() acme_key_file = pem_path.child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key( acme_key_file.getContent(), password=None, backend=default_backend()) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) acme_key = JWKRSA(key=key) return AutoTLSEndpoint( reactor=reactor, directory=directory, client_creator=partial(Client.from_url, key=acme_key, alg=RS256), cert_store=DirectoryStore(pem_path, onstore_scripts=onstore_scripts), cert_mapping=HostDirectoryMap(pem_path), sub_endpoint=serverFromString(reactor, sub))
def _generate_ca_cert(self): """ Generate a CA cert/key. """ if self._ca_key is None: self._ca_key = generate_private_key(u'rsa') self._ca_name = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u'ACME Snake Oil CA')]) self._ca_cert = ( x509.CertificateBuilder() .subject_name(self._ca_name) .issuer_name(self._ca_name) .not_valid_before(self._now() - timedelta(seconds=3600)) .not_valid_after(self._now() + timedelta(days=3650)) .public_key(self._ca_key.public_key()) .serial_number(int(uuid4())) .add_extension( x509.BasicConstraints(ca=True, path_length=0), critical=True) .add_extension( x509.SubjectKeyIdentifier.from_public_key( self._ca_key.public_key()), critical=False) .sign( private_key=self._ca_key, algorithm=hashes.SHA256(), backend=default_backend())) self._ca_aki = x509.AuthorityKeyIdentifier.from_issuer_public_key( self._ca_key.public_key())
def load_or_create_client_key(key_file): """Load the ACME account key from a file, creating it if it does not exist. Args: key_file (str): name of the file to use as the account key """ # this is based on txacme.endpoint.load_or_create_client_key, but doesn't # hardcode the 'client.key' filename acme_key_file = FilePath(key_file) if acme_key_file.exists(): logger.info("Loading ACME account key from '%s'", acme_key_file) key = serialization.load_pem_private_key( acme_key_file.getContent(), password=None, backend=default_backend() ) else: logger.info("Saving new ACME account key to '%s'", acme_key_file) key = generate_private_key("rsa") acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) ) return JWKRSA(key=key)
def generate_wildcard_pem_bytes(): """ Generate a wildcard (subject name '*') self-signed certificate valid for 10 years. https://cryptography.io/en/latest/x509/tutorial/#creating-a-self-signed-certificate :return: Bytes representation of the PEM certificate data """ key = generate_private_key(u'rsa') name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'*')]) cert = ( x509.CertificateBuilder() .issuer_name(name) .subject_name(name) .not_valid_before(datetime.today() - timedelta(days=1)) .not_valid_after(datetime.now() + timedelta(days=3650)) .serial_number(int(uuid.uuid4())) .public_key(key.public_key()) .sign( private_key=key, algorithm=hashes.SHA256(), backend=default_backend()) ) return b''.join(( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()), cert.public_bytes(serialization.Encoding.PEM) ))
def maybe_key(pem_path): """ Set up a client key if one does not exist already. https://gist.github.com/glyph/27867a478bb71d8b6046fbfb176e1a33#file-local-certs-py-L32-L50 :type pem_path: twisted.python.filepath.FilePath :param pem_path: The path to the certificate directory to use. """ acme_key_file = pem_path.child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key( acme_key_file.getContent(), password=None, backend=default_backend() ) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() ) ) return JWKRSA(key=key)
def setup_method(self): self.fake_marathon = FakeMarathon() self.fake_marathon_api = FakeMarathonAPI(self.fake_marathon) self.cert_store = MemoryStore() self.fake_marathon_lb = FakeMarathonLb() key = JWKRSA(key=generate_private_key(u'rsa')) self.clock = Clock() self.clock.rightNow = ( datetime.now() - datetime(1970, 1, 1)).total_seconds() self.txacme_client = FailableTxacmeClient(key, self.clock)
def maybe_key(pem_path): acme_key_file = pem_path.child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key(acme_key_file.getContent(), password=None, backend=default_backend()) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) acme_key = JWKRSA(key=key) return acme_key
def test_key_exists(self, pem_path): """ When we get the client key and the key file already exists, the file should be read and the existing key returned. """ raw_key = generate_private_key(u'rsa') expected_key = JWKRSA(key=raw_key) pem_file = pem_path.child(u'client.key') pem_file.setContent(raw_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() )) actual_key = maybe_key(pem_path) assert_that(actual_key, Equals(expected_key))
def _test_issue(self, name): def got_cert(certr): key_bytes = self.issued_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) FilePath('issued.crt').setContent(certr.body) FilePath('issued.key').setContent(key_bytes) return certr action = start_action(action_type=u'integration:issue') with action.context(): self.issued_key = generate_private_key('rsa') csr = csr_for_names([name], self.issued_key) return (DeferredContext( self.client.request_issuance(CertificateRequest( csr=csr))).addCallback(got_cert).addActionFinish())
def _test_issue(self, name): def got_cert(certr): key_bytes = self.issued_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) FilePath('issued.crt').setContent(certr.body) FilePath('issued.key').setContent(key_bytes) return certr action = start_action(action_type=u'integration:issue') with action.context(): self.issued_key = generate_private_key('rsa') csr = csr_for_names([name], self.issued_key) return ( DeferredContext( self.client.request_issuance(CertificateRequest(csr=csr))) .addCallback(got_cert) .addActionFinish())
def _get_account_key(): """ Return the private key to be used for ACME interaction. """ if ACCOUNT_KEY_PEM: return serialization.load_pem_private_key( ACCOUNT_KEY_PEM.encode('ascii'), password=None, backend=default_backend(), ) # We don't have a key...so generate one. key = generate_private_key('rsa') account_key = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) print('New account key generated:\n%s' % (account_key)) return key
def setup_method(self): self.fake_marathon = FakeMarathon() self.fake_marathon_api = FakeMarathonAPI(self.fake_marathon) marathon_client = MarathonClient(['http://localhost:8080'], client=self.fake_marathon_api.client) self.cert_store = MemoryStore() self.fake_marathon_lb = FakeMarathonLb() mlb_client = MarathonLbClient(['http://localhost:9090'], client=self.fake_marathon_lb.client) key = JWKRSA(key=generate_private_key(u'rsa')) clock = Clock() clock.rightNow = (datetime.now() - datetime(1970, 1, 1)).total_seconds() self.txacme_client = FailableTxacmeClient(key, clock) self.marathon_acme = MarathonAcme(marathon_client, 'external', self.cert_store, mlb_client, lambda: succeed(self.txacme_client), clock)
def maybe_key(pem_path): """ Set up a client key if one does not exist already. https://gist.github.com/glyph/27867a478bb71d8b6046fbfb176e1a33#file-local-certs-py-L32-L50 :type pem_path: twisted.python.filepath.FilePath :param pem_path: The path to the certificate directory to use. """ acme_key_file = pem_path.child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key(acme_key_file.getContent(), password=None, backend=default_backend()) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) return jose.JWKRSA(key=key)
def load_or_create_client_key(pem_path): """ Load the client key from a directory, creating it if it does not exist. .. note:: The client key that will be created will be a 2048-bit RSA key. :type pem_path: ``twisted.python.filepath.FilePath`` :param pem_path: The certificate directory to use, as with the endpoint. """ acme_key_file = pem_path.asTextMode().child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key(acme_key_file.getContent(), password=None, backend=default_backend()) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) return JWKRSA(key=key)
def load_or_create_client_key(pem_path): """ Load the client key from a directory, creating it if it does not exist. .. note:: The client key that will be created will be a 2048-bit RSA key. :type pem_path: ``twisted.python.filepath.FilePath`` :param pem_path: The certificate directory to use, as with the endpoint. """ acme_key_file = pem_path.asTextMode().child(u'client.key') if acme_key_file.exists(): key = serialization.load_pem_private_key( acme_key_file.getContent(), password=None, backend=default_backend()) else: key = generate_private_key(u'rsa') acme_key_file.setContent( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) return JWKRSA(key=key)
def _generate_ca_cert(self): """ Generate a CA cert/key. """ if self._ca_key is None: self._ca_key = generate_private_key(u'rsa') self._ca_name = x509.Name( [x509.NameAttribute(NameOID.COMMON_NAME, u'ACME Snake Oil CA')]) self._ca_cert = ( x509.CertificateBuilder().subject_name(self._ca_name).issuer_name( self._ca_name).not_valid_before(self._now() - timedelta(seconds=3600)). not_valid_after(self._now() + timedelta(days=3650)).public_key( self._ca_key.public_key()).serial_number(int( uuid4())).add_extension( x509.BasicConstraints(ca=True, path_length=0), critical=True).add_extension( x509.SubjectKeyIdentifier.from_public_key( self._ca_key.public_key()), critical=False).sign(private_key=self._ca_key, algorithm=hashes.SHA256(), backend=default_backend())) self._ca_aki = x509.AuthorityKeyIdentifier.from_issuer_public_key( self._ca_key.public_key())
def test_unknown_key_type(self, key_type): """ Passing an unknown key type results in :exc:`.ValueError`. """ with ExpectedException(ValueError): generate_private_key(key_type)
def _test_create_client(self): with start_action(action_type=u'integration:create_client').context(): self.key = JWKRSA(key=generate_private_key('rsa')) return ( DeferredContext(self._create_client(self.key)) .addActionFinish())
def test_unknown_key_type(self): """ Passing an unknown key type results in :exc:`.ValueError`. """ with self.assertRaises(ValueError): generate_private_key(u'not-a-real-key-type')
def get_things_done(): """ Here is where the client part is setup and action is done. """ responders = yield start_responders() # We first validate the directory. account_key = _get_account_key() try: client = yield Client.from_url( reactor, URL.fromText(acme_url.decode('utf-8')), key=JWKRSA(key=account_key), alg=RS256, ) except Exception as error: print('\n\nFailed to connect to ACME directory. %s' % (error, )) yield reactor.stop() defer.returnValue(None) # Then we register a new account or update an existing account. # First register a new account with a contact set, then using the same # key call register with a different contact and see that it was updated. response = yield client.start( email='[email protected],[email protected]') print('Account URI: %s' % (response.uri, )) print('Account contact: %s' % (response.body.contact, )) # We request a single certificate for a list of domains and get an "order" cert_key = generate_private_key('rsa') orderr = yield client.submit_order(cert_key, requested_domains) # Each order had a list of "authorizations" for which the challenge needs # to be validated. for authorization in orderr.authorizations: try: # Make sure all ACME server requests are sequential. # For now, answering to the challenges in parallel will not work. yield answer_challenge(authorization, client, responders, clock=reactor) except Exception as error: print('\n\nFailed to validate a challenge. %s' % (error, )) yield reactor.stop() defer.returnValue(None) certificate = yield get_certificate(orderr, client, clock=reactor) print('Got a new cert:\n') print(certificate.body) cert_key_pem = cert_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # Cleanup the client and disconnect any persistent connection to the # ACME server. yield client.stop() # The new certificate is available and we can start a demo HTTPS server # using it. yield start_https_demo_server(cert_key_pem, certificate.body) print('txacme demo done.')