diff options
author | Ade Lee <alee@redhat.com> | 2012-08-15 14:06:08 -0400 |
---|---|---|
committer | Ade Lee <alee@redhat.com> | 2012-08-15 14:06:08 -0400 |
commit | 75e1c66acb48e67951fc0ce5680328773fe837ae (patch) | |
tree | 0da680311142b5c2c80012eae86817aafeb1dad5 /base/tps/tools | |
parent | 0198bf929702b756214b5f509ffe677ca58bf650 (diff) | |
download | pki-75e1c66acb48e67951fc0ce5680328773fe837ae.tar.gz pki-75e1c66acb48e67951fc0ce5680328773fe837ae.tar.xz pki-75e1c66acb48e67951fc0ce5680328773fe837ae.zip |
https://fedorahosted.org/pki/ticket/237
ECC support for tpsclient
two parameters are added in the config file (see enroll.tps.ec for example): slotnamefile - this points to a file that contains the slot name. The reason why the slot name goes into another file instead of the conf file is because the existing conf file uses spaces for deliminator and I don't want to change the usage (and QE's tests) by changing it to something else. tokpasswod is the tokebn password
This ECC feature requires the up-coming ECC supporting TPS to trigger. Testing of the ECC specific areas requires the availability of such ECC TPS. Without it, one can test with the old RSA method to see if it's broken.
Diffstat (limited to 'base/tps/tools')
-rw-r--r-- | base/tps/tools/raclient/RA_Conn.cpp | 14 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Token.cpp | 562 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Token.h | 64 | ||||
-rwxr-xr-x | base/tps/tools/raclient/enroll.tps.ec | 43 |
4 files changed, 637 insertions, 46 deletions
diff --git a/base/tps/tools/raclient/RA_Conn.cpp b/base/tps/tools/raclient/RA_Conn.cpp index 17a3ed34f..8e7f30e51 100644 --- a/base/tps/tools/raclient/RA_Conn.cpp +++ b/base/tps/tools/raclient/RA_Conn.cpp @@ -30,6 +30,7 @@ #include "apdu/List_Objects_APDU.h" #include "apdu/Create_Object_APDU.h" #include "apdu/Generate_Key_APDU.h" +#include "apdu/Generate_Key_ECC_APDU.h" #include "apdu/External_Authenticate_APDU.h" #include "apdu/Initialize_Update_APDU.h" #include "apdu/Lifecycle_APDU.h" @@ -583,7 +584,7 @@ RA_Conn::CreateAPDU (RA_Token * tok, Buffer & in_apdu_data, Buffer & mac) } } - else if (((BYTE *) apdu_data)[1] == 0x0C) + else if ((((BYTE *) apdu_data)[1] == 0x0C) || (((BYTE *) apdu_data)[1] == 0x0D)) // for both RSA (0x0C) and ECC (0x0D) { /* Generate_Key_APDU */ BYTE p[2]; @@ -602,9 +603,16 @@ RA_Conn::CreateAPDU (RA_Token * tok, Buffer & in_apdu_data, Buffer & mac) ((BYTE *) apdu_data)[11 + wc_len + 1], (unsigned int) ((BYTE *) apdu_data)[11 + wc_len]); - apdu = - new Generate_Key_APDU (p[0], p[1], alg, keysize, option, type, + if (((BYTE *) apdu_data)[1] == 0x0D) { + apdu = + new Generate_Key_ECC_APDU (p[0], p[1], alg, keysize, option, type, *wrapped_challenge, *key_check); + } else { + apdu = + new Generate_Key_APDU (p[0], p[1], alg, keysize, option, type, + *wrapped_challenge, *key_check); + } + if (wrapped_challenge != NULL) { delete wrapped_challenge; diff --git a/base/tps/tools/raclient/RA_Token.cpp b/base/tps/tools/raclient/RA_Token.cpp index 069d6c23c..85de6f6d0 100644 --- a/base/tps/tools/raclient/RA_Token.cpp +++ b/base/tps/tools/raclient/RA_Token.cpp @@ -25,6 +25,7 @@ #include "apdu/APDU_Response.h" #include "apdu/Initialize_Update_APDU.h" #include "apdu/Generate_Key_APDU.h" +#include "apdu/Generate_Key_ECC_APDU.h" #include "apdu/Put_Key_APDU.h" #include "apdu/Select_APDU.h" #include "apdu/Get_Data_APDU.h" @@ -39,9 +40,103 @@ #include "keyhi.h" #include "nss.h" #include "cert.h" +#include "secoidt.h" +#define VERBOSE //#define VERIFY_PROOF +#define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1 +/* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */ + +/* curveNameTagPair is borrowed from certutil */ +typedef struct curveNameTagPairStr { + char *curveName; + SECOidTag curveOidTag; +} CurveNameTagPair; + +static CurveNameTagPair nameTagPair[] = +{ + { "sect163k1", SEC_OID_SECG_EC_SECT163K1}, + { "nistk163", SEC_OID_SECG_EC_SECT163K1}, + { "sect163r1", SEC_OID_SECG_EC_SECT163R1}, + { "sect163r2", SEC_OID_SECG_EC_SECT163R2}, + { "nistb163", SEC_OID_SECG_EC_SECT163R2}, + { "sect193r1", SEC_OID_SECG_EC_SECT193R1}, + { "sect193r2", SEC_OID_SECG_EC_SECT193R2}, + { "sect233k1", SEC_OID_SECG_EC_SECT233K1}, + { "nistk233", SEC_OID_SECG_EC_SECT233K1}, + { "sect233r1", SEC_OID_SECG_EC_SECT233R1}, + { "nistb233", SEC_OID_SECG_EC_SECT233R1}, + { "sect239k1", SEC_OID_SECG_EC_SECT239K1}, + { "sect283k1", SEC_OID_SECG_EC_SECT283K1}, + { "nistk283", SEC_OID_SECG_EC_SECT283K1}, + { "sect283r1", SEC_OID_SECG_EC_SECT283R1}, + { "nistb283", SEC_OID_SECG_EC_SECT283R1}, + { "sect409k1", SEC_OID_SECG_EC_SECT409K1}, + { "nistk409", SEC_OID_SECG_EC_SECT409K1}, + { "sect409r1", SEC_OID_SECG_EC_SECT409R1}, + { "nistb409", SEC_OID_SECG_EC_SECT409R1}, + { "sect571k1", SEC_OID_SECG_EC_SECT571K1}, + { "nistk571", SEC_OID_SECG_EC_SECT571K1}, + { "sect571r1", SEC_OID_SECG_EC_SECT571R1}, + { "nistb571", SEC_OID_SECG_EC_SECT571R1}, + { "secp160k1", SEC_OID_SECG_EC_SECP160K1}, + { "secp160r1", SEC_OID_SECG_EC_SECP160R1}, + { "secp160r2", SEC_OID_SECG_EC_SECP160R2}, + { "secp192k1", SEC_OID_SECG_EC_SECP192K1}, + { "secp192r1", SEC_OID_SECG_EC_SECP192R1}, + { "nistp192", SEC_OID_SECG_EC_SECP192R1}, + { "secp224k1", SEC_OID_SECG_EC_SECP224K1}, + { "secp224r1", SEC_OID_SECG_EC_SECP224R1}, + { "nistp224", SEC_OID_SECG_EC_SECP224R1}, + { "secp256k1", SEC_OID_SECG_EC_SECP256K1}, + { "secp256r1", SEC_OID_SECG_EC_SECP256R1}, + { "nistp256", SEC_OID_SECG_EC_SECP256R1}, + { "secp384r1", SEC_OID_SECG_EC_SECP384R1}, + { "nistp384", SEC_OID_SECG_EC_SECP384R1}, + { "secp521r1", SEC_OID_SECG_EC_SECP521R1}, + { "nistp521", SEC_OID_SECG_EC_SECP521R1}, + + { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 }, + { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 }, + { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 }, + { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 }, + { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 }, + { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 }, + + { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 }, + { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 }, + { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 }, + { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 }, + { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 }, + { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 }, + { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 }, + { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 }, + { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 }, + { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 }, + { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 }, + { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 }, + { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 }, + { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 }, + { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 }, + { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 }, + { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 }, + { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 }, + { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 }, + { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 }, + + { "secp112r1", SEC_OID_SECG_EC_SECP112R1}, + { "secp112r2", SEC_OID_SECG_EC_SECP112R2}, + { "secp128r1", SEC_OID_SECG_EC_SECP128R1}, + { "secp128r2", SEC_OID_SECG_EC_SECP128R2}, + + { "sect113r1", SEC_OID_SECG_EC_SECT113R1}, + { "sect113r2", SEC_OID_SECG_EC_SECT113R2}, + { "sect131r1", SEC_OID_SECG_EC_SECT131R1}, + { "sect131r2", SEC_OID_SECG_EC_SECT131R2}, +}; + + static BYTE ToVal (char c) { @@ -134,6 +229,7 @@ RA_Token::RA_Token () m_pin = PL_strdup ("password"); m_object_len = 0; m_object = NULL; + m_tokenpassword = NULL; } @@ -833,36 +929,71 @@ GetMusclePublicKeyData (SECKEYPublicKey * pubKey, int keylen) } static Buffer -Sign (SECKEYPrivateKey * privKey, Buffer & blob) +GetMusclePublicKeyDataEC (SECKEYPublicKey * pubKey, int keylen) +{ + Buffer pk = + Buffer ((BYTE *) pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len); + + Buffer blob = Buffer (1, (BYTE) 0) + + Buffer (1, (BYTE) 0x0a) + /* key type EC */ + Buffer (1, (BYTE) (keylen / 256)) + /* key size */ + Buffer (1, (BYTE) (keylen % 256)) + + Buffer (1, (BYTE) (pk.size() >> 8) & 0xff) + /*pubkey blob len*/ + Buffer (1, (BYTE) pk.size() & 0xff) + pk; +Output("pk ="); + printBuf(&pk); + return pk; +} + +static Buffer +Sign (SECOidTag sigAlg, SECKEYPrivateKey * privKey, Buffer & blob) { - SECStatus status; + SECStatus status = SECFailure; SECItem sigitem; - int signature_len; + int signature_len = 0;; signature_len = PK11_SignatureLen (privKey); sigitem.len = signature_len; sigitem.data = (unsigned char *) PORT_Alloc (signature_len); status = SEC_SignData (&sigitem, (BYTE *) blob, blob.size (), privKey, - SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE); - if (status != SECSuccess) - { - printf ("Signing error\n"); - if (sigitem.data != NULL) - { - PORT_Free (sigitem.data); - sigitem.data = NULL; - } - return Buffer (16, (BYTE) 0); // sucks - } + sigAlg); + + if (status != SECSuccess) { + char buffer[1024]; + PR_GetErrorText (buffer); + + printf ("Signing error:%d %s\n",PR_GetError(), buffer); + if (sigitem.data != NULL) { + PORT_Free (sigitem.data); + sigitem.data = NULL; + } + + /*fake proof for ECC until it works*/ + char fake_proof [] = { + 0x30 ,0x44 ,0x02 ,0x20 ,0x00, + 0xd6 ,0xc2 ,0x08 ,0x34 ,0x79 ,0x28 ,0x2e ,0x5f ,0x70 ,0xe5, + 0x38 ,0x1d ,0x84 ,0xa9 ,0x40 ,0x05 ,0x65 ,0x67 ,0x0f ,0x65, + 0x46 ,0x5d ,0xf7 ,0x68 ,0x37 ,0x86 ,0x0b ,0x66 ,0xf7 ,0x71, + 0x0e ,0x02 ,0x20 ,0x3f ,0x48 ,0xdf ,0x29 ,0xa1 ,0x0e ,0xfb, + 0xdf ,0x38 ,0x26 ,0x9d ,0x54 ,0x01 ,0xbc ,0xb6 ,0x9d ,0xc0, + 0xbf ,0x27 ,0x29 ,0x95 ,0x97 ,0x3c ,0x2f ,0xef ,0xb1 ,0xd2, + 0xdc ,0x9f ,0xcb ,0x03 ,0x8d + }; + +/* return Buffer (16, (BYTE) 0); // sucks*/ + + Output("returning fake proof"); + return Buffer ((BYTE *)fake_proof, (unsigned int)sizeof(fake_proof)); + } Buffer proof = Buffer (sigitem.data, signature_len); - if (sigitem.data != NULL) - { + if (sigitem.data != NULL) { PORT_Free (sigitem.data); sigitem.data = NULL; - } + } + Output("returning real proof"); return proof; } @@ -884,6 +1015,31 @@ GetKeyBlob (int keysize, SECKEYPublicKey * pubKey) } static Buffer +GetKeyBlobEC (int keysize, SECKEYPublicKey * pubKey) +{ + Buffer pubKeyBlob = + Buffer ((BYTE *) pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len); +#ifdef VERBOSE +Output("in GetKeyBlobEC, pubkey blob len =%d", pubKeyBlob.size()); +#endif + + Buffer blob = Buffer (1, (BYTE) 0) + + Buffer (1, (BYTE) 0x0a) + /* key type EC */ + Buffer (1, (BYTE) (keysize / 256)) + /* key size */ + Buffer (1, (BYTE) (keysize % 256)) + + Buffer (1, (BYTE) (pubKeyBlob.size() >> 8) & 0xff) + /*pubkey blob len*/ + Buffer (1, (BYTE) pubKeyBlob.size() & 0xff) + + pubKeyBlob; + +#ifdef VERBOSE +Output("GetKeyBlobEC: blob ="); +printBuf(&blob); +#endif + return blob; + +} + +static Buffer GetSignBlob (Buffer & muscle_public_key, Buffer & challenge) { int i, j; @@ -898,9 +1054,14 @@ GetSignBlob (Buffer & muscle_public_key, Buffer & challenge) { ((BYTE *) data)[i] = ((BYTE *) challenge)[j]; } +Output("datablob ="); + printBuf(&data); return data; } +/* + * for RSA keys + */ APDU_Response * RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, NameValueSet * vars, NameValueSet * params) @@ -957,8 +1118,10 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, /* generate key pair */ char *keygen_param = params->GetValue ("keygen"); + if (keygen_param == NULL || (strcmp (keygen_param, "true") == 0)) { + Output("keygen is true"); privKey = PK11_GenerateKeyPair (slot, mechanism, x_params, &pubKey, PR_FALSE /*isPerm */ , @@ -966,12 +1129,14 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, NULL /*wincx */ ); if (privKey == NULL) { + Output("privKey NULL"); // printf("privKey == NULL\n"); buffer_size = 1024; /* testing */ } else { + Output("privKey not NULL"); /* put key in the buffer */ // printf("modulus len %d\n", pubKey->u.rsa.modulus.len); // printf("exponent len %d\n", pubKey->u.rsa.publicExponent.len); @@ -1001,7 +1166,7 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, Buffer data_blob = GetSignBlob ( /*muscle_public_key */ blob, challenge); // printf("after getsignblob, blob size =%d",blob.size()); - Buffer proof = Sign (privKey, data_blob); + Buffer proof = Sign (SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE, privKey, data_blob); // printf("begin verifying proof"); unsigned char *pkeyb = (unsigned char *) (BYTE *) data_blob; int pkeyb_len = data_blob.size (); @@ -1036,6 +1201,7 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, return apdu_resp; } + Output("after VerifyProof"); m_buffer = Buffer (1, (BYTE) (blob.size () / 256)) + @@ -1049,8 +1215,9 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, } else { - // fake key - BYTE fake_key[] = { + Output("keygen is false"); + // fake RSA key + BYTE fake_RSA_key[] = { 0x00, 0x8b, 0x00, 0x01, 0x04, 0x00, 0x00, 0x80, 0x9f, 0xf9, 0x6e, 0xa6, 0x6c, 0xd9, 0x4b, 0x5c, 0x1a, 0xb6, 0xd8, 0x78, 0xd2, 0xaf, 0x45, 0xd5, 0xce, 0x8a, 0xee, 0x69, 0xfc, 0xdb, @@ -1068,18 +1235,365 @@ RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, 0x01, 0x00, 0x80, 0x58, 0x06, 0x40, 0x4e, 0x05, 0xd8, 0x54, 0x87, 0xb1, 0x5b, 0xfc, 0x67, 0x95, 0xe5 }; - m_buffer = Buffer ((BYTE *) fake_key, sizeof fake_key); + + m_buffer = Buffer ((BYTE *) fake_RSA_key, sizeof fake_RSA_key); buffer_size = m_buffer.size (); } - + Output("creating new APDU_Response, data = "); Buffer data = Buffer (1, (BYTE) (buffer_size >> 8) & 0xff) + // key length Buffer (1, (BYTE) buffer_size & 0xff) + // key length Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + printBuf(&data); + APDU_Response *apdu_resp = new APDU_Response (data); return apdu_resp; } + +SECKEYECParams * +RA_Token::getECParams(const char *curve) +{ +/*This function is borrowed from certutil*/ + SECKEYECParams *ecparams = NULL; + SECOidData *oidData = NULL; + SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */ + int i, numCurves; + + if (curve != NULL) { + numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair); + for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); + i++) { + if (PL_strcmp(curve, nameTagPair[i].curveName) == 0) + curveOidTag = nameTagPair[i].curveOidTag; + } + } + + /* Return NULL if curve name is not recognized */ + if ((curveOidTag == SEC_OID_UNKNOWN) || + (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) { + fprintf(stderr, "Unrecognized elliptic curve %s\n", curve); + return NULL; + } + + ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len)); + + /* + * ecparams->data needs to contain the ASN encoding of an object ID (OID) + * representing the named curve. The actual OID is in + * oidData->oid.data so we simply prepend 0x06 and OID length + */ + ecparams->data[0] = SEC_ASN1_OBJECT_ID; + ecparams->data[1] = oidData->oid.len; + memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len); + + return ecparams; +} + +static int ReadLine(PRFileDesc *f, char *buf, int buf_len, int *removed_return) +{ + char *cur = buf; + int sum = 0; + PRInt32 rc; + + if (removed_return != NULL) { + *removed_return = 0; + } + while (1) { + rc = PR_Read(f, cur, 1); + if (rc == -1 || rc == 0) + break; + if (*cur == '\r') { + continue; + } + if (*cur == '\n') { + *cur = '\0'; + if (removed_return != NULL) { + *removed_return = 1; + } + break; + } + sum++; + cur++; + } + return sum; +} + + +char * +RA_Token::getModulePasswordText(PK11SlotInfo *slot, PRBool retry, void *arg) { + secuPWData *pwdata = (secuPWData *)arg; + if (pwdata->data != NULL) { + return PL_strdup(pwdata->data); + } else { + Output("getModulePasswordText: password not found"); + return NULL; + } +} + +/* + * for EC keys + */ +APDU_Response * +RA_Token::ProcessGenerateKeyECC (Generate_Key_ECC_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + CK_MECHANISM_TYPE mechanism = CKM_EC_KEY_PAIR_GEN; + SECKEYPrivateKey *privKey = NULL; + SECKEYPublicKey *pubKey = NULL; + PK11SlotInfo *slot = NULL; + int buffer_size = 0; + + // for testing only +#ifdef VERBOSE + Output ("RA_Token::ProcessGenerateKeyECC"); +#endif + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_gk_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_gk_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer req = apdu->GetData (); + BYTE *raw = (BYTE *) req; + int keysize = (((BYTE *) req)[1] << 8) + ((BYTE *) req)[2]; +#ifdef VERBOSE + Output("Requested key size: %d", keysize); +#endif + char *keycurve = NULL; + /* only three curves are supported by token */ + if (keysize == 256) { + keycurve = "nistp256"; + } else if (keysize == 384) { + keycurve = "nistp384"; + } else if (keysize == 521) { + keycurve = "nistp521"; + } else { + Output("unsupported key size: %d, default to nistp256", keysize); + keycurve = "nistp256"; + } + + int wrapped_challenge_len = ((BYTE *) req)[5]; +#ifdef VERBOSE + printf("Challenged Size=%d\n", wrapped_challenge_len); +#endif + Buffer wrapped_challenge = Buffer ((BYTE *) & raw[6], + wrapped_challenge_len); + + PK11AttrFlags attrFlags = 0; + + /* generate key pair */ + char *keygen_param = params->GetValue ("keygen"); + + if (keygen_param == NULL || (strcmp (keygen_param, "true") == 0)) { +#ifdef VERBOSE + Output("EC keygen is true"); +#endif + /* + * slotnamefile contains the actual slot name. + * This is to overcome the issue with spaces in a token name + */ + char *slotnamefile = params->GetValue("slotnamefile"); + int removed_return = 0; + char slotname[500] = "internal"; + PRFileDesc *fd_slotname = (PRFileDesc *) NULL; + if (slotnamefile == NULL) { + slot = PK11_GetInternalKeySlot(); + } else { + fd_slotname = PR_Open(slotnamefile, PR_RDWR, 00400|00200); + int n = ReadLine(fd_slotname, slotname, 500, &removed_return); + slot = PK11_FindSlotByName(slotname); + } + + Output("slotname=%s ",slotname); + if (slot == NULL) { + Output("slot NULL"); + exit(1); + } else { + Output("using slot : %s", slotname); + } + + RA_Token::m_tokenpassword = params->GetValue("tokpasswd"); + /* log into token using plaintext*/ + secuPWData pwdata = {pwdata.PW_NONE, 0}; + pwdata.source = pwdata.PW_PLAINTEXT; + pwdata.data = RA_Token::m_tokenpassword; + PK11_SetPasswordFunc(RA_Token::getModulePasswordText); + + if (PK11_NeedLogin(slot)) { + Output("slot needs login"); + SECStatus rv = SECFailure; + rv = PK11_Authenticate(slot, PR_TRUE, &pwdata); + Output("after PK11_Authenticate"); + if (rv == SECSuccess) { + Output("token authenticated\n"); + } else { + Output("Could not get password for %s", + PK11_GetTokenName(slot)); + } + if (PK11_IsLoggedIn(slot, &pwdata)) { + Output("token logged in"); + } else { + Output("token not logged in"); + } + } + + SECKEYECParams *ecparams = getECParams(keycurve); + if (ecparams == NULL) { + Output("getECParams() returns NULL"); + exit(1); + } else { + Output("getECParams() returns not NULL"); + } + + Output("before calling PK11_GenerateKeyPair"); + privKey = PK11_GenerateKeyPair(slot, + mechanism, + ecparams, + &pubKey, + PR_TRUE /*isPerm*/, + PR_TRUE /*isSensitive*/, + &pwdata /*wincx*/); + Output("after calling PK11_GenerateKeyPair"); + + if (ecparams) { + SECITEM_FreeItem((SECItem *)ecparams, PR_TRUE); + } + if ((privKey == NULL) || (pubKey == NULL)) { + /*not good. should bail*/ + Output("privKey == NULL, fatal error."); + exit(1); + } else { +#ifdef VERBOSE +Output("privKey not NULL"); +#endif + /* put key in the buffer */ + Buffer blob = GetKeyBlobEC (keysize, pubKey); + +/* + * The key generation operation creates a proof-of-location for the + * newly generated key. This proof is a signature computed with the + * new private key using the ECDSA_SHA1signature algorithm. The + * signature is computed over the Muscle Key Blob representation of + * the new public key and the challenge sent in the key generation + * request. These two data fields are concatenated together to form + * the input to the signature, without any other data or length fields. + */ + + Buffer challenge = Buffer (16, (BYTE) 0x00); +#ifdef VERBOSE + printf("Encrypted Enrollment Challenge:\n"); + wrapped_challenge.dump(); +#endif + Util::DecryptData (m_kek_key, wrapped_challenge, challenge); + +#ifdef VERBOSE + printf("Enrollment Challenge:\n"); + challenge.dump(); + printf("after challenge dump"); +#endif + Buffer muscle_public_key = GetMusclePublicKeyDataEC (pubKey, keysize); +#ifdef VERBOSE + printf("after muscle_public_key get, muscle_public_key size=%d", muscle_public_key.size()); +#endif + Buffer data_blob = GetSignBlob ( /*muscle_public_key */ blob, + challenge); + Output("after getsignblob, blob size =%d",blob.size()); + Buffer proof = Sign (SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE, privKey, data_blob); + +#ifdef VERBOSE + printf("begin verifying proof"); +#endif + unsigned char *pkeyb = (unsigned char *) (BYTE *) data_blob; + int pkeyb_len = data_blob.size (); + +Output("skipping VerifyProof"); +#ifdef VERIFY_PROOF + SECItem siProof; + siProof.type = (SECItemType) 0; + siProof.data = (unsigned char *) proof; + siProof.len = proof.size (); + + if (VerifyProof (pubKey, &siProof, pkeyb_len, pkeyb, &challenge) != 1) + { + + Output ("VerifyProof failed"); + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + + } + +Output("after VerifyProof"); +Output("blob.size=%d", blob.size()); +Output("pkeyb_len=", pkeyb_len); +Output("proof.size=", proof.size()); +#endif /*VERIFY_PROOF */ + + /* ECC format */ + m_buffer = + Buffer (1, (BYTE) (blob.size () / 256)) + + Buffer (1, (BYTE) (blob.size () % 256)) + + Buffer (blob) + + Buffer (1, (BYTE) (proof.size () / 256)) + + Buffer (1, (BYTE) (proof.size () % 256)) + Buffer (proof); + buffer_size = m_buffer.size (); + } // if private key not NULL + + } else { + Output("keygen is false, using fake EC key with nistp256"); + + // fake/static EC key + BYTE fake_EC_key[] = { + 0x00, 0x47, // total length + 0x00, 0x0a, // EC + 0x01, 0x00, // keysize == 256 + 0x00, 0x41, // length of pubkey + // pubkey + 0x04, 0xd2, + 0x26 ,0x83 ,0x36 ,0x80 ,0x33 ,0x2d ,0x26 ,0xda ,0x76 ,0x97, + 0xbb ,0x0b ,0xc8 ,0xc3 ,0x86 ,0xc9 ,0x70 ,0x36 ,0x9b ,0x40, + 0x4c ,0xa4 ,0xec ,0x3a ,0x0b ,0xa5 ,0x89 ,0x67 ,0xde ,0xc4, + 0x89 ,0x47 ,0x28 ,0x15 ,0xdd ,0x74 ,0x4b ,0xf8 ,0x21 ,0x18, + 0x40 ,0x06 ,0xf9 ,0x28 ,0xc4 ,0x62 ,0x26 ,0xa1 ,0x59 ,0x59, + 0x85 ,0x62 ,0xaf ,0xd0 ,0x5d ,0x43 ,0xde ,0xd7 ,0xb4 ,0xcf, + 0xc5 ,0x5b ,0xee, + // proof size + 0x00, 0x46, + //proof + 0x30 ,0x44 ,0x02 ,0x20 ,0x00, + 0xd6 ,0xc2 ,0x08 ,0x34 ,0x79 ,0x28 ,0x2e ,0x5f ,0x70 ,0xe5, + 0x38 ,0x1d ,0x84 ,0xa9 ,0x40 ,0x05 ,0x65 ,0x67 ,0x0f ,0x65, + 0x46 ,0x5d ,0xf7 ,0x68 ,0x37 ,0x86 ,0x0b ,0x66 ,0xf7 ,0x71, + 0x0e ,0x02 ,0x20 ,0x3f ,0x48 ,0xdf ,0x29 ,0xa1 ,0x0e ,0xfb, + 0xdf ,0x38 ,0x26 ,0x9d ,0x54 ,0x01 ,0xbc ,0xb6 ,0x9d ,0xc0, + 0xbf ,0x27 ,0x29 ,0x95 ,0x97 ,0x3c ,0x2f ,0xef ,0xb1 ,0xd2, + 0xdc ,0x9f ,0xcb ,0x03 ,0x8d + }; + + m_buffer = Buffer ((BYTE *) fake_EC_key, sizeof fake_EC_key); + buffer_size = m_buffer.size (); + } + + Output("creating new APDU_Response, data = "); + Buffer data = + Buffer (1, (BYTE) (buffer_size >> 8) & 0xff) + // key length + Buffer (1, (BYTE) buffer_size & 0xff) + // key length + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + printBuf(&data); + + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + APDU_Response * RA_Token::ProcessCreateObject (Create_Object_APDU * apdu, NameValueSet * vars, NameValueSet * params) @@ -1995,6 +2509,10 @@ RA_Token::Process (APDU * apdu, NameValueSet * vars, NameValueSet * params) { resp = ProcessGenerateKey ((Generate_Key_APDU *) apdu, vars, params); } + else if (apdu->GetType () == APDU_GENERATE_KEY_ECC) + { + resp = ProcessGenerateKeyECC ((Generate_Key_ECC_APDU *) apdu, vars, params); + } else if (apdu->GetType () == APDU_IMPORT_KEY_ENC) { resp = ProcessImportKeyEnc ((Import_Key_Enc_APDU *) apdu, vars, params); diff --git a/base/tps/tools/raclient/RA_Token.h b/base/tps/tools/raclient/RA_Token.h index bf92e4e89..de60857da 100644 --- a/base/tps/tools/raclient/RA_Token.h +++ b/base/tps/tools/raclient/RA_Token.h @@ -62,6 +62,7 @@ #include "apdu/List_Objects_APDU.h" #include "apdu/Create_Pin_APDU.h" #include "apdu/Generate_Key_APDU.h" +#include "apdu/Generate_Key_ECC_APDU.h" #include "apdu/Select_APDU.h" #include "apdu/Delete_File_APDU.h" #include "apdu/Get_Version_APDU.h" @@ -76,6 +77,7 @@ typedef enum { kek } keyType; + class RA_Token { public: @@ -103,6 +105,17 @@ class RA_Token void SetMinorVersion(int v); BYTE GetLifeCycleState(); public: +typedef struct { + enum { + PW_NONE = 0, + PW_FROMFILE = 1, + PW_PLAINTEXT = 2, + PW_EXTERNAL = 3 + } source; + char *data; +} secuPWData; + + static char *getModulePasswordText(PK11SlotInfo *slot, PRBool retry, void *arg); int VerifyMAC(APDU *apdu); void ComputeAPDUMac(APDU *apdu, Buffer &new_mac); PK11SymKey *CreateSessionKey(keyType keytype, @@ -189,6 +202,9 @@ class RA_Token APDU_Response *ProcessGenerateKey(Generate_Key_APDU *apdu, NameValueSet *vars, NameValueSet *params); + APDU_Response *ProcessGenerateKeyECC(Generate_Key_ECC_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); APDU_Response *ProcessImportKeyEnc(Import_Key_Enc_APDU *apdu, NameValueSet *vars, NameValueSet *params); @@ -198,28 +214,34 @@ class RA_Token APDU_Response *ProcessPutKey(Put_Key_APDU *apdu, NameValueSet *vars, NameValueSet *params); + +#define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1 +/* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */ + + static SECKEYECParams *getECParams(const char *curve); public: - Buffer m_card_challenge; - Buffer m_host_challenge; - PK11SymKey *m_session_key; - PK11SymKey *m_enc_session_key; - Buffer m_icv; - Buffer m_cuid; - Buffer m_msn; - Buffer m_version; - Buffer m_key_info; - Buffer m_auth_key; - Buffer m_mac_key; - Buffer m_kek_key; - Buffer m_buffer; - BYTE m_lifecycle_state; - char *m_pin; - Buffer* m_object; - int m_major_version; - int m_minor_version; - int m_object_len; - int m_chunk_len; - char m_objectid[3]; + Buffer m_card_challenge; + Buffer m_host_challenge; + PK11SymKey *m_session_key; + PK11SymKey *m_enc_session_key; + Buffer m_icv; + Buffer m_cuid; + Buffer m_msn; + Buffer m_version; + Buffer m_key_info; + Buffer m_auth_key; + Buffer m_mac_key; + Buffer m_kek_key; + Buffer m_buffer; + BYTE m_lifecycle_state; + char *m_pin; + Buffer* m_object; + int m_major_version; + int m_minor_version; + int m_object_len; + int m_chunk_len; + char m_objectid[3]; + char *m_tokenpassword; }; #endif /* RA_TOKEN_H */ diff --git a/base/tps/tools/raclient/enroll.tps.ec b/base/tps/tools/raclient/enroll.tps.ec new file mode 100755 index 000000000..b6e25069d --- /dev/null +++ b/base/tps/tools/raclient/enroll.tps.ec @@ -0,0 +1,43 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; +# version 2.1 of the License. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# Copyright (C) 2007 Red Hat, Inc. +# All rights reserved. +# --- END COPYRIGHT BLOCK --- +# +######################################################## +# Description: +# This data file tests enrollment operation. +# +# Execution: +# tpsclient < enroll.test +# +######################################################## +op=var_set name=ra_host value=host1 +op=var_set name=ra_port value=7891 +op=var_set name=ra_uri value=/nk_service +# print original token status +op=token_set cuid=a00192030405060708c9 msn=01020304 app_ver=6FBBC105 key_info=0101 major_ver=0 minor_ver=0 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +# slotnamefile is the file name which contains the name of the token +op=ra_enroll uid=pinmanager num_threads=1 pwd=netscape new_pin=netscape extensions=tokenType=userKey keygen=true slotnamefile=tokenname tokpasswd=redhat +# print changed token status +op=token_status +op=exit + |