--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlseccrypto/src/xmlsecc_evpwrapper.cpp Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,761 @@
+/*
+* Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Methods that allows to sign and verify data.
+*
+*/
+
+
+/** A wrapper of OpenSSL evp.c functions to Symbian **/
+
+#include <stdlib.h>
+#include <string.h>
+#include <signed.h>
+#include "xmlsecc_config.h"
+#ifndef XMLSEC_NO_X509
+#include <x509cert.h>
+#endif //XMLSEC_NO_X509
+
+#include "xmlsecc_evpwrapper.h"
+#include "xmlsecc_cryptowrapper.h"
+
+#include "xmlsecmsymbiankeystore.h"
+
+#include "xmlsec_error_flag.h"
+
+_LIT8(KRsaKeyName, "xmlSecRsaKey");
+
+const TInt KAssertionLeave = -32380;
+
+// MK: Flag - is active scheduler created by xml sec or not.
+static TBool desActiv = FALSE;
+
+struct ScKeyStore
+{
+ // A handle to Symbian key store
+ CSymbianKeyStore *iKeyStore;
+ // A handle to the public key read from the certificate
+ CSubjectPublicKeyInfo *iSubjectPublicKeyInfo;
+};
+
+// -----------------------------------------------------------------------------
+// doInstallActiveSchedulerL Install ActiveScheduler
+// -----------------------------------------------------------------------------
+void doInstallActiveSchedulerL()
+{
+ // Construct active scheduler
+ CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
+ CleanupStack::PushL(activeScheduler) ;
+
+ // Install active scheduler
+ // We don't need to check whether an active scheduler is already installed
+ // as this is a new thread, so there won't be one
+ CActiveScheduler::Install(activeScheduler);
+
+ CleanupStack::Pop(activeScheduler);
+
+}
+
+// -----------------------------------------------------------------------------
+// sc_initialize Symbian key initialization
+// -----------------------------------------------------------------------------
+int sc_pkey_init()
+{
+ TInt leaveValue = KErrNone;
+ // Check if there is an active scheduler in current thread
+ if(!CActiveScheduler::Current())
+ {
+ TRAP(leaveValue, doInstallActiveSchedulerL());
+ desActiv = TRUE;
+ }
+ return leaveValue;
+}
+
+// -----------------------------------------------------------------------------
+// sc_pkey_shutdown Shutdown ActiveScheduler
+// -----------------------------------------------------------------------------
+void sc_pkey_shutdown()
+{
+ if(desActiv)
+ {
+ CActiveScheduler* activeScheduler = CActiveScheduler::Current();
+ CActiveScheduler::Install(NULL);
+ if (activeScheduler)
+ delete activeScheduler;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// doKeyStoreCreateL Create a new key store
+// Arguments: aKeyStore ScKeyStorePtr structure
+// -----------------------------------------------------------------------------
+void doKeyStoreCreateL(ScKeyStorePtr aKeyStore)
+{
+
+ aKeyStore->iKeyStore = CSymbianKeyStore::NewL();
+ aKeyStore->iKeyStore->CreateUnifiedKeyStoreL();
+ CActiveScheduler::Start();
+
+ User::LeaveIfError( aKeyStore->iKeyStore->GetError() );
+}
+
+// -----------------------------------------------------------------------------
+// sc_pkey_new Create a new key store structure
+// Arguments: aKeyType the type of key to be generated, enum sc_key_algos
+// Returns: the pointer of the EVP_PKEY generated
+// -----------------------------------------------------------------------------
+EVP_PKEY *sc_pkey_new(int aKeyType, char *keyname)
+{
+ ScKeyStorePtr keyStore;
+ TInt err=KErrNone;
+
+ EVP_PKEY *pkey = (EVP_PKEY*) malloc(sizeof(EVP_PKEY));
+
+ if (pkey)
+ {
+ if (keyname)
+ {
+ pkey->name = (char *)malloc(sizeof(char)*(strlen(keyname)+1));
+ if (!pkey->name)
+ {
+ free(pkey);
+ xmlSecSetErrorFlag( KErrNoMemory );
+ return NULL;
+ }
+ strcpy(pkey->name, keyname);
+ }
+ else
+ {
+ pkey->name = NULL;
+ }
+
+ keyStore = (ScKeyStorePtr) malloc(sizeof(ScKeyStore));
+ if (keyStore)
+ {
+ keyStore->iSubjectPublicKeyInfo = NULL;
+ keyStore->iKeyStore = NULL;
+
+ // Initialize the ScKeyStore - iKeyStore
+ TRAP(err, doKeyStoreCreateL(keyStore));
+
+ if (err)
+ {
+ delete keyStore->iKeyStore;
+ free(keyStore);
+ free(pkey->name);
+ free (pkey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ pkey->keyStore = keyStore;
+
+ }
+ else
+ {
+ free(pkey->name);
+ free(pkey);
+ xmlSecSetErrorFlag( KErrNoMemory );
+ return NULL;
+ }
+
+ pkey->type = aKeyType;
+ pkey->load = NOKEY;
+ pkey->bitsize = 0;
+ pkey->duplicate = 0;
+ }
+ else
+ {
+ xmlSecSetErrorFlag( KErrNoMemory );
+ }
+
+ return pkey;
+}
+
+// -----------------------------------------------------------------------------
+// sc_load_key Try to load usable key from the SymbianKeyStore
+// Arguments: aPKey a EVP_PKEY key structure
+// Returns: KErrNone if no error
+// KErrArgument if the arguments have error
+// KErrNotSupported if the key type is not supported
+// KErrNotFound if no key is found
+// -----------------------------------------------------------------------------
+int sc_pkey_load(EVP_PKEY *aPKey)
+{
+ TInt err=KErrNone;
+
+ // Check arguments
+ if (!aPKey || !aPKey->name)
+ {
+ return KErrArgument;
+ }
+
+ // Load key
+ TPtrC8 keyNamePtr((const unsigned char*)aPKey->name, strlen(aPKey->name));
+ switch (aPKey->type)
+ {
+ case EVP_PKEY_RSA:
+ aPKey->keyStore->iKeyStore->FindKey(keyNamePtr, CCTKeyInfo::ERSA);
+ break;
+ case EVP_PKEY_UNKNOWN:
+ aPKey->keyStore->iKeyStore->FindKey(keyNamePtr, CCTKeyInfo::EInvalidAlgorithm);
+ break;
+ default:
+ return KErrNotSupported;
+ }
+ err = aPKey->keyStore->iKeyStore->GetError();
+ if ( err != KErrNone )
+ {
+ return err;
+ }
+
+ // Run asynchronous key load until done
+ CActiveScheduler::Start();
+ err = aPKey->keyStore->iKeyStore->GetError();
+ if ( err == KErrNone )
+ {
+ err = aPKey->keyStore->iKeyStore->hasKey();
+ }
+ if (!err)
+ {
+ aPKey->load = HASKEY;
+ aPKey->bitsize = aPKey->keyStore->iKeyStore->GetKeySize();
+ if (aPKey->type == EVP_PKEY_UNKNOWN)
+ {
+ switch (aPKey->keyStore->iKeyStore->GetKeyAlgorithm())
+ {
+ case CCTKeyInfo::ERSA:
+ aPKey->type = EVP_PKEY_RSA;
+ break;
+ case CCTKeyInfo::EDSA:
+ aPKey->type = EVP_PKEY_DSA;
+ break;
+ default:
+ aPKey->type = EVP_PKEY_UNKNOWN;
+ break;
+ }
+ }
+ }
+ else
+ {
+ aPKey->load = NOKEY;
+ aPKey->bitsize = 0;
+ }
+
+ return err;
+
+}
+
+// -----------------------------------------------------------------------------
+// sc_generate_key Try to generate key from the SymbianKeyStore
+// Arguments: aPKey a EVP_PKEY key structure
+// aSizeBits bit size of the key generated
+// Returns: KErrNone if no error
+// KErrArgument if the arguments have error
+// -----------------------------------------------------------------------------
+int sc_pkey_generate(EVP_PKEY *aPKey, unsigned int aSizeBits)
+{
+ TInt err=KErrNone;
+
+ // Check arguments
+ if (!aPKey || (aSizeBits <= 0))
+ {
+ err = KErrArgument;
+ return err;
+ }
+
+ // Use SymbianKeyStore to create RSA key
+ aPKey->keyStore->iKeyStore->CreateRSAKey(aSizeBits, KRsaKeyName);
+ err = aPKey->keyStore->iKeyStore->GetError();
+ if ( err != KErrNone)
+ {
+ return err;
+ }
+
+ // Run asynchronous key creation until done
+ CActiveScheduler::Start();
+ err = aPKey->keyStore->iKeyStore->GetError();
+ if ( err == KErrNone )
+ err = aPKey->keyStore->iKeyStore->hasKey();
+ if (!err)
+ {
+ aPKey->load = HASKEY;
+ aPKey->bitsize = aSizeBits;
+ }
+ else
+ {
+ aPKey->load = NOKEY;
+ aPKey->bitsize = 0;
+ }
+
+ return err;
+}
+
+// -----------------------------------------------------------------------------
+// sc_pkey_free Free the EVP_PKEY structure
+// Arguments: aPKey a EVP_PKEY structure
+// Returns: None
+// -----------------------------------------------------------------------------
+void sc_pkey_free(EVP_PKEY *aPKey)
+{
+ if (!aPKey)
+ return;
+
+ if (aPKey->keyStore && !aPKey->duplicate)
+ {
+ if (aPKey->name)
+ {
+ free(aPKey->name);
+ aPKey->name = NULL;
+ }
+
+ if (aPKey->keyStore->iKeyStore)
+ {
+ delete aPKey->keyStore->iKeyStore;
+ aPKey->keyStore->iKeyStore = NULL;
+ }
+
+ if (aPKey->keyStore->iSubjectPublicKeyInfo)
+ {
+ delete aPKey->keyStore->iSubjectPublicKeyInfo;
+ aPKey->keyStore->iSubjectPublicKeyInfo = NULL;
+ }
+
+ free(aPKey->keyStore);
+ aPKey->keyStore = NULL;
+ }
+
+
+ free(aPKey);
+}
+
+// -----------------------------------------------------------------------------
+// sc_pkey_duplicate Duplicate the EVP_PKEY structure
+// Arguments: aPKey a EVP_PKEY structure to be copied
+// Returns: EVP_PKEY* the new EVP_PKEY structure pointer, NULL if failed
+// -----------------------------------------------------------------------------
+EVP_PKEY *sc_pkey_duplicate(EVP_PKEY *aPKey)
+{
+
+ EVP_PKEY *pKeyNew = (EVP_PKEY*) malloc(sizeof(EVP_PKEY));
+
+ if (pKeyNew)
+ {
+ pKeyNew->type = aPKey->type;
+ pKeyNew->bitsize = aPKey->bitsize;
+ pKeyNew->load = aPKey->load;
+ pKeyNew->duplicate = 1;
+ pKeyNew->keyStore = aPKey->keyStore;
+ pKeyNew->name = aPKey->name;
+
+ }
+ else
+ {
+ xmlSecSetErrorFlag( KErrNoMemory );
+ }
+
+ return pKeyNew;
+}
+
+unsigned int sc_pkey_size(EVP_PKEY */*aPKey*/)
+{
+ // temporary fix (max 16358 bits = 2048 bytes)
+ return 2048;
+}
+
+// -----------------------------------------------------------------------------
+// sc_sign_final Finalize signing
+// Arguments: aCtx EVP_MD_CTX structure, aOutbuf buffer,
+// aOutlen size of buffer,aPKey a EVP_PKEY structure,
+// Returns: NULL if correct operation, or error code
+// -----------------------------------------------------------------------------
+TInt sc_sign_final(EVP_MD_CTX aCtx, unsigned char *aOutbuf, unsigned int *aOutlen, EVP_PKEY *aPkey)
+{
+ const byte *hash;
+ unsigned int hashLen;
+ const unsigned char *outbuf = NULL;
+ TInt err;
+
+ hashLen = sc_md_get_algo_dlen(aCtx);
+ hash = sc_md_read(aCtx, 0); // the algo is not used currently
+ if (!hash)
+ {
+ return KErrNoMemory;
+ }
+
+ switch(aPkey->type)
+ {
+ case EVP_PKEY_RSA:
+ TRAP(err, aPkey->keyStore->iKeyStore->RSASignL(hash, hashLen));
+ if (err!=KErrNone)
+ {
+ xmlSecSetErrorFlag( err );
+ return err;
+ }
+ // Run asynchronous RSA signing until done
+ CActiveScheduler::Start();
+ outbuf = aPkey->keyStore->iKeyStore->GetSignedData(aOutlen);
+ break;
+ default:
+ return KErrNotSupported;
+ }
+
+ if (outbuf)
+ {
+ memcpy(aOutbuf, outbuf, *aOutlen);
+ return KErrNone;
+ }
+ else
+ {
+ TInt error = aPkey->keyStore->iKeyStore->GetError();
+ xmlSecSetErrorFlag( error );
+ return error;
+ }
+
+}
+
+// -----------------------------------------------------------------------------
+// doVerifyFinalL Finalize verification
+// Arguments: aHash buffer with hash, aHashLen size of hash, aSignature buffer,
+// aLen size of buffer,aPKey a EVP_PKEY structure,
+// Returns: NULL if correct operation, or error code
+// -----------------------------------------------------------------------------
+TInt doVerifyFinalL(const byte *aHash,
+ unsigned int aHashLen,
+ unsigned char *aSignature,
+ unsigned int aLen,
+ EVP_PKEY *aPKey)
+{
+ TInt res = 0;
+ switch(aPKey->type)
+ {
+ case EVP_PKEY_RSA:
+ if (aPKey->keyStore->iSubjectPublicKeyInfo)
+ {
+ res = (TInt)aPKey->keyStore->iKeyStore->RSAVerifyWithPublicKeyL(aHash,
+ aHashLen,
+ aSignature,
+ aLen,
+ aPKey->keyStore->iSubjectPublicKeyInfo);
+ }
+ else
+ {
+ aPKey->keyStore->iKeyStore->RSAVerifyL(aHash, aHashLen, aSignature, aLen);
+ // Run asynchronous RSA signing until done
+ CActiveScheduler::Start();
+ User::LeaveIfError( aPKey->keyStore->iKeyStore->GetError() );
+ res = (TInt)aPKey->keyStore->iKeyStore->GetVerifyResult();
+ };
+ break;
+ default:
+ res = KErrNotSupported;
+ }
+ return res;
+}
+
+// -----------------------------------------------------------------------------
+// sc_verify_final Finalize verification
+// Arguments: aCtx EVP_MD_CTX structure, aSignature buffer,
+// aLen size of buffer,aPKey a EVP_PKEY structure,
+// Returns: NULL if correct operation, or error code
+// -----------------------------------------------------------------------------
+TInt sc_verify_final(EVP_MD_CTX aCtx,
+ unsigned char *aSignature,
+ unsigned int aLen,
+ EVP_PKEY *aPKey)
+{
+ const byte *hash;
+ unsigned int hashLen;
+ TInt err;
+ TInt ret=0;
+
+ hashLen = sc_md_get_algo_dlen(aCtx);
+ hash = sc_md_read(aCtx, 0); // the algo is not used currently
+ if (!hash)
+ {
+ return KErrNoMemory;
+ }
+
+ TRAP(err, ret = doVerifyFinalL(hash, hashLen, aSignature, aLen, aPKey));
+
+ if (err != KErrNone)
+ {
+ xmlSecSetErrorFlag( err );
+ return err;
+ }
+ else
+ {
+ return ret;
+ }
+
+}
+
+// -----------------------------------------------------------------------------
+// d2i_PUBKEY_bio Read the public key from ASN.1 DER encoded format
+// Arguments: aBio BIO structure
+// Returns: EVP_PKEY structure
+// -----------------------------------------------------------------------------
+EVP_PKEY* d2i_PUBKEY_bio(BIO *aBio)
+{
+ // Import key to keystore
+ TInt err;
+ EVP_PKEY *pKey;
+
+ // Remember to get the key type later
+ pKey = sc_pkey_new(EVP_PKEY_UNKNOWN, aBio->name);
+ if (!pKey)
+ {
+ return NULL;
+ }
+
+ // Import key if key is not found
+ TPtrC8 keyPtr((const unsigned char*)aBio->mem, aBio->len);
+ TRAP(err, pKey->keyStore->iSubjectPublicKeyInfo = CX509SubjectPublicKeyInfo::NewL(keyPtr));
+ if (err!=KErrNone)
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ pKey->load = HASKEY;
+ switch (pKey->keyStore->iSubjectPublicKeyInfo->AlgorithmId())
+ {
+ case ERSA:
+ pKey->type = EVP_PKEY_RSA;
+ break;
+ case EDSA:
+ pKey->type = EVP_PKEY_DSA;
+ break;
+ default:
+ pKey->type = EVP_PKEY_UNKNOWN;
+ break;
+ }
+
+ return pKey;
+}
+
+// -----------------------------------------------------------------------------
+// doKeyImportL Imports key
+// Arguments: EVP_PKEY structure, aBio BIO structure
+// -----------------------------------------------------------------------------
+void doKeyImportL(EVP_PKEY *aPKey, BIO *aBio)
+{
+ __ASSERT_ALWAYS(aPKey, User::Leave(KAssertionLeave));
+ __ASSERT_ALWAYS(aPKey->name, User::Leave(KAssertionLeave));
+
+ TPtrC8 keyPtr((const unsigned char*)aBio->mem, aBio->len);
+ TPtrC8 keyNamePtr((const unsigned char*)aPKey->name, strlen(aPKey->name));
+
+ aPKey->keyStore->iKeyStore->ImportKey(keyPtr, keyNamePtr);
+ User::LeaveIfError( aPKey->keyStore->iKeyStore->GetError() );
+
+ // Run asynchronous key creation until done
+ CActiveScheduler::Start();
+ User::LeaveIfError( aPKey->keyStore->iKeyStore->GetError() );
+}
+
+// -----------------------------------------------------------------------------
+// d2i_PKCS8PrivateKey_bio Read the private key from ASN.1 DER encoded PKCS#8 format
+// Arguments: aBio BIO structure, aPwdCallback callback, aPwdCallbackCtx callback context
+// Returns: EVP_PKEY structure
+// -----------------------------------------------------------------------------
+EVP_PKEY* d2i_PKCS8PrivateKey_bio(BIO *aBio, void *aPwdCallback, void *aPwdCallbackCtx)
+{
+ // Import key to keystore
+ TInt err;
+ EVP_PKEY *pKey;
+
+ // Remember to get the key type later
+ pKey = sc_pkey_new(EVP_PKEY_UNKNOWN, aBio->name);
+ if (!pKey)
+ {
+ return NULL;
+ }
+
+ // Check if there is existing key first
+ err = sc_pkey_load(pKey);
+ if (err == 0 && pKey->load)
+ {
+ // Return key if it is found
+ return pKey;
+ }
+ else if ( err != KErrNotFound )
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ // Import key if key is not found
+ TRAP(err, doKeyImportL(pKey, aBio));
+ if (err!=KErrNone)
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+
+ // Check to see if the import key is successful
+ err = pKey->keyStore->iKeyStore->hasKey();
+ if (err)
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ pKey->load = HASKEY;
+ pKey->bitsize = pKey->keyStore->iKeyStore->GetKeySize();
+ switch (pKey->keyStore->iKeyStore->GetKeyAlgorithm())
+ {
+ case CCTKeyInfo::ERSA:
+ pKey->type = EVP_PKEY_RSA;
+ break;
+ case CCTKeyInfo::EDSA:
+ pKey->type = EVP_PKEY_DSA;
+ break;
+ default:
+ pKey->type = EVP_PKEY_UNKNOWN;
+ break;
+ }
+
+
+ return pKey;
+
+}
+
+// -----------------------------------------------------------------------------
+// d2i_PKCS8PrivateKey Read the private key from Unified Key Store
+// Arguments: keyname name of the key
+// Returns: EVP_PKEY structure
+// -----------------------------------------------------------------------------
+EVP_PKEY* d2i_PKCS8PrivateKey(char *keyname)
+{
+ TInt err;
+ EVP_PKEY *pKey;
+
+ // Remember to get the key type later
+ pKey = sc_pkey_new(EVP_PKEY_UNKNOWN, keyname);
+ if (!pKey)
+ {
+ return NULL;
+ }
+
+ // Check if there is existing key first
+ err = sc_pkey_load(pKey);
+ if (err == 0 && pKey->load)
+ {
+ // Return key if it is found
+ return pKey;
+ }
+ else if ( err != KErrNotFound )
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ // Check to see if the find key is successful
+ err = pKey->keyStore->iKeyStore->hasKey();
+ if (err)
+ {
+ sc_pkey_free(pKey);
+ xmlSecSetErrorFlag( err );
+ return NULL;
+ }
+
+ pKey->load = HASKEY;
+ pKey->bitsize = pKey->keyStore->iKeyStore->GetKeySize();
+ switch (pKey->keyStore->iKeyStore->GetKeyAlgorithm())
+ {
+ case CCTKeyInfo::ERSA:
+ pKey->type = EVP_PKEY_RSA;
+ break;
+ case CCTKeyInfo::EDSA:
+ pKey->type = EVP_PKEY_DSA;
+ break;
+ default:
+ pKey->type = EVP_PKEY_UNKNOWN;
+ break;
+ }
+
+
+ return pKey;
+
+}
+
+#ifndef XMLSEC_NO_X509
+
+// -----------------------------------------------------------------------------
+// doGetPubKeyL Set the public key info
+// Arguments: EVP_PKEY structure, aCert X509 structure
+// -----------------------------------------------------------------------------
+void doGetPubKeyL(EVP_PKEY *aPKey, X509 *aCert)
+{
+ // Convert X509 to CX509Certificate
+ TPtrC8 certPtr((const unsigned char*)aCert->der, aCert->derlen);
+ CX509Certificate *cert = CX509Certificate::NewLC(certPtr);
+
+ // Retrieve the public key
+ aPKey->keyStore->iSubjectPublicKeyInfo = CSubjectPublicKeyInfo::NewL(cert->PublicKey());
+
+ // Cleanup
+ CleanupStack::PopAndDestroy(cert);
+
+}
+
+// -----------------------------------------------------------------------------
+// sc_pkey_setPublic Set the public key info
+// Arguments: EVP_PKEY structure, aCert X509 structure
+// Returns: 0 if operation correct, or error code
+// -----------------------------------------------------------------------------
+TInt sc_pkey_setPublic(EVP_PKEY* aPKey, X509 *aCert)
+{
+ TInt err;
+
+ if (aPKey->keyStore->iSubjectPublicKeyInfo)
+ {
+ delete aPKey->keyStore->iSubjectPublicKeyInfo;
+ aPKey->keyStore->iSubjectPublicKeyInfo = NULL;
+ }
+
+ TRAP(err, doGetPubKeyL(aPKey, aCert));
+
+ if (err == KErrNone)
+ {
+ aPKey->load = HASKEY;
+ switch (aPKey->keyStore->iSubjectPublicKeyInfo->AlgorithmId())
+ {
+ case ERSA:
+ aPKey->type = EVP_PKEY_RSA;
+ break;
+ case EDSA:
+ aPKey->type = EVP_PKEY_DSA;
+ break;
+ default:
+ aPKey->type = EVP_PKEY_UNKNOWN;
+ break;
+ }
+
+ }
+ else
+ {
+ xmlSecSetErrorFlag( err );
+ }
+
+ return err;
+}
+
+#endif // XMLSEC_NO_X509