void DeriveTests::dhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey) { CK_ATTRIBUTE valAttrib = { CKA_VALUE, NULL_PTR, 0 }; CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); valAttrib.pValue = (CK_BYTE_PTR)malloc(valAttrib.ulValueLen); rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); CK_MECHANISM mechanism = { CKM_DH_PKCS_DERIVE, NULL_PTR, 0 }; mechanism.pParameter = valAttrib.pValue; mechanism.ulParameterLen = valAttrib.ulValueLen; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_BBOOL bFalse = CK_FALSE; CK_BBOOL bTrue = CK_TRUE; CK_ULONG secLen = 32; CK_ATTRIBUTE keyAttribs[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &bFalse, sizeof(bFalse) }, { CKA_SENSITIVE, &bFalse, sizeof(bFalse) }, { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }, { CKA_VALUE_LEN, &secLen, sizeof(secLen) } }; hKey = CK_INVALID_HANDLE; rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hPrivateKey, keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE), &hKey) ); free(valAttrib.pValue); CPPUNIT_ASSERT(rv == CKR_OK); }
void DeriveTests::symDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE &hDerive, CK_MECHANISM_TYPE mechType, CK_KEY_TYPE keyType) { CK_RV rv; CK_MECHANISM mechanism = { mechType, NULL_PTR, 0 }; CK_MECHANISM mechEncrypt = { CKM_VENDOR_DEFINED, NULL_PTR, 0 }; CK_KEY_DERIVATION_STRING_DATA param1; CK_DES_CBC_ENCRYPT_DATA_PARAMS param2; CK_AES_CBC_ENCRYPT_DATA_PARAMS param3; CK_BYTE data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32 }; CK_ULONG secLen = 0; switch (mechType) { case CKM_DES_ECB_ENCRYPT_DATA: case CKM_DES3_ECB_ENCRYPT_DATA: case CKM_AES_ECB_ENCRYPT_DATA: param1.pData = &data[0]; param1.ulLen = sizeof(data); mechanism.pParameter = ¶m1; mechanism.ulParameterLen = sizeof(param1); break; case CKM_DES_CBC_ENCRYPT_DATA: case CKM_DES3_CBC_ENCRYPT_DATA: memcpy(param2.iv, "12345678", 8); param2.pData = &data[0]; param2.length = sizeof(data); mechanism.pParameter = ¶m2; mechanism.ulParameterLen = sizeof(param2); break; case CKM_AES_CBC_ENCRYPT_DATA: memcpy(param3.iv, "1234567890ABCDEF", 16); param3.pData = &data[0]; param3.length = sizeof(data); mechanism.pParameter = ¶m3; mechanism.ulParameterLen = sizeof(param3); break; default: CPPUNIT_FAIL("Invalid mechanism"); } switch (keyType) { case CKK_GENERIC_SECRET: secLen = 32; break; case CKK_DES: mechEncrypt.mechanism = CKM_DES_ECB; break; case CKK_DES2: case CKK_DES3: mechEncrypt.mechanism = CKM_DES3_ECB; break; case CKK_AES: mechEncrypt.mechanism = CKM_AES_ECB; secLen = 32; break; default: CPPUNIT_FAIL("Invalid key type"); } CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BBOOL bFalse = CK_FALSE; CK_BBOOL bTrue = CK_TRUE; CK_ATTRIBUTE keyAttribs[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &bFalse, sizeof(bFalse) }, { CKA_ENCRYPT, &bTrue, sizeof(bTrue) }, { CKA_DECRYPT, &bTrue, sizeof(bTrue) }, { CKA_SENSITIVE, &bFalse, sizeof(bFalse) }, { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }, { CKA_VALUE_LEN, &secLen, sizeof(secLen) } }; hDerive = CK_INVALID_HANDLE; if (secLen > 0) { rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hKey, keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE), &hDerive) ); } else { rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hKey, keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE) - 1, &hDerive) ); } CPPUNIT_ASSERT(rv == CKR_OK); // Check that KCV has been set CK_ATTRIBUTE checkAttribs[] = { { CKA_CHECK_VALUE, NULL_PTR, 0 } }; CK_BYTE check[3]; checkAttribs[0].pValue = check; checkAttribs[0].ulValueLen = sizeof(check); rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hDerive, checkAttribs, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); CPPUNIT_ASSERT(checkAttribs[0].ulValueLen == 3); if (keyType == CKK_GENERIC_SECRET) return; CK_BYTE cipherText[300]; CK_ULONG ulCipherTextLen; CK_BYTE recoveredText[300]; CK_ULONG ulRecoveredTextLen; rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechEncrypt,hDerive) ); CPPUNIT_ASSERT(rv==CKR_OK); ulCipherTextLen = sizeof(cipherText); rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,data,sizeof(data),cipherText,&ulCipherTextLen) ); CPPUNIT_ASSERT(rv==CKR_OK); rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechEncrypt,hDerive) ); CPPUNIT_ASSERT(rv==CKR_OK); ulRecoveredTextLen = sizeof(recoveredText); rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) ); CPPUNIT_ASSERT(rv==CKR_OK); CPPUNIT_ASSERT(ulRecoveredTextLen==sizeof(data)); CPPUNIT_ASSERT(memcmp(data, recoveredText, sizeof(data)) == 0); }
void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw) { CK_ATTRIBUTE valAttrib = { CKA_EC_POINT, NULL_PTR, 0 }; CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); valAttrib.pValue = (CK_BYTE_PTR)malloc(valAttrib.ulValueLen); rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); CK_ECDH1_DERIVE_PARAMS parms = { CKD_NULL, 0, NULL_PTR, 0, NULL_PTR }; // Use RAW or DER format if (useRaw) { size_t offset = 0; unsigned char* buf = (unsigned char*)valAttrib.pValue; if (valAttrib.ulValueLen > 2 && buf[0] == 0x04) { if (buf[1] < 0x80) { offset = 2; } else { if (valAttrib.ulValueLen > ((buf[1] & 0x7F) + (unsigned int)2)) { offset = 2 + (buf[1] & 0x7F); } } } parms.pPublicData = buf + offset; parms.ulPublicDataLen = valAttrib.ulValueLen - offset; } else { parms.pPublicData = (unsigned char*)valAttrib.pValue; parms.ulPublicDataLen = valAttrib.ulValueLen; } CK_MECHANISM mechanism = { CKM_ECDH1_DERIVE, NULL, 0 }; mechanism.pParameter = &parms; mechanism.ulParameterLen = sizeof(parms); CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_BBOOL bFalse = CK_FALSE; CK_BBOOL bTrue = CK_TRUE; CK_ULONG secLen = 32; CK_ATTRIBUTE keyAttribs[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &bFalse, sizeof(bFalse) }, { CKA_SENSITIVE, &bFalse, sizeof(bFalse) }, { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }, { CKA_VALUE_LEN, &secLen, sizeof(secLen) } }; hKey = CK_INVALID_HANDLE; rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hPrivateKey, keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE), &hKey) ); free(valAttrib.pValue); CPPUNIT_ASSERT(rv == CKR_OK); }
/* initial code will only support what is needed for pkcs11_ec_ckey * i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE * and CK_EC_KDF_TYPE supported by token * The secret key object is deleted * * In future CKM_ECMQV_DERIVE with CK_ECMQV_DERIVE_PARAMS * could also be supported, and the secret key object could be returned. */ static int pkcs11_ecdh_derive(unsigned char **out, size_t *outlen, const unsigned long ecdh_mechanism, const void * ec_params, void *outnewkey, PKCS11_KEY * key) { PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_CTX *ctx = KEY2CTX(key); PKCS11_TOKEN *token = KEY2TOKEN(key); PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_MECHANISM mechanism; int rv; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY; CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET; CK_OBJECT_HANDLE * tmpnewkey = (CK_OBJECT_HANDLE *)outnewkey; CK_ATTRIBUTE newkey_template[] = { {CKA_TOKEN, &false, sizeof(false)}, /* session only object */ {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = ecdh_mechanism; mechanism.pParameter = (void*)ec_params; switch (ecdh_mechanism) { case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); break; #if 0 /* TODO */ case CK_ECMQV_DERIVE_PARAMS: mechanism.ulParameterLen = sizeof(CK_ECMQV_DERIVE_PARAMS); break; #endif default: PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(PKCS11_NOT_SUPPORTED)); return -1; } rv = CRYPTOKI_call(ctx, C_DeriveKey(spriv->session, &mechanism, kpriv->object, newkey_template, 5, &newkey)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, rv); /* Return the value of the secret key and/or the object handle of the secret key */ if (out && outlen) { /* pkcs11_ec_ckey only asks for the value */ if (pkcs11_getattr_alloc(token, newkey, CKA_VALUE, out, outlen)) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_ATTRIBUTE_VALUE_INVALID)); CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey)); return -1; } } if (tmpnewkey) /* For future use (not used by pkcs11_ec_ckey) */ *tmpnewkey = newkey; else /* Destroy the temporary key */ CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey)); return 0; }
/* initial code will only support what is needed for pkcs11_ec_ckey * i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE * and CK_EC_KDF_TYPE supported by token * The secret key object is deleted * * In future CKM_ECMQV_DERIVE with CK_ECMQV_DERIVE_PARAMS * could also be supported, and the secret key object could be returned. */ int pkcs11_ecdh_derive_internal(unsigned char **out, size_t *outlen, const unsigned long ecdh_mechanism, const void * ec_params, void *outnewkey, PKCS11_KEY * key) { int rv; int ret = -1; unsigned char * buf = NULL; size_t buflen; PKCS11_KEY_private *priv; PKCS11_SLOT *slot; PKCS11_CTX *ctx; PKCS11_TOKEN *token; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY; CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET; CK_OBJECT_HANDLE * tmpnewkey = (CK_OBJECT_HANDLE *)outnewkey; CK_ATTRIBUTE newkey_template[] = { {CKA_TOKEN, &false, sizeof(false)}, /* session only object */ {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; ctx = KEY2CTX(key); priv = PRIVKEY(key); token = KEY2TOKEN(key); slot = KEY2SLOT(key); CHECK_KEY_FORK(key); session = PRIVSLOT(slot)->session; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = ecdh_mechanism; mechanism.pParameter = (void*)ec_params; switch (ecdh_mechanism) { case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); break; // case CK_ECMQV_DERIVE_PARAMS: // mechanism.ulParameterLen = sizeof(CK_ECMQV_DERIVE_PARAMS); // break; default: PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, PKCS11_NOT_SUPPORTED); goto err; } CRYPTO_w_lock(PRIVSLOT(slot)->lockid); rv = CRYPTOKI_call(ctx, C_DeriveKey(session, &mechanism, priv->object, newkey_template, 5, &newkey)); if (rv) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(rv)); goto err; } /* Return the value of the secret key and/or the object handle of the secret key */ /* pkcs11_ec_ckey only asks for the value */ if (out && outlen) { /* get size of secret key value */ if (!pkcs11_getattr_var(token, newkey, CKA_VALUE, NULL, &buflen) && buflen > 0) { buf = OPENSSL_malloc(buflen); if (buf == NULL) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_HOST_MEMORY)); goto err; } } else { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_ATTRIBUTE_VALUE_INVALID)); goto err; } pkcs11_getattr_var(token, newkey, CKA_VALUE, buf, &buflen); *out = buf; *outlen = buflen; buf = NULL; } /* not used by pkcs11_ec_ckey for future use */ if (tmpnewkey) { *tmpnewkey = newkey; newkey = CK_INVALID_HANDLE; } ret = 1; err: if (buf) OPENSSL_free(buf); if (newkey != CK_INVALID_HANDLE && session != CK_INVALID_HANDLE) CRYPTOKI_call(ctx, C_DestroyObject(session, newkey)); return ret; }