summaryrefslogtreecommitdiff
path: root/docs/api/chapters/using-keysmngr.sgml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/api/chapters/using-keysmngr.sgml')
-rw-r--r--docs/api/chapters/using-keysmngr.sgml592
1 files changed, 592 insertions, 0 deletions
diff --git a/docs/api/chapters/using-keysmngr.sgml b/docs/api/chapters/using-keysmngr.sgml
new file mode 100644
index 00000000..1c25b3da
--- /dev/null
+++ b/docs/api/chapters/using-keysmngr.sgml
@@ -0,0 +1,592 @@
+<chapter id="xmlsec-notes-keysmngr">
+ <title>Keys manager.</title>
+ <sect1 id="xmlsec-notes-keysmngr-overview">
+ <title>Overview.</title>
+ <para>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".
+ </para>
+ <figure>
+ <title>The keys manager structure.</title>
+ <graphic fileref="images/keysmngr.png" align="center"></graphic>
+ </figure>
+ <para>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
+ <ulink URL="http://www.w3.org/TR/xmldsig-core/#sec-KeyName">&lt;dsig:KeyName/&gt;</ulink>
+ 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).
+ </para>
+ <para>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.
+ </para>
+ </sect1>
+
+ <sect1 id="xmlsec-notes-simple-keys-store">
+ <title>Simple keys store.</title>
+ <para>
+ 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.
+ </para>
+ <para>
+ <example>
+ <title>Initializing keys manager and loading keys from PEM files.</title>
+ <programlisting><![CDATA[
+/**
+ * load_keys:
+ * @files: the list of filenames.
+ * @files_size: the number of filenames in #files.
+ *
+ * Creates default keys manager and load PEM keys from #files in it.
+ * The caller is responsible for destroing returned keys manager using
+ * @xmlSecKeysMngrDestroy.
+ *
+ * Returns the pointer to newly created keys manager or NULL if an error
+ * occurs.
+ */
+xmlSecKeysMngrPtr
+load_keys(char** files, int files_size) {
+ xmlSecKeysMngrPtr mngr;
+ xmlSecKeyPtr key;
+ int i;
+
+ assert(files);
+ assert(files_size > 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);
+}
+ ]]></programlisting>
+ <simpara><link linkend="xmlsec-example-verify2">Full program listing</link></simpara>
+ </example>
+ </para>
+ </sect1>
+
+ <sect1 id="xmlsec-notes-keys-manager-sign-enc">
+ <title>Using keys manager for signatures/encryption.</title>
+ <para>Instead of specifiying signature or encryption key in the
+ corresponding context object (<structfield>signKey</structfield>
+ member of <link linkend="xmlSecDSigCtx">xmlSecDSigCtx</link>
+ structure or <structfield>encKey</structfield> member of
+ <link linkend="xmlSecEncCtx">xmlSecEncCtx</link> 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
+ <ulink URL="http://www.w3.org/TR/xmlenc-core/#sec-EncryptedKey">&lt;EncryptedKey/&gt;</ulink>
+ node could be selected using
+ <ulink URL="http://www.w3.org/TR/xmldsig-core/#sec-KeyName">&lt;dsig:KeyName/&gt;</ulink>
+ node in the template.
+ </para>
+ <para>
+ <example>
+ <title>Encrypting file using a session key and a permanent key from keys manager.</title>
+ <programlisting><![CDATA[
+/**
+ * load_rsa_keys:
+ * @key_file: the key filename.
+ *
+ * Creates default keys manager and load RSA key from #key_file in it.
+ * The caller is responsible for destroing returned keys manager using
+ * @xmlSecKeysMngrDestroy.
+ *
+ * Returns the pointer to newly created keys manager or NULL if an error
+ * occurs.
+ */
+xmlSecKeysMngrPtr
+load_rsa_keys(char* key_file) {
+ xmlSecKeysMngrPtr mngr;
+ xmlSecKeyPtr key;
+
+ assert(key_file);
+
+ /* 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);
+ }
+
+ /* load private RSA key */
+ key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
+ if(key == NULL) {
+ fprintf(stderr,"Error: failed to load rsa key from file \"%s\"\n", key_file);
+ xmlSecKeysMngrDestroy(mngr);
+ return(NULL);
+ }
+
+ /* set key name to the file name, this is just an example! */
+ if(xmlSecKeySetName(key, BAD_CAST key_file) < 0) {
+ fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file);
+ 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", key_file);
+ xmlSecKeyDestroy(key);
+ xmlSecKeysMngrDestroy(mngr);
+ return(NULL);
+ }
+
+ return(mngr);
+}
+
+/**
+ * encrypt_file:
+ * @mngr: the pointer to keys manager.
+ * @xml_file: the encryption template file name.
+ * @key_name: the RSA key name.
+ *
+ * Encrypts #xml_file using a dynamicaly created template, a session DES key
+ * and an RSA key from keys manager.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+int
+encrypt_file(xmlSecKeysMngrPtr mngr, const char* xml_file, const char* key_name) {
+ xmlDocPtr doc = NULL;
+ xmlNodePtr encDataNode = NULL;
+ xmlNodePtr keyInfoNode = NULL;
+ xmlNodePtr encKeyNode = NULL;
+ xmlNodePtr keyInfoNode2 = NULL;
+ xmlSecEncCtxPtr encCtx = NULL;
+ int res = -1;
+
+ assert(mngr);
+ assert(xml_file);
+ assert(key_name);
+
+ /* load template */
+ doc = xmlParseFile(xml_file);
+ if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
+ fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file);
+ goto done;
+ }
+
+ /* create encryption template to encrypt XML file and replace
+ * its content with encryption result */
+ encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId,
+ NULL, xmlSecTypeEncElement, NULL, NULL);
+ if(encDataNode == NULL) {
+ fprintf(stderr, "Error: failed to create encryption template\n");
+ goto done;
+ }
+
+ /* we want to put encrypted data in the <enc:CipherValue/> node */
+ if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) {
+ fprintf(stderr, "Error: failed to add CipherValue node\n");
+ goto done;
+ }
+
+ /* add <dsig:KeyInfo/> */
+ keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
+ if(keyInfoNode == NULL) {
+ fprintf(stderr, "Error: failed to add key info\n");
+ goto done;
+ }
+
+ /* add <enc:EncryptedKey/> 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 <enc:CipherValue/> node */
+ if(xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
+ fprintf(stderr, "Error: failed to add CipherValue node\n");
+ goto done;
+ }
+
+ /* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> */
+ 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);
+}
+
+ ]]></programlisting>
+ <simpara><link linkend="xmlsec-example-encrypt3">Full program listing</link></simpara>
+ </example>
+ </para>
+ </sect1>
+
+ <sect1 id="xmlsec-notes-keys-mngr-verify-decrypt">
+ <title>Using keys manager for verification/decryption.</title>
+ <para>If more than one key could be used for signature or encryption,
+ then using <structfield>signKey</structfield> member of
+ <link linkend="xmlSecDSigCtx">xmlSecDSigCtx</link> structure or
+ <structfield>encKey</structfield> member of
+ <link linkend="xmlSecEncCtx">xmlSecEncCtx</link> structure
+ is not possible. Instead, the application should load known keys in
+ the keys manager and use &lt;dsig:KeyName/&gt; element to specify
+ the key name.
+ </para>
+ <para>
+ <example>
+ <title>Initializing keys manager and loading DES keys from binary files.</title>
+ <programlisting><![CDATA[
+/**
+ * load_des_keys:
+ * @files: the list of filenames.
+ * @files_size: the number of filenames in #files.
+ *
+ * Creates default keys manager and load DES keys from #files in it.
+ * The caller is responsible for destroing returned keys manager using
+ * @xmlSecKeysMngrDestroy.
+ *
+ * Returns the pointer to newly created keys manager or NULL if an error
+ * occurs.
+ */
+xmlSecKeysMngrPtr
+load_des_keys(char** files, int files_size) {
+ xmlSecKeysMngrPtr mngr;
+ xmlSecKeyPtr key;
+ int i;
+
+ assert(files);
+ assert(files_size > 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);
+}
+ ]]></programlisting>
+ <simpara><link linkend="xmlsec-example-decrypt2">Full program listing</link></simpara>
+ </example>
+ </para>
+ </sect1>
+
+ <sect1 id="xmlsec-notes-custom-keys-store">
+ <title>Implementing a custom keys store.</title>
+ <para>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.</para>
+ <para>
+ <example>
+ <title>Creating a custom keys manager.</title>
+ <programlisting><![CDATA[
+/**
+ * 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);
+}
+ ]]></programlisting>
+ <simpara><link linkend="xmlsec-example-decrypt3">Full program listing</link></simpara>
+ </example>
+ </para>
+ </sect1>
+</chapter>