1 /*
2  * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*****************************************************************************
28  BotanECDSA.cpp
29 
30  Botan ECDSA asymmetric algorithm implementation
31  *****************************************************************************/
32 
33 #include "config.h"
34 #ifdef WITH_ECC
35 #include "log.h"
36 #include "BotanECDSA.h"
37 #include "BotanRNG.h"
38 #include "CryptoFactory.h"
39 #include "BotanCryptoFactory.h"
40 #include "ECParameters.h"
41 #include "BotanECDSAKeyPair.h"
42 #include "BotanUtil.h"
43 #include <algorithm>
44 #include <botan/ec_group.h>
45 #include <botan/ecdsa.h>
46 #include <botan/version.h>
47 #include <iostream>
48 
49 // Constructor
BotanECDSA()50 BotanECDSA::BotanECDSA()
51 {
52 	signer = NULL;
53 	verifier = NULL;
54 }
55 
56 // Destructor
~BotanECDSA()57 BotanECDSA::~BotanECDSA()
58 {
59 	delete signer;
60 	delete verifier;
61 }
62 
63 // Signing functions
sign(PrivateKey * privateKey,const ByteString & dataToSign,ByteString & signature,const AsymMech::Type mechanism,const void *,const size_t)64 bool BotanECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
65 		      ByteString& signature, const AsymMech::Type mechanism,
66 		      const void* /* param = NULL */, const size_t /* paramLen = 0 */)
67 {
68 	std::string emsa;
69 
70 	if (mechanism == AsymMech::ECDSA)
71 	{
72 		emsa = "Raw";
73 	}
74         else
75         {
76 		ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
77 		return false;
78         }
79 
80 	// Check if the private key is the right type
81 	if (!privateKey->isOfType(BotanECDSAPrivateKey::type))
82 	{
83 		ERROR_MSG("Invalid key type supplied");
84 
85 		return false;
86 	}
87 
88         BotanECDSAPrivateKey* pk = (BotanECDSAPrivateKey*) privateKey;
89         Botan::ECDSA_PrivateKey* botanKey = pk->getBotanKey();
90 
91         if (botanKey == NULL)
92         {
93 		ERROR_MSG("Could not get the Botan private key");
94 
95 		return false;
96 	}
97 
98 	try
99 	{
100 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
101 		signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
102 	}
103 	catch (...)
104 	{
105 		ERROR_MSG("Could not create the signer token");
106 
107 		return false;
108 	}
109 
110 	// Perform the signature operation
111 	std::vector<uint8_t> signResult;
112 	try
113 	{
114 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
115 		signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
116 	}
117 	catch (...)
118 	{
119 		ERROR_MSG("Could not sign the data");
120 
121 		delete signer;
122 		signer = NULL;
123 
124 		return false;
125 	}
126 
127 	// Return the result
128 	signature.resize(signResult.size());
129 	memcpy(&signature[0], signResult.data(), signResult.size());
130 
131 	delete signer;
132 	signer = NULL;
133 
134 	return true;
135 }
136 
137 // Signing functions
signInit(PrivateKey *,const AsymMech::Type,const void *,const size_t)138 bool BotanECDSA::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
139 			  const void* /* param = NULL */, const size_t /* paramLen = 0 */)
140 {
141 	ERROR_MSG("ECDSA does not support multi part signing");
142 
143 	return false;
144 }
145 
signUpdate(const ByteString &)146 bool BotanECDSA::signUpdate(const ByteString& /*dataToSign*/)
147 {
148 	ERROR_MSG("ECDSA does not support multi part signing");
149 
150 	return false;
151 }
152 
signFinal(ByteString &)153 bool BotanECDSA::signFinal(ByteString& /*signature*/)
154 {
155 	ERROR_MSG("ECDSA does not support multi part signing");
156 
157 	return false;
158 }
159 
160 // Verification functions
verify(PublicKey * publicKey,const ByteString & originalData,const ByteString & signature,const AsymMech::Type mechanism,const void *,const size_t)161 bool BotanECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
162 			const ByteString& signature, const AsymMech::Type mechanism,
163 			const void* /* param = NULL */, const size_t /* paramLen = 0 */)
164 {
165 	std::string emsa;
166 
167 	if (mechanism == AsymMech::ECDSA)
168 	{
169 		emsa = "Raw";
170 	}
171         else
172         {
173 		ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
174 
175 		return false;
176 	}
177 
178 	// Check if the public key is the right type
179 	if (!publicKey->isOfType(BotanECDSAPublicKey::type))
180 	{
181 		ERROR_MSG("Invalid key type supplied");
182 
183 		return false;
184 	}
185 
186 	BotanECDSAPublicKey* pk = (BotanECDSAPublicKey*) publicKey;
187 	Botan::ECDSA_PublicKey* botanKey = pk->getBotanKey();
188 
189 	if (botanKey == NULL)
190 	{
191 		ERROR_MSG("Could not get the Botan public key");
192 
193 		return false;
194 	}
195 
196 	try
197 	{
198 		verifier = new Botan::PK_Verifier(*botanKey, emsa);
199 	}
200 	catch (...)
201 	{
202 		ERROR_MSG("Could not create the verifier token");
203 
204 		return false;
205 	}
206 
207 	// Perform the verify operation
208 	bool verResult;
209 	try
210 	{
211 		verResult = verifier->verify_message(originalData.const_byte_str(),
212 							originalData.size(),
213 							signature.const_byte_str(),
214 							signature.size());
215 	}
216 	catch (...)
217 	{
218 		ERROR_MSG("Could not check the signature");
219 
220 		delete verifier;
221 		verifier = NULL;
222 
223 		return false;
224 	}
225 
226 	delete verifier;
227 	verifier = NULL;
228 
229 	return verResult;
230 }
231 
232 // Verification functions
verifyInit(PublicKey *,const AsymMech::Type,const void *,const size_t)233 bool BotanECDSA::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
234 			    const void* /* param = NULL */, const size_t /* paramLen = 0 */)
235 {
236 	ERROR_MSG("ECDSA does not support multi part verifying");
237 
238 	return false;
239 }
240 
verifyUpdate(const ByteString &)241 bool BotanECDSA::verifyUpdate(const ByteString& /*originalData*/)
242 {
243 	ERROR_MSG("ECDSA does not support multi part verifying");
244 
245 	return false;
246 }
247 
verifyFinal(const ByteString &)248 bool BotanECDSA::verifyFinal(const ByteString& /*signature*/)
249 {
250 	ERROR_MSG("ECDSA does not support multi part verifying");
251 
252 	return false;
253 }
254 
255 // Encryption functions
encrypt(PublicKey *,const ByteString &,ByteString &,const AsymMech::Type)256 bool BotanECDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
257 			 ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
258 {
259 	ERROR_MSG("ECDSA does not support encryption");
260 
261 	return false;
262 }
263 
264 // Decryption functions
decrypt(PrivateKey *,const ByteString &,ByteString &,const AsymMech::Type)265 bool BotanECDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
266 			 ByteString& /*data*/, const AsymMech::Type /*padding*/)
267 {
268 	ERROR_MSG("ECDSA does not support decryption");
269 
270 	return false;
271 }
272 
273 // Key factory
generateKeyPair(AsymmetricKeyPair ** ppKeyPair,AsymmetricParameters * parameters,RNG *)274 bool BotanECDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
275 {
276 	// Check parameters
277 	if ((ppKeyPair == NULL) ||
278 	    (parameters == NULL))
279 	{
280 		return false;
281 	}
282 
283 	if (!parameters->areOfType(ECParameters::type))
284 	{
285 		ERROR_MSG("Invalid parameters supplied for ECDSA key generation");
286 
287 		return false;
288 	}
289 
290 	ECParameters* params = (ECParameters*) parameters;
291 
292 	// Generate the key-pair
293 	Botan::ECDSA_PrivateKey* eckp = NULL;
294 	try
295 	{
296 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
297 		eckp = new Botan::ECDSA_PrivateKey(*rng->getRNG(), BotanUtil::byteString2ECGroup(params->getEC()));
298 	}
299 	catch (...)
300 	{
301 		ERROR_MSG("ECDSA key generation failed");
302 
303 		return false;
304 	}
305 
306 	// Create an asymmetric key-pair object to return
307 	BotanECDSAKeyPair* kp = new BotanECDSAKeyPair();
308 
309 	((BotanECDSAPublicKey*) kp->getPublicKey())->setFromBotan(eckp);
310 	((BotanECDSAPrivateKey*) kp->getPrivateKey())->setFromBotan(eckp);
311 
312 	*ppKeyPair = kp;
313 
314 	// Release the key
315 	delete eckp;
316 
317 	return true;
318 }
319 
getMinKeySize()320 unsigned long BotanECDSA::getMinKeySize()
321 {
322 	// Smallest EC group is secp112r1
323 	return 112;
324 }
325 
getMaxKeySize()326 unsigned long BotanECDSA::getMaxKeySize()
327 {
328 	// Biggest EC group is secp521r1
329 	return 521;
330 }
331 
reconstructKeyPair(AsymmetricKeyPair ** ppKeyPair,ByteString & serialisedData)332 bool BotanECDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
333 {
334 	// Check input
335 	if ((ppKeyPair == NULL) ||
336 	    (serialisedData.size() == 0))
337 	{
338 		return false;
339 	}
340 
341 	ByteString dPub = ByteString::chainDeserialise(serialisedData);
342 	ByteString dPriv = ByteString::chainDeserialise(serialisedData);
343 
344 	BotanECDSAKeyPair* kp = new BotanECDSAKeyPair();
345 
346 	bool rv = true;
347 
348 	if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
349 	{
350 		rv = false;
351 	}
352 
353 	if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
354 	{
355 		rv = false;
356 	}
357 
358 	if (!rv)
359 	{
360 		delete kp;
361 
362 		return false;
363 	}
364 
365 	*ppKeyPair = kp;
366 
367 	return true;
368 }
369 
reconstructPublicKey(PublicKey ** ppPublicKey,ByteString & serialisedData)370 bool BotanECDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
371 {
372 	// Check input
373 	if ((ppPublicKey == NULL) ||
374 	    (serialisedData.size() == 0))
375 	{
376 		return false;
377 	}
378 
379 	BotanECDSAPublicKey* pub = new BotanECDSAPublicKey();
380 
381 	if (!pub->deserialise(serialisedData))
382 	{
383 		delete pub;
384 
385 		return false;
386 	}
387 
388 	*ppPublicKey = pub;
389 
390 	return true;
391 }
392 
reconstructPrivateKey(PrivateKey ** ppPrivateKey,ByteString & serialisedData)393 bool BotanECDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
394 {
395 	// Check input
396 	if ((ppPrivateKey == NULL) ||
397 	    (serialisedData.size() == 0))
398 	{
399 		return false;
400 	}
401 
402 	BotanECDSAPrivateKey* priv = new BotanECDSAPrivateKey();
403 
404 	if (!priv->deserialise(serialisedData))
405 	{
406 		delete priv;
407 
408 		return false;
409 	}
410 
411 	*ppPrivateKey = priv;
412 
413 	return true;
414 }
415 
newPublicKey()416 PublicKey* BotanECDSA::newPublicKey()
417 {
418 	return (PublicKey*) new BotanECDSAPublicKey();
419 }
420 
newPrivateKey()421 PrivateKey* BotanECDSA::newPrivateKey()
422 {
423 	return (PrivateKey*) new BotanECDSAPrivateKey();
424 }
425 
newParameters()426 AsymmetricParameters* BotanECDSA::newParameters()
427 {
428 	return (AsymmetricParameters*) new ECParameters();
429 }
430 
reconstructParameters(AsymmetricParameters ** ppParams,ByteString & serialisedData)431 bool BotanECDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
432 {
433 	// Check input parameters
434 	if ((ppParams == NULL) || (serialisedData.size() == 0))
435 	{
436 		return false;
437 	}
438 
439 	ECParameters* params = new ECParameters();
440 
441 	if (!params->deserialise(serialisedData))
442 	{
443 		delete params;
444 
445 		return false;
446 	}
447 
448 	*ppParams = params;
449 
450 	return true;
451 }
452 #endif
453