Using new package pypicohsm.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos 2023-03-20 17:05:46 +01:00
parent a69d06b2d9
commit 11a30863e8
No known key found for this signature in database
GPG key ID: C0095B7870A4CCD3
21 changed files with 104 additions and 857 deletions

View file

@ -19,622 +19,15 @@
import sys import sys
import pytest import pytest
import os
from binascii import hexlify
from utils import APDUResponse, DOPrefixes, KeyType, Algorithm, Padding, int_to_bytes
from const import *
import hashlib
try: try:
from cvc.asn1 import ASN1 from picohsm import PicoHSM
from cvc import oid
from cvc.certificates import CVC
from cvc.ec_curves import ec_domain, find_curve
except ModuleNotFoundError: except ModuleNotFoundError:
print('ERROR: cvc module not found! Install pycvc package.\nTry with `pip install pycvc`') print('ERROR: picohsm module not found! Install picohsm package.\nTry with `pip install picohsm`')
sys.exit(-1) sys.exit(-1)
try:
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
except ModuleNotFoundError:
print('ERROR: smarctard module not found! Install pyscard package.\nTry with `pip install pyscard`')
sys.exit(-1)
try:
from cryptography.hazmat.primitives.asymmetric import ec, rsa, utils, padding
from cryptography.hazmat.primitives import hashes, cmac
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
except ModuleNotFoundError:
print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`')
sys.exit(-1)
class Device:
class EcDummy:
def __init__(self, name):
self.name = name
def __init__(self,pin='648219'):
self.__pin = pin
cardtype = AnyCardType()
try:
# request card insertion
cardrequest = CardRequest(timeout=10, cardType=cardtype)
self.__card = cardrequest.waitforcard()
# connect to the card and perform a few transmits
self.__card.connection.connect()
except CardRequestTimeoutException:
raise Exception('time-out: no card inserted during last 10s')
self.select_applet()
data = self.get_contents(p1=0x2f02)
self.device_id = CVC().decode(data).chr()
def select_applet(self):
self.__card.connection.transmit([0x00, 0xA4, 0x04, 0x00, 0xB, 0xE8, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xC3, 0x1F, 0x02, 0x01, 0x0])
def send(self, command, cla=0x00, p1=0x00, p2=0x00, ne=None, data=None, codes=[]):
lc = []
dataf = []
if (data):
lc = [0x00] + list(len(data).to_bytes(2, 'big'))
dataf = list(data)
else:
lc = [0x00*3]
if (ne is None):
le = [0x00, 0x00]
else:
le = list(ne.to_bytes(2, 'big'))
if (isinstance(command, list) and len(command) > 1):
apdu = command
else:
apdu = [cla, command]
apdu = apdu + [p1, p2] + lc + dataf + le
try:
response, sw1, sw2 = self.__card.connection.transmit(apdu)
except CardConnectionException:
self.__card.connection.reconnect()
response, sw1, sw2 = self.__card.connection.transmit(apdu)
code = (sw1<<8|sw2)
if (sw1 != 0x90):
if (sw1 == 0x63 and sw2 & 0xF0 == 0xC0):
pass
# elif (code == 0x6A82):
# self.select_applet()
# if (sw1 == 0x90):
# response, sw1, sw2 = self.__card.connection.transmit(apdu)
# if (sw1 == 0x90):
# return response
elif (code == 0x6982):
response, sw1, sw2 = self.__card.connection.transmit([0x00, 0x20, 0x00, 0x81, len(self.__pin)] + list(self.__pin.encode()) + [0x0])
if (sw1 == 0x90):
response, sw1, sw2 = self.__card.connection.transmit(apdu)
if (sw1 == 0x90):
return response
if (code not in codes):
raise APDUResponse(sw1, sw2)
if (len(codes) > 1):
return response, code
return response
def get_login_retries(self):
self.select_applet()
try:
self.send(command=0x20, p2=0x81)
except APDUResponse as e:
if (e.sw1 == 0x63 and e.sw2 & 0xF0 == 0xC0):
return e.sw2 & 0x0F
raise e
def is_logged(self):
try:
self.send(command=0x20, p2=0x81)
return True
except APDUResponse:
pass
return False
def logout(self):
self.select_applet()
def initialize(self, pin=DEFAULT_PIN, sopin=DEFAULT_SOPIN, options=None, retries=DEFAULT_RETRIES, dkek_shares=None, puk_auts=None, puk_min_auts=None, key_domains=None):
if (retries is not None and not 0 < retries <= 10):
raise ValueError('Retries must be in the range (0,10]')
if (dkek_shares is not None and not 0 <= dkek_shares <= 10):
raise ValueError('DKEK shares must be in the range [0,10]')
if ((puk_auts is not None and puk_min_auts is None) or (puk_auts is None and puk_min_auts is not None)):
raise ValueError('PUK Auts and PUK Min Auts must be specified both')
if (puk_auts is not None and not 0 < puk_auts <= 8):
raise ValueError('PUK Auts must be in the range (0,8]')
if (puk_min_auts is not None and not 0 < puk_min_auts <= 8):
raise ValueError('PUK Min Auts must be in the range (0,8]')
if (puk_auts is not None and puk_min_auts is not None and puk_min_auts > puk_auts):
raise ValueError('PUK Min Auts must be less or equal to PUK Auts')
if (key_domains is not None and not 0 < key_domains <= 8):
raise ValueError('Key Domains must be in the range (0,8]')
a = ASN1()
if (pin is not None):
a = a.add_tag(0x81, pin.encode())
if (sopin is not None):
a = a.add_tag(0x82, sopin.encode())
if (retries is not None):
a = a.add_tag(0x91, bytes([retries]))
if (dkek_shares is not None):
a = a.add_tag(0x92, bytes([dkek_shares]))
if (puk_auts is not None and puk_min_auts is not None):
a = a.add_tag(0x93, bytes([puk_auts, puk_min_auts]))
if (key_domains is not None):
a = a.add_tag(0x97, bytes([key_domains]))
data = a.encode()
self.send(cla=0x80, command=0x50, data=data)
def login(self, pin=None):
if (pin is None):
pin = self.__pin
self.send(command=0x20, p2=0x81, data=pin.encode())
def get_first_free_id(self):
kids = self.list_keys(prefix=DOPrefixes.KEY_PREFIX)
mset = set(range(max(kids)))-set(kids)
if (len(mset) > 0):
return min(mset)
if (max(kids) == 255):
raise ValueError('Max number of key id reached')
return max(kids)+1
def list_keys(self, prefix=None):
resp = self.send(command=0x58)
if (prefix is not None):
grouped = [(resp[i],resp[i+1]) for i in range(0, len(resp), 2) if resp[i] == prefix.value]
_, kids = zip(*grouped)
return kids
return [(resp[i],resp[i+1]) for i in range(0, len(resp), 2)]
def key_generation(self, type, param, use_counter=None, algorithms=None, key_domain=None):
meta_data = b''
if (use_counter is not None):
meta_data += b'\x90\x04' + use_counter.to_bytes(4, 'big')
if (algorithms is not None):
meta_data += b'\x91' + bytes([len(algorithms)] + algorithms)
if (key_domain is not None):
meta_data += b'\x92\x01' + bytes([key_domain])
if (type in [KeyType.RSA, KeyType.ECC]):
a = ASN1().add_tag(0x5f29, bytes([0])).add_tag(0x42, 'UTCA00001'.encode())
if (type == KeyType.RSA):
if (not 1024 <= param <= 4096):
raise ValueError('RSA bits must be in the range [1024,4096]')
a.add_tag(0x7f49, ASN1().add_oid(oid.ID_TA_RSA_V1_5_SHA_256).add_tag(0x2, param.to_bytes(2, 'big')).encode())
elif (type == KeyType.ECC):
if (param not in ('secp192r1', 'secp256r1', 'secp384r1', 'secp521r1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp192k1', 'secp256k1')):
raise ValueError('Bad elliptic curve name')
dom = ec_domain(Device.EcDummy(param))
pubctx = {1: dom.P, 2: dom.A, 3: dom.B, 4: dom.G, 5: dom.O, 7: dom.F}
a.add_object(0x7f49, oid.ID_TA_ECDSA_SHA_256, pubctx)
a.add_tag(0x5f20, 'UTCDUMMY00001'.encode())
data = a.encode()
keyid = self.get_first_free_id()
self.send(command=0x46, p1=keyid, data=list(data + meta_data))
elif (type == KeyType.AES):
if (param == 128):
p2 = 0xB0
elif (param == 192):
p2 = 0xB1
elif (param == 256):
p2 = 0xB2
else:
raise ValueError('Bad AES key size')
keyid = self.get_first_free_id()
self.send(command=0x48, p1=keyid, p2=p2)
else:
raise ValueError('Bad KeyType')
return keyid
def delete_file(self, p1, p2=None):
if (p2):
self.send(command=0xE4, data=[p1, p2])
else:
resp = self.delete_file(p1=p1 >> 8, p2=p1 & 0xff)
def get_contents(self, p1, p2=None):
if (p2):
resp = self.send(command=0xB1, p1=p1, p2=p2, data=[0x54, 0x02, 0x00, 0x00])
else:
resp = self.get_contents(p1=p1 >> 8, p2=p1 & 0xff)
return bytes(resp)
def put_contents(self, p1, p2=None, data=None):
if (p2):
self.send(command=0xD7, p1=p1, p2=p2, data=[0x54, 0x02, 0x00, 0x00, 0x53, len(data) if data else 0] + list(data) if data else [])
else:
self.put_contents(p1=p1 >> 8, p2=p1 & 0xff, data=data)
def public_key(self, keyid, param=None):
response = self.get_contents(p1=DOPrefixes.EE_CERTIFICATE_PREFIX.value, p2=keyid)
cert = bytearray(response)
roid = CVC().decode(cert).pubkey().oid()
if (roid == oid.ID_TA_ECDSA_SHA_256):
curve = find_curve(ec_domain(Device.EcDummy(param)).P)
Y = bytes(CVC().decode(cert).pubkey().find(0x86).data())
return ec.EllipticCurvePublicKey.from_encoded_point(
curve,
Y,
)
elif (roid == oid.ID_TA_RSA_V1_5_SHA_256):
n = int.from_bytes(bytes(CVC().decode(cert).pubkey().find(0x81).data()), 'big')
e = int.from_bytes(bytes(CVC().decode(cert).pubkey().find(0x82).data()), 'big')
return rsa.RSAPublicNumbers(e, n).public_key()
return None
def sign(self, keyid, scheme, data):
resp = self.send(cla=0x80, command=0x68, p1=keyid, p2=scheme.value, data=data)
return resp
def verify(self, pubkey, data, signature, scheme):
if (Algorithm.ALGO_EC_RAW.value <= scheme.value <= Algorithm.ALGO_EC_SHA512.value):
if (scheme == Algorithm.ALGO_EC_SHA1):
hsh = hashes.SHA1()
elif (scheme == Algorithm.ALGO_EC_SHA224):
hsh = hashes.SHA224()
elif (scheme == Algorithm.ALGO_EC_SHA256):
hsh = hashes.SHA256()
elif (scheme == Algorithm.ALGO_EC_RAW):
hsh = utils.Prehashed(hashes.SHA512())
elif (scheme == Algorithm.ALGO_EC_SHA384):
hsh = hashes.SHA384()
elif (scheme == Algorithm.ALGO_EC_SHA512):
hsh = hashes.SHA512()
return pubkey.verify(signature, data, ec.ECDSA(hsh))
elif (Algorithm.ALGO_RSA_PKCS1_SHA1.value <= scheme.value <= Algorithm.ALGO_RSA_PSS_SHA512.value):
if (scheme == Algorithm.ALGO_RSA_PKCS1_SHA1 or scheme == Algorithm.ALGO_RSA_PSS_SHA1):
hsh = hashes.SHA1()
elif (scheme == Algorithm.ALGO_RSA_PKCS1_SHA224 or scheme == Algorithm.ALGO_RSA_PSS_SHA224):
hsh = hashes.SHA224()
elif (scheme == Algorithm.ALGO_RSA_PKCS1_SHA256 or scheme == Algorithm.ALGO_RSA_PSS_SHA256):
hsh = hashes.SHA256()
elif (scheme == Algorithm.ALGO_RSA_PKCS1_SHA384 or scheme == Algorithm.ALGO_RSA_PSS_SHA384):
hsh = hashes.SHA384()
elif (scheme == Algorithm.ALGO_RSA_PKCS1_SHA512 or scheme == Algorithm.ALGO_RSA_PSS_SHA512):
hsh = hashes.SHA512()
if (Algorithm.ALGO_RSA_PKCS1_SHA1.value <= scheme.value <= Algorithm.ALGO_RSA_PKCS1_SHA512.value):
padd = padding.PKCS1v15()
elif (Algorithm.ALGO_RSA_PSS_SHA1.value <= scheme.value <= Algorithm.ALGO_RSA_PSS_SHA512.value):
padd = padding.PSS(
mgf=padding.MGF1(hsh),
salt_length=padding.PSS.AUTO
)
return pubkey.verify(signature, data, padd, hsh)
def decrypt(self, keyid, data, pad):
if (isinstance(pad, padding.OAEP)):
p2 = Padding.OAEP.value
elif (isinstance(pad, padding.PKCS1v15)):
p2 = Padding.PKCS.value
else:
p2 = Padding.RAW.value
resp = self.send(command=0x62, p1=keyid, p2=p2, data=list(data))
return bytes(resp)
def import_dkek(self, dkek, key_domain=0):
resp = self.send(cla=0x80, command=0x52, p1=0x0, p2=key_domain, data=dkek)
return resp
def import_key(self, pkey, dkek=None, purposes=None):
data = b''
kcv = hashlib.sha256(dkek or b'\x00'*32).digest()[:8]
kenc = hashlib.sha256((dkek or b'\x00'*32) + b'\x00\x00\x00\x01').digest()
kmac = hashlib.sha256((dkek or b'\x00'*32) + b'\x00\x00\x00\x02').digest()
data += kcv
if (isinstance(pkey, rsa.RSAPrivateKey)):
data += b'\x05'
algo = b'\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02'
elif (isinstance(pkey, ec.EllipticCurvePrivateKey)):
data += b'\x0C'
algo = b'\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03'
elif (isinstance(pkey, bytes)):
data += b'\x0F'
algo = b'\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01'
data += algo
if (not purposes and isinstance(pkey, bytes)):
purposes = [Algorithm.ALGO_AES_CBC_ENCRYPT.value, Algorithm.ALGO_AES_CBC_DECRYPT.value, Algorithm.ALGO_AES_CMAC.value, Algorithm.ALGO_AES_DERIVE.value, Algorithm.ALGO_EXT_CIPHER_ENCRYPT.value, Algorithm.ALGO_EXT_CIPHER_DECRYPT.value]
if (purposes):
data += b'\x00' + bytes([len(purposes)]) + bytes(purposes) + b'\x00'*4
else:
data += b'\x00'*6
kb = os.urandom(8)
if (isinstance(pkey, rsa.RSAPrivateKey)):
kb += int_to_bytes(pkey.key_size, length=2)
pubnum = pkey.public_key().public_numbers()
pnum = pkey.private_numbers()
kb += int_to_bytes((pnum.d.bit_length()+7)//8, length=2)
kb += int_to_bytes(pnum.d)
kb += int_to_bytes((pubnum.n.bit_length()+7)//8, length=2)
kb += int_to_bytes(pubnum.n)
kb += int_to_bytes((pubnum.e.bit_length()+7)//8, length=2)
kb += int_to_bytes(pubnum.e)
elif (isinstance(pkey, ec.EllipticCurvePrivateKey)):
curve = ec_domain(pkey.curve)
kb += int_to_bytes(len(curve.P)*8, length=2)
kb += int_to_bytes(len(curve.A), length=2)
kb += curve.A
kb += int_to_bytes(len(curve.B), length=2)
kb += curve.B
kb += int_to_bytes(len(curve.P), length=2)
kb += curve.P
kb += int_to_bytes(len(curve.O), length=2)
kb += curve.O
kb += int_to_bytes(len(curve.G), length=2)
kb += curve.G
kb += int_to_bytes((pkey.private_numbers().private_value.bit_length()+7)//8, length=2)
kb += int_to_bytes(pkey.private_numbers().private_value)
p = pkey.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)
kb += int_to_bytes(len(p), length=2)
kb += p
elif (isinstance(pkey, bytes)):
kb += int_to_bytes(len(pkey), length=2)
kb += pkey
kb_len_pad = (len(kb)//16)*16
if (len(kb) % 16 > 0):
kb_len_pad = (len(kb)//16 + 1)*16
if (len(kb) < kb_len_pad):
kb += b'\x80'
kb += b'\x00' * (kb_len_pad-len(kb))
cipher = Cipher(algorithms.AES(kenc), modes.CBC(b'\x00'*16))
encryptor = cipher.encryptor()
ct = encryptor.update(kb) + encryptor.finalize()
data += ct
c = cmac.CMAC(algorithms.AES(kmac))
c.update(data)
data += c.finalize()
p1 = self.get_first_free_id()
_ = self.send(cla=0x80, command=0x74, p1=p1, p2=0x93, data=data)
return p1
def export_key(self, keyid):
resp = self.send(cla=0x80, command=0x72, p1=keyid, p2=0x92)
return resp
def exchange(self, keyid, pubkey):
resp = self.send(cla=0x80, command=0x62, p1=keyid, p2=Algorithm.ALGO_EC_ECDH.value, data=pubkey.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint))
return resp[1:]
def parse_cvc(self, data):
car = CVC().decode(data).car()
chr = CVC().decode(data).chr()
return {'car': car, 'chr': chr}
def get_termca(self):
resp = self.get_contents(EF_TERMCA)
cv_data = self.parse_cvc(resp)
a = ASN1().decode(resp).find(0x7f21).data()
tlen = len(ASN1.calculate_len(len(a)))
ret = {'cv': cv_data}
if (len(a)+2+tlen < len(resp)): # There's more certificate
resp = resp[2+len(a)+tlen:]
dv_data = self.parse_cvc(resp)
ret['dv'] = dv_data
return ret
def get_version(self):
resp = self.send(cla=0x80, command=0x50)
return resp[5]+0.1*resp[6]
def get_key_domain(self, key_domain=0):
resp, code = self.send(cla=0x80, command=0x52, p2=key_domain, codes=[0x9000, 0x6A88, 0x6A86])
if (code == 0x9000):
ret = {
'dkek': {
'total': resp[0],
'missing': resp[1]
},
'kcv': resp[2:10]
}
if (len(resp) > 10):
ret.update({'xkek': resp[10:]})
return ret
return {'error': code}
def get_key_domains(self):
for k in range(0xFF):
_, code = self.send(cla=0x80, command=0x52, p2=k, codes=[0x9000, 0x6A88, 0x6A86])
if (code == 0x6A86):
return k
return 0
def set_key_domain(self, key_domain=0, total=DEFAULT_DKEK_SHARES):
resp = self.send(cla=0x80, command=0x52, p1=0x1, p2=key_domain, data=[total])
return resp
def clear_key_domain(self, key_domain=0):
resp = self.send(cla=0x80, command=0x52, p1=0x4, p2=key_domain)
return resp
def delete_key_domain(self, key_domain=0):
self.send(cla=0x80, command=0x52, p1=0x3, p2=key_domain, codes=[0x6A88])
def get_challenge(self, length):
return self.send(cla=0x80, command=0x84, ne=length)
def cipher(self, algo, keyid, data):
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=algo.value, data=data)
return resp
def hmac(self, hash, keyid, data):
if (hash == hashes.SHA1):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x07'
elif (hash == hashes.SHA224):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x08'
elif (hash == hashes.SHA256):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x09'
elif (hash == hashes.SHA384):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0A'
elif (hash == hashes.SHA512):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0B'
else:
raise ValueError("Hash not supported")
data = [0x06, len(algo)] + list(algo) + [0x81, len(data)] + list(data)
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data)
return resp
def cmac(self, keyid, data):
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=Algorithm.ALGO_AES_CMAC.value, data=data)
return resp
def hkdf(self, hash, keyid, data, salt, out_len=None):
if (hash == hashes.SHA256):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1D'
elif (hash == hashes.SHA384):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1E'
elif (hash == hashes.SHA512):
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1F'
data = [0x06, len(algo)] + list(algo) + [0x81, len(data)] + list(data) + [0x82, len(salt)] + list(salt)
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
return resp
def pbkdf2(self, hash, keyid, salt, iterations, out_len=None):
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C'
salt = b'\x04' + bytes([len(salt)]) + salt
iteration = b'\x02' + bytes([len(int_to_bytes(iterations))]) + int_to_bytes(iterations)
prf = b'\x30\x0A\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02'
if (hash == hashes.SHA1):
prf += b'\x07'
elif (hash == hashes.SHA224):
prf += b'\x08'
elif (hash == hashes.SHA256):
prf += b'\x09'
elif (hash == hashes.SHA384):
prf += b'\x0A'
elif (hash == hashes.SHA512):
prf += b'\x0B'
data = list(salt + iteration + prf)
data = [0x06, len(oid)] + list(oid) + [0x81, len(data)] + list(data)
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
return resp
def x963(self, hash, keyid, data, out_len=None):
oid = b'\x2B\x81\x05\x10\x86\x48\x3F'
enc = b'\x2A\x86\x48\x86\xF7\x0D\x02'
if (hash == hashes.SHA1):
enc += b'\x07'
elif (hash == hashes.SHA224):
enc += b'\x08'
elif (hash == hashes.SHA256):
enc += b'\x09'
elif (hash == hashes.SHA384):
enc += b'\x0A'
elif (hash == hashes.SHA512):
enc += b'\x0B'
else:
raise ValueError("Hash not supported")
data = [0x06, len(oid)] + list(oid) + [0x81, len(enc)] + list(enc) + [0x83, len(data)] + list(data)
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
return resp
def verify_certificate(self, cert):
chr = CVC().decode(cert).chr()
pukref = ASN1().add_tag(0x83, chr).encode()
_, code = self.send(command=0x22, p1=0x81, p2=0xB6, data=pukref, codes=[0x9000, 0x6A88])
if (code == 0x9000):
return
car = CVC().decode(cert).car()
pukref = ASN1().add_tag(0x83, car).encode()
self.send(command=0x22, p1=0x81, p2=0xB6, data=pukref)
data = ASN1().decode(cert).find(0x7F21).data()
self.send(command=0x2A, p2=0xBE, data=data)
def register_puk(self, puk, devcert, dicacert, replace=0):
self.verify_certificate(devcert)
self.verify_certificate(dicacert)
car = CVC().decode(puk).outer_car()
pukref = ASN1().add_tag(0x83, car).encode()
self.send(command=0x22, p1=0x81, p2=0xB6, data=pukref)
data = ASN1().decode(puk).find(0x67).data()
p1,p2 = 0,0
if (replace > 0):
p1 = 0x1
p2 = replace
status = self.send(cla=0x80, command=0x54, p1=p1, p2=p2, data=data)
return status
def get_puk_status(self):
status = self.send(cla=0x80, command=0x54)
return status
def enumerate_puk(self):
puk_no = self.get_puk_status()[0]
puks = []
for i in range(puk_no):
bin, code = self.send(cla=0x80, command=0x54, p1=0x02, p2=i, codes=[0x9000, 0x9001, 0x6A88])
if (code == 0x6A88):
puks.append({'status': -1})
else:
puks.append({'status': code & 0x1, 'chr': bin})
return puks
def is_puk(self):
_, code = self.send(cla=0x80, command=0x54, p1=0x02, codes=[0x9000, 0x9001, 0x6A88, 0x6A86])
return code != 0x6A86
def check_puk_key(self, chr):
pukref = ASN1().add_tag(0x83, chr).encode()
_, code = self.send(command=0x22, p1=0x81, p2=0xA4, data=pukref, codes=[0x9000, 0x6A88, 0x6985])
if (code == 0x9000):
return 0
elif (code == 0x6985):
return 1
return -1
def puk_prepare_signature(self):
challenge = self.send(command=0x84, ne=8)
input = self.device_id + bytes(challenge)
return input
def authenticate_puk(self, chr, signature):
pukref = ASN1().add_tag(0x83, chr).encode()
self.send(command=0x22, p1=0x81, p2=0xA4, data=pukref)
self.send(command=0x82, data=signature)
def create_xkek(self, kdm):
dicacert = ASN1().decode(kdm).find(0x30).find(0x61).data()
devcert = ASN1().decode(kdm).find(0x30).find(0x62).data()
gskcert = ASN1().decode(kdm).find(0x30).find(0x63).data()
gsksign = ASN1().decode(kdm).find(0x30).find(0x54).data(return_tag=True)
gskdata = CVC().decode(gskcert).req().data()
self.verify_certificate(devcert)
self.verify_certificate(dicacert)
status = self.send(cla=0x80, command=0x52, p1=0x02, data=gskdata + gsksign)
return status[2:10], status[10:]
def generate_xkek_key(self, key_domain=0):
key_id = self.key_generation(KeyType.ECC, 'brainpoolP256r1', algorithms=[Algorithm.ALGO_EC_ECDH_XKEK.value], key_domain=key_domain)
return key_id
def derive_xkek(self, keyid, cert):
self.send(cla=0x80, command=0x62, p1=keyid, p2=Algorithm.ALGO_EC_ECDH_XKEK.value, data=cert)
def delete_xkek(self, key_domain=0):
self.send(cla=0x80, command=0x52, p1=0x04, p2=key_domain)
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def device(): def device():
dev = Device() dev = PicoHSM()
return dev return dev

View file

@ -19,13 +19,7 @@
from binascii import unhexlify from binascii import unhexlify
DEFAULT_PIN = '648219'
DEFAULT_SOPIN = '57621880'
DEFAULT_RETRIES = 3
DEFAULT_DKEK = [0x1] * 32 DEFAULT_DKEK = [0x1] * 32
DEFAULT_DKEK_SHARES = 2
EF_TERMCA = 0x2f02
TERM_CERT = unhexlify('7F2181E57F4E819E5F290100421045535049434F48534D445630303030317F494F060A04007F00070202020203864104F571E53AA8E75C929D925081CF0F893CB5991D48BD546C1A3F22199F037E4B12D601ACD91C67C88D3C5B3D04C08EC0A372485F7A248E080EE0C6237C1B075E1C5F201045535049434F48534D54525A474E50327F4C0E060904007F0007030102025301005F25060203000300055F24060204000300045F374041BF5E970739135770DBCC5DDA81FFD8B13419A9257D44CAF8404267C644E8F435B43F5E57EB2A8CF4B198045ACD094E0CB34E6217D9C8922CFB9BBEFD4088AD') TERM_CERT = unhexlify('7F2181E57F4E819E5F290100421045535049434F48534D445630303030317F494F060A04007F00070202020203864104F571E53AA8E75C929D925081CF0F893CB5991D48BD546C1A3F22199F037E4B12D601ACD91C67C88D3C5B3D04C08EC0A372485F7A248E080EE0C6237C1B075E1C5F201045535049434F48534D54525A474E50327F4C0E060904007F0007030102025301005F25060203000300055F24060204000300045F374041BF5E970739135770DBCC5DDA81FFD8B13419A9257D44CAF8404267C644E8F435B43F5E57EB2A8CF4B198045ACD094E0CB34E6217D9C8922CFB9BBEFD4088AD')
DICA_CERT = unhexlify('7F2181E97F4E81A25F290100421045535049434F48534D434130303030317F494F060A04007F0007020202020386410421EE4A21C16A10F737F12E78E5091B266612038CDABEBB722B15BF6D41B877FBF64D9AB69C39B9831B1AE00BEF2A4E81976F7688D45189BB232A24703D8A96A55F201045535049434F48534D445630303030317F4C12060904007F000703010202530580000000005F25060202000801085F24060203000601045F37403F75C08FFFC9186B56E6147199E82BFC327CEEF72495BC567961CD54D702F13E3C2766FCD1D11BD6A9D1F4A229B76B248CEB9AF88D59A74D0AB149448705159B') DICA_CERT = unhexlify('7F2181E97F4E81A25F290100421045535049434F48534D434130303030317F494F060A04007F0007020202020386410421EE4A21C16A10F737F12E78E5091B266612038CDABEBB722B15BF6D41B877FBF64D9AB69C39B9831B1AE00BEF2A4E81976F7688D45189BB232A24703D8A96A55F201045535049434F48534D445630303030317F4C12060904007F000703010202530580000000005F25060202000801085F24060203000601045F37403F75C08FFFC9186B56E6147199E82BFC327CEEF72495BC567961CD54D702F13E3C2766FCD1D11BD6A9D1F4A229B76B248CEB9AF88D59A74D0AB149448705159B')

View file

@ -18,7 +18,6 @@
""" """
import pytest import pytest
from const import EF_TERMCA
def test_select(device): def test_select(device):
device.select_applet() device.select_applet()

View file

@ -19,8 +19,9 @@
import pytest import pytest
import hashlib import hashlib
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from const import DEFAULT_DKEK
from utils import SWCodes, APDUResponse from picohsm import APDUResponse, SWCodes
from picohsm.const import DEFAULT_DKEK_SHARES
KEY_DOMAINS = 3 KEY_DOMAINS = 3
TEST_KEY_DOMAIN = 1 TEST_KEY_DOMAIN = 1
@ -40,17 +41,17 @@ def test_key_domains(device):
def test_import_dkek_wrong_key_domain(device): def test_import_dkek_wrong_key_domain(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.import_dkek(DEFAULT_DKEK, key_domain=0) device.import_dkek(DEFAULT_DKEK, key_domain=0)
assert(e.value.sw == SWCodes.SW_COMMAND_NOT_ALLOWED.value) assert(e.value.sw == SWCodes.SW_COMMAND_NOT_ALLOWED)
def test_import_dkek_fail(device): def test_import_dkek_fail(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.import_dkek(DEFAULT_DKEK, key_domain=TEST_KEY_DOMAIN) device.import_dkek(DEFAULT_DKEK, key_domain=TEST_KEY_DOMAIN)
assert(e.value.sw == SWCodes.SW_COMMAND_NOT_ALLOWED.value) assert(e.value.sw == SWCodes.SW_COMMAND_NOT_ALLOWED)
def test_set_key_domain_fail(device): def test_set_key_domain_fail(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.set_key_domain(key_domain=10) device.set_key_domain(key_domain=10)
assert(e.value.sw == SWCodes.SW_INCORRECT_P1P2.value) assert(e.value.sw == SWCodes.SW_INCORRECT_P1P2)
def test_set_key_domain_ok(device): def test_set_key_domain_ok(device):
kd = device.get_key_domain(key_domain=TEST_KEY_DOMAIN) kd = device.get_key_domain(key_domain=TEST_KEY_DOMAIN)
@ -80,7 +81,7 @@ def test_import_dkek_ok(device):
def test_clear_key_domain(device): def test_clear_key_domain(device):
kd = device.get_key_domain(key_domain=0) kd = device.get_key_domain(key_domain=0)
assert('error' in kd) assert('error' in kd)
assert(kd['error'] == SWCodes.SW_REFERENCE_NOT_FOUND.value) assert(kd['error'] == SWCodes.SW_REFERENCE_NOT_FOUND)
kd = device.get_key_domain(key_domain=TEST_KEY_DOMAIN) kd = device.get_key_domain(key_domain=TEST_KEY_DOMAIN)
assert(kd['dkek']['total'] == DEFAULT_DKEK_SHARES) assert(kd['dkek']['total'] == DEFAULT_DKEK_SHARES)
@ -95,7 +96,7 @@ def test_delete_key_domain(device):
assert(kd['dkek']['total'] == DEFAULT_DKEK_SHARES) assert(kd['dkek']['total'] == DEFAULT_DKEK_SHARES)
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.delete_key_domain(key_domain=0) device.delete_key_domain(key_domain=0)
assert(e.value.sw == SWCodes.SW_INCORRECT_P1P2.value) assert(e.value.sw == SWCodes.SW_INCORRECT_P1P2)
def test_delete_key_domain(device): def test_delete_key_domain(device):
assert(device.get_key_domains() == KEY_DOMAINS) assert(device.get_key_domains() == KEY_DOMAINS)

View file

@ -19,8 +19,8 @@
import pytest import pytest
import hashlib import hashlib
from utils import APDUResponse, SWCodes from picohsm.const import DEFAULT_DKEK_SHARES, DEFAULT_PIN, DEFAULT_RETRIES
from const import DEFAULT_PIN, DEFAULT_RETRIES, DEFAULT_DKEK, DEFAULT_DKEK_SHARES from const import DEFAULT_DKEK
def test_dkek(device): def test_dkek(device):
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES) device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)

View file

@ -18,36 +18,35 @@
""" """
import pytest import pytest
from utils import APDUResponse, SWCodes from picohsm import APDUResponse, SWCodes
from const import DEFAULT_PIN, DEFAULT_RETRIES from picohsm.const import DEFAULT_PIN, DEFAULT_RETRIES
WRONG_PIN = '112233' WRONG_PIN = '112233'
RETRIES = DEFAULT_RETRIES
def test_pin_init_retries(device): def test_pin_init_retries(device):
device.initialize(retries=RETRIES) device.initialize(retries=DEFAULT_RETRIES)
retries = device.get_login_retries() retries = device.get_login_retries()
assert(retries == RETRIES) assert(retries == DEFAULT_RETRIES)
def test_pin_login(device): def test_pin_login(device):
device.initialize(retries=RETRIES) device.initialize(retries=DEFAULT_RETRIES)
device.login(DEFAULT_PIN) device.login(DEFAULT_PIN)
def test_pin_retries(device): def test_pin_retries(device):
device.initialize(retries=RETRIES) device.initialize(retries=DEFAULT_RETRIES)
device.login(DEFAULT_PIN) device.login(DEFAULT_PIN)
for ret in range(RETRIES-1): for ret in range(DEFAULT_RETRIES-1):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.login(WRONG_PIN) device.login(WRONG_PIN)
assert(e.value.sw1 == 0x63 and e.value.sw2 == (0xC0 | (RETRIES-1-ret))) assert(e.value.sw1 == 0x63 and e.value.sw2 == (0xC0 | (DEFAULT_RETRIES-1-ret)))
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.login(WRONG_PIN) device.login(WRONG_PIN)
assert(e.value.sw == SWCodes.SW_PIN_BLOCKED.value) assert(e.value.sw == SWCodes.SW_PIN_BLOCKED)
device.initialize(retries=RETRIES) device.initialize(retries=DEFAULT_RETRIES)
retries = device.get_login_retries() retries = device.get_login_retries()
assert(retries == RETRIES) assert(retries == DEFAULT_RETRIES)

View file

@ -18,7 +18,7 @@
""" """
import pytest import pytest
from utils import KeyType, DOPrefixes from picohsm import KeyType, DOPrefixes
def test_gen_initialize(device): def test_gen_initialize(device):
device.initialize() device.initialize()
@ -29,11 +29,11 @@ def test_gen_initialize(device):
def test_gen_ecc(device, curve): def test_gen_ecc(device, curve):
keyid = device.key_generation(KeyType.ECC, curve) keyid = device.key_generation(KeyType.ECC, curve)
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid) in resp) assert((DOPrefixes.KEY_PREFIX, keyid) in resp)
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid) not in resp) assert((DOPrefixes.KEY_PREFIX, keyid) not in resp)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"modulus", [1024, 2048, 4096] "modulus", [1024, 2048, 4096]
@ -41,7 +41,7 @@ def test_gen_ecc(device, curve):
def test_gen_rsa(device, modulus): def test_gen_rsa(device, modulus):
keyid = device.key_generation(KeyType.RSA, modulus) keyid = device.key_generation(KeyType.RSA, modulus)
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid) in resp) assert((DOPrefixes.KEY_PREFIX, keyid) in resp)
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)

View file

@ -20,9 +20,10 @@
import pytest import pytest
import hashlib import hashlib
import os import os
from utils import KeyType, DOPrefixes from picohsm import DOPrefixes
from cryptography.hazmat.primitives.asymmetric import rsa, ec from cryptography.hazmat.primitives.asymmetric import rsa, ec
from const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
from const import DEFAULT_DKEK
def test_prepare_dkek(device): def test_prepare_dkek(device):
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES) device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
@ -42,8 +43,8 @@ def test_import_rsa(device, modulus):
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
pubkey = device.public_key(keyid) pubkey = device.public_key(keyid)
assert(pubkey.public_numbers() == pkey.public_key().public_numbers()) assert(pubkey.public_numbers() == pkey.public_key().public_numbers())
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -54,8 +55,8 @@ def test_import_ecc(device, curve):
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
pubkey = device.public_key(keyid, param=curve().name) pubkey = device.public_key(keyid, param=curve().name)
assert(pubkey.public_numbers() == pkey.public_key().public_numbers()) assert(pubkey.public_numbers() == pkey.public_key().public_numbers())
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"size", [128, 192, 256] "size", [128, 192, 256]

View file

@ -19,9 +19,10 @@
import pytest import pytest
import hashlib import hashlib
from utils import KeyType, DOPrefixes from picohsm import DOPrefixes
from cryptography.hazmat.primitives.asymmetric import rsa, ec from cryptography.hazmat.primitives.asymmetric import ec
from const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
from const import DEFAULT_DKEK
def test_prepare_dkek(device): def test_prepare_dkek(device):
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES) device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
@ -48,5 +49,5 @@ def test_exchange_ecc(device, curve):
sharedAA = pkeyA.exchange(ec.ECDH(), pbkeyB) sharedAA = pkeyA.exchange(ec.ECDH(), pbkeyB)
assert(bytes(sharedA) == sharedAA) assert(bytes(sharedA) == sharedAA)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)

View file

@ -18,7 +18,7 @@
""" """
import pytest import pytest
from utils import KeyType, DOPrefixes from picohsm import KeyType, DOPrefixes
@pytest.mark.parametrize( @pytest.mark.parametrize(
"size", [128, 192, 256] "size", [128, 192, 256]
@ -26,5 +26,5 @@ from utils import KeyType, DOPrefixes
def test_gen_aes(device, size): def test_gen_aes(device, size):
keyid = device.key_generation(KeyType.AES, size) keyid = device.key_generation(KeyType.AES, size)
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid) in resp) assert((DOPrefixes.KEY_PREFIX, keyid) in resp)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)

View file

@ -18,7 +18,7 @@
""" """
import pytest import pytest
from utils import KeyType, DOPrefixes, APDUResponse, SWCodes from picohsm import KeyType, DOPrefixes, APDUResponse, SWCodes
from binascii import hexlify from binascii import hexlify
import hashlib import hashlib
from const import DEFAULT_DKEK from const import DEFAULT_DKEK
@ -38,28 +38,28 @@ keyid_out = -1
def test_key_generation_no_key_domain(device): def test_key_generation_no_key_domain(device):
global keyid_out global keyid_out
keyid_out = device.key_generation(KeyType.ECC, 'brainpoolP256r1') keyid_out = device.key_generation(KeyType.ECC, 'brainpoolP256r1')
device.put_contents(p1=DOPrefixes.PRKD_PREFIX.value, p2=keyid_out, data=[0xA0]) device.put_contents(p1=DOPrefixes.PRKD_PREFIX, p2=keyid_out, data=[0xA0])
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid_out) in resp) assert((DOPrefixes.KEY_PREFIX, keyid_out) in resp)
assert((DOPrefixes.PRKD_PREFIX.value, keyid_out) in resp) assert((DOPrefixes.PRKD_PREFIX, keyid_out) in resp)
def test_key_generation_with_key_domain(device): def test_key_generation_with_key_domain(device):
global keyid_in global keyid_in
keyid_in = device.key_generation(KeyType.ECC, 'brainpoolP256r1', key_domain=0) keyid_in = device.key_generation(KeyType.ECC, 'brainpoolP256r1', key_domain=0)
device.put_contents(p1=DOPrefixes.PRKD_PREFIX.value, p2=keyid_in, data=[0xA0]) device.put_contents(p1=DOPrefixes.PRKD_PREFIX, p2=keyid_in, data=[0xA0])
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid_in) in resp) assert((DOPrefixes.KEY_PREFIX, keyid_in) in resp)
assert((DOPrefixes.PRKD_PREFIX.value, keyid_in) in resp) assert((DOPrefixes.PRKD_PREFIX, keyid_in) in resp)
def test_export_key_out(device): def test_export_key_out(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.export_key(keyid_out) device.export_key(keyid_out)
assert(e.value.sw == SWCodes.SW_REFERENCE_NOT_FOUND.value) assert(e.value.sw == SWCodes.SW_REFERENCE_NOT_FOUND)
def test_export_key_in_fail(device): def test_export_key_in_fail(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.export_key(keyid_in) device.export_key(keyid_in)
assert(e.value.sw == SWCodes.SW_REFERENCE_NOT_FOUND.value) assert(e.value.sw == SWCodes.SW_REFERENCE_NOT_FOUND)
def test_export_import_dkek(device): def test_export_import_dkek(device):
resp = device.import_dkek(DEFAULT_DKEK, key_domain=0) resp = device.import_dkek(DEFAULT_DKEK, key_domain=0)
@ -79,10 +79,10 @@ def test_export_key_in_ok(device):
assert(resCMAC == resp[-16:]) assert(resCMAC == resp[-16:])
def test_delete_keys_in_out(device): def test_delete_keys_in_out(device):
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid_in) device.delete_file(DOPrefixes.KEY_PREFIX, keyid_in)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid_in) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid_in)
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid_out) device.delete_file(DOPrefixes.KEY_PREFIX, keyid_out)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid_out) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid_out)
def test_export_import(device): def test_export_import(device):
pkey_gen = ec.generate_private_key(ec.BrainpoolP256R1()) pkey_gen = ec.generate_private_key(ec.BrainpoolP256R1())
@ -133,5 +133,5 @@ def test_export_import(device):
assert(pkey_gen.private_bytes(serialization.Encoding.DER, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()) == pkey_ex.private_bytes(serialization.Encoding.DER, serialization.PrivateFormat.PKCS8, serialization.NoEncryption())) assert(pkey_gen.private_bytes(serialization.Encoding.DER, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()) == pkey_ex.private_bytes(serialization.Encoding.DER, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()))
assert(pkey_gen.public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) == pkey_ex.public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint)) assert(pkey_gen.public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) == pkey_ex.public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint))
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value, keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)

View file

@ -18,7 +18,7 @@
""" """
import pytest import pytest
from utils import KeyType, DOPrefixes, Algorithm from picohsm import KeyType, DOPrefixes, Algorithm
from binascii import hexlify from binascii import hexlify
import hashlib import hashlib
@ -39,7 +39,7 @@ def test_signature_ecc(device, curve, scheme):
else: else:
datab = data datab = data
signature = device.sign(keyid=keyid, scheme=scheme, data=datab) signature = device.sign(keyid=keyid, scheme=scheme, data=datab)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.verify(pubkey, datab, signature, scheme) device.verify(pubkey, datab, signature, scheme)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -52,6 +52,6 @@ def test_signature_rsa(device, modulus, scheme):
keyid = device.key_generation(KeyType.RSA, modulus) keyid = device.key_generation(KeyType.RSA, modulus)
pubkey = device.public_key(keyid=keyid) pubkey = device.public_key(keyid=keyid)
signature = device.sign(keyid=keyid, scheme=scheme, data=data) signature = device.sign(keyid=keyid, scheme=scheme, data=data)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.verify(pubkey, data, signature, scheme) device.verify(pubkey, data, signature, scheme)

View file

@ -18,9 +18,8 @@
""" """
import pytest import pytest
from utils import KeyType, DOPrefixes, Algorithm from picohsm import KeyType, DOPrefixes
from binascii import hexlify from binascii import hexlify
import hashlib
from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
@ -43,6 +42,6 @@ def test_decrypt_rsa(device, modulus, pad):
message = data[:(modulus//8)-100] message = data[:(modulus//8)-100]
ciphered = pubkey.encrypt(message, pad) ciphered = pubkey.encrypt(message, pad)
datab = device.decrypt(keyid, ciphered, pad) datab = device.decrypt(keyid, ciphered, pad)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
assert(datab == message) assert(datab == message)

View file

@ -20,8 +20,9 @@
import pytest import pytest
import os import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from utils import Algorithm, DOPrefixes from picohsm import Algorithm, DOPrefixes
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_DKEK_SHARES
from const import DEFAULT_DKEK
MESSAGE = b'a secret message' MESSAGE = b'a secret message'
@ -47,6 +48,6 @@ def test_cipher_aes_cipher(device, size):
decryptor = cipher.decryptor() decryptor = cipher.decryptor()
plA = decryptor.update(ctA) + decryptor.finalize() plA = decryptor.update(ctA) + decryptor.finalize()
plB = device.cipher(Algorithm.ALGO_AES_CBC_DECRYPT, keyid, ctA) plB = device.cipher(Algorithm.ALGO_AES_CBC_DECRYPT, keyid, ctA)
device.delete_file(DOPrefixes.KEY_PREFIX.value, keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
assert(bytes(plB) == plA) assert(bytes(plB) == plA)
assert(bytes(plB) == MESSAGE) assert(bytes(plB) == MESSAGE)

View file

@ -21,8 +21,9 @@ import pytest
import os import os
from cryptography.hazmat.primitives import hashes, hmac, cmac from cryptography.hazmat.primitives import hashes, hmac, cmac
from cryptography.hazmat.primitives.ciphers import algorithms from cryptography.hazmat.primitives.ciphers import algorithms
from utils import Algorithm, DOPrefixes from picohsm import DOPrefixes
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_DKEK_SHARES
from const import DEFAULT_DKEK
MESSAGE = b'a secret message' MESSAGE = b'a secret message'
@ -44,7 +45,7 @@ def test_mac_hmac(device, size, algo):
h = hmac.HMAC(pkey, algo()) h = hmac.HMAC(pkey, algo())
h.update(MESSAGE) h.update(MESSAGE)
resB = h.finalize() resB = h.finalize()
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
assert(bytes(resA) == resB) assert(bytes(resA) == resB)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -57,6 +58,6 @@ def test_mac_cmac(device, size):
c = cmac.CMAC(algorithms.AES(pkey)) c = cmac.CMAC(algorithms.AES(pkey))
c.update(MESSAGE) c.update(MESSAGE)
resB = c.finalize() resB = c.finalize()
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
assert(bytes(resA) == resB) assert(bytes(resA) == resB)

View file

@ -22,8 +22,9 @@ import os
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography import exceptions from cryptography import exceptions
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_DKEK_SHARES
from utils import DOPrefixes from const import DEFAULT_DKEK
from picohsm import DOPrefixes
INFO = b'info message' INFO = b'info message'
@ -47,7 +48,7 @@ class TestHKDF:
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
salt = os.urandom(16) salt = os.urandom(16)
resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len) resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
hkdf = HKDF( hkdf = HKDF(
algorithm=algo(), algorithm=algo(),
length=out_len, length=out_len,
@ -69,7 +70,7 @@ class TestHKDF:
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
salt = os.urandom(16) salt = os.urandom(16)
resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len) resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
hkdf = HKDF( hkdf = HKDF(
algorithm=algo(), algorithm=algo(),
length=out_len, length=out_len,

View file

@ -22,8 +22,9 @@ import os
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography import exceptions from cryptography import exceptions
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_DKEK_SHARES
from utils import DOPrefixes from const import DEFAULT_DKEK
from picohsm import DOPrefixes
INFO = b'info message' INFO = b'info message'
@ -50,7 +51,7 @@ class TestPBKDF2:
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
salt = os.urandom(16) salt = os.urandom(16)
resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len) resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
kdf = PBKDF2HMAC( kdf = PBKDF2HMAC(
algorithm=algo(), algorithm=algo(),
length=out_len, length=out_len,
@ -72,7 +73,7 @@ class TestPBKDF2:
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
salt = os.urandom(16) salt = os.urandom(16)
resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len) resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
kdf = PBKDF2HMAC( kdf = PBKDF2HMAC(
algorithm=algo(), algorithm=algo(),

View file

@ -22,8 +22,9 @@ import os
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
from cryptography import exceptions from cryptography import exceptions
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK from picohsm.const import DEFAULT_DKEK_SHARES
from utils import DOPrefixes from const import DEFAULT_DKEK
from picohsm import DOPrefixes
INFO = b'shared message' INFO = b'shared message'
@ -46,7 +47,7 @@ class TestX963:
pkey = os.urandom(size // 8) pkey = os.urandom(size // 8)
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
resA = device.x963(algo, keyid, INFO, out_len=out_len) resA = device.x963(algo, keyid, INFO, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
xkdf = X963KDF( xkdf = X963KDF(
algorithm=algo(), algorithm=algo(),
length=out_len, length=out_len,
@ -65,7 +66,7 @@ class TestX963:
pkey = os.urandom(size // 8) pkey = os.urandom(size // 8)
keyid = device.import_key(pkey) keyid = device.import_key(pkey)
resA = device.x963(algo, keyid, INFO, out_len=out_len) resA = device.x963(algo, keyid, INFO, out_len=out_len)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
xkdf = X963KDF( xkdf = X963KDF(
algorithm=algo(), algorithm=algo(),
length=out_len, length=out_len,

View file

@ -18,16 +18,13 @@
""" """
import pytest import pytest
import os
from binascii import unhexlify, hexlify from binascii import unhexlify, hexlify
from cvc.certificates import CVC from cvc.certificates import CVC
from cvc.asn1 import ASN1 from picohsm.utils import int_to_bytes
from utils import int_to_bytes from picohsm import APDUResponse, SWCodes
from utils import APDUResponse, SWCodes
from const import TERM_CERT, DICA_CERT from const import TERM_CERT, DICA_CERT
from cryptography.hazmat.primitives.asymmetric import ec, utils from cryptography.hazmat.primitives.asymmetric import ec, utils
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
AUT_KEY = unhexlify('0A40E11E672C28C558B72C25D93BCF28C08D39AFDD5A1A2FD3BAF7A6B27F0C2E') AUT_KEY = unhexlify('0A40E11E672C28C558B72C25D93BCF28C08D39AFDD5A1A2FD3BAF7A6B27F0C2E')
aut_pk = ec.derive_private_key(int.from_bytes(AUT_KEY, 'big'), ec.BrainpoolP256R1()) aut_pk = ec.derive_private_key(int.from_bytes(AUT_KEY, 'big'), ec.BrainpoolP256R1())
@ -87,7 +84,7 @@ def test_authentication_fail(device):
signature = list(int_to_bytes(r) + int_to_bytes(s)) signature = list(int_to_bytes(r) + int_to_bytes(s))
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.authenticate_puk(term_chr, signature) device.authenticate_puk(term_chr, signature)
assert(e.value.sw == SWCodes.SW_CONDITIONS_NOT_SATISFIED.value) assert(e.value.sw == SWCodes.SW_CONDITIONS_NOT_SATISFIED)
status = device.get_puk_status() status = device.get_puk_status()
assert(status == [1,0,1,0]) assert(status == [1,0,1,0])
@ -146,4 +143,4 @@ def test_register_puk_with_no_puk(device):
device.initialize() device.initialize()
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.register_puk(AUT_PUK, TERM_CERT, DICA_CERT) device.register_puk(AUT_PUK, TERM_CERT, DICA_CERT)
assert(e.value.sw == SWCodes.SW_FILE_NOT_FOUND.value) assert(e.value.sw == SWCodes.SW_FILE_NOT_FOUND)

View file

@ -19,14 +19,13 @@
import pytest import pytest
from binascii import unhexlify, hexlify from binascii import unhexlify, hexlify
from utils import APDUResponse, SWCodes from picohsm.utils import int_to_bytes
from utils import int_to_bytes
from const import TERM_CERT, DICA_CERT from const import TERM_CERT, DICA_CERT
from cvc.asn1 import ASN1 from cvc.asn1 import ASN1
from cvc.certificates import CVC from cvc.certificates import CVC
from cvc import oid from cvc import oid
from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import ec
from utils import DOPrefixes from picohsm import DOPrefixes, APDUResponse, SWCodes
KDM = unhexlify(b'30820420060b2b0601040181c31f0402016181ed7f2181e97f4e81a25f290100421045535049434f48534d434130303030317f494f060a04007f0007020202020386410421ee4a21c16a10f737f12e78e5091b266612038cdabebb722b15bf6d41b877fbf64d9ab69c39b9831b1ae00bef2a4e81976f7688d45189bb232a24703d8a96a55f201045535049434f48534d445630303030317f4c12060904007f000703010202530580000000005f25060202000801085f24060203000601045f37403f75c08fffc9186b56e6147199e82bfc327ceef72495bc567961cd54d702f13e3c2766fcd1d11bd6a9d1f4a229b76b248ceb9af88d59a74d0ab149448705159b6281e97f2181e57f4e819e5f290100421045535049434f48534d445630303030317f494f060a04007f00070202020203864104c8561b41e54fea81bb80dd4a6d537e7c3904344e8ca90bc5f668111811e02c8d5d51ca93ca89558f2a8a9cbb147434e3441ec174505ff980fd7a7106286196915f201045535049434f48534d54524a444736387f4c0e060904007f0007030102025301005f25060203000300065f24060204000300055f3740983de63d0975b715ebd8a93cb38fa9638882c8b7064d51a6facabed693b92edc098e458b713203413ef6de0958c44772cbdbc264205c7b1bdb8b4fcb2516437f638201f1678201ed7f218201937f4e82014b5f290100421045535049434f48534d54524a444736387f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641048b1f450912a2e4d428b7eefc5fa05618a9ef295e90009a61cbb0970181b333474ea94f94cde5a11aba0589e85d4225002789ff1cdcf25756f059647b49fc2a158701015f201045535049434f48534d54524a444736385f3740372407c20de7257c89dae1e6606c8a046ca65efaa010c0a22b75c402ee243de51f5f1507457193679ed9db4fbbfe8efb9d695b684492b665ad8ba98c1f84ea38421045535049434f48534d54524a444736385f374098718e2e14a44386b689b71a101530316b65ab49a91bab0dd56099c5161ecb8aadff6cf27449f94034e58b7306f01e6ffa2766a2f5bb1281e12e5f1f9174733454400cf8926ca5bec9a91bcd47bf391c15d94ef6e3243d5fd1fffeaafd586766bc3221eafd808f17f8450f238cc1fe7ab1854443db31d622f53a2b3fdb3ad750d5ce') KDM = unhexlify(b'30820420060b2b0601040181c31f0402016181ed7f2181e97f4e81a25f290100421045535049434f48534d434130303030317f494f060a04007f0007020202020386410421ee4a21c16a10f737f12e78e5091b266612038cdabebb722b15bf6d41b877fbf64d9ab69c39b9831b1ae00bef2a4e81976f7688d45189bb232a24703d8a96a55f201045535049434f48534d445630303030317f4c12060904007f000703010202530580000000005f25060202000801085f24060203000601045f37403f75c08fffc9186b56e6147199e82bfc327ceef72495bc567961cd54d702f13e3c2766fcd1d11bd6a9d1f4a229b76b248ceb9af88d59a74d0ab149448705159b6281e97f2181e57f4e819e5f290100421045535049434f48534d445630303030317f494f060a04007f00070202020203864104c8561b41e54fea81bb80dd4a6d537e7c3904344e8ca90bc5f668111811e02c8d5d51ca93ca89558f2a8a9cbb147434e3441ec174505ff980fd7a7106286196915f201045535049434f48534d54524a444736387f4c0e060904007f0007030102025301005f25060203000300065f24060204000300055f3740983de63d0975b715ebd8a93cb38fa9638882c8b7064d51a6facabed693b92edc098e458b713203413ef6de0958c44772cbdbc264205c7b1bdb8b4fcb2516437f638201f1678201ed7f218201937f4e82014b5f290100421045535049434f48534d54524a444736387f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641048b1f450912a2e4d428b7eefc5fa05618a9ef295e90009a61cbb0970181b333474ea94f94cde5a11aba0589e85d4225002789ff1cdcf25756f059647b49fc2a158701015f201045535049434f48534d54524a444736385f3740372407c20de7257c89dae1e6606c8a046ca65efaa010c0a22b75c402ee243de51f5f1507457193679ed9db4fbbfe8efb9d695b684492b665ad8ba98c1f84ea38421045535049434f48534d54524a444736385f374098718e2e14a44386b689b71a101530316b65ab49a91bab0dd56099c5161ecb8aadff6cf27449f94034e58b7306f01e6ffa2766a2f5bb1281e12e5f1f9174733454400cf8926ca5bec9a91bcd47bf391c15d94ef6e3243d5fd1fffeaafd586766bc3221eafd808f17f8450f238cc1fe7ab1854443db31d622f53a2b3fdb3ad750d5ce')
@ -37,7 +36,7 @@ def test_initialize(device):
def test_create_xkek(device): def test_create_xkek(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.create_xkek(KDM) device.create_xkek(KDM)
assert(e.value.sw == SWCodes.SW_CONDITIONS_NOT_SATISFIED.value) assert(e.value.sw == SWCodes.SW_CONDITIONS_NOT_SATISFIED)
device.login() device.login()
kcv, did = device.create_xkek(KDM) kcv, did = device.create_xkek(KDM)
@ -54,7 +53,7 @@ def test_derive_xkek(device):
keyid = device.generate_xkek_key() keyid = device.generate_xkek_key()
resp = device.list_keys() resp = device.list_keys()
assert((DOPrefixes.KEY_PREFIX.value, keyid) in resp) assert((DOPrefixes.KEY_PREFIX, keyid) in resp)
xkek_dom = device.get_key_domain()['xkek'] xkek_dom = device.get_key_domain()['xkek']
pkey = ec.generate_private_key(ec.BrainpoolP256R1()) pkey = ec.generate_private_key(ec.BrainpoolP256R1())
@ -83,10 +82,10 @@ def test_delete_xkek(device):
def test_delete_domain_with_key(device): def test_delete_domain_with_key(device):
with pytest.raises(APDUResponse) as e: with pytest.raises(APDUResponse) as e:
device.delete_key_domain() device.delete_key_domain()
assert(e.value.sw == SWCodes.SW_FILE_EXISTS.value) assert(e.value.sw == SWCodes.SW_FILE_EXISTS)
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.KEY_PREFIX, keyid)
device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX.value << 8 | keyid) device.delete_file(DOPrefixes.EE_CERTIFICATE_PREFIX, keyid)
def test_delete_domain(device): def test_delete_domain(device):
device.delete_key_domain() device.delete_key_domain()
@ -95,5 +94,5 @@ def test_delete_domain(device):
assert('kcv' not in resp) assert('kcv' not in resp)
assert('xkek' not in resp) assert('xkek' not in resp)
assert('error' in resp) assert('error' in resp)
assert(resp['error'] == SWCodes.SW_REFERENCE_NOT_FOUND.value) assert(resp['error'] == SWCodes.SW_REFERENCE_NOT_FOUND)

View file

@ -1,141 +0,0 @@
"""
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"""
from enum import Enum
class SWCodes(Enum):
SW_BYTES_REMAINING_00 = 0x6100
SW_WARNING_STATE_UNCHANGED = 0x6200
SW_WARNING_CORRUPTED = 0x6281
SW_WARNING_EOF = 0x6282
SW_WARNING_EF_DEACTIVATED = 0x6283
SW_WARNING_WRONG_FCI = 0x6284
SW_WARNING_EF_TERMINATED = 0x6285
SW_WARNING_NOINFO = 0x6300
SW_WARNING_FILLUP = 0x6381
SW_EXEC_ERROR = 0x6400
SW_SECURE_MESSAGE_EXEC_ERROR = 0x6600
SW_WRONG_LENGTH = 0x6700
SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 0x6881
SW_SECURE_MESSAGING_NOT_SUPPORTED = 0x6882
SW_COMMAND_INCOMPATIBLE = 0x6981
SW_SECURITY_STATUS_NOT_SATISFIED = 0x6982
SW_PIN_BLOCKED = 0x6983
SW_DATA_INVALID = 0x6984
SW_CONDITIONS_NOT_SATISFIED = 0x6985
SW_COMMAND_NOT_ALLOWED = 0x6986
SW_SECURE_MESSAGING_MISSING_DO = 0x6987
SW_SECURE_MESSAGING_INCORRECT_DO = 0x6988
SW_APPLET_SELECT_FAILED = 0x6999
SW_INCORRECT_PARAMS = 0x6A80
SW_FUNC_NOT_SUPPORTED = 0x6A81
SW_FILE_NOT_FOUND = 0x6A82
SW_RECORD_NOT_FOUND = 0x6A83
SW_FILE_FULL = 0x6A84
SW_WRONG_NE = 0x6A85
SW_INCORRECT_P1P2 = 0x6A86
SW_WRONG_NC = 0x6A87
SW_REFERENCE_NOT_FOUND = 0x6A88
SW_FILE_EXISTS = 0x6A89
SW_WRONG_P1P2 = 0x6B00
SW_CORRECT_LENGTH_00 = 0x6C00
SW_INS_NOT_SUPPORTED = 0x6D00
SW_CLA_NOT_SUPPORTED = 0x6E00
SW_UNKNOWN = 0x6F00
SW_OK = 0x900
class APDUResponse(Exception):
def __init__(self, sw1, sw2):
self.sw1 = sw1
self.sw2 = sw2
self.sw = sw1 << 8 | sw2
super().__init__(f'SW:{sw1:02X}{sw2:02X}')
class DOPrefixes(Enum):
PRKD_PREFIX = 0xC4
CD_PREFIX = 0xC8
DCOD_PREFIX = 0xC9
CA_CERTIFICATE_PREFIX = 0xCA
KEY_PREFIX = 0xCC
PROT_DATA_PREFIX = 0xCD
EE_CERTIFICATE_PREFIX = 0xCE
DATA_PREFIX = 0xCF
class KeyType(Enum):
RSA = 1
ECC = 2
AES = 3
class Algorithm(Enum):
ALGO_AES_CBC_ENCRYPT = 0x10
ALGO_AES_CBC_DECRYPT = 0x11
ALGO_AES_CMAC = 0x18
ALGO_EXT_CIPHER_ENCRYPT = 0x51
ALGO_EXT_CIPHER_DECRYPT = 0x52
ALGO_AES_DERIVE = 0x99
ALGO_EC_RAW = 0x70
ALGO_EC_SHA1 = 0x71
ALGO_EC_SHA224 = 0x72
ALGO_EC_SHA256 = 0x73
ALGO_EC_SHA384 = 0x74
ALGO_EC_SHA512 = 0x75
ALGO_EC_ECDH = 0x80
ALGO_EC_ECDH_XKEK = 0x84
ALGO_EC_DERIVE = 0x98
ALGO_RSA_RAW = 0x20
ALGO_RSA_DECRYPT = 0x21
ALGO_RSA_DECRYPT_PKCS1 = 0x22
ALGO_RSA_DECRYPT_OEP = 0x23
ALGO_RSA_PKCS1 = 0x30
ALGO_RSA_PKCS1_SHA1 = 0x31
ALGO_RSA_PKCS1_SHA224 = 0x32
ALGO_RSA_PKCS1_SHA256 = 0x33
ALGO_RSA_PKCS1_SHA384 = 0x34
ALGO_RSA_PKCS1_SHA512 = 0x35
ALGO_RSA_PSS = 0x40
ALGO_RSA_PSS_SHA1 = 0x41
ALGO_RSA_PSS_SHA224 = 0x42
ALGO_RSA_PSS_SHA256 = 0x43
ALGO_RSA_PSS_SHA384 = 0x44
ALGO_RSA_PSS_SHA512 = 0x45
class Padding(Enum):
RAW = 0x21
PKCS = 0x22
OAEP = 0x23
def int_to_bytes(x, length=None, byteorder='big'):
return x.to_bytes(length or (x.bit_length() + 7) // 8, byteorder=byteorder)