Implementazione open-source del protocollo di Strong Customer Authentication di Poste Italiane, (https://posteid.poste.it), lato client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
2.3 KiB

2 years ago
  1. import json
  2. from random import randint
  3. from time import time
  4. from uuid import uuid4
  5. from jwcrypto.jwe import JWE
  6. from pyotp import HOTP
  7. from requests import Request
  8. from .utils import sha256_base64, hmac_sha256
  9. class JWEHandler:
  10. def __init__(self, appdata):
  11. self.appdata = appdata
  12. def new_otp_specs(self):
  13. generator = HOTP(self.appdata['xkey_seed'], 8, "SHA1")
  14. counter = randint(0, 99999999)
  15. otp_specs = {}
  16. otp_specs['movingFactor'] = counter
  17. otp_specs['otp'] = generator.generate_otp(counter)
  18. otp_specs['type'] = "HMAC-SHA1"
  19. return otp_specs
  20. def encrypt(self, sub, data, auth=False):
  21. now = int(time())
  22. claims = {'data': data}
  23. claims['sub'] = sub
  24. claims['jti'] = str(uuid4())
  25. claims['iat'] = now
  26. claims['nbf'] = now
  27. claims['exp'] = now + 60
  28. claims['iss'] = "app-posteid-v3"
  29. headers = {}
  30. headers['cty'] = "JWE"
  31. headers['typ'] = "JWT"
  32. headers['alg'] = "RSA-OAEP-256"
  33. headers['enc'] = "A256CBC-HS512"
  34. if auth:
  35. app_uuid = self.appdata['xkey_appuuid']
  36. headers['kid'] = app_uuid
  37. claims['kid-sha256'] = sha256_base64(app_uuid)
  38. claims['otp-specs'] = self.new_otp_specs()
  39. jwe_token = JWE(json.dumps(claims),
  40. protected=headers,
  41. recipient=self.appdata.serv_pubkey.jwk)
  42. return jwe_token.serialize(compact=True)
  43. def req_jwe_post(self, url, sub, data, auth=False):
  44. jwe_token = self.encrypt(sub, data, auth)
  45. headers = {'Content-Type': "application/json; charset=UTF-8"}
  46. req = Request('POST', url, headers, data=jwe_token)
  47. return req
  48. def req_jwe_bearer(self, url, sub, data, auth=False):
  49. jwe_token = self.encrypt(sub, data, auth)
  50. headers = {'Content-Type': "",
  51. 'Authorization': "Bearer " + jwe_token}
  52. req = Request('GET', url, headers)
  53. return req
  54. def decrypt(self, serialized_jwe_token):
  55. if isinstance(serialized_jwe_token, bytes):
  56. serialized_jwe_token = serialized_jwe_token.decode('utf-8')
  57. jwe_token = JWE()
  58. jwe_token.deserialize(serialized_jwe_token)
  59. jwe_token.decrypt(self.appdata.app_privkey.jwk)
  60. return json.loads(jwe_token.payload)