# Based on https://github.com/Disappear9/pico-hsm-cvcgen/tree/main/research
# Tested on Debian 13.2 on aarch64 with Waveshare RP2040 zero and pico_hsm_pico-6.4.uf2
t=$(mktemp -d)
cd $t
cat >requirements.txt <<"EOF"
pycvc
pypicokey @ git+https://github.com/librekeys/pypicokey-mirror
pypicohsm @ git+https://github.com/librekeys/pypicohsm
EOF
apt update && apt install -y python3 python3-venv
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
wget https://github.com/librekeys/pico-hsm-sf/raw/refs/heads/master/tools/pico-hsm-tool.py
wget https://raw.githubusercontent.com/Disappear9/pico-hsm-cvcgen/refs/heads/main/research/convertcvc.py
wget https://raw.githubusercontent.com/Disappear9/pico-hsm-cvcgen/refs/heads/main/research/convertder.py
wget https://raw.githubusercontent.com/librekeys/pypicohsm/412aa07898a355beaec7f1b5da3895f8e85f5a09/picohsm/PicoHSM.py
cat > PicoHSM.patch <<"EOF"
--- PicoHSM.py.orig 2026-02-18 21:41:56.875706459 +0100
+++ PicoHSM.py 2026-02-19 17:08:38.328373314 +0100
@@ -29,6 +29,7 @@
from binascii import hexlify
import base64
import urllib
+import json
try:
from picokey import PicoKey, SecureChannel, APDUResponse, Product, Platform, PhyOpt
@@ -187,14 +188,19 @@
cert = bytearray(response)
Y = CVC().decode(cert).pubkey().find(0x86).data()
- #print(f'Public Point: {hexlify(Y).decode()}')
+ ##
+ print(f'Public Point: {hexlify(Y).decode()}')
pbk = base64.urlsafe_b64encode(Y)
params = {'pubkey': pbk}
- if (self.__card.platform in (Platform.RP2350, Platform.ESP32, Platform.EMULATION)):
+ print(self.__card.platform)
+ if (self.__card.platform in (Platform.RP2040, Platform.RP2350, Platform.ESP32, Platform.EMULATION)):
params['curve'] = 'secp256k1'
+ print(params)
data = urllib.parse.urlencode(params).encode()
- j = get_pki_data('cvc', data=data)
+ ##j = get_pki_data('cvc', data=data)
+ input_json = input("Enter a JSON string: ")
+ j = json.loads(input_json)
#print('Device name: '+j['devname'])
dataef = base64.urlsafe_b64decode(
j['cvcert']) + base64.urlsafe_b64decode(j['dvcert']) + base64.urlsafe_b64decode(j['cacert'])
@@ -900,7 +906,7 @@
def general_authentication(self):
self.send(command=0x22, p1=0x41, p2=0xA4, data=ASN1().add_tag(0x80, SecureChannel.PROTO_OID).encode())
- pkeyB = ec.generate_private_key(ec.SECP256R1())
+ pkeyB = ec.generate_private_key(ec.SECP256K1())
pbkeyB = pkeyB.public_key()
pbkeyBytes = PicoHSM.__pubkey_uncompressed(pbkeyB)
dado = ASN1().add_tag(0x7C, ASN1().add_tag(0x80, pbkeyBytes).encode()).encode()
EOF
patch venv/lib64/python3.13/site-packages/picohsm/PicoHSM.py < PicoHSM.patch
cat > convertder.py.patch <<"EOF"
--- convertder.py 2026-02-19 17:00:36.676131715 +0100
+++ convertder_RP2040.py 2026-02-19 17:03:05.414877545 +0100
@@ -1,50 +1,56 @@
-import base64
-import binascii
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.asymmetric import ec
-
-def convert_y_to_der(y_bytearray):
- """
- 将Y字节数组转换为DER格式的SubjectPublicKeyInfo
- """
- # 确保是字节格式
- if isinstance(y_bytearray, bytearray):
- y_bytes = bytes(y_bytearray)
- else:
- y_bytes = y_bytearray
-
- # 验证格式和长度
- if len(y_bytes) != 65 or y_bytes[0] != 0x04:
- raise ValueError("无效的公钥格式,应为65字节以0x04开头")
-
- # 创建secp256k1公钥对象
- public_key = ec.EllipticCurvePublicKey.from_encoded_point(
- ec.SECP256R1(), #RP2040 uses R1 even when K1 is explicitely requested!
- #ec.SECP256K1(),
- y_bytes
- )
-
- # 导出为DER格式
- der_bytes = public_key.public_bytes(
- encoding=serialization.Encoding.DER,
- format=serialization.PublicFormat.SubjectPublicKeyInfo
- )
-
- return der_bytes
-
-# 你的Y值
-input_y = input("Enter Y: ")
-input_y = binascii.unhexlify(input_y)
-Y = bytearray(input_y)
-
-# 转换
-der_data = convert_y_to_der(Y)
-
-# 保存到文件
-with open('public_key.pub', 'wb') as f:
- f.write(der_data)
-
-# 输出信息
-print(f"DER公钥长度: {len(der_data)} 字节")
-print(f"DER十六进制: {der_data.hex()}")
-print(f"文件已保存: public_key.pub")
+import binascii
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric import ec
+
+def convert_pubkey_to_der(pub_bytes):
+ """
+ Convert a public key to DER-encoded SubjectPublicKeyInfo.
+ Accepts:
+ - Raw uncompressed point: 65 bytes starting with 0x04
+ - DER-encoded key: will pass through unchanged
+ """
+ # Detect raw uncompressed key
+ if len(pub_bytes) == 65 and pub_bytes[0] == 0x04:
+ # Create EC public key object (P-256)
+ public_key = ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP256R1(),
+ pub_bytes
+ )
+ # Export as DER
+ der_bytes = public_key.public_bytes(
+ encoding=serialization.Encoding.DER,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
+ )
+ return der_bytes
+ else:
+ # Try loading as DER
+ try:
+ public_key = serialization.load_der_public_key(pub_bytes)
+ # Re-export as DER to standardize
+ der_bytes = public_key.public_bytes(
+ encoding=serialization.Encoding.DER,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
+ )
+ return der_bytes
+ except Exception as e:
+ raise ValueError(
+ "Invalid public key format. Must be either 65-byte uncompressed point or DER."
+ ) from e
+
+# Prompt user for input
+input_str = input("Enter public key (hex): ").strip()
+
+try:
+ pub_bytes = binascii.unhexlify(input_str)
+except binascii.Error:
+ raise ValueError("Invalid hex input.")
+
+# Convert and save DER
+der_data = convert_pubkey_to_der(pub_bytes)
+
+with open('public_key.pub', 'wb') as f:
+ f.write(der_data)
+
+print(f"DER public key length: {len(der_data)} bytes")
+print(f"DER hex: {der_data.hex()}")
+
EOF
patch convertder.py < convertder.py.patch
cat > convertcvc.py.patch <<"EOF"
--- convertcvc.py 2026-02-19 18:45:49.984865489 +0100
+++ convertcvc.py.orig 2026-02-19 18:46:50.697675465 +0100
@@ -14,35 +14,40 @@
except Exception as e:
print(f"An error occurred: {e}")
-def read_cert(file_path):
- try:
- with open(file_path, 'rb') as f:
- content = f.read()
- return base64.urlsafe_b64encode(content).decode('ascii')
- except FileNotFoundError:
- print(f"File {file_path} not found.")
- return None
- except Exception as e:
- print(f"An error occurred reading {file_path}: {e}")
- return None
+try:
+ with open('ESPICOHSMCA00001.cvcert', 'rb') as cafile:
+ content = cafile.read()
+ cacert = base64.urlsafe_b64encode(content)
+except FileNotFoundError:
+ print("File not found.")
+except Exception as e:
+ print(f"An error occurred: {e}")
-# Read certs
-cacert = read_cert('ESPICOHSMCA00001.cvcert')
-dvcert = read_cert('ESPICOHSMDV00001.cvcert')
-cvcert = read_cert('ESPICOHSMTR00002.cvcert')
-# Build JSON
-data = {
- 'cvcert': cvcert,
- 'dvcert': dvcert,
- 'cacert': cacert
-}
+try:
+ with open('ESPICOHSMDV00001.cvcert', 'rb') as dvfile:
+ content = dvfile.read()
+ dvcert = base64.urlsafe_b64encode(content)
+except FileNotFoundError:
+ print("File not found.")
+except Exception as e:
+ print(f"An error occurred: {e}")
-# Serialize
-json_data = json.dumps(data, separators=(',', ':'))
+try:
+ with open('ESPICOHSMTR00002.cvcert', 'rb') as cvfile:
+ content = cvfile.read()
+ cvcert = base64.urlsafe_b64encode(content)
+except FileNotFoundError:
+ print("File not found.")
+except Exception as e:
+ print(f"An error occurred: {e}")
+data = {}
+data['cvcert'] = cvcert
+data['dvcert'] = dvcert
+data['cacert'] = cacert
+json_data = json.dumps(data, separators=(',', ':'))
print("Json:")
print("===================================")
print(json_data)
print("===================================")
-
EOF
patch convertcvc.py < convertcvc.py.patch
# Setup the CA
openssl ecparam -out ESPICOHSMCA00001.pem -name prime256v1 -genkey
openssl pkcs8 -topk8 -nocrypt -in ESPICOHSMCA00001.pem -outform DER -out ESPICOHSMCA00001.pkcs8
cvc-create --role=cvca --type=at --chr=ESPICOHSMCA00001 --days=3650 --sign-key=ESPICOHSMCA00001.pkcs8 --scheme=ECDSA_SHA_256
# Setup the DV (domain validation)
openssl ecparam -out ESPICOHSMDV00001.pem -name prime256v1 -genkey
openssl pkcs8 -topk8 -nocrypt -in ESPICOHSMDV00001.pem -outform DER -out ESPICOHSMDV00001.pkcs8
openssl ec -in ESPICOHSMDV00001.pem -out ESPICOHSMDV00001.pub -pubout -outform DER
cvc-create --role=dv_domestic --type=at --chr=ESPICOHSMDV00001 --days=1820 --sign-key=ESPICOHSMCA00001.pkcs8 --scheme=ECDSA_SHA_256 --sign-as=ESPICOHSMCA00001.cvcert --public-key=ESPICOHSMDV00001.pub
python3 pico-hsm-tool.py --pin 114514 initialize --so-pin 57621880
# ctrl + z
python3 convertder.py
cvc-create --role=terminal --type=at --chr=ESPICOHSMTR00002 --days=365 --sign-key=ESPICOHSMDV00001.pkcs8 --scheme=ECDSA_SHA_256 --sign-as=ESPICOHSMDV00001.cvcert --public-key=public_key.pub
python3 convertcvc.py
# copy & paste JSON
fg
# enter JSON
python3 pico-hsm-tool.py phy vidpid 20a0:4230 # Nitrokey-HSM
# unplug and plug in again
cat > /etc/udev/rules.d/41-nitrokey.rules <<"EOF"
/etc/udev/rules.d/41-nitrokey.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", TAG+="uaccess"
EOF
udevadm control --reload-rules && sudo udevadm trigger
lsusb |grep Clay
#Bus 003 Device 020: ID 20a0:4230 Clay Logic Nitrokey HSM
dmesg |tail -7
#[260046.434174] usb 3-1.2: USB disconnect, device number 19
#[260049.408820] usb 3-1.2: new full-speed USB device number 20 using ehci-platform
#[260049.625840] usb 3-1.2: New USB device found, idVendor=20a0, idProduct=4230, bcdDevice= 8.05
#[260049.625872] usb 3-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
#[260049.625880] usb 3-1.2: Product: Pico Key
#[260049.625886] usb 3-1.2: Manufacturer: Pol Henarejos
#[260049.625892] usb 3-1.2: SerialNumber: E***D
pkcs15-tool -D
#Using reader with a card: Nitrokey Nitrokey HSM [Pico Key CCID OTP FIDO Interfac] (E***) 00 00
#PKCS#15 Card [Pico-HSM]:
# Version : 6
# Serial number : ESPICOHSMTR
# Manufacturer ID: Pol Henarejos
# Flags : PRN generation, EID compliant
#
#
#PIN [UserPIN]
# Object Flags : [0x03], private, modifiable
# Auth ID : 02
# ID : 01
# Flags : [0x812], local, initialized, exchangeRefData
# Length : min_len:6, max_len:15, stored_len:0
# Pad char : 0x00
# Reference : 129 (0x81)
# Type : ascii-numeric
# Path : e82b0601040181c31f0201::
# Tries left : 0
#
#PIN [SOPIN]
# Object Flags : [0x01], private
# ID : 02
# Flags : [0x9A], local, unblock-disabled, initialized, soPin
# Length : min_len:16, max_len:16, stored_len:0
# Pad char : 0x00
# Reference : 136 (0x88)
# Type : bcd
# Path : e82b0601040181c31f0201::
# Tries left : 15Then using scsh3gui:
- Patch scsh3gui
- Initialize device again with 8 key domains
- Create your keys as normal
scs3/scsh/sc-hsm/SmartCardHSM.js
IMPORTANT Copy YOUR
SCS3ByteString from theconvertcvc.pystep! This will change everytime you roll your CA!
SmartCardHSM.rootCerts = {
DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)),
UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX)),
//ESPICOHSMCA00001: new CVC(new ByteString("7F218201BA7F4E8201725F290100421045535049434F48534D434130303030317F4982011D060A04007F000702020202038120FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF8220FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC83205AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B8441046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F58520FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC6325518641046A82C0A4FEAF41D6A1336AE7E992D81AD4F827929145DD0D777E1AB63D7E3325C8F7DAC0F74B6EAE13A72F6366777EC133AC5C28F456868E5F2C315044EB54EF8701015F201045535049434F48534D434130303030317F4C12060904007F0007030102025305C0000000005F25060202000801085F24060203000801085F3740601E974F57DDE060875FE6121AEF5BC02E10FC655311C7A32CA822FD18E53A80298EDC56E0D5EBF38FB470DC12987B1600AE91A0ADB5B22C4D80080782E278AD", HEX)),
ESPICOHSMCA00001: new CVC(new ByteString("7F218201BA7F4E8201725F290100421045535049434F48534D434130303030317F4982011D060A04007F000702020202038120FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF8220FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC83205AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B8441046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F58520FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551864104283C680576E42EFDF0CE25FCD3921D7E5F6C7B7D2718DB6F2B7F271048BF804E7667E53DD082977FE8119CA0FB3103E7F73876E369C7D9A3A36468C368EC4DA28701015F201045535049434F48534D434130303030317F4C12060904007F0007030102025305C0000000005F25060206000201095F24060306000201075F37409F22B2C22DD622465DB1F4655A51187003AA08E69E3FD92DF6C683B2ECF668B86268567F997F0D0EAE6E507DD7A9E27719A8498122CA4D8A1892D8EEC57CE28F", HEX))
}
scs3/keymanager/keymanager.js
} else {
var pk = new CVC(a.get(0));
var devcert = new CVC(a.get(1));
var dicacert = new CVC(a.get(2));
}
assert(dicacert.verifyWithCVC(this.crypto, SmartCardHSM.rootCerts[dicacert.getCAR()]));
//assert(devcert.verifyWith(this.crypto, dicacert.getPublicKey(SmartCardHSM.rootCerts.UTSRCACC100001.getPublicKey()), dicacert.getPublicKeyOID()));
//assert(devcert.verifyWith(this.crypto, dicacert.getPublicKey(SmartCardHSM.rootCerts.ESPICOHSMCA00001.getPublicKey()), dicacert.getPublicKeyOID()));
assert(devcert.verifyWith(this.crypto, dicacert.getPublicKey(SmartCardHSM.rootCerts.ESPICOHSMCA00001.getPublicKey()), dicacert.getPublicKeyOID()));
var str = (typeof(id) == "undefined" ? "Add the key issued to " : "Replace key " + id + " with ");
var ok = Dialog.prompt(str + pk.getCHR() + " on device " + devcert.getCHR() + " (Cancel for No) ?");
if (ok == null) {
return;
}
# as root
# source venv/bin/activate
# openssl ecparam -out ESPICOHSMCA00001.pem -name prime256v1 -genkey
# openssl pkcs8 -topk8 -nocrypt -in ESPICOHSMCA00001.pem -outform DER -out ESPICOHSMCA00001.pkcs8
# cvc-create --role=cvca --type=at --chr=ESPICOHSMCA00001 --days=3650 --sign-key=ESPICOHSMCA00001.pkcs8 --scheme=ECDSA_SHA_256
# ls -al ESP*
-rw-r--r-- 1 root root 447 Feb 19 17:17 ESPICOHSMCA00001.cvcert
-rw------- 1 root root 302 Feb 19 17:17 ESPICOHSMCA00001.pem
-rw------- 1 root root 138 Feb 19 17:17 ESPICOHSMCA00001.pkcs8
# openssl ecparam -out ESPICOHSMDV00001.pem -name prime256v1 -genkey
# openssl pkcs8 -topk8 -nocrypt -in ESPICOHSMDV00001.pem -outform DER -out ESPICOHSMDV00001.pkcs8
# openssl ec -in ESPICOHSMDV00001.pem -out ESPICOHSMDV00001.pub -pubout -outform DER
# cvc-create --role=dv_domestic --type=at --chr=ESPICOHSMDV00001 --days=1820 --sign-key=ESPICOHSMCA00001.pkcs8 --scheme=ECDSA_SHA_256 --sign-as=ESPICOHSMCA00001.cvcert --public-key=ESPICOHSMDV00001.pub
# ls -al ESP*
-rw-r--r-- 1 root root 447 Feb 19 17:17 ESPICOHSMCA00001.cvcert
-rw------- 1 root root 302 Feb 19 17:17 ESPICOHSMCA00001.pem
-rw------- 1 root root 138 Feb 19 17:17 ESPICOHSMCA00001.pkcs8
-rw-r--r-- 1 root root 237 Feb 19 17:18 ESPICOHSMDV00001.cvcert
-rw------- 1 root root 302 Feb 19 17:18 ESPICOHSMDV00001.pem
-rw------- 1 root root 138 Feb 19 17:18 ESPICOHSMDV00001.pkcs8
-rw-r--r-- 1 root root 91 Feb 19 17:18 ESPICOHSMDV00001.pub
# python3 pico-hsm-tool.py --pin 114514 initialize --so-pin 57621880
Pico HSM Tool v2.4
Author: Pol Henarejos
Report bugs to https://github.com/polhenarejos/pico-hsm/issues
********************************
* PLEASE READ IT CAREFULLY *
********************************
This tool will erase and reset your device. It will delete all private and secret keys.
Are you sure?
[Press enter to confirm]
Public Point: 043034443a8c82fe8c407c26ae16bc66141323cf166aee17bcb314b0e5fd604a1904a560fedb3f60f12775502c4d255660cd9d33836ac0b18b328ff6c91fc69c03
RP2040
{'pubkey': b'BDA0RDqMgv6MQHwmrha8ZhQTI88Wau4XvLMUsOX9YEoZBKVg_ts_YPEndVAsTSVWYM2dM4NqwLGLMo_2yR_GnAM=', 'curve': 'secp256k1'}
Enter a JSON string: ^Z
[1]+ Stopped python3 pico-hsm-tool.py --pin 114514 initialize --so-pin 57621880
# python3 convertder.py # enter above Public Point
# ls -al public_key.pub
-rw-r--r-- 1 root root 91 Feb 19 17:20 public_key.pub
# cvc-create --role=terminal --type=at --chr=ESPICOHSMTR00002 --days=365 --sign-key=ESPICOHSMDV00001.pkcs8 --scheme=ECDSA_SHA_256 --sign-as=ESPICOHSMDV00001.cvcert --public-key=public_key.pub
# ls -al ESPICOHSMTR00002.cvcert
-rw-r--r-- 1 root root 237 Feb 19 17:22 ESPICOHSMTR00002.cvcert
# python convertcvc.py
SCS3:
===================================
b'7F218201BA7F4E8201725F290100421045535049434F48534D434130303030317F4982011D060A04007F000702020202038120FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF8220FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC83205AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B8441046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F58520FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551864104283C680576E42EFDF0CE25FCD3921D7E5F6C7B7D2718DB6F2B7F271048BF804E7667E53DD082977FE8119CA0FB3103E7F73876E369C7D9A3A36468C368EC4DA28701015F201045535049434F48534D434130303030317F4C12060904007F0007030102025305C0000000005F25060206000201095F24060306000201075F37409F22B2C22DD622465DB1F4655A51187003AA08E69E3FD92DF6C683B2ECF668B86268567F997F0D0EAE6E507DD7A9E27719A8498122CA4D8A1892D8EEC57CE28F'
===================================
Json:
===================================
{"cvcert":"fyGB6X9OgaJfKQEAQhBFU1BJQ09IU01EVjAwMDAxf0lPBgoEAH8ABwICAgIDhkEEMDREOoyC_oxAfCauFrxmFBMjzxZq7he8sxSw5f1gShkEpWD-2z9g8Sd1UCxNJVZgzZ0zg2rAsYsyj_bJH8acA18gEEVTUElDT0hTTVRSMDAwMDJ_TBIGCQQAfwAHAwECAlMFAAAAAABfJQYCBgACAQlfJAYCBwACAQlfN0DnIoRjyxrpoAjTUc_86pRNkvIRY17PrzeRye1w6C1-ZJWrfQ0BaUClhoUvl1gJSv5KXe_vbHxTi9UKpfqk6ARt","dvcert":"fyGB6X9OgaJfKQEAQhBFU1BJQ09IU01DQTAwMDAxf0lPBgoEAH8ABwICAgIDhkEE2i3Dd6u_JlGlBGJ55jEO8yxmtgBESpYlR2UAxu3malbUsSMZssPYADnklk-V8KTdrniNIkTB6eQBbDENeNd1_l8gEEVTUElDT0hTTURWMDAwMDF_TBIGCQQAfwAHAwECAlMFgAAAAABfJQYCBgACAQlfJAYDAQACAQNfN0DLjtmxLfH4U9IHmuYEBzi3JTUdVGcvCTF0USOfXkKuBZDwvbfSaHqBoTCC0voXs7t7J0mSQPhFWyCQhhGfejSD","cacert":"fyGCAbp_ToIBcl8pAQBCEEVTUElDT0hTTUNBMDAwMDF_SYIBHQYKBAB_AAcCAgICA4Eg_____wAAAAEAAAAAAAAAAAAAAAD_______________-CIP____8AAAABAAAAAAAAAAAAAAAA_______________8gyBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw-J9JgS4RBBGsX0fLhLEJH-Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT-NC4v4af5uO5-tKfA-eFivOM1drMV7Oy7ZAaDe_UfWFIP____8AAAAA__________-85vqtpxeehPO5ysL8YyVRhkEEKDxoBXbkLv3wziX805Idfl9se30nGNtvK38nEEi_gE52Z-U90IKXf-gRnKD7MQPn9zh242nH2aOjZGjDaOxNoocBAV8gEEVTUElDT0hTTUNBMDAwMDF_TBIGCQQAfwAHAwECAlMFwAAAAABfJQYCBgACAQlfJAYDBgACAQdfN0CfIrLCLdYiRl2x9GVaURhwA6oI5p4_2S32xoOy7PZouGJoVn-Zfw0Orm5Qfdep4ncZqEmBIspNihiS2O7FfOKP"}
===================================
# fg
python3 pico-hsm-tool.py --pin 114514 initialize --so-pin 57621880
{"cvcert":"fyGB6X9OgaJfKQEAQhBFU1BJQ09IU01EVjAwMDAxf0lPBgoEAH8ABwICAgIDhkEEMDREOoyC_oxAfCauFrxmFBMjzxZq7he8sxSw5f1gShkEpWD-2z9g8Sd1UCxNJVZgzZ0zg2rAsYsyj_bJH8acA18gEEVTUElDT0hTTVRSMDAwMDJ_TBIGCQQAfwAHAwECAlMFAAAAAABfJQYCBgACAQlfJAYCBwACAQlfN0CL2MmsUENHvqpZno0mAfwnJr5Cl84RQ1z-kgspswRrncbGbenWGlq-nSyx9AHah3AjSBbeFKLMSNBgNZQp0lnE","dvcert":"fyGB6X9OgaJfKQEAQhBFU1BJQ09IU01DQTAwMDAxf0lPBgoEAH8ABwICAgIDhkEE4eRcAunyi9ybpE8Ige-oj0EXkjvN87OvApCQmcslloMA26KqBThZTzxvNkDemsQJjacyWeV66qPt2vjG8fwVW18gEEVTUElDT0hTTURWMDAwMDF_TBIGCQQAfwAHAwECAlMFgAAAAABfJQYCBgACAQlfJAYDAQACAQNfN0BNSNx-kjjGhAIgsGHPFCgVX6ptxGpGecT8texnwKEIUfHMOmz1a6alxeQDma-1k0YKvlsWtR9wOGsD6zUWPtZt","cacert":"fyGCAbp_ToIBcl8pAQBCEEVTUElDT0hTTUNBMDAwMDF_SYIBHQYKBAB_AAcCAgICA4Eg_____wAAAAEAAAAAAAAAAAAAAAD_______________-CIP____8AAAABAAAAAAAAAAAAAAAA_______________8gyBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw-J9JgS4RBBGsX0fLhLEJH-Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT-NC4v4af5uO5-tKfA-eFivOM1drMV7Oy7ZAaDe_UfWFIP____8AAAAA__________-85vqtpxeehPO5ysL8YyVRhkEEYysDzWjbFJJX2Om-fRDNyrggdoz4iBaejPkmpB_TBTsD_wGq8nKu3DUg2iXzW9lJezIx5zWWt8SdxBRWHwHA8YcBAV8gEEVTUElDT0hTTUNBMDAwMDF_TBIGCQQAfwAHAwECAlMFwAAAAABfJQYCBgACAQlfJAYDBgACAQdfN0BNL42_QKW-Y2oXiZO-hKGCTxabwLDPoJgVCwaoMp4BZxnEX_3OLw898uKZZ4DhA9OBCRKQJFj5nsD2EShsW9nm"}
Certificate uploaded successfully!
Note that the device is initialized with a default PIN and configuration.
Now you can initialize the device as usual with your chosen PIN and configuration options.
# python3 pico-hsm-tool.py phy vidpid 20a0:4230
Pico HSM Tool v2.4
Author: Pol Henarejos
Report bugs to https://github.com/polhenarejos/pico-hsm/issues
Command executed successfully. Please, restart your Pico Key.
# dmesg -c
# unplug...
# dmesg -c
[328875.297176] usb 3-1.2: USB disconnect, device number 21
# ...and plugin again
[328911.303504] usb 3-1.2: new full-speed USB device number 22 using ehci-platform
[328911.520435] usb 3-1.2: New USB device found, idVendor=20a0, idProduct=4230, bcdDevice= 8.05
[328911.520468] usb 3-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[328911.520476] usb 3-1.2: Product: Pico Key
[328911.520482] usb 3-1.2: Manufacturer: Pol Henarejos
[328911.520489] usb 3-1.2: SerialNumber: E***2D
# cat > /etc/udev/rules.d/41-nitrokey.rules <<"EOF"
/etc/udev/rules.d/41-nitrokey.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", TAG+="uaccess"
EOF
# udevadm control --reload-rules && sudo udevadm trigger
# lsusb |grep Clay
Bus 003 Device 022: ID 20a0:4230 Clay Logic Nitrokey HSM
# killall -9 pcscd
# pkcs15-tool -D
Using reader with a card: Nitrokey Nitrokey HSM [Pico Key CCID OTP FIDO Interfac] (E***D) 00 00
PKCS#15 Card [Pico-HSM]:
Version : 6
Serial number : ESPICOHSMTR
Manufacturer ID: Pol Henarejos
Flags : PRN generation, EID compliant
PIN [UserPIN]
Object Flags : [0x03], private, modifiable
Auth ID : 02
ID : 01
Flags : [0x812], local, initialized, exchangeRefData
Length : min_len:6, max_len:15, stored_len:0
Pad char : 0x00
Reference : 129 (0x81)
Type : ascii-numeric
Path : e82b0601040181c31f0201::
Tries left : 2
PIN [SOPIN]
Object Flags : [0x01], private
ID : 02
Flags : [0x9A], local, unblock-disabled, initialized, soPin
Length : min_len:16, max_len:16, stored_len:0
Pad char : 0x00
Reference : 136 (0x88)
Type : bcd
Path : e82b0601040181c31f0201::
Tries left : 15