diff --git a/src/lib/P11Attributes.cpp b/src/lib/P11Attributes.cpp index fc9ab004..937f043f 100644 --- a/src/lib/P11Attributes.cpp +++ b/src/lib/P11Attributes.cpp @@ -411,13 +411,13 @@ CK_RV P11Attribute::update(Token* token, bool isPrivate, CK_VOID_PTR pValue, CK_ // given non-Cryptoki attribute is read-only is obviously outside the scope of Cryptoki. // Attributes cannot be changed if CKA_MODIFIABLE is set to false - if (!isModifiable() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE) { + if (!isModifiable() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE && op != OBJECT_OP_UNWRAP) { ERROR_MSG("An object is with CKA_MODIFIABLE set to false is not modifiable"); return CKR_ATTRIBUTE_READ_ONLY; } // Attributes cannot be modified if CKA_TRUSTED is true on a certificate object. - if (isTrusted() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE) { + if (isTrusted() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE && op != OBJECT_OP_UNWRAP) { if (osobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_CERTIFICATE) { ERROR_MSG("A trusted certificate cannot be modified"); diff --git a/src/lib/test/SymmetricAlgorithmTests.cpp b/src/lib/test/SymmetricAlgorithmTests.cpp index 3aeb1e7c..4e957173 100644 --- a/src/lib/test/SymmetricAlgorithmTests.cpp +++ b/src/lib/test/SymmetricAlgorithmTests.cpp @@ -1186,6 +1186,119 @@ void SymmetricAlgorithmTests::aesWrapUnwrapGeneric(CK_MECHANISM_TYPE mechanismTy CPPUNIT_ASSERT(rv == CKR_OK); } +void SymmetricAlgorithmTests::aesWrapUnwrapNonModifiableGeneric(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) +{ + CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 }; + CK_BBOOL bFalse = CK_FALSE; + CK_BBOOL bTrue = CK_TRUE; + CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY; + CK_KEY_TYPE genKeyType = CKK_GENERIC_SECRET; + CK_BYTE keyPtr[128]; + CK_ULONG keyLen = + mechanismType == CKM_AES_KEY_WRAP_PAD ? 125UL : 128UL; + + CK_RV rv; + CK_BYTE ivPtr[16]; + if( mechanismType == CKM_AES_CBC_PAD ) { + rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, ivPtr, sizeof ivPtr) ); + CPPUNIT_ASSERT(rv == CKR_OK); + mechanism.pParameter = ivPtr; + mechanism.ulParameterLen = sizeof ivPtr; + } + + CK_ATTRIBUTE attribs[] = { + { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }, + { CKA_CLASS, &secretClass, sizeof(secretClass) }, + { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) }, + { CKA_TOKEN, &bFalse, sizeof(bFalse) }, + { CKA_PRIVATE, &bTrue, sizeof(bTrue) }, + { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, // Wrapping is allowed even on sensitive objects + { CKA_VALUE, keyPtr, keyLen } + }; + CK_OBJECT_HANDLE hSecret; + + rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, keyPtr, keyLen) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + hSecret = CK_INVALID_HANDLE; + rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hSecret) ); + CPPUNIT_ASSERT(rv == CKR_OK); + CPPUNIT_ASSERT(hSecret != CK_INVALID_HANDLE); + + CK_BYTE_PTR wrappedPtr = NULL_PTR; + CK_ULONG wrappedLen = 0UL; + CK_ULONG zero = 0UL; + CK_ULONG rndKeyLen = keyLen; + if (mechanismType == CKM_AES_KEY_WRAP_PAD) + rndKeyLen = (keyLen + 7) & ~7; + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) ); + CPPUNIT_ASSERT(rv == CKR_KEY_UNEXTRACTABLE); + rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hSecret) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + attribs[0].pValue = &bTrue; + + hSecret = CK_INVALID_HANDLE; + rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hSecret) ); + CPPUNIT_ASSERT(rv == CKR_OK); + CPPUNIT_ASSERT(hSecret != CK_INVALID_HANDLE); + + // Estimate wrapped length + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + auto wrapOverhead = [mechanismType]() { + return (mechanismType == CKM_AES_KEY_WRAP || mechanismType == CKM_AES_KEY_WRAP_PAD) ? 8 : 16; + }; + CPPUNIT_ASSERT(wrappedLen == rndKeyLen + wrapOverhead() ); + + wrappedPtr = (CK_BYTE_PTR) malloc(wrappedLen); + CPPUNIT_ASSERT(wrappedPtr != NULL_PTR); + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) ); + CPPUNIT_ASSERT(rv == CKR_OK); + CPPUNIT_ASSERT(wrappedLen == rndKeyLen + wrapOverhead() ); + + // This should always fail because wrapped data have to be longer than 0 bytes + zero = 0; + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &zero) ); + CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL); + + CK_ATTRIBUTE nattribs[] = { + { CKA_CLASS, &secretClass, sizeof(secretClass) }, + { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) }, + { CKA_TOKEN, &bFalse, sizeof(bFalse) }, + { CKA_PRIVATE, &bTrue, sizeof(bTrue) }, + { CKA_ENCRYPT, &bFalse, sizeof(bFalse) }, + { CKA_DECRYPT, &bTrue, sizeof(bTrue) }, + { CKA_MODIFIABLE, &bFalse, sizeof(bFalse) }, + { CKA_SIGN, &bFalse,sizeof(bFalse) }, + { CKA_VERIFY, &bTrue, sizeof(bTrue) } + }; + CK_OBJECT_HANDLE hNew; + + hNew = CK_INVALID_HANDLE; + rv = CRYPTOKI_F_PTR( C_UnwrapKey(hSession, &mechanism, hKey, wrappedPtr, wrappedLen, nattribs, sizeof(nattribs)/sizeof(CK_ATTRIBUTE), &hNew) ); + CPPUNIT_ASSERT(rv == CKR_OK); + CPPUNIT_ASSERT(hNew != CK_INVALID_HANDLE); + + CK_ATTRIBUTE modifiableAttribs[] = { + { CKA_MODIFIABLE, &bFalse, sizeof(bFalse) } + }; + + rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hNew, modifiableAttribs, sizeof(modifiableAttribs)/sizeof(CK_ATTRIBUTE)) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + CPPUNIT_ASSERT(modifiableAttribs[0].ulValueLen == sizeof(bFalse)); + CPPUNIT_ASSERT(*(CK_BBOOL*)modifiableAttribs[0].pValue == bFalse); + + free(wrappedPtr); + wrappedPtr = NULL_PTR; + rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hSecret) ); + CPPUNIT_ASSERT(rv == CKR_OK); + rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hNew) ); + CPPUNIT_ASSERT(rv == CKR_OK); +} + inline void SymmetricAlgorithmTests::aesWrapUnwrapRsa(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { wrapUnwrapRsa(mechanismType, hSession, hKey); @@ -1643,6 +1756,8 @@ void SymmetricAlgorithmTests::testAesWrapUnwrap() aesWrapUnwrapGeneric(CKM_AES_KEY_WRAP, hSession, hKey); aesWrapUnwrapGeneric(CKM_AES_CBC_PAD, hSession, hKey); + aesWrapUnwrapNonModifiableGeneric(CKM_AES_KEY_WRAP, hSession, hKey); + aesWrapUnwrapNonModifiableGeneric(CKM_AES_CBC_PAD, hSession, hKey); aesWrapUnwrapRsa(CKM_AES_KEY_WRAP, hSession, hKey); aesWrapUnwrapRsa(CKM_AES_CBC_PAD, hSession, hKey); diff --git a/src/lib/test/SymmetricAlgorithmTests.h b/src/lib/test/SymmetricAlgorithmTests.h index 094c1b07..7d60fb57 100644 --- a/src/lib/test/SymmetricAlgorithmTests.h +++ b/src/lib/test/SymmetricAlgorithmTests.h @@ -88,6 +88,7 @@ class SymmetricAlgorithmTests : public TestsBase size_t messageSize, bool isSizeOK=true); void aesWrapUnwrapGeneric(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); + void aesWrapUnwrapNonModifiableGeneric(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); void aesWrapUnwrapRsa(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); void desWrapUnwrapRsa(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); CK_RV generateRsaPrivateKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);