/** 
 * XMLSec library
 *
 * This is free software; see Copyright file in the source
 * distribution for preciese wording.
 * 
 * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
 * Copyright (c) 2003 America Online, Inc.  All rights reserved.
 */
#include "globals.h"

#include <string.h>

#include <nspr.h>
#include <nss.h>
#include <pk11func.h>
#include <cert.h>
#include <keyhi.h>
#include <pkcs12.h>
#include <p12plcy.h>
/*
#include <ssl.h>
*/

#include <xmlsec/xmlsec.h>
#include <xmlsec/keys.h>
#include <xmlsec/transforms.h>
#include <xmlsec/errors.h>

#include <xmlsec/nss/app.h>
#include <xmlsec/nss/crypto.h>
#include <xmlsec/nss/x509.h>
#include <xmlsec/nss/pkikeys.h>
#include <xmlsec/nss/keysstore.h>

/* workaround - NSS exports this but doesn't declare it */
extern CERTCertificate * __CERT_NewTempCertificate		(CERTCertDBHandle *handle,
								 SECItem *derCert,
								 char *nickname,
								 PRBool isperm,
								 PRBool copyDER);
static int xmlSecNssAppCreateSECItem				(SECItem *contents, 
								 const xmlSecByte* data,
								 xmlSecSize dataSize);
static int xmlSecNssAppReadSECItem				(SECItem *contents, 
								 const char *fn);
static PRBool xmlSecNssAppAscii2UCS2Conv			(PRBool toUnicode,
								 unsigned char *inBuf,
								 unsigned int   inBufLen,
								 unsigned char *outBuf,
								 unsigned int   maxOutBufLen,
								 unsigned int  *outBufLen,
								 PRBool         swapBytes);
static SECItem *xmlSecNssAppNicknameCollisionCallback		(SECItem *old_nick,
						    		 PRBool *cancel,
								 void *wincx);
static xmlSecKeyPtr	xmlSecNssAppDerKeyLoadSECItem		(SECItem* secItem);

/**
 * xmlSecNssAppInit:
 * @config:		the path to NSS database files.
 * 
 * General crypto engine initialization. This function is used
 * by XMLSec command line utility and called before 
 * @xmlSecInit function.
 *
 * Returns 0 on success or a negative value otherwise.
 */
int
xmlSecNssAppInit(const char* config) {
    SECStatus rv;

    if(config) {
	rv = NSS_InitReadWrite(config);
	if(rv != SECSuccess) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"NSS_InitReadWrite",
			XMLSEC_ERRORS_R_CRYPTO_FAILED,
			"config=%s", 
			xmlSecErrorsSafeString(config));
	    return(-1);
	}
    } else {
	rv = NSS_NoDB_Init(NULL);
	if(rv != SECSuccess) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"NSS_NoDB_Init",
			XMLSEC_ERRORS_R_CRYPTO_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }

    /* configure PKCS11 */
    PK11_ConfigurePKCS11("manufacturesID", "libraryDescription",
                         "tokenDescription", "privateTokenDescription",
                         "slotDescription", "privateSlotDescription",
                         "fipsSlotDescription", "fipsPrivateSlotDescription", 
			 0, 0); 

    /* setup for PKCS12 */
    PORT_SetUCS2_ASCIIConversionFunction(xmlSecNssAppAscii2UCS2Conv);
    SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
    SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
    SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
    SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
    SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
    SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
    SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);

    return(0);
}

/**
 * xmlSecNssAppShutdown:
 * 
 * General crypto engine shutdown. This function is used
 * by XMLSec command line utility and called after 
 * @xmlSecShutdown function.
 *
 * Returns 0 on success or a negative value otherwise.
 */
int
xmlSecNssAppShutdown(void) {
    SECStatus rv;
/*
    SSL_ClearSessionCache();
*/    
    PK11_LogoutAll();    
    rv = NSS_Shutdown();
    if(rv != SECSuccess) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "NSS_Shutdown",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    return(0);
}


static int
xmlSecNssAppCreateSECItem(SECItem *contents, const xmlSecByte* data, xmlSecSize dataSize) {
    xmlSecAssert2(contents != NULL, -1);
    xmlSecAssert2(data != NULL, -1);

    contents->data = 0;
    if (!SECITEM_AllocItem(NULL, contents, dataSize)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SECITEM_AllocItem",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    if(dataSize > 0) {
	xmlSecAssert2(contents->data != NULL, -1);
	memcpy(contents->data,  data, dataSize);
    }

    return (0);
}

static int
xmlSecNssAppReadSECItem(SECItem *contents, const char *fn) {
    PRFileInfo info;
    PRFileDesc *file = NULL;
    PRInt32 numBytes;
    PRStatus prStatus;
    int ret = -1;

    xmlSecAssert2(contents != NULL, -1);
    xmlSecAssert2(fn != NULL, -1);

    file = PR_Open(fn, PR_RDONLY, 00660);
    if (file == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "PR_Open",
		    XMLSEC_ERRORS_R_IO_FAILED,
		    "filename=%s",
		    xmlSecErrorsSafeString(fn));
	goto done;
    }

    prStatus = PR_GetOpenFileInfo(file, &info);
    if (prStatus != PR_SUCCESS) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "PR_GetOpenFileInfo",
		    XMLSEC_ERRORS_R_IO_FAILED,
		    "filename=%s",
		    xmlSecErrorsSafeString(fn));
	goto done;
    }

    contents->data = 0;
    if (!SECITEM_AllocItem(NULL, contents, info.size)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SECITEM_AllocItem",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }
    
    numBytes = PR_Read(file, contents->data, info.size);
    if (numBytes != info.size) {
	SECITEM_FreeItem(contents, PR_FALSE);
	goto done;
    }

    ret = 0;
done:
    if (file) {
	PR_Close(file);
    }

    return (ret);
}

static PRBool 
xmlSecNssAppAscii2UCS2Conv(PRBool toUnicode,
		           unsigned char *inBuf,
			   unsigned int   inBufLen,
			   unsigned char *outBuf,
			   unsigned int   maxOutBufLen,
			   unsigned int  *outBufLen,
			   PRBool         swapBytes ATTRIBUTE_UNUSED)
{
    SECItem it;
                                          
    if (toUnicode == PR_FALSE) {
	return (PR_FALSE);
    }

    memset(&it, 0, sizeof(it));
    it.data = inBuf;
    it.len = inBufLen;

    return(PORT_UCS2_UTF8Conversion(toUnicode, it.data, it.len,
				    outBuf, maxOutBufLen, outBufLen));
}

static SECItem *
xmlSecNssAppNicknameCollisionCallback(SECItem *old_nick ATTRIBUTE_UNUSED,
		                      PRBool *cancel,
				      void *wincx ATTRIBUTE_UNUSED)
{
    if (cancel == NULL) {
	return (NULL);
    }

    /* XXX not handled yet  */
    *cancel = PR_TRUE;
    return (NULL);
}

/**
 * xmlSecNssAppKeyLoad:
 * @filename:		the key filename.
 * @format:		the key file format.
 * @pwd:		the key file password.
 * @pwdCallback:	the key password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key from a file
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr
xmlSecNssAppKeyLoad(const char *filename, xmlSecKeyDataFormat format,
		    const char *pwd, void* pwdCallback, void* pwdCallbackCtx) {
    SECItem secItem;
    xmlSecKeyPtr res;
    int ret;
    
    xmlSecAssert2(filename != NULL, NULL);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);

    /* read the file contents */
    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppReadSECItem(&secItem, filename);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppReadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(NULL);
    }
    
    res = xmlSecNssAppKeyLoadSECItem(&secItem, format, pwd, pwdCallback, pwdCallbackCtx);
    if(res == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeyLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(NULL);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(res);
}

/**
 * xmlSecNssAppKeyLoadMemory:
 * @data:		the key binary data.
 * @dataSize:		the key binary data size.
 * @format:		the key data format.
 * @pwd:		the key data2 password.
 * @pwdCallback:	the key password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key from a binary @data.
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr
xmlSecNssAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format,
		    const char *pwd, void* pwdCallback, void* pwdCallbackCtx) {
    SECItem secItem;
    xmlSecKeyPtr res;
    int ret;
    
    xmlSecAssert2(data != NULL, NULL);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);

    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppCreateSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(NULL);
    }
    
    res = xmlSecNssAppKeyLoadSECItem(&secItem, format, pwd, pwdCallback, pwdCallbackCtx);
    if(res == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeyLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(NULL);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(res);
}

/**
 * xmlSecNssAppKeyLoadSECItem:
 * @secItem:		the pointer to sec item.
 * @format:		the key format.
 * @pwd:		the key password.
 * @pwdCallback:	the key password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key from a file
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr
xmlSecNssAppKeyLoadSECItem(SECItem* secItem, xmlSecKeyDataFormat format,
		    const char *pwd,
		    void* pwdCallback,
		    void* pwdCallbackCtx) {
    xmlSecKeyPtr key = NULL;

    xmlSecAssert2(secItem != NULL, NULL);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);

    switch(format) {
#ifndef XMLSEC_NO_X509
    case xmlSecKeyDataFormatPkcs12:
	key = xmlSecNssAppPkcs12LoadSECItem(secItem, pwd, pwdCallback, pwdCallbackCtx);
        if(key == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecNssAppPkcs12LoadSECItem",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(NULL);	
	}
	break;
    case xmlSecKeyDataFormatCertDer: 
	key = xmlSecNssAppKeyFromCertLoadSECItem(secItem, format);
        if(key == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecNssAppKeyFromCertLoadSECItem",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(NULL);	
	}
	break;
#endif /* XMLSEC_NO_X509 */
    case xmlSecKeyDataFormatDer:
	key = xmlSecNssAppDerKeyLoadSECItem(secItem);
        if(key == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecNssAppDerKeyLoadSECItem",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(NULL);	
	}
	break;
    default:
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeyLoad",
		    XMLSEC_ERRORS_R_INVALID_FORMAT,
		    "format=%d", format);
	    return(NULL);	
    }

    return(key);
}

static xmlSecKeyPtr
xmlSecNssAppDerKeyLoadSECItem(SECItem* secItem) {
    xmlSecKeyPtr key = NULL;
    xmlSecKeyPtr retval = NULL;
    xmlSecKeyDataPtr data = NULL;
    int ret;
    SECKEYPublicKey *pubkey = NULL;
    SECKEYPrivateKey *privkey = NULL;
    CERTSubjectPublicKeyInfo *spki = NULL;
    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
    SECItem nickname;
    PK11SlotInfo *slot = NULL;
    SECStatus status;

    xmlSecAssert2(secItem != NULL, NULL);

    /* we're importing a key about which we know nothing yet, just use the 
     * internal slot 
     */
    slot = xmlSecNssGetInternalKeySlot();
    if (slot == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssGetInternalKeySlot",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }

    nickname.len = 0;
    nickname.data = NULL;


    /* TRY PRIVATE KEY FIRST 
     * Note: This expects the key to be in PrivateKeyInfo format. The
     * DER files created from PEM via openssl utilities aren't in that 
     * format
     */
    status = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, secItem, 
			    &nickname, NULL, PR_FALSE, 
			    PR_TRUE, KU_ALL, &privkey, NULL);
    if (status != SECSuccess) {
	/* TRY PUBLIC KEY */
	spki = SECKEY_DecodeDERSubjectPublicKeyInfo(secItem);
	if (spki == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"SECKEY_DecodeDERSubjectPublicKeyInfo",
			XMLSEC_ERRORS_R_CRYPTO_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	}
	
	pubkey = SECKEY_ExtractPublicKey(spki);
	if (pubkey == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"SECKEY_ExtractPublicKey",
			XMLSEC_ERRORS_R_CRYPTO_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    goto done;
	}
    }

    data = xmlSecNssPKIAdoptKey(privkey, pubkey);
    if(data == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssPKIAdoptKey",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }    
    privkey = NULL;
    pubkey = NULL;

    key = xmlSecKeyCreate();
    if(key == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyCreate",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }
    
    ret = xmlSecKeySetValue(key, data);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeySetValue",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "data=%s",
		    xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)));
	goto done;
    }
    retval = key;
    key = NULL;
    data = NULL;
    

done:
    if(slot != NULL) {
	PK11_FreeSlot(slot);
    }
    if(privkey != NULL) {
	SECKEY_DestroyPrivateKey(privkey);
    }
    if(pubkey != NULL) {
	SECKEY_DestroyPublicKey(pubkey);
    }
    if(key != NULL) {
	xmlSecKeyDestroy(key);
    }
    if(data != NULL) {
	xmlSecKeyDataDestroy(data);
    }
    if(spki != NULL) {
	SECKEY_DestroySubjectPublicKeyInfo(spki);
    }
    if(epki != NULL) {
	SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
    }
    return (retval);
}

#ifndef XMLSEC_NO_X509
/**
 * xmlSecNssAppKeyCertLoad:
 * @key:		the pointer to key.
 * @filename:		the certificate filename.
 * @format:		the certificate file format.
 *
 * Reads the certificate from $@filename and adds it to key 
 * 
 * Returns 0 on success or a negative value otherwise.
 */
int		
xmlSecNssAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, xmlSecKeyDataFormat format) {
    SECItem secItem;
    int ret;
    
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(filename != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);

    /* read the file contents */
    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppReadSECItem(&secItem, filename);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppReadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssAppKeyCertLoadSECItem(key, &secItem, format);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeyCertLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(-1);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(0);
}

/**
 * xmlSecNssAppKeyCertLoadMemory:
 * @key:		the pointer to key.
 * @data:		the key binary data.
 * @dataSize:		the key binary data size.
 * @format:		the certificate format.
 *
 * Reads the certificate from @data and adds it to key 
 * 
 * Returns 0 on success or a negative value otherwise.
 */
int		
xmlSecNssAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format) {
    SECItem secItem;
    int ret;
    
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);

    /* read the file contents */
    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppCreateSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssAppKeyCertLoadSECItem(key, &secItem, format);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeyCertLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(-1);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(0);
}

/**
 * xmlSecNssAppKeyCertLoadSECItem:
 * @key:		the pointer to key.
 * @secItem:		the pointer to SECItem.
 * @format:		the certificate format.
 *
 * Reads the certificate from @secItem and adds it to key 
 * 
 * Returns 0 on success or a negative value otherwise.
 */
int		
xmlSecNssAppKeyCertLoadSECItem(xmlSecKeyPtr key, SECItem* secItem, xmlSecKeyDataFormat format) {
    CERTCertificate *cert=NULL;
    xmlSecKeyDataPtr data;
    int ret;

    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(secItem != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);
    
    data = xmlSecKeyEnsureData(key, xmlSecNssKeyDataX509Id);
    if(data == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyEnsureData",		    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "transform=%s",
		    xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id)));
	return(-1);
    }

    switch(format) {
    case xmlSecKeyDataFormatPkcs8Der:
    case xmlSecKeyDataFormatDer:
	cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
					 secItem, NULL, PR_FALSE, PR_TRUE);
	if(cert == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"__CERT_NewTempCertificate", 
		        XMLSEC_ERRORS_R_CRYPTO_FAILED,
		        "format=%d", format);
	    return(-1);    
	}
	break;
    default:
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_INVALID_FORMAT,
		    "format=%d", format); 
	return(-1);
    }
    
    xmlSecAssert2(cert != NULL, -1);
    ret = xmlSecNssKeyDataX509AdoptCert(data, cert);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeyDataX509AdoptCert",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "data=%s",
		    xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)));
	CERT_DestroyCertificate(cert);
	return(-1);    
    }
    
    return(0);        
}

/**
 * xmlSecNssAppPkcs12Load:
 * @filename:		the PKCS12 key filename.
 * @pwd:		the PKCS12 file password.
 * @pwdCallback:	the password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key and all associated certificates from the PKCS12 file.
 * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass
 * in format=xmlSecKeyDataFormatPkcs12.
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr	
xmlSecNssAppPkcs12Load(const char *filename, const char *pwd,
		       void *pwdCallback ATTRIBUTE_UNUSED, 
		       void* pwdCallbackCtx ATTRIBUTE_UNUSED) {
    SECItem secItem;
    xmlSecKeyPtr res;
    int ret;
    
    xmlSecAssert2(filename != NULL, NULL);

    /* read the file contents */
    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppReadSECItem(&secItem, filename);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppReadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(NULL);
    }
    
    res = xmlSecNssAppPkcs12LoadSECItem(&secItem, pwd, pwdCallback, pwdCallbackCtx);
    if(res == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppPkcs12LoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(NULL);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(res);
}

/**
 * xmlSecNssAppPkcs12LoadMemory:
 * @data:		the key binary data.
 * @dataSize:		the key binary data size.
 * @pwd:		the PKCS12 password.
 * @pwdCallback:	the password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key and all associated certificates from the PKCS12 binary data.
 * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass
 * in format=xmlSecKeyDataFormatPkcs12.
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr	
xmlSecNssAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, const char *pwd,
		       void *pwdCallback ATTRIBUTE_UNUSED, 
		       void* pwdCallbackCtx ATTRIBUTE_UNUSED) {
    SECItem secItem;
    xmlSecKeyPtr res;
    int ret;
    
    xmlSecAssert2(data != NULL, NULL);

    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppCreateSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(NULL);
    }
    
    res = xmlSecNssAppPkcs12LoadSECItem(&secItem, pwd, pwdCallback, pwdCallbackCtx);
    if(res == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppPkcs12LoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(NULL);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(res);
}


/**
 * xmlSecNssAppPkcs12LoadSECItem:
 * @secItem:		the @SECItem object.
 * @pwd:		the PKCS12 file password.
 * @pwdCallback:	the password callback.
 * @pwdCallbackCtx:	the user context for password callback.
 *
 * Reads key and all associated certificates from the PKCS12 SECItem.
 * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass
 * in format=xmlSecKeyDataFormatPkcs12.
 *
 * Returns pointer to the key or NULL if an error occurs.
 */
xmlSecKeyPtr	
xmlSecNssAppPkcs12LoadSECItem(SECItem* secItem, const char *pwd,
		       void *pwdCallback ATTRIBUTE_UNUSED, 
		       void* pwdCallbackCtx ATTRIBUTE_UNUSED) {
    xmlSecKeyPtr key = NULL;
    xmlSecKeyDataPtr data = NULL;
    xmlSecKeyDataPtr x509Data = NULL;
    int ret;
    PK11SlotInfo *slot = NULL;
    SECItem pwditem;
    SECItem uc2_pwditem;
    SECStatus rv;
    SECKEYPrivateKey *privkey = NULL;
    SECKEYPublicKey *pubkey = NULL;
    CERTCertList *certlist = NULL;
    CERTCertListNode    *head = NULL;
    CERTCertificate     *cert = NULL;
    CERTCertificate     *tmpcert = NULL;
    SEC_PKCS12DecoderContext *p12ctx = NULL;


    xmlSecAssert2((secItem != NULL), NULL);

    if (pwd == NULL) {
	pwd = "";
    }
    memset(&uc2_pwditem, 0, sizeof(uc2_pwditem));
        
    /* we're importing a key about which we know nothing yet, just use the 
     * internal slot. We have no criteria to choose a slot. 
     */
    slot = xmlSecNssGetInternalKeySlot();
    if (slot == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssGetInternalKeySlot",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }

    pwditem.data = (unsigned char *)pwd;
    pwditem.len = strlen(pwd)+1;
    if (!SECITEM_AllocItem(NULL, &uc2_pwditem, 2*pwditem.len)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SECITEM_AllocItem",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }

    if (PORT_UCS2_ASCIIConversion(PR_TRUE, pwditem.data, pwditem.len,
                              uc2_pwditem.data, 2*pwditem.len,
                              &(uc2_pwditem.len), 0) == PR_FALSE) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "PORT_UCS2_ASCIIConversion",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }

    p12ctx = SEC_PKCS12DecoderStart(&uc2_pwditem, slot, NULL,
                                    NULL, NULL, NULL, NULL, NULL);
    if (p12ctx == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderStart",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    rv = SEC_PKCS12DecoderUpdate(p12ctx, secItem->data, secItem->len);
    if (rv != SECSuccess) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderUpdate",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    rv = SEC_PKCS12DecoderVerify(p12ctx);
    if (rv != SECSuccess) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderVerify",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    rv = SEC_PKCS12DecoderValidateBags(p12ctx, xmlSecNssAppNicknameCollisionCallback);
    if (rv != SECSuccess) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderValidateBags",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    rv = SEC_PKCS12DecoderImportBags(p12ctx);
    if (rv != SECSuccess) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderImportBags",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    certlist = SEC_PKCS12DecoderGetCerts(p12ctx);
    if (certlist == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "SEC_PKCS12DecoderGetCerts",
		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        goto done;
    }

    x509Data = xmlSecKeyDataCreate(xmlSecNssKeyDataX509Id);
    if(x509Data == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyDataCreate",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "transform=%s",
		    xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id)));
	goto done;
    }    

    for (head = CERT_LIST_HEAD(certlist);
         !CERT_LIST_END(head, certlist);
         head = CERT_LIST_NEXT(head)) {
        cert = head->cert;
        privkey = PK11_FindKeyByAnyCert(cert, NULL);

        if (privkey != NULL) {
	    if (data != NULL) {
		/* we already found a private key.
		 * assume the first private key we find is THE ONE 
		 */
		SECKEY_DestroyPrivateKey(privkey);
		privkey = NULL;
	    } else {
	        pubkey = CERT_ExtractPublicKey(cert);
	        if (pubkey == NULL) {
		    xmlSecError(XMLSEC_ERRORS_HERE,
			        NULL,
			        "CERT_ExtractPublicKey",
			        XMLSEC_ERRORS_R_CRYPTO_FAILED,
			        XMLSEC_ERRORS_NO_MESSAGE);
		    goto done;
	        }
	        data = xmlSecNssPKIAdoptKey(privkey, pubkey);
	        if(data == NULL) {
		    xmlSecError(XMLSEC_ERRORS_HERE,
			        NULL,
			        "xmlSecNssPKIAdoptKey",
			        XMLSEC_ERRORS_R_XMLSEC_FAILED,
			        XMLSEC_ERRORS_NO_MESSAGE);
		    goto done;
	        }

	        pubkey = NULL;
	        privkey = NULL;

		tmpcert = CERT_DupCertificate(cert);
        	if(tmpcert == NULL) {
    	    	    xmlSecError(XMLSEC_ERRORS_HERE,
				NULL,
				"CERT_DupCertificate",
				XMLSEC_ERRORS_R_CRYPTO_FAILED,
				"data=%s",
				xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
	    	    goto done;	
		}

        	ret = xmlSecNssKeyDataX509AdoptKeyCert(x509Data, tmpcert);
        	if(ret < 0) {
	    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        	NULL,
		        	"xmlSecNssKeyDataX509AdoptKeyCert",
		        	XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        	"data=%s",
		        	xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
		    CERT_DestroyCertificate(tmpcert);
	    	    goto done;
                }

	    }
        }

	tmpcert = CERT_DupCertificate(cert);
        if(tmpcert == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"CERT_DupCertificate",
			XMLSEC_ERRORS_R_CRYPTO_FAILED,
			"data=%s",
			xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
	    goto done;	
	}
	ret = xmlSecNssKeyDataX509AdoptCert(x509Data, tmpcert);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecNssKeyDataX509AdoptCert",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"data=%s",
		        xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
	    CERT_DestroyCertificate(tmpcert);
	    goto done;
	}

    } /* end for loop */

    if (data == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppPkcs12Load",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "private key not found in PKCS12 file");
	goto done;
     }

    key = xmlSecKeyCreate();
    if(key == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyCreate",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	goto done;
    }    
    
    ret = xmlSecKeySetValue(key, data);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeySetValue",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "data=%s",
		    xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
	xmlSecKeyDestroy(key);
	key = NULL;
	goto done;
    }
    data = NULL;

    ret = xmlSecKeyAdoptData(key, x509Data);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyAdoptData",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "data=%s",
		    xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data)));
	xmlSecKeyDestroy(key);
	key = NULL;
	goto done;
    }
    x509Data = NULL;
    
done:
    if (p12ctx) {
        SEC_PKCS12DecoderFinish(p12ctx);
    }
    SECITEM_FreeItem(&uc2_pwditem, PR_FALSE);
    if (slot) {
        PK11_FreeSlot(slot);
    }
    if (certlist) {
        CERT_DestroyCertList(certlist);
    }
    if(x509Data != NULL) {
	xmlSecKeyDataDestroy(x509Data);
    }
    if(data != NULL) {
        xmlSecKeyDataDestroy(data);
    }
    if (privkey) {
	SECKEY_DestroyPrivateKey(privkey);
    }
    if (pubkey) {
	SECKEY_DestroyPublicKey(pubkey);
    }

    return(key);    
}

/**
 * xmlSecNssAppKeyFromCertLoadSECItem:
 * @secItem:		the @SECItem object.
 * @format:		the cert format.
 *
 * Loads public key from cert.
 *
 * Returns pointer to key or NULL if an error occurs.
 */
xmlSecKeyPtr 
xmlSecNssAppKeyFromCertLoadSECItem(SECItem* secItem, xmlSecKeyDataFormat format) {
    xmlSecKeyPtr key;
    xmlSecKeyDataPtr keyData;
    xmlSecKeyDataPtr certData;
    CERTCertificate *cert=NULL;
    int ret;

    xmlSecAssert2(secItem != NULL, NULL);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);
    
    /* load cert */
    switch(format) {
    case xmlSecKeyDataFormatCertDer:
	cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
					 secItem, NULL, PR_FALSE, PR_TRUE);
	if(cert == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"__CERT_NewTempCertificate", 
		        XMLSEC_ERRORS_R_CRYPTO_FAILED,
		        "format=%d", format);
	    return(NULL);    
	}
	break;
    default:
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_INVALID_FORMAT,
		    "format=%d", format); 
	return(NULL);
    }

    /* get key value */
    keyData = xmlSecNssX509CertGetKey(cert);
    if(keyData == NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssX509CertGetKey",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	CERT_DestroyCertificate(cert);
	return(NULL);    
    }
    
    /* create key */
    key = xmlSecKeyCreate();
    if(key == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyCreate",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDataDestroy(keyData);
	CERT_DestroyCertificate(cert);
	return(NULL);    
    }    
    
    /* set key value */
    ret = xmlSecKeySetValue(key, keyData);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeySetValue",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDestroy(key);
	xmlSecKeyDataDestroy(keyData);
	CERT_DestroyCertificate(cert);
	return(NULL);    
    }

    /* create cert data */ 
    certData = xmlSecKeyEnsureData(key, xmlSecNssKeyDataX509Id);
    if(certData == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyEnsureData",		    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDestroy(key);
	CERT_DestroyCertificate(cert);
	return(NULL);    
    }

    /* put cert in the cert data */
    ret = xmlSecNssKeyDataX509AdoptCert(certData, cert);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeyDataX509AdoptCert",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDestroy(key);
	CERT_DestroyCertificate(cert);
	return(NULL);    
    }
    
    return(key);
}


/**
 * xmlSecNssAppKeysMngrCertLoad:
 * @mngr: 		the pointer to keys manager.
 * @filename: 		the certificate file.
 * @format:		the certificate file format (PEM or DER).
 * @type: 		the certificate type (trusted/untrusted).
 *
 * Reads cert from @filename and adds to the list of trusted or known
 * untrusted certs in @store
 *
 * Returns 0 on success or a negative value otherwise.
 */
int
xmlSecNssAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, 
			     xmlSecKeyDataFormat format, 
			     xmlSecKeyDataType type) {
    SECItem secItem;
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(filename != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);

    /* read the file contents */
    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppReadSECItem(&secItem, filename);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppReadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssAppKeysMngrCertLoadSECItem(mngr, &secItem, format, type);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeysMngrCertLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(-1);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(0);
}

/**
 * xmlSecNssAppKeysMngrCertLoadMemory:
 * @mngr: 		the pointer to keys manager.
 * @data:		the key binary data.
 * @dataSize:		the key binary data size.
 * @format:		the certificate format (PEM or DER).
 * @type: 		the certificate type (trusted/untrusted).
 *
 * Reads cert from @data and adds to the list of trusted or known
 * untrusted certs in @store
 *
 * Returns 0 on success or a negative value otherwise.
 */
int
xmlSecNssAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, 
			     xmlSecSize dataSize, xmlSecKeyDataFormat format, 
			     xmlSecKeyDataType type) {
    SECItem secItem;
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);

    memset(&secItem, 0, sizeof(secItem));
    ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppCreateSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssAppKeysMngrCertLoadSECItem(mngr, &secItem, format, type);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssAppKeysMngrCertLoadSECItem",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	SECITEM_FreeItem(&secItem, PR_FALSE);
	return(-1);
    }

    SECITEM_FreeItem(&secItem, PR_FALSE);
    return(0);
}

/**
 * xmlSecNssAppKeysMngrCertLoadSECItem:
 * @mngr: 		the pointer to keys manager.
 * @secItem:		the pointer to SECItem.
 * @format:		the certificate format (PEM or DER).
 * @type: 		the certificate type (trusted/untrusted).
 *
 * Reads cert from @secItem and adds to the list of trusted or known
 * untrusted certs in @store
 *
 * Returns 0 on success or a negative value otherwise.
 */
int
xmlSecNssAppKeysMngrCertLoadSECItem(xmlSecKeysMngrPtr mngr, SECItem* secItem, 
			     xmlSecKeyDataFormat format, 
			     xmlSecKeyDataType type) {
    xmlSecKeyDataStorePtr x509Store;
    CERTCertificate* cert;
    int ret;

    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(secItem != NULL, -1);
    xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);
    
    x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecNssX509StoreId);
    if(x509Store == NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    "xmlSecKeysMngrGetDataStore",
                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
                    "xmlSecNssX509StoreId");
        return(-1);
    }

    switch(format) {
    case xmlSecKeyDataFormatDer:
	cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
					 secItem, NULL, PR_FALSE, PR_TRUE);
	if(cert == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"__CERT_NewTempCertificate", 
		        XMLSEC_ERRORS_R_CRYPTO_FAILED,
		        "format=%d", format);
	    return(-1);    
	}
	break;
    default:
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_INVALID_FORMAT,
		    "format=%d", format); 
	return(-1);
    }
    
    ret = xmlSecNssX509StoreAdoptCert(x509Store, cert, type);
    if(ret < 0) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    "xmlSecNssX509StoreAdoptCert",
                    XMLSEC_ERRORS_R_XMLSEC_FAILED,
                    XMLSEC_ERRORS_NO_MESSAGE);
	CERT_DestroyCertificate(cert);
        return(-1);
    }

    return(0);
}

#endif /* XMLSEC_NO_X509 */

/**
 * xmlSecNssAppDefaultKeysMngrInit:
 * @mngr: 		the pointer to keys manager.
 *
 * Initializes @mngr with NSS keys store #xmlSecNssKeysStoreId
 * and a default NSS crypto key data stores.
 *
 * Returns 0 on success or a negative value otherwise.
 */ 
int
xmlSecNssAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) {
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);

    /* create NSS keys store if needed */        
    if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) {
	xmlSecKeyStorePtr keysStore;

	keysStore = xmlSecKeyStoreCreate(xmlSecNssKeysStoreId);
	if(keysStore == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecKeyStoreCreate",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"xmlSecNssKeysStoreId");
	    return(-1);
	}
	
	ret = xmlSecKeysMngrAdoptKeysStore(mngr, keysStore);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecKeysMngrAdoptKeysStore",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecKeyStoreDestroy(keysStore);
	    return(-1);        
	}
    }

    ret = xmlSecNssKeysMngrInit(mngr);    
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeysMngrInit",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1); 
    }
    
    mngr->getKey = xmlSecKeysMngrGetKey;
    return(0);
}

/**
 * xmlSecNssAppDefaultKeysMngrAdoptKey:
 * @mngr: 		the pointer to keys manager.
 * @key:		the pointer to key.
 *
 * Adds @key to the keys manager @mngr created with #xmlSecNssAppDefaultKeysMngrInit
 * function.
 *  
 * Returns 0 on success or a negative value otherwise.
 */ 
int 
xmlSecNssAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key) {
    xmlSecKeyStorePtr store;
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    
    store = xmlSecKeysMngrGetKeysStore(mngr);
    if(store == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeysMngrGetKeysStore",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssKeysStoreAdoptKey(store, key);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeysStoreAdoptKey",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    return(0);
}

/**
 * xmlSecNssAppDefaultKeysMngrLoad:
 * @mngr: 		the pointer to keys manager.
 * @uri:		the uri.
 *
 * Loads XML keys file from @uri to the keys manager @mngr created 
 * with #xmlSecNssAppDefaultKeysMngrInit function.
 *  
 * Returns 0 on success or a negative value otherwise.
 */ 
int 
xmlSecNssAppDefaultKeysMngrLoad(xmlSecKeysMngrPtr mngr, const char* uri) {
    xmlSecKeyStorePtr store;
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(uri != NULL, -1);
    
    store = xmlSecKeysMngrGetKeysStore(mngr);
    if(store == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeysMngrGetKeysStore",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssKeysStoreLoad(store, uri, mngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeysStoreLoad",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "uri=%s", xmlSecErrorsSafeString(uri));
	return(-1);
    }
    
    return(0);
}

/**
 * xmlSecNssAppDefaultKeysMngrSave:
 * @mngr: 		the pointer to keys manager.
 * @filename:		the destination filename.
 * @type:		the type of keys to save (public/private/symmetric).
 *
 * Saves keys from @mngr to  XML keys file.
 *  
 * Returns 0 on success or a negative value otherwise.
 */ 
int 
xmlSecNssAppDefaultKeysMngrSave(xmlSecKeysMngrPtr mngr, const char* filename, xmlSecKeyDataType type) {
    xmlSecKeyStorePtr store;
    int ret;
    
    xmlSecAssert2(mngr != NULL, -1);
    xmlSecAssert2(filename != NULL, -1);
    
    store = xmlSecKeysMngrGetKeysStore(mngr);
    if(store == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeysMngrGetKeysStore",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    ret = xmlSecNssKeysStoreSave(store, filename, type);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecNssKeysStoreSave",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "filename%s", xmlSecErrorsSafeString(filename));
	return(-1);
    }
    
    return(0);
}

/**
 * xmlSecNssAppGetDefaultPwdCallback:
 *
 * Gets default password callback.
 *
 * Returns default password callback.
 */
void*
xmlSecNssAppGetDefaultPwdCallback(void) {
    return(NULL);
}

