Git init
[external/xmlsec1.git] / src / nss / keysstore.c
1 /** 
2  * XMLSec library
3  * 
4  * Nss keys store that uses Simple Keys Store under the hood. Uses the
5  * Nss DB as a backing store for the finding keys, but the NSS DB is
6  * not written to by the keys store.
7  * So, if store->findkey is done and the key is not found in the simple
8  * keys store, the NSS DB is looked up.
9  * If store is called to adopt a key, that key is not written to the NSS
10  * DB.
11  * Thus, the NSS DB can be used to pre-load keys and becomes an alternate 
12  * source of keys for xmlsec
13  * 
14  * This is free software; see Copyright file in the source
15  * distribution for precise wording.
16  * 
17  * Copyright (c) 2003 America Online, Inc.  All rights reserved.
18  */
19 #include "globals.h"
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <nss.h> 
25 #include <cert.h> 
26 #include <pk11func.h> 
27 #include <keyhi.h> 
28
29 #include <libxml/tree.h> 
30
31 #include <xmlsec/xmlsec.h>
32 #include <xmlsec/buffer.h>
33 #include <xmlsec/base64.h>
34 #include <xmlsec/errors.h>
35 #include <xmlsec/xmltree.h>
36
37 #include <xmlsec/keysmngr.h>
38
39 #include <xmlsec/nss/crypto.h>
40 #include <xmlsec/nss/keysstore.h>
41 #include <xmlsec/nss/x509.h>
42 #include <xmlsec/nss/pkikeys.h>
43
44 /****************************************************************************
45  *
46  * Nss Keys Store. Uses Simple Keys Store under the hood
47  * 
48  * Simple Keys Store ptr is located after xmlSecKeyStore
49  *
50  ***************************************************************************/
51 #define xmlSecNssKeysStoreSize \
52         (sizeof(xmlSecKeyStore) + sizeof(xmlSecKeyStorePtr))
53
54 #define xmlSecNssKeysStoreGetSS(store) \
55     ((xmlSecKeyStoreCheckSize((store), xmlSecNssKeysStoreSize)) ? \
56      (xmlSecKeyStorePtr*)(((xmlSecByte*)(store)) + sizeof(xmlSecKeyStore)) : \
57      (xmlSecKeyStorePtr*)NULL)
58
59 static int                      xmlSecNssKeysStoreInitialize    (xmlSecKeyStorePtr store);
60 static void                     xmlSecNssKeysStoreFinalize      (xmlSecKeyStorePtr store);
61 static xmlSecKeyPtr             xmlSecNssKeysStoreFindKey       (xmlSecKeyStorePtr store, 
62                                                                  const xmlChar* name, 
63                                                                  xmlSecKeyInfoCtxPtr keyInfoCtx);
64
65 static xmlSecKeyStoreKlass xmlSecNssKeysStoreKlass = {
66     sizeof(xmlSecKeyStoreKlass),
67     xmlSecNssKeysStoreSize,
68
69     /* data */
70     BAD_CAST "NSS-keys-store",          /* const xmlChar* name; */ 
71         
72     /* constructors/destructor */
73     xmlSecNssKeysStoreInitialize,       /* xmlSecKeyStoreInitializeMethod initialize; */
74     xmlSecNssKeysStoreFinalize,         /* xmlSecKeyStoreFinalizeMethod finalize; */
75     xmlSecNssKeysStoreFindKey,          /* xmlSecKeyStoreFindKeyMethod findKey; */
76
77     /* reserved for the future */
78     NULL,                               /* void* reserved0; */
79     NULL,                               /* void* reserved1; */
80 };
81
82 /**
83  * xmlSecNssKeysStoreGetKlass:
84  * 
85  * The Nss list based keys store klass.
86  *
87  * Returns: Nss list based keys store klass.
88  */
89 xmlSecKeyStoreId 
90 xmlSecNssKeysStoreGetKlass(void) {
91     return(&xmlSecNssKeysStoreKlass);
92 }
93
94 /**
95  * xmlSecNssKeysStoreAdoptKey:
96  * @store:              the pointer to Nss keys store.
97  * @key:                the pointer to key.
98  * 
99  * Adds @key to the @store. 
100  *
101  * Returns: 0 on success or a negative value if an error occurs.
102  */
103 int 
104 xmlSecNssKeysStoreAdoptKey(xmlSecKeyStorePtr store, xmlSecKeyPtr key) {
105     xmlSecKeyStorePtr *ss;
106     
107     xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1);
108     xmlSecAssert2((key != NULL), -1);
109
110     ss = xmlSecNssKeysStoreGetSS(store);
111     xmlSecAssert2(((ss != NULL) && (*ss != NULL) && 
112                    (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1);
113
114     return (xmlSecSimpleKeysStoreAdoptKey(*ss, key));
115 }
116
117 /** 
118  * xmlSecNssKeysStoreLoad:
119  * @store:              the pointer to Nss keys store.
120  * @uri:                the filename.
121  * @keysMngr:           the pointer to associated keys manager. 
122  * 
123  * Reads keys from an XML file.
124  *
125  * Returns: 0 on success or a negative value if an error occurs.
126  */
127 int
128 xmlSecNssKeysStoreLoad(xmlSecKeyStorePtr store, const char *uri, 
129                             xmlSecKeysMngrPtr keysMngr) {
130     xmlDocPtr doc;
131     xmlNodePtr root;
132     xmlNodePtr cur;
133     xmlSecKeyPtr key;
134     xmlSecKeyInfoCtx keyInfoCtx;
135     int ret;
136
137     xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1);
138     xmlSecAssert2((uri != NULL), -1);    
139
140     doc = xmlParseFile(uri);
141     if(doc == NULL) {
142         xmlSecError(XMLSEC_ERRORS_HERE,
143                     xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
144                     "xmlParseFile",
145                     XMLSEC_ERRORS_R_XML_FAILED,
146                     "uri=%s", 
147                     xmlSecErrorsSafeString(uri));
148         return(-1);
149     }
150     
151     root = xmlDocGetRootElement(doc);
152     if(!xmlSecCheckNodeName(root, BAD_CAST "Keys", xmlSecNs)) {
153         xmlSecError(XMLSEC_ERRORS_HERE,
154                     xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
155                     xmlSecErrorsSafeString(xmlSecNodeGetName(root)),
156                     XMLSEC_ERRORS_R_INVALID_NODE,
157                     "expected-node=<xmlsec:Keys>");
158         xmlFreeDoc(doc);
159         return(-1);
160     }
161         
162     cur = xmlSecGetNextElementNode(root->children);
163     while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs)) {  
164         key = xmlSecKeyCreate();
165         if(key == NULL) {
166             xmlSecError(XMLSEC_ERRORS_HERE,
167                         xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
168                         xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
169                         XMLSEC_ERRORS_R_INVALID_NODE,
170                         "expected-node=%s",
171                         xmlSecErrorsSafeString(xmlSecNodeKeyInfo));
172             xmlFreeDoc(doc);
173             return(-1);
174         }
175
176         ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx, NULL);
177         if(ret < 0) {
178             xmlSecError(XMLSEC_ERRORS_HERE,
179                         xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
180                         "xmlSecKeyInfoCtxInitialize",
181                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
182                         XMLSEC_ERRORS_NO_MESSAGE);
183             xmlSecKeyDestroy(key);
184             xmlFreeDoc(doc);
185             return(-1);
186         }
187         
188         keyInfoCtx.mode           = xmlSecKeyInfoModeRead;
189         keyInfoCtx.keysMngr       = keysMngr;
190         keyInfoCtx.flags          = XMLSEC_KEYINFO_FLAGS_DONT_STOP_ON_KEY_FOUND |
191                                     XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
192         keyInfoCtx.keyReq.keyId   = xmlSecKeyDataIdUnknown;
193         keyInfoCtx.keyReq.keyType = xmlSecKeyDataTypeAny;
194         keyInfoCtx.keyReq.keyUsage= xmlSecKeyDataUsageAny;
195
196         ret = xmlSecKeyInfoNodeRead(cur, key, &keyInfoCtx);
197         if(ret < 0) {
198             xmlSecError(XMLSEC_ERRORS_HERE,
199                         xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
200                         "xmlSecKeyInfoNodeRead",
201                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
202                         XMLSEC_ERRORS_NO_MESSAGE);
203             xmlSecKeyInfoCtxFinalize(&keyInfoCtx);
204             xmlSecKeyDestroy(key);
205             xmlFreeDoc(doc);
206             return(-1);
207         }
208         xmlSecKeyInfoCtxFinalize(&keyInfoCtx);
209         
210         if(xmlSecKeyIsValid(key)) {
211             ret = xmlSecNssKeysStoreAdoptKey(store, key);
212             if(ret < 0) {
213                 xmlSecError(XMLSEC_ERRORS_HERE,
214                             xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
215                             "xmlSecNssKeysStoreAdoptKey",
216                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
217                             XMLSEC_ERRORS_NO_MESSAGE);
218                 xmlSecKeyDestroy(key);
219                 xmlFreeDoc(doc);
220                 return(-1);
221             }
222         } else {
223             /* we have an unknown key in our file, just ignore it */
224             xmlSecKeyDestroy(key);
225         }
226         cur = xmlSecGetNextElementNode(cur->next);
227     }
228     
229     if(cur != NULL) {
230         xmlSecError(XMLSEC_ERRORS_HERE,
231                     xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
232                     xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
233                     XMLSEC_ERRORS_R_UNEXPECTED_NODE,
234                     XMLSEC_ERRORS_NO_MESSAGE);
235         xmlFreeDoc(doc);
236         return(-1);         
237     }
238     
239     xmlFreeDoc(doc);
240     return(0);
241 }
242
243 /** 
244  * xmlSecNssKeysStoreSave:
245  * @store:              the pointer to Nss keys store.
246  * @filename:           the filename.
247  * @type:               the saved keys type (public, private, ...).
248  * 
249  * Writes keys from @store to an XML file.
250  *
251  * Returns: 0 on success or a negative value if an error occurs.
252  */
253 int
254 xmlSecNssKeysStoreSave(xmlSecKeyStorePtr store, const char *filename, xmlSecKeyDataType type) {
255     xmlSecKeyStorePtr *ss;
256
257     xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1);
258     xmlSecAssert2((filename != NULL), -1);    
259     
260     ss = xmlSecNssKeysStoreGetSS(store);
261     xmlSecAssert2(((ss != NULL) && (*ss != NULL) && 
262                    (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1);
263
264     return (xmlSecSimpleKeysStoreSave(*ss, filename, type));
265 }
266
267 static int
268 xmlSecNssKeysStoreInitialize(xmlSecKeyStorePtr store) {
269     xmlSecKeyStorePtr *ss;
270
271     xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1);
272
273     ss = xmlSecNssKeysStoreGetSS(store);
274     xmlSecAssert2((*ss == NULL), -1);
275
276     *ss = xmlSecKeyStoreCreate(xmlSecSimpleKeysStoreId);
277     if(*ss == NULL) {
278         xmlSecError(XMLSEC_ERRORS_HERE,
279                     xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)),
280                     "xmlSecKeyStoreCreate",
281                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
282                     "xmlSecSimpleKeysStoreId");
283         return(-1);
284     }
285
286     return(0);    
287 }
288
289 static void
290 xmlSecNssKeysStoreFinalize(xmlSecKeyStorePtr store) {
291     xmlSecKeyStorePtr *ss;
292     
293     xmlSecAssert(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId));
294     
295     ss = xmlSecNssKeysStoreGetSS(store);
296     xmlSecAssert((ss != NULL) && (*ss != NULL));
297     
298     xmlSecKeyStoreDestroy(*ss);
299 }
300
301 static xmlSecKeyPtr 
302 xmlSecNssKeysStoreFindKey(xmlSecKeyStorePtr store, const xmlChar* name, 
303                           xmlSecKeyInfoCtxPtr keyInfoCtx) {
304     xmlSecKeyStorePtr* ss;
305     xmlSecKeyPtr key = NULL;
306     xmlSecKeyPtr retval = NULL;
307     xmlSecKeyReqPtr keyReq = NULL;
308     CERTCertificate *cert = NULL;
309     SECKEYPublicKey *pubkey = NULL;
310     SECKEYPrivateKey *privkey = NULL;
311     xmlSecKeyDataPtr data = NULL;
312     xmlSecKeyDataPtr x509Data = NULL;
313     int ret;
314
315     xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), NULL);
316     xmlSecAssert2(keyInfoCtx != NULL, NULL);
317
318     ss = xmlSecNssKeysStoreGetSS(store);
319     xmlSecAssert2(((ss != NULL) && (*ss != NULL)), NULL);
320
321     key = xmlSecKeyStoreFindKey(*ss, name, keyInfoCtx);
322     if (key != NULL) {
323         return (key);
324     }
325
326     /* Try to find the key in the NSS DB, and construct an xmlSecKey.
327      * we must have a name to lookup keys in NSS DB.
328      */
329     if (name == NULL) {
330         goto done;
331     }
332
333     /* what type of key are we looking for? 
334      * TBD: For now, we'll look only for public/private keys using the
335      * name as a cert nickname. Later on, we can attempt to find
336      * symmetric keys using PK11_FindFixedKey 
337      */
338     keyReq = &(keyInfoCtx->keyReq);
339     if (keyReq->keyType & 
340         (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate)) {
341         cert = CERT_FindCertByNickname (CERT_GetDefaultCertDB(), (char *)name);
342         if (cert == NULL) {
343             goto done;
344         }
345
346         if (keyReq->keyType & xmlSecKeyDataTypePublic) {
347             pubkey = CERT_ExtractPublicKey(cert);
348             if (pubkey == NULL) {
349                 xmlSecError(XMLSEC_ERRORS_HERE,
350                             NULL,
351                             "CERT_ExtractPublicKey",
352                             XMLSEC_ERRORS_R_CRYPTO_FAILED,
353                             XMLSEC_ERRORS_NO_MESSAGE);
354                 goto done;
355             }
356         } 
357
358         if (keyReq->keyType & xmlSecKeyDataTypePrivate) { 
359             privkey = PK11_FindKeyByAnyCert(cert, NULL);
360             if (privkey == NULL) {
361                 xmlSecError(XMLSEC_ERRORS_HERE,
362                             NULL,
363                             "PK11_FindKeyByAnyCert",
364                             XMLSEC_ERRORS_R_CRYPTO_FAILED,
365                             XMLSEC_ERRORS_NO_MESSAGE);
366                 goto done;
367             }
368         }
369
370         data = xmlSecNssPKIAdoptKey(privkey, pubkey);
371         if(data == NULL) {
372             xmlSecError(XMLSEC_ERRORS_HERE,
373                         NULL,
374                         "xmlSecNssPKIAdoptKey",
375                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
376                         XMLSEC_ERRORS_NO_MESSAGE);
377             goto done;
378         }    
379         privkey = NULL;
380         pubkey = NULL;
381
382         key = xmlSecKeyCreate();
383         if (key == NULL) {
384             xmlSecError(XMLSEC_ERRORS_HERE,
385                         NULL,
386                         "xmlSecKeyCreate",
387                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
388                         XMLSEC_ERRORS_NO_MESSAGE);
389             return (NULL);
390         }
391
392         x509Data = xmlSecKeyDataCreate(xmlSecNssKeyDataX509Id);
393         if(x509Data == NULL) {
394             xmlSecError(XMLSEC_ERRORS_HERE,
395                         NULL,
396                         "xmlSecKeyDataCreate",
397                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
398                         "transform=%s",
399                         xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id)));
400             goto done;
401         }
402
403         ret = xmlSecNssKeyDataX509AdoptKeyCert(x509Data, cert);
404         if (ret < 0) {
405             xmlSecError(XMLSEC_ERRORS_HERE,
406                         NULL,
407                         "xmlSecNssKeyDataX509AdoptKeyCert",
408                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
409                         "data=%s",
410                         xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
411             goto done;
412         }
413         cert = CERT_DupCertificate(cert);
414         if (cert == NULL) {
415             xmlSecError(XMLSEC_ERRORS_HERE,
416                         NULL,
417                         "CERT_DupCertificate",
418                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
419                         "data=%s",
420                         xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
421             goto done;
422         }
423
424         ret = xmlSecNssKeyDataX509AdoptCert(x509Data, cert);
425         if (ret < 0) {
426             xmlSecError(XMLSEC_ERRORS_HERE,
427                         NULL,
428                         "xmlSecNssKeyDataX509AdoptCert",
429                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
430                         "data=%s",
431                         xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
432             goto done;
433         }
434         cert = NULL;
435
436         ret = xmlSecKeySetValue(key, data);
437         if (ret < 0) {
438             xmlSecError(XMLSEC_ERRORS_HERE,
439                         NULL,
440                         "xmlSecKeySetValue",
441                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
442                         "data=%s", 
443                         xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)));
444             goto done;
445         }
446         data = NULL;
447
448         ret = xmlSecKeyAdoptData(key, x509Data);
449         if (ret < 0) {
450             xmlSecError(XMLSEC_ERRORS_HERE,
451                         NULL,
452                         "xmlSecKeyAdoptData",
453                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
454                         "data=%s",
455                         xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
456             goto done;
457         }
458         x509Data = NULL;
459
460         retval = key;
461         key = NULL;
462     }
463
464 done:
465     if (cert != NULL) {
466         CERT_DestroyCertificate(cert);
467     }
468     if (pubkey != NULL) {
469         SECKEY_DestroyPublicKey(pubkey);
470     }
471     if (privkey != NULL) {
472         SECKEY_DestroyPrivateKey(privkey);
473     }
474     if (data != NULL) {
475         xmlSecKeyDataDestroy(data);
476     }
477     if (x509Data != NULL) {
478         xmlSecKeyDataDestroy(x509Data);
479     }
480     if (key != NULL) {
481         xmlSecKeyDestroy(key);
482     }
483
484     return (retval);
485 }