Git init
[external/xmlsec1.git] / src / nss / kw_aes.c
1 /** 
2  *
3  * XMLSec library
4  * 
5  * AES Algorithm support
6  * 
7  * This is free software; see Copyright file in the source
8  * distribution for preciese wording.
9  * 
10  * Copyright (c) 2003 America Online, Inc.  All rights reserved.
11  */
12 #ifndef XMLSEC_NO_AES
13
14 #include "globals.h"
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include <nss.h>
21 #include <pk11func.h>
22
23 #include <xmlsec/xmlsec.h>
24 #include <xmlsec/xmltree.h>
25 #include <xmlsec/keys.h>
26 #include <xmlsec/transforms.h>
27 #include <xmlsec/errors.h>
28
29 #include <xmlsec/nss/crypto.h>
30
31 #define XMLSEC_NSS_AES128_KEY_SIZE              16
32 #define XMLSEC_NSS_AES192_KEY_SIZE              24
33 #define XMLSEC_NSS_AES256_KEY_SIZE              32
34 #define XMLSEC_NSS_AES_IV_SIZE                  16
35 #define XMLSEC_NSS_AES_BLOCK_SIZE               16
36
37 #ifndef NSS_AES_KEYWRAP_BUG_FIXED
38 static PK11SymKey*      xmlSecNssMakeAesKey(const xmlSecByte *key, 
39                                             xmlSecSize keySize, int enc);
40 static void             xmlSecNssAesOp(PK11SymKey *aeskey, 
41                                        const xmlSecByte *in, xmlSecByte *out,
42                                        int enc);
43 #endif /* NSS_AES_KEYWRAP_BUG_FIXED */
44
45 /*********************************************************************
46  *
47  * AES KW transforms
48  *
49  * key (xmlSecBuffer) is located after xmlSecTransform structure
50  *
51  ********************************************************************/
52 #define xmlSecNssKWAesGetKey(transform) \
53     ((xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)))
54 #define xmlSecNssKWAesSize      \
55     (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer))
56
57 static int              xmlSecNssKWAesInitialize        (xmlSecTransformPtr transform);
58 static void             xmlSecNssKWAesFinalize          (xmlSecTransformPtr transform);
59 static int              xmlSecNssKWAesSetKeyReq         (xmlSecTransformPtr transform, 
60                                                          xmlSecKeyReqPtr keyReq);
61 static int              xmlSecNssKWAesSetKey            (xmlSecTransformPtr transform, 
62                                                          xmlSecKeyPtr key);
63 static int              xmlSecNssKWAesExecute           (xmlSecTransformPtr transform, 
64                                                          int last,
65                                                          xmlSecTransformCtxPtr transformCtx);
66 static xmlSecSize       xmlSecNssKWAesGetKeySize        (xmlSecTransformPtr transform);
67 static int              xmlSecNssKWAesOp                (const xmlSecByte *key,
68                                                          xmlSecSize keySize,
69                                                          const xmlSecByte* in,
70                                                          xmlSecSize inSize,
71                                                          xmlSecByte* out,
72                                                          xmlSecSize outSize,
73                                                          int enc);
74
75 static xmlSecTransformKlass xmlSecNssKWAes128Klass = {
76     /* klass/object sizes */
77     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
78     xmlSecNssKWAesSize,                         /* xmlSecSize objSize */
79
80     xmlSecNameKWAes128,                         /* const xmlChar* name; */
81     xmlSecHrefKWAes128,                         /* const xmlChar* href; */
82     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
83
84     xmlSecNssKWAesInitialize,                   /* xmlSecTransformInitializeMethod initialize; */
85     xmlSecNssKWAesFinalize,                     /* xmlSecTransformFinalizeMethod finalize; */
86     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
87     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
88     xmlSecNssKWAesSetKeyReq,                    /* xmlSecTransformSetKeyMethod setKeyReq; */
89     xmlSecNssKWAesSetKey,                       /* xmlSecTransformSetKeyMethod setKey; */
90     NULL,                                       /* xmlSecTransformValidateMethod validate; */
91     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
92     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
93     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
94     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
95     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
96     xmlSecNssKWAesExecute,                      /* xmlSecTransformExecuteMethod execute; */
97     
98     NULL,                                       /* void* reserved0; */
99     NULL,                                       /* void* reserved1; */
100 };
101
102 static xmlSecTransformKlass xmlSecNssKWAes192Klass = {
103     /* klass/object sizes */
104     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
105     xmlSecNssKWAesSize,                         /* xmlSecSize objSize */
106
107     xmlSecNameKWAes192,                         /* const xmlChar* name; */
108     xmlSecHrefKWAes192,                         /* const xmlChar* href; */
109     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
110
111     xmlSecNssKWAesInitialize,                   /* xmlSecTransformInitializeMethod initialize; */
112     xmlSecNssKWAesFinalize,                     /* xmlSecTransformFinalizeMethod finalize; */
113     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
114     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
115     xmlSecNssKWAesSetKeyReq,                    /* xmlSecTransformSetKeyMethod setKeyReq; */
116     xmlSecNssKWAesSetKey,                       /* xmlSecTransformSetKeyMethod setKey; */
117     NULL,                                       /* xmlSecTransformValidateMethod validate; */
118     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
119     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
120     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
121     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
122     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
123     xmlSecNssKWAesExecute,                      /* xmlSecTransformExecuteMethod execute; */
124     
125     NULL,                                       /* void* reserved0; */
126     NULL,                                       /* void* reserved1; */
127 };
128
129 static xmlSecTransformKlass xmlSecNssKWAes256Klass = {
130     /* klass/object sizes */
131     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
132     xmlSecNssKWAesSize,                         /* xmlSecSize objSize */
133
134     xmlSecNameKWAes256,                         /* const xmlChar* name; */
135     xmlSecHrefKWAes256,                         /* const xmlChar* href; */
136     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
137
138     xmlSecNssKWAesInitialize,                   /* xmlSecTransformInitializeMethod initialize; */
139     xmlSecNssKWAesFinalize,                     /* xmlSecTransformFinalizeMethod finalize; */
140     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
141     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
142     xmlSecNssKWAesSetKeyReq,                    /* xmlSecTransformSetKeyMethod setKeyReq; */
143     xmlSecNssKWAesSetKey,                       /* xmlSecTransformSetKeyMethod setKey; */
144     NULL,                                       /* xmlSecTransformValidateMethod validate; */
145     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
146     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
147     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
148     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
149     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
150     xmlSecNssKWAesExecute,                      /* xmlSecTransformExecuteMethod execute; */
151     
152     NULL,                                       /* void* reserved0; */
153     NULL,                                       /* void* reserved1; */
154 };
155
156 #define XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE              8
157
158 #define xmlSecNssKWAesCheckId(transform) \
159     (xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes128Id) || \
160      xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes192Id) || \
161      xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes256Id))
162
163 /** 
164  * xmlSecNssTransformKWAes128GetKlass:
165  *
166  * The AES-128 key wrapper transform klass.
167  *
168  * Returns: AES-128 key wrapper transform klass.
169  */
170 xmlSecTransformId 
171 xmlSecNssTransformKWAes128GetKlass(void) {
172     return(&xmlSecNssKWAes128Klass);
173 }
174
175 /** 
176  * xmlSecNssTransformKWAes192GetKlass:
177  *
178  * The AES-192 key wrapper transform klass.
179  *
180  * Returns: AES-192 key wrapper transform klass.
181  */
182 xmlSecTransformId 
183 xmlSecNssTransformKWAes192GetKlass(void) {
184     return(&xmlSecNssKWAes192Klass);
185 }
186
187 /** 
188  * xmlSecNssTransformKWAes256GetKlass:
189  *
190  * The AES-256 key wrapper transform klass.
191  *
192  * Returns: AES-256 key wrapper transform klass.
193  */
194 xmlSecTransformId 
195 xmlSecNssTransformKWAes256GetKlass(void) {
196     return(&xmlSecNssKWAes256Klass);
197 }
198
199 static int 
200 xmlSecNssKWAesInitialize(xmlSecTransformPtr transform) {
201     int ret;
202     
203     xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1);
204     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1);
205     
206     ret = xmlSecBufferInitialize(xmlSecNssKWAesGetKey(transform), 0);
207     if(ret < 0) {
208         xmlSecError(XMLSEC_ERRORS_HERE,
209                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
210                     "xmlSecBufferInitialize",
211                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
212                     XMLSEC_ERRORS_NO_MESSAGE);
213         return(-1);
214     }
215         
216     return(0);
217 }
218
219 static void 
220 xmlSecNssKWAesFinalize(xmlSecTransformPtr transform) {
221     xmlSecAssert(xmlSecNssKWAesCheckId(transform));
222     xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize));
223     
224     if(xmlSecNssKWAesGetKey(transform) != NULL) {
225         xmlSecBufferFinalize(xmlSecNssKWAesGetKey(transform));
226     }
227 }
228
229 static int  
230 xmlSecNssKWAesSetKeyReq(xmlSecTransformPtr transform,  xmlSecKeyReqPtr keyReq) {
231     xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1);
232     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
233     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1);
234     xmlSecAssert2(keyReq != NULL, -1);
235
236     keyReq->keyId        = xmlSecNssKeyDataAesId;
237     keyReq->keyType  = xmlSecKeyDataTypeSymmetric;
238     if(transform->operation == xmlSecTransformOperationEncrypt) {
239         keyReq->keyUsage = xmlSecKeyUsageEncrypt;
240     } else {
241         keyReq->keyUsage = xmlSecKeyUsageDecrypt;
242     }
243     keyReq->keyBitsSize = 8 * xmlSecNssKWAesGetKeySize(transform);
244     
245     return(0);
246 }
247
248 static int      
249 xmlSecNssKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
250     xmlSecBufferPtr buffer;
251     xmlSecSize keySize;
252     xmlSecSize expectedKeySize;
253     int ret;
254     
255     xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1);
256     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
257     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1);
258     xmlSecAssert2(xmlSecNssKWAesGetKey(transform) != NULL, -1);
259     xmlSecAssert2(key != NULL, -1);
260     xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataAesId), -1);
261     
262     buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
263     xmlSecAssert2(buffer != NULL, -1);
264
265     keySize = xmlSecBufferGetSize(buffer);
266     expectedKeySize = xmlSecNssKWAesGetKeySize(transform);
267     if(keySize < expectedKeySize) {
268         xmlSecError(XMLSEC_ERRORS_HERE,
269                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
270                     NULL,
271                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,
272                     "key=%d;expected=%d",
273                     keySize, expectedKeySize);
274         return(-1);
275     }
276         
277     ret = xmlSecBufferSetData(xmlSecNssKWAesGetKey(transform),
278                             xmlSecBufferGetData(buffer), 
279                             expectedKeySize);
280     if(ret < 0) {
281         xmlSecError(XMLSEC_ERRORS_HERE, 
282                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
283                     "xmlSecBufferSetData",
284                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
285                     "expected-size=%d", expectedKeySize);
286         return(-1);    
287     }
288
289     return(0);
290 }
291
292 static int 
293 xmlSecNssKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
294     xmlSecBufferPtr in, out, key;
295     xmlSecSize inSize, outSize, keySize, expectedKeySize;
296     int ret;
297
298     xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1);
299     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
300     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1);
301     xmlSecAssert2(transformCtx != NULL, -1);
302
303     key = xmlSecNssKWAesGetKey(transform);
304     xmlSecAssert2(key != NULL, -1);
305
306     keySize = xmlSecBufferGetSize(key);
307     expectedKeySize = xmlSecNssKWAesGetKeySize(transform);
308     xmlSecAssert2(keySize == expectedKeySize, -1);
309     
310     in = &(transform->inBuf);
311     out = &(transform->outBuf);
312     inSize = xmlSecBufferGetSize(in);
313     outSize = xmlSecBufferGetSize(out);    
314     xmlSecAssert2(outSize == 0, -1);
315     
316     if(transform->status == xmlSecTransformStatusNone) {
317         transform->status = xmlSecTransformStatusWorking;
318     }
319     
320     if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) {
321         /* just do nothing */
322     } else  if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) {
323         if((inSize % 8) != 0) {
324             xmlSecError(XMLSEC_ERRORS_HERE,
325                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
326                         NULL,
327                         XMLSEC_ERRORS_R_INVALID_SIZE,
328                         "size=%d(not 8 bytes aligned)", inSize);
329             return(-1);
330         }       
331         
332         if(transform->operation == xmlSecTransformOperationEncrypt) {
333             /* the encoded key might be 8 bytes longer plus 8 bytes just in case */
334             outSize = inSize + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE + 
335                                XMLSEC_NSS_AES_BLOCK_SIZE;
336         } else {
337             outSize = inSize + XMLSEC_NSS_AES_BLOCK_SIZE;
338         }
339
340         ret = xmlSecBufferSetMaxSize(out, outSize);
341         if(ret < 0) {
342             xmlSecError(XMLSEC_ERRORS_HERE, 
343                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
344                         "xmlSecBufferSetMaxSize",
345                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
346                         "outSize=%d", outSize);
347             return(-1);
348         }
349
350         if(transform->operation == xmlSecTransformOperationEncrypt) {
351             ret = xmlSecNssKWAesOp(xmlSecBufferGetData(key), keySize,
352                                    xmlSecBufferGetData(in), inSize,
353                                    xmlSecBufferGetData(out), outSize, 1);
354             if(ret < 0) {
355                 xmlSecError(XMLSEC_ERRORS_HERE, 
356                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
357                             "xmlSecNssKWAesOp",
358                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
359                             XMLSEC_ERRORS_NO_MESSAGE);
360                 return(-1);
361             }
362             outSize = ret;
363         } else {
364             ret = xmlSecNssKWAesOp(xmlSecBufferGetData(key), keySize,
365                                    xmlSecBufferGetData(in), inSize,
366                                    xmlSecBufferGetData(out), outSize, 0);
367             if(ret < 0) {
368                 xmlSecError(XMLSEC_ERRORS_HERE, 
369                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
370                             "xmlSecNssKWAesOp",
371                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
372                             XMLSEC_ERRORS_NO_MESSAGE);
373                 return(-1);
374             }
375             outSize = ret;
376         }
377
378         ret = xmlSecBufferSetSize(out, outSize);
379         if(ret < 0) {
380             xmlSecError(XMLSEC_ERRORS_HERE, 
381                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
382                         "xmlSecBufferSetSize", 
383                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
384                         "outSize=%d", outSize);
385             return(-1);
386         }
387         
388         ret = xmlSecBufferRemoveHead(in, inSize);
389         if(ret < 0) {
390             xmlSecError(XMLSEC_ERRORS_HERE, 
391                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
392                         "xmlSecBufferRemoveHead",
393                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
394                         "inSize%d", inSize);
395             return(-1);
396         }
397         
398         transform->status = xmlSecTransformStatusFinished;
399     } else if(transform->status == xmlSecTransformStatusFinished) {
400         /* the only way we can get here is if there is no input */
401         xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1);
402     } else {
403         xmlSecError(XMLSEC_ERRORS_HERE, 
404                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
405                     NULL,
406                     XMLSEC_ERRORS_R_INVALID_STATUS,
407                     "status=%d", transform->status);
408         return(-1);
409     }
410     return(0);
411 }
412
413 static xmlSecSize  
414 xmlSecNssKWAesGetKeySize(xmlSecTransformPtr transform) {
415     if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes128Id)) {
416         return(XMLSEC_NSS_AES128_KEY_SIZE);
417     } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes192Id)) {
418         return(XMLSEC_NSS_AES192_KEY_SIZE);
419     } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes256Id)) {
420         return(XMLSEC_NSS_AES256_KEY_SIZE);
421     }
422     return(0);
423 }
424
425 /**
426  * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap:
427  *
428  * Assume that the data to be wrapped consists of N 64-bit data blocks 
429  * denoted P(1), P(2), P(3) ... P(N). The result of wrapping will be N+1 
430  * 64-bit blocks denoted C(0), C(1), C(2), ... C(N). The key encrypting 
431  * key is represented by K. Assume integers i, j, and t and intermediate 
432  * 64-bit register A, 128-bit register B, and array of 64-bit quantities 
433  * R(1) through R(N).
434  *
435  * "|" represents concatentation so x|y, where x and y and 64-bit quantities, 
436  * is the 128-bit quantity with x in the most significant bits and y in the 
437  * least significant bits. AES(K)enc(x) is the operation of AES encrypting 
438  * the 128-bit quantity x under the key K. AES(K)dec(x) is the corresponding 
439  * decryption opteration. XOR(x,y) is the bitwise exclusive or of x and y. 
440  * MSB(x) and LSB(y) are the most significant 64 bits and least significant 
441  * 64 bits of x and y respectively.
442  *
443  * If N is 1, a single AES operation is performed for wrap or unwrap. 
444  * If N>1, then 6*N AES operations are performed for wrap or unwrap.
445  *
446  * The key wrap algorithm is as follows:
447  *
448  *   1. If N is 1:
449  *          * B=AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1))
450  *          * C(0)=MSB(B)
451  *          * C(1)=LSB(B)
452  *      If N>1, perform the following steps:
453  *   2. Initialize variables:
454  *          * Set A to 0xA6A6A6A6A6A6A6A6
455  *          * Fori=1 to N,
456  *            R(i)=P(i)
457  *   3. Calculate intermediate values:
458  *          * Forj=0 to 5,
459  *                o For i=1 to N,
460  *                  t= i + j*N
461  *                  B=AES(K)enc(A|R(i))
462  *                  A=XOR(t,MSB(B))
463  *                  R(i)=LSB(B)
464  *   4. Output the results:
465  *          * Set C(0)=A
466  *          * For i=1 to N,
467  *            C(i)=R(i)
468  *
469  * The key unwrap algorithm is as follows:
470  *
471  *   1. If N is 1:
472  *          * B=AES(K)dec(C(0)|C(1))
473  *          * P(1)=LSB(B)
474  *          * If MSB(B) is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, 
475  *            return an integrity check failure error.
476  *      If N>1, perform the following steps:
477  *   2. Initialize the variables:
478  *          * A=C(0)
479  *          * For i=1 to N,
480  *            R(i)=C(i)
481  *   3. Calculate intermediate values:
482  *          * For j=5 to 0,
483  *                o For i=N to 1,
484  *                  t= i + j*N
485  *                  B=AES(K)dec(XOR(t,A)|R(i))
486  *                  A=MSB(B)
487  *                  R(i)=LSB(B)
488  *   4. Output the results:
489  *          * For i=1 to N,
490  *            P(i)=R(i)
491  *          * If A is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, return 
492  *            an integrity check failure error.
493  */
494
495 #ifndef NSS_AES_KEYWRAP_BUG_FIXED
496 static const xmlSecByte xmlSecNssKWAesMagicBlock[XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE] = { 
497     0xA6,  0xA6,  0xA6,  0xA6,  0xA6,  0xA6,  0xA6,  0xA6
498 };
499                                                 
500 static int      
501 xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize,
502                  const xmlSecByte *in, xmlSecSize inSize,
503                  xmlSecByte *out, xmlSecSize outSize, int enc) {
504     xmlSecByte block[XMLSEC_NSS_AES_BLOCK_SIZE];
505     xmlSecByte *p;
506     int N, i, j, t;
507     int result = -1;
508     PK11SymKey *aeskey = NULL;
509     
510     xmlSecAssert2(key != NULL, -1);
511     xmlSecAssert2(keySize > 0, -1);
512     xmlSecAssert2(in != NULL, -1);
513     xmlSecAssert2(inSize > 0, -1);
514     xmlSecAssert2(out != NULL, -1);
515     xmlSecAssert2(outSize >= inSize + 8, -1);
516
517     if (enc == 1) {
518         aeskey = xmlSecNssMakeAesKey(key, keySize, enc);
519         if(aeskey == NULL) {
520             xmlSecError(XMLSEC_ERRORS_HERE, 
521                         NULL,
522                         "xmlSecNssMakeAesKey",
523                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
524                         XMLSEC_ERRORS_NO_MESSAGE);
525             goto done;
526         }
527     
528         /* prepend magic block */
529         if(in != out) {
530             memcpy(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, in, inSize);
531         } else {
532             memmove(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, out, inSize);
533         }
534         memcpy(out, xmlSecNssKWAesMagicBlock, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE);
535         
536         N = (inSize / 8);
537         if(N == 1) {
538             xmlSecNssAesOp(aeskey, out, out, enc);
539         } else {
540             for(j = 0; j <= 5; ++j) {
541                 for(i = 1; i <= N; ++i) {
542                     t = i + (j * N);
543                     p = out + i * 8;
544     
545                     memcpy(block, out, 8);
546                     memcpy(block + 8, p, 8);
547                 
548                     xmlSecNssAesOp(aeskey, block, block, enc);
549                     block[7] ^=  t;
550                     memcpy(out, block, 8);
551                     memcpy(p, block + 8, 8);
552                 }
553             }
554         }
555         
556         result = inSize + 8;
557     } else {
558         aeskey = xmlSecNssMakeAesKey(key, keySize, enc);
559         if(aeskey == NULL) {
560             xmlSecError(XMLSEC_ERRORS_HERE, 
561                         NULL,
562                         "xmlSecNssMakeAesKey",
563                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
564                         XMLSEC_ERRORS_NO_MESSAGE);
565             goto done;
566         }
567         
568         /* copy input */
569         if(in != out) {
570             memcpy(out, in, inSize);
571         }
572             
573         N = (inSize / 8) - 1;
574         if(N == 1) {
575             xmlSecNssAesOp(aeskey, out, out, enc);
576         } else {
577             for(j = 5; j >= 0; --j) {
578                 for(i = N; i > 0; --i) {
579                     t = i + (j * N);
580                     p = out + i * 8;
581     
582                     memcpy(block, out, 8);
583                     memcpy(block + 8, p, 8);
584                     block[7] ^= t;
585                 
586                     xmlSecNssAesOp(aeskey, block, block, enc);
587                     memcpy(out, block, 8);
588                     memcpy(p, block + 8, 8);
589                 }
590             }
591         }
592         /* do not left data in memory */
593         memset(block, 0, sizeof(block));
594         
595         if(memcmp(xmlSecNssKWAesMagicBlock, out, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE) != 0) {
596             xmlSecError(XMLSEC_ERRORS_HERE, 
597                         NULL,
598                         NULL,
599                         XMLSEC_ERRORS_R_INVALID_DATA,
600                         "bad magic block");
601             goto done;
602         }
603         
604         memmove(out, out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE);
605         result = (inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE);
606     }
607
608 done:
609     if (aeskey != NULL) {
610         PK11_FreeSymKey(aeskey);
611     }
612
613     return (result);
614 }
615
616 static PK11SymKey *
617 xmlSecNssMakeAesKey(const xmlSecByte *key, xmlSecSize keySize, int enc) {
618     CK_MECHANISM_TYPE  cipherMech;
619     PK11SlotInfo*      slot = NULL;
620     PK11SymKey*        aeskey = NULL;
621     SECItem            keyItem;
622     
623     xmlSecAssert2(key != NULL, NULL);
624     xmlSecAssert2(keySize > 0, NULL);
625
626     cipherMech = CKM_AES_ECB;
627     slot = PK11_GetBestSlot(cipherMech, NULL);
628     if (slot == NULL) {
629         xmlSecError(XMLSEC_ERRORS_HERE,
630                     NULL,
631                     "PK11_GetBestSlot",
632                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
633                     XMLSEC_ERRORS_NO_MESSAGE);
634         goto done;
635     }
636
637     keyItem.data = (unsigned char *)key;
638     keyItem.len = keySize;
639     aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, 
640                                enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL);
641     if (aeskey == NULL) {
642         xmlSecError(XMLSEC_ERRORS_HERE,
643                     NULL,
644                     "PK11_ImportSymKey",
645                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
646                     XMLSEC_ERRORS_NO_MESSAGE);
647         goto done;
648     }
649
650 done:
651     if (slot) {
652         PK11_FreeSlot(slot);
653     }
654
655     return(aeskey);
656 }
657
658 /* encrypt a block (XMLSEC_NSS_AES_BLOCK_SIZE), in and out can overlap */
659 static void
660 xmlSecNssAesOp(PK11SymKey *aeskey, const xmlSecByte *in, xmlSecByte *out,
661                int enc) {
662
663     CK_MECHANISM_TYPE  cipherMech;
664     SECItem*           SecParam = NULL;
665     PK11Context*       EncContext = NULL;
666     SECStatus          rv;
667     int                tmp1_outlen;
668     unsigned int       tmp2_outlen;
669
670     xmlSecAssert(in != NULL);
671     xmlSecAssert(out != NULL);
672
673     cipherMech = CKM_AES_ECB;
674     SecParam = PK11_ParamFromIV(cipherMech, NULL);
675     if (SecParam == NULL) {
676         xmlSecError(XMLSEC_ERRORS_HERE,
677                     NULL,
678                     "PK11_ParamFromIV",
679                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
680                     XMLSEC_ERRORS_NO_MESSAGE);
681         goto done;
682     }
683
684     EncContext = PK11_CreateContextBySymKey(cipherMech, 
685                                             enc ? CKA_ENCRYPT : CKA_DECRYPT, 
686                                             aeskey, SecParam);
687     if (EncContext == NULL) {
688         xmlSecError(XMLSEC_ERRORS_HERE,
689                     NULL,
690                     "PK11_CreateContextBySymKey",
691                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
692                     XMLSEC_ERRORS_NO_MESSAGE);
693         goto done;
694     }
695
696     tmp1_outlen = tmp2_outlen = 0;
697     rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, 
698                        XMLSEC_NSS_AES_BLOCK_SIZE, (unsigned char *)in, 
699                        XMLSEC_NSS_AES_BLOCK_SIZE);
700     if (rv != SECSuccess) {
701         xmlSecError(XMLSEC_ERRORS_HERE,
702                     NULL,
703                     "PK11_CipherOp",
704                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
705                     XMLSEC_ERRORS_NO_MESSAGE);
706         goto done;
707     }
708
709     rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, 
710                           &tmp2_outlen, XMLSEC_NSS_AES_BLOCK_SIZE-tmp1_outlen);
711     if (rv != SECSuccess) {
712         xmlSecError(XMLSEC_ERRORS_HERE,
713                     NULL,
714                     "PK11_DigestFinal",
715                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
716                     XMLSEC_ERRORS_NO_MESSAGE);
717         goto done;
718     }
719
720 done:
721     if (SecParam) {
722         SECITEM_FreeItem(SecParam, PR_TRUE);
723     }
724     if (EncContext) {
725         PK11_DestroyContext(EncContext, PR_TRUE);
726     }
727
728 }
729
730 #else /* NSS_AES_KEYWRAP_BUG_FIXED */
731
732 /* Note: When the bug gets fixed, it is not enough to just remove
733  * the #ifdef (NSS_AES_KEYWRAP_BUG_FIXED). The code also has
734  * to change from doing the Init/Update/Final to just a straight
735  * encrypt or decrypt. PK11 wrappers have to be exposed by
736  * NSS, and these should be used.
737  * Follow the NSS bug system for more details on the fix
738  * http://bugzilla.mozilla.org/show_bug.cgi?id=213795
739  */
740
741 /* NSS implements the AES Key Wrap algorithm described at
742  * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap
743  */ 
744
745 static int      
746 xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize,
747                  const xmlSecByte *in, xmlSecSize inSize,
748                  xmlSecByte *out, xmlSecSize outSize, int enc) {
749
750     CK_MECHANISM_TYPE  cipherMech;
751     PK11SlotInfo*      slot = NULL;
752     PK11SymKey*        aeskey = NULL;
753     SECItem*           SecParam = NULL;
754     PK11Context*       EncContext = NULL;
755     SECItem            keyItem;
756     SECStatus          rv;
757     int                result_len = -1;
758     int                tmp1_outlen;
759     unsigned int       tmp2_outlen;
760     
761     xmlSecAssert2(key != NULL, -1);
762     xmlSecAssert2(keySize > 0, -1);
763     xmlSecAssert2(in != NULL, -1);
764     xmlSecAssert2(inSize > 0, -1);
765     xmlSecAssert2(out != NULL, -1);
766     xmlSecAssert2(outSize >= inSize + 8, -1);
767
768     cipherMech = CKM_NETSCAPE_AES_KEY_WRAP;
769     slot = PK11_GetBestSlot(cipherMech, NULL);
770     if (slot == NULL) {
771         xmlSecError(XMLSEC_ERRORS_HERE,
772                     NULL,
773                     "PK11_GetBestSlot",
774                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
775                     XMLSEC_ERRORS_NO_MESSAGE);
776         goto done;
777     }
778
779     keyItem.data = (unsigned char *)key;
780     keyItem.len = keySize;
781     aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, 
782                                enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL);
783     if (aeskey == NULL) {
784         xmlSecError(XMLSEC_ERRORS_HERE,
785                     NULL,
786                     "PK11_ImportSymKey",
787                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
788                     XMLSEC_ERRORS_NO_MESSAGE);
789         goto done;
790     }
791
792     SecParam = PK11_ParamFromIV(cipherMech, NULL);
793     if (SecParam == NULL) {
794         xmlSecError(XMLSEC_ERRORS_HERE,
795                     NULL,
796                     "PK11_ParamFromIV",
797                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
798                     XMLSEC_ERRORS_NO_MESSAGE);
799         goto done;
800     }
801
802     EncContext = PK11_CreateContextBySymKey(cipherMech, 
803                                             enc ? CKA_ENCRYPT : CKA_DECRYPT, 
804                                             aeskey, SecParam);
805     if (EncContext == NULL) {
806         xmlSecError(XMLSEC_ERRORS_HERE,
807                     NULL,
808                     "PK11_CreateContextBySymKey",
809                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
810                     XMLSEC_ERRORS_NO_MESSAGE);
811         goto done;
812     }
813
814     tmp1_outlen = tmp2_outlen = 0;
815     rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize,
816                        (unsigned char *)in, inSize);
817     if (rv != SECSuccess) {
818         xmlSecError(XMLSEC_ERRORS_HERE,
819                     NULL,
820                     "PK11_CipherOp",
821                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
822                     XMLSEC_ERRORS_NO_MESSAGE);
823         goto done;
824     }
825
826     rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, 
827                           &tmp2_outlen, outSize-tmp1_outlen);
828     if (rv != SECSuccess) {
829         xmlSecError(XMLSEC_ERRORS_HERE,
830                     NULL,
831                     "PK11_DigestFinal",
832                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
833                     XMLSEC_ERRORS_NO_MESSAGE);
834         goto done;
835     }
836
837     result_len = tmp1_outlen + tmp2_outlen;
838
839 done:
840     if (slot) {
841         PK11_FreeSlot(slot);
842     }
843     if (aeskey) {
844         PK11_FreeSymKey(aeskey);
845     }
846     if (SecParam) {
847         SECITEM_FreeItem(SecParam, PR_TRUE);
848     }
849     if (EncContext) {
850         PK11_DestroyContext(EncContext, PR_TRUE);
851     }
852
853     return(result_len);
854 }
855 #endif /* NSS_AES_KEYWRAP_BUG_FIXED */
856
857 #endif /* XMLSEC_NO_AES */