Skip to content

Commit 96365cc

Browse files
committed
Fixed EDDSA context/pre-hash support
1 parent c26ef0a commit 96365cc

9 files changed

Lines changed: 613 additions & 19 deletions

File tree

‎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+
INFO_MSG("SignInit EDDSA mechanism, parameterLen=%lu, pParameter=%p", (unsigned long)pMechanism->ulParameterLen, pMechanism->pParameter);
4593+
if (pMechanism->pParameter == NULL_PTR)
4594+
{
4595+
INFO_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+
INFO_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+
INFO_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+
INFO_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+
INFO_MSG("EDDSA parameters not specified, using default values");
5733+
}
5734+
else
5735+
{
5736+
INFO_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+
INFO_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: 74 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,48 @@ 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 (pk->getOrderLength() == 32)
124+
{
125+
emsa = "Ed25519ph";
126+
}
127+
else
128+
{
129+
emsa = "Ed448ph";
130+
}
131+
}
132+
100133
try
101134
{
102135
BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
@@ -162,7 +195,7 @@ bool BotanEDDSA::signFinal(ByteString& /*signature*/)
162195
// Verification functions
163196
bool BotanEDDSA::verify(PublicKey* publicKey, const ByteString& originalData,
164197
const ByteString& signature, const AsymMech::Type mechanism,
165-
const MechanismParam* /* mechanismParam */)
198+
const MechanismParam* mechanismParam)
166199
{
167200
std::string emsa;
168201

@@ -195,6 +228,38 @@ bool BotanEDDSA::verify(PublicKey* publicKey, const ByteString& originalData,
195228
return false;
196229
}
197230

231+
// Extract context parameters if provided
232+
bool preHash = false;
233+
if (mechanismParam != NULL && mechanismParam->isOfType(EDDSAMechanismParam::type))
234+
{
235+
EDDSAMechanismParam* eddsaParam = (EDDSAMechanismParam*) mechanismParam;
236+
preHash = eddsaParam->flag;
237+
if (!preHash && eddsaParam->contextData.size() > 0)
238+
{
239+
ERROR_MSG("Context data is not supported in Botan EDDSA implementation");
240+
return false;
241+
}
242+
}
243+
244+
if (preHash)
245+
{
246+
unsigned long len = pk->getOrderLength();
247+
if (len == 0)
248+
{
249+
ERROR_MSG("EDDSA: Could not get the order length");
250+
return false;
251+
}
252+
253+
if (pk->getOrderLength() == 32)
254+
{
255+
emsa = "Ed25519ph";
256+
}
257+
else
258+
{
259+
emsa = "Ed448ph";
260+
}
261+
}
262+
198263
try
199264
{
200265
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)