mirror of
https://github.com/polhenarejos/pico-hsm.git
synced 2026-02-07 19:18:23 +00:00
Introducing version 2.0 with the following enhancements:
- Added Secure Messaging. - Added Session PIN. - Added tool to burn CVCerts onto the firmware, like a PKI.
This commit is contained in:
commit
5f4aafed37
29 changed files with 603 additions and 4034 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,6 +1,6 @@
|
|||
[submodule "OpenSC"]
|
||||
path = OpenSC
|
||||
url = https://github.com/polhenarejos/OpenSC
|
||||
[submodule "mbedtls"]
|
||||
path = mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
[submodule "pico-ccid"]
|
||||
path = pico-ccid
|
||||
url = https://github.com/polhenarejos/pico-ccid
|
||||
|
|
|
|||
103
CMakeLists.txt
103
CMakeLists.txt
|
|
@ -41,51 +41,61 @@ set_source_files_properties(
|
|||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/ctx.c
|
||||
PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\""
|
||||
)
|
||||
|
||||
|
||||
find_package( PythonInterp 3.7 REQUIRED )
|
||||
|
||||
if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/hsm/cvcerts.h)
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/burn-cvcerts.py ${CMAKE_CURRENT_LIST_DIR})
|
||||
message("Burning CVCert")
|
||||
endif()
|
||||
|
||||
target_sources(pico_hsm PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/files.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hmac_drbg.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/camellia.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aria.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/nist_kw.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1write.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hmac_drbg.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chachapoly.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/camellia.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chacha20.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aria.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/poly1305.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/gcm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ccm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/des.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/nist_kw.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hkdf.c
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c
|
||||
|
|
@ -106,15 +116,16 @@ target_sources(pico_hsm PUBLIC
|
|||
)
|
||||
|
||||
target_include_directories(pico_hsm PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb
|
||||
${CMAKE_CURRENT_LIST_DIR}/opensc/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library
|
||||
)
|
||||
|
||||
|
||||
pico_add_extra_outputs(pico_hsm)
|
||||
|
||||
#target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
VERSION_MAJOR="1"
|
||||
VERSION_MINOR="12"
|
||||
VERSION_MAJOR="2"
|
||||
VERSION_MINOR="0"
|
||||
|
||||
rm -rf release/*
|
||||
cd build_release
|
||||
|
|
|
|||
78
burn-cvcerts.py
Normal file
78
burn-cvcerts.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Apr 13 20:15:01 2022
|
||||
|
||||
@author: Pol Henarejos
|
||||
"""
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
import base64
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
def print_var(v, name):
|
||||
s = '\n'
|
||||
s += "static const unsigned char "+name+"[] = {\n"
|
||||
s += "\t0x{:02x},0x{:02x},\n".format((len(v) & 0xff),((len(v)>> 8) & 0xff))
|
||||
for i in range(len(v)):
|
||||
if (i%16 == 0):
|
||||
s += '\t'
|
||||
s += "0x{:02x}".format((v[i]))
|
||||
if (i < len(v)-1):
|
||||
s += ','
|
||||
if (i%16 == 15):
|
||||
s += '\n'
|
||||
s += '\n'
|
||||
s += '};\n'
|
||||
return s
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
private_key = ec.generate_private_key(ec.SECP192R1(), default_backend())
|
||||
public_key = private_key.public_key()
|
||||
pub_num = public_key.public_numbers()
|
||||
pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to_bytes(24,'big'))
|
||||
|
||||
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
|
||||
|
||||
data = urllib.parse.urlencode({'pubkey':pbk}).encode()
|
||||
req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", method='POST', data=data, headers={'User-Agent':user_agent,} ) #The assembled request
|
||||
response = urllib.request.urlopen(req)
|
||||
resp = response.read().decode('utf-8')
|
||||
j = json.loads(resp)
|
||||
cvcert = base64.b64decode(j['cvcert'])
|
||||
|
||||
dica = [
|
||||
0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||
0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e,
|
||||
0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb,
|
||||
0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08,
|
||||
0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20,
|
||||
0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80,
|
||||
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||
0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5,
|
||||
0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d,
|
||||
0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99,
|
||||
0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d
|
||||
]
|
||||
|
||||
s = '#ifndef _CVCERTS_H_\n#define _CVCERTS_H_\n'
|
||||
s += print_var(dica,'dica')
|
||||
s += print_var(cvcert,'termca')
|
||||
|
||||
pvk = private_key.private_numbers().private_value.to_bytes(24,'big')
|
||||
s += print_var(pvk,'termca_pk')
|
||||
s += '\n#endif\n'
|
||||
f = open(args[0] + '/src/hsm/cvcerts.h','w')
|
||||
f.write(s)
|
||||
f.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -4,12 +4,12 @@ Pico HSM supports a customized extra command to use with different options. Sinc
|
|||
|
||||
To send a raw APDU command, `opensc-tool -s <APDU>` can be used. The `APDU` parameter is a string of hexadecimal numbers and it takes the following form:
|
||||
```
|
||||
8054XX00YYZZZZRR
|
||||
8064XX00YYZZZZRR
|
||||
```
|
||||
|
||||
It composed by the following fields:
|
||||
- `80` to indicate that it is a custom vendor type command.
|
||||
- `54` is the `INS` custom command.
|
||||
- `64` is the `INS` custom command.
|
||||
- `XX` is the command to execute. It varies depending on the targeted command.
|
||||
- `00` is the parameter of the command. At this moment, no commands support parameters.
|
||||
- `YY` is the length of the data. If no data is provided, this field is absent.
|
||||
|
|
@ -25,9 +25,9 @@ To obtain the current datetime (referenced to 00:00:00 2020/01/01), the `XX` par
|
|||
For example, to obtain the current datetime:
|
||||
|
||||
```
|
||||
$ opensc-tool -s 80540A0008
|
||||
$ opensc-tool -s 80640A0008
|
||||
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||
Sending: 80 54 0A 00 08
|
||||
Sending: 80 64 0A 00 08
|
||||
Received (SW1=0x90, SW2=0x00):
|
||||
07 E6 04 06 03 13 29 1E ......).
|
||||
```
|
||||
|
|
@ -47,9 +47,9 @@ If the command is correctly received, `SW1=0x90` and `SW2=0x00`. Other values me
|
|||
To set the reference datetime, a datetime string must be provided. For example:
|
||||
|
||||
```
|
||||
$ opensc-tool -s 80540A000807E6040603132917
|
||||
$ opensc-tool -s 80640A000807E6040603132917
|
||||
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||
Sending: 80 54 0A 00 08 07 E6 04 06 03 13 29 17
|
||||
Sending: 80 64 0A 00 08 07 E6 04 06 03 13 29 17
|
||||
Received (SW1=0x90, SW2=0x00)
|
||||
```
|
||||
|
||||
|
|
@ -66,9 +66,9 @@ Press-to-confirm button offers an extra security layer by requiring the user con
|
|||
This feature is disabled by default but can be enabled rapidly by setting the LSB bit to 1:
|
||||
|
||||
```
|
||||
$ opensc-tool -s 805406000101
|
||||
$ opensc-tool -s 806406000101
|
||||
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||
Sending: 80 54 06 00 01 01
|
||||
Sending: 80 64 06 00 01 01
|
||||
Received (SW1=0x90, SW2=0x00)
|
||||
```
|
||||
|
||||
|
|
@ -77,9 +77,9 @@ At this moment, when a private/secret key is loaded, the Pico HSM will wait for
|
|||
To disable, the LSB bit must be set to 0:
|
||||
|
||||
```
|
||||
$ opensc-tool -s 805406000100
|
||||
$ opensc-tool -s 806406000100
|
||||
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||
Sending: 80 54 06 00 01 00
|
||||
Sending: 80 64 06 00 01 00
|
||||
Received (SW1=0x90, SW2=0x00)
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
VERSION_MAJOR="1"
|
||||
VERSION_MINOR="0C"
|
||||
VERSION_MAJOR="2"
|
||||
VERSION_MINOR="0"
|
||||
|
||||
echo "----------------------------"
|
||||
echo "VID/PID patcher for Pico HSM"
|
||||
|
|
|
|||
1
pico-ccid
Submodule
1
pico-ccid
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5e51c9a072fecc7113702b74e13b8a2d346186b2
|
||||
416
src/fs/file.c
416
src/fs/file.c
|
|
@ -1,416 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
#include "tusb.h"
|
||||
#include "hsm2040.h"
|
||||
#include "sc_hsm.h"
|
||||
#include "libopensc/card-sc-hsm.h"
|
||||
#include <string.h>
|
||||
|
||||
extern const uintptr_t end_data_pool;
|
||||
extern const uintptr_t start_data_pool;
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_word (uintptr_t addr, uint32_t data);
|
||||
extern int flash_program_uintptr (uintptr_t addr, uintptr_t data);
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t flash_read_uint8(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
extern void low_flash_available();
|
||||
|
||||
//puts FCI in the RAPDU
|
||||
void process_fci(const file_t *pe) {
|
||||
uint8_t *p = res_APDU;
|
||||
uint8_t buf[64];
|
||||
res_APDU_size = 0;
|
||||
res_APDU[res_APDU_size++] = 0x6f;
|
||||
res_APDU[res_APDU_size++] = 0x00; //computed later
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x81;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
if (pe->data) {
|
||||
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||
uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
|
||||
res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
|
||||
res_APDU[res_APDU_size++] = len & 0xff;
|
||||
}
|
||||
else {
|
||||
res_APDU[res_APDU_size++] = pe->data[1];
|
||||
res_APDU[res_APDU_size++] = pe->data[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(res_APDU+res_APDU_size, 0, 2);
|
||||
res_APDU_size += 2;
|
||||
}
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x82;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size] = 0;
|
||||
if (pe->type == FILE_TYPE_INTERNAL_EF)
|
||||
res_APDU[res_APDU_size++] |= 0x08;
|
||||
else if (pe->type == FILE_TYPE_WORKING_EF)
|
||||
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
|
||||
else if (pe->type == FILE_TYPE_DF)
|
||||
res_APDU[res_APDU_size++] |= 0x38;
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x83;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
put_uint16_t(pe->fid, res_APDU+res_APDU_size);
|
||||
res_APDU_size += 2;
|
||||
res_APDU[1] = res_APDU_size-2;
|
||||
}
|
||||
|
||||
extern const uint8_t sc_hsm_aid[];
|
||||
extern int parse_token_info(const file_t *f, int mode);
|
||||
extern int parse_cvca(const file_t *f, int mode);
|
||||
|
||||
file_t file_entries[] = {
|
||||
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
|
||||
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
|
||||
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
|
||||
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
||||
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
|
||||
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
|
||||
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
|
||||
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
|
||||
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
|
||||
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
|
||||
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
|
||||
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
||||
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
||||
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
||||
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
|
||||
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
||||
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
||||
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
||||
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
||||
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
||||
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
||||
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||
/* 25 */ { .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 *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
|
||||
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
|
||||
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
|
||||
file_t *file_pin1 = NULL;
|
||||
file_t *file_retries_pin1 = NULL;
|
||||
file_t *file_sopin = NULL;
|
||||
file_t *file_retries_sopin = NULL;
|
||||
|
||||
#define MAX_DYNAMIC_FILES 64
|
||||
uint16_t dynamic_files = 0;
|
||||
file_t dynamic_file[MAX_DYNAMIC_FILES];
|
||||
|
||||
bool card_terminated = false;
|
||||
|
||||
bool is_parent(const file_t *child, const file_t *parent) {
|
||||
if (child == parent)
|
||||
return true;
|
||||
if (child == MF)
|
||||
return false;
|
||||
return is_parent(&file_entries[child->parent], parent);
|
||||
}
|
||||
|
||||
file_t *get_parent(file_t *f) {
|
||||
return &file_entries[f->parent];
|
||||
}
|
||||
|
||||
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
for (file_t *p = file_entries; p != file_last; p++) {
|
||||
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
|
||||
|
||||
for (file_t *p = file_entries; p != file_last; p++) {
|
||||
if (p->fid != 0x0000 && p->fid == fid) {
|
||||
if (!parent || (parent && is_parent(p, parent))) {
|
||||
if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
|
||||
if (!buflen)
|
||||
return 0;
|
||||
if (pe == top) //MF or relative DF
|
||||
return 0;
|
||||
put_uint16_t(pe->fid, buf);
|
||||
return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
|
||||
}
|
||||
|
||||
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
uint8_t buf[MAX_DEPTH*2], *p = path;
|
||||
put_uint16_t(pe->fid, buf);
|
||||
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2;
|
||||
for (int d = depth-2; d >= 0; d -= 2) {
|
||||
memcpy(p, buf+d, 2);
|
||||
p += 2;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
|
||||
uint8_t path[MAX_DEPTH*2];
|
||||
if (pathlen > sizeof(path)) {
|
||||
return NULL;
|
||||
}
|
||||
for (file_t *p = file_entries; p != file_last; p++) {
|
||||
uint8_t depth = make_path(p, parent, path);
|
||||
if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *currentEF = NULL;
|
||||
file_t *currentDF = NULL;
|
||||
const file_t *selected_applet = NULL;
|
||||
bool isUserAuthenticated = false;
|
||||
|
||||
bool authenticate_action(const file_t *ef, uint8_t op) {
|
||||
uint8_t acl = ef->acl[op];
|
||||
if (acl == 0x0)
|
||||
return true;
|
||||
else if (acl == 0xff)
|
||||
return false;
|
||||
else if (acl == 0x90 || acl & 0x9F == 0x10) {
|
||||
// PIN required.
|
||||
if(isUserAuthenticated) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "libopensc/pkcs15.h"
|
||||
|
||||
void initialize_chain(file_chain_t **chain) {
|
||||
file_chain_t *next;
|
||||
for (file_chain_t *f = *chain; f; f = next) {
|
||||
next = f->next;
|
||||
free(f);
|
||||
}
|
||||
*chain = NULL;
|
||||
}
|
||||
|
||||
void initialize_flash(bool hard) {
|
||||
if (hard) {
|
||||
const uint8_t empty[8] = { 0 };
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
low_flash_available();
|
||||
}
|
||||
for (file_t *f = file_entries; f != file_last; f++) {
|
||||
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
|
||||
f->data = NULL;
|
||||
}
|
||||
dynamic_files = 0;
|
||||
}
|
||||
|
||||
void scan_flash() {
|
||||
initialize_flash(false); //soft initialization
|
||||
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
|
||||
{
|
||||
printf("First initialization (or corrupted!)\r\n");
|
||||
const uint8_t empty[8] = { 0 };
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
//low_flash_available();
|
||||
//wait_flash_finish();
|
||||
}
|
||||
printf("SCAN\r\n");
|
||||
|
||||
uintptr_t base = flash_read_uintptr(end_data_pool);
|
||||
for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) {
|
||||
if (base == 0x0) //all is empty
|
||||
break;
|
||||
|
||||
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
|
||||
printf("[%x] scan fid %x, len %d\r\n",base,fid,flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t)));
|
||||
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
if (!file) {
|
||||
file = file_new(fid);
|
||||
uint8_t pfx = fid >> 8;
|
||||
if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) {
|
||||
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
|
||||
if (flash_read_uintptr(base) == 0x0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
|
||||
if (file_pin1) {
|
||||
if (!file_pin1->data) {
|
||||
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
|
||||
const uint8_t empty[33] = { 0 };
|
||||
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
|
||||
}
|
||||
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
|
||||
if (file_sopin) {
|
||||
if (!file_sopin->data) {
|
||||
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
|
||||
const uint8_t empty[33] = { 0 };
|
||||
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
|
||||
}
|
||||
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
|
||||
if (file_retries_pin1) {
|
||||
if (!file_retries_pin1->data) {
|
||||
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
|
||||
const uint8_t retries = 3;
|
||||
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
|
||||
}
|
||||
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
|
||||
if (file_retries_sopin) {
|
||||
if (!file_retries_sopin->data) {
|
||||
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
|
||||
const uint8_t retries = 15;
|
||||
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
|
||||
}
|
||||
file_t *tf = NULL;
|
||||
|
||||
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
|
||||
if (tf) {
|
||||
if (!tf->data) {
|
||||
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
|
||||
const uint8_t retries = 3;
|
||||
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
|
||||
}
|
||||
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
|
||||
if (tf) {
|
||||
if (!tf->data) {
|
||||
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
|
||||
const uint8_t retries = 15;
|
||||
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
|
||||
}
|
||||
low_flash_available();
|
||||
}
|
||||
|
||||
uint8_t *file_read(const uint8_t *addr) {
|
||||
return flash_read((uintptr_t)addr);
|
||||
}
|
||||
uint16_t file_read_uint16(const uint8_t *addr) {
|
||||
return flash_read_uint16((uintptr_t)addr);
|
||||
}
|
||||
uint8_t file_read_uint8(const uint8_t *addr) {
|
||||
return flash_read_uint8((uintptr_t)addr);
|
||||
}
|
||||
|
||||
file_t *search_dynamic_file(uint16_t fid) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == fid)
|
||||
return &dynamic_file[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int delete_dynamic_file(file_t *f) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == f->fid) {
|
||||
for (int j = i+1; j < dynamic_files; j++)
|
||||
memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
|
||||
dynamic_files--;
|
||||
return HSM_OK;
|
||||
}
|
||||
}
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
file_t *file_new(uint16_t fid) {
|
||||
file_t *f;
|
||||
if ((f = search_dynamic_file(fid)))
|
||||
return f;
|
||||
if (dynamic_files == MAX_DYNAMIC_FILES)
|
||||
return NULL;
|
||||
f = &dynamic_file[dynamic_files];
|
||||
dynamic_files++;
|
||||
file_t file = {
|
||||
.fid = fid,
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.data = NULL,
|
||||
.acl = {0}
|
||||
};
|
||||
memcpy(f, &file, sizeof(file_t));
|
||||
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
|
||||
return f;
|
||||
}
|
||||
|
||||
file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) {
|
||||
if (search_file_chain(file->fid, *chain))
|
||||
return NULL;
|
||||
file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t));
|
||||
fc->file = file;
|
||||
fc->next = *chain;
|
||||
*chain = fc;
|
||||
return fc;
|
||||
}
|
||||
|
||||
file_t *search_file_chain(uint16_t fid, file_chain_t *chain) {
|
||||
for (file_chain_t *fc = chain; fc; fc = fc->next) {
|
||||
if (fid == fc->file->fid) {
|
||||
return fc->file;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
124
src/fs/file.h
124
src/fs/file.h
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#define FILE_TYPE_UNKNOWN 0x00
|
||||
#define FILE_TYPE_DF 0x04
|
||||
#define FILE_TYPE_INTERNAL_EF 0x03
|
||||
#define FILE_TYPE_WORKING_EF 0x01
|
||||
#define FILE_TYPE_BSO 0x10
|
||||
#define FILE_PERSISTENT 0x20
|
||||
#define FILE_DATA_FLASH 0x40
|
||||
#define FILE_DATA_FUNC 0x80
|
||||
|
||||
/* EF structures */
|
||||
#define FILE_EF_UNKNOWN 0x00
|
||||
#define FILE_EF_TRANSPARENT 0x01
|
||||
#define FILE_EF_LINEAR_FIXED 0x02
|
||||
#define FILE_EF_LINEAR_FIXED_TLV 0x03
|
||||
#define FILE_EF_LINEAR_VARIABLE 0x04
|
||||
#define FILE_EF_LINEAR_VARIABLE_TLV 0x05
|
||||
#define FILE_EF_CYCLIC 0x06
|
||||
#define FILE_EF_CYCLIC_TLV 0x07
|
||||
|
||||
#define ACL_OP_DELETE_SELF 0x00
|
||||
#define ACL_OP_CREATE_DF 0x01
|
||||
#define ACL_OP_CREATE_EF 0x02
|
||||
#define ACL_OP_DELETE_CHILD 0x03
|
||||
#define ACL_OP_WRITE 0x04
|
||||
#define ACL_OP_UPDATE_ERASE 0x05
|
||||
#define ACL_OP_READ_SEARCH 0x06
|
||||
|
||||
#define SPECIFY_EF 0x1
|
||||
#define SPECIFY_DF 0x2
|
||||
#define SPECIFY_ANY 0x3
|
||||
|
||||
#define EF_DKEK 0x108F
|
||||
#define EF_PRKDFS 0x6040
|
||||
#define EF_PUKDFS 0x6041
|
||||
#define EF_CDFS 0x6042
|
||||
#define EF_AODFS 0x6043
|
||||
#define EF_DODFS 0x6044
|
||||
#define EF_SKDFS 0x6045
|
||||
#define EF_DEVOPS 0x100E
|
||||
|
||||
#define MAX_DEPTH 4
|
||||
|
||||
typedef struct file
|
||||
{
|
||||
const uint16_t fid;
|
||||
const uint8_t parent; //entry number in the whole table!!
|
||||
const uint8_t *name;
|
||||
const uint8_t type;
|
||||
const uint8_t ef_structure;
|
||||
uint8_t *data; //should include 2 bytes len at begining
|
||||
const uint8_t acl[7];
|
||||
} __attribute__((packed)) file_t;
|
||||
|
||||
typedef struct file_chain
|
||||
{
|
||||
file_t *file;
|
||||
struct file_chain *next;
|
||||
} file_chain_t;
|
||||
|
||||
extern file_t *currentEF;
|
||||
extern file_t *currentDF;
|
||||
extern const file_t *selected_applet;
|
||||
|
||||
extern const file_t *MF;
|
||||
extern const file_t *file_last;
|
||||
extern const file_t *file_openpgp;
|
||||
extern const file_t *file_sc_hsm;
|
||||
extern bool card_terminated;
|
||||
extern file_t *file_pin1;
|
||||
extern file_t *file_retries_pin1;
|
||||
extern file_t *file_sopin;
|
||||
extern file_t *file_retries_sopin;
|
||||
|
||||
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
|
||||
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
|
||||
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||
extern bool authenticate_action(const file_t *ef, uint8_t op);
|
||||
extern void process_fci(const file_t *pe);
|
||||
extern void scan_flash();
|
||||
extern void initialize_flash(bool);
|
||||
|
||||
extern file_t file_entries[];
|
||||
|
||||
extern uint8_t *file_read(const uint8_t *addr);
|
||||
extern uint16_t file_read_uint16(const uint8_t *addr);
|
||||
extern uint8_t file_read_uint8(const uint8_t *addr);
|
||||
extern file_t *file_new(uint16_t);
|
||||
file_t *get_parent(file_t *f);
|
||||
|
||||
extern uint16_t dynamic_files;
|
||||
extern file_t dynamic_file[];
|
||||
extern file_t *search_dynamic_file(uint16_t);
|
||||
extern int delete_dynamic_file(file_t *f);
|
||||
|
||||
extern file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain);
|
||||
extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain);
|
||||
extern bool isUserAuthenticated;
|
||||
|
||||
#endif
|
||||
|
||||
133
src/fs/flash.c
133
src/fs/flash.c
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hsm2040.h"
|
||||
#include "tusb.h"
|
||||
#include "file.h"
|
||||
#include "sc_hsm.h"
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
* | |
|
||||
* | next_addr | prev_addr | fid | data (len + payload) |
|
||||
* | |
|
||||
* ------------------------------------------------------
|
||||
*/
|
||||
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
|
||||
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
|
||||
|
||||
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
|
||||
|
||||
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
|
||||
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE; //This is a fixed value. DO NOT CHANGE
|
||||
#define FLASH_ADDR_DATA_STORAGE_START start_data_pool
|
||||
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_uintptr(uintptr_t, uintptr_t);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
|
||||
extern void low_flash_available();
|
||||
|
||||
uintptr_t allocate_free_addr(uint16_t size) {
|
||||
if (size > FLASH_SECTOR_SIZE)
|
||||
return 0x0; //ERROR
|
||||
size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size
|
||||
uintptr_t next_base = 0x0;
|
||||
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
|
||||
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
|
||||
uintptr_t potential_addr = base-real_size;
|
||||
next_base = flash_read_uintptr(base);
|
||||
//printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
|
||||
//printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
|
||||
if (next_base == 0x0) { //we are at the end
|
||||
//now we check if we fit in the current sector
|
||||
if (addr_alg <= potential_addr) //it fits in the current sector
|
||||
{
|
||||
flash_program_uintptr(potential_addr, 0x0);
|
||||
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
|
||||
flash_program_uintptr(base, potential_addr);
|
||||
return potential_addr;
|
||||
}
|
||||
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
|
||||
potential_addr = addr_alg-real_size;
|
||||
flash_program_uintptr(potential_addr, 0x0);
|
||||
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
|
||||
flash_program_uintptr(base, potential_addr);
|
||||
return potential_addr;
|
||||
}
|
||||
return 0x0;
|
||||
}
|
||||
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked)
|
||||
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
|
||||
flash_program_uintptr(potential_addr, next_base);
|
||||
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
|
||||
flash_program_uintptr(base, potential_addr);
|
||||
return potential_addr;
|
||||
}
|
||||
}
|
||||
return 0x0; //probably never reached
|
||||
}
|
||||
|
||||
int flash_clear_file(file_t *file) {
|
||||
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
|
||||
uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t));
|
||||
uintptr_t next_addr = flash_read_uintptr(base_addr);
|
||||
//printf("nc %x->%x %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
|
||||
flash_program_uintptr(prev_addr, next_addr);
|
||||
flash_program_halfword((uintptr_t)file->data, 0);
|
||||
if (next_addr > 0)
|
||||
flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
|
||||
//printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
||||
if (!file)
|
||||
return HSM_ERR_NULL_PARAM;
|
||||
if (len > FLASH_SECTOR_SIZE)
|
||||
return HSM_ERR_NO_MEMORY;
|
||||
if (file->data) { //already in flash
|
||||
uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data);
|
||||
if (len <= size_file_flash) { //it fits, no need to move it
|
||||
flash_program_halfword((uintptr_t)file->data, len);
|
||||
if (data)
|
||||
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
|
||||
return HSM_OK;
|
||||
}
|
||||
else { //we clear the old file
|
||||
flash_clear_file(file);
|
||||
}
|
||||
}
|
||||
uintptr_t new_addr = allocate_free_addr(len);
|
||||
//printf("na %x\r\n",new_addr);
|
||||
if (new_addr == 0x0)
|
||||
return HSM_ERR_NO_MEMORY;
|
||||
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
|
||||
flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
|
||||
flash_program_halfword((uintptr_t)file->data, len);
|
||||
if (data)
|
||||
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
|
||||
return HSM_OK;
|
||||
}
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/sem.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hsm2040.h"
|
||||
#include "sc_hsm.h"
|
||||
#include <string.h>
|
||||
|
||||
#define TOTAL_FLASH_PAGES 4
|
||||
|
||||
typedef struct page_flash {
|
||||
uint8_t page[FLASH_SECTOR_SIZE];
|
||||
uintptr_t address;
|
||||
bool ready;
|
||||
bool erase;
|
||||
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
|
||||
} page_flash_t;
|
||||
|
||||
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
|
||||
|
||||
static mutex_t mtx_flash;
|
||||
static semaphore_t sem_wait;
|
||||
|
||||
static uint8_t ready_pages = 0;
|
||||
|
||||
bool flash_available = false;
|
||||
static bool locked_out = false;
|
||||
|
||||
|
||||
//this function has to be called from the core 0
|
||||
void do_flash()
|
||||
{
|
||||
if (mutex_try_enter(&mtx_flash, NULL) == true) {
|
||||
if (locked_out == true && flash_available == true && ready_pages > 0) {
|
||||
//printf(" DO_FLASH AVAILABLE\r\n");
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||
if (flash_pages[r].ready == true) {
|
||||
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
||||
while (multicore_lockout_start_timeout_us(1000) == false);
|
||||
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts (ints);
|
||||
while (multicore_lockout_end_timeout_us(1000) == false);
|
||||
//printf("WRITEN %X !\r\n",flash_pages[r].address);
|
||||
|
||||
flash_pages[r].ready = false;
|
||||
ready_pages--;
|
||||
}
|
||||
else if (flash_pages[r].erase == true) {
|
||||
while (multicore_lockout_start_timeout_us(1000) == false);
|
||||
//printf("WRITTING\r\n");
|
||||
flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
|
||||
while (multicore_lockout_end_timeout_us(1000) == false);
|
||||
flash_pages[r].erase = false;
|
||||
ready_pages--;
|
||||
}
|
||||
}
|
||||
flash_available = false;
|
||||
if (ready_pages != 0) {
|
||||
DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES");
|
||||
}
|
||||
}
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
sem_release(&sem_wait);
|
||||
}
|
||||
|
||||
//this function has to be called from the core 0
|
||||
void low_flash_init() {
|
||||
mutex_init(&mtx_flash);
|
||||
sem_init(&sem_wait, 0, 1);
|
||||
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
|
||||
}
|
||||
|
||||
void low_flash_init_core1() {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
multicore_lockout_victim_init();
|
||||
locked_out = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
void wait_flash_finish() {
|
||||
sem_acquire_blocking(&sem_wait); //blocks until released
|
||||
//wake up
|
||||
sem_acquire_blocking(&sem_wait); //decrease permits
|
||||
}
|
||||
|
||||
void low_flash_available() {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
flash_available = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
page_flash_t *find_free_page(uintptr_t addr) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
page_flash_t *p = NULL;
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
|
||||
{
|
||||
if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
|
||||
{
|
||||
p = &flash_pages[r];
|
||||
if (!flash_pages[r].ready && !flash_pages[r].erase)
|
||||
{
|
||||
memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
|
||||
ready_pages++;
|
||||
p->address = addr_alg;
|
||||
p->ready = true;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
page_flash_t *p = NULL;
|
||||
|
||||
if (!data || len == 0)
|
||||
return HSM_ERR_NULL_PARAM;
|
||||
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
|
||||
return HSM_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr)))
|
||||
{
|
||||
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
|
||||
mutex_exit(&mtx_flash);
|
||||
return HSM_ERR_MEMORY_FATAL;
|
||||
}
|
||||
memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
|
||||
//printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr);
|
||||
mutex_exit(&mtx_flash);
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int flash_program_halfword (uintptr_t addr, uint16_t data) {
|
||||
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
int flash_program_word (uintptr_t addr, uint32_t data) {
|
||||
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
int flash_program_uintptr (uintptr_t addr, uintptr_t data) {
|
||||
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
uint8_t *flash_read(uintptr_t addr) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
//mutex_enter_blocking(&mtx_flash);
|
||||
if (ready_pages > 0) {
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
|
||||
{
|
||||
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
|
||||
uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
|
||||
//mutex_exit(&mtx_flash);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t *v = (uint8_t *)addr;
|
||||
//mutex_exit(&mtx_flash);
|
||||
return v;
|
||||
}
|
||||
|
||||
uintptr_t flash_read_uintptr(uintptr_t addr) {
|
||||
uint8_t *p = flash_read(addr);
|
||||
uintptr_t v = 0x0;
|
||||
for (int i = 0; i < sizeof(uintptr_t); i++) {
|
||||
v |= (uintptr_t)p[i]<<(8*i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
uint16_t flash_read_uint16(uintptr_t addr) {
|
||||
uint8_t *p = flash_read(addr);
|
||||
uint16_t v = 0x0;
|
||||
for (int i = 0; i < sizeof(uint16_t); i++) {
|
||||
v |= p[i]<<(8*i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
uint8_t flash_read_uint8(uintptr_t addr) {
|
||||
return *flash_read(addr);
|
||||
}
|
||||
|
||||
int flash_erase_page (uintptr_t addr, size_t page_size) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
page_flash_t *p = NULL;
|
||||
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
|
||||
return HSM_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr))) {
|
||||
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
|
||||
mutex_exit(&mtx_flash);
|
||||
return HSM_ERR_MEMORY_FATAL;
|
||||
}
|
||||
p->erase = true;
|
||||
p->ready = false;
|
||||
p->page_size = page_size;
|
||||
mutex_exit(&mtx_flash);
|
||||
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
bool flash_check_blank(const uint8_t *p_start, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
for (p = p_start; p < p_start + size; p++) {
|
||||
if (*p != 0xff)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pico/unique_id.h>
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "sc_hsm.h"
|
||||
#include "libopensc/card-sc-hsm.h"
|
||||
|
||||
void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
|
||||
uint8_t o1[32];
|
||||
hash_multi(pin, len, o1);
|
||||
for (int i = 0; i < sizeof(o1); i++)
|
||||
o1[i] ^= pin[i%len];
|
||||
hash_multi(o1, sizeof(o1), output);
|
||||
}
|
||||
|
||||
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
int iters = 256;
|
||||
pico_unique_board_id_t unique_id;
|
||||
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
|
||||
mbedtls_sha256_starts (&ctx, 0);
|
||||
mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id));
|
||||
|
||||
while (iters > len)
|
||||
{
|
||||
mbedtls_sha256_update (&ctx, input, len);
|
||||
iters -= len;
|
||||
}
|
||||
if (iters > 0) // remaining iterations
|
||||
mbedtls_sha256_update (&ctx, input, iters);
|
||||
mbedtls_sha256_finish (&ctx, output);
|
||||
mbedtls_sha256_free (&ctx);
|
||||
}
|
||||
|
||||
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
|
||||
mbedtls_sha256_starts (&ctx, 0);
|
||||
mbedtls_sha256_update (&ctx, input, len);
|
||||
|
||||
mbedtls_sha256_finish (&ctx, output);
|
||||
mbedtls_sha256_free (&ctx);
|
||||
}
|
||||
|
||||
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_init(&ctx);
|
||||
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
|
||||
mbedtls_md_setup(&ctx, md_info, 0);
|
||||
mbedtls_md_starts(&ctx);
|
||||
mbedtls_md_update(&ctx, input, len);
|
||||
mbedtls_md_finish(&ctx, output);
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
|
||||
int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memset(tmp_iv, 0, IV_SIZE);
|
||||
if (iv)
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
if (mode == HSM_AES_MODE_CBC)
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memset(tmp_iv, 0, IV_SIZE);
|
||||
if (iv)
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
if (mode == HSM_AES_MODE_CBC)
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
|
||||
return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
|
||||
}
|
||||
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
|
||||
return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
|
||||
}
|
||||
|
||||
struct ec_curve_mbed_id {
|
||||
struct sc_lv_data curve;
|
||||
mbedtls_ecp_group_id id;
|
||||
};
|
||||
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 },
|
||||
{ { (unsigned char *) "\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\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 },
|
||||
{ { (unsigned char *) "\x01\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\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\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 },
|
||||
{ { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 },
|
||||
{ { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 },
|
||||
{ { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 },
|
||||
{ { (unsigned char *) "\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\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 },
|
||||
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
|
||||
};
|
||||
|
||||
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
|
||||
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
|
||||
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
|
||||
return ec->id;
|
||||
}
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_UTILS_H_
|
||||
#define _CRYPTO_UTILS_H_
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/md.h"
|
||||
|
||||
#define HSM_KEY_RSA 0x1
|
||||
#define HSM_KEY_EC 0x10
|
||||
#define HSM_KEY_AES 0x100
|
||||
#define HSM_KEY_AES_128 0x300
|
||||
#define HSM_KEY_AES_192 0x500
|
||||
#define HSM_KEY_AES_256 0x900
|
||||
|
||||
#define HSM_AES_MODE_CBC 1
|
||||
#define HSM_AES_MODE_CFB 2
|
||||
|
||||
extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
|
||||
extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]);
|
||||
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
|
||||
extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output);
|
||||
extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
|
||||
extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
|
||||
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
|
||||
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
|
||||
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef CVCERTS_H_
|
||||
#define CVCERTS_H_
|
||||
|
||||
static const unsigned char termca[] = {
|
||||
0xfa, 0x00,
|
||||
0x7f,0x21,0x81,0xf6,0x7f,0x4e,0x81,0xbf,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||
0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x0f,0x89,
|
||||
0xb4,0x00,0x97,0x5e,0xdd,0x2d,0x42,0x5a,0xbf,0x85,0xf2,0xfb,0xd3,0x18,0x77,0x9b,
|
||||
0x3d,0x85,0x47,0x5e,0x65,0xd4,0xd8,0x58,0x69,0xd3,0x04,0x14,0xb7,0x1f,0x16,0x1e,
|
||||
0xb0,0x40,0xd9,0xf7,0xa7,0xe3,0x73,0xa3,0x15,0xc7,0xd9,0x9a,0x51,0xf5,0x5f,0x20,
|
||||
0x0e,0x45,0x53,0x54,0x45,0x52,0x4d,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x00,
|
||||
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||
0x02,0x03,0x01,0x02,0x03,0x01,0x65,0x2f,0x73,0x2d,0x06,0x09,0x04,0x00,0x7f,0x00,
|
||||
0x07,0x03,0x01,0x03,0x01,0x80,0x20,0x68,0x53,0x30,0xc7,0x9a,0x47,0xad,0xfd,0x37,
|
||||
0xaa,0xe8,0x53,0xf4,0xbd,0x77,0x3a,0x40,0x89,0x3a,0x79,0x7e,0x3c,0x27,0x18,0x3b,
|
||||
0x39,0x67,0xdf,0x8d,0x4f,0xe5,0x99,0x5f,0x37,0x30,0x10,0xff,0x17,0x96,0x0d,0x93,
|
||||
0x07,0xc0,0x69,0x8e,0x3a,0xa0,0x44,0x69,0x70,0x88,0xe6,0x9c,0xb4,0xd3,0x16,0x9a,
|
||||
0x22,0x4e,0x5c,0x77,0xa9,0xe7,0x83,0x75,0x9a,0xd2,0x7e,0x92,0xf2,0x04,0x93,0xb1,
|
||||
0xe9,0xc9,0xe5,0x10,0xc9,0x94,0xff,0x9d,0xe2,0x00
|
||||
};
|
||||
|
||||
static const unsigned char dica[] = {
|
||||
0xc9, 0x00,
|
||||
0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||
0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e,
|
||||
0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb,
|
||||
0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08,
|
||||
0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20,
|
||||
0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80,
|
||||
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||
0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5,
|
||||
0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d,
|
||||
0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99,
|
||||
0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include "mbedtls/cmac.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "files.h"
|
||||
|
||||
static uint8_t dkek[IV_SIZE+32];
|
||||
static uint8_t tmp_dkek[32];
|
||||
|
|
@ -35,15 +36,15 @@ extern uint8_t session_pin[32];
|
|||
|
||||
int load_dkek() {
|
||||
if (has_session_pin == false)
|
||||
return HSM_NO_LOGIN;
|
||||
return CCID_NO_LOGIN;
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!tf)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
|
||||
int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||
if (ret != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
return HSM_OK;
|
||||
return CCID_EXEC_ERROR;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
void release_dkek() {
|
||||
|
|
@ -59,11 +60,11 @@ int store_dkek_key() {
|
|||
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!tf)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
flash_write_data_to_file(tf, dkek, sizeof(dkek));
|
||||
low_flash_available();
|
||||
release_dkek();
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int save_dkek_key(const uint8_t *key) {
|
||||
|
|
@ -83,43 +84,43 @@ void import_dkek_share(const uint8_t *share) {
|
|||
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
|
||||
uint8_t hsh[32];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
hash256(dkek+IV_SIZE, 32, hsh);
|
||||
release_dkek();
|
||||
memcpy(kcv, hsh, 8);
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
|
||||
uint8_t buf[32+4];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
memcpy(buf, dkek+IV_SIZE, 32);
|
||||
release_dkek();
|
||||
memcpy(buf+32, "\x0\x0\x0\x1", 4);
|
||||
hash256(buf, sizeof(buf), kenc);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
|
||||
uint8_t buf[32+4];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
memcpy(buf, dkek+IV_SIZE, 32);
|
||||
release_dkek();
|
||||
memcpy(buf+32, "\x0\x0\x0\x2", 4);
|
||||
hash256(buf, sizeof(buf), kmac);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int dkek_encrypt(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
if ((r = load_dkek()) != CCID_OK)
|
||||
return r;
|
||||
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||
release_dkek();
|
||||
|
|
@ -128,7 +129,7 @@ int dkek_encrypt(uint8_t *data, size_t len) {
|
|||
|
||||
int dkek_decrypt(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
if ((r = load_dkek()) != CCID_OK)
|
||||
return r;
|
||||
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||
release_dkek();
|
||||
|
|
@ -137,7 +138,7 @@ int dkek_decrypt(uint8_t *data, size_t len) {
|
|||
|
||||
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) {
|
||||
if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
|
||||
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||
memset(kb, 0, sizeof(kb));
|
||||
|
|
@ -167,9 +168,9 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
|
|||
kb_len = 32;
|
||||
|
||||
if (kb_len != 16 && kb_len != 24 && kb_len != 32)
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
if (*out_len < 8+1+10+6+4+(2+32+14)+16)
|
||||
return HSM_WRONG_LENGTH;
|
||||
return CCID_WRONG_LENGTH;
|
||||
|
||||
put_uint16_t(kb_len, kb+8);
|
||||
memcpy(kb+10, key_ctx, kb_len);
|
||||
|
|
@ -182,7 +183,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
|
|||
}
|
||||
else if (key_type & HSM_KEY_RSA) {
|
||||
if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
|
||||
return HSM_WRONG_LENGTH;
|
||||
return CCID_WRONG_LENGTH;
|
||||
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||
kb_len = 0;
|
||||
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
|
||||
|
|
@ -199,7 +200,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
|
|||
}
|
||||
else if (key_type & HSM_KEY_EC) {
|
||||
if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
|
||||
return HSM_WRONG_LENGTH;
|
||||
return CCID_WRONG_LENGTH;
|
||||
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||
kb_len = 0;
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2;
|
||||
|
|
@ -265,7 +266,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
|
|||
kb[kb_len] = 0x80;
|
||||
}
|
||||
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
|
||||
memcpy(out+*out_len, kb, kb_len_pad);
|
||||
|
|
@ -276,7 +277,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
|
|||
*out_len += 16;
|
||||
if (r != 0)
|
||||
return r;
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int dkek_type_key(const uint8_t *in) {
|
||||
|
|
@ -303,27 +304,27 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
dkek_kenc(kenc);
|
||||
|
||||
if (memcmp(kcv, in, 8) != 0)
|
||||
return HSM_WRONG_DKEK;
|
||||
return CCID_WRONG_DKEK;
|
||||
|
||||
uint8_t signature[16];
|
||||
int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature);
|
||||
if (r != 0)
|
||||
return HSM_WRONG_SIGNATURE;
|
||||
return CCID_WRONG_SIGNATURE;
|
||||
if (memcmp(signature, in+in_len-16, 16) != 0)
|
||||
return HSM_WRONG_SIGNATURE;
|
||||
return CCID_WRONG_SIGNATURE;
|
||||
|
||||
int key_type = in[8];
|
||||
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
|
||||
if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
|
||||
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
|
||||
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
|
||||
size_t ofs = 9;
|
||||
|
||||
|
|
@ -344,12 +345,12 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
ofs += len+2;
|
||||
|
||||
if ((in_len-16-ofs) % 16 != 0)
|
||||
return HSM_WRONG_PADDING;
|
||||
return CCID_WRONG_PADDING;
|
||||
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||
memset(kb, 0, sizeof(kb));
|
||||
memcpy(kb, in+ofs, in_len-16-ofs);
|
||||
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
|
||||
int key_size = get_uint16_t(kb, 8);
|
||||
|
|
@ -364,14 +365,14 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
}
|
||||
else if (key_type == 6) {
|
||||
|
|
@ -385,7 +386,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
|
||||
//PQ
|
||||
|
|
@ -395,7 +396,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
//N
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
|
@ -405,33 +406,33 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
|
||||
if (key_type == 5) {
|
||||
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 6) {
|
||||
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
r = mbedtls_rsa_complete(rsa);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
r = mbedtls_rsa_check_privkey(rsa);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 12) {
|
||||
|
|
@ -449,7 +450,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
|
||||
if (ec_id == MBEDTLS_ECP_DP_NONE) {
|
||||
mbedtls_ecdsa_free(ecdsa);
|
||||
return HSM_WRONG_DATA;
|
||||
return CCID_WRONG_DATA;
|
||||
}
|
||||
ofs += len;
|
||||
|
||||
|
|
@ -464,11 +465,11 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
|
|||
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdsa_free(ecdsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 15) {
|
||||
memcpy(key_ctx, kb+ofs, key_size);
|
||||
}
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
60
src/hsm/files.c
Normal file
60
src/hsm/files.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "files.h"
|
||||
|
||||
extern const uint8_t sc_hsm_aid[];
|
||||
extern int parse_token_info(const file_t *f, int mode);
|
||||
extern int parse_cvca(const file_t *f, int mode);
|
||||
|
||||
file_t file_entries[] = {
|
||||
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
|
||||
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
|
||||
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
|
||||
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
||||
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
|
||||
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
|
||||
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
|
||||
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
|
||||
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
|
||||
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
|
||||
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
|
||||
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
||||
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
||||
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
||||
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
|
||||
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
||||
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
||||
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
||||
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
||||
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
||||
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
||||
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||
/* 25 */ { .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 *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
|
||||
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
|
||||
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
|
||||
file_t *file_pin1 = NULL;
|
||||
file_t *file_retries_pin1 = NULL;
|
||||
file_t *file_sopin = NULL;
|
||||
file_t *file_retries_sopin = NULL;
|
||||
|
|
@ -15,15 +15,24 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef USB_DESCRIPTORS_H_
|
||||
#define USB_DESCRIPTORS_H_
|
||||
|
||||
enum
|
||||
{
|
||||
VENDOR_REQUEST_WEBUSB = 1,
|
||||
VENDOR_REQUEST_MICROSOFT = 2
|
||||
};
|
||||
#ifndef _FILES_H_
|
||||
#define _FILES_H_
|
||||
|
||||
extern uint8_t const desc_ms_os_20[];
|
||||
#include "file.h"
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
#define EF_DKEK 0x108F
|
||||
#define EF_PRKDFS 0x6040
|
||||
#define EF_PUKDFS 0x6041
|
||||
#define EF_CDFS 0x6042
|
||||
#define EF_AODFS 0x6043
|
||||
#define EF_DODFS 0x6044
|
||||
#define EF_SKDFS 0x6045
|
||||
#define EF_DEVOPS 0x100E
|
||||
|
||||
extern file_t *file_pin1;
|
||||
extern file_t *file_retries_pin1;
|
||||
extern file_t *file_sopin;
|
||||
extern file_t *file_retries_sopin;
|
||||
|
||||
#endif
|
||||
1691
src/hsm/hsm2040.c
1691
src/hsm/hsm2040.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _HSM2040_H_
|
||||
#define _HSM2040_H_
|
||||
|
||||
#include "ccid.h"
|
||||
#include "tusb.h"
|
||||
#include "file.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "pico/util/queue.h"
|
||||
|
||||
#define USB_REQ_CCID 0xA1
|
||||
|
||||
typedef struct app {
|
||||
const uint8_t *aid;
|
||||
int (*process_apdu)();
|
||||
struct app* (*select_aid)();
|
||||
int (*unload)();
|
||||
} app_t;
|
||||
|
||||
extern int register_app(app_t * (*)());
|
||||
|
||||
extern const uint8_t historical_bytes[];
|
||||
|
||||
#define DEBUG_PAYLOAD(p,s) { \
|
||||
printf("Payload %s (%d bytes):\r\n", #p,s);\
|
||||
for (int i = 0; i < s; i += 16) {\
|
||||
printf("%07Xh : ",i+p);\
|
||||
for (int j = 0; j < 16; j++) {\
|
||||
if (j < s-i) printf("%02X ",(p)[i+j]);\
|
||||
else printf(" ");\
|
||||
if (j == 7) printf(" ");\
|
||||
} printf(": "); \
|
||||
for (int j = 0; j < MIN(16,s-i); j++) {\
|
||||
printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\
|
||||
if (j == 7) printf(" ");\
|
||||
}\
|
||||
printf("\r\n");\
|
||||
} printf("\r\n"); \
|
||||
}
|
||||
|
||||
struct apdu {
|
||||
uint8_t seq;
|
||||
|
||||
/* command APDU */
|
||||
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
|
||||
uint8_t *cmd_apdu_data;
|
||||
size_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
|
||||
size_t expected_res_size; /* Ne, calculated by Le field */
|
||||
|
||||
/* response APDU */
|
||||
uint16_t sw;
|
||||
uint16_t res_apdu_data_len;
|
||||
uint8_t *res_apdu_data;
|
||||
};
|
||||
|
||||
#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
|
||||
#define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
|
||||
#define CCID_MSG_HEADER_SIZE 10
|
||||
#define USB_LL_BUF_SIZE 64
|
||||
|
||||
/* CCID thread */
|
||||
#define EV_CARD_CHANGE 1
|
||||
#define EV_TX_FINISHED 2 /* CCID Tx finished */
|
||||
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
|
||||
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
|
||||
#define EV_RX_DATA_READY 16 /* USB Rx data available */
|
||||
#define EV_PRESS_BUTTON 32
|
||||
|
||||
/* SC HSM thread */
|
||||
#define EV_MODIFY_CMD_AVAILABLE 1
|
||||
#define EV_VERIFY_CMD_AVAILABLE 2
|
||||
#define EV_CMD_AVAILABLE 4
|
||||
#define EV_EXIT 8
|
||||
#define EV_BUTTON_PRESSED 16
|
||||
|
||||
//Variables set by core1
|
||||
extern queue_t *ccid_comm;
|
||||
extern queue_t *card_comm;
|
||||
|
||||
enum ccid_state {
|
||||
CCID_STATE_NOCARD, /* No card available */
|
||||
CCID_STATE_START, /* Initial */
|
||||
CCID_STATE_WAIT, /* Waiting APDU */
|
||||
|
||||
CCID_STATE_EXECUTE, /* Executing command */
|
||||
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
|
||||
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
|
||||
|
||||
CCID_STATE_EXITED, /* CCID Thread Terminated */
|
||||
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||
};
|
||||
|
||||
#define CLS(a) a.cmd_apdu_head[0]
|
||||
#define INS(a) a.cmd_apdu_head[1]
|
||||
#define P1(a) a.cmd_apdu_head[2]
|
||||
#define P2(a) a.cmd_apdu_head[3]
|
||||
|
||||
#define res_APDU apdu.res_apdu_data
|
||||
#define res_APDU_size apdu.res_apdu_data_len
|
||||
|
||||
extern struct apdu apdu;
|
||||
|
||||
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
|
||||
|
||||
|
||||
static inline const uint16_t make_uint16_t(uint8_t b1, uint8_t b2) {
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
static inline const uint16_t get_uint16_t(const uint8_t *b, uint16_t offset) {
|
||||
return make_uint16_t(b[offset], b[offset+1]);
|
||||
}
|
||||
static inline const void put_uint16_t(uint16_t n, uint8_t *b) {
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void stdout_init (void);
|
||||
#define DEBUG_MORE 1
|
||||
/*
|
||||
* Debug functions in debug.c
|
||||
*/
|
||||
void put_byte (uint8_t b);
|
||||
void put_byte_with_no_nl (uint8_t b);
|
||||
void put_short (uint16_t x);
|
||||
void put_word (uint32_t x);
|
||||
void put_int (uint32_t x);
|
||||
void put_string (const char *s);
|
||||
void put_binary (const char *s, int len);
|
||||
|
||||
#define DEBUG_INFO(msg) put_string (msg)
|
||||
#define DEBUG_WORD(w) put_word (w)
|
||||
#define DEBUG_SHORT(h) put_short (h)
|
||||
#define DEBUG_BYTE(b) put_byte (b)
|
||||
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
|
||||
#else
|
||||
#define DEBUG_INFO(msg)
|
||||
#define DEBUG_WORD(w)
|
||||
#define DEBUG_SHORT(h)
|
||||
#define DEBUG_BYTE(b)
|
||||
#define DEBUG_BINARY(s,len)
|
||||
#endif
|
||||
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern void low_flash_available();
|
||||
extern int flash_clear_file(file_t *file);
|
||||
|
||||
extern pico_unique_board_id_t unique_id;
|
||||
|
||||
enum {
|
||||
BLINK_NOT_MOUNTED = (250 << 16) | 250,
|
||||
BLINK_MOUNTED = (250 << 16) | 250,
|
||||
BLINK_SUSPENDED = (500 << 16) | 1000,
|
||||
BLINK_PROCESSING = (50 << 16) | 50,
|
||||
|
||||
BLINK_ALWAYS_ON = UINT32_MAX,
|
||||
BLINK_ALWAYS_OFF = 0
|
||||
};
|
||||
extern void led_set_blink(uint32_t mode);
|
||||
|
||||
#endif
|
||||
448
src/hsm/sc_hsm.c
448
src/hsm/sc_hsm.c
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "sc_hsm.h"
|
||||
#include "file.h"
|
||||
#include "files.h"
|
||||
#include "libopensc/card-sc-hsm.h"
|
||||
#include "random.h"
|
||||
#include "common.h"
|
||||
|
|
@ -33,12 +33,18 @@
|
|||
#include "crypto_utils.h"
|
||||
#include "dkek.h"
|
||||
#include "hardware/rtc.h"
|
||||
#include "eac.h"
|
||||
|
||||
const uint8_t sc_hsm_aid[] = {
|
||||
11,
|
||||
0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01
|
||||
};
|
||||
|
||||
char atr_sc_hsm[] = {
|
||||
24,
|
||||
0x3B,0xFE,0x18,0x00,0x00,0x81,0x31,0xFE,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xFA
|
||||
};
|
||||
|
||||
uint8_t session_pin[32], session_sopin[32];
|
||||
bool has_session_pin = false, has_session_sopin = false;
|
||||
static uint8_t dkeks = 0, current_dkeks = 0;
|
||||
|
|
@ -47,6 +53,7 @@ static int sc_hsm_process_apdu();
|
|||
|
||||
static void init_sc_hsm();
|
||||
static int sc_hsm_unload();
|
||||
static int cmd_select();
|
||||
|
||||
app_t *sc_hsm_select_aid(app_t *a) {
|
||||
if (!memcmp(apdu.cmd_apdu_data, sc_hsm_aid+1, MIN(apdu.cmd_apdu_data_len,sc_hsm_aid[0]))) {
|
||||
|
|
@ -60,19 +67,99 @@ app_t *sc_hsm_select_aid(app_t *a) {
|
|||
}
|
||||
|
||||
void __attribute__ ((constructor)) sc_hsm_ctor() {
|
||||
ccid_atr = atr_sc_hsm;
|
||||
register_app(sc_hsm_select_aid);
|
||||
}
|
||||
|
||||
void init_sc_hsm() {
|
||||
void scan_files() {
|
||||
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
|
||||
if (file_pin1) {
|
||||
if (!file_pin1->data) {
|
||||
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
|
||||
const uint8_t empty[33] = { 0 };
|
||||
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
|
||||
}
|
||||
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
|
||||
if (file_sopin) {
|
||||
if (!file_sopin->data) {
|
||||
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
|
||||
const uint8_t empty[33] = { 0 };
|
||||
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
|
||||
}
|
||||
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
|
||||
if (file_retries_pin1) {
|
||||
if (!file_retries_pin1->data) {
|
||||
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
|
||||
const uint8_t retries = 3;
|
||||
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
|
||||
}
|
||||
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
|
||||
if (file_retries_sopin) {
|
||||
if (!file_retries_sopin->data) {
|
||||
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
|
||||
const uint8_t retries = 15;
|
||||
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
|
||||
}
|
||||
file_t *tf = NULL;
|
||||
|
||||
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
|
||||
if (tf) {
|
||||
if (!tf->data) {
|
||||
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
|
||||
const uint8_t retries = 3;
|
||||
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
|
||||
}
|
||||
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
|
||||
if (tf) {
|
||||
if (!tf->data) {
|
||||
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
|
||||
const uint8_t retries = 15;
|
||||
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else {
|
||||
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
|
||||
}
|
||||
low_flash_available();
|
||||
}
|
||||
|
||||
void scan_all() {
|
||||
scan_flash();
|
||||
scan_files();
|
||||
}
|
||||
|
||||
void init_sc_hsm() {
|
||||
scan_all();
|
||||
has_session_pin = has_session_sopin = false;
|
||||
isUserAuthenticated = false;
|
||||
cmd_select();
|
||||
}
|
||||
|
||||
int sc_hsm_unload() {
|
||||
has_session_pin = has_session_sopin = false;
|
||||
isUserAuthenticated = false;
|
||||
return HSM_OK;
|
||||
sm_session_pin_len = 0;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
void select_file(file_t *pe) {
|
||||
|
|
@ -191,10 +278,11 @@ static int cmd_select() {
|
|||
process_fci(pe);
|
||||
if (pe == file_sc_hsm) {
|
||||
res_APDU[res_APDU_size++] = 0x85;
|
||||
res_APDU[res_APDU_size++] = 4;
|
||||
res_APDU[res_APDU_size++] = 5;
|
||||
uint16_t opts = get_device_options();
|
||||
res_APDU[res_APDU_size++] = opts & 0xff;
|
||||
res_APDU[res_APDU_size++] = opts >> 8;
|
||||
res_APDU[res_APDU_size++] = opts & 0xff;
|
||||
res_APDU[res_APDU_size++] = 0xFF;
|
||||
res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR;
|
||||
res_APDU[res_APDU_size++] = HSM_VERSION_MINOR;
|
||||
res_APDU[1] = res_APDU_size-2;
|
||||
|
|
@ -250,7 +338,7 @@ int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_
|
|||
}
|
||||
hash256(cvcbin, cvclen, hsh);
|
||||
free(cvcbin);
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int parse_token_info(const file_t *f, int mode) {
|
||||
|
|
@ -384,7 +472,7 @@ static int cmd_read_binary()
|
|||
uint16_t maxle = data_len-offset;
|
||||
if (apdu.expected_res_size > maxle)
|
||||
apdu.expected_res_size = maxle;
|
||||
res_APDU = file_read(ef->data+2+offset);
|
||||
memcpy(res_APDU, file_read(ef->data+2+offset), data_len-offset);
|
||||
res_APDU_size = data_len-offset;
|
||||
}
|
||||
}
|
||||
|
|
@ -394,14 +482,14 @@ static int cmd_read_binary()
|
|||
|
||||
int pin_reset_retries(const file_t *pin, bool force) {
|
||||
if (!pin)
|
||||
return HSM_ERR_NULL_PARAM;
|
||||
return CCID_ERR_NULL_PARAM;
|
||||
const file_t *max = search_by_fid(pin->fid+1, NULL, SPECIFY_EF);
|
||||
const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF);
|
||||
if (!max || !act)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
uint8_t retries = file_read_uint8(act->data+2);
|
||||
if (retries == 0 && force == false) //blocked
|
||||
return HSM_ERR_BLOCKED;
|
||||
return CCID_ERR_BLOCKED;
|
||||
retries = file_read_uint8(max->data+2);
|
||||
int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries));
|
||||
low_flash_available();
|
||||
|
|
@ -410,22 +498,22 @@ int pin_reset_retries(const file_t *pin, bool force) {
|
|||
|
||||
int pin_wrong_retry(const file_t *pin) {
|
||||
if (!pin)
|
||||
return HSM_ERR_NULL_PARAM;
|
||||
return CCID_ERR_NULL_PARAM;
|
||||
const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF);
|
||||
if (!act)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
uint8_t retries = file_read_uint8(act->data+2);
|
||||
if (retries > 0) {
|
||||
retries -= 1;
|
||||
int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries));
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
low_flash_available();
|
||||
if (retries == 0)
|
||||
return HSM_ERR_BLOCKED;
|
||||
return CCID_ERR_BLOCKED;
|
||||
return retries;
|
||||
}
|
||||
return HSM_ERR_BLOCKED;
|
||||
return CCID_ERR_BLOCKED;
|
||||
}
|
||||
|
||||
int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
|
||||
|
|
@ -436,20 +524,30 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
|
|||
}
|
||||
isUserAuthenticated = false;
|
||||
has_session_pin = has_session_sopin = false;
|
||||
uint8_t dhash[32];
|
||||
double_hash_pin(data, len, dhash);
|
||||
if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) {
|
||||
uint8_t retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < HSM_OK)
|
||||
return SW_PIN_BLOCKED();
|
||||
return set_res_sw(0x63, 0xc0 | retries);
|
||||
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) {
|
||||
uint8_t retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < CCID_OK)
|
||||
return SW_PIN_BLOCKED();
|
||||
return set_res_sw(0x63, 0xc0 | retries);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t dhash[32];
|
||||
double_hash_pin(data, len, dhash);
|
||||
if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) {
|
||||
uint8_t retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < CCID_OK)
|
||||
return SW_PIN_BLOCKED();
|
||||
return set_res_sw(0x63, 0xc0 | retries);
|
||||
}
|
||||
}
|
||||
int r = pin_reset_retries(pin, false);
|
||||
if (r == HSM_ERR_BLOCKED)
|
||||
if (r == CCID_ERR_BLOCKED)
|
||||
return SW_PIN_BLOCKED();
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
isUserAuthenticated = true;
|
||||
hash_multi(data, len, session_pin);
|
||||
|
|
@ -494,6 +592,9 @@ static int cmd_verify() {
|
|||
return SW_OK();
|
||||
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2));
|
||||
}
|
||||
else if (p2 == 0x85) {
|
||||
return SW_OK();
|
||||
}
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
|
||||
|
|
@ -530,7 +631,7 @@ static int cmd_reset_retry() {
|
|||
dhash[0] = newpin_len;
|
||||
double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1);
|
||||
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
||||
if (pin_reset_retries(file_pin1, true) != HSM_OK)
|
||||
if (pin_reset_retries(file_pin1, true) != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
|
|
@ -551,7 +652,7 @@ static int cmd_reset_retry() {
|
|||
if (apdu.cmd_apdu_data_len != 0)
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
if (pin_reset_retries(file_pin1, true) != HSM_OK)
|
||||
if (pin_reset_retries(file_pin1, true) != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
return SW_OK();
|
||||
}
|
||||
|
|
@ -562,7 +663,7 @@ static int cmd_challenge() {
|
|||
uint8_t *rb = (uint8_t *)random_bytes_get(apdu.expected_res_size);
|
||||
if (!rb)
|
||||
return SW_WRONG_LENGTH();
|
||||
res_APDU = rb;
|
||||
memcpy(res_APDU, rb, apdu.expected_res_size);
|
||||
res_APDU_size = apdu.expected_res_size;
|
||||
return SW_OK();
|
||||
}
|
||||
|
|
@ -578,23 +679,22 @@ int heapLeft() {
|
|||
static int cmd_initialize() {
|
||||
if (apdu.cmd_apdu_data_len > 0) {
|
||||
initialize_flash(true);
|
||||
scan_flash();
|
||||
scan_all();
|
||||
dkeks = current_dkeks = 0;
|
||||
const uint8_t *p = apdu.cmd_apdu_data;
|
||||
while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) {
|
||||
uint8_t tag = *p++;
|
||||
uint8_t tag_len = *p++;
|
||||
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
|
||||
size_t tag_len = 0;
|
||||
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x80) { //options
|
||||
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
||||
flash_write_data_to_file(tf, p, tag_len);
|
||||
flash_write_data_to_file(tf, tag_data, tag_len);
|
||||
}
|
||||
else if (tag == 0x81) { //user pin
|
||||
if (file_pin1 && file_pin1->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
double_hash_pin(tag_data, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_pin);
|
||||
hash_multi(tag_data, tag_len, session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -602,29 +702,28 @@ static int cmd_initialize() {
|
|||
if (file_sopin && file_sopin->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
double_hash_pin(tag_data, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_sopin, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_sopin);
|
||||
hash_multi(tag_data, tag_len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
}
|
||||
else if (tag == 0x91) { //retries user pin
|
||||
file_t *tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
|
||||
if (tf && tf->data) {
|
||||
flash_write_data_to_file(tf, p, tag_len);
|
||||
flash_write_data_to_file(tf, tag_data, tag_len);
|
||||
}
|
||||
if (file_retries_pin1 && file_retries_pin1->data) {
|
||||
flash_write_data_to_file(file_retries_pin1, p, tag_len);
|
||||
flash_write_data_to_file(file_retries_pin1, tag_data, tag_len);
|
||||
}
|
||||
}
|
||||
else if (tag == 0x92) {
|
||||
dkeks = *p;
|
||||
dkeks = *tag_data;
|
||||
}
|
||||
p += tag_len;
|
||||
}
|
||||
if (dkeks == 0) {
|
||||
int r = save_dkek_key(random_bytes_get(32));
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
else
|
||||
|
|
@ -660,7 +759,7 @@ static int cmd_import_dkek() {
|
|||
return SW_WRONG_LENGTH();
|
||||
import_dkek_share(apdu.cmd_apdu_data);
|
||||
if (++current_dkeks == dkeks) {
|
||||
if (save_dkek_key(NULL) != HSM_OK)
|
||||
if (save_dkek_key(NULL) != CCID_OK)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
|
||||
}
|
||||
|
|
@ -702,14 +801,14 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
|
|||
memcpy(kdata, key_ctx, key_size);
|
||||
}
|
||||
r = dkek_encrypt(kdata, key_size);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
return r;
|
||||
}
|
||||
file_t *fpk = file_new((KEY_PREFIX << 8) | key_id);
|
||||
if (!fpk)
|
||||
return SW_MEMORY_FAILURE();
|
||||
r = flash_write_data_to_file(fpk, kdata, key_size);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
//add_file_to_chain(fpk, &ef_kf);
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC) {
|
||||
|
|
@ -743,7 +842,7 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
|
|||
r = flash_write_data_to_file(fpk, asn1bin, asn1len);
|
||||
if (asn1bin)
|
||||
free(asn1bin);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
//add_file_to_chain(fpk, &ef_prkdf);
|
||||
/*
|
||||
|
|
@ -774,12 +873,12 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
|
|||
fpk = file_new((EE_CERTIFICATE_PREFIX << 8) | key_id);
|
||||
r = flash_write_data_to_file(fpk, asn1bin, asn1len);
|
||||
free(asn1bin);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return r;
|
||||
//add_file_to_chain(fpk, &ef_cdf);
|
||||
*/
|
||||
low_flash_available();
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
static int cmd_keypair_gen() {
|
||||
|
|
@ -846,7 +945,7 @@ static int cmd_keypair_gen() {
|
|||
|
||||
uint8_t hsh[32];
|
||||
ret = cvc_prepare_signatures(&p15card, &cvc, key_size/8, hsh);
|
||||
if (ret != HSM_OK) {
|
||||
if (ret != CCID_OK) {
|
||||
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
||||
mbedtls_rsa_free(&rsa);
|
||||
free(ctx);
|
||||
|
|
@ -862,7 +961,7 @@ static int cmd_keypair_gen() {
|
|||
return SW_EXEC_ERROR();
|
||||
}
|
||||
ret = store_keys(&rsa, SC_PKCS15_TYPE_PRKEY_RSA, key_id, ctx);
|
||||
if (ret != HSM_OK) {
|
||||
if (ret != CCID_OK) {
|
||||
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
||||
mbedtls_rsa_free(&rsa);
|
||||
free(ctx);
|
||||
|
|
@ -971,7 +1070,7 @@ static int cmd_keypair_gen() {
|
|||
|
||||
uint8_t hsh[32];
|
||||
ret = cvc_prepare_signatures(&p15card, &cvc, ecdsa.grp.pbits*2/8+9, hsh);
|
||||
if (ret != HSM_OK) {
|
||||
if (ret != CCID_OK) {
|
||||
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
free(ctx);
|
||||
|
|
@ -988,7 +1087,7 @@ static int cmd_keypair_gen() {
|
|||
}
|
||||
|
||||
ret = store_keys(&ecdsa, SC_PKCS15_TYPE_PRKEY_EC, key_id, ctx);
|
||||
if (ret != HSM_OK) {
|
||||
if (ret != CCID_OK) {
|
||||
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
free(ctx);
|
||||
|
|
@ -1000,6 +1099,8 @@ static int cmd_keypair_gen() {
|
|||
|
||||
}
|
||||
}
|
||||
else
|
||||
return SW_WRONG_DATA();
|
||||
uint8_t *cvcbin;
|
||||
size_t cvclen;
|
||||
ret = sc_pkcs15emu_sc_hsm_encode_cvc(&p15card, &cvc, &cvcbin, &cvclen);
|
||||
|
|
@ -1012,29 +1113,22 @@ static int cmd_keypair_gen() {
|
|||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
||||
res_APDU[0] = 0x67;
|
||||
int outer_len = strlen(cvc.outer_car)+2+2+1+4;
|
||||
int bytes_length = 0;
|
||||
if (cvclen+outer_len < 128)
|
||||
res_APDU[1] = cvclen+outer_len;
|
||||
else if (cvclen+outer_len < 256) {
|
||||
res_APDU[1] = 0x81;
|
||||
res_APDU[2] = cvclen+outer_len;
|
||||
bytes_length = 1;
|
||||
}
|
||||
else {
|
||||
res_APDU[1] = 0x82;
|
||||
res_APDU[2] = (cvclen+outer_len) >> 8;
|
||||
res_APDU[3] = (cvclen+outer_len) & 0xff;
|
||||
bytes_length = 2;
|
||||
}
|
||||
memcpy(res_APDU+bytes_length+2, cvcbin, cvclen);
|
||||
res_APDU[bytes_length+2+cvclen] = 0x42;
|
||||
res_APDU[bytes_length+2+cvclen+1] = strlen(cvc.outer_car);
|
||||
memcpy(res_APDU+bytes_length+2+cvclen+2, cvc.outer_car, strlen(cvc.outer_car));
|
||||
memcpy(res_APDU+bytes_length+2+cvclen+2+strlen(cvc.outer_car), "\x5F\x37\x04",3);
|
||||
res_APDU[res_APDU_size++] = 0x67;
|
||||
int outer_len = 2+strlen(cvc.outer_car)+3+4;
|
||||
int bytes_length = format_tlv_len(cvclen+outer_len, res_APDU+res_APDU_size);
|
||||
res_APDU_size += bytes_length;
|
||||
memcpy(res_APDU+res_APDU_size, cvcbin, cvclen);
|
||||
res_APDU_size += cvclen;
|
||||
res_APDU[res_APDU_size++] = 0x42;
|
||||
res_APDU[res_APDU_size++] = strlen(cvc.outer_car);
|
||||
memcpy(res_APDU+res_APDU_size, cvc.outer_car, strlen(cvc.outer_car));
|
||||
res_APDU_size += strlen(cvc.outer_car);
|
||||
memcpy(res_APDU+res_APDU_size, "\x5F\x37\x04",3);
|
||||
res_APDU_size += 3;
|
||||
memset(res_APDU+res_APDU_size, 0, 4);
|
||||
res_APDU_size += 4;
|
||||
free(cvcbin);
|
||||
res_APDU_size = cvclen+bytes_length+2+outer_len;
|
||||
//res_APDU_size = cvclen+bytes_length+1+outer_len;
|
||||
apdu.expected_res_size = res_APDU_size;
|
||||
|
||||
//sc_asn1_print_tags(res_APDU, res_APDU_size);
|
||||
|
|
@ -1049,7 +1143,7 @@ static int cmd_keypair_gen() {
|
|||
static int cmd_update_ef() {
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
uint16_t fid = (p1 << 8) | p2;
|
||||
uint8_t *p = apdu.cmd_apdu_data, *data;
|
||||
uint8_t *data;
|
||||
uint16_t offset = 0;
|
||||
uint16_t data_len = 0;
|
||||
file_t *ef = NULL;
|
||||
|
|
@ -1063,25 +1157,16 @@ static int cmd_update_ef() {
|
|||
if (ef && !authenticate_action(ef, ACL_OP_UPDATE_ERASE))
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
|
||||
while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) {
|
||||
uint8_t tag = *p++;
|
||||
uint8_t taglen = *p++;
|
||||
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
|
||||
size_t tag_len = 0;
|
||||
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x54) { //ofset tag
|
||||
for (int i = 0; i < taglen; i++)
|
||||
offset |= (*p++ << (8*(taglen-i-1)));
|
||||
for (int i = 1; i <= tag_len; i++)
|
||||
offset |= (*tag_data++ << (8*(tag_len-i)));
|
||||
}
|
||||
else if (tag == 0x53) { //data
|
||||
if (taglen == 0x82) {
|
||||
data_len = *p++ << 8;
|
||||
data_len |= *p++;
|
||||
}
|
||||
else if (taglen == 0x81) {
|
||||
data_len = *p++;
|
||||
}
|
||||
else
|
||||
data_len = taglen;
|
||||
data = p;
|
||||
p += data_len;
|
||||
data_len = tag_len;
|
||||
data = tag_data;
|
||||
}
|
||||
}
|
||||
if (data_len == 0 && offset == 0) { //new file
|
||||
|
|
@ -1099,7 +1184,7 @@ static int cmd_update_ef() {
|
|||
}
|
||||
if (offset == 0) {
|
||||
int r = flash_write_data_to_file(ef, data, data_len);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
else {
|
||||
|
|
@ -1110,7 +1195,7 @@ static int cmd_update_ef() {
|
|||
memcpy(data_merge+offset, data, data_len);
|
||||
int r = flash_write_data_to_file(ef, data_merge, offset+data_len);
|
||||
free(data_merge);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
low_flash_available();
|
||||
|
|
@ -1135,9 +1220,9 @@ static int cmd_delete_file() {
|
|||
}
|
||||
if (!authenticate_action(ef, ACL_OP_DELETE_SELF))
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
if (flash_clear_file(ef) != HSM_OK)
|
||||
if (flash_clear_file(ef) != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
if (delete_dynamic_file(ef) != HSM_OK)
|
||||
if (delete_dynamic_file(ef) != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
|
|
@ -1156,12 +1241,12 @@ static int cmd_change_pin() {
|
|||
uint16_t r = check_pin(file_pin1, apdu.cmd_apdu_data, pin_len);
|
||||
if (r != 0x9000)
|
||||
return r;
|
||||
if (load_dkek() != HSM_OK) //loads the DKEK with old pin
|
||||
if (load_dkek() != CCID_OK) //loads the DKEK with old pin
|
||||
return SW_EXEC_ERROR();
|
||||
//encrypt DKEK with new pin
|
||||
hash_multi(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, session_pin);
|
||||
has_session_pin = true;
|
||||
if (store_dkek_key() != HSM_OK)
|
||||
if (store_dkek_key() != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = apdu.cmd_apdu_data_len-pin_len;
|
||||
|
|
@ -1199,7 +1284,7 @@ static int cmd_key_gen() {
|
|||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(aes_key, aes_type, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
|
|
@ -1237,7 +1322,7 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) {
|
|||
mbedtls_rsa_free(ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
|
||||
|
|
@ -1246,15 +1331,15 @@ int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
|
|||
uint8_t kdata[67]; //Worst case, 521 bit + 1byte
|
||||
memcpy(kdata, file_read(fkey->data+2), key_size);
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
mbedtls_ecp_group_id gid = kdata[0];
|
||||
int r = mbedtls_ecp_read_key(gid, ctx, kdata+1, key_size-1);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdsa_free(ctx);
|
||||
return HSM_EXEC_ERROR;
|
||||
return CCID_EXEC_ERROR;
|
||||
}
|
||||
return HSM_OK;
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
static int cmd_signature() {
|
||||
|
|
@ -1283,7 +1368,7 @@ static int cmd_signature() {
|
|||
|
||||
int r;
|
||||
r = load_private_key_rsa(&ctx, fkey);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
const uint8_t *hash = apdu.cmd_apdu_data;
|
||||
size_t hash_len = apdu.cmd_apdu_data_len;
|
||||
|
|
@ -1379,7 +1464,7 @@ static int cmd_signature() {
|
|||
md = MBEDTLS_MD_SHA256;
|
||||
int r;
|
||||
r = load_private_key_ecdsa(&ctx, fkey);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
size_t olen = 0;
|
||||
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
|
||||
|
|
@ -1414,7 +1499,7 @@ static int cmd_key_wrap() {
|
|||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
r = load_private_key_rsa(&ctx, ef);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_rsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
|
@ -1425,7 +1510,7 @@ static int cmd_key_wrap() {
|
|||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
r = load_private_key_ecdsa(&ctx, ef);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
|
@ -1448,7 +1533,7 @@ static int cmd_key_wrap() {
|
|||
aes_type = HSM_KEY_AES_128;
|
||||
r = dkek_encode_key(kdata, aes_type, res_APDU, &wrap_len);
|
||||
}
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
res_APDU_size = wrap_len;
|
||||
return SW_OK();
|
||||
|
|
@ -1467,7 +1552,7 @@ static int cmd_key_unwrap() {
|
|||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_rsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
|
@ -1475,7 +1560,7 @@ static int cmd_key_unwrap() {
|
|||
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_RSA, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
mbedtls_rsa_free(&ctx);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
|
|
@ -1483,7 +1568,7 @@ static int cmd_key_unwrap() {
|
|||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
|
@ -1491,7 +1576,7 @@ static int cmd_key_unwrap() {
|
|||
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
|
|
@ -1499,7 +1584,7 @@ static int cmd_key_unwrap() {
|
|||
uint8_t aes_key[32];
|
||||
int key_size = 0, aes_type;
|
||||
r = dkek_decode_key(aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
if (key_size == 32)
|
||||
|
|
@ -1511,7 +1596,7 @@ static int cmd_key_unwrap() {
|
|||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(aes_key, aes_type, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
|
|
@ -1529,7 +1614,7 @@ static int cmd_decrypt_asym() {
|
|||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
int r = load_private_key_rsa(&ctx, ef);
|
||||
if (r != HSM_OK)
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
int key_size = file_read_uint16(ef->data);
|
||||
if (apdu.cmd_apdu_data_len < key_size) //needs padding
|
||||
|
|
@ -1698,7 +1783,7 @@ static int cmd_derive_asym() {
|
|||
|
||||
int r;
|
||||
r = load_private_key_ecdsa(&ctx, fkey);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
|
@ -1729,7 +1814,7 @@ static int cmd_derive_asym() {
|
|||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, dest_id, card_ctx);
|
||||
free(card_ctx);
|
||||
if (r != HSM_OK) {
|
||||
if (r != CCID_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
mbedtls_mpi_free(&a);
|
||||
mbedtls_mpi_free(&nd);
|
||||
|
|
@ -1796,6 +1881,117 @@ static int cmd_extras() {
|
|||
return SW_OK();
|
||||
}
|
||||
|
||||
static int cmd_mse() {
|
||||
int p1 = P1(apdu);
|
||||
int p2 = P2(apdu);
|
||||
if (p1 & 0x1) { //SET
|
||||
if (p2 == 0xA4) { //AT
|
||||
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
|
||||
size_t tag_len = 0;
|
||||
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x80) {
|
||||
if (tag_len == 10 && memcmp(tag_data, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0)
|
||||
sm_set_protocol(MSE_AES);
|
||||
else if (tag_len == 10 && memcmp(tag_data, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0)
|
||||
sm_set_protocol(MSE_3DES);
|
||||
else
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
else
|
||||
return SW_INCORRECT_P1P2();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_general_authenticate() {
|
||||
if (P1(apdu) == 0x0 && P2(apdu) == 0x0) {
|
||||
if (apdu.cmd_apdu_data[0] == 0x7C) {
|
||||
int r = 0;
|
||||
size_t pubkey_len = 0;
|
||||
const uint8_t *pubkey = NULL;
|
||||
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
|
||||
size_t tag_len = 0;
|
||||
while (walk_tlv(apdu.cmd_apdu_data+2, apdu.cmd_apdu_data_len-2, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x80) {
|
||||
pubkey = tag_data-1; //mbedtls ecdh starts reading one pos before
|
||||
pubkey_len = tag_len+1;
|
||||
}
|
||||
}
|
||||
mbedtls_ecdh_context ctx;
|
||||
int key_size = file_read_uint16(termca_pk);
|
||||
mbedtls_ecdh_init(&ctx);
|
||||
mbedtls_ecp_group_id gid = MBEDTLS_ECP_DP_SECP192R1;
|
||||
r = mbedtls_ecdh_setup(&ctx, gid);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
r = mbedtls_mpi_read_binary(&ctx.ctx.mbed_ecdh.d, termca_pk+2, key_size);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
r = mbedtls_ecdh_read_public(&ctx, pubkey, pubkey_len);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
size_t olen = 0;
|
||||
uint8_t derived[MBEDTLS_ECP_MAX_BYTES];
|
||||
r = mbedtls_ecdh_calc_secret(&ctx, &olen, derived, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
if (r != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
||||
sm_derive_all_keys(derived, olen);
|
||||
|
||||
uint8_t *t = (uint8_t *)calloc(1, pubkey_len+16);
|
||||
memcpy(t, "\x7F\x49\x3F\x06\x0A", 5);
|
||||
if (sm_get_protocol() == MSE_AES)
|
||||
memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", 10);
|
||||
else if (sm_get_protocol() == MSE_3DES)
|
||||
memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", 10);
|
||||
t[15] = 0x86;
|
||||
memcpy(t+16, pubkey, pubkey_len);
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x7C;
|
||||
res_APDU[res_APDU_size++] = 20;
|
||||
res_APDU[res_APDU_size++] = 0x81;
|
||||
res_APDU[res_APDU_size++] = 8;
|
||||
memcpy(res_APDU+res_APDU_size, sm_get_nonce(), 8);
|
||||
res_APDU_size += 8;
|
||||
res_APDU[res_APDU_size++] = 0x82;
|
||||
res_APDU[res_APDU_size++] = 8;
|
||||
|
||||
r = sm_sign(t, pubkey_len+16, res_APDU+res_APDU_size);
|
||||
|
||||
free(t);
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
res_APDU_size += 8;
|
||||
}
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_session_pin() {
|
||||
if (P1(apdu) == 0x01 && P2(apdu) == 0x81) {
|
||||
memcpy(sm_session_pin, random_bytes_get(8), 8);
|
||||
sm_session_pin_len = 8;
|
||||
|
||||
memcpy(res_APDU, sm_session_pin, sm_session_pin_len);
|
||||
res_APDU_size = sm_session_pin_len;
|
||||
apdu.expected_res_size = sm_session_pin_len;
|
||||
}
|
||||
else
|
||||
return SW_INCORRECT_P1P2();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
typedef struct cmd
|
||||
{
|
||||
|
|
@ -1804,21 +2000,24 @@ typedef struct cmd
|
|||
} cmd_t;
|
||||
|
||||
#define INS_VERIFY 0x20
|
||||
#define INS_MSE 0x22
|
||||
#define INS_CHANGE_PIN 0x24
|
||||
#define INS_RESET_RETRY 0x2C
|
||||
#define INS_KEYPAIR_GEN 0x46
|
||||
#define INS_KEY_GEN 0x48
|
||||
#define INS_INITIALIZE 0x50
|
||||
#define INS_IMPORT_DKEK 0x52
|
||||
#define INS_EXTRAS 0x54
|
||||
#define INS_LIST_KEYS 0x58
|
||||
#define INS_SESSION_PIN 0x5A
|
||||
#define INS_DECRYPT_ASYM 0x62
|
||||
#define INS_EXTRAS 0x64
|
||||
#define INS_SIGNATURE 0x68
|
||||
#define INS_WRAP 0x72
|
||||
#define INS_UNWRAP 0x74
|
||||
#define INS_DERIVE_ASYM 0x76
|
||||
#define INS_CIPHER_SYM 0x78
|
||||
#define INS_CHALLENGE 0x84
|
||||
#define INS_GENERAL_AUTHENTICATE 0x86
|
||||
#define INS_SELECT_FILE 0xA4
|
||||
#define INS_READ_BINARY 0xB0
|
||||
#define INS_READ_BINARY_ODD 0xB1
|
||||
|
|
@ -1847,13 +2046,20 @@ static const cmd_t cmds[] = {
|
|||
{ INS_CIPHER_SYM, cmd_cipher_sym },
|
||||
{ INS_DERIVE_ASYM, cmd_derive_asym },
|
||||
{ INS_EXTRAS, cmd_extras },
|
||||
{ INS_MSE, cmd_mse },
|
||||
{ INS_GENERAL_AUTHENTICATE, cmd_general_authenticate },
|
||||
{ INS_SESSION_PIN, cmd_session_pin },
|
||||
{ 0x00, 0x0}
|
||||
};
|
||||
|
||||
int sc_hsm_process_apdu() {
|
||||
int r = sm_unwrap();
|
||||
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
||||
if (cmd->ins == INS(apdu))
|
||||
return cmd->cmd_handler();
|
||||
if (cmd->ins == INS(apdu)) {
|
||||
int r = cmd->cmd_handler();
|
||||
sm_wrap();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return SW_INS_NOT_SUPPORTED();
|
||||
}
|
||||
|
|
@ -20,50 +20,10 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hsm2040.h"
|
||||
#include "ccid2040.h"
|
||||
|
||||
extern const uint8_t sc_hsm_aid[];
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
||||
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
|
||||
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
||||
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
|
||||
#define SW_WRONG_DATA() set_res_sw (0x67, 0x00)
|
||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
|
||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
|
||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
|
||||
#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83)
|
||||
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
|
||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
||||
#define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99)
|
||||
#define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81)
|
||||
#define SW_FILE_NOT_FOUND() set_res_sw (0x6A, 0x82)
|
||||
#define SW_RECORD_NOT_FOUND() set_res_sw (0x6A, 0x83)
|
||||
#define SW_FILE_FULL() set_res_sw (0x6A, 0x84)
|
||||
#define SW_INCORRECT_P1P2() set_res_sw (0x6A, 0x86)
|
||||
#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88)
|
||||
#define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00)
|
||||
#define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00)
|
||||
#define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00)
|
||||
#define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00)
|
||||
#define SW_UNKNOWN() set_res_sw (0x6F, 0x00)
|
||||
#define SW_OK() set_res_sw (0x90, 0x00)
|
||||
|
||||
#define HSM_OK 0
|
||||
#define HSM_ERR_NO_MEMORY -1000
|
||||
#define HSM_ERR_MEMORY_FATAL -1001
|
||||
#define HSM_ERR_NULL_PARAM -1002
|
||||
#define HSM_ERR_FILE_NOT_FOUND -1003
|
||||
#define HSM_ERR_BLOCKED -1004
|
||||
#define HSM_NO_LOGIN -1005
|
||||
#define HSM_EXEC_ERROR -1006
|
||||
#define HSM_WRONG_LENGTH -1007
|
||||
#define HSM_WRONG_DATA -1008
|
||||
#define HSM_WRONG_DKEK -1009
|
||||
#define HSM_WRONG_SIGNATURE -1010
|
||||
#define HSM_WRONG_PADDING -1011
|
||||
|
||||
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
|
||||
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
|
||||
|
|
@ -110,6 +70,4 @@ extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
|
|||
|
||||
extern uint8_t session_pin[32], session_sopin[32];
|
||||
|
||||
#define IV_SIZE 16
|
||||
|
||||
#endif
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define HSM_VERSION 0x010C
|
||||
#define HSM_VERSION 0x0200
|
||||
|
||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||
|
|
|
|||
182
src/rng/neug.c
182
src/rng/neug.c
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//Part of the code is taken from GnuK (GPLv3)
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "neug.h"
|
||||
#include "hardware/structs/rosc.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/adc.h"
|
||||
#include "bsp/board.h"
|
||||
#include "pico/unique_id.h"
|
||||
|
||||
void adc_start() {
|
||||
adc_init();
|
||||
adc_gpio_init(27);
|
||||
adc_select_input(1);
|
||||
}
|
||||
|
||||
void adc_stop() {
|
||||
}
|
||||
|
||||
static uint64_t random_word = 0xcbf29ce484222325;
|
||||
static uint8_t ep_round = 0;
|
||||
|
||||
static void ep_init() {
|
||||
random_word = 0xcbf29ce484222325;
|
||||
ep_round = 0;
|
||||
}
|
||||
|
||||
/* Here, we assume a little endian architecture. */
|
||||
static int ep_process () {
|
||||
if (ep_round == 0) {
|
||||
ep_init();
|
||||
}
|
||||
uint64_t word = 0x0;
|
||||
for (int n = 0; n < 64; n++) {
|
||||
uint8_t bit1, bit2;
|
||||
do
|
||||
{
|
||||
bit1 = rosc_hw->randombit&0xff;
|
||||
//sleep_ms(1);
|
||||
bit2 = rosc_hw->randombit&0xff;
|
||||
} while(bit1 == bit2);
|
||||
word = (word << 1) | bit1;
|
||||
}
|
||||
random_word ^= word^board_millis()^adc_read();
|
||||
random_word *= 0x00000100000001B3;
|
||||
if (++ep_round == 8) {
|
||||
ep_round = 0;
|
||||
return 2; //2 words
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint32_t *ep_output() {
|
||||
return (uint32_t *)&random_word;
|
||||
}
|
||||
|
||||
struct rng_rb {
|
||||
uint32_t *buf;
|
||||
uint8_t head, tail;
|
||||
uint8_t size;
|
||||
unsigned int full :1;
|
||||
unsigned int empty :1;
|
||||
};
|
||||
|
||||
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
rb->head = rb->tail = 0;
|
||||
rb->full = 0;
|
||||
rb->empty = 1;
|
||||
}
|
||||
|
||||
static void rb_add(struct rng_rb *rb, uint32_t v) {
|
||||
rb->buf[rb->tail++] = v;
|
||||
if (rb->tail == rb->size)
|
||||
rb->tail = 0;
|
||||
if (rb->tail == rb->head)
|
||||
rb->full = 1;
|
||||
rb->empty = 0;
|
||||
}
|
||||
|
||||
static uint32_t rb_del(struct rng_rb *rb) {
|
||||
uint32_t v = rb->buf[rb->head++];
|
||||
|
||||
if (rb->head == rb->size)
|
||||
rb->head = 0;
|
||||
if (rb->head == rb->tail)
|
||||
rb->empty = 1;
|
||||
rb->full = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static struct rng_rb the_ring_buffer;
|
||||
|
||||
void *neug_task() {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
int n;
|
||||
|
||||
if ((n = ep_process())) {
|
||||
int i;
|
||||
const uint32_t *vp;
|
||||
|
||||
vp = ep_output();
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
rb_add (rb, *vp++);
|
||||
if (rb->full)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void neug_init(uint32_t *buf, uint8_t size) {
|
||||
pico_unique_board_id_t unique_id;
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
const uint32_t *u = (const uint32_t *)unique_id.id;
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
int i;
|
||||
|
||||
rb_init(rb, buf, size);
|
||||
|
||||
adc_start();
|
||||
|
||||
ep_init();
|
||||
}
|
||||
|
||||
void neug_flush(void) {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
while (!rb->empty)
|
||||
rb_del (rb);
|
||||
}
|
||||
|
||||
uint32_t neug_get(int kick) {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
uint32_t v;
|
||||
|
||||
while (rb->empty)
|
||||
neug_task();
|
||||
v = rb_del(rb);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void neug_wait_full(void) { //should be called only on core1
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
while (!rb->full) {
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
void neug_fini(void) {
|
||||
neug_get(1);
|
||||
}
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _NEUG_H_
|
||||
#define _NEUG_H_
|
||||
|
||||
#define NEUG_PRE_LOOP 32
|
||||
|
||||
void neug_init(uint32_t *buf, uint8_t size);
|
||||
uint32_t neug_get();
|
||||
void neug_flush(void);
|
||||
void neug_wait_full(void);
|
||||
void neug_fini(void);
|
||||
|
||||
#endif
|
||||
109
src/rng/random.c
109
src/rng/random.c
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "neug.h"
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 32
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
||||
|
||||
void random_init(void) {
|
||||
int i;
|
||||
|
||||
neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
|
||||
|
||||
for (i = 0; i < NEUG_PRE_LOOP; i++)
|
||||
neug_get();
|
||||
}
|
||||
|
||||
void random_fini(void) {
|
||||
neug_fini ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointer to random 32-byte
|
||||
*/
|
||||
void random_bytes_free (const uint8_t *p);
|
||||
#define MAX_RANDOM_BUFFER 1024
|
||||
const uint8_t * random_bytes_get(size_t len) {
|
||||
if (len > MAX_RANDOM_BUFFER)
|
||||
return NULL;
|
||||
static uint32_t return_word[MAX_RANDOM_BUFFER/sizeof(uint32_t)];
|
||||
for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
||||
neug_wait_full();
|
||||
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
||||
random_bytes_free((const uint8_t *)random_word);
|
||||
}
|
||||
return (const uint8_t *)return_word;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free pointer to random 32-byte
|
||||
*/
|
||||
void random_bytes_free(const uint8_t *p) {
|
||||
(void)p;
|
||||
memset(random_word, 0, RANDOM_BYTES_LENGTH);
|
||||
neug_flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 4-byte salt
|
||||
*/
|
||||
void random_get_salt(uint8_t *p) {
|
||||
uint32_t rnd;
|
||||
|
||||
rnd = neug_get();
|
||||
memcpy(p, &rnd, sizeof (uint32_t));
|
||||
rnd = neug_get();
|
||||
memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
uint8_t *index_p = (uint8_t *)arg;
|
||||
uint8_t index = index_p ? *index_p : 0;
|
||||
size_t n;
|
||||
|
||||
while (out_len) {
|
||||
neug_wait_full();
|
||||
|
||||
n = RANDOM_BYTES_LENGTH - index;
|
||||
if (n > out_len)
|
||||
n = out_len;
|
||||
|
||||
memcpy(out, ((unsigned char *)random_word) + index, n);
|
||||
out += n;
|
||||
out_len -= n;
|
||||
index += n;
|
||||
|
||||
if (index >= RANDOM_BYTES_LENGTH) {
|
||||
index = 0;
|
||||
neug_flush();
|
||||
}
|
||||
}
|
||||
|
||||
if (index_p)
|
||||
*index_p = index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
void random_init (void);
|
||||
void random_fini (void);
|
||||
|
||||
/* 32-byte random bytes */
|
||||
const uint8_t *random_bytes_get (size_t);
|
||||
void random_bytes_free (const uint8_t *p);
|
||||
|
||||
/* 8-byte salt */
|
||||
void random_get_salt (uint8_t *p);
|
||||
|
||||
/* iterator returning a byta at a time */
|
||||
int random_gen (void *arg, unsigned char *output, size_t output_len);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CCID_H_
|
||||
#define _CCID_H_
|
||||
|
||||
#include "libopensc/ccid-types.h"
|
||||
|
||||
static const struct ccid_class_descriptor desc_ccid = {
|
||||
.bLength = sizeof(struct ccid_class_descriptor),
|
||||
.bDescriptorType = 0x21,
|
||||
.bcdCCID = (0x0110),
|
||||
.bMaxSlotIndex = 0,
|
||||
.bVoltageSupport = 0x01, // 5.0V
|
||||
.dwProtocols = (
|
||||
0x01| // T=0
|
||||
0x02), // T=1
|
||||
.dwDefaultClock = (0xDFC),
|
||||
.dwMaximumClock = (0xDFC),
|
||||
.bNumClockSupport = 0,
|
||||
.dwDataRate = (0x2580),
|
||||
.dwMaxDataRate = (0x2580),
|
||||
.bNumDataRatesSupported = 0,
|
||||
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
|
||||
.dwSynchProtocols = (0),
|
||||
.dwMechanical = (0),
|
||||
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
|
||||
.dwMaxCCIDMessageLength = 65544+10,
|
||||
.bClassGetResponse = 0xFF,
|
||||
.bclassEnvelope = 0xFF,
|
||||
.wLcdLayout = 0x0,
|
||||
.bPINSupport = 0x0,
|
||||
.bMaxCCIDBusySlots = 0x01,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by board.mk
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_DEVICE_RHPORT_NUM
|
||||
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
|
||||
#ifndef BOARD_DEVICE_RHPORT_SPEED
|
||||
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
|
||||
#else
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Device mode with rhport and speed defined by board.mk
|
||||
#if BOARD_DEVICE_RHPORT_NUM == 0
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#elif BOARD_DEVICE_RHPORT_NUM == 1
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#else
|
||||
#error "Incorrect RHPort configuration"
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_PICO
|
||||
#endif
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 1
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 16
|
||||
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
#include "pico/types.h"
|
||||
|
||||
static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); }
|
||||
static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "ccid.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
#ifndef USB_VID
|
||||
#define USB_VID 0xFEFF
|
||||
#endif
|
||||
#ifndef USB_PID
|
||||
#define USB_PID 0xFCFD
|
||||
#endif
|
||||
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
#define USB_CONFIG_ATT_ONE TU_BIT(7)
|
||||
|
||||
#define MAX_USB_POWER 1
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = (USB_BCD),
|
||||
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = (USB_VID),
|
||||
.idProduct = (USB_PID),
|
||||
.bcdDevice = HSM_VERSION,
|
||||
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
uint8_t const * tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
tusb_desc_interface_t const desc_interface =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_interface_t),
|
||||
.bDescriptorType = TUSB_DESC_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = TUSB_CLASS_SMART_CARD,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 5,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
tusb_desc_configuration_t const desc_config =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_configuration_t),
|
||||
.bDescriptorType = TUSB_DESC_CONFIGURATION,
|
||||
.wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)),
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 4,
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
|
||||
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1),
|
||||
};
|
||||
|
||||
tusb_desc_endpoint_t const desc_ep1 =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
.bEndpointAddress = TUSB_DIR_IN_MASK | 1,
|
||||
.bmAttributes.xfer = TUSB_XFER_BULK,
|
||||
.wMaxPacketSize.size = (64),
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
tusb_desc_endpoint_t const desc_ep2 =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
.bEndpointAddress = 2,
|
||||
.bmAttributes.xfer = TUSB_XFER_BULK,
|
||||
.wMaxPacketSize.size = (64),
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)];
|
||||
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
|
||||
static uint8_t initd = 0;
|
||||
if (initd == 0)
|
||||
{
|
||||
uint8_t *p = desc_config_extended;
|
||||
memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t);
|
||||
memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t);
|
||||
memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor);
|
||||
memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
|
||||
memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
|
||||
initd = 1;
|
||||
}
|
||||
return (const uint8_t *)desc_config_extended;
|
||||
}
|
||||
|
||||
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN)
|
||||
|
||||
#define MS_OS_20_DESC_LEN 0xB2
|
||||
|
||||
uint8_t const desc_bos[] =
|
||||
{
|
||||
// total length, number of device caps
|
||||
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2)
|
||||
};
|
||||
|
||||
uint8_t const * tud_descriptor_bos_cb(void)
|
||||
{
|
||||
return desc_bos;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"Pol Henarejos", // 1: Manufacturer
|
||||
"Pico HSM", // 2: Product
|
||||
"11223344", // 3: Serials, should use chip ID
|
||||
"Pico HSM Config", // 4: Vendor Interface
|
||||
"Pico HSM Interface"
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
}
|
||||
else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
|
||||
return NULL;
|
||||
|
||||
const char* str = string_desc_arr[index];
|
||||
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
if (index == 3) {
|
||||
pico_unique_board_id_t unique_id;
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
|
||||
str = unique_id_str;
|
||||
}
|
||||
|
||||
chr_count = strlen(str);
|
||||
if ( chr_count > 31 )
|
||||
chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for(uint8_t i=0; i<chr_count; i++) {
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue