Keys manager. Overview. Processing some of the key data objects require additional information which is global across the application (or in the particular area of the application). For example, X509 certificates processing require a common list of trusted certificates to be available. XML Security Library keeps all the common information for key data processing in a a collection of key data stores called "keys manager".
The keys manager structure.
Keys manager has a special "keys store" which lists the keys known to the application. This "keys store" is used by XML Security Library to lookup keys by name, type and crypto algorithm (for example, during <dsig:KeyName/> processing). The XML Security Library provides default simple "flat list" based implementation of a default keys store. The application can replace it with any other keys store (for example, based on an SQL database). Keys manager is the only object in XML Security Library which is supposed to be shared by many different operations. Usually keys manager is initialized once at the application startup and later is used by XML Security library routines in "read-only" mode. If application or crypto function need to modify any of the key data stores inside keys manager then proper synchronization must be implemented. In the same time, application can create a new keys manager each time it needs to perform XML signature, verification, encryption or decryption.
Simple keys store. XML Security Library has a built-in simple keys store implemented using a keys list. You can use it in your application if you have a small number of keys. However, this might be not a best option from performance point of view if you have a lot of keys. In this case, you probably should implement your own keys store using an SQL database or some other keys storage. Initializing keys manager and loading keys from PEM files. 0); /* create and initialize keys manager, we use a default list based * keys manager, implement your own xmlSecKeysStore klass if you need * something more sophisticated */ mngr = xmlSecKeysMngrCreate(); if(mngr == NULL) { fprintf(stderr, "Error: failed to create keys manager.\n"); return(NULL); } if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { fprintf(stderr, "Error: failed to initialize keys manager.\n"); xmlSecKeysMngrDestroy(mngr); return(NULL); } for(i = 0; i < files_size; ++i) { assert(files[i]); /* load key */ key = xmlSecCryptoAppKeyLoad(files[i], xmlSecKeyDataFormatPem, NULL, NULL, NULL); if(key == NULL) { fprintf(stderr,"Error: failed to load pem key from \"%s\"\n", files[i]); xmlSecKeysMngrDestroy(mngr); return(NULL); } /* set key name to the file name, this is just an example! */ if(xmlSecKeySetName(key, BAD_CAST files[i]) < 0) { fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", files[i]); xmlSecKeyDestroy(key); xmlSecKeysMngrDestroy(mngr); return(NULL); } /* add key to keys manager, from now on keys manager is responsible * for destroying key */ if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) { fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", files[i]); xmlSecKeyDestroy(key); xmlSecKeysMngrDestroy(mngr); return(NULL); } } return(mngr); } ]]> Full program listing Using keys manager for signatures/encryption. Instead of specifiying signature or encryption key in the corresponding context object (signKey member of xmlSecDSigCtx structure or encKey member of xmlSecEncCtx structure), the application can use keys manager to select the signature or encryption key. This is especialy useful when you are encrypting or signing something with a session key which is by itself should be encrypted. The key for the session key encryption in the <EncryptedKey/> node could be selected using <dsig:KeyName/> node in the template. Encrypting file using a session key and a permanent key from keys manager. node */ if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) { fprintf(stderr, "Error: failed to add CipherValue node\n"); goto done; } /* add */ keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL); if(keyInfoNode == NULL) { fprintf(stderr, "Error: failed to add key info\n"); goto done; } /* add to store the encrypted session key */ encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, xmlSecTransformRsaOaepId, NULL, NULL, NULL); if(encKeyNode == NULL) { fprintf(stderr, "Error: failed to add key info\n"); goto done; } /* we want to put encrypted key in the node */ if(xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) { fprintf(stderr, "Error: failed to add CipherValue node\n"); goto done; } /* add and nodes to */ keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL); if(keyInfoNode2 == NULL) { fprintf(stderr, "Error: failed to add key info\n"); goto done; } /* set key name so we can lookup key when needed */ if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, key_name) == NULL) { fprintf(stderr, "Error: failed to add key name\n"); goto done; } /* create encryption context */ encCtx = xmlSecEncCtxCreate(mngr); if(encCtx == NULL) { fprintf(stderr,"Error: failed to create encryption context\n"); goto done; } /* generate a Triple DES key */ encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession); if(encCtx->encKey == NULL) { fprintf(stderr,"Error: failed to generate session des key\n"); goto done; } /* encrypt the data */ if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) { fprintf(stderr,"Error: encryption failed\n"); goto done; } /* we template is inserted in the doc */ encDataNode = NULL; /* print encrypted data with document to stdout */ xmlDocDump(stdout, doc); /* success */ res = 0; done: /* cleanup */ if(encCtx != NULL) { xmlSecEncCtxDestroy(encCtx); } if(encDataNode != NULL) { xmlFreeNode(encDataNode); } if(doc != NULL) { xmlFreeDoc(doc); } return(res); } ]]> Full program listing Using keys manager for verification/decryption. If more than one key could be used for signature or encryption, then using signKey member of xmlSecDSigCtx structure or encKey member of xmlSecEncCtx structure is not possible. Instead, the application should load known keys in the keys manager and use <dsig:KeyName/> element to specify the key name. Initializing keys manager and loading DES keys from binary files. 0); /* create and initialize keys manager, we use a default list based * keys manager, implement your own xmlSecKeysStore klass if you need * something more sophisticated */ mngr = xmlSecKeysMngrCreate(); if(mngr == NULL) { fprintf(stderr, "Error: failed to create keys manager.\n"); return(NULL); } if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { fprintf(stderr, "Error: failed to initialize keys manager.\n"); xmlSecKeysMngrDestroy(mngr); return(NULL); } for(i = 0; i < files_size; ++i) { assert(files[i]); /* load DES key */ key = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, files[i]); if(key == NULL) { fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", files[i]); xmlSecKeysMngrDestroy(mngr); return(NULL); } /* set key name to the file name, this is just an example! */ if(xmlSecKeySetName(key, BAD_CAST files[i]) < 0) { fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", files[i]); xmlSecKeyDestroy(key); xmlSecKeysMngrDestroy(mngr); return(NULL); } /* add key to keys manager, from now on keys manager is responsible * for destroying key */ if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) { fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", files[i]); xmlSecKeyDestroy(key); xmlSecKeysMngrDestroy(mngr); return(NULL); } } return(mngr); } ]]> Full program listing Implementing a custom keys store. In many cases, a default built-in list based keys store is not good enough. For example, XML Security Library (and the built-in default keys store) have no synchronization and you'll need to implement a custom keys store if you want to add or remove keys while other threads use the store. Creating a custom keys manager. getKey = xmlSecKeysMngrGetKey; return(mngr); } /**************************************************************************** * * Files Keys Store: we assume that key's name (content of the * element is a name of the file with a key. * Attention: this probably not a good solution for high traffic systems. * ***************************************************************************/ static xmlSecKeyPtr files_keys_store_find_key (xmlSecKeyStorePtr store, const xmlChar* name, xmlSecKeyInfoCtxPtr keyInfoCtx); static xmlSecKeyStoreKlass files_keys_store_klass = { sizeof(xmlSecKeyStoreKlass), sizeof(xmlSecKeyStore), BAD_CAST "files-based-keys-store", /* const xmlChar* name; */ NULL, /* xmlSecKeyStoreInitializeMethod initialize; */ NULL, /* xmlSecKeyStoreFinalizeMethod finalize; */ files_keys_store_find_key, /* xmlSecKeyStoreFindKeyMethod findKey; */ /* reserved for the future */ NULL, /* void* reserved0; */ NULL, /* void* reserved1; */ }; /** * files_keys_store_get_klass: * * The files based keys store klass: we assume that key name is the * key file name, * * Returns files based keys store klass. */ xmlSecKeyStoreId files_keys_store_get_klass(void) { return(&files_keys_store_klass); } /** * files_keys_store_find_key: * @store: the pointer to default keys store. * @name: the desired key name. * @keyInfoCtx: the pointer to node processing context. * * Lookups key in the @store. * * Returns pointer to key or NULL if key not found or an error occurs. */ static xmlSecKeyPtr files_keys_store_find_key(xmlSecKeyStorePtr store, const xmlChar* name, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecKeyPtr key; const xmlChar* p; assert(store); assert(keyInfoCtx); /* it's possible to do not have the key name or desired key type * but we could do nothing in this case */ if((name == NULL) || (keyInfoCtx->keyReq.keyId == xmlSecKeyDataIdUnknown)){ return(NULL); } /* we don't want to open files in a folder other than "current"; * to prevent it limit the characters in the key name to alpha/digit, * '.', '-' or '_'. */ for(p = name; (*p) != '\0'; ++p) { if(!isalnum((*p)) && ((*p) != '.') && ((*p) != '-') && ((*p) != '_')) { return(NULL); } } if((keyInfoCtx->keyReq.keyId == xmlSecKeyDataDsaId) || (keyInfoCtx->keyReq.keyId == xmlSecKeyDataRsaId)) { /* load key from a pem file, if key is not found then it's an error (is it?) */ key = xmlSecCryptoAppKeyLoad(name, xmlSecKeyDataFormatPem, NULL, NULL, NULL); if(key == NULL) { fprintf(stderr,"Error: failed to load pem key from \"%s\"\n", name); return(NULL); } } else { /* otherwise it's a binary key, if key is not found then it's an error (is it?) */ key = xmlSecKeyReadBinaryFile(keyInfoCtx->keyReq.keyId, name); if(key == NULL) { fprintf(stderr,"Error: failed to load key from binary file \"%s\"\n", name); return(NULL); } } /* set key name */ if(xmlSecKeySetName(key, name) < 0) { fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", name); xmlSecKeyDestroy(key); return(NULL); } return(key); } ]]> Full program listing