Skip to content

Commit 25b94d4

Browse files
authored
Merge pull request #683 from MatthiasValvekens/feature/ecdsa-with-hashing
Support for ECDSA with hashing
2 parents 4f296fa + 7a33bae commit 25b94d4

File tree

5 files changed

+441
-29
lines changed

5 files changed

+441
-29
lines changed

src/lib/SoftHSM.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,11 @@ void SoftHSM::prepareSupportedMechanisms(std::map<std::string, CK_MECHANISM_TYPE
805805
#ifdef WITH_ECC
806806
t["CKM_EC_KEY_PAIR_GEN"] = CKM_EC_KEY_PAIR_GEN;
807807
t["CKM_ECDSA"] = CKM_ECDSA;
808+
t["CKM_ECDSA_SHA1"] = CKM_ECDSA_SHA1;
809+
t["CKM_ECDSA_SHA224"] = CKM_ECDSA_SHA224;
810+
t["CKM_ECDSA_SHA256"] = CKM_ECDSA_SHA256;
811+
t["CKM_ECDSA_SHA384"] = CKM_ECDSA_SHA384;
812+
t["CKM_ECDSA_SHA512"] = CKM_ECDSA_SHA512;
808813
#endif
809814
#if defined(WITH_ECC) || defined(WITH_EDDSA)
810815
t["CKM_ECDH1_DERIVE"] = CKM_ECDH1_DERIVE;
@@ -1249,6 +1254,11 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_
12491254
pInfo->flags = CKF_GENERATE_KEY_PAIR | CKF_EC_COMMOM;
12501255
break;
12511256
case CKM_ECDSA:
1257+
case CKM_ECDSA_SHA1:
1258+
case CKM_ECDSA_SHA224:
1259+
case CKM_ECDSA_SHA256:
1260+
case CKM_ECDSA_SHA384:
1261+
case CKM_ECDSA_SHA512:
12521262
pInfo->ulMinKeySize = ecdsaMinSize;
12531263
pInfo->ulMaxKeySize = ecdsaMaxSize;
12541264
pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_EC_COMMOM;
@@ -4367,6 +4377,31 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan
43674377
bAllowMultiPartOp = false;
43684378
isECDSA = true;
43694379
break;
4380+
case CKM_ECDSA_SHA1:
4381+
mechanism = AsymMech::ECDSA_SHA1;
4382+
bAllowMultiPartOp = false;
4383+
isECDSA = true;
4384+
break;
4385+
case CKM_ECDSA_SHA224:
4386+
mechanism = AsymMech::ECDSA_SHA224;
4387+
bAllowMultiPartOp = false;
4388+
isECDSA = true;
4389+
break;
4390+
case CKM_ECDSA_SHA256:
4391+
mechanism = AsymMech::ECDSA_SHA256;
4392+
bAllowMultiPartOp = false;
4393+
isECDSA = true;
4394+
break;
4395+
case CKM_ECDSA_SHA384:
4396+
mechanism = AsymMech::ECDSA_SHA384;
4397+
bAllowMultiPartOp = false;
4398+
isECDSA = true;
4399+
break;
4400+
case CKM_ECDSA_SHA512:
4401+
mechanism = AsymMech::ECDSA_SHA512;
4402+
bAllowMultiPartOp = false;
4403+
isECDSA = true;
4404+
break;
43704405
#endif
43714406
#ifdef WITH_GOST
43724407
case CKM_GOSTR3410:
@@ -5343,6 +5378,31 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
53435378
bAllowMultiPartOp = false;
53445379
isECDSA = true;
53455380
break;
5381+
case CKM_ECDSA_SHA1:
5382+
mechanism = AsymMech::ECDSA_SHA1;
5383+
bAllowMultiPartOp = false;
5384+
isECDSA = true;
5385+
break;
5386+
case CKM_ECDSA_SHA224:
5387+
mechanism = AsymMech::ECDSA_SHA224;
5388+
bAllowMultiPartOp = false;
5389+
isECDSA = true;
5390+
break;
5391+
case CKM_ECDSA_SHA256:
5392+
mechanism = AsymMech::ECDSA_SHA256;
5393+
bAllowMultiPartOp = false;
5394+
isECDSA = true;
5395+
break;
5396+
case CKM_ECDSA_SHA384:
5397+
mechanism = AsymMech::ECDSA_SHA384;
5398+
bAllowMultiPartOp = false;
5399+
isECDSA = true;
5400+
break;
5401+
case CKM_ECDSA_SHA512:
5402+
mechanism = AsymMech::ECDSA_SHA512;
5403+
bAllowMultiPartOp = false;
5404+
isECDSA = true;
5405+
break;
53465406
#endif
53475407
#ifdef WITH_GOST
53485408
case CKM_GOSTR3410:

src/lib/crypto/AsymmetricAlgorithm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ struct AsymMech
8585
DSA_SHA384,
8686
DSA_SHA512,
8787
ECDSA,
88+
ECDSA_SHA1,
89+
ECDSA_SHA224,
90+
ECDSA_SHA256,
91+
ECDSA_SHA384,
92+
ECDSA_SHA512,
8893
GOST,
8994
GOST_GOST,
9095
EDDSA

src/lib/crypto/BotanECDSA.cpp

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,33 @@ bool BotanECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
6565
ByteString& signature, const AsymMech::Type mechanism,
6666
const void* /* param = NULL */, const size_t /* paramLen = 0 */)
6767
{
68-
std::string emsa;
68+
std::string emsa = "Raw";
6969

70-
if (mechanism == AsymMech::ECDSA)
70+
HashAlgo::Type hash = HashAlgo::Unknown;
71+
if (mechanism != AsymMech::ECDSA)
7172
{
72-
emsa = "Raw";
73+
switch (mechanism)
74+
{
75+
case AsymMech::ECDSA_SHA1:
76+
hash = HashAlgo::SHA1;
77+
break;
78+
case AsymMech::ECDSA_SHA224:
79+
hash = HashAlgo::SHA224;
80+
break;
81+
case AsymMech::ECDSA_SHA256:
82+
hash = HashAlgo::SHA256;
83+
break;
84+
case AsymMech::ECDSA_SHA384:
85+
hash = HashAlgo::SHA384;
86+
break;
87+
case AsymMech::ECDSA_SHA512:
88+
hash = HashAlgo::SHA512;
89+
break;
90+
default:
91+
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
92+
return false;
93+
}
7394
}
74-
else
75-
{
76-
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
77-
return false;
78-
}
7995

8096
// Check if the private key is the right type
8197
if (!privateKey->isOfType(BotanECDSAPrivateKey::type))
@@ -107,12 +123,30 @@ bool BotanECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
107123
return false;
108124
}
109125

126+
// Pre-hash the data if necessary
127+
ByteString prepDataToSign;
128+
129+
if (hash == HashAlgo::Unknown) {
130+
prepDataToSign = dataToSign;
131+
} else {
132+
HashAlgorithm* digest = BotanCryptoFactory::i()->getHashAlgorithm(hash);
133+
134+
if (!digest->hashInit()
135+
|| !digest->hashUpdate(dataToSign)
136+
|| !digest->hashFinal(prepDataToSign))
137+
{
138+
delete digest;
139+
return false;
140+
}
141+
delete digest;
142+
}
143+
110144
// Perform the signature operation
111145
std::vector<uint8_t> signResult;
112146
try
113147
{
114148
BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
115-
signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
149+
signResult = signer->sign_message(prepDataToSign.const_byte_str(), prepDataToSign.size(), *rng->getRNG());
116150
}
117151
catch (...)
118152
{
@@ -162,18 +196,33 @@ bool BotanECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
162196
const ByteString& signature, const AsymMech::Type mechanism,
163197
const void* /* param = NULL */, const size_t /* paramLen = 0 */)
164198
{
165-
std::string emsa;
199+
std::string emsa = "Raw";
166200

167-
if (mechanism == AsymMech::ECDSA)
168-
{
169-
emsa = "Raw";
170-
}
171-
else
201+
HashAlgo::Type hash = HashAlgo::Unknown;
202+
if (mechanism != AsymMech::ECDSA)
203+
{
204+
switch (mechanism)
172205
{
173-
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
174-
175-
return false;
176-
}
206+
case AsymMech::ECDSA_SHA1:
207+
hash = HashAlgo::SHA1;
208+
break;
209+
case AsymMech::ECDSA_SHA224:
210+
hash = HashAlgo::SHA224;
211+
break;
212+
case AsymMech::ECDSA_SHA256:
213+
hash = HashAlgo::SHA256;
214+
break;
215+
case AsymMech::ECDSA_SHA384:
216+
hash = HashAlgo::SHA384;
217+
break;
218+
case AsymMech::ECDSA_SHA512:
219+
hash = HashAlgo::SHA512;
220+
break;
221+
default:
222+
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
223+
return false;
224+
}
225+
}
177226

178227
// Check if the public key is the right type
179228
if (!publicKey->isOfType(BotanECDSAPublicKey::type))
@@ -204,12 +253,30 @@ bool BotanECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
204253
return false;
205254
}
206255

256+
// Pre-hash the data if necessary
257+
ByteString prepDataToSign;
258+
259+
if (hash == HashAlgo::Unknown) {
260+
prepDataToSign = originalData;
261+
} else {
262+
HashAlgorithm* digest = BotanCryptoFactory::i()->getHashAlgorithm(hash);
263+
264+
if (!digest->hashInit()
265+
|| !digest->hashUpdate(originalData)
266+
|| !digest->hashFinal(prepDataToSign))
267+
{
268+
delete digest;
269+
return false;
270+
}
271+
delete digest;
272+
}
273+
207274
// Perform the verify operation
208275
bool verResult;
209276
try
210277
{
211-
verResult = verifier->verify_message(originalData.const_byte_str(),
212-
originalData.size(),
278+
verResult = verifier->verify_message(prepDataToSign.const_byte_str(),
279+
prepDataToSign.size(),
213280
signature.const_byte_str(),
214281
signature.size());
215282
}

src/lib/crypto/OSSLECDSA.cpp

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,32 @@ bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
5353
ByteString& signature, const AsymMech::Type mechanism,
5454
const void* /* param = NULL */, const size_t /* paramLen = 0 */)
5555
{
56+
57+
HashAlgo::Type hash = HashAlgo::Unknown;
58+
5659
if (mechanism != AsymMech::ECDSA)
5760
{
58-
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
59-
return false;
61+
switch (mechanism)
62+
{
63+
case AsymMech::ECDSA_SHA1:
64+
hash = HashAlgo::SHA1;
65+
break;
66+
case AsymMech::ECDSA_SHA224:
67+
hash = HashAlgo::SHA224;
68+
break;
69+
case AsymMech::ECDSA_SHA256:
70+
hash = HashAlgo::SHA256;
71+
break;
72+
case AsymMech::ECDSA_SHA384:
73+
hash = HashAlgo::SHA384;
74+
break;
75+
case AsymMech::ECDSA_SHA512:
76+
hash = HashAlgo::SHA512;
77+
break;
78+
default:
79+
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
80+
return false;
81+
}
6082
}
6183

6284
// Check if the private key is the right type
@@ -93,6 +115,24 @@ bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
93115
EC_KEY_set_method(eckey, EC_KEY_OpenSSL());
94116
#endif
95117

118+
// Pre-hash the data if necessary
119+
ByteString prepDataToSign;
120+
if (hash == HashAlgo::Unknown) {
121+
prepDataToSign = dataToSign;
122+
} else {
123+
HashAlgorithm* digest = CryptoFactory::i()->getHashAlgorithm(hash);
124+
125+
if (!digest->hashInit()
126+
|| !digest->hashUpdate(dataToSign)
127+
|| !digest->hashFinal(prepDataToSign))
128+
{
129+
delete digest;
130+
return false;
131+
}
132+
delete digest;
133+
}
134+
135+
96136
// Perform the signature operation
97137
size_t len = pk->getOrderLength();
98138
if (len == 0)
@@ -102,7 +142,7 @@ bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
102142
}
103143
signature.resize(2 * len);
104144
memset(&signature[0], 0, 2 * len);
105-
ECDSA_SIG *sig = ECDSA_do_sign(dataToSign.const_byte_str(), dataToSign.size(), eckey);
145+
ECDSA_SIG *sig = ECDSA_do_sign(prepDataToSign.const_byte_str(), prepDataToSign.size(), eckey);
106146
if (sig == NULL)
107147
{
108148
ERROR_MSG("ECDSA sign failed (0x%08X)", ERR_get_error());
@@ -145,11 +185,33 @@ bool OSSLECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
145185
const ByteString& signature, const AsymMech::Type mechanism,
146186
const void* /* param = NULL */, const size_t /* paramLen = 0 */)
147187
{
188+
189+
HashAlgo::Type hash = HashAlgo::Unknown;
190+
148191
if (mechanism != AsymMech::ECDSA)
149-
{
150-
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
151-
return false;
152-
}
192+
{
193+
switch (mechanism)
194+
{
195+
case AsymMech::ECDSA_SHA1:
196+
hash = HashAlgo::SHA1;
197+
break;
198+
case AsymMech::ECDSA_SHA224:
199+
hash = HashAlgo::SHA224;
200+
break;
201+
case AsymMech::ECDSA_SHA256:
202+
hash = HashAlgo::SHA256;
203+
break;
204+
case AsymMech::ECDSA_SHA384:
205+
hash = HashAlgo::SHA384;
206+
break;
207+
case AsymMech::ECDSA_SHA512:
208+
hash = HashAlgo::SHA512;
209+
break;
210+
default:
211+
ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
212+
return false;
213+
}
214+
}
153215

154216
// Check if the private key is the right type
155217
if (!publicKey->isOfType(OSSLECPublicKey::type))
@@ -213,7 +275,25 @@ bool OSSLECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
213275
ECDSA_SIG_free(sig);
214276
return false;
215277
}
216-
int ret = ECDSA_do_verify(originalData.const_byte_str(), originalData.size(), sig, eckey);
278+
279+
// Pre-hash the data if necessary
280+
ByteString prepDataToSign;
281+
if (hash == HashAlgo::Unknown) {
282+
prepDataToSign = originalData;
283+
} else {
284+
HashAlgorithm* digest = CryptoFactory::i()->getHashAlgorithm(hash);
285+
286+
if (!digest->hashInit()
287+
|| !digest->hashUpdate(originalData)
288+
|| !digest->hashFinal(prepDataToSign))
289+
{
290+
delete digest;
291+
return false;
292+
}
293+
delete digest;
294+
}
295+
296+
int ret = ECDSA_do_verify(prepDataToSign.const_byte_str(), prepDataToSign.size(), sig, eckey);
217297
if (ret != 1)
218298
{
219299
if (ret < 0)

0 commit comments

Comments
 (0)