def _restore_master_secret(self, backup_file, encrypt_master_secret, passphrase, salt): """Restore secret from file. Decode secret if encrypted. """ try: with open(backup_file) as json_file: backup = json.load(json_file) except ValueError: raise SecretsError('Master Secret backup file is corrupted.') if encrypt_master_secret: tag, plaintext = crypto.aes_gcm_decrypt( aes_key=generate_aes_key(passphrase, salt), iv=str(backup['IV'].decode('hex')), header=str(backup['startTime']), ciphertext=str(backup['ciphertext'].decode('hex'))) # Check authentication tag if backup['tag'] != tag: raise SecretsError('AES-GSM Decryption Failed. Authentication tag is not correct') self.start_time = Time.ISOtoDateTime(str(backup['startTime'])) master_secret = plaintext.decode('hex') else: self.start_time = Time.ISOtoDateTime(backup['startTime']) master_secret = backup['master_secret_hex'].decode('hex') return master_secret, self.start_time
def generate_qr(self, wId): webOTT = secrets.generate_ott(options.OTTLength, self.application.server_secret.rng, "hex") nowTime = Time.syncedNow() expirePinPadTime = nowTime + datetime.timedelta( seconds=options.accessNumberExpireSeconds) expireTime = expirePinPadTime + datetime.timedelta( seconds=options.accessNumberExtendValiditySeconds) self.storage.add(stage="auth", expire_time=expireTime, webOTT=webOTT, wid=wId) qrUrl = options.rpsBaseURL + "#" + wId params = { "ttlSeconds": options.accessNumberExpireSeconds, "qrUrl": qrUrl, "webOTT": webOTT, "localTimeStart": Time.DateTimetoEpoch(nowTime), "localTimeEnd": Time.DateTimetoEpoch(expirePinPadTime) } return params
def _verifySignature(self): identity = self.get_argument("i", default="") expires = self.get_argument("e", default="") signature = self.get_argument("s", default="") log.debug("/mpinActivate request for identity: {0}".format(identity)) try: data = json.loads(identity.decode("hex")) userid = data["userID"] issued = data["issued"] sIssued = Time.DateTimetoHuman(Time.ISOtoDateTime(issued)) mobile = int(data.get("mobile") or 0) except Exception as E: log.error("Error parsing the verification email: {0}".format(E)) userid, issued, sIssued = None, None, None if userid: if expires < datetime.datetime.utcnow().isoformat(b"T").split( ".")[0] + "Z": isValid = False info = "Link expired" else: isValid = True info = "" deviceName = mobile and "Mobile" or "PC" else: log.error("/mpinActivate: Invalid IDENTITY: {0}".format(identity)) isValid, info = False, "Invalid identity" deviceName, issued = "", "" params = { "isValid": isValid, "identity": identity, "errorMessage": info, "userid": userid, "issued": issued, "humanIssued": sIssued, "activated": False, "deviceName": deviceName, "activateKey": signature } return params
def _schedule_expiration_check(self): if self._timeout: self.ioloop.remove_timeout(self._timeout) self._timeout = None while len(self._expires_list) > 0: item_expiration, item_id = self._expires_list[0] try: item = self._items[item_id] except KeyError: del self._expires_list[0] continue now = Time.syncedNow() if not item._active or item_expiration < now: del self._expires_list[0] del self._items[item_id] self._delete_from_indexes(item) continue # No more expired items, schedule next check self._timeout = self.ioloop.add_timeout( item_expiration - now + datetime.timedelta(milliseconds=100), self._schedule_expiration_check) break self._storage_change()
def _schedule_expiration_check(self): if self._timeout: self.ioloop.remove_timeout(self._timeout) self._timeout = None while len(self._expires_list) > 0: item_expiration, item_id = self._expires_list[0] try: item = self._items[item_id] except KeyError: del self._expires_list[0] continue now = Time.syncedNow() if not item._active or item_expiration < now: del self._expires_list[0] del self._items[item_id] self._delete_from_indexes(item) continue # No more expired items, schedule next check self._timeout = self.ioloop.add_timeout( item_expiration - now + datetime.timedelta(milliseconds=100), self._schedule_expiration_check ) break self._storage_change()
def get(self): reason = "OK" self.set_status(200, reason=reason) start_time_str = Time.DateTimeToISO( self.application.master_secret.start_time), self.write({ 'startTime': start_time_str, 'service_name': 'D-TA server', 'message': reason }) return
def _get_server_secret(self): expires = Time.syncedISO(seconds=SIGNATURE_EXPIRES_OFFSET_SECONDS) certivox_server_secret = self._get_certivox_server_secret_share(expires) customer_server_secret = self._get_customer_server_secret_share(expires) try: server_secret_hex = crypto.mpin_recombine_g2(certivox_server_secret, customer_server_secret) except crypto.CryptoError as e: log.error(e) raise SecretsError('M-Pin Server Secret Generation Failed') return server_secret_hex.decode("hex")
def validate_pass2_value(self, mpin_id, u, ut, y, v): """Validate pass2 value. y - pass 1 values v - pass 2 value in question """ date = crypto.today() check_dates = [date] if Time.syncedNow().hour < 1: check_dates.append(date - 1) for date in check_dates: hid, htid = crypto.mpin_server_1(mpin_id, date) success, _, _ = crypto.mpin_server_2(self.server_secret, v, date, hid, htid, y, u, ut) if success != -19: break return success
def __init__(self, storage, expire_time, **kwargs): '''expireTime should be in ISO format''' self.__fields = ["_id", "_active", "_expires"] self.__storage = storage self._id = uuid.uuid1().hex if isinstance(expire_time, datetime.datetime): self._expires = expire_time.isoformat() else: self._expires = expire_time self._update_item(**kwargs) self._expiration_datetime = None if self._expires: self._expiration_datetime = Time.ISOtoDateTime(self._expires) self.__storage.update_index(self)
def generate_qr(self, wId): webOTT = secrets.generate_ott(options.OTTLength, self.application.server_secret.rng, "hex") nowTime = Time.syncedNow() expirePinPadTime = nowTime + datetime.timedelta(seconds=options.accessNumberExpireSeconds) expireTime = expirePinPadTime + datetime.timedelta(seconds=options.accessNumberExtendValiditySeconds) self.storage.add(stage="auth", expire_time=expireTime, webOTT=webOTT, wid=wId) qrUrl = options.rpsBaseURL + "#" + wId params = { "ttlSeconds": options.accessNumberExpireSeconds, "qrUrl": qrUrl, "webOTT": webOTT, "localTimeStart": Time.DateTimetoEpoch(nowTime), "localTimeEnd": Time.DateTimetoEpoch(expirePinPadTime) } return params
def __init__(self): handlers = [ (r"/clientSecret", ClientSecretHandler), (r"/serverSecret", ServerSecretHandler), (r"/timePermit", TimePermitHandler), (r"/timePermits", TimePermitsHandler), (r"/status", StatusHandler), (r"/(.*)", DefaultHandler), ] settings = dict(xsrf_cookies=False) super(Application, self).__init__(handlers, **settings) Seed.getSeed(options.EntropySources ) # Get seed value for random number generator self.master_secret = secrets.MasterSecret( passphrase=options.passphrase, salt=options.salt, seed=Seed.seedValue, backup_file=options.backup_file, encrypt_master_secret=options.encrypt_master_secret, time=Time.syncedNow())
def add(self, key, expires, value): if expires: self._execute("setex", key, (expires - Time.syncedNow()), value) else: self._execute("set", key, value)
def today(): """Return time in slots since epoch using synced time""" utc_dt = datetime.datetime.utcfromtimestamp(0) return int((Time.syncedNow() - utc_dt).total_seconds() / 86400)
def get(self): # Remote request information if 'User-Agent' in self.request.headers.keys(): UA = self.request.headers['User-Agent'] else: UA = 'unknown' request_info = '%s %s %s %s ' % ( self.request.method, self.request.path, self.request.remote_ip, UA) # Get arguments try: app_id = str(self.get_argument('app_id')) expires = self.get_argument('expires') signature = self.get_argument('signature') except tornado.web.MissingArgumentError as ex: reason = ex.log_message log.error("%s %s" % (request_info, reason)) self.set_status(403, reason=reason) self.content_type = 'application/json' self.write({'message': reason}) self.finish() return request_info = request_info + app_id # Get path used for signature path = self.request.path path = path.replace("/", "") # Check signature is valid and that timestamp has not expired M = str("%s%s%s" % (path, Keys.app_id, expires)) valid, reason, code = verifySignature(M, signature, Keys.app_key, expires) if not valid: return_data = {'code': code, 'message': reason} log.error("%s %s" % (request_info, reason)) self.set_status(status_code=code, reason=reason) self.content_type = 'application/json' self.write(return_data) self.finish() return try: server_secret_hex = self.application.master_secret.get_server_secret( ) except secrets.SecretsError as e: log.error( 'M-Pin Server Secret Generation Failed: {0}. Request info: {1}' .format(e, request_info)) return_data = { 'errorCode': e.message, 'reason': 'M-Pin Server Secret Generation Failed', } self.set_status(500, reason=reason) self.content_type = 'application/json' self.write(return_data) self.finish() return # Hash server secret share server_secret = server_secret_hex.decode("hex") hash_server_secret_hex = hashlib.sha256(server_secret).hexdigest() log.info("%s hash_server_secret_hex: %s" % (request_info, hash_server_secret_hex)) # Returned data reason = "OK" self.set_status(200, reason=reason) self.content_type = 'application/json' return_data = { 'serverSecret': server_secret_hex, 'startTime': Time.DateTimeToISO(self.application.master_secret.start_time), 'message': reason } self.write(return_data) log.debug("%s %s" % (request_info, return_data)) self.finish() return
try: credentialsFile = options.credentialsFile Keys.loadFromFile(credentialsFile) except Exception as E: log.error( "Error opening the credentials file: {0}".format(credentialsFile)) log.error(E) sys.exit(1) # TMP fix for 'ValueError: I/O operation on closed epoll fd' # Fixed in Tornado 4.2 tornado.ioloop.IOLoop.instance() # Sync time to CertiVox time server if options.syncTime: Time.getTime(wait=True) if options.backup and options.encrypt_master_secret and not options.passphrase: options.passphrase = getpass.getpass("Please enter passphrase:") http_server = Application() http_server.listen(options.port, options.address, xheaders=True) io_loop = tornado.ioloop.IOLoop.instance() if options.autoReload: log.debug("Starting autoreloader") tornado.autoreload.watch(CONFIG_FILE) tornado.autoreload.start(io_loop) if options.syncTime and (options.timePeriod > 0): scheduler = tornado.ioloop.PeriodicCallback(Time.getTime,