mem info , now supports loading PEM with private key

This commit is contained in:
iceman1001 2021-03-31 15:52:57 +02:00
parent 1d6b4b2722
commit e35ebf6b69
2 changed files with 140 additions and 80 deletions

View file

@ -17,6 +17,7 @@
#include "cmdflashmemspiffs.h" // spiffs commands
#include "rsa.h"
#include "sha1.h"
#include "pk.h" // PEM key load functions
#define MCK 48000000
#define FLASH_MINFAST 24000000 //33000000
@ -128,6 +129,7 @@ int rdv4_validate(rdv40_validation_t *mem) {
return PM3_EFAILED;
}
static int rdv4_sign_write(uint8_t *signature, uint8_t slen){
// save to mem
clearCommandBuffer();
@ -401,9 +403,9 @@ static int CmdFlashMemWipe(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem wipe",
"Wipe flash memory on device, which fills it with 0xFF\n"
_WHITE_("[ ") _RED_("!!! OBS") " ] use with caution",
"mem wipe -p 0 -> wipes first page"
// "mem wipe -i -> inital total wipe"
_WHITE_("[ ") _RED_("!!! OBS") _WHITE_(" ] use with caution"),
"mem wipe -p 0 -> wipes first page"
// "mem wipe -i -> inital total wipe"
);
void *argtable[] = {
@ -450,33 +452,84 @@ static int CmdFlashMemInfo(const char *Cmd) {
CLIParserInit(&ctx, "mem info",
"Collect signature and verify it from flash memory",
"mem info"
// "mem info -s -d 0102030405060708"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("s", "sign", "create a signature"),
arg_str0("d", NULL, "<hex>", "flash memory id, 8 hex bytes"),
arg_str0("p", "pem", "<fn>", "key in PEM format"),
arg_lit0("v", "verbose", "verbose output"),
// arg_lit0("w", "write", "write signature to flash memory"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool shall_sign = false, shall_write = false;
shall_sign = arg_get_lit(ctx, 1);
bool shall_sign = arg_get_lit(ctx, 1);
int dlen = 0;
uint8_t id[8] = {0};
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), id, sizeof(id), &dlen);
// shall_write = arg_get_lit(ctx, 3);
int pemlen = 0;
char pem_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)pem_fn, FILE_PATH_SIZE, &pemlen);
bool verbose = arg_get_lit(ctx, 4);
bool shall_write = false;
// shall_write = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (dlen > 0 && dlen < sizeof(id) ) {
if (res || (dlen > 0 && dlen < sizeof(id)) ) {
PrintAndLogEx(FAILED, "Error parsing flash memory id, expect 8, got %d", dlen);
return PM3_EINVARG;
}
// set up PK key context now.
mbedtls_pk_context pkctx;
mbedtls_pk_init( &pkctx );
bool got_private = false;
// PEM
if (pemlen) {
// PEM file
char *path = NULL;
if (searchFile(&path, RESOURCES_SUBDIR, pem_fn, ".pem", true) != PM3_SUCCESS) {
if (searchFile(&path, RESOURCES_SUBDIR, pem_fn, "", false) != PM3_SUCCESS) {
return PM3_EFILE;
}
}
PrintAndLogEx(INFO, "loading file `" _YELLOW_("%s") "`" NOLF, path);
// load private
res = mbedtls_pk_parse_keyfile(&pkctx, path, NULL);
//res = mbedtls_pk_parse_public_keyfile(&pkctx, path);
if (res == 0) {
PrintAndLogEx(NORMAL, " ( " _GREEN_("ok") " )");
} else {
PrintAndLogEx(NORMAL, " ( " _RED_("fail") " )");
mbedtls_pk_free(&pkctx);
free(path);
return PM3_EFILE;
}
mbedtls_rsa_context *rsa = (mbedtls_rsa_context*)pkctx.pk_ctx;
if (rsa == NULL) {
PrintAndLogEx(FAILED, "failed to allocate rsa context memory");
return PM3_EMALLOC;
}
free(path);
got_private = true;
} else {
// it not loaded, we need to setup the context manually
if (mbedtls_pk_setup( &pkctx, mbedtls_pk_info_from_type( (mbedtls_pk_type_t) MBEDTLS_PK_RSA ) ) != 0 ) {
PrintAndLogEx(FAILED, "failed, mbedtls_pk_setup returned ");
return PM3_ESOFT;
}
}
// validate devicesignature data
rdv40_validation_t mem;
res = rdv4_get_signature(&mem);
@ -494,66 +547,69 @@ static int CmdFlashMemInfo(const char *Cmd) {
PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------");
PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid)));
PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------");
for (int i = 0; i < (sizeof(mem.signature) / 32); i++) {
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32));
}
PrintAndLogEx(
(res == PM3_SUCCESS) ? SUCCESS : FAILED,
"Signature............ ( %s )",
(res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")
);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------");
for (int i = 0; i < (sizeof(mem.signature) / 32); i++) {
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32));
mbedtls_rsa_context *rsa = NULL;
if (got_private) {
rsa = mbedtls_pk_rsa( pkctx );
rsa->padding = MBEDTLS_RSA_PKCS_V15;
rsa->hash_id = 0;
rsa->len = RRG_RSA_KEY_LEN;
} else {
rsa = (mbedtls_rsa_context *)calloc(1, sizeof(mbedtls_rsa_context));
mbedtls_rsa_init(rsa, MBEDTLS_RSA_PKCS_V15, 0);
rsa->len = RRG_RSA_KEY_LEN;
// add public key
mbedtls_mpi_read_string(&rsa->N, 16, RRG_RSA_N);
mbedtls_mpi_read_string(&rsa->E, 16, RRG_RSA_E);
}
mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
rsa.len = RRG_RSA_KEY_LEN;
// add public key
mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N);
mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E);
// add private key
mbedtls_mpi_read_string(&rsa.D, 16, RSA_D);
mbedtls_mpi_read_string(&rsa.P, 16, RSA_P);
mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q);
mbedtls_mpi_read_string(&rsa.DP, 16, RSA_DP);
mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ);
mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------");
if (verbose) {
char str_exp[10];
char str_pk[261];
size_t exlen = 0, pklen = 0;
mbedtls_mpi_write_string(&rsa->E, 16, str_exp, sizeof(str_exp), &exlen);
mbedtls_mpi_write_string(&rsa->N, 16, str_pk, sizeof(str_pk), &pklen);
char str_exp[10];
char str_pk[261];
size_t exlen = 0, pklen = 0;
mbedtls_mpi_write_string(&rsa.E, 16, str_exp, sizeof(str_exp), &exlen);
mbedtls_mpi_write_string(&rsa.N, 16, str_pk, sizeof(str_pk), &pklen);
PrintAndLogEx(INFO, "Len.................. %"PRIu64, rsa->len);
PrintAndLogEx(INFO, "Exponent............. %s", str_exp);
PrintAndLogEx(INFO, "Public key modulus N");
PrintAndLogEx(INFO, " %.64s", str_pk);
PrintAndLogEx(INFO, " %.64s", str_pk + 64);
PrintAndLogEx(INFO, " %.64s", str_pk + 128);
PrintAndLogEx(INFO, " %.64s", str_pk + 192);
PrintAndLogEx(NORMAL, "");
}
PrintAndLogEx(INFO, "Len.................. %"PRIu64, rsa.len);
PrintAndLogEx(INFO, "Exponent............. %s", str_exp);
PrintAndLogEx(INFO, "Public key modulus N");
PrintAndLogEx(INFO, " %.64s", str_pk);
PrintAndLogEx(INFO, " %.64s", str_pk + 64);
PrintAndLogEx(INFO, " %.64s", str_pk + 128);
PrintAndLogEx(INFO, " %.64s", str_pk + 192);
PrintAndLogEx(NORMAL, "");
bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0);
bool is_keyok = (mbedtls_rsa_check_pubkey(rsa) == 0);
PrintAndLogEx(
(is_keyok) ? SUCCESS : FAILED,
"RSA public key validation.... ( %s )",
(is_keyok) ? _GREEN_("ok") : _RED_("fail")
);
is_keyok = (mbedtls_rsa_check_privkey(&rsa) == 0);
PrintAndLogEx(
(is_keyok) ? SUCCESS : FAILED,
"RSA private key validation... ( %s )",
"RRG/Iceman RSA public key check.... ( %s )",
(is_keyok) ? _GREEN_("ok") : _RED_("fail")
);
is_keyok = (mbedtls_rsa_check_privkey(rsa) == 0);
if (verbose) {
PrintAndLogEx(
(is_keyok) ? SUCCESS : FAILED,
"RRG/Iceman RSA private key check... ( %s )",
(is_keyok) ? _GREEN_("ok") : _YELLOW_("N/A")
);
}
// to be verified
uint8_t from_device[RRG_RSA_KEY_LEN];
@ -565,43 +621,47 @@ static int CmdFlashMemInfo(const char *Cmd) {
// Signing (private key)
if (shall_sign) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Enter signing") " --------------------");
if (dlen == 8) {
mbedtls_sha1(id, sizeof(id), sha_hash);
}
PrintAndLogEx(INFO, "Signing %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
if (is_keyok) {
int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign);
PrintAndLogEx(
(is_signed == 0) ? SUCCESS : FAILED,
"RSA signing.......... ( %s )",
(is_signed == 0) ? _GREEN_("ok") : _RED_("fail")
);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Enter signing") " --------------------");
if (shall_write) {
rdv4_sign_write(sign, RRG_RSA_KEY_LEN);
}
PrintAndLogEx(INFO, "Signed");
for (int i = 0; i < (sizeof(sign) / 32); i++) {
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32));
if (dlen == 8) {
mbedtls_sha1(id, sizeof(id), sha_hash);
}
PrintAndLogEx(INFO, "Signing....... %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
int is_signed = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign);
PrintAndLogEx(
(is_signed == 0) ? SUCCESS : FAILED,
"RSA signing... ( %s )",
(is_signed == 0) ? _GREEN_("ok") : _RED_("fail")
);
if (shall_write) {
rdv4_sign_write(sign, RRG_RSA_KEY_LEN);
}
PrintAndLogEx(INFO, "New signature");
for (int i = 0; i < (sizeof(sign) / 32); i++) {
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32));
}
} else {
PrintAndLogEx(FAILED, "no private key available to sign");
}
}
// Verify (public key)
bool is_verified = (mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0);
mbedtls_rsa_free(&rsa);
bool is_verified = (mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0);
mbedtls_pk_free(&pkctx);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(
(is_verified) ? SUCCESS : FAILED,
"RSA verification..... ( %s )",
(is_verified) ? _GREEN_("ok") : _RED_("fail")
"Genuine Proxmark3 RDV4 signature detected... %s",
(is_verified) ? ":heavy_check_mark:" : ":x:"
);
if (is_verified) {
PrintAndLogEx(SUCCESS, "Genuine Proxmark3 RDV4 signature detected");
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}

View file

@ -1805,7 +1805,7 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
int res = searchFinalFile(foundpath, pm3dir, filename, silent);
if (res != PM3_SUCCESS) {
if ((res == PM3_EFILE) && (!silent))
PrintAndLogEx(FAILED, "Error - can't find %s", filename);
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
free(filename);
return res;
}