async def __anit__(self, certdir=None): await s_base.Base.__anit__(self) self._shareLoopTasks = set() self.certdir = s_certdir.CertDir(path=certdir) self.televers = s_telepath.televers self.addr = None # our main listen address self.cells = {} # all cells are shared. not all shared are cells. self.shared = {} # objects provided by daemon self.listenservers = [] # the sockets we're listening on self.links = set() self.sessions = {} self.mesgfuncs = { 'tele:syn': self._onTeleSyn, 'task:init': self._onTaskInit, 'share:fini': self._onShareFini, # task version 2 API 't2:init': self._onTaskV2Init, } self.onfini(self._onDmonFini)
async def test_storm_http_inject_ca(self): with self.getTestDir() as dirn: cdir = s_common.gendir(dirn, 'certs') cadir = s_common.gendir(cdir, 'cas') tdir = s_certdir.CertDir(cdir) tdir.genCaCert('somelocalca') tdir.genHostCert('localhost', signas='somelocalca') localkeyfp = tdir.getHostKeyPath('localhost') localcertfp = tdir.getHostCertPath('localhost') shutil.copyfile(localkeyfp, s_common.genpath(dirn, 'sslkey.pem')) shutil.copyfile(localcertfp, s_common.genpath(dirn, 'sslcert.pem')) tlscadir = s_common.gendir(dirn, 'cadir') for fn in os.listdir(cadir): if fn.endswith('.crt'): shutil.copyfile(os.path.join(cadir, fn), os.path.join(tlscadir, fn)) async with self.getTestCore(dirn=dirn) as core: root = await core.auth.getUserByName('root') await root.setPasswd('root') addr, port = await core.addHttpsPort(0) core.addHttpApi('/api/v0/test', s_test.HttpReflector, {'cell': core}) url = f'https://*****:*****@localhost:{port}/api/v0/test' opts = {'vars': {'url': url}} q = ''' $params=((foo, bar), (key, valu)) $resp = $lib.inet.http.get($url, params=$params) return ( ($resp.code, $resp.err) ) ''' code, (errname, _) = await core.callStorm(q, opts=opts) self.eq(code, -1) self.eq('ClientConnectorCertificateError', errname) conf = {'tls:ca:dir': tlscadir} async with self.getTestCore(dirn=dirn, conf=conf) as core: addr, port = await core.addHttpsPort(0) core.addHttpApi('/api/v0/test', s_test.HttpReflector, {'cell': core}) url = f'https://*****:*****@localhost:{port}/api/v0/test' opts = {'vars': {'url': url}} q = ''' $params=((foo, bar), (key, valu)) $resp = $lib.inet.http.get($url, params=$params) return ( $resp.json() ) ''' resp = await core.callStorm(q, opts=opts) data = resp.get('result') self.eq(data.get('params'), { 'key': ('valu', ), 'foo': ('bar', ) })
def getCertDir(self): ''' Get a test CertDir object. Yields: s_certdir.CertDir: A certdir object based out of a temp directory. ''' # create a temp folder and make it a cert dir with self.getTestDir() as dirname: yield s_certdir.CertDir(path=dirname)
async def test_axon_tlscapath(self): with self.getTestDir() as dirn: cdir = s_common.gendir(dirn, 'certs') cadir = s_common.gendir(cdir, 'cas') tdir = s_certdir.CertDir(cdir) tdir.genCaCert('somelocalca') tdir.genHostCert('localhost', signas='somelocalca') localkeyfp = tdir.getHostKeyPath('localhost') localcertfp = tdir.getHostCertPath('localhost') shutil.copyfile(localkeyfp, s_common.genpath(dirn, 'sslkey.pem')) shutil.copyfile(localcertfp, s_common.genpath(dirn, 'sslcert.pem')) tlscadir = s_common.gendir(dirn, 'cadir') for fn in os.listdir(cadir): if fn.endswith('.crt'): shutil.copyfile(os.path.join(cadir, fn), os.path.join(tlscadir, fn)) conf = {'auth:passwd': 'root'} async with self.getTestAxon(dirn=dirn, conf=conf) as axon: host, port = await axon.addHttpsPort(0, host='127.0.0.1') url = f'https://*****:*****@127.0.0.1:{port}/api/v1/active' resp = await axon.wget(url) self.false(resp.get('ok')) self.isin('unable to get local issuer certificate', resp.get('mesg')) retn = await axon.put(abuf) self.eq(retn, asdfretn) axon.addHttpApi('/api/v1/pushfile', HttpPushFile, {'cell': axon}) url = f'https://*****:*****@127.0.0.1:{port}/api/v1/pushfile' resp = await axon.wput(asdfhash, url) self.false(resp.get('ok')) self.isin('unable to get local issuer certificate', resp.get('mesg')) resp = await axon.postfiles(fields, url) self.false(resp.get('ok')) self.isin('unable to get local issuer certificate', resp.get('err')) conf = {'auth:passwd': 'root', 'tls:ca:dir': tlscadir} async with self.getTestAxon(dirn=dirn, conf=conf) as axon: host, port = await axon.addHttpsPort(0, host='127.0.0.1') url = f'https://*****:*****@localhost:{port}/api/v1/active' resp = await axon.wget(url) self.true(resp.get('ok')) retn = await axon.put(abuf) self.eq(retn, asdfretn) axon.addHttpApi('/api/v1/pushfile', HttpPushFile, {'cell': axon}) url = f'https://*****:*****@localhost:{port}/api/v1/pushfile' resp = await axon.wput(asdfhash, url) self.true(resp.get('ok')) resp = await axon.postfiles(fields, url) self.true(resp.get('ok'))
def _listen(self): host = self.link[1].get('host') port = self.link[1].get('port') sock = socket.socket() sock.bind((host, port)) sock.listen(100) self.link[1]['port'] = sock.getsockname()[1] certdir = self.link[1].get('certdir') cdir = s_certdir.CertDir(path=certdir) hostname = socket.gethostname() cafile = self.link[1].get('cafile') if cafile is None: caname = self.link[1].get('ca') if caname is not None: cafile = cdir.getCaCertPath(caname) certfile = self.link[1].get('certfile') if certfile is None: certfile = cdir.getHostCertPath(hostname) keyfile = self.link[1].get('keyfile') if keyfile is None: keyfile = cdir.getHostKeyPath(hostname) sslopts = dict( server_side=True, ca_certs=cafile, keyfile=keyfile, certfile=certfile, cert_reqs=ssl.CERT_NONE, do_handshake_on_connect=False, ssl_version=ssl.PROTOCOL_TLSv1, ) # if they give a cafile to the server, require client certs if cafile is not None: sslopts['cert_reqs'] = ssl.CERT_REQUIRED wrap = ssl.wrap_socket(sock, **sslopts) sock = s_socket.Socket(wrap) sock.on('link:sock:accept', self._onSslAccept) return sock
def _connect(self): sock = socket.socket() host = self.link[1].get('host') port = self.link[1].get('port') cafile = None keyfile = None certfile = None user = self.link[1].get('user') certdir = self.link[1].get('certdir') cdir = s_certdir.CertDir(path=certdir) certuser = cdir.getUserForHost(user, host) if certuser is not None: cafile = cdir.getUserCaPath(certuser) keyfile = cdir.getUserKeyPath(certuser) certfile = cdir.getUserCertPath(certuser) cafile = self.link[1].get('cafile', cafile) keyfile = self.link[1].get('keyfile', keyfile) certfile = self.link[1].get('certfile', certfile) sslopts = dict(ca_certs=cafile, keyfile=keyfile, certfile=certfile, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1) if self.link[1].get('nocheck'): sslopts['cert_reqs'] = ssl.CERT_NONE try: sock.connect((host, port)) except s_common.sockerrs as e: sock.close() raiseSockError(self.link, e) try: wrap = ssl.wrap_socket(sock, **sslopts) except ssl.SSLError as e: sock.close() raise s_common.LinkErr(self.link, str(e)) return s_socket.Socket(wrap)
async def _main(argv, outp): pars = getArgParser() opts = pars.parse_args(argv) cdir = s_certdir.CertDir(path=opts.certdir) async with await s_telepath.openurl(opts.aha) as prox: # try: # s_version.reqVersion(prox._getSynVers(), reqver) # except s_exc.BadVersion as e: # pragma: no cover # valu = s_version.fmtVersion(*e.get('valu')) # outp.printf(f'Proxy version {valu} is outside of the aha supported range ({reqver}).') # return 1 name = opts.name if opts.ca: # A User may only have get permissions; so try get first # before attempting to generate a new CA. certbyts = await prox.getCaCert(name) if not certbyts: certbyts = await prox.genCaCert(name) cert = crypto.load_certificate(crypto.FILETYPE_PEM, certbyts) path = cdir._saveCertTo(cert, 'cas', f'{name}.crt') outp.printf(f'Saved CA cert to {path}') return 0 elif opts.server: csr = cdir.genHostCsr(name, outp=outp) certbyts = await prox.signHostCsr(csr.decode(), signas=opts.network, sans=opts.server_sans) cert = crypto.load_certificate(crypto.FILETYPE_PEM, certbyts) path = cdir._saveCertTo(cert, 'hosts', f'{name}.crt') outp.printf(f'crt saved: {path}') return 0 else: csr = cdir.genUserCsr(name, outp=outp) certbyts = await prox.signUserCsr(csr.decode(), signas=opts.network) cert = crypto.load_certificate(crypto.FILETYPE_PEM, certbyts) path = cdir._saveCertTo(cert, 'users', f'{name}.crt') outp.printf(f'crt saved: {path}') return 0
async def __anit__(self, dirn=None, conf=None): await s_base.Base.__anit__(self) self.dirn = None if dirn is not None: self.dirn = s_common.gendir(dirn) self._shareLoopTasks = set() yaml = self._loadDmonYaml() if conf is not None: yaml.update(conf) self.conf = s_common.config(yaml, self.confdefs) self.certdir = s_certdir.CertDir(os.path.join(dirn, 'certs')) self.mods = {} # keep refs to mods we load ( mostly for testing ) self.televers = s_telepath.televers self.addr = None # our main listen address self.cells = {} # all cells are shared. not all shared are cells. self.shared = {} # objects provided by daemon self.listenservers = [] # the sockets we're listening on self.connectedlinks = [] # the links we're currently connected on self.sessions = {} self.mesgfuncs = { 'tele:syn': self._onTeleSyn, 'task:init': self._onTaskInit, 'share:fini': self._onShareFini, # task version 2 API 't2:init': self._onTaskV2Init, } self.onfini(self._onDmonFini) await self._loadDmonConf() await self._loadDmonCells()
async def addHttpsPort(self, port, host='0.0.0.0', sslctx=None): addr = socket.gethostbyname(host) if sslctx is None: pkeypath = os.path.join(self.dirn, 'sslkey.pem') certpath = os.path.join(self.dirn, 'sslcert.pem') if not os.path.isfile(certpath): logger.warning('NO CERTIFICATE FOUND! generating self-signed certificate.') with s_common.getTempDir() as dirn: cdir = s_certdir.CertDir(dirn) pkey, cert = cdir.genHostCert('cortex') cdir.savePkeyPem(pkey, pkeypath) cdir.saveCertPem(cert, certpath) sslctx = self.initSslCtx(certpath, pkeypath) serv = self.wapp.listen(port, address=addr, ssl_options=sslctx) self.httpds.append(serv) return list(serv._sockets.values())[0].getsockname()
def main(argv, outp=None): if outp is None: outp = s_output.OutPut() pars = argparse.ArgumentParser(prog='easycert', description=descr) pars.add_argument('--certdir', default='~/.syn/certs', help='Directory for certs/keys') pars.add_argument('--signas', help='sign the new cert with the given cert name') pars.add_argument('--ca', default=False, action='store_true', help='mark the certificate as a CA/CRL signer') pars.add_argument('--server', default=False, action='store_true', help='mark the certificate as a server') pars.add_argument('--server-sans', help='server cert subject alternate names') pars.add_argument('--csr', default=False, action='store_true', help='generate a cert signing request') pars.add_argument('--sign-csr', default=False, action='store_true', help='sign a cert signing request') pars.add_argument( 'name', help='common name for the certificate (or filename for CSR signing)') opts = pars.parse_args(argv) cdir = s_certdir.CertDir(path=opts.certdir) try: if opts.sign_csr: if opts.signas is None: outp.printf('--sign-csr requires --signas') return -1 xcsr = cdir._loadCsrPath(opts.name) if xcsr is None: outp.printf('csr not found: %s' % (opts.name, )) return -1 if opts.server: cdir.signHostCsr(xcsr, opts.signas, outp=outp) return 0 cdir.signUserCsr(xcsr, opts.signas, outp=outp) return 0 if opts.csr: if opts.ca: cdir.genCaCsr(opts.name, outp=outp) raise Exception('CSR for CA cert not supported (yet)') if opts.server: cdir.genHostCsr(opts.name, outp=outp) return 0 cdir.genUserCsr(opts.name, outp=outp) return 0 if opts.ca: cdir.genCaCert(opts.name, signas=opts.signas, outp=outp) return 0 if opts.server: cdir.genHostCert(opts.name, signas=opts.signas, outp=outp, sans=opts.server_sans) return 0 cdir.genUserCert(opts.name, signas=opts.signas, outp=outp) return 0 except s_common.DupFileName as e: outp.printf('file exists: %s' % (e.errinfo.get('path'), )) return -1
def test_webapp_ssl(self): # tornado does not support windows (yet) self.thisHostMustNot(platform='windows') foo = Foo() with self.getTestDir() as dirname: cdir = s_certdir.CertDir(path=dirname) cdir.genCaCert('syntest') # Generate a new CA cdir.genUserCert( '*****@*****.**', signas='syntest' ) # Generate a new user cert and key, signed by the new CA cdir.genHostCert( 'localhost', signas='syntest' ) # Generate a new server cert and key, signed by the new CA ca_cert = cdir.getCaCertPath('syntest') host_key = cdir.getHostKeyPath('localhost') host_cert = cdir.getHostCertPath('localhost') ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx.verify_mode = ssl.CERT_REQUIRED ssl_ctx.load_cert_chain(host_cert, host_key) ssl_ctx.load_verify_locations(ca_cert) conf = {'server': {'ssl_options': ssl_ctx}} wapp = s_webapp.WebApp(**conf) wapp.listen(0, host='127.0.0.1') wapp.addApiPath('/v1/bar', foo.bar) client = AsyncHTTPClient(self.io_loop) port = wapp.getServBinds()[0][1] http_url = 'http://127.0.0.1:%d/v1/bar' % port https_url = 'https://127.0.0.1:%d/v1/bar' % port user_key = cdir.getUserKeyPath('*****@*****.**') user_cert = cdir.getUserCertPath('*****@*****.**') client_opts = { 'ca_certs': ca_cert, 'client_key': user_key, 'client_cert': user_cert } # Assert that the request fails w/ http protocol with self.raises(TstSSLConnectionResetErr): resp = yield client.fetch(http_url) # Assert that the request fails w/ no client SSL config with self.raises(ssl.SSLError): resp = yield client.fetch(https_url) # Assert that the request fails w/ no client SSL config, even if client does not validate cert # (server must also validate client cert) with self.raises(TstSSLInvalidClientCertErr): resp = yield client.fetch(https_url, validate_cert=False) resp = yield client.fetch(https_url, **client_opts) resp = json.loads(resp.body.decode('utf-8')) self.eq(resp.get('ret'), 'baz') self.eq(resp.get('status'), 'ok') wapp.fini()
def getCertDir(self): # create a temp folder and make it a cert dir with self.getTestDir() as dirname: cdir = s_certdir.CertDir(path=dirname) yield cdir
def test_certdir_invalidpath(self): with self.raises(s_exc.SynErr): s_certdir.CertDir(path=1)
async def openurl(url, **opts): ''' Open a URL to a remote telepath object. Args: url (str): A telepath URL. **opts (dict): Telepath connect options. Returns: (synapse.telepath.Proxy): A telepath proxy object. The telepath proxy may then be used for sync or async calls: proxy = openurl(url) value = proxy.getFooThing() ... or ... proxy = await openurl(url) valu = await proxy.getFooThing() ... or ... async with await openurl(url) as proxy: valu = await proxy.getFooThing() ''' if url.find('://') == -1: newurl = alias(url) if newurl is None: raise s_exc.BadUrl( mesg=f':// not found in [{url}] and no alias found!', url=url) url = newurl info = s_urlhelp.chopurl(url) info.update(opts) scheme = info.get('scheme') if '+' in scheme: scheme, disc = scheme.split('+', 1) # Discovery protocols modify info dict inband? if disc == 'consul': await disc_consul(info) else: raise s_exc.BadUrl(mesg=f'Unknown discovery protocol [{disc}].', disc=disc) host = info.get('host') port = info.get('port') auth = None user = info.get('user') if user is not None: passwd = info.get('passwd') auth = (user, {'passwd': passwd}) if scheme == 'cell': # cell:///path/to/celldir:share # cell://rel/path/to/celldir:share path = info.get('path') name = info.get('name', '*') # support cell://<relpath>/<to>/<cell> # by detecting host... host = info.get('host') if host: path = path.strip('/') path = os.path.join(host, path) if ':' in path: path, name = path.split(':') full = os.path.join(path, 'sock') link = await s_link.unixconnect(full) elif scheme == 'unix': # unix:///path/to/sock:share name = '*' path = info.get('path') if ':' in path: path, name = path.split(':') link = await s_link.unixconnect(path) else: path = info.get('path') name = info.get('name', path[1:]) sslctx = None if scheme == 'ssl': certname = None certpath = None certdir = opts.get('certdir') query = info.get('query') if query is not None: certpath = query.get('certdir') certname = query.get('certname') if certdir is None: certdir = s_certdir.CertDir(certpath) sslctx = certdir.getClientSSLContext(certname=certname) link = await s_link.connect(host, port, ssl=sslctx) prox = await Proxy.anit(link, name) prox.onfini(link) try: await prox.handshake(auth=auth) except Exception: await prox.fini() raise return prox
async def openurl(url, **opts): ''' Open a URL to a remote telepath object. Args: url (str): A telepath URL. **opts (dict): Telepath connect options. Returns: (synapse.telepath.Proxy): A telepath proxy object. The telepath proxy may then be used for sync or async calls: proxy = openurl(url) value = proxy.getFooThing() ... or ... proxy = await openurl(url) valu = await proxy.getFooThing() ... or ... async with await openurl(url) as proxy: valu = await proxy.getFooThing() ''' if url.find('://') == -1: newurl = alias(url) if newurl is None: raise s_exc.BadUrl(f':// not found in [{url}] and no alias found!') url = newurl info = s_urlhelp.chopurl(url) info.update(opts) host = info.get('host') port = info.get('port') name = info.get('path')[1:] auth = None user = info.get('user') if user is not None: passwd = info.get('passwd') auth = (user, {'passwd': passwd}) sslctx = None if info.get('scheme') == 'ssl': certpath = info.get('certdir') certdir = s_certdir.CertDir(certpath) sslctx = certdir.getClientSSLContext() link = await s_link.connect(host, port, ssl=sslctx) prox = await Proxy.anit(link, name) prox.onfini(link) try: await prox.handshake(auth=auth) except Exception as e: await prox.fini() raise return prox