model.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. # Copyright 2016 Google Inc. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Implements data model for the library.
  15. This module implements basic data model objects that are necessary
  16. for interacting with the Security Key as well as for implementing
  17. the higher level components of the U2F protocol.
  18. """
  19. import base64
  20. import json
  21. from pyu2f import errors
  22. class ClientData(object):
  23. """FIDO U2F ClientData.
  24. Implements the ClientData object of the FIDO U2F protocol.
  25. """
  26. TYP_AUTHENTICATION = 'navigator.id.getAssertion'
  27. TYP_REGISTRATION = 'navigator.id.finishEnrollment'
  28. def __init__(self, typ, raw_server_challenge, origin):
  29. if typ not in [ClientData.TYP_REGISTRATION, ClientData.TYP_AUTHENTICATION]:
  30. raise errors.InvalidModelError()
  31. self.typ = typ
  32. self.raw_server_challenge = raw_server_challenge
  33. self.origin = origin
  34. def GetJson(self):
  35. """Returns JSON version of ClientData compatible with FIDO spec."""
  36. # The U2F Raw Messages specification specifies that the challenge is encoded
  37. # with URL safe Base64 without padding encoding specified in RFC 4648.
  38. # Python does not natively support a paddingless encoding, so we simply
  39. # remove the padding from the end of the string.
  40. server_challenge_b64 = base64.urlsafe_b64encode(
  41. self.raw_server_challenge).decode()
  42. server_challenge_b64 = server_challenge_b64.rstrip('=')
  43. return json.dumps({'typ': self.typ,
  44. 'challenge': server_challenge_b64,
  45. 'origin': self.origin}, sort_keys=True)
  46. def __repr__(self):
  47. return self.GetJson()
  48. class RegisteredKey(object):
  49. def __init__(self, key_handle, version=u'U2F_V2'):
  50. self.key_handle = key_handle
  51. self.version = version
  52. class RegisterResponse(object):
  53. def __init__(self, registration_data, client_data):
  54. self.registration_data = registration_data
  55. self.client_data = client_data
  56. class SignResponse(object):
  57. def __init__(self, key_handle, signature_data, client_data):
  58. self.key_handle = key_handle
  59. self.signature_data = signature_data
  60. self.client_data = client_data