1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * XSECCryptoSymmetricKey := Bulk encryption algorithms should all be
24  *							implemented via this interface
25  *
26  * Author(s): Milan Tomic
27  *
28  */
29 
30 #include <xsec/framework/XSECDefs.hpp>
31 #include <xsec/utils/XSECPlatformUtils.hpp>
32 #include <xsec/enc/NSS/NSSCryptoProvider.hpp>
33 #include <xsec/enc/NSS/NSSCryptoSymmetricKey.hpp>
34 #include <xsec/framework/XSECError.hpp>
35 #include <xsec/enc/XSECCryptoException.hpp>
36 
37 #include <xercesc/util/Janitor.hpp>
38 
39 #if defined (XSEC_HAVE_NSS)
40 
41 #include "prerror.h"
42 
43 XERCES_CPP_NAMESPACE_USE
44 
45 // --------------------------------------------------------------------------------
46 //           Constructor
47 // --------------------------------------------------------------------------------
48 
NSSCryptoSymmetricKey(XSECCryptoSymmetricKey::SymmetricKeyType type)49 NSSCryptoSymmetricKey::NSSCryptoSymmetricKey(XSECCryptoSymmetricKey::SymmetricKeyType type) :
50 m_keyType(type),
51 m_keyMode(MODE_NONE),
52 m_initialised(false),
53 mp_k(NULL)
54 {
55 
56 
57 
58 }
59 
60 // --------------------------------------------------------------------------------
61 //           Destructor
62 // --------------------------------------------------------------------------------
63 
~NSSCryptoSymmetricKey()64 NSSCryptoSymmetricKey::~NSSCryptoSymmetricKey() {
65 
66   if (mp_k != 0)
67 	  PK11_FreeSymKey(mp_k);
68 
69 }
70 
71 // --------------------------------------------------------------------------------
72 //           Get key type
73 // --------------------------------------------------------------------------------
74 
getSymmetricKeyType() const75 XSECCryptoSymmetricKey::SymmetricKeyType NSSCryptoSymmetricKey::getSymmetricKeyType() const {
76 
77 	return m_keyType;
78 
79 }
80 
81 // --------------------------------------------------------------------------------
82 //           Get provider name
83 // --------------------------------------------------------------------------------
84 
getProviderName() const85 const XMLCh * NSSCryptoSymmetricKey::getProviderName() const {
86 
87 	return DSIGConstants::s_unicodeStrPROVNSS;
88 
89 }
90 
91 // --------------------------------------------------------------------------------
92 //           Replicate key
93 // --------------------------------------------------------------------------------
94 
clone() const95 XSECCryptoKey * NSSCryptoSymmetricKey::clone() const {
96 
97 	NSSCryptoSymmetricKey * ret;
98 
99 	XSECnew(ret, NSSCryptoSymmetricKey(m_keyType));
100 
101 	if (mp_k != 0) {
102 
103     ret->mp_k = PK11_ReferenceSymKey(mp_k);
104 
105   }
106 
107   ret->m_keyType = m_keyType;
108 
109 	return ret;
110 
111 }
112 
113 // --------------------------------------------------------------------------------
114 //           Store the key value
115 // --------------------------------------------------------------------------------
116 
setKey(const unsigned char * key,unsigned int keyLen)117 void NSSCryptoSymmetricKey::setKey(const unsigned char * key, unsigned int keyLen) {
118 
119   if (mp_k != 0) {
120 		PK11_FreeSymKey(mp_k);
121     mp_k = 0;
122   }
123 
124   CK_MECHANISM_TYPE cipherMech;
125 
126   switch (m_keyType) {
127 
128 	case (XSECCryptoSymmetricKey::KEY_3DES_192) :
129 
130     cipherMech = CKM_DES3_CBC_PAD;
131     break;
132 
133   case (XSECCryptoSymmetricKey::KEY_AES_128) :
134   case (XSECCryptoSymmetricKey::KEY_AES_192) :
135   case (XSECCryptoSymmetricKey::KEY_AES_256) :
136 
137     cipherMech = CKM_AES_CBC_PAD;
138     break;
139 
140   default:
141 
142     throw XSECCryptoException(XSECCryptoException::SymmetricError,
143 			"NSS:SymmetricKey - Unknown key type");
144 
145   }
146 
147   // Turn the raw key into a SECItem
148   SECItem keyItem;
149   keyItem.data = (unsigned char*)key;
150   keyItem.len = keyLen;
151 
152   PK11SlotInfo * slot = PK11_GetBestSlot(cipherMech, NULL);
153 
154   // Turn the SECItem into a key object
155   mp_k = PK11_ImportSymKey(slot,
156                           cipherMech,
157                           PK11_OriginUnwrap,
158                           CKA_ENCRYPT,
159                           &keyItem,
160                           NULL);
161 
162   if (slot)
163 	  PK11_FreeSlot(slot);
164 
165 }
166 
167 // --------------------------------------------------------------------------------
168 //           Decrypt context initialisation
169 // --------------------------------------------------------------------------------
170 
decryptCtxInit(const unsigned char * iv)171 int NSSCryptoSymmetricKey::decryptCtxInit(const unsigned char * iv) {
172 
173 	// Returns amount of IV data used (in bytes)
174 	// Sets m_initialised if the key is OK and the IV is OK.
175 
176 	if (m_initialised)
177 		return 0;
178 
179 	if (mp_k == 0) {
180 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
181 			"NSS:SymmetricKey - Cannot initialise without key");
182 	}
183     else if (m_keyMode == MODE_NONE) {
184 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
185 			"NSS:SymmetricKey - Cannot initialise without mode");
186     }
187 
188 	// Set up the context according to the required cipher type
189 
190 	switch (m_keyType) {
191 
192 	case (XSECCryptoSymmetricKey::KEY_3DES_192) :
193 
194 		// A 3DES key
195 
196 		if (m_keyMode == MODE_CBC) {
197 
198 			if (iv == NULL) {
199 
200 				return 0;	// Cannot initialise without an IV
201 
202 			}
203 
204             SECItem ivItem;
205             ivItem.data = (unsigned char*)iv;
206             ivItem.len = 8;
207             int encryptAlg = (m_doPad == true ? CKM_DES3_CBC_PAD : CKM_DES3_CBC);
208 
209             SECItem * secParam = PK11_ParamFromIV(encryptAlg, &ivItem);
210             mp_ctx = PK11_CreateContextBySymKey(encryptAlg, CKA_DECRYPT, mp_k, secParam);
211 
212             if (secParam)
213                 SECITEM_FreeItem(secParam, PR_TRUE);
214 
215             m_ivSize = 8;
216         }
217         else if (m_keyMode == MODE_ECB) {
218 	        SECItem * secParam = PK11_ParamFromIV(CKM_DES3_ECB, NULL);
219             mp_ctx = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_DECRYPT, mp_k, secParam);
220             if (secParam)
221                 SECITEM_FreeItem(secParam, PR_TRUE);
222             m_ivSize = 0;
223 		}
224         else {
225 		    throw XSECCryptoException(XSECCryptoException::SymmetricError,
226 			    "NSS:SymmetricKey - Unrecognized cipher mode");
227         }
228 
229 		break;
230 
231 	case (XSECCryptoSymmetricKey::KEY_AES_128) :
232     case (XSECCryptoSymmetricKey::KEY_AES_192) :
233     case (XSECCryptoSymmetricKey::KEY_AES_256) :
234 
235 		// An AES key
236 
237 		if (m_keyMode == MODE_CBC) {
238 
239 			if (iv == NULL) {
240 
241 				return 0;	// Cannot initialise without an IV
242 
243 			}
244 
245             SECItem ivItem;
246             ivItem.data = (unsigned char*)iv;
247             ivItem.len = 16;
248 
249             SECItem * secParam = PK11_ParamFromIV(CKM_AES_CBC_PAD, &ivItem);
250             mp_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_DECRYPT, mp_k, secParam);
251 
252             if (secParam)
253                 SECITEM_FreeItem(secParam, PR_TRUE);
254 
255             m_ivSize = 16;
256 
257 		}
258 		else if (m_keyMode == MODE_ECB) {
259 
260 			SECItem * secParam = PK11_ParamFromIV(CKM_AES_ECB, NULL);
261 			mp_ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_DECRYPT, mp_k, secParam);
262             if (secParam)
263                 SECITEM_FreeItem(secParam, PR_TRUE);
264 
265             m_ivSize = 0;
266 
267 		}
268         else {
269 		    throw XSECCryptoException(XSECCryptoException::SymmetricError,
270 			    "NSS:SymmetricKey - Unrecognized cipher mode");
271         }
272 
273 		break;
274 
275 	default :
276 
277 		// Cannot do this without an IV
278 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
279 			"NSS:SymmetricKey - Unknown key type");
280 
281 	}
282 
283 	// Reset some parameters
284 	m_initialised = true;
285 
286 	// Return number of bytes chewed up by IV
287 	return m_ivSize;
288 }
289 
290 // --------------------------------------------------------------------------------
291 //           Decrypt initialisation
292 // --------------------------------------------------------------------------------
293 
decryptInit(bool doPad,SymmetricKeyMode mode,const unsigned char * iv,const unsigned char * tag,unsigned int taglen)294 bool NSSCryptoSymmetricKey::decryptInit(bool doPad,
295 											SymmetricKeyMode mode,
296 											const unsigned char * iv,
297                                             const unsigned char* tag,
298                                             unsigned int taglen) {
299 
300 	m_initialised = false;
301     m_ivSent = iv == NULL;
302 	m_doPad = doPad;
303 	m_keyMode = mode;
304 	decryptCtxInit(iv);
305 	return true;
306 
307 }
308 
309 // --------------------------------------------------------------------------------
310 //           Decrypt
311 // --------------------------------------------------------------------------------
312 
decrypt(const unsigned char * inBuf,unsigned char * plainBuf,unsigned int inLength,unsigned int maxOutLength)313 unsigned int NSSCryptoSymmetricKey::decrypt(const unsigned char * inBuf,
314 								 unsigned char * plainBuf,
315 								 unsigned int inLength,
316 								 unsigned int maxOutLength) {
317 
318 	// NOTE: This won't actually stop NSS blowing the buffer, so the onus is
319 	// on the caller.
320 
321 	unsigned int offset = 0;
322 	if (!m_initialised) {
323 		offset = decryptCtxInit(inBuf);
324 		if (offset > inLength) {
325 			throw XSECCryptoException(XSECCryptoException::SymmetricError,
326 			"NSS:SymmetricKey - Not enough data passed in to get IV");
327 		}
328 	}
329 
330 	int outl = inLength - offset;
331 
332     SECStatus s = PK11_CipherOp(mp_ctx, plainBuf, &outl, maxOutLength, (unsigned char*)inBuf, inLength);
333 
334     if (s != SECSuccess) {
335 
336         throw XSECCryptoException(XSECCryptoException::SymmetricError,
337 	    		"NSS:SymmetricKey - Error during NSS decrypt");
338 
339     }
340 
341     // remove IV
342     if (m_ivSent) {
343         memmove(plainBuf, &plainBuf[m_ivSize], outl);
344         outl -= m_ivSize;
345         m_ivSent = false;
346     }
347 
348 	return outl;
349 
350 }
351 
352 // --------------------------------------------------------------------------------
353 //           Decrypt finalisation
354 // --------------------------------------------------------------------------------
355 
decryptFinish(unsigned char * plainBuf,unsigned int maxOutLength)356 unsigned int NSSCryptoSymmetricKey::decryptFinish(unsigned char * plainBuf,
357 													  unsigned int maxOutLength) {
358 
359 	unsigned int outl = 0;
360 
361     SECStatus s = PK11_DigestFinal(mp_ctx, plainBuf, &outl, maxOutLength);
362 
363     if (s != SECSuccess) {
364 
365 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
366 			"NSS:SymmetricKey - Error during NSS decrypt finalisation");
367 
368     }
369 
370     PK11_DestroyContext(mp_ctx, PR_TRUE);
371     mp_ctx = NULL;
372     m_initialised = false;
373 
374     return outl;
375 }
376 
377 // --------------------------------------------------------------------------------
378 //           Encrypt initialisation
379 // --------------------------------------------------------------------------------
380 
encryptInit(bool doPad,SymmetricKeyMode mode,const unsigned char * iv)381 bool NSSCryptoSymmetricKey::encryptInit(bool doPad,
382 											SymmetricKeyMode mode,
383 											const unsigned char * iv) {
384 
385 	if (m_initialised == true)
386 		return true;
387 
388 	m_doPad = doPad;
389 	m_keyMode = mode;
390 
391 	if (mp_k == 0) {
392 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
393 			"NSS:SymmetricKey - Cannot initialise without key");
394 	}
395     else if (m_keyMode == MODE_NONE) {
396 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
397 			"NSS:SymmetricKey - Cannot initialise without mode");
398     }
399 
400 	// Do some parameter initialisation
401 	m_initialised = true;
402 
403 	// Set up the context according to the required cipher type
404 
405 	const unsigned char * usedIV = NULL;
406 	unsigned char genIV[256];
407 
408 	// Tell the library that the IV still has to be sent
409 
410 	m_ivSent = false;
411 
412 	switch (m_keyType) {
413 
414 	case (XSECCryptoSymmetricKey::KEY_3DES_192) :
415 
416 		// A 3DES key
417 
418 		if (m_keyMode == MODE_CBC) {
419 
420 		    if (iv == NULL) {
421 
422                 SECStatus s = PK11_GenerateRandom(genIV, 8);
423 
424                 if (s != SECSuccess) {
425 
426 					throw XSECCryptoException(XSECCryptoException::SymmetricError,
427 						"NSS:SymmetricKey - Error generating random IV");
428 
429                 }
430 
431 				usedIV = genIV;
432 
433 		    }
434 		    else
435 				usedIV = iv;
436 
437             SECItem ivItem;
438             ivItem.data = (unsigned char*)usedIV;
439             ivItem.len = 8;
440 	        int encryptAlg = (m_doPad == true ? CKM_DES3_CBC_PAD : CKM_DES3_CBC);
441 
442             SECItem * secParam = PK11_ParamFromIV(encryptAlg, &ivItem);
443             mp_ctx = PK11_CreateContextBySymKey(encryptAlg, CKA_ENCRYPT, mp_k, secParam);
444 
445             if (secParam)
446                 SECITEM_FreeItem(secParam, PR_TRUE);
447 
448             m_ivSize = 8;
449 	    }
450 		else if (m_keyMode == MODE_ECB) {
451             mp_ctx = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, mp_k, NULL);
452 
453             m_ivSize = 0;
454 		}
455         else {
456 		    throw XSECCryptoException(XSECCryptoException::SymmetricError,
457 			        "NSS:SymmetricKey - Unsupported DES3 cipher mode");
458         }
459 
460 		break;
461 
462 	case (XSECCryptoSymmetricKey::KEY_AES_128) :
463     case (XSECCryptoSymmetricKey::KEY_AES_192) :
464     case (XSECCryptoSymmetricKey::KEY_AES_256) :
465 
466 		// An AES key
467 
468 		if (m_keyMode == MODE_CBC) {
469 
470 			if (iv == NULL) {
471 
472 				SECStatus s = PK11_GenerateRandom(genIV, 16);
473 
474                 if (s != SECSuccess) {
475 
476 					throw XSECCryptoException(XSECCryptoException::SymmetricError,
477 						"NSS:SymmetricKey - Error generating random IV");
478 
479                 }
480 
481 				usedIV = genIV;
482 
483 			}
484 			else
485 				usedIV = iv;
486 
487 			SECItem ivItem;
488             ivItem.data = (unsigned char*)usedIV;
489             ivItem.len = 16;
490 
491             SECItem * secParam = PK11_ParamFromIV(CKM_AES_CBC_PAD, &ivItem);
492             mp_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_ENCRYPT, mp_k, secParam);
493 
494             if (secParam)
495                 SECITEM_FreeItem(secParam, PR_TRUE);
496 
497             m_ivSize = 16;
498 		}
499 		else if (m_keyMode == MODE_ECB) {
500 			SECItem * secParam = PK11_ParamFromIV(CKM_AES_ECB, NULL);
501 			mp_ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, mp_k, secParam);
502 			if (secParam)
503 				SECITEM_FreeItem(secParam, PR_TRUE);
504 
505             m_ivSize = 0;
506 		}
507         else {
508 		    throw XSECCryptoException(XSECCryptoException::SymmetricError,
509 			        "NSS:SymmetricKey - Unsupported AES cipher mode");
510         }
511 
512 		break;
513 
514 	default :
515 
516 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
517 			"NSS:SymmetricKey - Unknown key type");
518 
519 	}
520 
521 	// Add IV
522 	if (m_keyMode == MODE_CBC || m_keyMode == MODE_GCM) {
523 
524 		memcpy(m_lastBlock, usedIV, m_ivSize);
525 
526 	}
527 
528 	return true;
529 
530 }
531 
532 // --------------------------------------------------------------------------------
533 //           Encrypt
534 // --------------------------------------------------------------------------------
535 
encrypt(const unsigned char * inBuf,unsigned char * cipherBuf,unsigned int inLength,unsigned int maxOutLength)536 unsigned int NSSCryptoSymmetricKey::encrypt(const unsigned char * inBuf,
537 								 unsigned char * cipherBuf,
538 								 unsigned int inLength,
539 								 unsigned int maxOutLength) {
540 
541     if (m_initialised == false) {
542 
543 		encryptInit();
544 
545 	}
546 
547 	// NOTE: This won't actually stop NSS blowing the buffer, so the onus is
548 	// on the caller.
549 
550 	unsigned int offset = 0;
551 	if (m_ivSent == false && m_ivSize > 0) {
552 
553 		memcpy(cipherBuf, m_lastBlock, m_ivSize);
554 		m_ivSent = true;
555 
556 		offset = m_ivSize;
557 
558 	}
559 
560 	int outl = 0;
561 
562 	if (inLength + offset > maxOutLength) {
563 
564 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
565 			"NSS:SymmetricKey - Not enough space in output buffer for encrypt");
566 
567 	}
568 
569     SECStatus s = PK11_CipherOp(mp_ctx,
570                               &cipherBuf[offset],
571                               &outl,
572                               maxOutLength - offset,
573                               (unsigned char*)inBuf,
574                               inLength);
575 
576 	if (s != SECSuccess) {
577 
578 		throw XSECCryptoException(XSECCryptoException::SymmetricError,
579 			"NSS:SymmetricKey - Error during NSS encrypt");
580 
581 	}
582 
583 	return outl + offset;
584 
585 }
586 
587 // --------------------------------------------------------------------------------
588 //           Encrypt finalisation
589 // --------------------------------------------------------------------------------
590 
encryptFinish(unsigned char * cipherBuf,unsigned int maxOutLength,unsigned int taglen)591 unsigned int NSSCryptoSymmetricKey::encryptFinish(unsigned char * cipherBuf,
592                                                   unsigned int maxOutLength,
593                                                   unsigned int taglen) {
594 
595 	unsigned int outl = 0;
596 
597 	SECStatus s = PK11_DigestFinal(mp_ctx, cipherBuf, &outl, maxOutLength);
598 
599 		if (s != SECSuccess) {
600 
601 			throw XSECCryptoException(XSECCryptoException::SymmetricError,
602 				"NSS:SymmetricKey - Error during NSS encrypt");
603 
604 	}
605 
606 	PK11_DestroyContext(mp_ctx, PR_TRUE);
607 	mp_ctx = NULL;
608 
609 	// Setup so can be re-used
610 	m_initialised = false;
611 
612 	return outl;
613 
614 }
615 
616 #endif /* XSEC_HAVE_NSS */
617