From 2585a8269408c3599ea8d4f1c6f7e513f9795b1c Mon Sep 17 00:00:00 2001 From: "atul.jha" Date: Sat, 1 Aug 2020 11:30:58 +0200 Subject: [PATCH] PK to PEM experiment failed. Moving on. --- trial3/layer1.c | 58 +++++++++++++++++++++++++++++++++++------------- trial3/layer1.h | 10 ++++++++- trial3/layer2.c | 11 ++++++++- trial3/layer2.h | 12 +++++++++- trial3/out/main | Bin 18704 -> 19016 bytes 5 files changed, 73 insertions(+), 18 deletions(-) diff --git a/trial3/layer1.c b/trial3/layer1.c index a489eaf..5c979ed 100644 --- a/trial3/layer1.c +++ b/trial3/layer1.c @@ -207,6 +207,11 @@ int deriveECCKeyPair(mbedtls_mpi * SK, mbedtls_ecp_point * PK) size_t pubkeysize; char privkeybuf[100]; size_t privkeysize; + char privkeybuf2[100]; + size_t privkey2size; + + + mbedtls_ecp_group ecpGrp; mbedtls_ecp_group_init(&ecpGrp); @@ -253,36 +258,59 @@ int deriveECCKeyPair(mbedtls_mpi * SK, mbedtls_ecp_point * PK) printf("%hhx",pubkeybuf[i]); printf(" : PubKey\n"); - // ret = mbedtls_mpi_write_binary(&secret, privkeybuf, 100); - // if(ret < 0) - // { - // printf("%d\n", ret); - // perror("MPI write point failure\n"); - // return RIOTFAILURE; - // } - - // for(int i = 0; i < 100; i++) - // printf("%x",privkeybuf[i]); - // printf(" : PrivKey\n\n\n"); ret = mbedtls_mpi_write_string(&secret, 16, privkeybuf, sizeof(privkeybuf), &privkeysize); - if(ret < 0) + if(ret < 0) { printf("%d\n", ret); perror("MPI write point to string failure\n"); return RIOTFAILURE; } - //printf("%zu : privkeysize\n", privkeysize); - //for(int i = 0; i < privkeysize; i++) printf("%s : PrivKey\n",privkeybuf); - + //copy keys to parent function mbedtls_ecp_copy(PK, &Public); mbedtls_mpi_copy(SK, &secret); //what now? how to obtain the keys in PEM/DER/bin format? + //following experiment better documented in ECC_trial/PKtoPEM.c + /** + mbedtls_pk_context ec_pkCtx; + mbedtls_pk_init(&ec_pkCtx); + + mbedtls_pk_setup(&ec_pkCtx, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); + mbedtls_ecp_keypair *pk_ecp = mbedtls_pk_ec( ec_pkCtx ); + + mbedtls_ecp_copy(&pk_ecp->Q, &Public); + mbedtls_mpi_copy(&pk_ecp->d, &secret); + + mbedtls_mpi_write_string(&pk_ecp->d, 16, privkeybuf2, sizeof(privkeybuf2), &privkey2size); + printf("%s : wrapped PrivKey\n",privkeybuf2); + + + + ret = 0; + unsigned char privBuf[16000]; + unsigned char * d_b = privBuf; + memset(privBuf, 0, 16000); + unsigned char pubBuf[16000]; + unsigned char * Q_b = pubBuf; + memset(pubBuf, 0, 16000); + ret = mbedtls_pk_write_key_pem(&ec_pkCtx, privBuf, 16000); + printf("write priv pem ret value = %d\n", ret); + + printf("%s\n", privBuf); + + ret = mbedtls_pk_write_pubkey_pem(&ec_pkCtx, pubBuf, 16000); + printf("write pub pem ret value = %d\n", ret); + + printf("%s\n", pubBuf); + + **/ + + mbedtls_mpi_free(&secret); mbedtls_ecp_point_free(&Public); mbedtls_ecp_group_free(&ecpGrp); diff --git a/trial3/layer1.h b/trial3/layer1.h index 8cf389c..597c0b0 100644 --- a/trial3/layer1.h +++ b/trial3/layer1.h @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include @@ -21,8 +23,14 @@ //int createUDS(); //create rand file. to be replaced with real fuse pointer int readUDS(uint8_t* UDSdigest); + int readFWID(uint8_t * FW_M); + int _calcCDID(uint8_t * CDID); + int _calcCDIKEY(uint8_t * CDIKEY); + int deriveECCKeyPair(mbedtls_mpi * SK, mbedtls_ecp_point * PK); -int deriveRSAKeyPair(void); \ No newline at end of file + +int deriveRSAKeyPair(void); + diff --git a/trial3/layer2.c b/trial3/layer2.c index 5501e49..16f0907 100644 --- a/trial3/layer2.c +++ b/trial3/layer2.c @@ -57,6 +57,10 @@ void deriveDeviceIDKeyPair(uint8_t * CDIKEY, int isECC) //init //gen keypair + + //return pubkey and privkey both to L2? + + if(isECC) { @@ -66,7 +70,12 @@ void deriveDeviceIDKeyPair(uint8_t * CDIKEY, int isECC) mbedtls_ecp_point Public; mbedtls_ecp_point_init(&Public); - deriveECCKeyPair(&secret, &Public); + //return pubkey and privkey both to L2? + deriveECCKeyPair(&secret, &Public); + + //secret and Public contain raw key inormation of generated keys + //Public also needs group and context to handle ECP + //Converting raw info to PEM is not easible like this return; } diff --git a/trial3/layer2.h b/trial3/layer2.h index 18e2ceb..9453b8c 100644 --- a/trial3/layer2.h +++ b/trial3/layer2.h @@ -22,5 +22,15 @@ void ROMprotocol(void); + +void seedRNGSource(uint8_t * CDIKEY); + void deriveDeviceIDKeyPair(uint8_t * CDIKEY, int isECC); -void seedRNGSource(uint8_t * CDIKEY); \ No newline at end of file + +void deriveAliasKeyPair(uint8_t * ALIKEY, int isECC); + +void writePrivKeytoFile(char * filename, int isPEM); + +void writePubKeytoFile(char* filename, int isPEM); + +void genCertiicate(); \ No newline at end of file diff --git a/trial3/out/main b/trial3/out/main index 002440024c9ab86cd9ddffe2fc0de17a4f46170f..1f933d99acdd31428786616940cc6d0d64824b3f 100755 GIT binary patch literal 19016 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 bYIvEW%2k4Nfvu4Ks0tzRr4p1hU;n=VvgkF6 literal 18704 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