KMF_RETURN kmf_create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech, CK_FLAGS wanted_flags) { CK_RV rv; KMF_RETURN ret; KMF_RETURN kmf_rv = KMF_OK; CK_SLOT_ID_PTR pSlotList; CK_ULONG pulCount; CK_MECHANISM_INFO info; int i; ret = init_pk11(); if (ret != KMF_OK) return (ret); rv = C_GetSlotList(0, NULL, &pulCount); if (rv != CKR_OK) { kmf_rv = KMF_ERR_UNINITIALIZED; goto out; } pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID)); if (pSlotList == NULL) { kmf_rv = KMF_ERR_MEMORY; goto out; } rv = C_GetSlotList(0, pSlotList, &pulCount); if (rv != CKR_OK) { kmf_rv = KMF_ERR_UNINITIALIZED; goto out; } for (i = 0; i < pulCount; i++) { rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info); if (rv == CKR_OK && (info.flags & wanted_flags) == wanted_flags) break; } if (i < pulCount) { rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION, NULL, NULL, sessionp); if (rv != CKR_OK) { kmf_rv = KMF_ERR_UNINITIALIZED; } } else { kmf_rv = KMF_ERR_UNINITIALIZED; } out: if (pSlotList != NULL) free(pSlotList); return (kmf_rv); }
void InfoTests::testGetMechanismInfo() { CK_RV rv; CK_MECHANISM_INFO info; CK_ULONG ulMechCount = 0; CK_MECHANISM_TYPE_PTR pMechanismList; // Just make sure that we finalize any previous failed tests C_Finalize(NULL_PTR); rv = C_GetMechanismInfo(SLOT_INIT_TOKEN, CKM_RSA_PKCS, &info); CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED); rv = C_Initialize(NULL_PTR); CPPUNIT_ASSERT(rv == CKR_OK); // Get the mechanism list rv = C_GetMechanismList(SLOT_INIT_TOKEN, NULL_PTR, &ulMechCount); CPPUNIT_ASSERT(rv == CKR_OK); CPPUNIT_ASSERT(ulMechCount != 0); pMechanismList = (CK_MECHANISM_TYPE_PTR)malloc(ulMechCount * sizeof(CK_MECHANISM_TYPE_PTR)); rv = C_GetMechanismList(SLOT_INIT_TOKEN, pMechanismList, &ulMechCount); CPPUNIT_ASSERT(rv == CKR_OK); rv = C_GetMechanismInfo(SLOT_INIT_TOKEN, pMechanismList[0], NULL_PTR); CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD); rv = C_GetMechanismInfo(SLOT_INVALID, pMechanismList[0], &info); CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID); rv = C_GetMechanismInfo(SLOT_INIT_TOKEN, CKM_VENDOR_DEFINED, &info); CPPUNIT_ASSERT(rv == CKR_MECHANISM_INVALID); for (unsigned int i = 0; i < ulMechCount; i++) { rv = C_GetMechanismInfo(SLOT_INIT_TOKEN, pMechanismList[i], &info); CPPUNIT_ASSERT(rv == CKR_OK); } free(pMechanismList); C_Finalize(NULL_PTR); }
/* * retrieve the session handle from the first slot that supports the specified * mechanism. */ static CK_RV get_session_handle (CK_MECHANISM_TYPE mech_type, CK_FLAGS flag, CK_SESSION_HANDLE_PTR sess) { CK_RV rv = CKR_OK; CK_MECHANISM_INFO info; netsnmp_pkcs_slot_session *p = NULL; int i, slotcount = 0; if (pSlot) { slotcount = pSlot->count; p = pSlot->pSession; } /* Find a slot with matching mechanism */ for (i = 0; i < slotcount; i++, p++) { rv = C_GetMechanismInfo (p->sid, mech_type, &info); if (rv != CKR_OK) { continue; /* to the next slot */ } else { if (info.flags & flag) { rv = get_slot_session_handle (p, sess); break; /* found */ } } } /* Show error if no matching mechanism found */ if (i == slotcount) { DEBUGMSGTL (("pkcs_init", "No cryptographic provider for %s", mech_type)); return CKR_SESSION_HANDLE_INVALID; } return rv; }
static CAPABILITY_INFO *getCapability( const DEVICE_INFO *deviceInfo, const PKCS11_MECHANISM_INFO *mechanismInfoPtr, const int maxMechanisms ) { VARIABLE_CAPABILITY_INFO *capabilityInfo; CK_MECHANISM_INFO pMechanism; CK_RV status; const CRYPT_ALGO_TYPE cryptAlgo = mechanismInfoPtr->cryptAlgo; const BOOLEAN isPKC = isPkcAlgo( cryptAlgo ) ? TRUE : FALSE; const CK_FLAGS keyGenFlag = isPKC ? CKF_GENERATE_KEY_PAIR : CKF_GENERATE; PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11; int hardwareOnly, i, iterationCount; assert( isReadPtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isReadPtr( mechanismInfoPtr, \ maxMechanisms * sizeof( PKCS11_MECHANISM_INFO ) ) ); /* Set up canary values for the mechanism information in case the driver blindly reports success for every mechanism that we ask for */ memset( &pMechanism, 0, sizeof( CK_MECHANISM_INFO ) ); pMechanism.ulMinKeySize = 0xA5A5; pMechanism.ulMaxKeySize = 0x5A5A; /* Get the information for this mechanism. Since many PKCS #11 drivers implement some of their capabilities using God knows what sort of software implementation, we provide the option to skip emulated mechanisms if required */ status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->mechanism, &pMechanism ); if( status != CKR_OK ) return( NULL ); if( pMechanism.ulMinKeySize == 0xA5A5 && \ pMechanism.ulMaxKeySize == 0x5A5A ) { /* The driver reported that this mechanism is available but didn't update the mechanism information, it's lying */ DEBUG_DIAG(( "Driver reports that mechanism %X is available even " "though it isn't", mechanismInfoPtr->mechanism )); assert( DEBUG_WARN ); return( NULL ); } status = krnlSendMessage( deviceInfo->ownerHandle, IMESSAGE_GETATTRIBUTE, &hardwareOnly, CRYPT_OPTION_DEVICE_PKCS11_HARDWAREONLY ); if( cryptStatusOK( status ) && hardwareOnly && \ !( pMechanism.flags & CKF_HW ) ) { DEBUG_DIAG(( "Skipping mechanism %X, which is only available in " "software emulation", mechanismInfoPtr->mechanism )); return( NULL ); } if( mechanismInfoPtr->requiredFlags != CKF_NONE ) { /* Make sure that the driver flags indicate support for the specific functionality that we require */ if( ( mechanismInfoPtr->requiredFlags & \ pMechanism.flags ) != mechanismInfoPtr->requiredFlags ) { DEBUG_DIAG(( "Driver reports that mechanism %X only has " "capabilities %lX when we require %lX", mechanismInfoPtr->mechanism, mechanismInfoPtr->requiredFlags & pMechanism.flags, mechanismInfoPtr->requiredFlags )); ////////////////////////////////// // Kludge to allow it to be used ////////////////////////////////// // assert( DEBUG_WARN ); // return( NULL ); } } /* Copy across the template for this capability */ if( ( capabilityInfo = clAlloc( "getCapability", \ sizeof( CAPABILITY_INFO ) ) ) == NULL ) return( NULL ); for( i = 0; capabilityTemplates[ i ].cryptAlgo != cryptAlgo && \ capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR && \ i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ); i++ ); ENSURES_N( i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ) ); ENSURES_N( capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR ); memcpy( capabilityInfo, &capabilityTemplates[ i ], sizeof( CAPABILITY_INFO ) ); /* Set up the keysize information if there's anything useful available */ if( keysizeValid( cryptAlgo ) ) { int minKeySize = ( int ) pMechanism.ulMinKeySize; int maxKeySize = ( int ) pMechanism.ulMaxKeySize; /* Adjust the key size to bytes and make sure that all values are consistent. Some implementations report silly bounds (e.g. 1-bit RSA, "You naughty minKey" or alternatively 4Gbit RSA) so we adjust them to a sane value if necessary. We also limit the maximum key size to match the cryptlib native maximum key size, both for consistency and because cryptlib performs buffer allocation based on the maximum native buffer size */ if( pMechanism.ulMinKeySize < 0 || \ pMechanism.ulMinKeySize >= 10000L ) { DEBUG_DIAG(( "Driver reports invalid minimum key size %lu for " "%s algorithm", pMechanism.ulMinKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); minKeySize = 0; } if( pMechanism.ulMaxKeySize < 0 || \ pMechanism.ulMaxKeySize >= 100000L ) { DEBUG_DIAG(( "Driver reports invalid maximum key size %lu for " "%s algorithm", pMechanism.ulMaxKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); maxKeySize = 0; } if( !keysizeInBytes( cryptAlgo ) ) { minKeySize = bitsToBytes( minKeySize ); maxKeySize = bitsToBytes( maxKeySize ); } if( minKeySize > capabilityInfo->minKeySize ) capabilityInfo->minKeySize = minKeySize; if( capabilityInfo->keySize < capabilityInfo->minKeySize ) capabilityInfo->keySize = capabilityInfo->minKeySize; capabilityInfo->maxKeySize = min( maxKeySize, capabilityInfo->maxKeySize ); if( capabilityInfo->maxKeySize < capabilityInfo->minKeySize ) { /* Serious braindamage in the driver, we'll just have to make a sensible guess */ DEBUG_DIAG(( "Driver reports maximum key size %d < minimum key " "size %d for %s algorithm", capabilityInfo->maxKeySize, capabilityInfo->minKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); if( isPKC ) { capabilityInfo->maxKeySize = \ max( capabilityInfo->minKeySize, bitsToBytes( 2048 ) ); } else capabilityInfo->maxKeySize = 16; } if( capabilityInfo->keySize > capabilityInfo->maxKeySize ) capabilityInfo->keySize = capabilityInfo->maxKeySize; capabilityInfo->endFunction = genericEndFunction; } /* Set up the device-specific handlers */ capabilityInfo->selfTestFunction = selfTestFunction; capabilityInfo->getInfoFunction = getDefaultInfo; if( !isPKC ) capabilityInfo->initParamsFunction = initGenericParams; capabilityInfo->endFunction = mechanismInfoPtr->endFunction; capabilityInfo->initKeyFunction = mechanismInfoPtr->initKeyFunction; if( pMechanism.flags & keyGenFlag ) capabilityInfo->generateKeyFunction = \ mechanismInfoPtr->generateKeyFunction; if( pMechanism.flags & CKF_SIGN ) { /* cryptlib treats hashing as an encrypt/decrypt operation while PKCS #11 treats it as a sign/verify operation, so we have to juggle the function pointers based on the underlying algorithm type */ if( isPKC ) capabilityInfo->signFunction = mechanismInfoPtr->signFunction; else capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; } if( pMechanism.flags & CKF_VERIFY ) { /* See comment above */ if( isPKC ) capabilityInfo->sigCheckFunction = mechanismInfoPtr->sigCheckFunction; else capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; } if( pMechanism.flags & CKF_ENCRYPT ) { /* Not all devices implement all modes, so we have to be careful to set up the pointer for the exact mode that's supported */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: capabilityInfo->encryptCBCFunction = mechanismInfoPtr->encryptFunction; break; case CRYPT_MODE_CFB: capabilityInfo->encryptCFBFunction = mechanismInfoPtr->encryptFunction; break; case CRYPT_MODE_GCM: capabilityInfo->encryptGCMFunction = mechanismInfoPtr->encryptFunction; break; default: /* ECB or a PKC */ capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; break; } } if( pMechanism.flags & CKF_DECRYPT ) { /* Not all devices implement all modes, so we have to be careful to set up the pointer for the exact mode that's supported */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: capabilityInfo->decryptCBCFunction = mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_CFB: capabilityInfo->decryptCFBFunction = mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_GCM: capabilityInfo->decryptGCMFunction = mechanismInfoPtr->decryptFunction; break; default: /* ECB or a PKC */ capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; break; } } if( cryptAlgo == CRYPT_ALGO_DH && pMechanism.flags & CKF_DERIVE ) { /* DH is a special-case that doesn't really have an encrypt function and where "decryption" is actually a derivation */ capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; } /* Keygen capabilities are generally present as separate mechanisms, sometimes CKF_GENERATE/CKF_GENERATE_KEY_PAIR is set for the main mechanism and sometimes it's set for the separate one so if it isn't present in the main one we check the alternative one */ if( !( pMechanism.flags & keyGenFlag ) && \ ( mechanismInfoPtr->keygenMechanism != CKM_NONE ) ) { status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->keygenMechanism, &pMechanism ); if( status == CKR_OK && ( pMechanism.flags & keyGenFlag ) && \ ( !hardwareOnly || ( pMechanism.flags & CKF_HW ) ) ) { /* Some tinkertoy tokens don't implement key generation in hardware but instead do it on the host PC (!!!) and load the key into the token afterwards, so we have to perform another check here to make sure that they're doing things right */ capabilityInfo->generateKeyFunction = \ mechanismInfoPtr->generateKeyFunction; } } /* Record mechanism-specific parameters if required */ if( isConvAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) ) { capabilityInfo->paramKeyType = mechanismInfoPtr->keyType; capabilityInfo->paramKeyGen = mechanismInfoPtr->keygenMechanism; capabilityInfo->paramDefaultMech = mechanismInfoPtr->defaultMechanism; } /* Some drivers report bizarre combinations of capabilities like (for RSA) sign, verify, and decrypt but not encrypt, which will fail later sanity checks. If we run into one of these we force the capabilities to be consistent by disabling any for which only partial capabilities are supported */ if( isPkcAlgo( cryptAlgo ) ) { if( capabilityInfo->decryptFunction != NULL && \ capabilityInfo->encryptFunction == NULL ) { DEBUG_DIAG(( "Driver reports decryption but not encryption " "capability for %s algorithm, disabling " "encryption", capabilityInfo->algoName )); capabilityInfo->decryptFunction = NULL; } if( capabilityInfo->signFunction != NULL && \ capabilityInfo->sigCheckFunction == NULL ) { DEBUG_DIAG(( "Driver reports signature-generation but not " "signature-verification capability for %s " "algorithm, disabling signing", capabilityInfo->algoName )); ////////////////////////////////// // Kludge to allow it to be used ////////////////////////////////// if( cryptAlgo == CRYPT_ALGO_ECDSA ) capabilityInfo->sigCheckFunction = capabilityInfo->signFunction; else capabilityInfo->signFunction = NULL; } /* If we've now disabled all capabilities, we can't use this algorithm */ if( capabilityInfo->decryptFunction == NULL && \ capabilityInfo->signFunction == NULL ) { DEBUG_DIAG(( "Use of algorithm %s disabled since no consistent " "set of capabilities is available", capabilityInfo->algoName )); clFree( "getCapability", capabilityInfo ); assert( DEBUG_WARN ); return( NULL ); } } /* If it's not a conventional encryption algo, we're done */ if( !isConvAlgo( cryptAlgo ) ) return( ( CAPABILITY_INFO * ) capabilityInfo ); /* PKCS #11 handles encryption modes by defining a separate mechanism for each one. In order to enumerate all the modes available for a particular algorithm we check for each mechanism in turn and set up the appropriate function pointers if it's available */ for( mechanismInfoPtr++, iterationCount = 0; mechanismInfoPtr->cryptAlgo == cryptAlgo && \ iterationCount < maxMechanisms; mechanismInfoPtr++, iterationCount++ ) { /* There's a different form of the existing mechanism available, check whether the driver implements it */ status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->mechanism, &pMechanism ); if( status != CKR_OK ) continue; /* Set up the pointer for the appropriate encryption mode */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptCBCFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptCBCFunction = \ mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_CFB: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptCFBFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptCFBFunction = \ mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_GCM: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptGCMFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptGCMFunction = \ mechanismInfoPtr->decryptFunction; break; default: retIntError_Null(); } } ENSURES_N( iterationCount < maxMechanisms ); return( ( CAPABILITY_INFO * ) capabilityInfo ); }