8261433: Better pkcs11 performance for libpkcs11:C_EncryptInit/libpkcs11:C_DecryptInit

Reviewed-by: djelinski, valeriep, coffeys
This commit is contained in:
Prajwal Kumaraswamy 2024-05-13 16:10:45 +00:00 committed by Sean Coffey
parent ff4bf1cf9f
commit 7c2c24fc05
5 changed files with 220 additions and 77 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -454,12 +454,26 @@ final class P11AEADCipher extends CipherSpi {
if (session == null) {
session = token.getOpSession();
}
if (encrypt) {
token.p11.C_EncryptInit(session.id(), mechWithParams,
p11KeyID);
if (type == Transformation.AES_GCM) {
CK_VERSION cryptokiVersion = token.p11.getVersion();
boolean useNormativeMechFirst = cryptokiVersion.major > 2 ||
(cryptokiVersion.major == 2 && cryptokiVersion.minor >= 40);
if (encrypt) {
token.p11.C_GCMEncryptInitWithRetry(session.id(), mechWithParams,
p11KeyID, useNormativeMechFirst);
} else {
token.p11.C_GCMDecryptInitWithRetry(session.id(), mechWithParams,
p11KeyID, useNormativeMechFirst);
}
} else {
token.p11.C_DecryptInit(session.id(), mechWithParams,
p11KeyID);
if (encrypt) {
token.p11.C_EncryptInit(session.id(), mechWithParams,
p11KeyID);
} else {
token.p11.C_DecryptInit(session.id(), mechWithParams,
p11KeyID);
}
}
} catch (PKCS11Exception e) {
p11Key.releaseKeyID();

View File

@ -793,6 +793,24 @@ public class PKCS11 {
public native void C_EncryptInit(long hSession, CK_MECHANISM pMechanism,
long hKey) throws PKCS11Exception;
/**
* C_GCMEncryptInitWithRetry initializes a GCM encryption operation and retry
* with alternative param structure for max compatibility.
* (Encryption and decryption)
*
* @param hSession the session's handle
* (PKCS#11 param: CK_SESSION_HANDLE hSession)
* @param pMechanism the encryption mechanism
* (PKCS#11 param: CK_MECHANISM_PTR pMechanism)
* @param hKey the handle of the encryption key
* (PKCS#11 param: CK_OBJECT_HANDLE hKey)
* @param useNormativeVerFirst whether to use normative version of GCM parameter first
* @exception PKCS11Exception If function returns other value than CKR_OK.
* @preconditions
* @postconditions
*/
public native void C_GCMEncryptInitWithRetry(long hSession, CK_MECHANISM pMechanism,
long hKey, boolean useNormativeVerFirst) throws PKCS11Exception;
/**
* C_Encrypt encrypts single-part data.
@ -887,6 +905,24 @@ public class PKCS11 {
public native void C_DecryptInit(long hSession, CK_MECHANISM pMechanism,
long hKey) throws PKCS11Exception;
/**
* C_GCMDecryptInitWithRetry initializes a GCM decryption operation
* with alternative param structure for max compatibility.
* (Encryption and decryption)
*
* @param hSession the session's handle
* (PKCS#11 param: CK_SESSION_HANDLE hSession)
* @param pMechanism the decryption mechanism
* (PKCS#11 param: CK_MECHANISM_PTR pMechanism)
* @param hKey the handle of the decryption key
* (PKCS#11 param: CK_OBJECT_HANDLE hKey)
* @param useNormativeVerFirst whether to use normative version of GCM parameter first
* @exception PKCS11Exception If function returns other value than CKR_OK.
* @preconditions
* @postconditions
*/
public native void C_GCMDecryptInitWithRetry(long hSession, CK_MECHANISM pMechanism,
long hKey, boolean useNormativeVerFirst) throws PKCS11Exception;
/**
* C_Decrypt decrypts encrypted data in a single part.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
@ -1014,18 +1014,19 @@ cleanup:
}
/*
* converts the Java CK_GCM_PARAMS object to a CK_GCM_PARAMS_NO_IVBITS pointer
* Note: Need to try NSS definition first to avoid SIGSEGV.
* converts the Java CK_GCM_PARAMS object to a CK_GCM_PARAMS pointer
* Note: Early NSS versions crash w/ CK_GCM_PARAMS and need to use
* CK_GCM_PARAMS_NO_IVBITS to avoid SIGSEGV.
*
* @param env - used to call JNI funktions to get the Java classes and objects
* @param jParam - the Java CK_GCM_PARAMS object to convert
* @param pLength - length of the allocated memory of the returned pointer
* @return pointer to the new CK_GCM_PARAMS_NO_IVBITS structure
* @return pointer to the new CK_GCM_PARAMS structure
*/
CK_GCM_PARAMS_NO_IVBITS_PTR
CK_GCM_PARAMS_PTR
jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
{
CK_GCM_PARAMS_NO_IVBITS_PTR ckParamPtr;
CK_GCM_PARAMS_PTR ckParamPtr;
jclass jGcmParamsClass;
jfieldID fieldID;
jobject jIv, jAad;
@ -1053,8 +1054,8 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
if (fieldID == NULL) { return NULL; }
jTagLen = (*env)->GetLongField(env, jParam, fieldID);
// allocate memory for CK_GCM_PARAMS_NO_IVBITS pointer
ckParamPtr = calloc(1, sizeof(CK_GCM_PARAMS_NO_IVBITS));
// allocate memory for CK_GCM_PARAMS pointer
ckParamPtr = calloc(1, sizeof(CK_GCM_PARAMS));
if (ckParamPtr == NULL) {
p11ThrowOutOfMemoryError(env, 0);
return NULL;
@ -1065,6 +1066,8 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
if ((*env)->ExceptionCheck(env)) {
goto cleanup;
}
// adjust since the value is in bits
ckParamPtr->ulIvBits = ckParamPtr->ulIvLen << 3;
jByteArrayToCKByteArray(env, jAad, &(ckParamPtr->pAAD), &(ckParamPtr->ulAADLen));
if ((*env)->ExceptionCheck(env)) {
@ -1074,9 +1077,9 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
ckParamPtr->ulTagBits = jLongToCKULong(jTagLen);
if (pLength != NULL) {
*pLength = sizeof(CK_GCM_PARAMS_NO_IVBITS);
*pLength = sizeof(CK_GCM_PARAMS);
}
TRACE1("Created inner GCM_PARAMS PTR w/o ulIvBits %p\n", ckParamPtr);
TRACE1("Created inner GCM_PARAMS PTR %p\n", ckParamPtr);
return ckParamPtr;
cleanup:
free(ckParamPtr->pIv);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
@ -72,7 +72,6 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit
{
CK_SESSION_HANDLE ckSessionHandle;
CK_MECHANISM_PTR ckpMechanism = NULL;
CK_MECHANISM_PTR ckpTemp;
CK_OBJECT_HANDLE ckKeyHandle;
CK_RV rv;
@ -90,20 +89,60 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit
rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
if (ckpMechanism->mechanism == CKM_AES_GCM) {
if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
// retry with CKM_GCM_PARAMS structure in pkcs11t.h
TRACE0("DEBUG C_EncryptInit: retry with CK_GCM_PARAMS\n");
ckpTemp = updateGCMParams(env, ckpMechanism);
if (ckpTemp != NULL) { // only re-call if conversion succeeds
ckpMechanism = ckpTemp;
rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
}
TRACE1("DEBUG C_EncryptInit: freed pMech = %p\n", ckpMechanism);
freeCKMechanismPtr(ckpMechanism);
if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
TRACE0("FINISHED\n");
}
/*
* Class: sun_security_pkcs11_wrapper_PKCS11
* Method: C_GCMEncryptInitWithRetry
* Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;JZ)V
* Parametermapping: *PKCS11*
* @param jlong jSessionHandle CK_SESSION_HANDLE hSession
* @param jobject jMechanism CK_MECHANISM_PTR pMechanism
* @param jlong jKeyHandle CK_OBJECT_HANDLE hKey
* @param jboolean useNormVerFirst CK_BBOOL retry (only retry if the first
* init uses the non-normative version)
*/
JNIEXPORT void JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1GCMEncryptInitWithRetry
(JNIEnv *env, jobject obj, jlong jSessionHandle,
jobject jMechanism, jlong jKeyHandle, jboolean useNormVerFirst)
{
CK_SESSION_HANDLE ckSessionHandle;
CK_MECHANISM_PTR ckpMechanism = NULL;
CK_OBJECT_HANDLE ckKeyHandle;
CK_BBOOL retry = FALSE;
CK_RV rv = 1;
CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
if (ckpFunctions == NULL) { return; }
ckSessionHandle = jLongToCKULong(jSessionHandle);
ckKeyHandle = jLongToCKULong(jKeyHandle);
ckpMechanism = jMechanismToCKMechanismPtr(env, jMechanism);
if ((*env)->ExceptionCheck(env)) { return; }
// if !useNormVerFirst, then update 'ckpMechanism' in place w/
// non-normative GCM params.
retry = (!useNormVerFirst && updateGCMParams(env, ckpMechanism) != NULL);
rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism, ckKeyHandle);
if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
// retry and update 'ckpMechanism' in place w/ normative GCM params.
if (retry && updateGCMParams(env, ckpMechanism) != NULL) {
TRACE0("DEBUG retry C_EncryptInit\n");
rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle,
ckpMechanism, ckKeyHandle);
}
}
TRACE1("DEBUG C_EncryptInit: freed pMech = %p\n", ckpMechanism);
TRACE1("DEBUG C_GCMEncryptInitWithRetry: freed pMech = %p\n", ckpMechanism);
freeCKMechanismPtr(ckpMechanism);
if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
@ -312,7 +351,6 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit
{
CK_SESSION_HANDLE ckSessionHandle;
CK_MECHANISM_PTR ckpMechanism = NULL;
CK_MECHANISM_PTR ckpTemp;
CK_OBJECT_HANDLE ckKeyHandle;
CK_RV rv;
@ -330,20 +368,61 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit
rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
if (ckpMechanism->mechanism == CKM_AES_GCM) {
if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
// retry with CKM_GCM_PARAMS structure in pkcs11t.h
TRACE0("DEBUG C_DecryptInit: retry with CK_GCM_PARAMS\n");
ckpTemp = updateGCMParams(env, ckpMechanism);
if (ckpTemp != NULL) { // only re-call if conversion succeeds
ckpMechanism = ckpTemp;
rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
}
TRACE1("DEBUG C_DecryptInit: freed pMech = %p\n", ckpMechanism);
freeCKMechanismPtr(ckpMechanism);
if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
TRACE0("FINISHED\n");
}
/*
* Class: sun_security_pkcs11_wrapper_PKCS11
* Method: C_GCMDecryptInitWithRetry
* Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;JZ)V
* Parametermapping: *PKCS11*
* @param jlong jSessionHandle CK_SESSION_HANDLE hSession
* @param jobject jMechanism CK_MECHANISM_PTR pMechanism
* @param jlong jKeyHandle CK_OBJECT_HANDLE hKey
* @param jboolean useNormVerFirst CK_BBOOL retry (only retry if the first
* init uses the non-normative version)
*/
JNIEXPORT void JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1GCMDecryptInitWithRetry
(JNIEnv *env, jobject obj, jlong jSessionHandle,
jobject jMechanism, jlong jKeyHandle, jboolean useNormVerFirst)
{
CK_SESSION_HANDLE ckSessionHandle;
CK_MECHANISM_PTR ckpMechanism = NULL;
CK_OBJECT_HANDLE ckKeyHandle;
CK_BBOOL retry = FALSE;
CK_RV rv = 1;
CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
if (ckpFunctions == NULL) { return; }
ckSessionHandle = jLongToCKULong(jSessionHandle);
ckKeyHandle = jLongToCKULong(jKeyHandle);
ckpMechanism = jMechanismToCKMechanismPtr(env, jMechanism);
if ((*env)->ExceptionCheck(env)) { return; }
// if !useNormVerFirst, then update 'ckpMechanism' in place w/
// non-normative GCM params.
retry = (!useNormVerFirst && updateGCMParams(env, ckpMechanism) != NULL);
rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
// retry and update 'ckpMechanism' in place w/ normative GCM params.
if (retry && updateGCMParams(env, ckpMechanism) != NULL) {
TRACE0("DEBUG retry C_DecryptInit with normative CK_GCM_PARAMS\n");
rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
ckKeyHandle);
}
}
TRACE1("DEBUG C_DecryptInit: freed pMech = %p\n", ckpMechanism);
TRACE1("DEBUG C_GCMDecryptInitWithRetry: freed pMech = %p\n", ckpMechanism);
freeCKMechanismPtr(ckpMechanism);
if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
@ -327,14 +327,14 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
tmp = mechPtr->pParameter;
switch (mechPtr->mechanism) {
case CKM_AES_GCM:
if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
TRACE0("[ GCM_PARAMS w/o ulIvBits ]\n");
free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pIv);
free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pAAD);
} else if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS)) {
if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS)) {
TRACE0("[ GCM_PARAMS ]\n");
free(((CK_GCM_PARAMS*)tmp)->pIv);
free(((CK_GCM_PARAMS*)tmp)->pAAD);
} else if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
TRACE0("[ GCM_PARAMS w/o ulIvBits ]\n");
free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pIv);
free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pAAD);
}
break;
case CKM_AES_CCM:
@ -451,43 +451,54 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
}
}
/* This function replaces the CK_GCM_PARAMS_NO_IVBITS structure associated
* with the specified CK_MECHANISM structure with CK_GCM_PARAMS
* structure.
/* This function updates the specified CK_MECHANISM structure
* and its GCM parameter structure switching between CK_GCM_PARAMS and
* CK_GCM_PARAMS_NO_IVBITS.
*
* @param mechPtr pointer to the CK_MECHANISM structure containing
* the to-be-converted CK_GCM_PARAMS_NO_IVBITS structure.
* the to-be-converted CK_GCM_PARAMS / CK_GCM_PARAMS_NO_IVBITS structure.
* @return pointer to the CK_MECHANISM structure containing the
* converted CK_GCM_PARAMS structure or NULL if no conversion took place.
* converted structure or NULL if no conversion is done.
*/
CK_MECHANISM_PTR updateGCMParams(JNIEnv *env, CK_MECHANISM_PTR mechPtr) {
CK_GCM_PARAMS* pGcmParams2 = NULL;
CK_GCM_PARAMS_NO_IVBITS* pParams = NULL;
if ((mechPtr->mechanism == CKM_AES_GCM) &&
(mechPtr->pParameter != NULL_PTR) &&
(mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS))) {
pGcmParams2 = calloc(1, sizeof(CK_GCM_PARAMS));
if (pGcmParams2 == NULL) {
p11ThrowOutOfMemoryError(env, 0);
return NULL;
CK_GCM_PARAMS_PTR pParams;
CK_GCM_PARAMS_NO_IVBITS_PTR pParamsNoIvBits;
CK_ULONG paramLen;
if (mechPtr != NULL) {
paramLen = mechPtr->ulParameterLen;
if (paramLen == sizeof(CK_GCM_PARAMS)) {
// CK_GCM_PARAMS => CK_GCM_PARAMS_NO_IVBITS
pParams = (CK_GCM_PARAMS*) mechPtr->pParameter;
pParamsNoIvBits = calloc(1, sizeof(CK_GCM_PARAMS_NO_IVBITS));
pParamsNoIvBits->pIv = pParams->pIv;
pParamsNoIvBits->ulIvLen = pParams->ulIvLen;
pParamsNoIvBits->pAAD = pParams->pAAD;
pParamsNoIvBits->ulAADLen = pParams->ulAADLen;
pParamsNoIvBits->ulTagBits = pParams->ulTagBits;
mechPtr->pParameter = pParamsNoIvBits;
mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS_NO_IVBITS);
free(pParams);
TRACE0("DEBUG update CK_GCM_PARAMS to CK_GCM_PARAMS_NO_IVBITS\n");
return mechPtr;
} else if (paramLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
// CK_GCM_PARAMS_NO_IVBITS => CK_GCM_PARAMS
pParamsNoIvBits = (CK_GCM_PARAMS_NO_IVBITS*) mechPtr->pParameter;
pParams = calloc(1, sizeof(CK_GCM_PARAMS));
pParams->pIv = pParamsNoIvBits->pIv;
pParams->ulIvLen = pParamsNoIvBits->ulIvLen;
pParams->ulIvBits = pParamsNoIvBits->ulIvLen << 3;
pParams->pAAD = pParamsNoIvBits->pAAD;
pParams->ulAADLen = pParamsNoIvBits->ulAADLen;
pParams->ulTagBits = pParamsNoIvBits->ulTagBits;
mechPtr->pParameter = pParams;
mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS);
free(pParamsNoIvBits);
TRACE0("DEBUG update CK_GCM_PARAMS_NO_IVBITS to CK_GCM_PARAMS\n");
return mechPtr;
}
pParams = (CK_GCM_PARAMS_NO_IVBITS*) mechPtr->pParameter;
pGcmParams2->pIv = pParams->pIv;
pGcmParams2->ulIvLen = pParams->ulIvLen;
pGcmParams2->ulIvBits = (pGcmParams2->ulIvLen << 3);
pGcmParams2->pAAD = pParams->pAAD;
pGcmParams2->ulAADLen = pParams->ulAADLen;
pGcmParams2->ulTagBits = pParams->ulTagBits;
TRACE1("DEBUG updateGCMParams: pMech %p\n", mechPtr);
TRACE2("\t=> GCM param w/o ulIvBits %p => GCM param %p\n", pParams,
pGcmParams2);
free(pParams);
mechPtr->pParameter = pGcmParams2;
mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS);
return mechPtr;
} else {
TRACE0("DEBUG updateGCMParams: no conversion done\n");
}
TRACE0("DEBUG updateGCMParams: no conversion done\n");
return NULL;
}