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.
 

128 lines
3.5 KiB

import json
from base64 import b64encode, b64decode
from pathlib import Path
import xdgappdirs
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from jwcrypto import jwk
from pathvalidate import sanitize_filename
data_dir = xdgappdirs.user_data_dir('pyjod', as_path=True)
class RSAPrivateKey:
def __init__(self, key):
self.key = key
@classmethod
def generate(cls):
key = rsa.generate_private_key(65537, 2048)
return cls(key)
@classmethod
def from_pem(cls, data):
key = serialization.load_pem_private_key(data, None)
return cls(key)
@property
def jwk(self):
return jwk.JWK.from_pyca(self.key)
@property
def pubkey_b64(self):
pubkey = self.key.public_key()
pubkey_bytes = pubkey.public_bytes(
serialization.Encoding.DER,
serialization.PublicFormat.SubjectPublicKeyInfo
)
return b64encode(pubkey_bytes).decode('utf-8')
def to_pem(self):
return self.key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption()
)
class RSAPublicKey:
def __init__(self, key):
self.key = key
@classmethod
def from_b64(cls, data):
key_bytes = b64decode(data)
key = serialization.load_der_public_key(key_bytes)
return cls(key)
@classmethod
def from_pem(cls, data):
key = serialization.load_pem_public_key(data)
return cls(key)
@property
def jwk(self):
return jwk.JWK.from_pyca(self.key)
def to_pem(self):
return self.key.public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo
)
class AppData:
def __init__(self, profile_name):
self.profile_dir = data_dir / sanitize_filename(profile_name)
self.profile_dir.mkdir(exist_ok=True, parents=True)
self.values_file = self.profile_dir / "values.json"
@property
def app_privkey(self):
key_file = self.profile_dir / 'app_privkey.pem'
if key_file.is_file():
with key_file.open('rb') as f:
key_bytes = f.read()
return RSAPrivateKey.from_pem(key_bytes)
else:
key = RSAPrivateKey.generate()
with key_file.open('wb') as f:
f.write(key.to_pem())
return key
@property
def serv_pubkey(self):
key_file = self.profile_dir / 'serv_pubkey.pem'
if key_file.is_file():
with key_file.open('rb') as f:
key_bytes = f.read()
return RSAPublicKey.from_pem(key_bytes)
else:
return None
@serv_pubkey.setter
def serv_pubkey(self, key_b64):
key = RSAPublicKey.from_b64(key_b64)
key_file = self.profile_dir / 'serv_pubkey.pem'
with key_file.open('wb') as f:
f.write(key.to_pem())
def __getitem__(self, key):
if self.values_file.is_file():
with self.values_file.open() as f:
values = json.load(f)
if key in values:
return values[key]
return None
def __setitem__(self, key, value):
if self.values_file.is_file():
with self.values_file.open() as f:
values = json.load(f)
else:
values = {}
values[key] = value
with self.values_file.open('w') as f:
json.dump(values, f)