diff --git a/src/lib/P11Attributes.cpp b/src/lib/P11Attributes.cpp index fc9ab004..1c3640a8 100644 --- a/src/lib/P11Attributes.cpp +++ b/src/lib/P11Attributes.cpp @@ -410,9 +410,10 @@ CK_RV P11Attribute::update(Token* token, bool isPrivate, CK_VOID_PTR pValue, CK_ // combinations of other attributes) for a particular library and token. Whether or not a // 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) { - ERROR_MSG("An object is with CKA_MODIFIABLE set to false is not modifiable"); + // Attributes cannot be changed if CKA_MODIFIABLE is false. + // Note: During CREATE/GENERATE/UNWRAP the object is in creation; allow setting attributes in the same op. + if (!isModifiable() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE && op != OBJECT_OP_UNWRAP) { + ERROR_MSG("An object with CKA_MODIFIABLE set to false is not modifiable"); return CKR_ATTRIBUTE_READ_ONLY; } diff --git a/src/lib/SoftHSM.cpp b/src/lib/SoftHSM.cpp index 62c695b9..28dcfc90 100644 --- a/src/lib/SoftHSM.cpp +++ b/src/lib/SoftHSM.cpp @@ -1138,13 +1138,12 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ /* FALLTHROUGH */ #endif case CKM_DES3_CBC: - pInfo->flags |= CKF_WRAP; /* FALLTHROUGH */ case CKM_DES3_ECB: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; - pInfo->flags |= CKF_ENCRYPT | CKF_DECRYPT; + pInfo->flags |= CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; break; case CKM_DES3_CMAC: // Key size is not in use @@ -6269,6 +6268,7 @@ CK_RV SoftHSM::WrapKeySym // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymWrap::Type mode = SymWrap::Unknown; + SymMode::Type sym_mode = SymMode::Unknown; size_t bb = 8; size_t blocksize = 0; auto wrappedlen = keydata.size(); @@ -6291,22 +6291,44 @@ CK_RV SoftHSM::WrapKeySym #endif case CKM_AES_CBC: algo = SymAlgo::AES; + sym_mode = SymMode::CBC; + blocksize = 16; + if ((wrappedlen % 16) != 0) + return CKR_KEY_SIZE_RANGE; break; case CKM_AES_CBC_PAD: blocksize = 16; wrappedlen = RFC5652Pad(keydata, blocksize); algo = SymAlgo::AES; - break; - - case CKM_DES3_CBC: - algo = SymAlgo::DES3; + sym_mode = SymMode::CBC; break; case CKM_DES3_CBC_PAD: - blocksize = 8; + blocksize = 8; wrappedlen = RFC5652Pad(keydata, blocksize); + algo = SymAlgo::DES3; + sym_mode = SymMode::CBC; + bb = 7; + break; + + case CKM_DES3_CBC: + if ((wrappedlen % 8) != 0) + return CKR_KEY_SIZE_RANGE; + blocksize = 8; algo = SymAlgo::DES3; + sym_mode = SymMode::CBC; + bb = 7; + break; + + case CKM_DES3_ECB: + // ECB mode has no IV; keep blocksize=0 so iv remains empty + if ((wrappedlen % 8) != 0) + return CKR_KEY_SIZE_RANGE; + blocksize = 0; + algo = SymAlgo::DES3; + sym_mode = SymMode::ECB; + bb = 7; break; default: @@ -6333,13 +6355,18 @@ CK_RV SoftHSM::WrapKeySym switch(pMechanism->mechanism) { case CKM_AES_CBC: - case CKM_AES_CBC_PAD: + case CKM_AES_CBC_PAD: case CKM_DES3_CBC: - case CKM_DES3_CBC_PAD: - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); - - if (!cipher->encryptInit(wrappingkey, SymMode::CBC, iv, false)) + case CKM_DES3_CBC_PAD: + case CKM_DES3_ECB: + if (blocksize > 0) { + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize); + } else { + iv.wipe(); + } + + if (!cipher->encryptInit(wrappingkey, sym_mode, iv, false)) { cipher->recycleKey(wrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); @@ -6612,6 +6639,15 @@ CK_RV SoftHSM::C_WrapKey pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; break; + case CKM_DES3_ECB: + if (pMechanism->ulParameterLen != 0) + return CKR_ARGUMENTS_BAD; // no IV for ECB; allow NULL or non-NULL pointer when length==0 + break; + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + break; default: return CKR_MECHANISM_INVALID; } @@ -6652,9 +6688,11 @@ CK_RV SoftHSM::C_WrapKey return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; - if (pMechanism->mechanism == CKM_DES3_CBC && (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + if ((pMechanism->mechanism == CKM_DES3_CBC || pMechanism->mechanism == CKM_DES3_CBC_PAD || pMechanism->mechanism == CKM_DES3_ECB) && + ((wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3))) { + return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + } // Check if the wrapping key can be used for wrapping if (wrapKey->getBooleanValue(CKA_WRAP, false) == false) @@ -6865,6 +6903,7 @@ CK_RV SoftHSM::UnwrapKeySym // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymWrap::Type mode = SymWrap::Unknown; + SymMode::Type sym_mode = SymMode::Unknown; size_t bb = 8; size_t blocksize = 0; @@ -6881,16 +6920,28 @@ CK_RV SoftHSM::UnwrapKeySym mode = SymWrap::AES_KEYWRAP_PAD; break; #endif - case CKM_AES_CBC_PAD: + case CKM_AES_CBC_PAD: algo = SymAlgo::AES; + sym_mode = SymMode::CBC; blocksize = 16; break; - - case CKM_DES3_CBC_PAD: + + case CKM_DES3_CBC_PAD: + case CKM_DES3_CBC: algo = SymAlgo::DES3; + sym_mode = SymMode::CBC; blocksize = 8; - break; - + bb = 7; + break; + + case CKM_DES3_ECB: + algo = SymAlgo::DES3; + sym_mode = SymMode::ECB; + // ECB mode has no IV; keep blocksize=0 so iv remains empty + blocksize = 0; + bb = 7; + break; + default: return CKR_MECHANISM_INVALID; } @@ -6916,39 +6967,43 @@ CK_RV SoftHSM::UnwrapKeySym switch(pMechanism->mechanism) { - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC_PAD: - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); - - if (!cipher->decryptInit(unwrappingkey, SymMode::CBC, iv, false)) - { - cipher->recycleKey(unwrappingkey); - CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); - return CKR_MECHANISM_INVALID; - } - if (!cipher->decryptUpdate(wrapped, keydata)) - { - cipher->recycleKey(unwrappingkey); - CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); - return CKR_GENERAL_ERROR; - } - // Finalize encryption - if (!cipher->decryptFinal(decryptedFinal)) - { - cipher->recycleKey(unwrappingkey); - CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); - return CKR_GENERAL_ERROR; - } - keydata += decryptedFinal; + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_ECB: + if (blocksize > 0) { + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize); + } else { + iv.wipe(); + } - if(!RFC5652Unpad(keydata,blocksize)) - { - cipher->recycleKey(unwrappingkey); - CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); - return CKR_GENERAL_ERROR; // TODO should be another error - } - break; + if (!cipher->decryptInit(unwrappingkey, sym_mode, iv, false)) { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_MECHANISM_INVALID; + } + if (!cipher->decryptUpdate(wrapped, keydata)) { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_GENERAL_ERROR; + } + // Finalize decryption + if (!cipher->decryptFinal(decryptedFinal)) { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_WRAPPED_KEY_INVALID; + } + keydata += decryptedFinal; + + if (pMechanism->mechanism == CKM_AES_CBC_PAD || pMechanism->mechanism == CKM_DES3_CBC_PAD) { + if (!RFC5652Unpad(keydata, blocksize)) { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_WRAPPED_KEY_INVALID; + } + } + break; default: // Unwrap the key @@ -7227,20 +7282,34 @@ CK_RV SoftHSM::C_UnwrapKey return rv; break; - case CKM_AES_CBC_PAD: - // TODO check block length - if (pMechanism->pParameter == NULL_PTR || - pMechanism->ulParameterLen != 16) + case CKM_AES_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; + if (ulWrappedKeyLen == 0 || (ulWrappedKeyLen % 16) != 0) + return CKR_WRAPPED_KEY_LEN_RANGE; break; - case CKM_DES3_CBC_PAD: - // TODO check block length - if (pMechanism->pParameter == NULL_PTR || - pMechanism->ulParameterLen != 8) + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + if (ulWrappedKeyLen == 0 || (ulWrappedKeyLen % 8) != 0) + return CKR_WRAPPED_KEY_LEN_RANGE; + break; + + case CKM_DES3_CBC: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 8) return CKR_ARGUMENTS_BAD; + if ((ulWrappedKeyLen % 8) != 0) + return CKR_WRAPPED_KEY_LEN_RANGE; break; - + + case CKM_DES3_ECB: + if (pMechanism->ulParameterLen != 0) + return CKR_ARGUMENTS_BAD; // ECB takes no IV; allow NULL or non-NULL pointer when length==0 + if ((ulWrappedKeyLen % 8) != 0) + return CKR_WRAPPED_KEY_LEN_RANGE; + break; + default: return CKR_MECHANISM_INVALID; } @@ -7279,12 +7348,14 @@ CK_RV SoftHSM::C_UnwrapKey if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP || pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; - if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; - if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; - + if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; + if ((pMechanism->mechanism == CKM_DES3_CBC_PAD || pMechanism->mechanism == CKM_DES3_CBC || pMechanism->mechanism == CKM_DES3_ECB) && + (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; + // Check if the unwrapping key can be used for unwrapping if (unwrapKey->getBooleanValue(CKA_UNWRAP, false) == false) return CKR_KEY_FUNCTION_NOT_PERMITTED; @@ -7334,7 +7405,11 @@ CK_RV SoftHSM::C_UnwrapKey }; CK_ULONG secretAttribsCount = 4; - // Add the additional + // Capture optional CKA_VALUE_LEN from the template (for compatibility) + CK_ULONG requestedValueLen = 0; + bool haveRequestedValueLen = false; + + // Add the additional attributes, skipping read-only for unwrap and capturing CKA_VALUE_LEN if (ulCount > (maxAttribs - secretAttribsCount)) return CKR_TEMPLATE_INCONSISTENT; for (CK_ULONG i = 0; i < ulCount; ++i) @@ -7346,6 +7421,14 @@ CK_RV SoftHSM::C_UnwrapKey case CKA_PRIVATE: case CKA_KEY_TYPE: continue; + case CKA_VALUE_LEN: + // Accept a caller-provided length for compatibility, but do not set it here; we will verify after unwrap + if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) { + return CKR_TEMPLATE_INCONSISTENT; + } + requestedValueLen = *(CK_ULONG *) pTemplate[i].pValue; + haveRequestedValueLen = true; + continue; default: secretAttribs[secretAttribsCount++] = pTemplate[i]; } @@ -7420,6 +7503,12 @@ CK_RV SoftHSM::C_UnwrapKey return rv; } + // If provided, enforce CKA_VALUE_LEN only for secret keys + if (objClass == CKO_SECRET_KEY && haveRequestedValueLen && keydata.size() != requestedValueLen) + { + return CKR_TEMPLATE_INCONSISTENT; + } + // Create the secret object using C_CreateObject rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, hKey, OBJECT_OP_UNWRAP); @@ -12044,7 +12133,7 @@ CK_RV SoftHSM::deriveSymmetric // attributes set to CK_TRUE bool bNeverExtractable = baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false) && otherKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false); - bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE, bNeverExtractable); + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable); } else if (pMechanism->mechanism == CKM_CONCATENATE_BASE_AND_DATA || pMechanism->mechanism == CKM_CONCATENATE_DATA_AND_BASE) diff --git a/src/lib/crypto/BotanDES.cpp b/src/lib/crypto/BotanDES.cpp index 393cf4dc..0fc31353 100644 --- a/src/lib/crypto/BotanDES.cpp +++ b/src/lib/crypto/BotanDES.cpp @@ -61,12 +61,15 @@ std::string BotanDES::getCipher() const switch (currentKey->getBitLen()) { case 56: - // People shouldn't really be using 56-bit DES keys, generate a warning - DEBUG_MSG("CAUTION: use of 56-bit DES keys is not recommended!"); + case 64: + // Single-DES (effective 56-bit) is weak; warn irrespective of representation + DEBUG_MSG("CAUTION: use of single-DES keys (effective 56-bit) is not recommended!"); algo = "DES"; break; case 112: + case 128: case 168: + case 192: algo = "TripleDES"; break; default: diff --git a/src/lib/crypto/OSSLDES.cpp b/src/lib/crypto/OSSLDES.cpp index 4fb56b5e..053c8785 100644 --- a/src/lib/crypto/OSSLDES.cpp +++ b/src/lib/crypto/OSSLDES.cpp @@ -53,23 +53,29 @@ const EVP_CIPHER* OSSLDES::getCipher() const { if (currentKey == NULL) return NULL; - // Check currentKey bit length; 3DES only supports 56-bit, 112-bit or 168-bit keys + // Accept both effective (without parity) and parity-included lengths: + // DES: 56 or 64 bits (64 includes parity) + // 2-key 3DES: 112 or 128 bits (128 includes parity) + // 3-key 3DES: 168 or 192 bits (192 includes parity) if ( #ifndef WITH_FIPS (currentKey->getBitLen() != 56) && + (currentKey->getBitLen() != 64) && #endif (currentKey->getBitLen() != 112) && - (currentKey->getBitLen() != 168)) + (currentKey->getBitLen() != 128) && + (currentKey->getBitLen() != 168) && + (currentKey->getBitLen() != 192)) { ERROR_MSG("Invalid DES currentKey length (%d bits)", currentKey->getBitLen()); return NULL; } - // People shouldn't really be using 56-bit DES keys, generate a warning - if (currentKey->getBitLen() == 56) + // Single-DES (effective 56-bit) is weak; warn irrespective of representation + if (currentKey->getBitLen() == 56 || currentKey->getBitLen() == 64) { - DEBUG_MSG("CAUTION: use of 56-bit DES keys is not recommended!"); + DEBUG_MSG("CAUTION: use of single-DES keys (effective 56-bit) is not recommended!"); } // Determine the cipher mode @@ -78,10 +84,13 @@ const EVP_CIPHER* OSSLDES::getCipher() const switch(currentKey->getBitLen()) { case 56: + case 64: return EVP_des_cbc(); case 112: + case 128: return EVP_des_ede_cbc(); case 168: + case 192: return EVP_des_ede3_cbc(); }; } @@ -90,10 +99,13 @@ const EVP_CIPHER* OSSLDES::getCipher() const switch(currentKey->getBitLen()) { case 56: + case 64: return EVP_des_ecb(); case 112: + case 128: return EVP_des_ede_ecb(); case 168: + case 192: return EVP_des_ede3_ecb(); }; } @@ -102,10 +114,13 @@ const EVP_CIPHER* OSSLDES::getCipher() const switch(currentKey->getBitLen()) { case 56: + case 64: return EVP_des_ofb(); case 112: + case 128: return EVP_des_ede_ofb(); case 168: + case 192: return EVP_des_ede3_ofb(); }; } @@ -114,10 +129,13 @@ const EVP_CIPHER* OSSLDES::getCipher() const switch(currentKey->getBitLen()) { case 56: + case 64: return EVP_des_cfb(); case 112: + case 128: return EVP_des_ede_cfb(); case 168: + case 192: return EVP_des_ede3_cfb(); }; }