def SIGALRMhandler(signum, frame): CommonUtils.atm_protocol_error_exit('TIMEOUT')
def do_GET(self): self.connection.settimeout(10.0) # Parse URL query parameters, error out if invalid # FIXME: Move everything to POST once ATM-side implemented response_to_client = "" try: urlparts = urlparse.urlparse(self.path) path = urlparts.path if path != "/atm.cgi": raise Exception("Invalid path") query = urlparts.query queryitems = urlparse.parse_qs(query) action = queryitems['action'][0] if action not in ('new', 'balance', 'deposit', 'withdraw'): raise Exception("Invalid action") if (action == 'balance') and ('amount' in queryitems): raise Exception("Invalid parameters") account = queryitems['account'][0] if CommonUtils.valid_accountstr(account) is False: raise Exception("Invalid parameters") amount = None if (action != 'balance'): amount = queryitems['amount'][0] if CommonUtils.valid_currency(amount) is False: raise Exception("Invalid parameters") card = None if (action != 'new'): card = queryitems['card'][0] if (card is None) or (card == ""): raise Exception("Invalid parameters") elif (action == 'new') and (card in queryitems): raise Exception("Invalid parameters") # After validation completes above, process the request if action == 'new': response_to_client = BANKVAULT.adduser(account, amount) elif action == 'balance': response_to_client = BANKVAULT.getbalance(account, card) elif action == 'deposit': response_to_client = BANKVAULT.deposit(account, card, amount) elif action == 'withdraw': response_to_client = BANKVAULT.withdraw(account, card, amount) except ParameterException: # ATM supplied something incorrect self.fail_request("REQUEST FAILED") return except Exception: sys.stdout.write("protocol_error\n") sys.stdout.flush() self.fail_request("REQUEST FAILED") return # FIXME: Parse POST parameters # Validate supplied parameters/combinations (POST items) self.send_response(200) self.send_header("Content-type", "text/plain") self.send_header("Pragma", "no-cache") self.send_header("Content-control", "no-cache") self.end_headers() self.wfile.write(response_to_client) sys.stdout.write(response_to_client.split("\n")[0] + "\n") sys.stdout.flush()
class Bank: def __init__(self): self._common_utils = CommonUtils('Bank') self.error_exit = self._common_utils.error_exit self._common_utils.parse_opts() # For CA self._certauthorityprivatekey = None self._certauthority = None self._certauthoritynextserial = None # For web server self._tlscert = None self._tlsprivatekey = None def setup_ca(self): self._certauthorityprivatekey = crypto.PKey() # Key sizes based on survey of bank web sites & CA Authorities # Code based on http://docs.ganeti.org/ganeti/2.9/html/design-x509-ca.html self._certauthorityprivatekey.generate_key(crypto.TYPE_RSA, 2048) self._certauthority = crypto.X509() self._certauthority.set_version(3) self._certauthority.set_serial_number(1) self._certauthority.get_subject().CN = "ca.bank.example.com" self._certauthority.gmtime_adj_notBefore(0) self._certauthority.gmtime_adj_notAfter(86400 * 365 * 5) # ~5 years self._certauthority.set_issuer(self._certauthority.get_subject()) self._certauthority.set_pubkey(self._certauthorityprivatekey) self._certauthority.add_extensions([ crypto.X509Extension("basicConstraints", True, "CA:TRUE, pathlen:0"), crypto.X509Extension("subjectAltName", True, "DNS:ca.bank.example.com"), crypto.X509ExtensionType("keyUsage", True, "keyCertSign, cRLSign"), crypto.X509ExtensionType("subjectKeyIdentifier", False, "hash", subject=self._certauthority), ]) self._certauthority.sign(self._certauthorityprivatekey, "sha256") self._certauthoritynextserial = 2 def setup_atmcrypto(self): atmkey = crypto.PKey() atmkey.generate_key(crypto.TYPE_RSA, 2048) certreq = crypto.X509Req() certreq.get_subject().CN = "atm-machine.bank.example.com" certreq.set_pubkey(atmkey) certreq.sign(atmkey, "sha256") atmcert = crypto.X509() atmcert.set_subject(certreq.get_subject()) atmcert.set_serial_number(self._certauthoritynextserial) atmcert.set_issuer(self._certauthority.get_subject()) atmcert.gmtime_adj_notBefore(0) atmcert.gmtime_adj_notAfter(86400 * 365 * 3) # under CA's lifetime atmcert.set_pubkey(certreq.get_pubkey()) atmcert.add_extensions([ crypto.X509Extension("basicConstraints", True, "CA:FALSE"), crypto.X509ExtensionType("extendedKeyUsage", True, "clientAuth"), ]) atmcert.sign(self._certauthorityprivatekey, "sha256") self._certauthoritynextserial = self._certauthoritynextserial + 1 if path.exists(self._common_utils.get_authfilename()): self.error_exit('Auth file already exists (race check)') outfile = file(self._common_utils.get_authfilename(), 'w') outfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, atmkey)) outfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, atmcert)) outfile.write( crypto.dump_certificate(crypto.FILETYPE_PEM, self._certauthority)) outfile.close() def setup_webcrypto(self): global TLStempfile self._tlsprivatekey = crypto.PKey() self._tlsprivatekey.generate_key(crypto.TYPE_RSA, 2048) certreq = crypto.X509Req() certreq.get_subject().CN = "atmserver.bank.example.com" certreq.set_pubkey(self._tlsprivatekey) certreq.sign(self._tlsprivatekey, "sha256") self._tlscert = crypto.X509() self._tlscert.set_subject(certreq.get_subject()) self._tlscert.set_serial_number(self._certauthoritynextserial) self._tlscert.set_issuer(self._certauthority.get_subject()) self._tlscert.gmtime_adj_notBefore(0) self._tlscert.gmtime_adj_notAfter(86400 * 365 * 3) # under CA's lifetime self._tlscert.set_pubkey(certreq.get_pubkey()) self._tlscert.add_extensions([ crypto.X509Extension("basicConstraints", True, "CA:FALSE"), crypto.X509Extension("subjectAltName", True, "DNS:atmserver.bank.example.com"), crypto.X509ExtensionType("extendedKeyUsage", True, "serverAuth"), ]) self._tlscert.sign(self._certauthorityprivatekey, "sha256") self._certauthoritynextserial = self._certauthoritynextserial + 1 tlsfile = tempfile.NamedTemporaryFile() tlsfile.file.write( crypto.dump_privatekey(crypto.FILETYPE_PEM, self._tlsprivatekey)) tlsfile.file.write( crypto.dump_certificate(crypto.FILETYPE_PEM, self._tlscert)) tlsfile.file.write( crypto.dump_certificate(crypto.FILETYPE_PEM, self._certauthority)) tlsfile.file.flush() TLStempfile = tlsfile # Closing the file/program will destroy this temporary file def start_webserver(self): tlsServer = Threading_TLSHTTPServer(self._common_utils.get_ipaddress(), self._common_utils.get_ipport(), self._tlscert, self._tlsprivatekey) # Since we infinitely loop in the webserver # Notify that the card was created as late as possible to avoid races # with the test infrastructure sys.stdout.write("created\n") sys.stdout.flush() tlsServer.run() def run(self): global BANKVAULT global BANKVAULT_THREADLOCK BANKVAULT = Vault() BANKVAULT_THREADLOCK = threading.Lock() self.setup_ca() self.setup_webcrypto() self.setup_atmcrypto() # Start mutlithreading try: self.start_webserver() except socket.error as e: self.error_exit(str(e))
def test_int_to_str(): assert CommonUtils.int_to_str(1) == "1" assert CommonUtils.int_to_str(1000) == "1,000" assert CommonUtils.int_to_str(1000000) == "1,000,000" assert CommonUtils.int_to_str(-1000) == "-1,000"
def test_timestamp_to_datetime(): assert CommonUtils.timestamp_to_datetime(0) == datetime.datetime(1970, month=1, day=1, hour=2)
def test_bytes_to_str(): assert CommonUtils.bytes_to_str(11) == "11 Bytes" assert CommonUtils.bytes_to_str(1000) == "1000 Bytes" assert CommonUtils.bytes_to_str(10000000) == "9.54 MiB" assert CommonUtils.bytes_to_str(100000000000000) == "90.95 TiB"
def __init__(self): self._common_utils = CommonUtils('ATM') self.atm_protocol_error_exit = \ self._common_utils.atm_protocol_error_exit self.error_exit = self._common_utils.error_exit self._common_utils.parse_opts()
class ATM: def __init__(self): self._common_utils = CommonUtils('ATM') self.atm_protocol_error_exit = \ self._common_utils.atm_protocol_error_exit self.error_exit = self._common_utils.error_exit self._common_utils.parse_opts() def read_cardfile(self, card_filename): cardhandle = file(card_filename, 'r') card_data = cardhandle.readline().rstrip() cardhandle.close() return card_data def write_cardfile(self, card_filename, card_data): cardhandle = file(card_filename, 'w') cardhandle.write(card_data) cardhandle.close() def run(self): global tempcafile utils = self._common_utils transactiontype = utils.get_transactiontype() card_filename = utils.get_cardfilename() card_data = "" if transactiontype != 'N': if card_filename is not None and os.path.isfile(card_filename): try: card_data = self.read_cardfile(card_filename) except Exception: self.error_exit('Error loading ATM card') else: self.error_exit('Card file not found to load') params = {} if transactiontype == 'N': params['action'] = 'new' params['account'] = utils.get_account() params['amount'] = utils.get_transactionamount() elif transactiontype == 'G': params['action'] = 'balance' params['account'] = utils.get_account() params['card'] = card_data elif transactiontype == 'D': params['action'] = 'deposit' params['account'] = utils.get_account() params['amount'] = utils.get_transactionamount() params['card'] = card_data elif transactiontype == 'W': params['action'] = 'withdraw' params['account'] = utils.get_account() params['amount'] = utils.get_transactionamount() params['card'] = card_data else: self.error_exit('Unknown transaction type - should never get here') clientcertfile = self._common_utils.get_authfilename() cacertfile = clientcertfile # Last item; only cert with CA:TRUE set try: # We are using IPs, but certificates prefer names # Override the SSL processing to look for our desired name atmserverhostname = 'atmserver.bank.example.com' httpsclient = urllib3.HTTPSConnectionPool( host=utils.get_ipaddress(), port=utils.get_ipport(), maxsize=1, ca_certs=cacertfile, cert_reqs=ssl.CERT_REQUIRED, cert_file=clientcertfile, ssl_version=ssl.PROTOCOL_TLSv1_2, retries=0, timeout=10, assert_hostname=atmserverhostname) response = httpsclient.request('GET', '/atm.cgi', params) except urllib3.exceptions.SSLError: self.atm_protocol_error_exit('SSL Communication failure') except Exception: self.error_exit('Unknown Communication failure') if response.status != 200: self.error_exit('Remote error') response_data = response.data responselines = response_data.split('\n') if transactiontype == 'N': if len(responselines) == 1: self.error_exit('No card info provided') if os.path.exists(card_filename) is False: self.write_cardfile(card_filename, responselines[1] + '\n') else: self.error_exit('Card file found-cannot overwrite') sys.stdout.write(responselines[0] + '\n') sys.stdout.flush()