Permalink
Browse files

updates!

  • Loading branch information...
1 parent 305dd05 commit 958f06ae830cffd851a40d33bfba8daaee768ce3 @rep committed Oct 8, 2012
Showing with 96 additions and 109 deletions.
  1. +2 −2 README
  2. +0 −71 README.md
  3. +30 −4 pcat.py
  4. +64 −32 pwrtls.py
  5. BIN pwrtls.pyc
View
4 README
@@ -39,7 +39,7 @@ server_hello_msg:
{
box: crypto_box({
spub: short-term public key,
- OPTIONAL pskv: crypto_secretbox(client short-term public key + 1),
+ OPTIONAL pskv: crypto_secretbox(client short-term public key),
OPTIONAL cav: crypto_sign(long-term public key)
}),
lpub: long-term public key
@@ -58,7 +58,7 @@ client_verify_msg:
lpub: long-term public key,
v: crypto_box(short-term public key),
vn: verifybox_nonce,
- OPTIONAL pskv: crypto_secretbox(server short-term public key + 1)
+ OPTIONAL pskv: crypto_secretbox(server short-term public key)
OPTIONAL cav: crypto_sign(long-term public key)
})
}
View
@@ -1,71 +0,0 @@
-pwrtls - inspired by nacl and curvecp
-=====================================
-
- - client and server need a long term keypair and generate short-term keypairs for each connection
- authentication options:
- 1) server side key is known, clients not authenticated
- 2) like 1) but server knows a list of client public keys
- 3) server/client supply each other with signatures on their long-term keys by a trustedkey
- 4) server and client know a pre-shared symmetric key
- 5) no known keys, server key displayed to user for verification and storage (compare SSH)
-
- - we do three round-trips starting with a client hello
- - optional: the third message (client->server) could include a payload already if needed
- - messages: client_hello_msg, server_hello_msg, client_verify_msg
- - after handshake, we use the short-term keys to encrypt and authenticate each message
- - profit!
-
-==============================
-nacl provides:
-crypto_box(message, nonce, receiver-public-key, sender-private-key)
- -> asymmetric authenticated encrypted message
-crypto_secretbox(message, nonce, key)
- -> symmetric authenticated encrypted message
-crypto_sign(message, signkey)
- -> asymmetric signature on message
-
-------------------------------
-client_hello_msg:
-{
- spub: short-term public key of client,
- OPTIONAL pskhint: identifier for resolving psk,
- OPTIONAL cahint: identifier for trusted pubkey
-}
-
- -> pskhint only sent when client wants psk auth
-
-------------------------------
-server_hello_msg:
-{
- box: crypto_box({
- spub: short-term public key,
- OPTIONAL pskv: crypto_secretbox(client short-term public key + 1),
- OPTIONAL cav: crypto_sign(long-term public key)
- }),
- lpub: long-term public key
-}
-
- -> box authenticated with long-term key, encrypted for client short-term key
- -> nonce used is "2" (short-term key only valid for this connection)
- -> long-term key is sent in case the client does not yet have it (lookup/display_accept)
- -> pskv is only sent when client wanted psk auth
- -> cav is a signature on the servers long-term key by the trusted key
-
-------------------------------
-client_verify_msg:
-{
- box: crypto_box({
- lpub: long-term public key,
- v: crypto_box(short-term public key),
- vn: verifybox_nonce,
- OPTIONAL pskv: crypto_secretbox(server short-term public key + 1)
- OPTIONAL cav: crypto_sign(long-term public key)
- })
-}
-
- -> v is verifybox, long-term to long-term key
- -> box authenticated with short-term key, encrypted for server short-term key
- -> the public key is sent to be able to look it up on the server's side
- -> the verifybox vouches for the short-term key used by the client
- -> pskv and cav see server_hello_msg
-
View
34 pcat.py
@@ -25,15 +25,28 @@
def forwardstdin(stdin, sock):
try:
while True:
- gevent.select([stdin], [], [])
+ gevent.select.select([stdin], [], [])
data = stdin.read()
- if not data:
- break
+ if not data: break
sock.send(data)
+ except pwrtls.pwrtls_closed:
+ pass
except:
print 'exc in forwardstdin'
traceback.print_exc()
+def forwardsock(sock, stdin):
+ try:
+ while True:
+ data = sock.read()
+ if not data: break
+ stdin.write('from sock: ' + data)
+ except pwrtls.pwrtls_closed:
+ pass
+ except:
+ print 'exc in forwardsock'
+ traceback.print_exc()
+
def main():
parser = argparse.ArgumentParser(description='pwrcall nacl test.')
@@ -55,8 +68,14 @@ def main():
socket = gevent.socket.create_connection((ip, port))
socket = pwrtls.wrap_socket(socket, **state)
- #socket.connect()
socket.do_handshake()
+ socket.write('hello from client!\n')
+ #g1 = gevent.spawn(forwardstdin, sys.stdin, socket)
+ #print 'spawned g1'
+ forwardsock(socket, sys.stdout)
+ print 'forwardsock end'
+ #g1.kill()
+ #print 'killed g1'
socket.close()
elif args.action[0] == 'l':
@@ -67,6 +86,13 @@ def main():
def handle(sock, addr):
socket = pwrtls.wrap_socket(sock, server_side=True, **state)
socket.do_handshake()
+ socket.write('hello from server\n')
+ try:
+ print ' client>', socket.read()
+ forwardsock(socket, sys.stdout)
+ except pwrtls.pwrtls_closed:
+ pass
+
socket.close()
server = gevent.server.StreamServer((ip, port), handle)
View
@@ -16,6 +16,7 @@
import struct
import random
import logging
+import traceback
import bson
import nacl
@@ -75,26 +76,26 @@ def from_bson(enced, *args):
class PTLS_Socket(object):
- def __init__(self, sock, pubkey=None, privkey=None, nonce=None):
- print 'PTLS_Socket init', repr(nonce)
+ def __init__(self, sock, validate_cb=None, pubkey=None, privkey=None, nonce=None):
self._sock = socket(_sock=sock)
self.pubkey = pubkey
self.privkey = privkey
self.nonce = nonce
self.shortpub, self.shortpriv = nacl.crypto_box_keypair()
self.rbuf = ''
+ self.validate_cb = validate_cb
+ self.psk, self.cav = None, None
def _recv_frame(self):
lengthbytes = self._recv(4)
if len(lengthbytes) < 4: raise pwrtls_exception('Invalid frame.')
framelen = struct.unpack('!I', lengthbytes)[0]
buf = ''
- while len(buf) < framelen:
- tmp = self._recv(min(BUFSIZE, framelen-len(buf)))
+ while len(buf) < framelen-4:
+ tmp = self._recv(min(BUFSIZE, framelen-4-len(buf)))
buf += tmp
-
return buf
def _recv(self, length):
@@ -119,24 +120,20 @@ def send(self, data):
return len(data)
def _send_frame(self, data):
- data = struct.pack('!I', len(data)) + data
+ data = struct.pack('!I', len(data)+4) + data
self._sock.sendall(data)
def do_handshake(self):
raise Exception("Implement in subclass!")
def _message(self, data):
- m = {
- 'box': _b(nacl.crypto_box(data, snonce(self.shortnonce), self.remote_shortpub, self.shortpriv)),
- 'n': self.shortnonce
- }
-
+ m = nacl.crypto_box(data, snonce(self.shortnonce), self.remote_shortpub, self.shortpriv)
self.shortnonce += 2
- return bson.BSON.encode(m)
+ return m
def _open_message(self, data):
- box, tmpnonce = from_bson(data, 'box', 'n')
- opened = nacl.crypto_box_open(box, snonce(tmpnonce), self.remote_shortpub, self.shortpriv)
+ opened = nacl.crypto_box_open(data, snonce(self.remotenonce), self.remote_shortpub, self.shortpriv)
+ self.remotenonce += 2
return opened
def close(self):
@@ -150,21 +147,47 @@ def read(self):
class PTLS_Server(PTLS_Socket):
- def do_handshake(self):
- """Perform a PTLS handshake."""
+ def __init__(self, *args, **kwargs):
+ PTLS_Socket.__init__(self, *args, **kwargs)
self.shortnonce = 4
+ self.remotenonce = 5
+
+ # hint cb only called if client sends hints
+ self.hint_cb = None
+ def do_handshake(self):
+ """Perform a PTLS handshake."""
# first frame is client_hello, with his short-term pubkey
data = self._recv_frame()
- self.remote_shortpub = from_bson(data, 'spub')
+ self.remote_shortpub, pskhint, cahint = from_bson(data, 'spub', 'pskhint', 'cahint')
+
+ # in case we get a hint we need to get the respective psk/cav
+ if pskhint or cahint:
+ if not self.hint_cb: raise pwrtls_exception('Hint supplied, but no hint_cb set.')
+ self.psk, self.cav = self.hint_cb()
# now send our hello message with short-term pubkey
self._send_frame(self.serverhello())
# receive verification message for authenticating the short-term key
data = self._recv_frame()
opened = nacl.crypto_box_open(data, snonce(3), self.remote_shortpub, self.shortpriv)
- remote_longpub, vbox, vnonce = from_bson(opened, 'lpub', 'v', 'vn')
+ self.remote_longpub, vbox, vnonce, pskv, cav = from_bson(opened, 'lpub', 'v', 'vn', 'pskv', 'cav')
+
+ # check verifybox
+ inner_spub = None
+ try: inner_spub = nacl.crypto_box_open(vbox, vnonce, self.remote_longpub, self.privkey)
+ except ValueError: pass
+ if not inner_spub == str(self.remote_shortpub):
+ raise pwrtls_exception('Verifybox failure, client not in posession of correct private keys!')
+
+ # now actual remote authentication must happen
+ # verifybox is checked before this because validate_cb probably costs more
+ if not self.validate_cb:
+ logger.critical('PTLS socket has no validate_cb, connection will be INSECURE!')
+ else:
+ if not self.validate_cb(self.remote_longpub, pskv, cav):
+ raise pwrtls_exception('Validation callback veto.')
def serverhello(self):
m = {
@@ -175,22 +198,33 @@ def serverhello(self):
snonce(2), self.remote_shortpub, self.privkey)),
'lpub': _b(self.pubkey),
}
- return bson.BSON.encode(m)
+ enc = bson.BSON.encode(m)
+ return enc
class PTLS_Client(PTLS_Socket):
- def do_handshake(self):
- """Perform a PTLS handshake."""
+ def __init__(self, *args, **kwargs):
+ PTLS_Socket.__init__(self, *args, **kwargs)
self.shortnonce = 5
+ self.remotenonce = 4
+ def do_handshake(self):
+ """Perform a PTLS handshake."""
self._send_frame(self.clienthello())
# receive server hello with his short-term pubkey
data = self._recv_frame()
box, self.remote_longpub = from_bson(data, 'box', 'lpub')
srvhello = nacl.crypto_box_open(box, snonce(2), self.remote_longpub, self.shortpriv)
- self.remote_shortpub = from_bson(srvhello, 'spub')
+ self.remote_shortpub, pskv, cav = from_bson(srvhello, 'spub', 'pskv', 'cav')
+
+ # now actual remote authentication must happen
+ if not self.validate_cb:
+ logger.critical('PTLS socket has no validate_cb, connection will be INSECURE!')
+ else:
+ if not self.validate_cb(self.remote_longpub, pskv, cav):
+ raise pwrtls_exception('Validation callback veto.')
# send verification message authenticating our short-term key with our long-term one
self._send_frame(self.clientverify())
@@ -205,14 +239,12 @@ def clientverify(self):
self.nonce += 1
vn = lnonce(self.nonce)
- verifybox = _b(nacl.crypto_box(
- self.shortpub, vn, self.remote_longpub, self.privkey
- ))
+ verifybox = nacl.crypto_box(self.shortpub, vn, self.remote_longpub, self.privkey)
m = _b(nacl.crypto_box(
str(bson.BSON.encode({
'lpub': _b(self.pubkey),
- 'v': verifybox,
+ 'v': _b(verifybox),
'vn': _b(vn),
})),
snonce(3), self.remote_shortpub, self.shortpriv
@@ -229,9 +261,9 @@ def wrap_socket(sock, pubkey=None, privkey=None, nonce=None,
return PTLS_Client(sock, pubkey=pubkey, privkey=privkey, nonce=nonce)
-def verify_remote_longterm_pubkey():
- # we can only open this if we actually have the clients long-term key.
- if self.rpub:
- if str(remote_longpub) != self.rpub: raise pwrtls_exception('remote long-term key mismatch.')
- boxshort = nacl.crypto_box_open(vbox, vnonce, self.rpub, self.privkey)
- if str(boxshort) != str(self.remote_shortpub): raise pwrtls_exception('remote short-term key verify failed.')
+def validator_longterm_pubkey(knownkey):
+ return lambda lpub, pskv, cav: lpub == knownkey
+
+def validator_psk(psk):
+ # TODO
+ return lambda lpub, pskv, cav: lpub == knownkey
View
Binary file not shown.

0 comments on commit 958f06a

Please sign in to comment.