[xmlsec] Dos the XMLSec library support multithreading?

StackWood stackwood at 263.net
Wed May 12 23:26:50 PDT 2004


dear,

   I have to paste my program below, and I appreciate your check for me.
   I compile with gcc in LINUX9 and use openssl to encrypt.
   When I begin to encryption, I just use only one thread but program fail in function xmlSecEncCtxXmlEncrypt(), the error message is "Segmentation fault". Now I expect to run in multithreading enviroment, so I wish to get some help. I appreciate you.

************************************************encrypt.c**************************************************************
 
#define XMLSEC_CRYPTO_OPENSSL  //use openssl to encrypt
#include <pthread.h>  //the multithreading is needed

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#ifndef XMLSEC_NO_XSLT
#include <libxslt/xslt.h>
#endif /* XMLSEC_NO_XSLT */

#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#include <xmlsec/xmlenc.h>
#include <xmlsec/templates.h>
#include <xmlsec/crypto.h>

struct fileInfo
{
  char *xmlFile;
  char *nodeName;
//  char *keyFile;
  xmlSecKeysMngrPtr mngr;
};

xmlSecKeysMngrPtr load_rsa_keys(xmlSecKeysMngrPtr mngr, char* key_file);
int encrypt_file(struct fileInfo *xmlInfo);

int main(int argc, char **argv) 
{
    xmlSecKeysMngrPtr mngr;
    pthread_t id;
    struct fileInfo *xmlInfo;
    int num,i,ret;
    
    if (argc<2||((argc-1)%3)!=0)
    {
    	fprintf(stderr, "Error: wrong number of arguments.\n");
	fprintf(stderr, "Usage: %s <xml-file> <node-name> <key-file> [<xml-file> ...] ...\n", argv[0]);
	fprintf(stderr, "Usage: %s <XML file name> <node name want to encrypt in XML file> <encrypt key file name>...\n", argv[0]);
	return(1);
    }

    num=(argc-1)/3;

    xmlInfo=(struct fileInfo *)malloc(sizeof(struct fileInfo));

    /* Init libxml and libxslt libraries */
    xmlInitParser();
    LIBXML_TEST_VERSION
    xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
    xmlSubstituteEntitiesDefault(1);
#ifndef XMLSEC_NO_XSLT
    xmlIndentTreeOutput = 1; 
#endif /* XMLSEC_NO_XSLT */
        	
    /* Init xmlsec library */
    if(xmlSecInit() < 0) {
	fprintf(stderr, "Error: xmlsec initialization failed.\n");
	return(-1);
    }

    /* Check loaded library version */
    if(xmlSecCheckVersion() != 1) {
	fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n");
	return(-1);
    }
    
    /* Load default crypto engine if we are supporting dynamic
     * loading for xmlsec-crypto libraries. Use the crypto library
     * name ("openssl", "nss", etc.) to load corresponding 
     * xmlsec-crypto library.
     */
#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
    if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
	fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n"
			"that you have it installed and check shared libraries path\n"
			"(LD_LIBRARY_PATH) envornment variable.\n");
	return(-1);	
    }
#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */

    /* Init crypto library */
    if(xmlSecCryptoAppInit(NULL) < 0) {
	fprintf(stderr, "Error: crypto initialization failed.\n");
	return(-1);
    }

    /* Init xmlsec-crypto library */
    if(xmlSecCryptoInit() < 0) {
	fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n");
	return(-1);
    }

    /* init xmlSecKeysMngrPtr in the main */
    mngr = xmlSecKeysMngrCreate();
    if(mngr == NULL) {
        fprintf(stderr, "Error: failed to create keys manager.\n");
        return(-1);
    }

    if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
        fprintf(stderr, "Error: failed to initialize keys manager.\n");
        xmlSecKeysMngrDestroy(mngr);
        return(-1);
    }

    fprintf(stderr, "Begine to process in thread.\n");

    /* begin to enter thread to process */
    for (i=0;i<num;i++)
    {
      xmlInfo->xmlFile=argv[3*i+1];
      xmlInfo->nodeName=argv[3*i+2];

      /* load keys into key manager*/
      mngr = load_rsa_keys(mngr, argv[3*i+3]);
      if(mngr == NULL) {
        goto end;
      }

      xmlInfo->mngr=mngr;

      ret=pthread_create(&id,NULL,(void *) encrypt_file,(void *) xmlInfo);
      if(ret!=0)
      {
        fprintf(stderr, "ERROR: Create pthread error!\n");
        return(-1);
      }
    }

end:

    /* destroy keys manager */
    xmlSecKeysMngrDestroy(mngr);
    
    /* Shutdown xmlsec-crypto library */
    xmlSecCryptoShutdown();
    
    /* Shutdown crypto library */
    xmlSecCryptoAppShutdown();
    
    /* Shutdown xmlsec library */
    xmlSecShutdown();

    /* Shutdown libxslt/libxml */
#ifndef XMLSEC_NO_XSLT
    xsltCleanupGlobals();            
#endif /* XMLSEC_NO_XSLT */
    xmlCleanupParser();

    free(xmlInfo);
    
    return(0);
}

/**
 * load_rsa_keys:
 * @key_file:		the key filename.
 *
 * Creates simple 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(xmlSecKeysMngrPtr mngr, char* key_file) {
    xmlSecKeyPtr key;
    BIO *keyIO;
    
    assert(key_file);

    /* get public key from input certificate */
    if ((keyIO = BIO_new(BIO_s_file())) == NULL)	
    {
        fprintf(stderr,"Error: failed to create BIO file \n");
	return;
    }

    if (BIO_read_filename(keyIO,key_file) <= 0)
    {
        fprintf(stderr,"Error: failed to read certificate from file \"%s\"\n", key_file);
        BIO_free(keyIO);
	return;
    }

    key=xmlSecOpenSSLAppKeyFromCertLoadBIO(keyIO,xmlSecKeyDataFormatPem);
    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 "prvkey.pem") < 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);
    }

    fprintf(stderr, "End to complete mngr.\n");

    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(struct fileInfo *xmlInfo)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr encDataNode = NULL;
    xmlNodePtr keyInfoNode = NULL;
    xmlNodePtr encKeyNode = NULL;
    xmlNodePtr keyInfoNode2 = NULL;
    xmlSecEncCtxPtr encCtx = NULL;

    xmlNodePtr encNode = NULL;
    xmlSecKeysMngrPtr mngr;

    int id;
    int res = -1;

    FILE *fp;

    char* xml_node;
    char* xml_file;
//  char* xml_key;
    char saveName[20];    

    xml_file=xmlInfo->xmlFile;
    xml_node=xmlInfo->nodeName;
//  xml_key=xmlInfo->keyFile;
    mngr=xmlInfo->mngr;

#if 0
    /* load keys into key manager*/
    mngr = load_rsa_keys(mngr, xml_key);
    if(mngr == NULL) {
        goto done;
    }
#endif
    
    /* load temilate */
    doc = xmlParseFile(xml_file);
    if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
	fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file);
	goto done;	
    }

    /* this is a sample that find Signature node to be encrypted */
    encNode = xmlSecFindNode(xmlDocGetRootElement(doc), xml_node, NULL);
    if(encNode == NULL) {
        fprintf(stderr, "Error: not found %s Node \n", xml_node);
        goto done;
    }

    encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformAes128CbcId,
                                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, 
				    xmlSecTransformRsaPkcs1Id, 
				    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, "Private Key") == 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 AES128 key */
    encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 128, xmlSecKeyDataTypeSession);
    if(encCtx->encKey == NULL) {
        fprintf(stderr,"Error: failed to generate session des key\n");
        goto done;
    }

    fprintf(stderr,"Begine to encrypt the Node...\n");
    
    /* encrypt the data */
    if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, encNode) < 0) {
        fprintf(stderr,"Error: encryption failed\n");
	goto done;
    }

    fprintf(stderr,"End to encrypt the Node...\n");

    /* we template is inserted in the doc */
    encDataNode = NULL;
        
    /* print encrypted data with document to stdout */
    xmlDocDump(stdout, doc);

    /* save to file by the threadID name */ 
    id=pthread_self();
    id=abs(id);
    sprintf(saveName, "%d.xml", id);
 
    if((fp=fopen(saveName, "w"))==NULL)
    {
      fprintf(stderr,"ERROR: cannot open file %s.",saveName);
      goto done;
    }

    /* print encrypted data with document to file */
    xmlDocDump(fp, doc);
    
    /* success */
    res = 0;

done:    

    /* cleanup */
    if(encCtx != NULL) {
	xmlSecEncCtxDestroy(encCtx);
    }

    if(encDataNode != NULL) {
	xmlFreeNode(encDataNode);
    }
        
    if(doc != NULL) {
	xmlFreeDoc(doc); 
    }

    return(res);
}

**************************************************************************************************************


>Yes, the library does support multithreading. xmlSecSigCtx
>and xmlSecEncCtx are supposed to be used to do one signature
>at a time and from one thread at a time. xmlSecKeysMngr can
>be shared by many threads *for reading*. There are no
>sychronizaton inside the library itself. If you want to read
>and write to xmlSecKeysMngr in the same time then you have
>to implement your own keys manager.
>
>You did not provide information about OS/crypto library you use
>or the stack of your crash. It might happen that there is an issue
>with particular crypto library that might require additional "per
>thread" initialization.
>
>Aleksey
>

Best, 
				 
StackWood
        stackwood at 263.net
          2004-05-12





More information about the xmlsec mailing list