Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/cst_signer
*.o
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ Build this tool using `make` command.

---

### Sign images using hardware backed cryptographic keys "--pkcs11"
This introduces a few changes to nxp-cst--signer for secure hardware signing.
This code is experimental, and has been tested with AHAB mimx9352, iMX.8MP, and i.MX8MN.
Have not tested with fastboot on i.MX8MP or i.MX8MN.

Steps required
- Works currently on linux
- build nxp-cst-signer
- build cst-3.4.1 (make sure the copmiled binary is in ${CST_PATH}/code/build director)
- make sure that you have PKCS11_MODULE_PATH to the pkcs#11 library when executing cst-signer
- make sure to set the PKCS#11 as key in the cfg.
- Set private key in the cfg : "pkcs11# url". The URL can be fetched using:
```
p11tool --provider $PKCS11_MODULE_PATH --list-all-privkeys --login
# --only-urls can be added to reduce the output
```
- Had to remove the "object" from the pkcs11 url to make it work, needs to be investigated.


Note:
- The benfit of using this is that it protects private key from exposure.
- Make sure that you use a have a recoverable backup of your private key. And consult the manual from pkcs11 key
- The solution protects the private key from exposure of normal usage.

PKCS#11 is experimental support is added for linux, append --pkcs11
In order for this to work, PKCS11_MODULE_PATH must be set before invoking

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will reword this description. CST does have HSM docker environment to experiment with this feature, so would refer to it as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite still experimental, still working on it, have also made some adjustment for it to work with i.MX8MN and i.MX8MP.


----

### Run

To run this tool, along with CST, you would also need to have the CSF config
Expand Down
11 changes: 11 additions & 0 deletions csf_ahab_pkcs11.cfg.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#Header
header_version=1.0
#Install SRK
srktable_file=SRK_1_2_3_4_table.bin
srk_source=pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=31832638;token=YubiKey%20PIV%20%2331832638;id=%02;type=private
srk_source_index=0
srk_source_set=OEM
srk_revocations=0x0
#Install Certificate
sgk_file=
sgk_permissions=
28 changes: 28 additions & 0 deletions csf_hab4.cfg.pkcs11.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#Header
header_version=4.3
header_eng=ANY
header_eng_config=0
#Install SRK
srktable_file=SRK_1_2_3_4_table.bin
srk_source_index=0
#Install NOCAK
nocak_file=
#Install CSFK
# csfk_file=CSF1_1_sha256_2048_65537_v3_usr_crt.pem
csfk_file=pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=31832638;token=YubiKey%20PIV%20%2331832638;id=%03;type=private
#Authenticate CSF
#Unlock
unlock_engine=
unlock_features=
unlock_uid=
#Install Key
img_verification_index=0
img_target_index=2
#img_file=IMG1_1_sha256_2048_65537_v3_usr_crt.pem
# PEGE experimental (not yet fully tested)
img_file=pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=31832638;token=YubiKey%20PIV%20%2331832638;id=%02;type=private
#Authenticate Data
auth_verification_index=2



5 changes: 4 additions & 1 deletion inc/cst_signer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Command line arguments
************************/
/* Valid short command line option letters. */
const char* const short_opt = "hfdi:o:c:";
const char* const short_opt = "hfdi:o:c:p:";

/* Valid long command line options. */
const struct option long_opt[] =
Expand All @@ -30,6 +30,7 @@ const struct option long_opt[] =
{"offset", required_argument, 0, 'o'},
{"debug", no_argument, 0, 'd'},
{"fdt-debug", no_argument, 0, 'f'},
{"pkcs11", no_argument, 0, 'p'},
{"help", no_argument, 0, 'h'},
{NULL, 0, NULL, 0}
};
Expand All @@ -42,6 +43,7 @@ const char* desc_opt[] =
"(Optional) Offset to the start of image",
"(Optional) Enable debug information",
"(Optional) FDT debug information",
"(Optional) Enable pkcs#11 signing. Currently only Linux support, and for cst-3.4.1 you must compile the source",
"This text",
NULL
};
Expand Down Expand Up @@ -186,6 +188,7 @@ static bool g_debug = 0;
static char *g_csf_cfgfilename = NULL;
extern uint32_t g_image_offset;
static char *g_cst_path = NULL;
static bool g_pkcs11 = 0; // static to enable pkcs#11 signing

unsigned char g_ivt_v1_mask[] = {0xFF,0xFF,0xFF,0xF0};
unsigned char g_ivt_v1[] = {0xD1,0x00,0x20,0x41};
Expand Down
13 changes: 12 additions & 1 deletion src/cfg_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,22 @@ void cfg_parser(FILE *fp_cfgfile, char *res_val, unsigned int res_size, char *ex
!(strncmp(line_buf, "//", 2)) || \
('\0' == line_buf[0]))
continue;
#if defined(__linux__)
if ( NULL != strchr(line_buf, '\r') ) {
printf("This program expects lines ending with only \\n\n"); // it passes \r to cst that causes failure.
exit(-1);
}
#endif
/* Get value of the corresponding key */
res = get_value(line_buf, exp_key);
if (NULL != res) {
/* Copy until the new line character */
strncpy(res_val, res, strlen(res) - 1);
if ( strlen(res) ) // // Added a test for empty value field on last row "sgk_permissions=\x0", to avoid segmentation failure.
strncpy(res_val, res, strlen(res) - 1);
else {
printf("Code expect lf on last line\n"); // else: segmentation error
exit(-1);
}
break;
}
}
Expand Down
97 changes: 85 additions & 12 deletions src/cst_signer.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,17 @@ int sign_csf(char *ifname, char *ofname)
return -E_FAILURE;
}
#if defined(__linux__)
if (0 > (snprintf(sys_cmd, SYS_CMD_LEN, "%s/linux64/bin/cst ", g_cst_path))) {
const char *sz_bin_path="/linux64/bin/cst";
const char *sz_extra_venv="";
char tmp_sz_buf[128];
if ( g_pkcs11 ) { // pkcs#11 - extend with ENV variable and modify to compiled cst
#define PKCS11_MODULE_PATH_VAR "PKCS11_MODULE_PATH"
sprintf( tmp_sz_buf, "%s=%s && ", PKCS11_MODULE_PATH_VAR, getenv(PKCS11_MODULE_PATH_VAR)); // The last space is important!
sz_extra_venv=tmp_sz_buf;
//sz_bin_path="/code/build/cst";
}

if (0 > (snprintf(sys_cmd, SYS_CMD_LEN, "%s%s%s ", sz_extra_venv, g_cst_path, sz_bin_path))) {
fprintf(stderr, "ERROR: System command build unsuccessful. Exiting.\n");
return -E_FAILURE;
}
Expand All @@ -139,8 +149,12 @@ int sign_csf(char *ifname, char *ofname)
#else
#error Unsupported OS
#endif

if (0 > (snprintf(sys_cmd + strlen(sys_cmd), (SYS_CMD_LEN - strlen(sys_cmd)), "--i %s --o %s", ifname, ofname))) {

const char *sz_cmd_format = "--i %s --o %s";
if ( g_pkcs11 ) {
sz_cmd_format = "-b pkcs11 --i %s --o %s"; // use pkcs11
}
if (0 > (snprintf(sys_cmd + strlen(sys_cmd), (SYS_CMD_LEN - strlen(sys_cmd)), sz_cmd_format, ifname, ofname))) {
fprintf(stderr, "ERROR: System command build unsuccessful. Exiting.\n");
return -E_FAILURE;
}
Expand Down Expand Up @@ -239,6 +253,10 @@ static int create_csf_file_v1(image_block_t *blocks, int idx, char *ofname)
char rvalue[RSIZE] = {0};
bool fast_auth = false;

// pkcs11 keys are prefixed with pkcs11: we should prepend path
const char *sz_pkcs11prefix="pkcs11:";


if (0 > (snprintf(csf_filename, sizeof(csf_filename), "csf_image%d.txt", idx))) {
fprintf(stderr, "ERROR: Cannot populate CSF file name.\n");
goto err;
Expand Down Expand Up @@ -308,16 +326,31 @@ static int create_csf_file_v1(image_block_t *blocks, int idx, char *ofname)
fast_auth = true;
/* Install NOCAK */
fprintf(fp_csf_file, "[Install NOCAK]\n");
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);

if ( 0 == strncmp(rvalue, sz_pkcs11prefix, strlen(sz_pkcs11prefix)) ) {
// PEGE: Don't add path when we are using pkcs#11
printf("NOT TESTED: processing pkcs#11 uri\n");
fprintf(fp_csf_file, "\tFile = \"%s\"\n", rvalue);
} else {
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);
}
} else {
/* Prepare normal authentication parameters */
/* Install CSFK */
fprintf(fp_csf_file, "[Install CSFK]\n");
cfg_parser(fp_cfg, rvalue, RSIZE, "csfk_file");
if ('\0' == rvalue[0])
fprintf(fp_csf_file, "\tFile = \"%s/crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem\"\n", g_cst_path);
else
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);
else {
if ( 0 == strncmp(rvalue, sz_pkcs11prefix, strlen(sz_pkcs11prefix)) ) {
// PEGE: Don't add path when we are using pkcs#11
printf("Processing pkcs#11 uri\n");
fprintf(fp_csf_file, "\tFile = \"%s\"\n", rvalue);

} else {
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);
}
}
}

fprintf(fp_csf_file, "[Authenticate CSF]\n");
Expand Down Expand Up @@ -420,8 +453,15 @@ static int create_csf_file_v1(image_block_t *blocks, int idx, char *ofname)
cfg_parser(fp_cfg, rvalue, RSIZE, "img_file");
if ('\0' == rvalue[0])
fprintf(fp_csf_file, "\tFile = \"%s/crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem\"\n", g_cst_path);
else
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);
else {
if ( 0 == strncmp(rvalue, sz_pkcs11prefix, strlen(sz_pkcs11prefix)) ) {
// PEGE: Don't add path when we are using pkcs#11
printf("Processing pkcs#11 uri\n");
fprintf(fp_csf_file, "\tFile = \"%s\"\n", rvalue);
} else {
fprintf(fp_csf_file, "\tFile = \"%s/crts/%s\"\n", g_cst_path, rvalue);
}
}
}

/* Authenticate Data */
Expand Down Expand Up @@ -529,8 +569,16 @@ static int create_csf_file_v3(char *csf_filename, char *ifname, csf_params_t *cs
cfg_parser(fp_cfg, rvalue, RSIZE, "srk_source");
if ('\0' == rvalue[0])
fprintf(fp_csf_file, "\tSource = \"%s/crts/SRK1_sha256_prime256v1_v3_ca_crt.pem\"\n", g_cst_path);
else
fprintf(fp_csf_file, "\tSource = \"%s/crts/%s\"\n", g_cst_path, rvalue);
else {
if ( 0 == g_pkcs11 ) {
DEBUG("Source = \"%s/crts/%s\"\n", g_cst_path, rvalue);
fprintf(fp_csf_file, "\tSource = \"%s/crts/%s\"\n", g_cst_path, rvalue);

} else { // use PKCS#11
DEBUG("PKCS11, Source = %s\n", rvalue);
fprintf(fp_csf_file, "\tSource = \"%s\"\n", rvalue);
}
}

cfg_parser(fp_cfg, rvalue, RSIZE, "srk_source_index");
if ('\0' == rvalue[0])
Expand Down Expand Up @@ -1094,7 +1142,18 @@ static int generate_csf_v1(int idx, char *csf_file)
}

#if defined(__linux__)
if (0 > (snprintf(sys_cmd, SYS_CMD_LEN, "%s/linux64/bin/cst ", g_cst_path))) {
const char *sz_bin_path="/linux64/bin/cst";
const char *sz_extra_venv="";
char tmp_sz_buf[128];
if ( g_pkcs11 ) { // do some trckling
#define PKCS11_MODULE_PATH_VAR "PKCS11_MODULE_PATH"
sprintf( tmp_sz_buf, "%s=%s && ", PKCS11_MODULE_PATH_VAR, getenv(PKCS11_MODULE_PATH_VAR)); // The last space is important!
sz_extra_venv=tmp_sz_buf;
//sz_bin_path="/code/build/cst";
}


if (0 > (snprintf(sys_cmd, SYS_CMD_LEN, "%s%s%s ", sz_extra_venv, g_cst_path, sz_bin_path))) {
fprintf(stderr, "ERROR: System command build unsuccessful. Exiting.\n");
goto err;
}
Expand All @@ -1106,8 +1165,12 @@ static int generate_csf_v1(int idx, char *csf_file)
#else
#error Unsupported OS
#endif
const char *sz_cmd_format = "--i %s --o %s";
if ( g_pkcs11 ) {
sz_cmd_format = "-b pkcs11 --i %s --o %s"; // use pkcs11
}

if (0 > (snprintf(sys_cmd + strlen(sys_cmd), (SYS_CMD_LEN - strlen(sys_cmd)), "--i %s --o %s", csf_ifilename, csf_ofilename))) {
if (0 > (snprintf(sys_cmd + strlen(sys_cmd), (SYS_CMD_LEN - strlen(sys_cmd)), sz_cmd_format, csf_ifilename, csf_ofilename))) {
fprintf(stderr, "ERROR: System command build unsuccessful. Exiting.\n");
goto err;
}
Expand Down Expand Up @@ -1619,6 +1682,16 @@ int main(int argc, char **argv)
print_usage();
exit(EXIT_SUCCESS);
break;
case 'p': // enable pkcs, this command does NOT take 'pkcs11' as option as cst
#if defined(__linux__)
g_pkcs11 = 1;
#else
print_usage();
DEBUG("pkcs#11 only implemented on Linux\n");
exit(EXIT_FAILURE);

#endif
break;
/* Invalid Option */
default:
break;
Expand Down