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.
Example 4. Creating a custom keys manager.
/**
* create_files_keys_mngr:
*
* Creates a files based keys manager: we assume that key name is
* the key file name,
*
* Returns pointer to newly created keys manager or NULL if an error occurs.
*/
xmlSecKeysMngrPtr
create_files_keys_mngr(void) {
xmlSecKeyStorePtr keysStore;
xmlSecKeysMngrPtr mngr;
/* create files based keys store */
keysStore = xmlSecKeyStoreCreate(files_keys_store_get_klass());
if(keysStore == NULL) {
fprintf(stderr, "Error: failed to create keys store.\n");
return(NULL);
}
/* create keys manager */
mngr = xmlSecKeysMngrCreate();
if(mngr == NULL) {
fprintf(stderr, "Error: failed to create keys manager.\n");
xmlSecKeyStoreDestroy(keysStore);
return(NULL);
}
/* add store to keys manager, from now on keys manager destroys the store if needed */
if(xmlSecKeysMngrAdoptKeysStore(mngr, keysStore) < 0) {
fprintf(stderr, "Error: failed to add keys store to keys manager.\n");
xmlSecKeyStoreDestroy(keysStore);
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
/* initialize crypto library specific data in keys manager */
if(xmlSecCryptoKeysMngrInit(mngr) < 0) {
fprintf(stderr, "Error: failed to initialize crypto data in keys manager.\n");
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
/* set the get key callback */
mngr->getKey = xmlSecKeysMngrGetKey;
return(mngr);
}
/****************************************************************************
*
* Files Keys Store: we assume that key's name (content of the
* <dsig:KeyName/> 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 <dsig:KeyInfo/> 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