Skip to content

Commit c4e8cca

Browse files
committed
Fixed EDDSA context/pre-hash support
1 parent f12916e commit c4e8cca

11 files changed

Lines changed: 622 additions & 22 deletions

‎src/bin/util/softhsm2-util-botan.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ eddsa_key_material_t* crypto_malloc_eddsa
837837
return NULL;
838838
}
839839

840-
eddsa_key_material_t* keyMat = (eddsa_key_material_t*)malloc(sizeof(eddsa_key_material_t));
840+
eddsa_key_material_t* keyMat = (eddsa_key_material_t*)calloc(1, sizeof(eddsa_key_material_t));
841841
if (keyMat == NULL)
842842
{
843843
return NULL;
@@ -848,13 +848,13 @@ eddsa_key_material_t* crypto_malloc_eddsa
848848
if (ed25519) oid = Botan::OIDS::lookup("Ed25519");
849849
if (oid.empty())
850850
{
851+
crypto_free_eddsa(keyMat);
851852
return NULL;
852853
}
853854

854855
Botan::secure_vector<Botan::byte> derOID;
855856
derOID = Botan::DER_Encoder().encode(oid).get_contents();
856857

857-
memset(keyMat, 0, sizeof(*keyMat));
858858
keyMat->sizeOID = derOID.size();
859859
keyMat->derOID = (CK_VOID_PTR)malloc(keyMat->sizeOID);
860860

‎src/lib/SoftHSM.cpp‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
#include "ECParameters.h"
5959
#include "EDPublicKey.h"
6060
#include "EDPrivateKey.h"
61+
#ifdef WITH_EDDSA
62+
#include "EDDSAMechanismParam.h"
63+
#endif
6164
#include "DHParameters.h"
6265
#include "DHPublicKey.h"
6366
#include "DHPrivateKey.h"
@@ -4320,6 +4323,7 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan
43204323
#endif
43214324
#ifdef WITH_EDDSA
43224325
bool isEDDSA = false;
4326+
EDDSAMechanismParam eddsaParam;
43234327
#endif
43244328
#ifdef WITH_ML_DSA
43254329
bool isMLDSA = false;
@@ -4585,6 +4589,46 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan
45854589
mechanism = AsymMech::EDDSA;
45864590
bAllowMultiPartOp = false;
45874591
isEDDSA = true;
4592+
DEBUG_MSG("SignInit EDDSA mechanism, parameterLen=%lu, pParameter=%p", (unsigned long)pMechanism->ulParameterLen, pMechanism->pParameter);
4593+
if (pMechanism->pParameter == NULL_PTR)
4594+
{
4595+
DEBUG_MSG("EDDSA mechanism parameters not specified, using default values");
4596+
if (pMechanism->ulParameterLen != 0)
4597+
{
4598+
ERROR_MSG("Invalid parameters");
4599+
return CKR_ARGUMENTS_BAD;
4600+
}
4601+
// Default EdDSA parameters
4602+
eddsaParam.flag = false;
4603+
}
4604+
else
4605+
{
4606+
DEBUG_MSG("EDDSA mechanism parameters specified, parameterLen=%lu", (unsigned long)pMechanism->ulParameterLen);
4607+
if (pMechanism->ulParameterLen != sizeof(CK_EDDSA_PARAMS))
4608+
{
4609+
ERROR_MSG("Invalid parameters");
4610+
return CKR_ARGUMENTS_BAD;
4611+
}
4612+
CK_EDDSA_PARAMS* ckEddsaParams = (CK_EDDSA_PARAMS*) pMechanism->pParameter;
4613+
if (ckEddsaParams->ulContextDataLen > 255)
4614+
{
4615+
ERROR_MSG("Invalid parameters");
4616+
return CKR_ARGUMENTS_BAD;
4617+
}
4618+
DEBUG_MSG("SignInit EDDSA flag=%s, contextDataLen=%lu", ckEddsaParams->phFlag != 0x00 ? "true" : "false", (unsigned long)ckEddsaParams->ulContextDataLen);
4619+
eddsaParam.flag = (ckEddsaParams->phFlag != 0x00);
4620+
if (ckEddsaParams->ulContextDataLen > 0)
4621+
{
4622+
if (ckEddsaParams->pContextData == NULL_PTR)
4623+
{
4624+
ERROR_MSG("Invalid parameters");
4625+
return CKR_ARGUMENTS_BAD;
4626+
}
4627+
eddsaParam.contextData = ByteString(ckEddsaParams->pContextData, ckEddsaParams->ulContextDataLen);
4628+
DEBUG_MSG("Sign EdDSA flag=%s, contextDataLen=%lu", eddsaParam.flag ? "true" : "false", (unsigned long)eddsaParam.contextData.size());
4629+
}
4630+
mechanismParam = &eddsaParam;
4631+
}
45884632
break;
45894633
#endif
45904634
#ifdef WITH_ML_DSA
@@ -5410,6 +5454,7 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
54105454
#endif
54115455
#ifdef WITH_EDDSA
54125456
bool isEDDSA = false;
5457+
EDDSAMechanismParam eddsaParam;
54135458
#endif
54145459
#ifdef WITH_ML_DSA
54155460
bool isMLDSA = false;
@@ -5674,6 +5719,45 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
56745719
mechanism = AsymMech::EDDSA;
56755720
bAllowMultiPartOp = false;
56765721
isEDDSA = true;
5722+
DEBUG_MSG("Found EDDSA mechanism, checking parameters");
5723+
if (pMechanism->pParameter == NULL_PTR)
5724+
{
5725+
if (pMechanism->ulParameterLen != 0)
5726+
{
5727+
ERROR_MSG("Invalid parameters");
5728+
return CKR_ARGUMENTS_BAD;
5729+
}
5730+
// Default EdDSA parameters
5731+
eddsaParam.flag = false;
5732+
DEBUG_MSG("EDDSA parameters not specified, using default values");
5733+
}
5734+
else
5735+
{
5736+
DEBUG_MSG("EDDSA parameters specified, checking values");
5737+
if (pMechanism->ulParameterLen != sizeof(CK_EDDSA_PARAMS))
5738+
{
5739+
ERROR_MSG("Invalid parameters");
5740+
return CKR_ARGUMENTS_BAD;
5741+
}
5742+
CK_EDDSA_PARAMS* ckEddsaParams = (CK_EDDSA_PARAMS*) pMechanism->pParameter;
5743+
if (ckEddsaParams->ulContextDataLen > 255)
5744+
{
5745+
ERROR_MSG("Invalid parameters");
5746+
return CKR_ARGUMENTS_BAD;
5747+
}
5748+
eddsaParam.flag = (ckEddsaParams->phFlag != 0x00);
5749+
if (ckEddsaParams->ulContextDataLen > 0)
5750+
{
5751+
if (ckEddsaParams->pContextData == NULL_PTR)
5752+
{
5753+
ERROR_MSG("Invalid parameters");
5754+
return CKR_ARGUMENTS_BAD;
5755+
}
5756+
eddsaParam.contextData = ByteString(ckEddsaParams->pContextData, ckEddsaParams->ulContextDataLen);
5757+
DEBUG_MSG("Verify EdDSA flag=%s, contextDataLen=%lu", eddsaParam.flag ? "true" : "false", (unsigned long)eddsaParam.contextData.size());
5758+
}
5759+
mechanismParam = &eddsaParam;
5760+
}
56775761
break;
56785762
#endif
56795763
#ifdef WITH_ML_DSA

‎src/lib/crypto/BotanEDDSA.cpp‎

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "CryptoFactory.h"
3939
#include "BotanCryptoFactory.h"
4040
#include "ECParameters.h"
41+
#include "EDDSAMechanismParam.h"
4142
#include "BotanEDKeyPair.h"
4243
#include "BotanUtil.h"
4344
#include <algorithm>
@@ -65,19 +66,19 @@ BotanEDDSA::~BotanEDDSA()
6566
// Signing functions
6667
bool BotanEDDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
6768
ByteString& signature, const AsymMech::Type mechanism,
68-
const MechanismParam* /* mechanismParam */)
69+
const MechanismParam* mechanismParam)
6970
{
7071
std::string emsa;
7172

7273
if (mechanism == AsymMech::EDDSA)
7374
{
7475
emsa = "Pure";
7576
}
76-
else
77-
{
77+
else
78+
{
7879
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
7980
return false;
80-
}
81+
}
8182

8283
// Check if the private key is the right type
8384
if (!privateKey->isOfType(BotanEDPrivateKey::type))
@@ -87,16 +88,54 @@ bool BotanEDDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
8788
return false;
8889
}
8990

90-
BotanEDPrivateKey* pk = (BotanEDPrivateKey*) privateKey;
91-
Botan::Ed25519_PrivateKey* botanKey = dynamic_cast<Botan::Ed25519_PrivateKey*>(pk->getBotanKey());
91+
BotanEDPrivateKey* pk = (BotanEDPrivateKey*) privateKey;
92+
Botan::Ed25519_PrivateKey* botanKey = dynamic_cast<Botan::Ed25519_PrivateKey*>(pk->getBotanKey());
9293

93-
if (botanKey == NULL)
94-
{
94+
if (botanKey == NULL)
95+
{
9596
ERROR_MSG("Could not get the Botan private key");
9697

9798
return false;
9899
}
99100

101+
// Extract context parameters if provided
102+
bool preHash = false;
103+
if (mechanismParam != NULL && mechanismParam->isOfType(EDDSAMechanismParam::type))
104+
{
105+
EDDSAMechanismParam* eddsaParam = (EDDSAMechanismParam*) mechanismParam;
106+
preHash = eddsaParam->flag;
107+
if (!preHash && eddsaParam->contextData.size() > 0)
108+
{
109+
ERROR_MSG("Context data is not supported in Botan EDDSA implementation");
110+
return false;
111+
}
112+
}
113+
114+
if (preHash)
115+
{
116+
unsigned long len = pk->getOrderLength();
117+
if (len == 0)
118+
{
119+
ERROR_MSG("EDDSA: Could not get the order length");
120+
return false;
121+
}
122+
123+
if (len == 32)
124+
{
125+
emsa = "Ed25519ph";
126+
}
127+
else if (len == 57)
128+
{
129+
ERROR_MSG("EDDSA: Ed448 is not supported in Botan EDDSA implementation");
130+
return false;
131+
}
132+
else
133+
{
134+
ERROR_MSG("EDDSA: Invalid order length");
135+
return false;
136+
}
137+
}
138+
100139
try
101140
{
102141
BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
@@ -162,7 +201,7 @@ bool BotanEDDSA::signFinal(ByteString& /*signature*/)
162201
// Verification functions
163202
bool BotanEDDSA::verify(PublicKey* publicKey, const ByteString& originalData,
164203
const ByteString& signature, const AsymMech::Type mechanism,
165-
const MechanismParam* /* mechanismParam */)
204+
const MechanismParam* mechanismParam)
166205
{
167206
std::string emsa;
168207

@@ -195,6 +234,44 @@ bool BotanEDDSA::verify(PublicKey* publicKey, const ByteString& originalData,
195234
return false;
196235
}
197236

237+
// Extract context parameters if provided
238+
bool preHash = false;
239+
if (mechanismParam != NULL && mechanismParam->isOfType(EDDSAMechanismParam::type))
240+
{
241+
EDDSAMechanismParam* eddsaParam = (EDDSAMechanismParam*) mechanismParam;
242+
preHash = eddsaParam->flag;
243+
if (!preHash && eddsaParam->contextData.size() > 0)
244+
{
245+
ERROR_MSG("Context data is not supported in Botan EDDSA implementation");
246+
return false;
247+
}
248+
}
249+
250+
if (preHash)
251+
{
252+
unsigned long len = pk->getOrderLength();
253+
if (len == 0)
254+
{
255+
ERROR_MSG("EDDSA: Could not get the order length");
256+
return false;
257+
}
258+
259+
if (len == 32)
260+
{
261+
emsa = "Ed25519ph";
262+
}
263+
else if (len == 57)
264+
{
265+
ERROR_MSG("EDDSA: Ed448 is not supported in Botan EDDSA implementation");
266+
return false;
267+
}
268+
else
269+
{
270+
ERROR_MSG("EDDSA: Invalid order length");
271+
return false;
272+
}
273+
}
274+
198275
try
199276
{
200277
verifier = new Botan::PK_Verifier(*botanKey, emsa);

‎src/lib/crypto/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ set(SOURCES AESKey.cpp
2626
ECPublicKey.cpp
2727
EDPrivateKey.cpp
2828
EDPublicKey.cpp
29+
EDDSAMechanismParam.cpp
2930
GOSTPrivateKey.cpp
3031
GOSTPublicKey.cpp
3132
HashAlgorithm.cpp
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2026 SoftHSMv2 contributors
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
/*****************************************************************************
7+
EDDSAMechanismParam.cpp
8+
9+
EdDSA mechanism parameters used for signing/verifying operations
10+
*****************************************************************************/
11+
12+
#include "config.h"
13+
#ifdef WITH_EDDSA
14+
#include "ByteString.h"
15+
#include "MechanismParam.h"
16+
#include "EDDSAMechanismParam.h"
17+
18+
EDDSAMechanismParam::EDDSAMechanismParam() {
19+
this->flag = false;
20+
}
21+
22+
EDDSAMechanismParam::EDDSAMechanismParam(bool flag) {
23+
this->flag = flag;
24+
}
25+
26+
EDDSAMechanismParam::EDDSAMechanismParam(bool flag, ByteString contextData) {
27+
this->flag = flag;
28+
this->contextData = contextData;
29+
}
30+
31+
// Set the type
32+
/*static*/ const char* EDDSAMechanismParam::type = "EdDSA Signature param";
33+
34+
EDDSAMechanismParam* EDDSAMechanismParam::clone() const
35+
{
36+
return new EDDSAMechanismParam(static_cast<const EDDSAMechanismParam&>(*this)); // call the copy ctor.
37+
}
38+
39+
// Check if the parameter is of the given type
40+
bool EDDSAMechanismParam::isOfType(const char* inType) const
41+
{
42+
return !strcmp(type, inType);
43+
}
44+
#endif
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2026 SoftHSMv2 contributors
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
/*****************************************************************************
7+
EDDSAMechanismParam.h
8+
9+
EdDSA mechanism parameters used for signing/verifying operations
10+
*****************************************************************************/
11+
12+
#ifndef _SOFTHSM_V2_EDDSAMECHANISMPARAM_H
13+
#define _SOFTHSM_V2_EDDSAMECHANISMPARAM_H
14+
15+
#include "config.h"
16+
#ifdef WITH_EDDSA
17+
#include "ByteString.h"
18+
#include "MechanismParam.h"
19+
20+
class EDDSAMechanismParam : public MechanismParam
21+
{
22+
public:
23+
24+
// EdDSA parameters from ck_eddsa_params
25+
bool flag; // false = no pre-hash (pure), true = with pre-hash (ph)
26+
ByteString contextData;
27+
28+
// The type
29+
static const char* type;
30+
31+
EDDSAMechanismParam();
32+
33+
EDDSAMechanismParam(bool flag);
34+
35+
EDDSAMechanismParam(bool flag, ByteString contextData);
36+
37+
EDDSAMechanismParam* clone() const;
38+
39+
// Check if the mechanism param is of the given type
40+
virtual bool isOfType(const char* inType) const;
41+
};
42+
43+
#endif // WITH_EDDSA
44+
#endif // !_SOFTHSM_V2_EDDSAMECHANISMPARAM_H

‎src/lib/crypto/Makefile.am‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ libsofthsm_crypto_la_SOURCES = AESKey.cpp \
2626
ECPrivateKey.cpp \
2727
EDPublicKey.cpp \
2828
EDPrivateKey.cpp \
29+
EDDSAMechanismParam.cpp \
2930
GOSTPublicKey.cpp \
3031
GOSTPrivateKey.cpp \
3132
HashAlgorithm.cpp \

0 commit comments

Comments
 (0)