Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions OSX-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ Now we need to install some dependencies

$ brew install automake
$ brew install pkg-config
$ brew install openssl
$ brew install openssl@3.6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the availability of openssl@3.6 in Homebrew

# Check if the formula exists
brew info openssl@3.6 2>&1 | head -20

Repository: softhsm/SoftHSMv2

Length of output: 104


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant sections around the referenced line numbers
echo "---- OSX-NOTES.md: around line 35-70 ----"
nl -ba OSX-NOTES.md | sed -n '35,75p'

echo "---- OSX-NOTES.md: around line 80-115 ----"
nl -ba OSX-NOTES.md | sed -n '80,115p'

Repository: softhsm/SoftHSMv2

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- OSX-NOTES.md: around line 35-75 ----"
awk 'NR>=35 && NR<=75 { printf "%d:%s\n", NR, $0 }' OSX-NOTES.md

echo "---- OSX-NOTES.md: around line 80-115 ----"
awk 'NR>=80 && NR<=115 { printf "%d:%s\n", NR, $0 }' OSX-NOTES.md

Repository: softhsm/SoftHSMv2

Length of output: 2744


Align --with-openssl path with openssl@3.6

  • brew install openssl@3.6 but ./configure uses --with-openssl=/usr/local/opt/openssl (lines 91-92, 101-102); update to the versioned OpenSSL path (e.g., /usr/local/opt/openssl@3.6, or whatever Homebrew symlink targets) to ensure the build links against the intended OpenSSL 3.6+.
  • “ref issue #22773” needs clearer context (repo/URL) for readers (lines 51-52).
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 46-46: Dollar signs used before commands without showing output

(MD014, commands-show-output)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@OSX-NOTES.md` at line 46, Update the OpenSSL path used in the configure flags
to match the installed Homebrew formula by replacing the hardcoded
"--with-openssl=/usr/local/opt/openssl" with the versioned path for the
installed formula (e.g., "--with-openssl=/usr/local/opt/openssl@3.6" or the
Homebrew symlink target) so the build links against openssl@3.6 that you
installed with "brew install openssl@3.6"; also replace the ambiguous "ref issue
`#22773`" note with a full repository/URL reference (e.g.,
https://github.com/ORG/REPO/issues/22773) so readers can find the issue context.

$ brew install sqlite
$ brew install cppunit
$ brew install libtool

OpenSSL 3.6+ required for AES-CCM ref issue #22773

openssl, sqlite, and libtool are pre-installed on the system. The versions downloaded
by brew are stored in an alternative location under /usr/local

The only brew warning of note is for libtool:

==> Caveats
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Minimum required versions:

- Botan 2.0.0
- OpenSSL 1.0.0
**OpenSSL 3.6+ required for AES-CCM** [ref issue #22773](https://github.com/openssl/openssl/issues/22773)

If you are using Botan, use at least version 2.6.0. This will improve
the performance when doing public key operations.
Expand Down
59 changes: 59 additions & 0 deletions src/lib/SoftHSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ void SoftHSM::prepareSupportedMechanisms(std::map<std::string, CK_MECHANISM_TYPE
t["CKM_AES_CBC_PAD"] = CKM_AES_CBC_PAD;
t["CKM_AES_CTR"] = CKM_AES_CTR;
t["CKM_AES_GCM"] = CKM_AES_GCM;
t["CKM_AES_CCM"] = CKM_AES_CCM;
t["CKM_AES_KEY_WRAP"] = CKM_AES_KEY_WRAP;
#ifdef HAVE_AES_KEY_WRAP_PAD
t["CKM_AES_KEY_WRAP_PAD"] = CKM_AES_KEY_WRAP_PAD;
Expand Down Expand Up @@ -1218,6 +1219,7 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_
case CKM_AES_ECB:
case CKM_AES_CTR:
case CKM_AES_GCM:
case CKM_AES_CCM:
pInfo->ulMinKeySize = 16;
pInfo->ulMaxKeySize = 32;
pInfo->flags |= CKF_ENCRYPT | CKF_DECRYPT;
Expand Down Expand Up @@ -2226,6 +2228,7 @@ static bool isSymMechanism(CK_MECHANISM_PTR pMechanism)
case CKM_AES_CBC_PAD:
case CKM_AES_CTR:
case CKM_AES_GCM:
case CKM_AES_CCM:
return true;
default:
return false;
Expand Down Expand Up @@ -2445,6 +2448,34 @@ CK_RV SoftHSM::SymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
}
tagBytes = tagBytes / 8;
break;
case CKM_AES_CCM:
if (keyType != CKK_AES)
return CKR_KEY_TYPE_INCONSISTENT;
algo = SymAlgo::AES;
mode = SymMode::CCM;
if (pMechanism->pParameter == NULL_PTR ||
pMechanism->ulParameterLen != sizeof(CK_CCM_PARAMS))
{
DEBUG_MSG("CCM mode requires parameters");
return CKR_ARGUMENTS_BAD;
}
if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen < 7 && CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen > 13) {
DEBUG_MSG("Invalid ulNonceLen value, is %#5d should be 7 ≤ ulNonceLen ≤ 13.", CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
return CKR_ARGUMENTS_BAD;
}
iv.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
memcpy(&iv[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->nonce, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
aad.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen > 0)
memcpy(&aad[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->aad, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
tagBytes = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulMACLen;
counterBits = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulDataLen;
if (tagBytes != 16 && tagBytes != 14 && tagBytes != 12 && tagBytes != 10 && tagBytes != 8)
{
DEBUG_MSG("Invalid ulMACLen value, is %#5d should be 16, 14, 12, 10 or 8", tagBytes);
return CKR_ARGUMENTS_BAD;
}
Comment on lines +2471 to +2477

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix CCM parameter validation (CK_CCM_PARAMS) for ulMACLen and ulDataLen.

ulMACLen must allow 4, 6, 8, 10, 12, 14, 16, but the current check rejects 4 and 6 (and the DEBUG_MSG text also omits them). Also add the spec-required bound ulDataLen < 2^(8L) with L = 15 - ulNonceLen before forwarding parameters into encryptInit / decryptInit.

File: src/lib/SoftHSM.cpp (also applies to 3255-3261)

Suggested fix
-			if (tagBytes != 16 &amp;&amp; tagBytes != 14 &amp;&amp; tagBytes != 12 &amp;&amp; tagBytes != 10 &amp;&amp; tagBytes != 8)
+			if (tagBytes != 16 &amp;&amp; tagBytes != 14 &amp;&amp; tagBytes != 12 &amp;&amp;
+			    tagBytes != 10 &amp;&amp; tagBytes != 8 &amp;&amp; tagBytes != 6 &amp;&amp; tagBytes != 4)
 			{
 				DEBUG_MSG("Invalid ulMACLen value, is %#5d should be 16, 14, 12, 10 or 8", tagBytes);
 				return CKR_ARGUMENTS_BAD;
 			}
+			size_t L = 15 - CK_CCM_PARAMS_PTR(pMechanism-&gt;pParameter)-&gt;ulNonceLen;
+			if (L &lt; sizeof(CK_ULONG) &amp;&amp;
+			    CK_CCM_PARAMS_PTR(pMechanism-&gt;pParameter)-&gt;ulDataLen &gt;= (CK_ULONG(1) &lt;&lt; (8 * L)))
+			{
+				return CKR_MECHANISM_PARAM_INVALID;
+			}

Update the DEBUG_MSG text to include 4 and 6 as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/SoftHSM.cpp` around lines 2471 - 2477, The CCM parameter validation
must accept ulMACLen values 4,6,8,10,12,14,16 and must enforce ulDataLen <
2^(8*L) where L = 15 - ulNonceLen before passing parameters to
encryptInit/decryptInit; update the validation around
CK_CCM_PARAMS_PTR(pMechanism->pParameter) (variables tagBytes and counterBits)
to allow 4 and 6, fix the DEBUG_MSG to list 4 and 6, compute L from
CK_CCM_PARAMS_PTR(...)->ulNonceLen and check counterBits (ulDataLen) is less
than (1ULL << (8 * L)) and return CKR_ARGUMENTS_BAD on violation, and ensure
this same logic is applied at both occurrences (around the blocks handling
encryptInit/decryptInit).

break;
default:
return CKR_MECHANISM_INVALID;
}
Expand Down Expand Up @@ -3201,6 +3232,34 @@ CK_RV SoftHSM::SymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
}
tagBytes = tagBytes / 8;
break;
case CKM_AES_CCM:
if (keyType != CKK_AES)
return CKR_KEY_TYPE_INCONSISTENT;
algo = SymAlgo::AES;
mode = SymMode::CCM;
if (pMechanism->pParameter == NULL_PTR ||
pMechanism->ulParameterLen != sizeof(CK_CCM_PARAMS))
{
DEBUG_MSG("CCM mode requires parameters");
return CKR_ARGUMENTS_BAD;
}
if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen < 7 && CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen > 13) {
DEBUG_MSG("Invalid ulNonceLen value, is %#5d should be 7 ≤ ulNonceLen ≤ 13.", CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
return CKR_ARGUMENTS_BAD;
}
iv.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
memcpy(&iv[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->nonce, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulNonceLen);
aad.resize(CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
if (CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen > 0)
memcpy(&aad[0], CK_CCM_PARAMS_PTR(pMechanism->pParameter)->aad, CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
tagBytes = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulMACLen;
counterBits = CK_CCM_PARAMS_PTR(pMechanism->pParameter)->ulDataLen;
if (tagBytes != 16 && tagBytes != 14 && tagBytes != 12 && tagBytes != 10 && tagBytes != 8)
{
DEBUG_MSG("Invalid ulDataLen value, is %#5d should be 16, 14, 12, 10 or 8", tagBytes);
return CKR_ARGUMENTS_BAD;
}
break;
default:
return CKR_MECHANISM_INVALID;
}
Expand Down
11 changes: 11 additions & 0 deletions src/lib/crypto/BotanAES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ std::string BotanAES::getCipher() const
break;
case SymMode::GCM:
return algo + "/GCM(" + std::to_string(currentTagBytes) + ")";
case SymMode::CCM:
{
int preL = std::to_string(currentCounterBits).length();
int L;
if (preL < 2) {
L = 2;
} else {
L = preL;
}
return algo + "/CCM(" + std::to_string(currentTagBytes) + "," + std::to_string(L) + ")";
}
default:
ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode);

Expand Down
24 changes: 19 additions & 5 deletions src/lib/crypto/BotanSymmetricAlgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,15 @@ BotanSymmetricAlgorithm::~BotanSymmetricAlgorithm()
// Encryption functions
bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode:CBC */, const ByteString& IV /* = ByteString()*/, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */)
{

// Call the superclass initialiser
if (!SymmetricAlgorithm::encryptInit(key, mode, IV, padding, counterBits, aad, tagBytes))
{
return false;
}

// Check the IV
if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize()))
{
ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());

Expand Down Expand Up @@ -188,7 +189,7 @@ bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode
cipher->set_key(botanKey);
cryption = new Botan::Pipe(cipher);
}
else if (mode == SymMode::GCM)
else if (mode == SymMode::GCM || mode == SymMode::CCM)
{
Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::ENCRYPTION);
aead->set_key(botanKey);
Expand Down Expand Up @@ -336,7 +337,7 @@ bool BotanSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode
}

// Check the IV
if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
if ((mode != SymMode::GCM && mode != SymMode::CCM) && (IV.size() > 0) && (IV.size() != getBlockSize()))
{
ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());

Expand Down Expand Up @@ -434,6 +435,19 @@ bool BotanSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode
filter->set_iv(botanIV);
cryption = new Botan::Pipe(filter);
}
else if (mode == SymMode::CCM)
{
Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::DECRYPTION);
aead->set_key(botanKey);
if (aad.size() > 0) {
aead->set_associated_data(aad.const_byte_str(), aad.size());
}

Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
Botan::Keyed_Filter* filter = new Botan::Cipher_Mode_Filter(aead);
filter->set_iv(botanIV);
cryption = new Botan::Pipe(filter);
}
else
{
Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
Expand Down Expand Up @@ -468,7 +482,7 @@ bool BotanSymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, Byt
}

// AEAD ciphers should not return decrypted data until final is called
if (currentCipherMode == SymMode::GCM)
if (currentCipherMode == SymMode::GCM || currentCipherMode == SymMode::CCM)
{
data.resize(0);
return true;
Expand Down Expand Up @@ -541,7 +555,7 @@ bool BotanSymmetricAlgorithm::decryptFinal(ByteString& data)
return false;
}

if (mode == SymMode::GCM)
if (mode == SymMode::GCM || mode == SymMode::CCM)
{
// Write data
try
Expand Down
12 changes: 12 additions & 0 deletions src/lib/crypto/OSSLAES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ const EVP_CIPHER* OSSLAES::getCipher() const
return EVP_aes_256_gcm();
};
}
else if (currentCipherMode == SymMode::CCM)
{
switch(currentKey->getBitLen())
{
case 128:
return EVP_aes_128_ccm();
case 192:
return EVP_aes_192_ccm();
case 256:
return EVP_aes_256_ccm();
};
}

ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode);

Expand Down
Loading