def register(self, facet, app_id, request): """ RegisterRequest = { "version": "U2F_V2", "challenge": string, //b64 encoded challenge "appId": string, //app_id } """ if not isinstance(request, RegisterRequest): request = RegisterRequest(request) if request.version != 'U2F_V2': raise ValueError('Unsupported U2F version: %s' % request.version) # Client data client_data = ClientData( typ=Type.REGISTER.value, challenge=request['challenge'], origin=facet ) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # ECC key generation priv_key = ec.generate_private_key(CURVE, default_backend()) pub_key = priv_key.public_key().public_bytes( Encoding.DER, PublicFormat.SubjectPublicKeyInfo) pub_key = pub_key[-65:] # Store key_handle = os.urandom(64) app_param = sha_256(app_id.encode('idna')) self.keys[key_handle] = (priv_key, app_param) # Attestation signature cert_priv = load_pem_private_key( CERT_PRIV, password=None, backend=default_backend()) cert = CERT data = b'\x00' + app_param + client_param + key_handle + pub_key signer = cert_priv.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = (b'\x05' + pub_key + six.int2byte(len(key_handle)) + key_handle + cert + signature) return RegisterResponse( version=request.version, registrationData=websafe_encode(raw_response), clientData=websafe_encode(client_data), )
def register(self, facet, app_id, request): """ RegisterRequest = { "version": "U2F_V2", "challenge": string, //b64 encoded challenge "appId": string, //app_id } """ if not isinstance(request, RegisterRequest): request = RegisterRequest(request) if request.version != "U2F_V2": raise ValueError("Unsupported U2F version: %s" % request.version) # Client data client_data = ClientData(typ=Type.REGISTER.value, challenge=request['challenge'], origin=facet) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # ECC key generation priv_key = ec.generate_private_key(CURVE, default_backend()) pub_key = priv_key.public_key().public_bytes( Encoding.DER, PublicFormat.SubjectPublicKeyInfo) pub_key = pub_key[-65:] # Store key_handle = os.urandom(64) app_param = sha_256(app_id.encode('idna')) self.keys[key_handle] = (priv_key, app_param) # Attestation signature cert_priv = load_pem_private_key(CERT_PRIV, password=None, backend=default_backend()) cert = CERT data = b'\x00' + app_param + client_param + key_handle + pub_key signer = cert_priv.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = (b'\x05' + pub_key + six.int2byte(len(key_handle)) + key_handle + cert + signature) return RegisterResponse( version=request.version, registrationData=websafe_encode(raw_response), clientData=websafe_encode(client_data), )
def verify_signature(self, pubkey): data = self.app_param + self.user_presence + self.counter + \ self.chal_param digest = sha_256(data) pub_key = pub_key_from_der(pubkey) if not pub_key.verify_dsa_asn1(digest, self.signature) == 1: raise Exception('Challenge signature verification failed!')
def verify_csr_signature(self): data = (chr(0x00) + self.app_param + self.chal_param + self.key_handle + self.pub_key) digest = sha_256(data) pub_key = self.certificate.public_key() verify_ecdsa_signature(digest, pub_key, self.signature)
def verify_signature(self, pubkey): data = (self.app_param + self.user_presence + self.counter + self.chal_param) digest = sha_256(data) pub_key = pub_key_from_der(pubkey) verify_ecdsa_signature(digest, pub_key, self.signature)
def create(cls, app_id, devices, challenge=None): # When the challenge is set we encode and hash it to be used in the signature if challenge is not None: encoded_challenge = challenge.encode('ascii') challenge = sha_256(encoded_challenge) if challenge is None: challenge = os.urandom(32) return cls(appId=app_id, registeredKeys=devices, challenge=websafe_encode(challenge))
def getAssertion(self, request, facet="https://www.example.com", touch=False): """ signData = { 'version': "U2F_V2", 'challenge': websafe_encode(self.challenge), 'appId': self.binding.app_id, 'keyHandle': websafe_encode(self.binding.key_handle), } """ if not isinstance(request, SignRequest): request = SignRequest(request) if request.version != "U2F_V2": raise ValueError("Unsupported U2F version: %s" % request.version) key_handle = websafe_decode(request.keyHandle) if key_handle not in self.keys: raise ValueError("Unknown key handle!") # Client data client_data = ClientData( typ="navigator.id.getAssertion", challenge=request['challenge'], origin=facet ) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # Unwrap: priv_key, app_param = self.keys[key_handle] # Increment counter self.counter += 1 # Create signature touch = int2byte(1 if touch else 0) counter = struct.pack('>I', self.counter) data = app_param + touch + counter + client_param signer = priv_key.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = touch + counter + signature return SignResponse( clientData=websafe_encode(client_data), signatureData=websafe_encode(raw_response), keyHandle=request.keyHandle )
def getAssertion(self, request, facet="https://www.example.com"): """ signData = { 'version': "U2F_V2", 'challenge': websafe_encode(self.challenge), 'appId': self.binding.app_id, 'keyHandle': websafe_encode(self.binding.key_handle), } """ if not isinstance(request, SignRequest): request = SignRequest(request) if request.version != "U2F_V2": raise ValueError("Unsupported U2F version: %s" % request.version) key_handle = websafe_decode(request.keyHandle) if key_handle not in self.keys: raise ValueError("Unknown key handle!") # Client data client_data = ClientData( typ="navigator.id.getAssertion", challenge=request['challenge'], origin=facet ) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # Unwrap: priv_key, app_param = self.keys[key_handle] # Increment counter self.counter += 1 # Create signature touch = int2byte(1) counter = struct.pack('>I', self.counter) data = app_param + touch + counter + client_param signer = priv_key.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = touch + counter + signature return SignResponse( clientData=websafe_encode(client_data), signatureData=websafe_encode(raw_response), keyHandle=request.keyHandle )
def retrieve(self, client_id, user_id, transaction_id): transaction_id = b2a_hex(sha_256(transaction_id)) self._delete_expired() transaction = Transaction.query \ .filter(Transaction.transaction_id == transaction_id).first() if transaction is None: raise ValueError('Invalid transaction') if transaction.user.name != user_id or \ transaction.user.client_id != client_id: raise ValueError('Transaction not valid for user_id: %s' % user_id) db.session.delete(transaction) db.session.commit() return transaction.data
def getAssertion(self, facet, app_id, challenge, key, touch_byte=1): """ signData = { 'version': "U2F_V2", 'challenge': websafe_encode(self.challenge), 'appId': self.binding.app_id, 'keyHandle': websafe_encode(self.binding.key_handle), } """ key = RegisteredKey.wrap(key) if key.version != 'U2F_V2': raise ValueError('Unsupported U2F version: %s' % key.version) if key.keyHandle not in self.keys: raise ValueError('Unknown key handle!') # Client data client_data = ClientData( typ=Type.SIGN.value, challenge=challenge, origin=facet ) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # Unwrap: priv_key, app_param = self.keys[key.keyHandle] # Increment counter self.counter += 1 # Create signature touch = six.int2byte(touch_byte) counter = struct.pack('>I', self.counter) data = app_param + touch + counter + client_param signer = priv_key.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = touch + counter + signature return SignResponse( clientData=websafe_encode(client_data), signatureData=websafe_encode(raw_response), keyHandle=key['keyHandle'] )
def store(self, client_id, user_id, transaction_id, data): transaction_id = b2a_hex(sha_256(transaction_id)) user = User.query \ .filter(User.client_id == client_id) \ .filter(User.name == user_id).first() if user is None: user = User(user_id) user.client_id = client_id db.session.add(user) else: self._delete_expired() # Delete oldest transactions until we have room for one more. for transaction in user.transactions \ .offset(self._max_transactions - 1).all(): db.session.delete(transaction) user.transactions.append(Transaction(transaction_id, data)) db.session.commit()
def getAssertion(self, facet, app_id, challenge, key, touch_byte=1): """ signData = { 'version': "U2F_V2", 'challenge': websafe_encode(self.challenge), 'appId': self.binding.app_id, 'keyHandle': websafe_encode(self.binding.key_handle), } """ key = RegisteredKey.wrap(key) if key.version != "U2F_V2": raise ValueError("Unsupported U2F version: %s" % key.version) if key.keyHandle not in self.keys: raise ValueError("Unknown key handle!") # Client data client_data = ClientData(typ=Type.SIGN.value, challenge=challenge, origin=facet) client_data = client_data.json.encode('utf-8') client_param = sha_256(client_data) # Unwrap: priv_key, app_param = self.keys[key.keyHandle] # Increment counter self.counter += 1 # Create signature touch = six.int2byte(touch_byte) counter = struct.pack('>I', self.counter) data = app_param + touch + counter + client_param signer = priv_key.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() raw_response = touch + counter + signature return SignResponse(clientData=websafe_encode(client_data), signatureData=websafe_encode(raw_response), keyHandle=key['keyHandle'])
def _fix_cert(der): # Some early certs have UNUSED BITS incorrectly set. if sha_256(der) in CERTS_TO_FIX: der = der[:-257] + b'\0' + der[-256:] return der
def appParam(self): return sha_256(self['appId'].encode('idna'))
def clientParam(self): return sha_256(websafe_decode(self['clientData']))
def challengeParameter(self): return sha_256(websafe_decode(self['clientData']))
def applicationParameter(self): return sha_256(self['appId'].encode('idna'))