mirror of
https://github.com/polhenarejos/pico-hsm.git
synced 2026-01-17 09:28:05 +00:00
Using new package pypicohsm.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
parent
a69d06b2d9
commit
11a30863e8
21 changed files with 104 additions and 857 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
141
tests/utils.py
141
tests/utils.py
|
|
@ -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)
|
|
||||||
Loading…
Add table
Reference in a new issue