Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrate tack-client-demo into tackpy #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.pyc
.idea

# pin.store of tack-client
pin.store
42 changes: 42 additions & 0 deletions tack/structures/TackPin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python
from __future__ import print_function
from tack.structures.Tack import Tack
from tack.util.Time import Time
import time


class TackPin():

def __init__(self, tack):
assert isinstance(tack, Tack), "Obj was no TACK"
self.initial_time = time.time()
self.end_time = 0
self.public_key = tack.public_key
self.min_generation = tack.min_generation

def __str__(self):
s = """initial_time = %s
end_time = %s
public_key = %s
min_generation = %s""" %\
(Time.posixTimeToStr(self.initial_time),
Time.posixTimeToStr(self.end_time),
self.public_key,
self.min_generation)

return s

def fitsTack(self, tack):
return self.public_key.getRawKey() == tack.public_key.getRawKey()

def extend(self, tack): # which means also activate
if self.fitsTack(tack):
diff = time.time() - self.initial_time
self.end_time = time.time() + min(diff, 2592000) # max 30days

'''If a tack has matching pins and a min_generation greater than the
stored min_generation, the stored value SHALL be set to the tack's value.'''
self.min_generation = tack.min_generation

else:
raise SyntaxError("active TACK and pin don't fit!")
151 changes: 151 additions & 0 deletions tests/tack-client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env python
from __future__ import print_function
import socket
from tlslite import TLSConnection, HandshakeSettings, tackpyLoaded
from tack.structures.TackPin import TackPin
import argparse
import shelve
import time
import os


def pinActivation(pin, tack, min_generation):
'''will only be called when there is a active, valid TACK'''
if tack.generation >= min_generation:
if pin is None:
pin = TackPin(tack)
print("New inactive Pin:")
print(pin)

elif isinstance(pin, TackPin):
if pin.end_time < time.time(): # pin inactive
if pin.fitsTack(tack):
print("Activating pin:")
pin.extend(tack)
else:
pin = TackPin(tack)
print("Replacing old inactive pin by new inactive pin:")
else:
print("Extending pin:")
pin.extend(tack)
print(pin)

else:
raise TypeError

print("------------------------------")
assert (pin is not None), "This should be a pin."
return pin

if __name__ == "__main__":

full_path = os.path.realpath(__file__)
PATH = os.path.dirname(full_path) + "/pin.store"
havePin = False
haveActivePin = False
usingTACK = False
newPins = False
min_generation = 0

parser = argparse.ArgumentParser(description="TACK client demo")
parser.add_argument("-s", "--server", help="connect to server", required=True)
parser.add_argument("-p", "--port", help="connect to port", required=True)
parser.add_argument("--show", action="store_true", help="show the content of your pin store for that domain")
args = parser.parse_args()

### get pins from store
store = shelve.open(PATH)
sockString = args.server + ":" + args.port # identifier of connection

if sockString in store:
pins = store[sockString]
havePin = True
for pin in pins:
try:
if pin.end_time < time.time():
haveActivePin = True
min_generation = max(min_generation, pin.min_generation) # update min_generation
except AttributeError:
pass
else:
pins = [None, None]

assert not (haveActivePin and not havePin), "Cant't have activePin, but no pins"

if args.show:
for pin in pins:
print("------------------------------")
print(pin)
print("------------------------------")
exit(0)
### end get pins

# open socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((args.server, int(args.port)))

# construct TLS Connection
conn = TLSConnection(sock)
settings = HandshakeSettings()
settings.useExperimentalTackExtension = True
conn.handshakeClientCert(settings=settings)

if conn.session.tackExt:
tackExt = conn.session.tackExt
print("TACK is working on " + sockString)
print("------------------------------")
print(tackExt)
print("------------------------------")
if tackExt.activation_flags != 0:
usingTACK = True

# if no active TACKs in TLS-Connection
if not usingTACK:
if haveActivePin:
raise Error("Active PIN, but no active TACK. Connection might be compromised!")
elif havePin:
del store[sockString] # del inactive pin
print("deleting inactive pin")
else:
print(sockString + " doesn't seem to you use TACK.")

store.close()
conn.close()
exit(0)

if not tackExt.verifySignatures():
raise SyntaxError("TACK doesn't belong to Cert!")
# from here exist only one or two valid TACKs

# check tack generations
'''If a tack has matching pins in the pin store and a generation
less than the stored min_generation, then that tack is revoked and
the client SHALL send a fatal "certificate_revoked" error alert.'''
for tack in tackExt.tacks:
if tack.min_generation < min_generation:
raise Error("Certificate revoked")

if tackExt.activation_flags == 3:
assert tackExt.tacks[0].public_key != tackExt.tacks[1].public_key, "two pins MUST reference different public keys"

# process pin activation
if tackExt.activation_flags % 2 == 1: # 1 and 3
pins[0] = pinActivation(pins[0], tackExt.tacks[0], min_generation)
if tackExt.activation_flags >= 2: # 2 and 3
pins[1] = pinActivation(pins[1], tackExt.tacks[1], min_generation)

# sync min_generation
for pin in pins:
if pin is not None:
# update min_generation
min_generation = max(min_generation, pin.min_generation)
for pin in pins:
if pin is not None:
# write to pins
pin.min_generation = min_generation

# write and close
# print("writing: " + str(pins))
store[sockString] = pins
store.close()
conn.close()