14 Commits
v2.4 ... v2.6

Author SHA1 Message Date
Pol Henarejos
f122a9ab28 Upgrade to version 2.6.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-09 00:42:58 +02:00
Pol Henarejos
14dbad4dd7 Do not return PIN unitialized if PKA is enabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-09 00:27:53 +02:00
Pol Henarejos
cdce9ab50b Adding pka_enabled() to check whether the device is configured with PKA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-09 00:26:56 +02:00
Pol Henarejos
30d3270e1d Adding clarification on setting PKA and PIN with SCS3.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-09 00:26:35 +02:00
Pol Henarejos
157923decc Clafiricate docs about PKA and PIN
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-06 01:44:24 +02:00
Pol Henarejos
7bbcbc57eb Removing unnecessary debug.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-06 01:36:03 +02:00
Pol Henarejos
9074463f4e Added clarification on PKA and PIN
DKEK is protected in the device with a derived key from the PIN number. Unfortunately, SCS3 does not support the combination of PKA and PIN but OpenSC does. This is explained here.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-06 01:27:51 +02:00
Pol Henarejos
3ebf4fdff5 User authentication is unlinked from session_pin
Due to PUK Authentication, user authentication is not linked to having a valid session_pin anymore. In case of enabled PUK Auth, session_pin is used only for unlocking DKEK, but not for granting auth privileges, as they only are granted when PUK Auth succeeds.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-06 01:13:09 +02:00
Pol Henarejos
77e5fa2d2b Added static files for device key and certiticate.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-15 15:57:54 +02:00
Pol Henarejos
6bd2e65459 Add function for building PrKD asn1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-15 15:38:11 +02:00
Pol Henarejos
3363e9ad0c Updating ccid.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-14 19:12:31 +02:00
Pol Henarejos
d1f0f45525 Added support for native PKCS1.5 and OEP decryption.
It is not tested, as it is not supported by pkcs11 modules. For instance, OpenSSL implements OEP in local side, calling a RAW decryption on the device.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-14 17:00:23 +02:00
Pol Henarejos
efc1b4a4ae Fix meta deletion.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-14 16:45:06 +02:00
Pol Henarejos
a45303d9e6 Added support for specific purposes. Added support for SHA512 operations.
Keys can only be used for the specific purpose provided during the keypair generation.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-14 16:12:04 +02:00
11 changed files with 208 additions and 60 deletions

View File

@@ -109,7 +109,7 @@ Key usage can also be used to perform and auditory and track the usage of a part
### Public Key Authentication ### Public Key Authentication
Public Key Authentication (PKA) allows to authenticate by using a secondary device with a private key and a registered public key in the primary device. A challenge is generated by the primary Pico HSM and given to the secondary for signature. The secondary device signs the challenge and returns the signature. Then, the primary device verifies the signature with the registered public key and if it is valid, it grants full access, as normal PIN authentication. Public Key Authentication (PKA) allows to authenticate by using a secondary device with a private key and a registered public key in the primary device. A challenge is generated by the primary Pico HSM and given to the secondary for signature. The secondary device signs the challenge and returns the signature. Then, the primary device verifies the signature with the registered public key and if it is valid, it grants full access, as normal PIN authentication.
In PKA, neither PIN nor retry counters are used, since a private key is needed. 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.
[^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.

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="2" VERSION_MAJOR="2"
VERSION_MINOR="4" VERSION_MINOR="6"
rm -rf release/* rm -rf release/*
cd build_release cd build_release

View File

@@ -1,6 +1,6 @@
# Public Key Authentication # Public Key Authentication
Public Key Authentication (PKA) is a mechanism to authenticate a legit user without introducing any PIN. The authentication is performed by signing a challenge and checking the signature result. Public Key Authentication (PKA) is a mechanism to authenticate a legit user without introducing any PIN (see Notes below). The authentication is performed by signing a challenge and checking the signature result.
1. A Pico HSM #A contains a private key, whose public key will be used for authentication. 1. A Pico HSM #A contains a private key, whose public key will be used for authentication.
2. The public key of #A is registered into a second Pico HSM #B. 2. The public key of #A is registered into a second Pico HSM #B.
@@ -9,8 +9,6 @@ Public Key Authentication (PKA) is a mechanism to authenticate a legit user with
5. #B verifies the signature against the challenge with the public key of #A, previously registered. 5. #B verifies the signature against the challenge with the public key of #A, previously registered.
6. If the signature is valid, #B grants access to the user. 6. If the signature is valid, #B grants access to the user.
This mechanism has no retry counter or PIN throttling, as no PIN is set up on the device.
To enable PKA, the device must be initialized beforehand. In case the device has secret/private keys, all shall be exported and reimported when the set up is finished. To enable PKA, the device must be initialized beforehand. In case the device has secret/private keys, all shall be exported and reimported when the set up is finished.
## Requirements ## Requirements
@@ -18,8 +16,8 @@ To enable PKA, the device must be initialized beforehand. In case the device has
To take advantage of PKA, the following is required: To take advantage of PKA, the following is required:
1. Two Pico HSM: one will be used only for authentication (it can be any device able to generate a private key and sign arbitrary data). 1. Two Pico HSM: one will be used only for authentication (it can be any device able to generate a private key and sign arbitrary data).
2. [SCS3](/doc/scs3.md "SCS3") tool to authenticate the user. At this time, OpenSC does not support PKA. 2. [SCS3](/doc/scs3.md "SCS3") tool to authenticate the user. At this time, OpenSC does not support PKA, only initialization.
3. A secret key of ECC 256 bits. SCS3 does not support other curves. 3. A secret key of ECC 256 bits.
## Usage ## Usage
@@ -29,35 +27,71 @@ Before using SCS3, it must be patched [scs3.patch.txt](https://github.com/polhen
On a secondary device, generate a private key, on the ECC 256 bits (`brainpoolP256r1` or `secp192r1`). Label it with an easy name, such as "Authentication". On a secondary device, generate a private key, on the ECC 256 bits (`brainpoolP256r1` or `secp192r1`). Label it with an easy name, such as "Authentication".
<img width="1037" alt="Captura de Pantalla 2022-06-13 a les 12 11 00" src="https://user-images.githubusercontent.com/55573252/173353764-4620ece4-0d82-4a23-a153-99bf912621a7.png"> <img width="1037" src="https://user-images.githubusercontent.com/55573252/173353764-4620ece4-0d82-4a23-a153-99bf912621a7.png">
Once finished, export the public key. Once finished, export the public key.
<img width="350" alt="Captura de Pantalla 2022-06-13 a les 12 11 39" src="https://user-images.githubusercontent.com/55573252/173353732-63f40572-a42f-4e5c-a9ab-6e52a083956b.png"> <img width="350" src="https://user-images.githubusercontent.com/55573252/173353732-63f40572-a42f-4e5c-a9ab-6e52a083956b.png">
### Initialization ### Initialization
On the primary device, initialize it. When prompting for an authentication mechanism, select "Public Key Authentication". On the primary device, initialize it. When prompting for an authentication mechanism, select "Public Key Authentication".
<img width="412" alt="Captura de Pantalla 2022-06-13 a les 12 05 09" src="https://user-images.githubusercontent.com/55573252/173353661-17caf6db-0c76-4903-9b70-5afa79f5ae54.png"><img width="1037" alt="Captura de Pantalla 2022-06-13 a les 12 14 48" src="https://user-images.githubusercontent.com/55573252/173353822-310219dc-7c7d-4ece-9fd9-c7835c2688df.png"> <img width="412" src="https://user-images.githubusercontent.com/55573252/173353661-17caf6db-0c76-4903-9b70-5afa79f5ae54.png"><img width="1037" alt="Captura de Pantalla 2022-06-13 a les 12 14 48" src="https://user-images.githubusercontent.com/55573252/173353822-310219dc-7c7d-4ece-9fd9-c7835c2688df.png">
Once finished, register the exported public key. A message of `0 authenticated public key(s) in 1 of 1 scheme` will appear if it is properly registered. Once finished, register the exported public key. A message of `0 authenticated public key(s) in 1 of 1 scheme` will appear if it is properly registered.
<img width="342" alt="Captura de Pantalla 2022-06-13 a les 12 15 44" src="https://user-images.githubusercontent.com/55573252/173353917-f3f99405-c7ff-43ce-8914-6f3b713df952.png"><img width="1037" alt="Captura de Pantalla 2022-06-13 a les 12 16 17" src="https://user-images.githubusercontent.com/55573252/173353946-ee7eacf9-cead-4804-ac7a-57848f7c822b.png"> <img width="342" src="https://user-images.githubusercontent.com/55573252/173353917-f3f99405-c7ff-43ce-8914-6f3b713df952.png"><img width="1037" alt="Captura de Pantalla 2022-06-13 a les 12 16 17" src="https://user-images.githubusercontent.com/55573252/173353946-ee7eacf9-cead-4804-ac7a-57848f7c822b.png">
### Authentication ### Authentication
Plug the secondary device that stores the private key (do not load the device in the SCS3 tool) and initiate the public key authentication. Plug the secondary device that stores the private key (do not load the device in the SCS3 tool) and initiate the public key authentication.
<img width="321" alt="Captura de Pantalla 2022-06-13 a les 12 19 47" src="https://user-images.githubusercontent.com/55573252/173353998-8f418ec6-d90d-4168-801f-51008c78824d.png"> <img width="321" src="https://user-images.githubusercontent.com/55573252/173353998-8f418ec6-d90d-4168-801f-51008c78824d.png">
Select the secondary card and the Authentication private key (or the name you labeled it). Select the secondary card and the Authentication private key (or the name you labeled it).
<img width="435" alt="Captura de Pantalla 2022-06-13 a les 14 25 25" src="https://user-images.githubusercontent.com/55573252/173354044-50163113-829e-4d80-bbda-7b589849af73.png"> <img width="435" src="https://user-images.githubusercontent.com/55573252/173354044-50163113-829e-4d80-bbda-7b589849af73.png">
Introduce the PIN of the secondary device. Introduce the PIN of the secondary device.
If the private key matches with the registered public key, the primary device will grant access and it will display `User PIN authenticated (9000)` (despite no PIN is provided). If the private key matches with the registered public key, the primary device will grant access and it will display `User PIN authenticated (9000)` (despite no PIN is provided).
From now on, you have full access and can operate normally with the primary device. From now on, you have full access and can operate normally with the primary device.
## Notes on DKEK
Pico HSM uses the PIN to protect the DKEK, which is lately used to protect private/secret keys and wrap/unwrap. However, when PKA is enabled, the authentication is not performed by introducing any PIN.
Authenticated privileges are granted when PKA succeeds, regardless of PIN, which is optional.
Nevertheless, **it is extremely recommended to combine PKA with PIN**. Note that when combined, only PKA grants authenticated privileges. Therefore, if both schemes are setup, it is necessary to unlock the DKEK with PIN verification.
Otherwise, it will not be possible to operate with private/secret keys despite the user will be logged in.
With this scheme, multiple custodians may authenticate the device individually and remotely and, when fully authenticated, the master user can unlock the DKEK with the PIN.
Moreover, with this approach the device is kept safe and neither the DKEK nor the private/secret keys are stored in plain text in the device.
Even though the flash memory is dumped by an attacker, it will not be possible to decipher any sensitive data or key.
Initialization of the device with PKA **and** PIN can be achieved with SCS3 or OpenSC:
**Note:** do not import any DKEK share or DKEK operation before PKA and PIN setup.
### With OpenSC
Use the following command (or similar), which accepts the use of PIN parameter **and** PKA configuration:
```
sc-hsm-tool -X --so-pin 1234567890123456 --pin 648219 -K 1 -n 1 -s 1
```
and PKA and PIN are enabled, jointly with DKEK protection.
### With SCS3
Unfortunately, SCS3 does not allow to initialize the device with PKA and PIN at the same time, though it can be achieved in separated steps:
1. Initialize the device with PKA. When done, the PIN will not be initialized but it will advice that 3 attemps can be performed.
2. There is NO default PIN. So, DO NOT attempt to log in yet. A reset PIN shall be requested.
3. Click on ``Reset User-PIN``, introduce the SO-PIN configured during the initialization and introduce the desired User-PIN.
When done, the device will be configured with PIN **and** PKA.

View File

@@ -288,6 +288,51 @@ size_t asn1_build_cert_description(const uint8_t *label, size_t label_len, const
return p-buf; return p-buf;
} }
size_t asn1_build_prkd_ecc(const uint8_t *label, size_t label_len, const uint8_t *keyid, size_t keyid_len, size_t keysize, uint8_t *buf, size_t buf_len) {
size_t seq1_size = asn1_len_tag(0x30, asn1_len_tag(0xC, label_len));
size_t seq2_size = asn1_len_tag(0x30, asn1_len_tag(0x4, keyid_len)+asn1_len_tag(0x3, 3));
size_t seq3_size = asn1_len_tag(0xA1, asn1_len_tag(0x30, asn1_len_tag(0x30, asn1_len_tag(0x4, 0))+asn1_len_tag(0x2,2)));
size_t tot_len = asn1_len_tag(0xA0, seq1_size+seq2_size+seq3_size);
if (buf_len == 0 || buf == NULL)
return tot_len;
if (buf_len < tot_len)
return 0;
uint8_t *p = buf;
*p++ = 0xA0;
p += format_tlv_len(seq1_size+seq2_size+seq3_size, p);
//Seq 1
*p++ = 0x30;
p += format_tlv_len(asn1_len_tag(0xC, label_len), p);
*p++ = 0xC;
p += format_tlv_len(label_len, p);
memcpy(p, label, label_len); p += label_len;
//Seq 2
*p++ = 0x30;
p += format_tlv_len(asn1_len_tag(0x4, keyid_len)+asn1_len_tag(0x3, 3), p);
*p++ = 0x4;
p += format_tlv_len(keyid_len, p);
memcpy(p, keyid, keyid_len); p += keyid_len;
*p++ = 0x3;
p += format_tlv_len(3, p);
memcpy(p, "\x07\x20\x80", 3); p += 3;
//Seq 3
*p++ = 0xA1;
p += format_tlv_len(asn1_len_tag(0x30, asn1_len_tag(0x30, asn1_len_tag(0x4, 0))+asn1_len_tag(0x2,2)), p);
*p++ = 0x30;
p += format_tlv_len(asn1_len_tag(0x30, asn1_len_tag(0x4, 0))+asn1_len_tag(0x2,2), p);
*p++ = 0x30;
p += format_tlv_len(asn1_len_tag(0x4, 0), p);
*p++ = 0x4;
p += format_tlv_len(0, p);
*p++ = 0x2;
p += format_tlv_len(2, p);
*p++ = (keysize >> 8) & 0xff;
*p++ = keysize & 0xff;
return p-buf;
}
const uint8_t *cvc_get_field(const uint8_t *data, size_t len, size_t *olen, uint16_t tag) { const uint8_t *cvc_get_field(const uint8_t *data, size_t len, size_t *olen, uint16_t tag) {
uint8_t *rdata = NULL; uint8_t *rdata = NULL;
if (data == NULL || len == 0) if (data == NULL || len == 0)

View File

@@ -46,5 +46,6 @@ extern const uint8_t *cvc_get_pub(const uint8_t *data, size_t len, size_t *olen)
extern int cvc_verify(const uint8_t *cert, size_t cert_len, const uint8_t *ca, size_t ca_len); extern int cvc_verify(const uint8_t *cert, size_t cert_len, const uint8_t *ca, size_t ca_len);
extern mbedtls_ecp_group_id cvc_inherite_ec_group(const uint8_t *ca, size_t ca_len); extern mbedtls_ecp_group_id cvc_inherite_ec_group(const uint8_t *ca, size_t ca_len);
extern int puk_verify(const uint8_t *sig, size_t sig_len, const uint8_t *hash, size_t hash_len, const uint8_t *ca, size_t ca_len); extern int puk_verify(const uint8_t *sig, size_t sig_len, const uint8_t *hash, size_t hash_len, const uint8_t *ca, size_t ca_len);
extern size_t asn1_build_prkd_ecc(const uint8_t *label, size_t label_len, const uint8_t *keyid, size_t keyid_len, size_t keysize, uint8_t *buf, size_t buf_len);
#endif #endif

View File

@@ -47,9 +47,12 @@ file_t file_entries[] = {
/* 22 */ { .fid = EF_KEY_DOMAIN, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Key domain options /* 22 */ { .fid = EF_KEY_DOMAIN, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Key domain options
/* 23 */ { .fid = EF_META , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //EF.CDFs /* 23 */ { .fid = EF_META , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //EF.CDFs
/* 24 */ { .fid = EF_PUKAUT, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Public Key Authentication /* 24 */ { .fid = EF_PUKAUT, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Public Key Authentication
///* 25 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, /* 25 */ { .fid = EF_KEY_DEV, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device Key
/* 26 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, /* 26 */ { .fid = EF_PRKD_DEV, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PrKD Device
/* 27 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end /* 27 */ { .fid = EF_EE_DEV, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //End Entity Certificate Device
///* 28 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 29 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 30 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
}; };
const file_t *MF = &file_entries[0]; const file_t *MF = &file_entries[0];

View File

@@ -33,6 +33,10 @@
#define EF_DODFS 0x6044 #define EF_DODFS 0x6044
#define EF_SKDFS 0x6045 #define EF_SKDFS 0x6045
#define EF_KEY_DEV 0xCC00
#define EF_PRKD_DEV 0xC400
#define EF_EE_DEV 0xCE00
extern file_t *file_pin1; extern file_t *file_pin1;
extern file_t *file_retries_pin1; extern file_t *file_retries_pin1;
extern file_t *file_sopin; extern file_t *file_sopin;

View File

@@ -520,13 +520,17 @@ int pin_wrong_retry(const file_t *pin) {
return CCID_ERR_BLOCKED; return CCID_ERR_BLOCKED;
} }
bool pka_enabled() {
file_t *ef_puk = search_by_fid(EF_PUKAUT, NULL, SPECIFY_EF);
return ef_puk && ef_puk->data && file_get_size(ef_puk) > 0 && file_read_uint8(file_get_data(ef_puk)) > 0;
}
int check_pin(const file_t *pin, const uint8_t *data, size_t len) { int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
if (!pin) if (!pin || !pin->data || file_get_size(pin) == 0) {
return SW_REFERENCE_NOT_FOUND();
if (!pin->data) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
isUserAuthenticated = false; if (pka_enabled() == false)
isUserAuthenticated = false;
has_session_pin = has_session_sopin = false; has_session_pin = has_session_sopin = false;
if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) { if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) {
if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) { if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) {
@@ -553,7 +557,8 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
return SW_PIN_BLOCKED(); return SW_PIN_BLOCKED();
if (r != CCID_OK) if (r != CCID_OK)
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
isUserAuthenticated = true; if (pka_enabled() == false)
isUserAuthenticated = true;
hash_multi(data, len, session_pin); hash_multi(data, len, session_pin);
if (pin == file_pin1) if (pin == file_pin1)
has_session_pin = true; has_session_pin = true;
@@ -573,9 +578,9 @@ static int cmd_verify() {
uint16_t opts = get_device_options(); uint16_t opts = get_device_options();
if (opts & HSM_OPT_TRANSPORT_PIN) if (opts & HSM_OPT_TRANSPORT_PIN)
return SW_DATA_INVALID(); return SW_DATA_INVALID();
if (has_session_pin && apdu.nc == 0) /* It can be true from PUK AUT */ if (has_session_pin && apdu.nc == 0)
return SW_OK(); return SW_OK();
if (*file_get_data(file_pin1) == 0) //not initialized if (*file_get_data(file_pin1) == 0 && pka_enabled() == false) //not initialized
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
if (apdu.nc > 0) { if (apdu.nc > 0) {
return check_pin(file_pin1, apdu.data, apdu.nc); return check_pin(file_pin1, apdu.data, apdu.nc);
@@ -813,42 +818,52 @@ static int cmd_initialize() {
return SW_OK(); return SW_OK();
} }
uint8_t get_key_domain(file_t *fkey) { const uint8_t *get_meta_tag(file_t *ef, uint16_t meta_tag, size_t *tag_len) {
if (!fkey) if (ef == NULL)
return 0xff; return NULL;
uint8_t *meta_data = NULL; uint8_t *meta_data = NULL;
uint8_t meta_size = meta_find(fkey->fid, &meta_data); uint8_t meta_size = meta_find(ef->fid, &meta_data);
if (meta_size > 0 && meta_data != NULL) { if (meta_size > 0 && meta_data != NULL) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
size_t tag_len = 0; while (walk_tlv(meta_data, meta_size, &p, &tag, tag_len, &tag_data)) {
while (walk_tlv(meta_data, meta_size, &p, &tag, &tag_len, &tag_data)) { if (tag == meta_tag) {
if (tag == 0x92) { //ofset tag return tag_data;
return *tag_data;
} }
} }
} }
return NULL;
}
uint8_t get_key_domain(file_t *fkey) {
size_t tag_len = 0;
const uint8_t *meta_tag = get_meta_tag(fkey, 0x92, &tag_len);
if (meta_tag)
return *meta_tag;
return 0; return 0;
} }
uint32_t get_key_counter(file_t *fkey) { uint32_t get_key_counter(file_t *fkey) {
if (!fkey) size_t tag_len = 0;
return 0xffffff; const uint8_t *meta_tag = get_meta_tag(fkey, 0x90, &tag_len);
uint8_t *meta_data = NULL; if (meta_tag)
uint8_t meta_size = meta_find(fkey->fid, &meta_data); return (meta_tag[0] << 24) | (meta_tag[1] << 16) | (meta_tag[2] << 8) | meta_tag[3];
if (meta_size > 0 && meta_data != NULL) {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
size_t tag_len = 0;
while (walk_tlv(meta_data, meta_size, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x90) { //ofset tag
return (tag_data[0] << 24) | (tag_data[1] << 16) | (tag_data[2] << 8) | tag_data[3];
}
}
}
return 0xffffffff; return 0xffffffff;
} }
bool key_has_purpose(file_t *ef, uint8_t purpose) {
size_t tag_len = 0;
const uint8_t *meta_tag = get_meta_tag(ef, 0x91, &tag_len);
if (meta_tag) {
for (int i = 0; i < tag_len; i++) {
if (meta_tag[i] == purpose)
return true;
}
return false;
}
return true;
}
uint32_t decrement_key_counter(file_t *fkey) { uint32_t decrement_key_counter(file_t *fkey) {
if (!fkey) if (!fkey)
return 0xffffff; return 0xffffff;
@@ -887,7 +902,7 @@ static int cmd_key_domain() {
//if (dkeks == 0) //if (dkeks == 0)
// return SW_COMMAND_NOT_ALLOWED(); // return SW_COMMAND_NOT_ALLOWED();
uint8_t p1 = P1(apdu), p2 = P2(apdu); uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (has_session_pin == false && apdu.nc > 0) if ((has_session_pin == false || isUserAuthenticated == false) && apdu.nc > 0)
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
if (p2 >= MAX_KEY_DOMAINS) if (p2 >= MAX_KEY_DOMAINS)
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
@@ -1225,6 +1240,7 @@ static int cmd_delete_file() {
} }
if (!authenticate_action(ef, ACL_OP_DELETE_SELF)) if (!authenticate_action(ef, ACL_OP_DELETE_SELF))
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
meta_delete(ef->fid);
if (flash_clear_file(ef) != CCID_OK) if (flash_clear_file(ef) != CCID_OK)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
if (delete_dynamic_file(ef) != CCID_OK) if (delete_dynamic_file(ef) != CCID_OK)
@@ -1441,6 +1457,8 @@ static int cmd_signature() {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
if (get_key_counter(fkey) == 0) if (get_key_counter(fkey) == 0)
return SW_FILE_FULL(); return SW_FILE_FULL();
if (key_has_purpose(fkey, p2) == false)
return SW_CONDITIONS_NOT_SATISFIED();
int key_size = file_get_size(fkey); int key_size = file_get_size(fkey);
if (p2 == ALGO_RSA_PKCS1_SHA1 || p2 == ALGO_RSA_PSS_SHA1 || p2 == ALGO_EC_SHA1) if (p2 == ALGO_RSA_PKCS1_SHA1 || p2 == ALGO_RSA_PSS_SHA1 || p2 == ALGO_EC_SHA1)
md = MBEDTLS_MD_SHA1; md = MBEDTLS_MD_SHA1;
@@ -1452,7 +1470,7 @@ static int cmd_signature() {
generic_hash(md, apdu.data, apdu.nc, apdu.data); generic_hash(md, apdu.data, apdu.nc, apdu.data);
apdu.nc = mbedtls_md_get_size(mbedtls_md_info_from_type(md)); apdu.nc = mbedtls_md_get_size(mbedtls_md_info_from_type(md));
} }
if (p2 == ALGO_RSA_RAW || p2 == ALGO_RSA_PKCS1 || p2 == ALGO_RSA_PKCS1_SHA1 || p2 == ALGO_RSA_PKCS1_SHA256 || p2 == ALGO_RSA_PSS || p2 == ALGO_RSA_PSS_SHA1 || p2 == ALGO_RSA_PSS_SHA256) { if (p2 >= ALGO_RSA_RAW && p2 <= ALGO_RSA_PSS_SHA512) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
@@ -1496,12 +1514,18 @@ static int cmd_signature() {
else if (memcmp(oid, MBEDTLS_OID_DIGEST_ALG_SHA512, oid_len) == 0) else if (memcmp(oid, MBEDTLS_OID_DIGEST_ALG_SHA512, oid_len) == 0)
md = MBEDTLS_MD_SHA512; md = MBEDTLS_MD_SHA512;
} }
if (p2 == ALGO_RSA_PSS || p2 == ALGO_RSA_PSS_SHA1 || p2 == ALGO_RSA_PSS_SHA256) { if (p2 >= ALGO_RSA_PSS && p2 <= ALGO_RSA_PSS_SHA512) {
if (p2 == ALGO_RSA_PSS && !oid) { if (p2 == ALGO_RSA_PSS && !oid) {
if (apdu.nc == 20) //default is sha1 if (apdu.nc == 20) //default is sha1
md = MBEDTLS_MD_SHA1; md = MBEDTLS_MD_SHA1;
else if (apdu.nc == 32) else if (apdu.nc == 28)
md = MBEDTLS_MD_SHA224;
else if (apdu.nc == 32)
md = MBEDTLS_MD_SHA256; md = MBEDTLS_MD_SHA256;
else if (apdu.nc == 48)
md = MBEDTLS_MD_SHA384;
else if (apdu.nc == 64)
md = MBEDTLS_MD_SHA512;
} }
mbedtls_rsa_set_padding(&ctx, MBEDTLS_RSA_PKCS_V21, md); mbedtls_rsa_set_padding(&ctx, MBEDTLS_RSA_PKCS_V21, md);
} }
@@ -1525,7 +1549,7 @@ static int cmd_signature() {
apdu.ne = key_size; apdu.ne = key_size;
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
} }
else if (p2 == ALGO_EC_RAW || p2 == ALGO_EC_SHA1 || p2 == ALGO_EC_SHA224 || p2 == ALGO_EC_SHA256) { else if (p2 >= ALGO_EC_RAW && p2 <= ALGO_EC_SHA512) {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
md = MBEDTLS_MD_SHA256; md = MBEDTLS_MD_SHA256;
@@ -1547,6 +1571,10 @@ static int cmd_signature() {
md = MBEDTLS_MD_SHA224; md = MBEDTLS_MD_SHA224;
else if (p2 == ALGO_EC_SHA256) else if (p2 == ALGO_EC_SHA256)
md = MBEDTLS_MD_SHA256; md = MBEDTLS_MD_SHA256;
else if (p2 == ALGO_EC_SHA384)
md = MBEDTLS_MD_SHA384;
else if (p2 == ALGO_EC_SHA512)
md = MBEDTLS_MD_SHA512;
int r; int r;
r = load_private_key_ecdsa(&ctx, fkey); r = load_private_key_ecdsa(&ctx, fkey);
if (r != CCID_OK) { if (r != CCID_OK) {
@@ -1581,6 +1609,8 @@ static int cmd_key_wrap() {
uint8_t kdom = get_key_domain(ef); uint8_t kdom = get_key_domain(ef);
if (!ef) if (!ef)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
if (key_has_purpose(ef, ALGO_WRAP) == false)
return SW_CONDITIONS_NOT_SATISFIED();
file_t *prkd = search_dynamic_file((PRKD_PREFIX << 8) | key_id); file_t *prkd = search_dynamic_file((PRKD_PREFIX << 8) | key_id);
if (!prkd) if (!prkd)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
@@ -1711,6 +1741,7 @@ static int cmd_key_unwrap() {
static int cmd_decrypt_asym() { static int cmd_decrypt_asym() {
int key_id = P1(apdu); int key_id = P1(apdu);
uint8_t p2 = P2(apdu);
if (!isUserAuthenticated) if (!isUserAuthenticated)
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id); file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id);
@@ -1718,9 +1749,13 @@ static int cmd_decrypt_asym() {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
if (get_key_counter(ef) == 0) if (get_key_counter(ef) == 0)
return SW_FILE_FULL(); return SW_FILE_FULL();
if (P2(apdu) == ALGO_RSA_DECRYPT) { if (key_has_purpose(ef, p2) == false)
return SW_CONDITIONS_NOT_SATISFIED();
if (p2 >= ALGO_RSA_DECRYPT && p2 <= ALGO_RSA_DECRYPT_OEP) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
if (p2 == ALGO_RSA_DECRYPT_OEP)
mbedtls_rsa_set_padding(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_NONE);
int r = load_private_key_rsa(&ctx, ef); int r = load_private_key_rsa(&ctx, ef);
if (r != CCID_OK) { if (r != CCID_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
@@ -1731,15 +1766,24 @@ static int cmd_decrypt_asym() {
int key_size = file_get_size(ef); int key_size = file_get_size(ef);
if (apdu.nc < key_size) //needs padding if (apdu.nc < key_size) //needs padding
memset(apdu.data+apdu.nc, 0, key_size-apdu.nc); memset(apdu.data+apdu.nc, 0, key_size-apdu.nc);
r = mbedtls_rsa_private(&ctx, random_gen, NULL, apdu.data, res_APDU); if (p2 == ALGO_RSA_DECRYPT_PKCS1 || p2 == ALGO_RSA_DECRYPT_OEP) {
size_t olen = apdu.nc;
r = mbedtls_rsa_pkcs1_decrypt(&ctx, random_gen, NULL, &olen, apdu.data, res_APDU, 512);
if (r == 0)
res_APDU_size = olen;
}
else {
r = mbedtls_rsa_private(&ctx, random_gen, NULL, apdu.data, res_APDU);
if (r == 0)
res_APDU_size = key_size;
}
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU_size = key_size;
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
} }
else if (P2(apdu) == ALGO_EC_DH) { else if (p2 == ALGO_EC_DH) {
mbedtls_ecdh_context ctx; mbedtls_ecdh_context ctx;
if (wait_button() == true) //timeout if (wait_button() == true) //timeout
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
@@ -1795,6 +1839,8 @@ static int cmd_cipher_sym() {
file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id); file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id);
if (!ef) if (!ef)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
if (key_has_purpose(ef, algo) == false)
return SW_CONDITIONS_NOT_SATISFIED();
if ((apdu.nc % 16) != 0) { if ((apdu.nc % 16) != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
@@ -1890,7 +1936,8 @@ static int cmd_derive_asym() {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
if (!(fkey = search_dynamic_file((KEY_PREFIX << 8) | key_id)) || !fkey->data || file_get_size(fkey) == 0) if (!(fkey = search_dynamic_file((KEY_PREFIX << 8) | key_id)) || !fkey->data || file_get_size(fkey) == 0)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
if (key_has_purpose(fkey, ALGO_EC_DERIVE) == false)
return SW_CONDITIONS_NOT_SATISFIED();
if (apdu.nc == 0) if (apdu.nc == 0)
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
if (apdu.data[0] == ALGO_EC_DERIVE) { if (apdu.data[0] == ALGO_EC_DERIVE) {
@@ -2342,7 +2389,7 @@ int cmd_external_authenticate() {
for (int i = 0; i < puk_data[0]; i++) for (int i = 0; i < puk_data[0]; i++)
auts += puk_status[i]; auts += puk_status[i];
if (auts >= puk_data[2]) { if (auts >= puk_data[2]) {
has_session_pin = isUserAuthenticated = true; isUserAuthenticated = true;
} }
return SW_OK(); return SW_OK();
} }

View File

@@ -26,21 +26,35 @@ extern const uint8_t sc_hsm_aid[];
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */ #define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */ #define ALGO_RSA_DECRYPT 0x21 /* RSA raw decrypt */
#define ALGO_RSA_DECRYPT_PKCS1 0x22
#define ALGO_RSA_DECRYPT_OEP 0x23
#define ALGO_RSA_PKCS1 0x30 /* RSA signature with DigestInfo input and PKCS#1 V1.5 padding */ #define ALGO_RSA_PKCS1 0x30 /* RSA signature with DigestInfo input and PKCS#1 V1.5 padding */
#define ALGO_RSA_PKCS1_SHA1 0x31 /* RSA signature with SHA-1 hash and PKCS#1 V1.5 padding */ #define ALGO_RSA_PKCS1_SHA1 0x31 /* RSA signature with SHA-1 hash and PKCS#1 V1.5 padding */
#define ALGO_RSA_PKCS1_SHA224 0x32
#define ALGO_RSA_PKCS1_SHA256 0x33 /* RSA signature with SHA-256 hash and PKCS#1 V1.5 padding */ #define ALGO_RSA_PKCS1_SHA256 0x33 /* RSA signature with SHA-256 hash and PKCS#1 V1.5 padding */
#define ALGO_RSA_PKCS1_SHA384 0x34
#define ALGO_RSA_PKCS1_SHA512 0x35
#define ALGO_RSA_PSS 0x40 /* RSA signature with external hash and PKCS#1 PSS padding*/ #define ALGO_RSA_PSS 0x40 /* RSA signature with external hash and PKCS#1 PSS padding*/
#define ALGO_RSA_PSS_SHA1 0x41 /* RSA signature with SHA-1 hash and PKCS#1 PSS padding */ #define ALGO_RSA_PSS_SHA1 0x41 /* RSA signature with SHA-1 hash and PKCS#1 PSS padding */
#define ALGO_RSA_PSS_SHA224 0x42
#define ALGO_RSA_PSS_SHA256 0x43 /* RSA signature with SHA-256 hash and PKCS#1 PSS padding */ #define ALGO_RSA_PSS_SHA256 0x43 /* RSA signature with SHA-256 hash and PKCS#1 PSS padding */
#define ALGO_RSA_PSS_SHA384 0x44
#define ALGO_RSA_PSS_SHA512 0x45
#define ALGO_EC_RAW 0x70 /* ECDSA signature with hash input */ #define ALGO_EC_RAW 0x70 /* ECDSA signature with hash input */
#define ALGO_EC_SHA1 0x71 /* ECDSA signature with SHA-1 hash */ #define ALGO_EC_SHA1 0x71 /* ECDSA signature with SHA-1 hash */
#define ALGO_EC_SHA224 0x72 /* ECDSA signature with SHA-224 hash */ #define ALGO_EC_SHA224 0x72 /* ECDSA signature with SHA-224 hash */
#define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */ #define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */
#define ALGO_EC_SHA384 0x74
#define ALGO_EC_SHA512 0x75
#define ALGO_EC_DH 0x80 /* ECDH key derivation */ #define ALGO_EC_DH 0x80 /* ECDH key derivation */
#define ALGO_WRAP 0x92
#define ALGO_UNWRAP 0x93
#define ALGO_REPLACE 0x94
#define ALGO_EC_DERIVE 0x98 /* Derive EC key from EC key */ #define ALGO_EC_DERIVE 0x98 /* Derive EC key from EC key */
#define ALGO_AES_CBC_ENCRYPT 0x10 #define ALGO_AES_CBC_ENCRYPT 0x10

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_ #ifndef __VERSION_H_
#define __VERSION_H_ #define __VERSION_H_
#define HSM_VERSION 0x0204 #define HSM_VERSION 0x0206
#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)