Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e9cf9b768 | ||
|
|
c95dee84f2 | ||
|
|
65cde9960f | ||
|
|
7ca96178fb | ||
|
|
020feaf325 | ||
|
|
e70461e551 | ||
|
|
0e918434a2 | ||
|
|
63c85000d0 | ||
|
|
4113f6a65d | ||
|
|
f98d744076 | ||
|
|
bb4c293736 | ||
|
|
aa8b1e6efe | ||
|
|
0cb2e8ec2e | ||
|
|
0e96753ccb | ||
|
|
2b2df22d75 | ||
|
|
f65167e3c7 | ||
|
|
8fe2677a56 | ||
|
|
d09a7cf9c8 | ||
|
|
6bf72e5a59 | ||
|
|
7c877ebea2 | ||
|
|
e1983f7bcc | ||
|
|
a5e025a4e5 | ||
|
|
a7682d2639 | ||
|
|
30301c68f1 | ||
|
|
abf980d84e | ||
|
|
8718f55df2 | ||
|
|
d1a3a24527 | ||
|
|
f363b77a07 | ||
|
|
d5899a90c1 | ||
|
|
f1058ea611 | ||
|
|
00279da8d5 | ||
|
|
eda8b53949 | ||
|
|
cfc0cc8f6e | ||
|
|
ab61b2a2d5 | ||
|
|
f79a6ed30a | ||
|
|
4313722b06 | ||
|
|
eec4612a6f | ||
|
|
b2ac893efc | ||
|
|
14e8d9cd04 | ||
|
|
1a6cfd17cb | ||
|
|
3835507e00 | ||
|
|
4536589e2c |
17
README.md
17
README.md
@@ -13,7 +13,7 @@ RSA key generation in place for 1024, 2048, 3072 and 4096 bits. Private keys nev
|
|||||||
ECDSA key generation in place for different curves, from 192 to 521 bits.
|
ECDSA key generation in place for different curves, from 192 to 521 bits.
|
||||||
|
|
||||||
### > ECC curves
|
### > ECC curves
|
||||||
It supports secp192r1, secp256r1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, secp192k1 (insecure), secp256k1 curves.
|
It supports secp192r1, secp256r1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, secp192k1 (insecure), secp256k1 curves. Also Curve25519 and Curve448.
|
||||||
|
|
||||||
### > SHA1, SHA224, SHA256, SHA384, SHA512 digests
|
### > SHA1, SHA224, SHA256, SHA384, SHA512 digests
|
||||||
ECDSA and RSA signature can be combined with SHA digest in place.
|
ECDSA and RSA signature can be combined with SHA digest in place.
|
||||||
@@ -111,6 +111,21 @@ Public Key Authentication (PKA) allows to authenticate by using a secondary devi
|
|||||||
|
|
||||||
In PKA, the PIN is used for protecting the DKEK, as classic method with only PIN, and PKA is used for adding an extra security layer. Therefore, this mechanism provides a higher degree of security, since it needs a secondary Pico HSM to authenticate the primary one.
|
In PKA, the PIN is used for protecting the DKEK, as classic method with only PIN, and PKA is used for adding an extra security layer. Therefore, this mechanism provides a higher degree of security, since it needs a secondary Pico HSM to authenticate the primary one.
|
||||||
|
|
||||||
|
### > Secure Lock
|
||||||
|
An extra layer can be added to the device by adding a private key stored on the computer to lock that Pico HSM to the specific computer. The content will be completely encrypted with a private key only available from a specific computer.
|
||||||
|
|
||||||
|
### > ChaCha20-Poly1305
|
||||||
|
This is a novel fast and efficient symmetric encryption algorithm. Similarly to AES, it can be used to cipher your private data.
|
||||||
|
|
||||||
|
### > X25519 and X448
|
||||||
|
Both cruves Curve25519 and Curve448 are supported for doing DH X25519 and X448. Remember that cannot be used for signing.
|
||||||
|
|
||||||
|
### > Key Derivation Functions: HKDF, PBKDF2 and X963-KDF
|
||||||
|
It supports symmetric key derivations from different standards and RFC.
|
||||||
|
|
||||||
|
### > HMAC
|
||||||
|
It supports performing HMAC from a secret key on a arbitrary data with SHA digest algorithm.
|
||||||
|
|
||||||
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
|
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
|
||||||
[^2]: Available via SCS3 tool. See [SCS3](/doc/scs3.md "SCS3") for more information.
|
[^2]: Available via SCS3 tool. See [SCS3](/doc/scs3.md "SCS3") for more information.
|
||||||
[^3]: Imports are available only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process.
|
[^3]: Imports are available only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
VERSION_MAJOR="3"
|
VERSION_MAJOR="3"
|
||||||
VERSION_MINOR="0"
|
VERSION_MINOR="2"
|
||||||
|
|
||||||
rm -rf release/*
|
rm -rf release/*
|
||||||
cd build_release
|
cd build_release
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ PIN=648219
|
|||||||
## Initialization
|
## Initialization
|
||||||
The first step is to initialize the HSM. To do so, use the `pico-hsm-tool.py` in `tools` folder:
|
The first step is to initialize the HSM. To do so, use the `pico-hsm-tool.py` in `tools` folder:
|
||||||
```
|
```
|
||||||
$ python3 pico-hsm-tool initialize --so-pin 3537363231383830 --pin 648219
|
$ python3 pico-hsm-tool.py initialize --so-pin 3537363231383830 --pin 648219
|
||||||
```
|
```
|
||||||
The PIN number is used to manage all private keys in the device. It supports three attemps. After the third PIN failure, it gets blocked.
|
The PIN number is used to manage all private keys in the device. It supports three attemps. After the third PIN failure, it gets blocked.
|
||||||
The PIN accepts from 6 to 16 characters.
|
The PIN accepts from 6 to 16 characters.
|
||||||
|
|||||||
Submodule pico-hsm-sdk updated: 1e66e51595...fa54da973c
@@ -19,9 +19,130 @@
|
|||||||
#include "mbedtls/aes.h"
|
#include "mbedtls/aes.h"
|
||||||
#include "mbedtls/cmac.h"
|
#include "mbedtls/cmac.h"
|
||||||
#include "mbedtls/hkdf.h"
|
#include "mbedtls/hkdf.h"
|
||||||
|
#include "mbedtls/chachapoly.h"
|
||||||
|
#include "md_wrap.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
#include "crypto_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
#include "kek.h"
|
#include "kek.h"
|
||||||
|
#include "asn1.h"
|
||||||
|
#include "oid.h"
|
||||||
|
#include "mbedtls/pkcs5.h"
|
||||||
|
#include "mbedtls/error.h"
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
#include "mbedtls/cipher.h"
|
||||||
|
#include "mbedtls/oid.h"
|
||||||
|
|
||||||
|
/* This is copied from pkcs5.c Mbedtls */
|
||||||
|
/** Unfortunately it is declared as static, so I cannot call it. **/
|
||||||
|
|
||||||
|
static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params,
|
||||||
|
mbedtls_asn1_buf *salt, int *iterations,
|
||||||
|
int *keylen, mbedtls_md_type_t *md_type )
|
||||||
|
{
|
||||||
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||||
|
mbedtls_asn1_buf prf_alg_oid;
|
||||||
|
unsigned char *p = params->p;
|
||||||
|
const unsigned char *end = params->p + params->len;
|
||||||
|
|
||||||
|
if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE))
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
|
||||||
|
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) );
|
||||||
|
/*
|
||||||
|
* PBKDF2-params ::= SEQUENCE {
|
||||||
|
* salt OCTET STRING,
|
||||||
|
* iterationCount INTEGER,
|
||||||
|
* keyLength INTEGER OPTIONAL
|
||||||
|
* prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len,
|
||||||
|
MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret ) );
|
||||||
|
|
||||||
|
salt->p = p;
|
||||||
|
p += salt->len;
|
||||||
|
|
||||||
|
if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 )
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret ) );
|
||||||
|
|
||||||
|
if( p == end )
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 ) {
|
||||||
|
if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p == end )
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 )
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret ) );
|
||||||
|
|
||||||
|
if( mbedtls_oid_get_md_hmac( &prf_alg_oid, md_type ) != 0 )
|
||||||
|
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
||||||
|
|
||||||
|
if( p != end )
|
||||||
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
|
||||||
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Taken from https://github.com/Mbed-TLS/mbedtls/issues/2335 */
|
||||||
|
int mbedtls_ansi_x936_kdf(mbedtls_md_type_t md_type, size_t input_len, uint8_t *input, size_t shared_info_len, uint8_t *shared_info, size_t output_len, uint8_t *output) {
|
||||||
|
mbedtls_md_context_t md_ctx;
|
||||||
|
const mbedtls_md_info_t *md_info = NULL;
|
||||||
|
int hashlen = 0, exit_code = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
|
||||||
|
uint8_t counter_buf[4], tmp_output[64]; //worst case
|
||||||
|
|
||||||
|
mbedtls_md_init(&md_ctx);
|
||||||
|
|
||||||
|
md_info = mbedtls_md_info_from_type(md_type);
|
||||||
|
|
||||||
|
if (md_info == NULL) {
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_md_setup(&md_ctx, md_info, 0)) {
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_len + shared_info_len + 4 >= (1ULL<<61)-1) {
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keydatalen equals output_len
|
||||||
|
hashlen = md_info->size;
|
||||||
|
if (output_len >= hashlen * ((1ULL<<32)-1)) {
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, counter = 1; i < output_len; counter++) {
|
||||||
|
mbedtls_md_starts(&md_ctx);
|
||||||
|
mbedtls_md_update(&md_ctx, input, input_len);
|
||||||
|
|
||||||
|
//TODO: be careful with architecture little vs. big
|
||||||
|
counter_buf[0] = (uint8_t) ((counter >> 24) & 0xff);
|
||||||
|
counter_buf[1] = (uint8_t) ((counter >> 16) & 0xff);
|
||||||
|
counter_buf[2] = (uint8_t) ((counter >> 8) & 0xff);
|
||||||
|
counter_buf[3] = (uint8_t) ((counter >> 0) & 0xff);
|
||||||
|
|
||||||
|
mbedtls_md_update(&md_ctx, counter_buf, 4);
|
||||||
|
|
||||||
|
if (shared_info_len > 0 && shared_info != NULL) {
|
||||||
|
mbedtls_md_update(&md_ctx, shared_info, shared_info_len);
|
||||||
|
}
|
||||||
|
mbedtls_md_finish(&md_ctx, tmp_output);
|
||||||
|
memcpy(&output[i], tmp_output, (output_len - i < hashlen) ? output_len - i : hashlen);
|
||||||
|
i += hashlen;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
mbedtls_md_free(&md_ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_cipher_sym() {
|
int cmd_cipher_sym() {
|
||||||
int key_id = P1(apdu);
|
int key_id = P1(apdu);
|
||||||
@@ -33,9 +154,6 @@ int cmd_cipher_sym() {
|
|||||||
return SW_FILE_NOT_FOUND();
|
return SW_FILE_NOT_FOUND();
|
||||||
if (key_has_purpose(ef, algo) == false)
|
if (key_has_purpose(ef, algo) == false)
|
||||||
return SW_CONDITIONS_NOT_SATISFIED();
|
return SW_CONDITIONS_NOT_SATISFIED();
|
||||||
if ((apdu.nc % 16) != 0) {
|
|
||||||
return SW_WRONG_LENGTH();
|
|
||||||
}
|
|
||||||
if (wait_button_pressed() == true) // timeout
|
if (wait_button_pressed() == true) // timeout
|
||||||
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||||
int key_size = file_get_size(ef);
|
int key_size = file_get_size(ef);
|
||||||
@@ -45,6 +163,9 @@ int cmd_cipher_sym() {
|
|||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
if (algo == ALGO_AES_CBC_ENCRYPT || algo == ALGO_AES_CBC_DECRYPT) {
|
if (algo == ALGO_AES_CBC_ENCRYPT || algo == ALGO_AES_CBC_DECRYPT) {
|
||||||
|
if ((apdu.nc % 16) != 0) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
mbedtls_aes_context aes;
|
mbedtls_aes_context aes;
|
||||||
mbedtls_aes_init(&aes);
|
mbedtls_aes_init(&aes);
|
||||||
uint8_t tmp_iv[IV_SIZE];
|
uint8_t tmp_iv[IV_SIZE];
|
||||||
@@ -105,6 +226,129 @@ int cmd_cipher_sym() {
|
|||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
res_APDU_size = apdu.nc;
|
res_APDU_size = apdu.nc;
|
||||||
}
|
}
|
||||||
|
else if (algo == ALGO_EXT_CIPHER_ENCRYPT || algo == ALGO_EXT_CIPHER_DECRYPT) {
|
||||||
|
size_t oid_len = 0, aad_len = 0, iv_len = 0, enc_len = 0;
|
||||||
|
uint8_t *oid = NULL, *aad = NULL, *iv = NULL, *enc = NULL;
|
||||||
|
if (!asn1_find_tag(apdu.data, apdu.nc, 0x6, &oid_len, &oid) || oid_len == 0 || oid == NULL) {
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
asn1_find_tag(apdu.data, apdu.nc, 0x81, &enc_len, &enc);
|
||||||
|
asn1_find_tag(apdu.data, apdu.nc, 0x82, &iv_len, &iv);
|
||||||
|
asn1_find_tag(apdu.data, apdu.nc, 0x83, &aad_len, &aad);
|
||||||
|
uint8_t tmp_iv[16];
|
||||||
|
memset(tmp_iv, 0, sizeof(tmp_iv));
|
||||||
|
if (memcmp(oid, OID_CHACHA20_POLY1305, oid_len) == 0) {
|
||||||
|
if (algo == ALGO_EXT_CIPHER_DECRYPT && enc_len < 16) {
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
int r = 0;
|
||||||
|
mbedtls_chachapoly_context ctx;
|
||||||
|
mbedtls_chachapoly_init(&ctx);
|
||||||
|
if (algo == ALGO_EXT_CIPHER_ENCRYPT) {
|
||||||
|
r = mbedtls_chachapoly_encrypt_and_tag(&ctx, enc_len, iv ? iv : tmp_iv, aad, aad_len, enc, res_APDU, res_APDU + enc_len);
|
||||||
|
}
|
||||||
|
else if (algo == ALGO_EXT_CIPHER_DECRYPT) {
|
||||||
|
r = mbedtls_chachapoly_auth_decrypt(&ctx, enc_len - 16, iv ? iv : tmp_iv, aad, aad_len, enc + enc_len - 16, enc, res_APDU);
|
||||||
|
}
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
mbedtls_chachapoly_free(&ctx);
|
||||||
|
if (r != 0)
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
if (algo == ALGO_EXT_CIPHER_ENCRYPT)
|
||||||
|
res_APDU_size = enc_len + 16;
|
||||||
|
else if (algo == ALGO_EXT_CIPHER_DECRYPT)
|
||||||
|
res_APDU_size = enc_len - 16;
|
||||||
|
}
|
||||||
|
else if (memcmp(oid, OID_DIGEST, 7) == 0) {
|
||||||
|
const mbedtls_md_info_t *md_info = NULL;
|
||||||
|
if (memcmp(oid, OID_HMAC_SHA1, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
|
||||||
|
else if (memcmp(oid, OID_HMAC_SHA224, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA224);
|
||||||
|
else if (memcmp(oid, OID_HMAC_SHA256, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||||
|
else if (memcmp(oid, OID_HMAC_SHA384, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||||
|
else if (memcmp(oid, OID_HMAC_SHA512, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||||
|
if (md_info == NULL)
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
int r = mbedtls_md_hmac(md_info, kdata, key_size, apdu.data, apdu.nc, res_APDU);
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
if (r != 0)
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
res_APDU_size = md_info->size;
|
||||||
|
}
|
||||||
|
else if (memcmp(oid, OID_HKDF_SHA256, oid_len) == 0 || memcmp(oid, OID_HKDF_SHA384, oid_len) == 0 || memcmp(oid, OID_HKDF_SHA512, oid_len) == 0) {
|
||||||
|
const mbedtls_md_info_t *md_info = NULL;
|
||||||
|
if (memcmp(oid, OID_HKDF_SHA256, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||||
|
else if (memcmp(oid, OID_HKDF_SHA384, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||||
|
else if (memcmp(oid, OID_HKDF_SHA512, oid_len) == 0)
|
||||||
|
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||||
|
int r = mbedtls_hkdf(md_info, iv, iv_len, kdata, key_size, enc, enc_len, res_APDU, apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : mbedtls_md_get_size(md_info));
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
if (r != 0)
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
res_APDU_size = apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne :mbedtls_md_get_size(md_info);
|
||||||
|
}
|
||||||
|
else if (memcmp(oid, OID_PKCS5_PBKDF2, oid_len) == 0) {
|
||||||
|
int iterations = 0, keylen = 0;
|
||||||
|
mbedtls_asn1_buf salt, params = { .p = enc, .len = enc_len, .tag = (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) };
|
||||||
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
|
||||||
|
mbedtls_md_context_t md_ctx;
|
||||||
|
|
||||||
|
int r = pkcs5_parse_pbkdf2_params(¶ms, &salt, &iterations, &keylen, &md_type);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_md_init(&md_ctx);
|
||||||
|
if (mbedtls_md_setup(&md_ctx, mbedtls_md_info_from_type(md_type), 1) != 0) {
|
||||||
|
mbedtls_md_free(&md_ctx);
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
r = mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, kdata, key_size, salt.p, salt.len, iterations, keylen ? keylen : (apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : 32), res_APDU);
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
mbedtls_md_free(&md_ctx);
|
||||||
|
if (r != 0)
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
res_APDU_size = keylen ? keylen : (apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : 32);
|
||||||
|
}
|
||||||
|
else if (memcmp(oid, OID_PKCS5_PBES2, oid_len) == 0) {
|
||||||
|
mbedtls_asn1_buf params = { .p = aad, .len = aad_len, .tag = (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) };
|
||||||
|
int r = mbedtls_pkcs5_pbes2(¶ms, algo == ALGO_EXT_CIPHER_ENCRYPT ? MBEDTLS_PKCS5_ENCRYPT : MBEDTLS_PKCS5_DECRYPT, kdata, key_size, enc, enc_len, res_APDU);
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
res_APDU_size = enc_len;
|
||||||
|
}
|
||||||
|
else if (memcmp(oid, OID_KDF_X963, oid_len) == 0) {
|
||||||
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
|
||||||
|
if (memcmp(enc, OID_HMAC_SHA1, enc_len) == 0)
|
||||||
|
md_type = MBEDTLS_MD_SHA1;
|
||||||
|
else if (memcmp(enc, OID_HMAC_SHA224, enc_len) == 0)
|
||||||
|
md_type = MBEDTLS_MD_SHA224;
|
||||||
|
else if (memcmp(enc, OID_HMAC_SHA256, enc_len) == 0)
|
||||||
|
md_type = MBEDTLS_MD_SHA256;
|
||||||
|
else if (memcmp(enc, OID_HMAC_SHA384, enc_len) == 0)
|
||||||
|
md_type = MBEDTLS_MD_SHA384;
|
||||||
|
else if (memcmp(enc, OID_HMAC_SHA512, enc_len) == 0)
|
||||||
|
md_type = MBEDTLS_MD_SHA512;
|
||||||
|
int r = mbedtls_ansi_x936_kdf(md_type, key_size, kdata, aad_len, aad, apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : 32, res_APDU);
|
||||||
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
res_APDU_size = apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||||
return SW_WRONG_P1P2();
|
return SW_WRONG_P1P2();
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ int cmd_decrypt_asym() {
|
|||||||
size_t olen = 0;
|
size_t olen = 0;
|
||||||
res_APDU[0] = 0x04;
|
res_APDU[0] = 0x04;
|
||||||
r = mbedtls_ecdh_calc_secret(&ctx, &olen, res_APDU+1, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
|
r = mbedtls_ecdh_calc_secret(&ctx, &olen, res_APDU+1, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
|
||||||
if (r != 0) {
|
|
||||||
mbedtls_ecdh_free(&ctx);
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
if (p2 == ALGO_EC_DH)
|
if (p2 == ALGO_EC_DH)
|
||||||
@@ -161,7 +161,6 @@ int cmd_decrypt_asym() {
|
|||||||
}
|
}
|
||||||
return SW_REFERENCE_NOT_FOUND();
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
mbedtls_ecdh_free(&ctx);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return SW_WRONG_P1P2();
|
return SW_WRONG_P1P2();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "mbedtls/ecdsa.h"
|
#include "mbedtls/ecdsa.h"
|
||||||
#include "crypto_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
|
#include "cvc.h"
|
||||||
|
|
||||||
#define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED -0x006E
|
#define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED -0x006E
|
||||||
#define MOD_ADD( N ) \
|
#define MOD_ADD( N ) \
|
||||||
@@ -72,29 +72,24 @@ int cmd_derive_asym() {
|
|||||||
return SW_DATA_INVALID();
|
return SW_DATA_INVALID();
|
||||||
}
|
}
|
||||||
r = mbedtls_mpi_add_mod(&ctx.grp, &nd, &ctx.d, &a);
|
r = mbedtls_mpi_add_mod(&ctx.grp, &nd, &ctx.d, &a);
|
||||||
|
mbedtls_mpi_free(&a);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
mbedtls_ecdsa_free(&ctx);
|
mbedtls_ecdsa_free(&ctx);
|
||||||
mbedtls_mpi_free(&a);
|
|
||||||
mbedtls_mpi_free(&nd);
|
mbedtls_mpi_free(&nd);
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
r = mbedtls_mpi_copy(&ctx.d, &nd);
|
r = mbedtls_mpi_copy(&ctx.d, &nd);
|
||||||
|
mbedtls_mpi_free(&nd);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
mbedtls_ecdsa_free(&ctx);
|
mbedtls_ecdsa_free(&ctx);
|
||||||
mbedtls_mpi_free(&a);
|
|
||||||
mbedtls_mpi_free(&nd);
|
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
r = store_keys(&ctx, HSM_KEY_EC, dest_id);
|
r = store_keys(&ctx, HSM_KEY_EC, dest_id);
|
||||||
if (r != CCID_OK) {
|
if (r != CCID_OK) {
|
||||||
mbedtls_ecdsa_free(&ctx);
|
mbedtls_ecdsa_free(&ctx);
|
||||||
mbedtls_mpi_free(&a);
|
|
||||||
mbedtls_mpi_free(&nd);
|
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
mbedtls_ecdsa_free(&ctx);
|
mbedtls_ecdsa_free(&ctx);
|
||||||
mbedtls_mpi_free(&a);
|
|
||||||
mbedtls_mpi_free(&nd);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return SW_WRONG_DATA();
|
return SW_WRONG_DATA();
|
||||||
|
|||||||
@@ -15,14 +15,20 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "mbedtls/ecdh.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
#include "hardware/rtc.h"
|
#include "hardware/rtc.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "kek.h"
|
||||||
|
#include "mbedtls/hkdf.h"
|
||||||
|
#include "mbedtls/chachapoly.h"
|
||||||
|
|
||||||
int cmd_extras() {
|
int cmd_extras() {
|
||||||
|
if (P1(apdu) == 0xA) { //datetime operations
|
||||||
if (P2(apdu) != 0x0)
|
if (P2(apdu) != 0x0)
|
||||||
return SW_INCORRECT_P1P2();
|
return SW_INCORRECT_P1P2();
|
||||||
if (P1(apdu) == 0xA) { //datetime operations
|
|
||||||
if (apdu.nc == 0) {
|
if (apdu.nc == 0) {
|
||||||
datetime_t dt;
|
datetime_t dt;
|
||||||
if (!rtc_get_datetime(&dt))
|
if (!rtc_get_datetime(&dt))
|
||||||
@@ -52,6 +58,8 @@ int cmd_extras() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (P1(apdu) == 0x6) { //dynamic options
|
else if (P1(apdu) == 0x6) { //dynamic options
|
||||||
|
if (P2(apdu) != 0x0)
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
if (apdu.nc > sizeof(uint8_t))
|
if (apdu.nc > sizeof(uint8_t))
|
||||||
return SW_WRONG_LENGTH();
|
return SW_WRONG_LENGTH();
|
||||||
uint16_t opts = get_device_options();
|
uint16_t opts = get_device_options();
|
||||||
@@ -66,6 +74,86 @@ int cmd_extras() {
|
|||||||
low_flash_available();
|
low_flash_available();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (P1(apdu) == 0x3A) { // secure lock
|
||||||
|
if (apdu.nc == 0) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
if (P2(apdu) == 0x01) { // Key Agreement
|
||||||
|
mbedtls_ecdh_context hkey;
|
||||||
|
mbedtls_ecdh_init(&hkey);
|
||||||
|
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
|
||||||
|
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
|
||||||
|
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
|
||||||
|
ret = mbedtls_ecp_point_read_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, apdu.data, apdu.nc);
|
||||||
|
if (ret != 0) {
|
||||||
|
mbedtls_ecdh_free(&hkey);
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
memcpy(mse.Qpt, apdu.data, sizeof(mse.Qpt));
|
||||||
|
|
||||||
|
uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
|
||||||
|
size_t olen = 0;
|
||||||
|
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
mbedtls_ecdh_free(&hkey);
|
||||||
|
mbedtls_platform_zeroize(buf, sizeof(buf));
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc));
|
||||||
|
mbedtls_platform_zeroize(buf, sizeof(buf));
|
||||||
|
if (ret != 0) {
|
||||||
|
mbedtls_ecdh_free(&hkey);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 4096);
|
||||||
|
mbedtls_ecdh_free(&hkey);
|
||||||
|
if (ret != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
mse.init = true;
|
||||||
|
res_APDU_size = olen;
|
||||||
|
}
|
||||||
|
else if (P2(apdu) == 0x02 || P2(apdu) == 0x03 || P2(apdu) == 0x04) {
|
||||||
|
if (mse.init == false)
|
||||||
|
return SW_COMMAND_NOT_ALLOWED();
|
||||||
|
|
||||||
|
int ret = mse_decrypt_ct(apdu.data, apdu.nc);
|
||||||
|
if (ret != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (P2(apdu) == 0x02 || P2(apdu) == 0x04) { // Enable
|
||||||
|
uint16_t opts = get_device_options();
|
||||||
|
uint8_t newopts[] = { opts >> 8, (opts & 0xff) };
|
||||||
|
if ((P2(apdu) == 0x02 && !(opts & HSM_OPT_SECURE_LOCK)) || (P2(apdu) == 0x04 && (opts & HSM_OPT_SECURE_LOCK))) {
|
||||||
|
uint16_t tfids[] = { EF_MKEK, EF_MKEK_SO };
|
||||||
|
for (int t = 0; t < sizeof(tfids)/sizeof(uint16_t); t++) {
|
||||||
|
file_t *tf = search_by_fid(tfids[t], NULL, SPECIFY_EF);
|
||||||
|
if (tf) {
|
||||||
|
uint8_t *tmp = (uint8_t *)calloc(1, file_get_size(tf));
|
||||||
|
memcpy(tmp, file_get_data(tf), file_get_size(tf));
|
||||||
|
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
|
||||||
|
MKEK_KEY(tmp)[i] ^= apdu.data[i];
|
||||||
|
}
|
||||||
|
flash_write_data_to_file(tf, tmp, file_get_size(tf));
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (P2(apdu) == 0x02)
|
||||||
|
newopts[0] |= HSM_OPT_SECURE_LOCK >> 8;
|
||||||
|
else if (P2(apdu) == 0x04)
|
||||||
|
newopts[0] &= ~HSM_OPT_SECURE_LOCK >> 8;
|
||||||
|
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
||||||
|
flash_write_data_to_file(tf, newopts, sizeof(newopts));
|
||||||
|
low_flash_available();
|
||||||
|
}
|
||||||
|
else if (P2(apdu) == 0x03) {
|
||||||
|
memcpy(mkek_mask, apdu.data, apdu.nc);
|
||||||
|
has_mkek_mask = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return SW_INCORRECT_P1P2();
|
return SW_INCORRECT_P1P2();
|
||||||
return SW_OK();
|
return SW_OK();
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ int cmd_general_authenticate() {
|
|||||||
sm_derive_all_keys(derived, olen);
|
sm_derive_all_keys(derived, olen);
|
||||||
|
|
||||||
uint8_t *t = (uint8_t *)calloc(1, pubkey_len+16);
|
uint8_t *t = (uint8_t *)calloc(1, pubkey_len+16);
|
||||||
memcpy(t, "\x7F\x49\x3F\x06\x0A", 5);
|
memcpy(t, "\x7F\x49\x4F\x06\x0A", 5);
|
||||||
if (sm_get_protocol() == MSE_AES)
|
if (sm_get_protocol() == MSE_AES)
|
||||||
memcpy(t+5, OID_ID_CA_ECDH_AES_CBC_CMAC_128, 10);
|
memcpy(t+5, OID_ID_CA_ECDH_AES_CBC_CMAC_128, 10);
|
||||||
t[15] = 0x86;
|
t[15] = 0x86;
|
||||||
|
|||||||
@@ -122,14 +122,18 @@ int cmd_keypair_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((res_APDU_size = asn1_cvc_aut(&ecdsa, HSM_KEY_EC, res_APDU, 4096, ext, ext_len)) == 0) {
|
if ((res_APDU_size = asn1_cvc_aut(&ecdsa, HSM_KEY_EC, res_APDU, 4096, ext, ext_len)) == 0) {
|
||||||
|
if (ext)
|
||||||
|
free(ext);
|
||||||
|
mbedtls_ecdsa_free(&ecdsa);
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
|
if (ext)
|
||||||
|
free(ext);
|
||||||
ret = store_keys(&ecdsa, HSM_KEY_EC, key_id);
|
ret = store_keys(&ecdsa, HSM_KEY_EC, key_id);
|
||||||
if (ret != CCID_OK) {
|
|
||||||
mbedtls_ecdsa_free(&ecdsa);
|
mbedtls_ecdsa_free(&ecdsa);
|
||||||
|
if (ret != CCID_OK) {
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
mbedtls_ecdsa_free(&ecdsa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -142,8 +146,8 @@ int cmd_keypair_gen() {
|
|||||||
ret = flash_write_data_to_file(fpk, res_APDU, res_APDU_size);
|
ret = flash_write_data_to_file(fpk, res_APDU, res_APDU_size);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
if (apdu.ne == 0)
|
//if (apdu.ne == 0)
|
||||||
apdu.ne = res_APDU_size;
|
// apdu.ne = res_APDU_size;
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ size_t asn1_cvc_public_key_ecdsa(mbedtls_ecdsa_context *ecdsa, uint8_t *buf, siz
|
|||||||
size_t b_size = mbedtls_mpi_size(&ecdsa->grp.B), g_size = 1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.X);
|
size_t b_size = mbedtls_mpi_size(&ecdsa->grp.B), g_size = 1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.X);
|
||||||
size_t o_size = mbedtls_mpi_size(&ecdsa->grp.N), y_size = 1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.X);
|
size_t o_size = mbedtls_mpi_size(&ecdsa->grp.N), y_size = 1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.X);
|
||||||
size_t c_size = 1;
|
size_t c_size = 1;
|
||||||
size_t ptot_size = asn1_len_tag(0x81, p_size), atot_size = asn1_len_tag(0x82, a_size ? a_size : (pointA[ecdsa->grp.id] ? p_size : 0));
|
size_t ptot_size = asn1_len_tag(0x81, p_size), atot_size = asn1_len_tag(0x82, a_size ? a_size : (pointA[ecdsa->grp.id] && ecdsa->grp.id < 6 ? p_size : 1));
|
||||||
size_t btot_size = asn1_len_tag(0x83, b_size), gtot_size = asn1_len_tag(0x84, g_size);
|
size_t btot_size = asn1_len_tag(0x83, b_size), gtot_size = asn1_len_tag(0x84, g_size);
|
||||||
size_t otot_size = asn1_len_tag(0x85, o_size), ytot_size = asn1_len_tag(0x86, y_size);
|
size_t otot_size = asn1_len_tag(0x85, o_size), ytot_size = asn1_len_tag(0x86, y_size);
|
||||||
size_t ctot_size = asn1_len_tag(0x87, c_size);
|
size_t ctot_size = asn1_len_tag(0x87, c_size);
|
||||||
@@ -90,11 +90,12 @@ size_t asn1_cvc_public_key_ecdsa(mbedtls_ecdsa_context *ecdsa, uint8_t *buf, siz
|
|||||||
*p++ = 0x82; p += format_tlv_len(a_size, p); mbedtls_mpi_write_binary(&ecdsa->grp.A, p, a_size); p += a_size;
|
*p++ = 0x82; p += format_tlv_len(a_size, p); mbedtls_mpi_write_binary(&ecdsa->grp.A, p, a_size); p += a_size;
|
||||||
}
|
}
|
||||||
else { //mbedtls does not set point A for some curves
|
else { //mbedtls does not set point A for some curves
|
||||||
if (pointA[ecdsa->grp.id]) {
|
if (pointA[ecdsa->grp.id] && ecdsa->grp.id < 6) {
|
||||||
*p++ = 0x82; p += format_tlv_len(p_size, p); memcpy(p, pointA[ecdsa->grp.id], p_size); p += p_size;
|
*p++ = 0x82; p += format_tlv_len(p_size, p); memcpy(p, pointA[ecdsa->grp.id], p_size); p += p_size;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*p++ = 0x82; p += format_tlv_len(0, p);
|
*p++ = 0x82; p += format_tlv_len(1, p);
|
||||||
|
*p++ = 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//B
|
//B
|
||||||
@@ -108,7 +109,13 @@ size_t asn1_cvc_public_key_ecdsa(mbedtls_ecdsa_context *ecdsa, uint8_t *buf, siz
|
|||||||
size_t y_new_size = 0;
|
size_t y_new_size = 0;
|
||||||
*p++ = 0x86; p += format_tlv_len(y_size, p); mbedtls_ecp_point_write_binary(&ecdsa->grp, &ecdsa->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &y_new_size, p, y_size); p += y_size;
|
*p++ = 0x86; p += format_tlv_len(y_size, p); mbedtls_ecp_point_write_binary(&ecdsa->grp, &ecdsa->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &y_new_size, p, y_size); p += y_size;
|
||||||
//cofactor
|
//cofactor
|
||||||
*p++ = 0x87; p += format_tlv_len(c_size, p); *p++ = 1;
|
*p++ = 0x87; p += format_tlv_len(c_size, p);
|
||||||
|
if (ecdsa->grp.id == MBEDTLS_ECP_DP_CURVE448)
|
||||||
|
*p++ = 4;
|
||||||
|
else if (ecdsa->grp.id == MBEDTLS_ECP_DP_CURVE25519)
|
||||||
|
*p++ = 8;
|
||||||
|
else
|
||||||
|
*p++ = 1;
|
||||||
return tot_len;
|
return tot_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +195,7 @@ size_t asn1_cvc_cert(void *rsa_ecdsa, uint8_t key_type, uint8_t *buf, size_t buf
|
|||||||
p += format_tlv_len(key_size, p);
|
p += format_tlv_len(key_size, p);
|
||||||
if (key_type == HSM_KEY_RSA) {
|
if (key_type == HSM_KEY_RSA) {
|
||||||
if (mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa_ecdsa, random_gen, NULL, MBEDTLS_MD_SHA256, 32, hsh, p) != 0)
|
if (mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa_ecdsa, random_gen, NULL, MBEDTLS_MD_SHA256, 32, hsh, p) != 0)
|
||||||
return 0;
|
memset(p, 0, key_size);
|
||||||
p += key_size;
|
p += key_size;
|
||||||
}
|
}
|
||||||
else if (key_type == HSM_KEY_EC) {
|
else if (key_type == HSM_KEY_EC) {
|
||||||
@@ -198,13 +205,14 @@ size_t asn1_cvc_cert(void *rsa_ecdsa, uint8_t key_type, uint8_t *buf, size_t buf
|
|||||||
mbedtls_mpi_init(&r);
|
mbedtls_mpi_init(&r);
|
||||||
mbedtls_mpi_init(&s);
|
mbedtls_mpi_init(&s);
|
||||||
ret = mbedtls_ecdsa_sign(&ecdsa->grp, &r, &s, &ecdsa->d, hsh, sizeof(hsh), random_gen, NULL);
|
ret = mbedtls_ecdsa_sign(&ecdsa->grp, &r, &s, &ecdsa->d, hsh, sizeof(hsh), random_gen, NULL);
|
||||||
if (ret != 0) {
|
if (ret == 0) {
|
||||||
mbedtls_mpi_free(&r);
|
|
||||||
mbedtls_mpi_free(&s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mbedtls_mpi_write_binary(&r, p, mbedtls_mpi_size(&r)); p += mbedtls_mpi_size(&r);
|
mbedtls_mpi_write_binary(&r, p, mbedtls_mpi_size(&r)); p += mbedtls_mpi_size(&r);
|
||||||
mbedtls_mpi_write_binary(&s, p, mbedtls_mpi_size(&s)); p += mbedtls_mpi_size(&s);
|
mbedtls_mpi_write_binary(&s, p, mbedtls_mpi_size(&s)); p += mbedtls_mpi_size(&s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset(p, 0, key_size);
|
||||||
|
p += key_size;
|
||||||
|
}
|
||||||
mbedtls_mpi_free(&r);
|
mbedtls_mpi_free(&r);
|
||||||
mbedtls_mpi_free(&s);
|
mbedtls_mpi_free(&s);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,13 @@
|
|||||||
#include "mbedtls/cmac.h"
|
#include "mbedtls/cmac.h"
|
||||||
#include "mbedtls/rsa.h"
|
#include "mbedtls/rsa.h"
|
||||||
#include "mbedtls/ecdsa.h"
|
#include "mbedtls/ecdsa.h"
|
||||||
|
#include "mbedtls/chachapoly.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
|
||||||
extern bool has_session_pin, has_session_sopin;
|
extern bool has_session_pin, has_session_sopin;
|
||||||
extern uint8_t session_pin[32], session_sopin[32];
|
extern uint8_t session_pin[32], session_sopin[32];
|
||||||
|
uint8_t mkek_mask[MKEK_KEY_SIZE];
|
||||||
|
bool has_mkek_mask = false;
|
||||||
|
|
||||||
#define POLY 0xedb88320
|
#define POLY 0xedb88320
|
||||||
|
|
||||||
@@ -65,6 +68,12 @@ int load_mkek(uint8_t *mkek) {
|
|||||||
}
|
}
|
||||||
if (pin == NULL) //Should never happen
|
if (pin == NULL) //Should never happen
|
||||||
return CCID_EXEC_ERROR;
|
return CCID_EXEC_ERROR;
|
||||||
|
|
||||||
|
if (has_mkek_mask) {
|
||||||
|
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
|
||||||
|
MKEK_KEY(mkek)[i] ^= mkek_mask[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE+MKEK_KEY_CS_SIZE);
|
int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE+MKEK_KEY_CS_SIZE);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return CCID_EXEC_ERROR;
|
return CCID_EXEC_ERROR;
|
||||||
@@ -73,6 +82,17 @@ int load_mkek(uint8_t *mkek) {
|
|||||||
return CCID_OK;
|
return CCID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mse_t mse = {.init = false};
|
||||||
|
|
||||||
|
int mse_decrypt_ct(uint8_t *data, size_t len) {
|
||||||
|
mbedtls_chachapoly_context chatx;
|
||||||
|
mbedtls_chachapoly_init(&chatx);
|
||||||
|
mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12);
|
||||||
|
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, len - 16, mse.key_enc, mse.Qpt, 65, data + len - 16, data, data);
|
||||||
|
mbedtls_chachapoly_free(&chatx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int load_dkek(uint8_t id, uint8_t *dkek) {
|
int load_dkek(uint8_t id, uint8_t *dkek) {
|
||||||
file_t *tf = search_dynamic_file(EF_DKEK+id);
|
file_t *tf = search_dynamic_file(EF_DKEK+id);
|
||||||
if (!tf)
|
if (!tf)
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#ifndef _DKEK_H_
|
#ifndef _DKEK_H_
|
||||||
#define _DKEK_H_
|
#define _DKEK_H_
|
||||||
|
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
|
||||||
extern int load_mkek(uint8_t *);
|
extern int load_mkek(uint8_t *);
|
||||||
extern int store_mkek(const uint8_t *);
|
extern int store_mkek(const uint8_t *);
|
||||||
extern int save_dkek_key(uint8_t, const uint8_t *key);
|
extern int save_dkek_key(uint8_t, const uint8_t *key);
|
||||||
@@ -45,4 +47,16 @@ extern int dkek_decode_key(uint8_t, void *key_ctx, const uint8_t *in, size_t in_
|
|||||||
#define MKEK_CHECKSUM(p) (MKEK_KEY(p)+MKEK_KEY_SIZE)
|
#define MKEK_CHECKSUM(p) (MKEK_KEY(p)+MKEK_KEY_SIZE)
|
||||||
#define DKEK_KEY_SIZE (32)
|
#define DKEK_KEY_SIZE (32)
|
||||||
|
|
||||||
|
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
|
||||||
|
extern bool has_mkek_mask;
|
||||||
|
|
||||||
|
typedef struct mse {
|
||||||
|
uint8_t Qpt[65];
|
||||||
|
uint8_t key_enc[12 + 32];
|
||||||
|
bool init;
|
||||||
|
} mse_t;
|
||||||
|
extern mse_t mse;
|
||||||
|
|
||||||
|
extern int mse_decrypt_ct(uint8_t *, size_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,6 +23,22 @@
|
|||||||
|
|
||||||
#define OID_BSI_DE "\x04\x00\x7F\x00\x07"
|
#define OID_BSI_DE "\x04\x00\x7F\x00\x07"
|
||||||
|
|
||||||
|
#define OID_ECKA OID_BSI_DE "\x01\x01\x05"
|
||||||
|
#define OID_ECKA_EG OID_ECKA "\x01"
|
||||||
|
#define OID_ECKA_EG_X963KDF OID_ECKA_EG "\x01"
|
||||||
|
#define OID_ECKA_EG_X963KDF_SHA1 OID_ECKA_EG_X963KDF "\x01"
|
||||||
|
#define OID_ECKA_EG_X963KDF_SHA224 OID_ECKA_EG_X963KDF "\x02"
|
||||||
|
#define OID_ECKA_EG_X963KDF_SHA256 OID_ECKA_EG_X963KDF "\x03"
|
||||||
|
#define OID_ECKA_EG_X963KDF_SHA384 OID_ECKA_EG_X963KDF "\x04"
|
||||||
|
#define OID_ECKA_EG_X963KDF_SHA512 OID_ECKA_EG_X963KDF "\x05"
|
||||||
|
#define OID_ECKA_DH OID_ECKA "\x02"
|
||||||
|
#define OID_ECKA_DH_X963KDF OID_ECKA_DH "\x01"
|
||||||
|
#define OID_ECKA_DH_X963KDF_SHA1 OID_ECKA_DH_X963KDF "\x01"
|
||||||
|
#define OID_ECKA_DH_X963KDF_SHA224 OID_ECKA_DH_X963KDF "\x02"
|
||||||
|
#define OID_ECKA_DH_X963KDF_SHA256 OID_ECKA_DH_X963KDF "\x03"
|
||||||
|
#define OID_ECKA_DH_X963KDF_SHA384 OID_ECKA_DH_X963KDF "\x04"
|
||||||
|
#define OID_ECKA_DH_X963KDF_SHA512 OID_ECKA_DH_X963KDF "\x05"
|
||||||
|
|
||||||
#define OID_ID_PK OID_BSI_DE "\x02\x02\x01"
|
#define OID_ID_PK OID_BSI_DE "\x02\x02\x01"
|
||||||
#define OID_ID_PK_DH OID_ID_PK "\x01"
|
#define OID_ID_PK_DH OID_ID_PK "\x01"
|
||||||
#define OID_ID_PK_ECDH OID_ID_PK "\x02"
|
#define OID_ID_PK_ECDH OID_ID_PK "\x02"
|
||||||
@@ -103,4 +119,32 @@
|
|||||||
#define OID_CC_FF_PKA OID_CC_FORMAT "\x03"
|
#define OID_CC_FF_PKA OID_CC_FORMAT "\x03"
|
||||||
#define OID_CC_FF_KDA OID_CC_FORMAT "\x04"
|
#define OID_CC_FF_KDA OID_CC_FORMAT "\x04"
|
||||||
|
|
||||||
|
#define OID_RSADSI "\x2A\x86\x48\x86\xF7\x0D"
|
||||||
|
|
||||||
|
#define OID_PKCS OID_RSADSI "\x01"
|
||||||
|
|
||||||
|
#define OID_PKCS_5 OID_PKCS "\x05"
|
||||||
|
#define OID_PKCS5_PBKDF2 OID_PKCS_5 "\x0C"
|
||||||
|
#define OID_PKCS5_PBES2 OID_PKCS_5 "\x0D"
|
||||||
|
|
||||||
|
#define OID_PKCS_9 OID_PKCS "\x09"
|
||||||
|
|
||||||
|
#define OID_PKCS9_SMIME_ALG OID_PKCS_9 "\x10\x03"
|
||||||
|
|
||||||
|
#define OID_CHACHA20_POLY1305 OID_PKCS9_SMIME_ALG "\x12"
|
||||||
|
#define OID_HKDF_SHA256 OID_PKCS9_SMIME_ALG "\x1D"
|
||||||
|
#define OID_HKDF_SHA384 OID_PKCS9_SMIME_ALG "\x1E"
|
||||||
|
#define OID_HKDF_SHA512 OID_PKCS9_SMIME_ALG "\x1F"
|
||||||
|
|
||||||
|
|
||||||
|
#define OID_DIGEST OID_RSADSI "\x02"
|
||||||
|
|
||||||
|
#define OID_HMAC_SHA1 OID_DIGEST "\x07"
|
||||||
|
#define OID_HMAC_SHA224 OID_DIGEST "\x08"
|
||||||
|
#define OID_HMAC_SHA256 OID_DIGEST "\x09"
|
||||||
|
#define OID_HMAC_SHA384 OID_DIGEST "\x0A"
|
||||||
|
#define OID_HMAC_SHA512 OID_DIGEST "\x0B"
|
||||||
|
|
||||||
|
#define OID_KDF_X963 "\x2B\x81\x05\x10\x86\x48\x3F"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -647,7 +647,9 @@ static const cmd_t cmds[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int sc_hsm_process_apdu() {
|
int sc_hsm_process_apdu() {
|
||||||
sm_unwrap();
|
int r = sm_unwrap();
|
||||||
|
if (r != CCID_OK)
|
||||||
|
return SW_DATA_INVALID();
|
||||||
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
||||||
if (cmd->ins == INS(apdu)) {
|
if (cmd->ins == INS(apdu)) {
|
||||||
int r = cmd->cmd_handler();
|
int r = cmd->cmd_handler();
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define ALGO_AES_CBC_ENCRYPT 0x10
|
#define ALGO_AES_CBC_ENCRYPT 0x10
|
||||||
#define ALGO_AES_CBC_DECRYPT 0x11
|
#define ALGO_AES_CBC_DECRYPT 0x11
|
||||||
#define ALGO_AES_CMAC 0x18
|
#define ALGO_AES_CMAC 0x18
|
||||||
|
#define ALGO_EXT_CIPHER_ENCRYPT 0x51 /* Extended ciphering Encrypt */
|
||||||
|
#define ALGO_EXT_CIPHER_DECRYPT 0x52 /* Extended ciphering Decrypt */
|
||||||
#define ALGO_AES_DERIVE 0x99
|
#define ALGO_AES_DERIVE 0x99
|
||||||
|
|
||||||
#define HSM_OPT_RRC 0x0001
|
#define HSM_OPT_RRC 0x0001
|
||||||
@@ -77,6 +79,7 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define HSM_OPT_RRC_RESET_ONLY 0x0020
|
#define HSM_OPT_RRC_RESET_ONLY 0x0020
|
||||||
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
|
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
|
||||||
#define HSM_OPT_KEY_COUNTER_ALL 0x0200
|
#define HSM_OPT_KEY_COUNTER_ALL 0x0200
|
||||||
|
#define HSM_OPT_SECURE_LOCK 0x0400
|
||||||
|
|
||||||
#define PRKD_PREFIX 0xC4 /* Hi byte in file identifier for PKCS#15 PRKD objects */
|
#define PRKD_PREFIX 0xC4 /* Hi byte in file identifier for PKCS#15 PRKD objects */
|
||||||
#define CD_PREFIX 0xC8 /* Hi byte in file identifier for PKCS#15 CD objects */
|
#define CD_PREFIX 0xC8 /* Hi byte in file identifier for PKCS#15 CD objects */
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#ifndef __VERSION_H_
|
#ifndef __VERSION_H_
|
||||||
#define __VERSION_H_
|
#define __VERSION_H_
|
||||||
|
|
||||||
#define HSM_VERSION 0x0300
|
#define HSM_VERSION 0x0302
|
||||||
|
|
||||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||||
|
|||||||
386
tools/pico-hsm-tool.py
Executable file → Normal file
386
tools/pico-hsm-tool.py
Executable file → Normal file
@@ -19,46 +19,91 @@
|
|||||||
*/
|
*/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from smartcard.CardType import AnyCardType
|
import sys
|
||||||
from smartcard.CardRequest import CardRequest
|
try:
|
||||||
from smartcard.Exceptions import CardRequestTimeoutException
|
from smartcard.CardType import AnyCardType
|
||||||
from cvc.certificates import CVC
|
from smartcard.CardRequest import CardRequest
|
||||||
from cvc.asn1 import ASN1
|
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
|
||||||
from cvc.oid import oid2scheme
|
except ModuleNotFoundError:
|
||||||
from cvc.utils import scheme_rsa
|
print('ERROR: smarctard module not found! Install pyscard package.\nTry with `pip install pyscard`')
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
sys.exit(-1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cvc.certificates import CVC
|
||||||
|
from cvc.asn1 import ASN1
|
||||||
|
from cvc.oid import oid2scheme
|
||||||
|
from cvc.utils import scheme_rsa
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
print('ERROR: cvc module not found! Install pycvc package.\nTry with `pip install pycvc`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||||
|
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
||||||
|
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import base64
|
import base64
|
||||||
from binascii import hexlify
|
from binascii import hexlify, unhexlify
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from argparse import RawTextHelpFormatter
|
from argparse import RawTextHelpFormatter
|
||||||
|
|
||||||
|
pin = None
|
||||||
|
|
||||||
class APDUResponse(Exception):
|
class APDUResponse(Exception):
|
||||||
def __init__(self, sw1, sw2):
|
def __init__(self, sw1, sw2):
|
||||||
self.sw1 = sw1
|
self.sw1 = sw1
|
||||||
self.sw2 = sw2
|
self.sw2 = sw2
|
||||||
super().__init__(f'SW:{sw1:02X}{sw2:02X}')
|
super().__init__(f'SW:{sw1:02X}{sw2:02X}')
|
||||||
|
|
||||||
|
def hexy(a):
|
||||||
|
return [hex(i) for i in a]
|
||||||
|
|
||||||
def send_apdu(card, command, p1, p2, data=None):
|
def send_apdu(card, command, p1, p2, data=None, ne=None):
|
||||||
lc = []
|
lc = []
|
||||||
dataf = []
|
dataf = []
|
||||||
if (data):
|
if (data):
|
||||||
lc = [0x00] + list(len(data).to_bytes(2, 'big'))
|
lc = [0x00] + list(len(data).to_bytes(2, 'big'))
|
||||||
dataf = data
|
dataf = data
|
||||||
|
if (ne is None):
|
||||||
le = [0x00, 0x00]
|
le = [0x00, 0x00]
|
||||||
|
else:
|
||||||
|
le = list(ne.to_bytes(2, 'big'))
|
||||||
if (isinstance(command, list) and len(command) > 1):
|
if (isinstance(command, list) and len(command) > 1):
|
||||||
apdu = command
|
apdu = command
|
||||||
else:
|
else:
|
||||||
apdu = [0x00, command]
|
apdu = [0x00, command]
|
||||||
|
|
||||||
apdu = apdu + [p1, p2] + lc + dataf + le
|
apdu = apdu + [p1, p2] + lc + dataf + le
|
||||||
|
try:
|
||||||
|
response, sw1, sw2 = card.connection.transmit(apdu)
|
||||||
|
except CardConnectionException:
|
||||||
|
card.connection.reconnect()
|
||||||
response, sw1, sw2 = card.connection.transmit(apdu)
|
response, sw1, sw2 = card.connection.transmit(apdu)
|
||||||
if (sw1 != 0x90):
|
if (sw1 != 0x90):
|
||||||
|
if (sw1 == 0x6A and sw2 == 0x82):
|
||||||
|
response, sw1, sw2 = card.connection.transmit([0x00, 0xA4, 0x04, 0x00, 0xB, 0xE8, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xC3, 0x1F, 0x02, 0x01, 0x0])
|
||||||
|
if (sw1 == 0x90):
|
||||||
|
response, sw1, sw2 = card.connection.transmit(apdu)
|
||||||
|
if (sw1 == 0x90):
|
||||||
|
return response
|
||||||
|
elif (sw1 == 0x69 and sw2 == 0x82):
|
||||||
|
response, sw1, sw2 = card.connection.transmit([0x00, 0x20, 0x00, 0x81, len(pin)] + list(pin.encode()) + [0x0])
|
||||||
|
if (sw1 == 0x90):
|
||||||
|
response, sw1, sw2 = card.connection.transmit(apdu)
|
||||||
|
if (sw1 == 0x90):
|
||||||
|
return response
|
||||||
raise APDUResponse(sw1, sw2)
|
raise APDUResponse(sw1, sw2)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -66,7 +111,7 @@ def parse_args():
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
subparser = parser.add_subparsers(title="commands", dest="command")
|
subparser = parser.add_subparsers(title="commands", dest="command")
|
||||||
parser_init = subparser.add_parser('initialize', help='Performs the first initialization of the Pico HSM.')
|
parser_init = subparser.add_parser('initialize', help='Performs the first initialization of the Pico HSM.')
|
||||||
parser_init.add_argument('--pin', help='PIN number')
|
parser.add_argument('--pin', help='PIN number')
|
||||||
parser_init.add_argument('--so-pin', help='SO-PIN number')
|
parser_init.add_argument('--so-pin', help='SO-PIN number')
|
||||||
|
|
||||||
parser_attestate = subparser.add_parser('attestate', help='Generates an attestation report for a private key and verifies the private key was generated in the devices or outside.')
|
parser_attestate = subparser.add_parser('attestate', help='Generates an attestation report for a private key and verifies the private key was generated in the devices or outside.')
|
||||||
@@ -81,12 +126,62 @@ def parse_args():
|
|||||||
parser_pki_init.add_argument('--force', help='Forces the download of certificates.', action='store_true')
|
parser_pki_init.add_argument('--force', help='Forces the download of certificates.', action='store_true')
|
||||||
|
|
||||||
parser_rtc = subparser.add_parser('datetime', help='Datetime operations with the integrated Real Time Clock (RTC).')
|
parser_rtc = subparser.add_parser('datetime', help='Datetime operations with the integrated Real Time Clock (RTC).')
|
||||||
parser_rtc.add_argument('subcommand', choices=['set', 'get'], help='Sets or gets current datetime.')
|
subparser_rtc = parser_rtc.add_subparsers(title='commands', dest='subcommand')
|
||||||
|
parser_rtc_set = subparser_rtc.add_parser('set', help='Sets the current datetime.')
|
||||||
|
parser_rtc_get = subparser_rtc.add_parser('set', help='Gets the current datetime.')
|
||||||
|
|
||||||
parser_opts = subparser.add_parser('options', help='Manage extra options.', formatter_class=RawTextHelpFormatter)
|
parser_opts = subparser.add_parser('options', help='Manage extra options.', formatter_class=RawTextHelpFormatter)
|
||||||
parser_opts.add_argument('subcommand', choices=['set', 'get'], help='Sets or gets option OPT.')
|
subparser_opts = parser_opts.add_subparsers(title='commands', dest='subcommand')
|
||||||
parser_opts.add_argument('opt', choices=['button', 'counter'], help='Button: press-to-confirm button.\nCounter: every generated key has an internal counter.')
|
parser_opts_set = subparser_opts.add_parser('set', help='Sets option OPT.')
|
||||||
parser_opts.add_argument('onoff', choices=['on', 'off'], help='Toggles state ON or OFF', metavar='ON/OFF', nargs='?')
|
parser_opts_get = subparser_opts.add_parser('get', help='Gets optiont OPT.')
|
||||||
|
parser_opts.add_argument('opt', choices=['button', 'counter'], help='button: press-to-confirm button.\ncounter: every generated key has an internal counter.', metavar='OPT')
|
||||||
|
parser_opts_set.add_argument('onoff', choices=['on', 'off'], help='Toggles state ON or OFF', metavar='ON/OFF', nargs='?')
|
||||||
|
|
||||||
|
parser_secure = subparser.add_parser('secure', help='Manages security of Pico HSM.')
|
||||||
|
subparser_secure = parser_secure.add_subparsers(title='commands', dest='subcommand')
|
||||||
|
parser_opts_enable = subparser_secure.add_parser('enable', help='Enables secure lock.')
|
||||||
|
parser_opts_unlock = subparser_secure.add_parser('unlock', help='Unlocks the secure lock.')
|
||||||
|
parser_opts_disable = subparser_secure.add_parser('disable', help='Disables secure lock.')
|
||||||
|
|
||||||
|
parser_cipher = subparser.add_parser('cipher', help='Implements extended symmetric ciphering with new algorithms and options.\n\tIf no file input/output is specified, stdin/stoud will be used.')
|
||||||
|
subparser_cipher = parser_cipher.add_subparsers(title='commands', dest='subcommand')
|
||||||
|
parser_cipher_encrypt = subparser_cipher.add_parser('encrypt', help='Performs encryption.')
|
||||||
|
parser_cipher_decrypt = subparser_cipher.add_parser('decrypt', help='Performs decryption.')
|
||||||
|
parser_cipher_keygen = subparser_cipher.add_parser('keygen', help='Generates new AES key.')
|
||||||
|
parser_cipher_hmac = subparser_cipher.add_parser('hmac', help='Computes HMAC.')
|
||||||
|
parser_cipher_kdf = subparser_cipher.add_parser('kdf', help='Performs key derivation function on a secret key.')
|
||||||
|
parser_cipher_encrypt.add_argument('--alg', choices=['CHACHAPOLY'], required=True)
|
||||||
|
parser_cipher_encrypt.add_argument('--iteration', help='Iteration count.', required=any(['PBKDF2' in s for s in sys.argv]))
|
||||||
|
parser_cipher_decrypt.add_argument('--alg', choices=['CHACHAPOLY'], required=True)
|
||||||
|
parser_cipher_decrypt.add_argument('--iteration', help='Iteration count.', required=any(['PBKDF2' in s for s in sys.argv]))
|
||||||
|
|
||||||
|
parser_cipher_hmac.add_argument('--alg', choices=['HMAC-SHA1', 'HMAC-SHA224', 'HMAC-SHA256', 'HMAC-SHA384', 'HMAC-SHA512'], help='Selects the algorithm.', required=True)
|
||||||
|
parser_cipher_kdf.add_argument('--alg', choices=['HKDF-SHA256', 'HKDF-SHA384', 'HKDF-SHA512', 'PBKDF2-SHA1', 'PBKDF2-SHA224', 'PBKDF2-SHA256', 'PBKDF2-SHA384', 'PBKDF2-SHA512', 'X963-SHA1', 'X963-SHA224', 'X963-SHA256', 'X963-SHA384', 'X963-SHA512'], help='Selects the algorithm.', required=True)
|
||||||
|
parser_cipher_kdf.add_argument('--output-len', help='Specifies the output length of derived material.')
|
||||||
|
parser_cipher_kdf.add_argument('--iteration', help='Iteration count.', required=any(['PBKDF2' in s for s in sys.argv]))
|
||||||
|
|
||||||
|
parser_cipher.add_argument('--iv', help='Sets the IV/nonce (hex string).')
|
||||||
|
parser_cipher.add_argument('--file-in', help='File to encrypt or decrypt.')
|
||||||
|
parser_cipher.add_argument('--file-out', help='File to write the result.')
|
||||||
|
parser_cipher.add_argument('--aad', help='Specifies the authentication data (it can be a string or hex string. Combine with --hex if necesary).')
|
||||||
|
parser_cipher.add_argument('--hex', help='Parses the AAD parameter as a hex string (for binary data).', action='store_true')
|
||||||
|
parser_cipher.add_argument('-k', '--key', help='The private key index', metavar='KEY_ID', required=True)
|
||||||
|
parser_cipher.add_argument('-s', '--key-size', default=32, help='Size of the key in bytes.')
|
||||||
|
|
||||||
|
parser_x25519 = argparse.ArgumentParser(add_help=False)
|
||||||
|
subparser_x25519 = parser_x25519.add_subparsers(title='commands', dest='subcommand')
|
||||||
|
parser_x25519_keygen = subparser_x25519.add_parser('keygen', help='Generates a keypair for X25519 or X448.')
|
||||||
|
parser_x25519.add_argument('-k', '--key', help='The private key index', metavar='KEY_ID', required=True)
|
||||||
|
|
||||||
|
# Subparsers based on parent
|
||||||
|
|
||||||
|
parser_create = subparser.add_parser("x25519", parents=[parser_x25519],
|
||||||
|
help='X25519 key management.')
|
||||||
|
# Add some arguments exclusively for parser_create
|
||||||
|
|
||||||
|
parser_update = subparser.add_parser("x448", parents=[parser_x25519],
|
||||||
|
help='X448 key management.')
|
||||||
|
# Add some arguments exclusively for parser_update
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
return args
|
return args
|
||||||
@@ -97,7 +192,7 @@ def get_pki_data(url, data=None, method='GET'):
|
|||||||
method = 'GET'
|
method = 'GET'
|
||||||
if (data is not None):
|
if (data is not None):
|
||||||
method = 'POST'
|
method = 'POST'
|
||||||
req = urllib.request.Request(f"https://www.henarejos.me/pico/pico-hsm/{url}/",
|
req = urllib.request.Request(f"https://www.picokeys.com/pico/pico-hsm/{url}/",
|
||||||
method=method,
|
method=method,
|
||||||
data=data,
|
data=data,
|
||||||
headers={'User-Agent': user_agent, })
|
headers={'User-Agent': user_agent, })
|
||||||
@@ -127,6 +222,14 @@ def pki(card, args):
|
|||||||
else:
|
else:
|
||||||
print('Error: no PKI is passed. Use --default to retrieve default PKI.')
|
print('Error: no PKI is passed. Use --default to retrieve default PKI.')
|
||||||
|
|
||||||
|
def login(card, args):
|
||||||
|
global pin
|
||||||
|
pin = args.pin
|
||||||
|
try:
|
||||||
|
response = send_apdu(card, 0x20, 0x00, 0x81, list(args.pin.encode()))
|
||||||
|
except APDUResponse:
|
||||||
|
pass
|
||||||
|
|
||||||
def initialize(card, args):
|
def initialize(card, args):
|
||||||
print('********************************')
|
print('********************************')
|
||||||
print('* PLEASE READ IT CAREFULLY *')
|
print('* PLEASE READ IT CAREFULLY *')
|
||||||
@@ -138,14 +241,9 @@ def initialize(card, args):
|
|||||||
_ = input('[Press enter to confirm]')
|
_ = input('[Press enter to confirm]')
|
||||||
|
|
||||||
send_apdu(card, 0xA4, 0x04, 0x00, [0xE8, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xC3, 0x1F, 0x02, 0x01])
|
send_apdu(card, 0xA4, 0x04, 0x00, [0xE8, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xC3, 0x1F, 0x02, 0x01])
|
||||||
if (args.pin):
|
if (not args.pin):
|
||||||
pin = args.pin.encode()
|
|
||||||
try:
|
|
||||||
response = send_apdu(card, 0x20, 0x00, 0x81, list(pin))
|
|
||||||
except APDUResponse:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
pin = b'648219'
|
pin = b'648219'
|
||||||
|
|
||||||
if (args.so_pin):
|
if (args.so_pin):
|
||||||
so_pin = args.so_pin.encode()
|
so_pin = args.so_pin.encode()
|
||||||
try:
|
try:
|
||||||
@@ -203,7 +301,7 @@ def attestate(card, args):
|
|||||||
if (a.sw1 == 0x6a and a.sw2 == 0x82):
|
if (a.sw1 == 0x6a and a.sw2 == 0x82):
|
||||||
print('ERROR: Key not found')
|
print('ERROR: Key not found')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
from binascii import hexlify
|
|
||||||
print(hexlify(bytearray(cert)))
|
print(hexlify(bytearray(cert)))
|
||||||
print(f'Details of key {kid}:\n')
|
print(f'Details of key {kid}:\n')
|
||||||
print(f' CAR: {(CVC().decode(cert).car()).decode()}')
|
print(f' CAR: {(CVC().decode(cert).car()).decode()}')
|
||||||
@@ -266,12 +364,232 @@ def opts(card, args):
|
|||||||
elif (args.subcommand == 'get'):
|
elif (args.subcommand == 'get'):
|
||||||
print(f'Option {args.opt.upper()} is {"ON" if current & opt else "OFF"}')
|
print(f'Option {args.opt.upper()} is {"ON" if current & opt else "OFF"}')
|
||||||
|
|
||||||
|
class SecureLock:
|
||||||
|
def __init__(self, card):
|
||||||
|
self.card = card
|
||||||
|
|
||||||
|
def mse(self):
|
||||||
|
sk = ec.generate_private_key(ec.SECP256R1())
|
||||||
|
pn = sk.public_key().public_numbers()
|
||||||
|
self.__pb = sk.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)
|
||||||
|
|
||||||
|
|
||||||
|
ret = send_apdu(self.card, [0x80, 0x64], 0x3A, 0x01, list(self.__pb))
|
||||||
|
|
||||||
|
pk = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), bytes(ret))
|
||||||
|
shared_key = sk.exchange(ec.ECDH(), pk)
|
||||||
|
|
||||||
|
xkdf = HKDF(
|
||||||
|
algorithm=hashes.SHA256(),
|
||||||
|
length=12+32,
|
||||||
|
salt=None,
|
||||||
|
info=self.__pb
|
||||||
|
)
|
||||||
|
kdf_out = xkdf.derive(shared_key)
|
||||||
|
self.__key_enc = kdf_out[12:]
|
||||||
|
self.__iv = kdf_out[:12]
|
||||||
|
|
||||||
|
def encrypt_chacha(self, data):
|
||||||
|
chacha = ChaCha20Poly1305(self.__key_enc)
|
||||||
|
ct = chacha.encrypt(self.__iv, data, self.__pb)
|
||||||
|
return ct
|
||||||
|
|
||||||
|
def unlock_device(self):
|
||||||
|
ct = self.get_skey()
|
||||||
|
send_apdu(self.card, [0x80, 0x64], 0x3A, 0x03, list(ct))
|
||||||
|
|
||||||
|
def _get_key_device(self):
|
||||||
|
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
|
||||||
|
from secure_key import windows as skey
|
||||||
|
elif (platform.system() == 'Darwin'):
|
||||||
|
from secure_key import macos as skey
|
||||||
|
else:
|
||||||
|
print('ERROR: platform not supported')
|
||||||
|
sys.exit(-1)
|
||||||
|
return skey.get_secure_key()
|
||||||
|
|
||||||
|
def get_skey(self):
|
||||||
|
self.mse()
|
||||||
|
ct = self.encrypt_chacha(self._get_key_device())
|
||||||
|
return ct
|
||||||
|
|
||||||
|
def enable_device_aut(self):
|
||||||
|
ct = self.get_skey()
|
||||||
|
send_apdu(self.card, [0x80, 0x64], 0x3A, 0x02, list(ct))
|
||||||
|
|
||||||
|
def disable_device_aut(self):
|
||||||
|
ct = self.get_skey()
|
||||||
|
send_apdu(self.card, [0x80, 0x64], 0x3A, 0x04, list(ct))
|
||||||
|
|
||||||
|
|
||||||
|
def secure(card, args):
|
||||||
|
slck = SecureLock(card)
|
||||||
|
if (args.subcommand == 'enable'):
|
||||||
|
slck.enable_device_aut()
|
||||||
|
elif (args.subcommand == 'unlock'):
|
||||||
|
slck.unlock_device()
|
||||||
|
elif (args.subcommand == 'disable'):
|
||||||
|
slck.disable_device_aut()
|
||||||
|
|
||||||
|
|
||||||
|
def cipher(card, args):
|
||||||
|
if (args.subcommand == 'keygen'):
|
||||||
|
ksize = 0xB2
|
||||||
|
if (args.key_size == 24):
|
||||||
|
ksize = 0xB1
|
||||||
|
elif (args.key_size == 16):
|
||||||
|
ksize = 0xB0
|
||||||
|
ret = send_apdu(card, 0x48, int(args.key), ksize)
|
||||||
|
|
||||||
|
else:
|
||||||
|
enc = None
|
||||||
|
aad = None
|
||||||
|
if (args.alg == 'CHACHAPOLY'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x12'
|
||||||
|
elif (args.alg == 'HMAC-SHA1'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x02\x07'
|
||||||
|
elif (args.alg == 'HMAC-SHA224'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x02\x08'
|
||||||
|
elif (args.alg == 'HMAC-SHA256'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x02\x09'
|
||||||
|
elif (args.alg == 'HMAC-SHA384'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0A'
|
||||||
|
elif (args.alg == 'HMAC-SHA512'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0B'
|
||||||
|
elif (args.alg == 'HKDF-SHA256'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1D'
|
||||||
|
elif (args.alg == 'HKDF-SHA384'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1E'
|
||||||
|
elif (args.alg == 'HKDF-SHA512'):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1F'
|
||||||
|
elif (args.alg in ['PBKDF2-SHA1', 'PBKDF2-SHA224', 'PBKDF2-SHA256', 'PBKDF2-SHA384', 'PBKDF2-SHA512']):
|
||||||
|
if ('PBKDF2' in args.alg):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C'
|
||||||
|
salt = b'\x04' + bytes([len(args.iv)//2]) + unhexlify(args.iv)
|
||||||
|
iteration = b'\x02' + bytes([len(int_to_bytes(int(args.iteration)))]) + int_to_bytes(int(args.iteration))
|
||||||
|
prf = b'\x30\x0A\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02'
|
||||||
|
if (args.alg == 'PBKDF2-SHA1'):
|
||||||
|
prf += b'\x07'
|
||||||
|
elif (args.alg == 'PBKDF2-SHA224'):
|
||||||
|
prf += b'\x08'
|
||||||
|
elif (args.alg == 'PBKDF2-SHA256'):
|
||||||
|
prf += b'\x09'
|
||||||
|
elif (args.alg == 'PBKDF2-SHA384'):
|
||||||
|
prf += b'\x0A'
|
||||||
|
elif (args.alg == 'PBKDF2-SHA512'):
|
||||||
|
prf += b'\x0B'
|
||||||
|
enc = list(salt + iteration + prf)
|
||||||
|
elif (args.alg in 'X963-SHA1', 'X963-SHA224', 'X963-SHA256', 'X963-SHA384', 'X963-SHA512'):
|
||||||
|
oid = b'\x2B\x81\x05\x10\x86\x48\x3F'
|
||||||
|
enc = b'\x2A\x86\x48\x86\xF7\x0D\x02'
|
||||||
|
if (args.alg == 'X963-SHA1'):
|
||||||
|
enc += b'\x07'
|
||||||
|
elif (args.alg == 'X963-SHA224'):
|
||||||
|
enc += b'\x08'
|
||||||
|
elif (args.alg == 'X963-SHA256'):
|
||||||
|
enc += b'\x09'
|
||||||
|
elif (args.alg == 'X963-SHA384'):
|
||||||
|
enc += b'\x0A'
|
||||||
|
elif (args.alg == 'X963-SHA512'):
|
||||||
|
enc += b'\x0B'
|
||||||
|
'''
|
||||||
|
# To be finished: it does not work with AES (only supported by HSM)
|
||||||
|
elif (args.alg in ['PBES2-SHA1', 'PBES2-SHA224', 'PBES2-SHA256', 'PBES2-SHA384', 'PBES2-SHA512']):
|
||||||
|
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0D'
|
||||||
|
if (not args.iv):
|
||||||
|
sys.stderr.buffer.write(b'ERROR: --iv required')
|
||||||
|
sys.exit(-1)
|
||||||
|
salt = b'\x04' + bytes([len(args.iv)//2]) + unhexlify(args.iv)
|
||||||
|
iteration = b'\x02' + bytes([len(int_to_bytes(int(args.iteration)))]) + int_to_bytes(int(args.iteration))
|
||||||
|
prf = b'\x30\x0A\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02'
|
||||||
|
if (args.alg == 'PBES2-SHA1'):
|
||||||
|
prf += b'\x07'
|
||||||
|
elif (args.alg == 'PBES2-SHA224'):
|
||||||
|
prf += b'\x08'
|
||||||
|
elif (args.alg == 'PBES2-SHA256'):
|
||||||
|
prf += b'\x09'
|
||||||
|
elif (args.alg == 'PBES2-SHA384'):
|
||||||
|
prf += b'\x0A'
|
||||||
|
elif (args.alg == 'PBES2-SHA512'):
|
||||||
|
prf += b'\x0B'
|
||||||
|
oid_kdf = b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C'
|
||||||
|
aad = hexlify(oid_kdf + b'\x30' + bytes([len(salt)+len(iteration)+len(prf)]) + salt + iteration + prf)
|
||||||
|
args.hex = True
|
||||||
|
'''
|
||||||
|
|
||||||
|
if (args.subcommand[0] == 'e' or args.subcommand == 'hmac' or args.subcommand == 'kdf'):
|
||||||
|
alg = 0x51
|
||||||
|
elif (args.subcommand[0] == 'd'):
|
||||||
|
alg = 0x52
|
||||||
|
|
||||||
|
if (not enc):
|
||||||
|
if (args.file_in):
|
||||||
|
fin = open(args.file_in, 'rb')
|
||||||
|
else:
|
||||||
|
fin = sys.stdin.buffer
|
||||||
|
enc = fin.read()
|
||||||
|
fin.close()
|
||||||
|
|
||||||
|
data = [0x06, len(oid)] + list(oid) + [0x81, len(enc)] + list(enc)
|
||||||
|
|
||||||
|
if (args.iv and not 'PBKDF2' in args.alg and not 'PBES2' in args.alg):
|
||||||
|
data += [0x82, len(args.iv)//2] + list(unhexlify(args.iv))
|
||||||
|
if (not aad):
|
||||||
|
aad = args.aad
|
||||||
|
if (aad):
|
||||||
|
if (args.hex):
|
||||||
|
data += [0x83, len(aad)//2] + list(unhexlify(aad))
|
||||||
|
else:
|
||||||
|
data += [0x83, len(aad)] + list(aad)
|
||||||
|
|
||||||
|
ne = int(args.output_len) if 'output_len' in args and args.output_len else None
|
||||||
|
|
||||||
|
ret = send_apdu(card, [0x80, 0x78], int(args.key), alg, data=data, ne=ne)
|
||||||
|
if (args.file_out):
|
||||||
|
fout = open(args.file_out, 'wb')
|
||||||
|
else:
|
||||||
|
fout = sys.stdout.buffer
|
||||||
|
if (args.hex):
|
||||||
|
fout.write(hexlify(bytes(ret)))
|
||||||
|
else:
|
||||||
|
fout.write(bytes(ret))
|
||||||
|
if (args.file_out):
|
||||||
|
fout.close()
|
||||||
|
|
||||||
|
def int_to_bytes(x: int) -> bytes:
|
||||||
|
return x.to_bytes((x.bit_length() + 7) // 8, 'big')
|
||||||
|
|
||||||
|
def x25519(card, args):
|
||||||
|
if (args.command == 'x25519'):
|
||||||
|
P = b'\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xed'
|
||||||
|
A = int_to_bytes(0x01DB42)
|
||||||
|
N = b'\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\xDE\xF9\xDE\xA2\xF7\x9C\xD6\x58\x12\x63\x1A\x5C\xF5\xD3\xED'
|
||||||
|
G = b'\x04\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd3\xce\x7e\xa2\xc5\xe9\x29\xb2\x61\x7c\x6d\x7e\x4d\x3d\x92\x4c\xd1\x48\x77\x2c\xdd\x1e\xe0\xb4\x86\xa0\xb8\xa1\x19\xae\x20'
|
||||||
|
h = b'\x08'
|
||||||
|
elif (args.command == 'x448'):
|
||||||
|
P = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
|
||||||
|
A = int_to_bytes(0x98AA)
|
||||||
|
N = b'\x3f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7c\xca\x23\xe9\xc4\x4e\xdb\x49\xae\xd6\x36\x90\x21\x6c\xc2\x72\x8d\xc5\x8f\x55\x23\x78\xc2\x92\xab\x58\x44\xf3'
|
||||||
|
G = b'\x04\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x5b\x7b\x45\x3d\x22\xd7\x6f\xf7\x7a\x67\x50\xb1\xc4\x12\x13\x21\x0d\x43\x46\x23\x7e\x02\xb8\xed\xf6\xf3\x8d\xc2\x5d\xf7\x60\xd0\x45\x55\xf5\x34\x5d\xae\xcb\xce\x6f\x32\x58\x6e\xab\x98\x6c\xf6\xb1\xf5\x95\x12\x5d\x23\x7d'
|
||||||
|
h = b'\x04'
|
||||||
|
oid = b'\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03'
|
||||||
|
p_data = b'\x81' + bytes([len(P)]) + P
|
||||||
|
a_data = b'\x82' + bytes([len(A)]) + A
|
||||||
|
g_data = b'\x84' + bytes([len(G)]) + G
|
||||||
|
n_data = b'\x85' + bytes([len(N)]) + N
|
||||||
|
h_data = b'\x87' + bytes([len(h)]) + h
|
||||||
|
|
||||||
|
cdata = b'\x5F\x29\x01\x00'
|
||||||
|
cdata += b'\x42\x0C\x55\x54\x44\x55\x4D\x4D\x59\x30\x30\x30\x30\x31'
|
||||||
|
cdata += b'\x7f\x49\x81' + bytes([len(oid)+len(p_data)+len(a_data)+len(g_data)+len(n_data)+len(h_data)]) + oid + p_data + a_data + g_data + n_data + h_data
|
||||||
|
cdata += b'\x5F\x20\x0C\x55\x54\x44\x55\x4D\x4D\x59\x30\x30\x30\x30\x31'
|
||||||
|
ret = send_apdu(card, 0x46, int(args.key), 0x00, list(cdata))
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
print('Pico HSM Tool v1.4')
|
sys.stderr.buffer.write(b'Pico HSM Tool v1.8\n')
|
||||||
print('Author: Pol Henarejos')
|
sys.stderr.buffer.write(b'Author: Pol Henarejos\n')
|
||||||
print('Report bugs to https://github.com/polhenarejos/pico-hsm/issues')
|
sys.stderr.buffer.write(b'Report bugs to https://github.com/polhenarejos/pico-hsm/issues\n')
|
||||||
print('')
|
sys.stderr.buffer.write(b'\n\n')
|
||||||
print('')
|
|
||||||
cardtype = AnyCardType()
|
cardtype = AnyCardType()
|
||||||
try:
|
try:
|
||||||
# request card insertion
|
# request card insertion
|
||||||
@@ -284,6 +602,9 @@ def main(args):
|
|||||||
except CardRequestTimeoutException:
|
except CardRequestTimeoutException:
|
||||||
print('time-out: no card inserted during last 10s')
|
print('time-out: no card inserted during last 10s')
|
||||||
|
|
||||||
|
if (args.pin):
|
||||||
|
login(card, args)
|
||||||
|
|
||||||
# Following commands may raise APDU exception on error
|
# Following commands may raise APDU exception on error
|
||||||
if (args.command == 'initialize'):
|
if (args.command == 'initialize'):
|
||||||
initialize(card, args)
|
initialize(card, args)
|
||||||
@@ -295,6 +616,13 @@ def main(args):
|
|||||||
rtc(card, args)
|
rtc(card, args)
|
||||||
elif (args.command == 'options'):
|
elif (args.command == 'options'):
|
||||||
opts(card, args)
|
opts(card, args)
|
||||||
|
elif (args.command == 'secure'):
|
||||||
|
secure(card, args)
|
||||||
|
elif (args.command == 'cipher'):
|
||||||
|
cipher(card, args)
|
||||||
|
elif (args.command == 'x25519' or args.command == 'x448'):
|
||||||
|
x25519(card, args)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|||||||
59
tools/secure_key/macos.py
Normal file
59
tools/secure_key/macos.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import sys
|
||||||
|
import keyring
|
||||||
|
|
||||||
|
DOMAIN = "PicoKeys.com"
|
||||||
|
USERNAME = "Pico-HSM"
|
||||||
|
|
||||||
|
try:
|
||||||
|
import keyring
|
||||||
|
from keyrings.osx_keychain_keys.backend import OSXKeychainKeysBackend, OSXKeychainKeyType, OSXKeyChainKeyClassType
|
||||||
|
except:
|
||||||
|
print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyrings.osx-keychain-keys`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
|
||||||
|
except:
|
||||||
|
print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_backend(use_secure_enclave=False):
|
||||||
|
backend = OSXKeychainKeysBackend(
|
||||||
|
key_type=OSXKeychainKeyType.EC, # Key type, e.g. RSA, RC, DSA, ...
|
||||||
|
key_class_type=OSXKeyChainKeyClassType.Private, # Private key, Public key, Symmetric-key
|
||||||
|
key_size_in_bits=256,
|
||||||
|
is_permanent=True, # If set, saves the key in keychain; else, returns a transient key
|
||||||
|
use_secure_enclave=use_secure_enclave, # Saves the key in the T2 (TPM) chip, requires a code-signed interpreter
|
||||||
|
access_group=None, # Limits key management and retrieval to set group, requires a code-signed interpreter
|
||||||
|
is_extractable=True # If set, private key is extractable; else, it can't be retrieved, but only operated against
|
||||||
|
)
|
||||||
|
return backend
|
||||||
|
|
||||||
|
def generate_secure_key(use_secure_enclave=False):
|
||||||
|
backend = get_backend(use_secure_enclave)
|
||||||
|
backend.set_password(DOMAIN, USERNAME, password=None)
|
||||||
|
return backend.get_password(DOMAIN, USERNAME)
|
||||||
|
|
||||||
|
def get_d(key):
|
||||||
|
return key.private_numbers().private_value.to_bytes(32, 'big')
|
||||||
|
|
||||||
|
def set_secure_key(pk):
|
||||||
|
backend = get_backend(False)
|
||||||
|
try:
|
||||||
|
backend.delete_password(DOMAIN, USERNAME)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
backend.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption()))
|
||||||
|
|
||||||
|
def get_secure_key():
|
||||||
|
key = None
|
||||||
|
try:
|
||||||
|
backend = get_backend(False)
|
||||||
|
key = backend.get_password(DOMAIN, USERNAME)[0]
|
||||||
|
except keyring.errors.KeyringError:
|
||||||
|
try:
|
||||||
|
key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault
|
||||||
|
except keyring.errors.PasswordSetError:
|
||||||
|
key = generate_secure_key(False)[0]
|
||||||
|
return get_d(key)
|
||||||
44
tools/secure_key/windows.py
Normal file
44
tools/secure_key/windows.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import base64
|
||||||
|
|
||||||
|
DOMAIN = "PicoKeys.com"
|
||||||
|
USERNAME = "Pico-HSM"
|
||||||
|
|
||||||
|
try:
|
||||||
|
import keyring
|
||||||
|
except:
|
||||||
|
print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyrings.osx-keychain-keys`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, load_pem_private_key
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
|
except:
|
||||||
|
print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def generate_secure_key():
|
||||||
|
pkey = ec.generate_private_key(ec.SECP256R1())
|
||||||
|
set_secure_key(pkey)
|
||||||
|
return keyring.get_password(DOMAIN, USERNAME)
|
||||||
|
|
||||||
|
def get_d(key):
|
||||||
|
return load_pem_private_key(key, password=None).private_numbers().private_value.to_bytes(32, 'big')
|
||||||
|
|
||||||
|
def set_secure_key(pk):
|
||||||
|
try:
|
||||||
|
keyring.delete_password(DOMAIN, USERNAME)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
keyring.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()).decode())
|
||||||
|
|
||||||
|
def get_secure_key():
|
||||||
|
key = None
|
||||||
|
try:
|
||||||
|
key = keyring.get_password(DOMAIN, USERNAME)
|
||||||
|
except keyring.errors.KeyringError:
|
||||||
|
key = generate_secure_key()
|
||||||
|
return get_d(key.encode())
|
||||||
Reference in New Issue
Block a user