def test_client_chain_certificate(self): """ A certificate chain in the *client-certificate* section of in the kube configuration file is used to configure the TLS context used when connecting to the API server. """ def sign_ca_cert(key, requestObject, dn): from OpenSSL.crypto import X509, X509Extension from twisted.internet.ssl import Certificate req = requestObject.original cert = X509() dn._copyInto(cert.get_issuer()) cert.set_subject(req.get_subject()) cert.set_pubkey(req.get_pubkey()) cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(60 * 60) cert.set_serial_number(1) cert.add_extensions([ X509Extension(b"basicConstraints", True, b"CA:TRUE"), # Not necessarily a good way to populate subjectAltName but it # quiets the deprecation warning we get from service_identity. X509Extension(b"subjectAltName", True, b"DNS:" + dn.commonName), ]) cert.sign(key.original, "sha256") return Certificate(cert) ca_key = KeyPair.generate() ca_req = ca_key.requestObject(DN(commonName="kubernetes")) ca_cert = sign_ca_cert(ca_key, ca_req, DN(commonName="kubernetes")) intermediate_key = KeyPair.generate() intermediate_req = intermediate_key.requestObject(DN(commonName="intermediate")) intermediate_cert = sign_ca_cert(ca_key, intermediate_req, DN(commonName="kubernetes")) client_key = KeyPair.generate() client_req = client_key.requestObject(DN(commonName="client")) client_cert = intermediate_key.signRequestObject(DN(commonName="intermediate"), client_req, 1) chain = b"".join([ client_cert.dumpPEM(), intermediate_cert.dumpPEM(), ]) FilePath("ca.key").setContent(ca_key.dump(FILETYPE_PEM)) FilePath("ca.crt").setContent(ca_cert.dump(FILETYPE_PEM)) FilePath("intermediate.crt").setContent(intermediate_cert.dump(FILETYPE_PEM)) FilePath("client.key").setContent(client_key.dump(FILETYPE_PEM)) FilePath("client.crt").setContent(client_cert.dump(FILETYPE_PEM)) FilePath("chain.crt").setContent(chain) config = self.write_config(ca_cert, chain, client_key) kubernetes = lambda reactor: network_kubernetes_from_context( reactor, "foo-ctx", path=config, ) return self.check_tls_config(ca_key, ca_cert, kubernetes)
def setUp(self): """ Create a L{PantheonHTTPChecker} pointed at a mock authentication service with some simple site and user information. """ self.site = 'example.com' self.cwd = '/some/path' self.uid = 1542 self.username = '******' self.password = '******' keyString = FilePath(__file__).sibling('id_rsa').getContent() self.privateKey = Key.fromString(keyString) caKeyString = FilePath(__file__).sibling('cakey.pem').getContent() self.caKey = KeyPair.load(caKeyString, FILETYPE_PEM) caCertString = FilePath(__file__).sibling('cacert.pem').getContent() self.caCert = PrivateCertificate.load( caCertString, self.caKey, FILETYPE_PEM) self.resource = MockPantheonAuthResource( sites={self.site: [self.username]}, authorizations={self.site: dict(cwd=self.cwd, uid=self.uid)}, passwords={self.username: self.password}, keys={self.username: self.privateKey}, ) self.server = MockPantheonAuthServer( reactor, self.resource, self.caCert) self.server.startService() self.addCleanup(self.server.stopService)
def getServerContext(self): """ Generate a new L{OpenSSL.SSL.Context} object configured to use a certificate signed by C{self.ca} and only accept connections from peers which are also using a certificate signed by C{self.ca}. """ # Generate a new key for the server and have the CA sign a certificate # for it. key = KeyPair.generate(size=512) req = key.certificateRequest(DN(commonName='localhost')) certData = self.ca.signCertificateRequest(req, lambda dn: True, 1) cert = PrivateCertificate.load(certData, key) # Use the new key/certificate context = Context(TLSv1_METHOD) context.use_privatekey(key.original) context.use_certificate(cert.original) context.check_privatekey() # Allow peer certificates signed by the CA store = context.get_cert_store() store.add_cert(self.ca.original) # Verify the peer certificate and require that they have one. def verify(conn, cert, errno, depth, preverify_ok): return preverify_ok context.set_verify(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify) return context
def pems(): for i in count(): key = KeyPair.generate() cert = key.selfSignedCert(i, commonName=u"lae_automation testing") pem = PrivateCertificate.fromCertificateAndKeyPair(cert, key).dumpPEM() yield pem.decode("ascii")
def test_ssl(self): """ When passed an SSL strports description, L{clientFromString} returns a L{SSL4ClientEndpoint} instance initialized with the values from the string. """ reactor = object() client = endpoints.clientFromString( reactor, "ssl:host=example.net:port=4321:privateKey=%s:" "certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" % (escapedPEMPathName, escapedPEMPathName, escapedCAsPathName)) self.assertIsInstance(client, endpoints.SSL4ClientEndpoint) self.assertIdentical(client._reactor, reactor) self.assertEquals(client._host, "example.net") self.assertEquals(client._port, 4321) self.assertEquals(client._timeout, 3) self.assertEquals(client._bindAddress, "10.0.0.3") certOptions = client._sslContextFactory self.assertIsInstance(certOptions, CertificateOptions) ctx = certOptions.getContext() self.assertIsInstance(ctx, ContextType) self.assertEquals(Certificate(certOptions.certificate), testCertificate) privateCert = PrivateCertificate(certOptions.certificate) privateCert._setPrivateKey(KeyPair(certOptions.privateKey)) self.assertEquals(privateCert, testPrivateCertificate) expectedCerts = [ Certificate.loadPEM(x.getContent()) for x in [casPath.child("thing1.pem"), casPath.child("thing2.pem")] if x.basename().lower().endswith('.pem') ] self.assertEquals([Certificate(x) for x in certOptions.caCerts], expectedCerts)
def clientCertFor(name): signingCert = getCAPrivateCert() clientKey = KeyPair.generate(size=4096) csr = clientKey.requestObject(DN(CN=name), "sha1") clientCert = signingCert.signRequestObject( csr, serialNumber=1, digestAlgorithm="sha1") return PrivateCertificate.fromCertificateAndKeyPair(clientCert, clientKey)
def get_context_factory(cert_path, pkey_path): """OpenSSL context factory. Generates an OpenSSL context factory using Twisted's CertificateOptions class. This will keep a server cipher order. Args: cert_path (string): The path to the certificate file pkey_path (string): The path to the private key file Returns: twisted.internet.ssl.CertificateOptions: An OpenSSL context factory """ with open(cert_path) as cert: certificate = Certificate.loadPEM(cert.read()).original with open(pkey_path) as pkey: private_key = KeyPair.load(pkey.read(), FILETYPE_PEM).original ciphers = AcceptableCiphers.fromOpenSSLCipherString(TLS_CIPHERS) cert_options = CertificateOptions( privateKey=private_key, certificate=certificate, raiseMinimumTo=TLSVersion.TLSv1_2, acceptableCiphers=ciphers, ) ctx = cert_options.getContext() ctx.use_certificate_chain_file(cert_path) ctx.set_options(SSL_OP_NO_RENEGOTIATION) return cert_options
def flocker_keypair(): """ Create a new 4096-bit RSA key pair. """ return ComparableKeyPair( keypair=KeyPair.generate(crypto.TYPE_RSA, size=4096) )
def testBadCertRequestSubject(self): kp = KeyPair.generate() subject = DistinguishedName(commonName='HACKERX', localityName='INTERNETANIA') reqobj = kp.requestObject(subject) fakereq = kp.requestObject(subject) ssigned = kp.signRequestObject(subject, fakereq, 1) certpair = PrivateCertificate.fromCertificateAndKeyPair fakecert = certpair(ssigned, kp) apc = self.serverService2.certificateStorage.addPrivateCertificate def _2(secured): D = secured.callRemote( q2q.Sign, certificate_request=reqobj, password='******') def _1(dcert): cert = dcert['certificate'] privcert = certpair(cert, kp) apc(str(self.fromAddress), privcert) return D.addCallback(_1) d = self.serverService2.getSecureConnection( self.fromAddress, self.fromAddress.domainAddress(), authorize=False, usePrivateCertificate=fakecert, ).addCallback(_2) def unexpectedSuccess(result): self.fail("Expected BadCertificateRequest, got %r" % (result,)) def expectedFailure(err): err.trap(q2q.BadCertificateRequest) d.addCallbacks(unexpectedSuccess, expectedFailure) return d
def clientCertFor(p_name): l_signingCert = getCAPrivateCert() l_clientKey = KeyPair.generate(size = 4096) l_csr = l_clientKey.requestObject(DN(CN = p_name), "sha1") l_clientCert = l_signingCert.signRequestObject( l_csr, serialNumber = 1, digestAlgorithm = "sha1") return PrivateCertificate.fromCertificateAndKeyPair(l_clientCert, l_clientKey)
def generate_keypair(): """ Create a new 4096-bit RSA key pair. """ return FlockerKeyPair( keypair=KeyPair.generate(crypto.TYPE_RSA, size=4096) )
def clientCertFor(name): signingCert = getCAPrivateCert() clientKey = KeyPair.generate(size=4096) csr = clientKey.requestObject(DN(CN=name), "sha1") clientCert = signingCert.signRequestObject(csr, serialNumber=1, digestAlgorithm="sha1") return PrivateCertificate.fromCertificateAndKeyPair(clientCert, clientKey)
def getServerContext(self): """ Return a new SSL context suitable for use in a test server. """ pem = self._pem.getContent() cert = PrivateCertificate.load( pem, KeyPair.load(pem, FILETYPE_PEM), FILETYPE_PEM) return cert.options()
def getServerContext(self): """ Return a new SSL context suitable for use in a test server. """ cert = PrivateCertificate.load( self._certificateText, KeyPair.load(self._privateKeyText, FILETYPE_PEM), FILETYPE_PEM) return cert.options()
def getCAPrivateCert(): privatePath = FilePath(b"ca-private-cert.pem") if privatePath.exists(): return PrivateCertificate.loadPEM(privatePath.getContent()) else: caKey = KeyPair.generate(size=4096) caCert = caKey.selfSignedCert(1, CN="the-authority") privatePath.setContent(caCert.dumpPEM()) return caCert
def getCAPrivateCert(): l_privatePath = FilePath(b"ca-private-cert.pem") if l_privatePath.exists(): return PrivateCertificate.loadPEM(l_privatePath.getContent()) else: l_caKey = KeyPair.generate(size=4096) l_caCert = l_caKey.selfSignedCert(1, CN="the-authority") l_privatePath.setContent(l_caCert.dumpPEM()) return l_caCert
def clientCertFor(p_name): l_signingCert = getCAPrivateCert() l_clientKey = KeyPair.generate(size=4096) l_csr = l_clientKey.requestObject(DN(CN=p_name), "sha1") l_clientCert = l_signingCert.signRequestObject(l_csr, serialNumber=1, digestAlgorithm="sha1") return PrivateCertificate.fromCertificateAndKeyPair( l_clientCert, l_clientKey)
def requestCert(config): subject = config['subject'] path = config['path'] store = yield config.parent.storeDeferred key = KeyPair.loadPEM(path.getContent()) req = generateCertificateRequest(key, subject) yield store.submitCertificateRequest(req)
def makeCert(cn): """ Create a self-signed cert. """ sharedDN = DN(CN=cn) key = KeyPair.generate() cr = key.certificateRequest(sharedDN) sscrd = key.signCertificateRequest(sharedDN, cr, lambda dn: True, 1) return key.newCertificate(sscrd)
def new_tahoe_configuration(deploy_config, bucketname, key_prefix, publichost, privatehost, introducer_port, storageserver_port): """ Create brand new secrets and configuration for use by an introducer/storage pair. """ base_name = dict( organizationName=b"Least Authority Enterprises", organizationalUnitName=b"S4", emailAddress=bucketname, ) keypair = KeyPair.generate(size=2048) introducer_certificate = keypair.selfSignedCert( serialNumber=1, commonName=b"introducer", **base_name ) storage_certificate = keypair.selfSignedCert( serialNumber=1, commonName=b"storage", **base_name ) def pem(key, cert): return b"\n".join((key.dump(FILETYPE_PEM), cert.dump(FILETYPE_PEM))) introducer_tub = Tub(certData=pem(keypair, introducer_certificate)) introducer_tub.setLocation("{}:{}".format(publichost, introducer_port)) storage_tub = Tub(certData=pem(keypair, storage_certificate)) return marshal_tahoe_configuration( introducer_pem=introducer_tub.getCertData().strip(), storage_pem=storage_tub.getCertData().strip(), storage_privkey=keyutil.make_keypair()[0] + b"\n", introducer_port=introducer_port, storageserver_port=storageserver_port, bucket_name=bucketname, key_prefix=key_prefix, publichost=publichost, privatehost=privatehost, # The object of the reference is irrelevant. The furl will # get hooked up to something else when Tahoe really runs. # Just need to pass something _weak referenceable_! Which # rules out a lot of things... introducer_furl=introducer_tub.registerReference(introducer_tub), s3_access_key_id=deploy_config.s3_access_key_id, s3_secret_key=deploy_config.s3_secret_key, log_gatherer_furl=deploy_config.log_gatherer_furl, stats_gatherer_furl=deploy_config.stats_gatherer_furl, )
def makeCertRequest(cn): """ Create a certificate request with the given common name. @param cn: Common Name to use in certificate request. @type cn: L{bytes} @return: Certificate request. @rtype: L{CertificateRequest} """ key = KeyPair.generate() return key.certificateRequest(DN(CN=cn))
def start_ssl(self): log.debug("Enabling SSL with PKey: %s, Cert: %s", self.pkey, self.cert) check_ssl_keys() with open(configmanager.get_config_dir(self.cert)) as cert: certificate = Certificate.loadPEM(cert.read()).original with open(configmanager.get_config_dir(self.pkey)) as pkey: private_key = KeyPair.load(pkey.read(), FILETYPE_PEM).original options = CertificateOptions(privateKey=private_key, certificate=certificate, method=SSL.SSLv23_METHOD) options.getContext().set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) self.socket = reactor.listenSSL(self.port, self.site, options) log.info("Serving on %s:%s view at https://127.0.0.1:%s", "0.0.0.0", self.port, self.port)
def createSSLCertificate(opts): sslopt = {} for x, y in (('country', 'C'), ('state', 'ST'), ('city', 'L'), ('organization', 'O'), ('unit', 'OU'), ('hostname', 'CN'), ('email', 'emailAddress')): sslopt[y] = opts[x] serialNumber = int(opts['serial-number']) ssc = KeyPair.generate().selfSignedCert(serialNumber, **sslopt) file(opts['filename'], 'w').write(ssc.dumpPEM()) if not opts['quiet']: print 'Wrote SSL certificate:' print ssc.inspect() return ssc
def fromFilePath(cls, filePath): privatePath = filePath.child('private') publicPath = filePath.child('public') csrPath = filePath.child('csr') issuerPath = filePath.child('issuer') if issuerPath.exists(): issuer = issuerPath.getContent() key = KeyPair.loadPEM(privatePath.child(issuer).getContent()) cert = Certificate.loadPEM(publicPath.child(issuer).getContent()) store = cls(publicPath, privatePath, csrPath, key, cert, issuer) return store
def _create_tls_client_context(config, cbdir, log): """ Create a CertificateOptions object for use with TLS listening endpoints. """ # server hostname: The expected name of the remote host. hostname = config['hostname'] # explicit trust (certificate) root ca_certs = None if 'ca_certificates' in config: log.info("TLS client using explicit trust ({cnt_certs} certificates)", cnt_certs=len(config['ca_certificates'])) ca_certs = [] for cert_fname in [os.path.abspath(os.path.join(cbdir, x)) for x in (config['ca_certificates'])]: cert = crypto.load_certificate( crypto.FILETYPE_PEM, six.u(open(cert_fname, 'r').read()) ) log.info("TLS client trust root CA certificate loaded from '{fname}'", fname=cert_fname) ca_certs.append(cert) ca_certs = OpenSSLCertificateAuthorities(ca_certs) else: log.info("TLS client using platform trust") # client key/cert to use client_cert = None if 'key' in config: if 'certificate' not in config: raise Exception('TLS client key present, but certificate missing') key_fname = os.path.abspath(os.path.join(cbdir, config['key'])) with open(key_fname, 'r') as f: private_key = KeyPair.load(f.read(), format=crypto.FILETYPE_PEM) log.info("Loaded client TLS key from '{key_fname}'", key_fname=key_fname) cert_fname = os.path.abspath(os.path.join(cbdir, config['certificate'])) with open(cert_fname, 'r') as f: cert = Certificate.loadPEM(f.read(),) log.info("Loaded client TLS certificate from '{cert_fname}' (cn='{cert_cn}', sha256={cert_sha256}..)", cert_fname=cert_fname, cert_cn=cert.getSubject().CN, cert_sha256=cert.digest('sha256')[:12]) client_cert = PrivateCertificate.fromCertificateAndKeyPair(cert, private_key) else: if 'certificate' in config: log.warn('TLS client certificate present, but key is missing') # create TLS client context ctx = optionsForClientTLS(hostname, trustRoot=ca_certs, clientCertificate=client_cert) return ctx
def from_path(cls, path): """ :param FilePath path: Directory where private key and certificate are stored. """ if not path.isdir(): raise PathError( b"Path {path} is not a directory.".format(path=path.path) ) certPath = path.child(certificate_filename) keyPath = path.child(key_filename) if not certPath.isfile(): raise PathError( b"Certificate file {path} does not exist.".format( path=certPath.path) ) if not keyPath.isfile(): raise PathError( b"Private key file {path} does not exist.".format( path=keyPath.path) ) try: certFile = certPath.open() except IOError: raise PathError( (b"Certificate file {path} could not be opened. " b"Check file permissions.").format( path=certPath.path) ) try: keyFile = keyPath.open() except IOError: raise PathError( (b"Private key file {path} could not be opened. " b"Check file permissions.").format( path=keyPath.path) ) certificate = Certificate.load( certFile.read(), format=crypto.FILETYPE_PEM) keypair = FlockerKeyPair( keypair=KeyPair.load(keyFile.read(), format=crypto.FILETYPE_PEM) ) return cls(path=path, certificate=certificate, keypair=keypair)
def createCertificate(): # this is copied from test_sslverify.py dn = DistinguishedName(commonName="newpb_thingy") keypair = KeyPair.generate(size=2048) req = keypair.certificateRequest(dn, digestAlgorithm="sha256") certData = keypair.signCertificateRequest(dn, req, lambda dn: True, 1, # serial number digestAlgorithm="sha256", ) cert = keypair.newCertificate(certData) #opts = cert.options() # 'opts' can be given to reactor.listenSSL, or to transport.startTLS return cert
def start_ssl(self): log.debug("Enabling SSL with PKey: %s, Cert: %s", self.pkey, self.cert) check_ssl_keys() with open(configmanager.get_config_dir(self.cert)) as cert: certificate = Certificate.loadPEM(cert.read()).original with open(configmanager.get_config_dir(self.pkey)) as pkey: private_key = KeyPair.load(pkey.read(), FILETYPE_PEM).original options = CertificateOptions(privateKey=private_key, certificate=certificate, method=SSL.SSLv23_METHOD) ctx = options.getContext() ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) ctx.use_certificate_chain_file(configmanager.get_config_dir(self.cert)) self.socket = reactor.listenSSL(self.port, self.site, options, interface=self.interface) log.info("Serving on %s:%s view at https://%s:%s", self.interface, self.port, self.interface, self.port)
def makeCert(cn): """ Create a self-signed certificate with the given common name. @param cn: Common Name to use in certificate. @type cn: L{bytes} @return: Self-signed certificate. @rtype: L{Certificate<twisted.internet.ssl.Certificate>} """ sharedDN = DN(CN=cn) key = KeyPair.generate() cr = key.certificateRequest(sharedDN) sscrd = key.signCertificateRequest(sharedDN, cr, lambda dn: True, 1) return key.newCertificate(sscrd)
def createCertificate(): # this is copied from test_sslverify.py dn = DistinguishedName(commonName="newpb_thingy") keypair = KeyPair.generate(size=2048) req = keypair.certificateRequest(dn, digestAlgorithm="sha256") certData = keypair.signCertificateRequest( dn, req, lambda dn: True, 1, # serial number digestAlgorithm="sha256", ) cert = keypair.newCertificate(certData) #opts = cert.options() # 'opts' can be given to reactor.listenSSL, or to transport.startTLS return cert
def start_ssl(self): check_ssl_keys() log.debug('Enabling SSL with PKey: %s, Cert: %s', self.pkey, self.cert) with open(configmanager.get_config_dir(self.cert)) as cert: certificate = Certificate.loadPEM(cert.read()).original with open(configmanager.get_config_dir(self.pkey)) as pkey: private_key = KeyPair.load(pkey.read(), FILETYPE_PEM).original options = CertificateOptions(privateKey=private_key, certificate=certificate, method=SSL.SSLv23_METHOD) ctx = options.getContext() ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) ctx.use_certificate_chain_file(configmanager.get_config_dir(self.cert)) self.socket = reactor.listenSSL(self.port, self.site, options, interface=self.interface) ip = self.socket.getHost().host ip = '[%s]' % ip if is_ipv6(ip) else ip log.info('Serving at https://%s:%s%s', ip, self.port, self.base)
def createSSLCertificate(opts): sslopt = {} for x, y in (('country','C'), ('state', 'ST'), ('city', 'L'), ('organization', 'O'), ('unit', 'OU'), ('hostname', 'CN'), ('email','emailAddress')): sslopt[y] = opts[x] serialNumber = int(opts['serial-number']) ssc = KeyPair.generate().selfSignedCert(serialNumber, **sslopt) file(opts['filename'], 'w').write(ssc.dumpPEM()) if not opts['quiet']: print 'Wrote SSL certificate:' print ssc.inspect() return ssc
def load_key_file(path): """ Load a private key from a specified path. :param FilePath path: Absolute path to certificate file. :return: A ``ComparableKeyPair`` instance representing the parsed key data. """ try: key_file = path.open() except IOError as e: code, failure = e raise PathError(b"Private key file could not be opened.", e.filename, code, failure) keypair = ComparableKeyPair( keypair=KeyPair.load(key_file.read(), format=crypto.FILETYPE_PEM)) return keypair
def createDatabase(siteStore): """ Populate the given Store with a TCPPort and SSLPort. """ factory = WebSite(store=siteStore) installOn(factory, siteStore) installOn(TCPPort(store=siteStore, portNumber=TCP_PORT, factory=factory), siteStore) certificatePath = siteStore.newFilePath('certificate') key = KeyPair.generate() cert = key.selfSignedCert(1) certificatePath.setContent( cert.dump(FILETYPE_PEM) + key.dump(FILETYPE_PEM)) installOn( SSLPort(store=siteStore, portNumber=SSL_PORT, certificatePath=certificatePath, factory=factory), siteStore)
def objectsFromPEM(pemdata): """ Load some objects from a PEM. """ certificates = [] keys = [] for line in pemdata.split("\n"): if line.startswith('-----BEGIN'): if 'CERTIFICATE' in line: blobs = certificates else: blobs = keys blobs.append('') blobs[-1] += line blobs[-1] += '\n' keys = [KeyPair.load(key, FILETYPE_PEM) for key in keys] certificates = [ Certificate.loadPEM(certificate) for certificate in certificates ] return PEMObjects(keys=keys, certificates=certificates)
def objectsFromPEM(pemdata): """ Load some objects from a PEM. """ certificates = [] keys = [] blobs = [b""] for line in pemdata.split(b"\n"): if line.startswith(b'-----BEGIN'): if b'CERTIFICATE' in line: blobs = certificates else: blobs = keys blobs.append(b'') blobs[-1] += line blobs[-1] += b'\n' keys = [KeyPair.load(key, FILETYPE_PEM) for key in keys] certificates = [Certificate.loadPEM(certificate) for certificate in certificates] return PEMObjects(keys=keys, certificates=certificates)
def load_key_file(path): """ Load a private key from a specified path. :param FilePath path: Absolute path to certificate file. :return: A ``ComparableKeyPair`` instance representing the parsed key data. """ try: key_file = path.open() except IOError as e: code, failure = e raise PathError( b"Private key file could not be opened.", e.filename, code, failure ) keypair = ComparableKeyPair( keypair=KeyPair.load(key_file.read(), format=crypto.FILETYPE_PEM) ) return keypair
def createDatabase(siteStore): """ Populate the given Store with a TCPPort and SSLPort. """ factory = WebSite(store=siteStore) installOn(factory, siteStore) installOn( TCPPort(store=siteStore, portNumber=TCP_PORT, factory=factory), siteStore) certificatePath = siteStore.newFilePath('certificate') key = KeyPair.generate() cert = key.selfSignedCert(1) certificatePath.setContent( cert.dump(FILETYPE_PEM) + key.dump(FILETYPE_PEM)) installOn( SSLPort(store=siteStore, portNumber=SSL_PORT, certificatePath=certificatePath, factory=factory), siteStore)
def load_certificate_from_path(path, key_filename, cert_filename): """ Load a certificate and keypair from a specified path. :param FilePath path: Directory where certificate and key files are stored. :param bytes key_filename: The file name of the private key. :param bytes cert_filename: The file name of the certificate. :return: A ``tuple`` containing the loaded key and certificate instances. """ certPath = path.child(cert_filename) keyPath = path.child(key_filename) try: certFile = certPath.open() except IOError as e: code, failure = e raise PathError( b"Certificate file could not be opened.", e.filename, code, failure ) try: keyFile = keyPath.open() except IOError as e: code, failure = e raise PathError( b"Private key file could not be opened.", e.filename, code, failure ) certificate = Certificate.load( certFile.read(), format=crypto.FILETYPE_PEM) keypair = ComparableKeyPair( keypair=KeyPair.load(keyFile.read(), format=crypto.FILETYPE_PEM) ) return (keypair, certificate)
def testBadCertRequestSubject(self): kp = KeyPair.generate() subject = DistinguishedName(commonName='HACKERX', localityName='INTERNETANIA') reqobj = kp.requestObject(subject) fakereq = kp.requestObject(subject) ssigned = kp.signRequestObject(subject, fakereq, 1) certpair = PrivateCertificate.fromCertificateAndKeyPair fakecert = certpair(ssigned, kp) apc = self.serverService2.certificateStorage.addPrivateCertificate def _2(secured): D = secured.callRemote(q2q.Sign, certificate_request=reqobj, password='******') def _1(dcert): cert = dcert['certificate'] privcert = certpair(cert, kp) apc(str(self.fromAddress), privcert) return D.addCallback(_1) d = self.serverService2.getSecureConnection( self.fromAddress, self.fromAddress.domainAddress(), authorize=False, usePrivateCertificate=fakecert, ).addCallback(_2) def unexpectedSuccess(result): self.fail("Expected BadCertificateRequest, got %r" % (result, )) def expectedFailure(err): err.trap(q2q.BadCertificateRequest) d.addCallbacks(unexpectedSuccess, expectedFailure) return d
def generateKey(): return KeyPair.generate()
def create_listening_endpoint_from_config(config, cbdir, reactor): """ Create a Twisted stream server endpoint from a Crossbar.io transport configuration. See: https://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IStreamServerEndpoint.html :param config: The transport configuration. :type config: dict :param cbdir: Crossbar.io node directory (we need this for TLS key/certificates). :type cbdir: str :param reactor: The reactor to use for endpoint creation. :type reactor: obj :returns obj -- An instance implementing IStreamServerEndpoint """ log = make_logger() endpoint = None # a TCP endpoint # if config['type'] == 'tcp': # the TCP protocol version (v4 or v6) # version = int(config.get('version', 4)) # the listening port # if type(config['port']) is six.text_type: # read port from environment variable .. try: port = int(environ[config['port'][1:]]) except Exception as e: print( "Could not read listening port from env var: {}".format(e)) raise e else: port = config['port'] # the listening interface # interface = str(config.get('interface', '').strip()) # the TCP accept queue depth # backlog = int(config.get('backlog', 50)) if 'tls' in config: if _HAS_TLS: key_filepath = abspath(join(cbdir, config['tls']['key'])) cert_filepath = abspath( join(cbdir, config['tls']['certificate'])) with open(key_filepath) as key_file: with open(cert_filepath) as cert_file: if 'dhparam' in config['tls']: dhpath = FilePath( abspath(join(cbdir, config['tls']['dhparam']))) dh_params = DiffieHellmanParameters.fromFile( dhpath) else: # XXX won't be doing ANY EDH # curves... maybe make dhparam required? # or do "whatever tlxctx was doing" dh_params = None log.warn( "OpenSSL DH modes not active (no 'dhparam')") # create a TLS context factory # key = key_file.read() cert = cert_file.read() ca_certs = None if 'ca_certificates' in config['tls']: ca_certs = [] for fname in config['tls']['ca_certificates']: with open(fname, 'r') as f: ca_certs.append( Certificate.loadPEM(f.read()).original) crossbar_ciphers = AcceptableCiphers.fromOpenSSLCipherString( 'ECDHE-RSA-AES128-GCM-SHA256:' 'DHE-RSA-AES128-GCM-SHA256:' 'ECDHE-RSA-AES128-SHA256:' 'DHE-RSA-AES128-SHA256:' 'ECDHE-RSA-AES128-SHA:' 'DHE-RSA-AES128-SHA') ctx = CertificateOptions( privateKey=KeyPair.load( key, crypto.FILETYPE_PEM).original, certificate=Certificate.loadPEM(cert).original, verify=(ca_certs is not None), caCerts=ca_certs, dhParameters=dh_params, acceptableCiphers=crossbar_ciphers, ) if ctx._ecCurve is None: log.warn( "OpenSSL failed to set ECDH default curve") else: log.info( "Ok, OpenSSL is using ECDH elliptic curve {curve}", curve=ctx._ecCurve.snName, ) # create a TLS server endpoint # if version == 4: endpoint = SSL4ServerEndpoint(reactor, port, ctx, backlog=backlog, interface=interface) elif version == 6: raise Exception("TLS on IPv6 not implemented") else: raise Exception( "invalid TCP protocol version {}".format(version)) else: raise Exception( "TLS transport requested, but TLS packages not available:\n{}" .format(_LACKS_TLS_MSG)) else: # create a non-TLS server endpoint # if version == 4: endpoint = TCP4ServerEndpoint(reactor, port, backlog=backlog, interface=interface) elif version == 6: endpoint = TCP6ServerEndpoint(reactor, port, backlog=backlog, interface=interface) else: raise Exception( "invalid TCP protocol version {}".format(version)) # a Unix Domain Socket endpoint # elif config['type'] == 'unix': # the accept queue depth # backlog = int(config.get('backlog', 50)) # the path # path = FilePath(join(cbdir, config['path'])) # if there is already something there, delete it. # if path.exists(): log.info(("{path} exists, attempting to remove before using as a " "UNIX socket"), path=path) path.remove() # create the endpoint # endpoint = UNIXServerEndpoint(reactor, path.path, backlog=backlog) else: raise Exception("invalid endpoint type '{}'".format(config['type'])) return endpoint
""" This benchmarks runs a trivial Twisted TLSv1 echo server using a certificate with a 2048 bit RSA key as well as a client which pumps as much data to that server as it can in a fixed period of time. """ from twisted.internet.protocol import ServerFactory from twisted.internet.endpoints import SSL4ClientEndpoint from twisted.internet.ssl import ( DN, KeyPair, PrivateCertificate, CertificateOptions) from twisted.protocols.wire import Echo from tcp_throughput import Client, driver # Generate a new self-signed certificate key = KeyPair.generate(size=2048) req = key.certificateRequest(DN(commonName='localhost'), digestAlgorithm='sha1') cert = PrivateCertificate.load( key.signCertificateRequest( DN(commonName='localhost'), req, lambda dn: True, 1, digestAlgorithm='sha1'), key) def main(reactor, duration): chunkSize = 16384 server = ServerFactory() server.protocol = Echo port = reactor.listenSSL(0, server, cert.options()) client = Client(
def create_connecting_endpoint_from_config(config, cbdir, reactor): """ Create a Twisted stream client endpoint from a Crossbar.io transport configuration. See: https://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IStreamClientEndpoint.html :param config: The transport configuration. :type config: dict :param cbdir: Crossbar.io node directory (we need this for Unix domain socket paths and TLS key/certificates). :type cbdir: str :param reactor: The reactor to use for endpoint creation. :type reactor: obj :returns obj -- An instance implementing IStreamClientEndpoint """ endpoint = None log = make_logger() # a TCP endpoint # if config['type'] == 'tcp': # the TCP protocol version (v4 or v6) # version = int(config.get('version', 4)) # the host to connect to # host = str(config['host']) # the port to connect to # port = int(config['port']) # connection timeout in seconds # timeout = int(config.get('timeout', 10)) if 'tls' in config: if _HAS_TLS: # if the config specified any CA certificates, we use those (only!) if 'ca_certificates' in config['tls']: ca_certs = [] for cert_fname in config['tls']['ca_certificates']: cert = crypto.load_certificate( crypto.FILETYPE_PEM, six.u(open(cert_fname, 'r').read())) log.info("Loaded CA certificate '{fname}'", fname=cert_fname) ca_certs.append(cert) client_cert = None if 'key' in config['tls']: with open(config['tls']['certificate'], 'r') as f: cert = Certificate.loadPEM(f.read(), ) log.info( "{fname}: CN={subj.CN}, sha={sha}", fname=config['tls']['certificate'], subj=cert.getSubject(), sha=cert.digest('sha'), ) with open(config['tls']['key'], 'r') as f: private_key = KeyPair.load( f.read(), format=crypto.FILETYPE_PEM, ) log.info( "{fname}: {key}", fname=config['tls']['key'], key=private_key.inspect(), ) client_cert = PrivateCertificate.fromCertificateAndKeyPair( cert, private_key) # XXX OpenSSLCertificateAuthorities is a "private" # class, in _sslverify, so we shouldn't really be # using it. However, while you can pass a single # Certificate as trustRoot= there's no way to pass # multiple ones. # XXX ...but maybe the config should only allow # the user to configure a single cert to trust # here anyway? options = optionsForClientTLS( config['tls']['hostname'], trustRoot=OpenSSLCertificateAuthorities(ca_certs), clientCertificate=client_cert, ) else: options = optionsForClientTLS(config['tls']['hostname']) # create a TLS client endpoint # if version == 4: endpoint = SSL4ClientEndpoint( reactor, host, port, options, timeout=timeout, ) elif version == 6: raise Exception("TLS on IPv6 not implemented") else: raise Exception( "invalid TCP protocol version {}".format(version)) else: raise Exception( "TLS transport requested, but TLS packages not available:\n{}" .format(_LACKS_TLS_MSG)) else: # create a non-TLS client endpoint # if version == 4: endpoint = TCP4ClientEndpoint(reactor, host, port, timeout=timeout) elif version == 6: endpoint = TCP6ClientEndpoint(reactor, host, port, timeout=timeout) else: raise Exception( "invalid TCP protocol version {}".format(version)) # a Unix Domain Socket endpoint # elif config['type'] == 'unix': # the path # path = abspath(join(cbdir, config['path'])) # connection timeout in seconds # timeout = int(config.get('timeout', 10)) # create the endpoint # endpoint = UNIXClientEndpoint(reactor, path, timeout=timeout) else: raise Exception("invalid endpoint type '{}'".format(config['type'])) return endpoint
def _create_tls_server_context(config, cbdir, log): """ Create a CertificateOptions object for use with TLS listening endpoints. """ # server private key key_filepath = abspath(join(cbdir, config['key'])) log.info("Loading server TLS key from {key_filepath}", key_filepath=key_filepath) with open(key_filepath) as key_file: # server certificate (but only the server cert, no chain certs) cert_filepath = abspath(join(cbdir, config['certificate'])) log.info("Loading server TLS certificate from {cert_filepath}", cert_filepath=cert_filepath) with open(cert_filepath) as cert_file: key = KeyPair.load(key_file.read(), crypto.FILETYPE_PEM).original cert = Certificate.loadPEM(cert_file.read()).original # list of certificates that complete your verification chain extra_certs = None if 'chain_certificates' in config: extra_certs = [] for fname in config['chain_certificates']: extra_cert_filepath = abspath(join(cbdir, fname)) with open(extra_cert_filepath, 'r') as f: extra_certs.append(Certificate.loadPEM(f.read()).original) log.info("Loading server TLS chain certificate from {extra_cert_filepath}", extra_cert_filepath=extra_cert_filepath) # list of certificate authority certificate objects to use to verify the peer's certificate ca_certs = None if 'ca_certificates' in config: ca_certs = [] for fname in config['ca_certificates']: ca_cert_filepath = abspath(join(cbdir, fname)) with open(ca_cert_filepath, 'r') as f: ca_certs.append(Certificate.loadPEM(f.read()).original) log.info("Loading server TLS CA certificate from {ca_cert_filepath}", ca_cert_filepath=ca_cert_filepath) # ciphers we accept # # We prefer to make every single cipher (6 in total) _explicit_ (to reduce chances either we or the pattern-matching # language inside OpenSSL messes up) and drop support for Windows XP (we do WebSocket anyway). # # We don't use AES256 and SHA384, to reduce number of ciphers and since the additional # security gain seems not worth the additional performance drain. # # We also don't use ECDSA, since EC certificates a rare in the wild. # # The effective list of ciphers determined from an OpenSSL cipher string: # # openssl ciphers -v 'ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:' # # References: # # * https://www.ssllabs.com/ssltest/analyze.html?d=myserver.com # * http://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ # * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT # * https://wiki.mozilla.org/Talk:Security/Server_Side_TLS # if 'ciphers' in config: log.info("Using explicit TLS ciphers from config") crossbar_ciphers = AcceptableCiphers.fromOpenSSLCipherString(config['ciphers']) else: log.info("Using secure default TLS ciphers") crossbar_ciphers = AcceptableCiphers.fromOpenSSLCipherString( # AEAD modes (GCM) # 'ECDHE-ECDSA-AES128-GCM-SHA256:' 'ECDHE-RSA-AES128-GCM-SHA256:' # 'ECDHE-ECDSA-AES256-GCM-SHA384:' # 'ECDHE-RSA-AES256-GCM-SHA384:' 'DHE-RSA-AES128-GCM-SHA256:' # 'DHE-RSA-AES256-GCM-SHA384:' # CBC modes 'ECDHE-RSA-AES128-SHA256:' 'DHE-RSA-AES128-SHA256:' 'ECDHE-RSA-AES128-SHA:' 'DHE-RSA-AES128-SHA:' ) # DH modes require a parameter file if 'dhparam' in config: dhpath = FilePath(abspath(join(cbdir, config['dhparam']))) dh_params = DiffieHellmanParameters.fromFile(dhpath) else: dh_params = None log.warn("No OpenSSL DH parameter file set - DH cipher modes will be deactive!") # create a TLS context factory # see: https://twistedmatrix.com/documents/current/api/twisted.internet.ssl.CertificateOptions.html ctx = CertificateOptions( privateKey=key, certificate=cert, extraCertChain=extra_certs, verify=(ca_certs is not None), caCerts=ca_certs, dhParameters=dh_params, acceptableCiphers=crossbar_ciphers, # TLS hardening method=TLSv1_2_METHOD, enableSingleUseKeys=True, enableSessions=False, enableSessionTickets=False, fixBrokenPeers=False, ) # Without a curve being set, ECDH won't be available even if listed # in acceptable ciphers! # # The curves available in OpenSSL can be listed: # # openssl ecparam -list_curves # # prime256v1: X9.62/SECG curve over a 256 bit prime field # # This is elliptic curve "NIST P-256" from here # http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf # # This seems to be the most widely used curve # # http://crypto.stackexchange.com/questions/11310/with-openssl-and-ecdhe-how-to-show-the-actual-curve-being-used # # and researchers think it is "ok" (other than wrt timing attacks etc) # # https://twitter.com/hyperelliptic/status/394258454342148096 # if ctx._ecCurve is None: log.warn("No OpenSSL elliptic curve set - EC cipher modes will be deactive!") else: if ctx._ecCurve.snName != "prime256v1": log.info("OpenSSL is using elliptic curve {curve}", curve=ctx._ecCurve.snName) else: log.info("OpenSSL is using elliptic curve prime256v1 (NIST P-256)") return ctx
def _create_tls_server_context(config, cbdir, log): """ Create a CertificateOptions object for use with TLS listening endpoints. """ # server private key key_filepath = abspath(join(cbdir, config['key'])) log.info("Loading server TLS key from {key_filepath}", key_filepath=key_filepath) with open(key_filepath) as key_file: # server certificate (but only the server cert, no chain certs) cert_filepath = abspath(join(cbdir, config['certificate'])) log.info("Loading server TLS certificate from {cert_filepath}", cert_filepath=cert_filepath) with open(cert_filepath) as cert_file: key = KeyPair.load(key_file.read(), crypto.FILETYPE_PEM).original cert = Certificate.loadPEM(cert_file.read()).original # list of certificates that complete your verification chain extra_certs = None if 'chain_certificates' in config: extra_certs = [] for fname in config['chain_certificates']: extra_cert_filepath = abspath(join(cbdir, fname)) with open(extra_cert_filepath, 'r') as f: extra_certs.append(Certificate.loadPEM(f.read()).original) log.info( "Loading server TLS chain certificate from {extra_cert_filepath}", extra_cert_filepath=extra_cert_filepath) # list of certificate authority certificate objects to use to verify the peer's certificate ca_certs = None if 'ca_certificates' in config: ca_certs = [] for fname in config['ca_certificates']: ca_cert_filepath = abspath(join(cbdir, fname)) with open(ca_cert_filepath, 'r') as f: ca_certs.append(Certificate.loadPEM(f.read()).original) log.info( "Loading server TLS CA certificate from {ca_cert_filepath}", ca_cert_filepath=ca_cert_filepath) # ciphers we accept # # We prefer to make every single cipher (6 in total) _explicit_ (to reduce chances either we or the pattern-matching # language inside OpenSSL messes up) and drop support for Windows XP (we do WebSocket anyway). # # We don't use AES256 and SHA384, to reduce number of ciphers and since the additional # security gain seems not worth the additional performance drain. # # We also don't use ECDSA, since EC certificates a rare in the wild. # # The effective list of ciphers determined from an OpenSSL cipher string: # # openssl ciphers -v 'ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:' # # References: # # * https://www.ssllabs.com/ssltest/analyze.html?d=myserver.com # * http://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ # * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT # * https://wiki.mozilla.org/Talk:Security/Server_Side_TLS # if 'ciphers' in config: log.info("Using explicit TLS ciphers from config") crossbar_ciphers = AcceptableCiphers.fromOpenSSLCipherString( config['ciphers']) else: log.info("Using secure default TLS ciphers") crossbar_ciphers = AcceptableCiphers.fromOpenSSLCipherString( # AEAD modes (GCM) # 'ECDHE-ECDSA-AES128-GCM-SHA256:' 'ECDHE-RSA-AES128-GCM-SHA256:' # 'ECDHE-ECDSA-AES256-GCM-SHA384:' # 'ECDHE-RSA-AES256-GCM-SHA384:' 'DHE-RSA-AES128-GCM-SHA256:' # 'DHE-RSA-AES256-GCM-SHA384:' # CBC modes 'ECDHE-RSA-AES128-SHA256:' 'DHE-RSA-AES128-SHA256:' 'ECDHE-RSA-AES128-SHA:' 'DHE-RSA-AES128-SHA:') # DH modes require a parameter file if 'dhparam' in config: dhpath = FilePath(abspath(join(cbdir, config['dhparam']))) dh_params = DiffieHellmanParameters.fromFile(dhpath) else: dh_params = None log.warn( "No OpenSSL DH parameter file set - DH cipher modes will be deactive!" ) ctx = CertificateOptions( privateKey=key, certificate=cert, extraCertChain=extra_certs, verify=(ca_certs is not None), caCerts=ca_certs, dhParameters=dh_params, acceptableCiphers=crossbar_ciphers, # Disable SSLv3 and TLSv1 -- only allow TLSv1.1 or higher # # We are using Twisted private stuff (from twisted.internet._sslverify import TLSVersion), # as OpenSSL.SSL.TLSv1_1_METHOD wont work: # # [ERROR] File "../twisted/internet/_sslverify.py", line 1530, in __init__ # if raiseMinimumTo > self._defaultMinimumTLSVersion: # builtins.TypeError: '>' not supported between instances of 'int' and 'NamedConstant' # raiseMinimumTo=TLSVersion.TLSv1_1, # TLS hardening enableSingleUseKeys=True, enableSessions=False, enableSessionTickets=False, fixBrokenPeers=False, ) # Without a curve being set, ECDH won't be available even if listed # in acceptable ciphers! # # The curves available in OpenSSL can be listed: # # openssl ecparam -list_curves # # prime256v1: X9.62/SECG curve over a 256 bit prime field # # This is elliptic curve "NIST P-256" from here # http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf # # This seems to be the most widely used curve # # http://crypto.stackexchange.com/questions/11310/with-openssl-and-ecdhe-how-to-show-the-actual-curve-being-used # # and researchers think it is "ok" (other than wrt timing attacks etc) # # https://twitter.com/hyperelliptic/status/394258454342148096 # if False: # FIXME: this doesn't work anymore with Twisted 18.4. (there now seems more complex machinery # in self._ecChooser) if ctx._ecCurve is None: log.warn( "No OpenSSL elliptic curve set - EC cipher modes will be deactive!" ) else: if ctx._ecCurve.snName != "prime256v1": log.info("OpenSSL is using elliptic curve {curve}", curve=ctx._ecCurve.snName) else: log.info( "OpenSSL is using elliptic curve prime256v1 (NIST P-256)") return ctx