xmlsecurityengine/xmlseccrypto/src/xmlsecc_x509vfy.cpp
changeset 0 e35f40988205
child 8 e65204f75c47
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlseccrypto/src/xmlsecc_x509vfy.cpp	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1326 @@
+/** 
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ * 
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
+ */
+#include "xmlsecc_config.h"
+#ifndef XMLSEC_NO_X509
+#include "xmlsecc_globals.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <libxml2_tree.h>
+
+#include "xmlsec_xmlsec.h"
+#include "xmlsec_xmltree.h"
+#include "xmlsec_keys.h"
+#include "xmlsec_keyinfo.h"
+#include "xmlsec_keysmngr.h"
+#include "xmlsec_base64.h"
+#include "xmlsec_errors.h"
+
+#include "xmlsecc_crypto.h"
+#include "xmlsecc_x509wrapper.h"
+#include "xmlsecc_x509.h"
+#include "xmlsec_error_flag.h"
+
+#define XMLSEC_OPENSSL_097
+
+/**************************************************************************
+ *
+ * Internal SymbianCrypto X509 store CTX
+ *
+ *************************************************************************/
+typedef struct _xmlSecSymbianCryptoX509StoreCtx		xmlSecSymbianCryptoX509StoreCtx, 
+							*xmlSecSymbianCryptoX509StoreCtxPtr;
+struct _xmlSecSymbianCryptoX509StoreCtx {
+    X509_STORE* 	xst;
+    STACK_OF(X509)* 	untrusted;
+    STACK_OF(X509_CRL)* crls;
+
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+    X509_VERIFY_PARAM * vpm;	    
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+};	    
+
+/****************************************************************************
+ *
+ * xmlSecSymbianCryptoKeyDataStoreX509Id:
+ *
+ * xmlSecSymbianCryptoX509StoreCtx is located after xmlSecTransform
+ *
+ ***************************************************************************/
+#define xmlSecSymbianCryptoX509StoreGetCtx(store) \
+    ((xmlSecSymbianCryptoX509StoreCtxPtr)(((xmlSecByte*)(store)) + \
+				    sizeof(xmlSecKeyDataStoreKlass)))
+#define xmlSecSymbianCryptoX509StoreSize	\
+    (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecSymbianCryptoX509StoreCtx))
+ 
+static int		xmlSecSymbianCryptoX509StoreInitialize	(xmlSecKeyDataStorePtr store);
+static void		xmlSecSymbianCryptoX509StoreFinalize		(xmlSecKeyDataStorePtr store);
+
+static xmlSecKeyDataStoreKlass xmlSecSymbianCryptoX509StoreKlass = {
+    sizeof(xmlSecKeyDataStoreKlass),
+    xmlSecSymbianCryptoX509StoreSize,
+
+    /* data */
+    xmlSecNameX509Store,			/* const xmlChar* name; */ 
+        
+    /* constructors/destructor */
+    xmlSecSymbianCryptoX509StoreInitialize,		/* xmlSecKeyDataStoreInitializeMethod initialize; */
+    xmlSecSymbianCryptoX509StoreFinalize,		/* xmlSecKeyDataStoreFinalizeMethod finalize; */
+
+    /* reserved for the future */
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+static int		xmlSecSymbianCryptoX509VerifyCrl			(X509_STORE* xst, 
+									 X509_CRL *crl );
+static X509*		xmlSecSymbianCryptoX509FindCert			(STACK_OF(X509) *certs,
+									 xmlChar *subjectName,
+									 xmlChar *issuerName, 
+									 xmlChar *issuerSerial,
+									 xmlChar *ski);
+static X509*		xmlSecSymbianCryptoX509FindNextChainCert		(STACK_OF(X509) *chain, 
+		    							 X509 *cert);
+static int		xmlSecSymbianCryptoX509VerifyCertAgainstCrls		(STACK_OF(X509_CRL) *crls, 
+								         X509* cert);
+static X509_NAME*	xmlSecSymbianCryptoX509NameRead			(xmlSecByte *str, 
+									 int len);
+static int 		xmlSecSymbianCryptoX509NameStringRead			(xmlSecByte **str, 
+									 int *strLen, 
+									 xmlSecByte *res, 
+									 int resLen, 
+									 xmlSecByte delim, 
+									 int ingoreTrailingSpaces);
+static int		xmlSecSymbianCryptoX509NamesCompare			(X509_NAME *a,
+									 X509_NAME *b);
+static int 		xmlSecSymbianCryptoX509_NAME_cmp			(const X509_NAME *a, 
+									 const X509_NAME *b);
+/*
+static int 		xmlSecSymbianCryptoX509_NAME_ENTRY_cmp		(const X509_NAME_ENTRY **a, 
+									 const X509_NAME_ENTRY **b);
+*/
+/** 
+ * xmlSecSymbianCryptoX509StoreGetKlass:
+ * 
+ * The SymbianCrypto X509 certificates key data store klass.
+ *
+ * Returns pointer to SymbianCrypto X509 certificates key data store klass.
+ */
+EXPORT_C
+xmlSecKeyDataStoreId 
+xmlSecSymbianCryptoX509StoreGetKlass(void) {
+    return(&xmlSecSymbianCryptoX509StoreKlass);
+}
+
+/**
+ * xmlSecSymbianCryptoX509StoreFindCert:
+ * @store:		the pointer to X509 key data store klass.
+ * @subjectName:	the desired certificate name.
+ * @issuerName:		the desired certificate issuer name.
+ * @issuerSerial:	the desired certificate issuer serial number.
+ * @ski:		the desired certificate SKI.
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Searches @store for a certificate that matches given criteria.
+ *
+ * Returns pointer to found certificate or NULL if certificate is not found
+ * or an error occurs.
+ */
+EXPORT_C
+X509* 
+xmlSecSymbianCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName,
+				xmlChar *issuerName, xmlChar *issuerSerial,
+				xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    X509* res = NULL;
+    
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), NULL);
+    xmlSecAssert2(keyInfoCtx, NULL);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, NULL);
+
+    if((!res) && (ctx->untrusted)) {
+        res = xmlSecSymbianCryptoX509FindCert(ctx->untrusted, 
+                                                            subjectName, 
+                                                            issuerName, 
+                                                            issuerSerial, 
+                                                            ski);
+    }
+    return(res);
+}
+
+
+/**
+ * xmlSecSymbianCryptoX509StoreVerify:
+ * @store:		the pointer to X509 key data store klass.
+ * @cert:		the untrusted key cert.
+ *
+ * Verifies @certs list.
+ *
+ * Returns Result of the verification
+ */
+EXPORT_C 
+int 	
+xmlSecSymbianCryptoX509StoreKeyCertVerify(xmlSecKeyDataStorePtr store, X509* cert) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    X509* res = NULL;
+    X509 *err_cert = NULL;
+    char buf[256];
+    int err = 0, depth;
+    int i;
+    int ret;
+
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), NULL);
+    xmlSecAssert2(cert, NULL);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, NULL);
+    xmlSecAssert2(ctx->xst, NULL);
+    
+ if(!xmlSecCheckCertStoreFlag()) //SymbianCertStore Flag == FALSE
+    {
+    err = X509_STORE_certchain_init (ctx->xst, cert);
+    if(err != 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	//goto done;
+	    return -1;
+        }       
+    err = X509_STORE_certchain_validate(ctx->xst);
+	if(err != 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	//goto done;
+	    return -1;
+        }	   
+
+        return X509_STORE_certchain_getValidateResult(ctx->xst);    
+    }
+else    //SymbianCertStore Flag ==TRUE
+    {  
+        err = X509_STORE_certchain_init_fromCertStore(ctx->xst, cert);
+        if(err != 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	//goto done;
+	    return -1;
+        }
+        err = X509_STORE_certchain_validate(ctx->xst);
+        if(err != 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	    //goto done;
+	    return -1;
+        }	          
+        return X509_STORE_certchain_getValidateResult(ctx->xst);            
+    } //else
+}
+			   
+/**
+ * xmlSecSymbianCryptoX509StoreVerify:
+ * @store:		the pointer to X509 key data store klass.
+ * @certs:		the untrusted certificates stack.
+ * @crls:		the crls stack.
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Verifies @certs list.
+ *
+ * Returns pointer to the first verified certificate from @certs.
+ */
+EXPORT_C 
+X509* 	
+xmlSecSymbianCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, XMLSEC_STACK_OF_X509* certs,
+			     XMLSEC_STACK_OF_X509_CRL* crls, xmlSecKeyInfoCtx* keyInfoCtx) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    STACK_OF(X509)* certs2 = NULL;	
+    X509* res = NULL;
+    X509* cert = NULL;
+    X509 *err_cert = NULL;
+    char buf[256];
+    int err = 0, depth;
+    int i;
+    int ret;
+
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), NULL);
+    xmlSecAssert2(certs, NULL);
+    xmlSecAssert2(keyInfoCtx, NULL);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, NULL);
+    xmlSecAssert2(ctx->xst, NULL);
+    
+    err = X509_STORE_certchain_init (ctx->xst, certs);
+    if(err != 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+    }
+    
+    
+    err = X509_STORE_certchain_validate(ctx->xst);
+	if(err != 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_certchain_init",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+    }	   
+    
+    ret = X509_STORE_certchain_getValidateResult(ctx->xst);
+	if(ret == 1) {
+		res = cert;
+	}    
+  
+#ifdef XMLSEC_FUTURE_SUPPORT  
+    /* dup certs */
+    /*
+    certs2 = sk_X509_dup(certs);
+    if(certs2 == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "sk_X509_dup",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	goto done;
+    }
+	*/
+    /* add untrusted certs from the store */
+#ifndef XMLSEC_NO_X509_UNTRUST    
+    if(ctx->untrusted) {
+	for(i = 0; i < sk_X509_num(ctx->untrusted); ++i) { 
+	    ret = sk_X509_push(certs2, sk_X509_value(ctx->untrusted, i));
+	    if(ret < 1) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "sk_X509_push",
+			    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		goto done;
+	    }
+	}
+    }
+#endif //XMLSEC_NO_X509_UNTRUST
+
+#ifndef XMLSEC_NO_X509_CRL 
+    /* dup crls but remove all non-verified */   
+    if(crls) {
+	crls2 = sk_X509_CRL_dup(crls);
+	if(!crls2) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			"sk_X509_CRL_dup",
+			XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    goto done;
+	}
+
+	for(i = 0; i < sk_X509_CRL_num(crls2); ) { 
+	    ret = xmlSecSymbianCryptoX509VerifyCrl(ctx->xst, sk_X509_CRL_value(crls2, i));
+	    if(ret == 1) {
+		++i;
+	    } else if(ret == 0) {
+		sk_X509_CRL_delete(crls2, i);
+	    } else {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "xmlSecSymbianCryptoX509VerifyCrl",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		goto done;
+	    }
+	}	
+    }
+    
+    /* remove all revoked certs */
+    for(i = 0; i < sk_X509_num(certs2);) { 
+	cert = sk_X509_value(certs2, i);
+
+	if(crls2) {
+	    ret = xmlSecSymbianCryptoX509VerifyCertAgainstCrls(crls2, cert);
+	    if(ret == 0) {
+		sk_X509_delete(certs2, i);
+		continue;
+	    } else if(ret != 1) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "xmlSecSymbianCryptoX509VerifyCertAgainstCrls",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		goto done;
+	    }
+	}	    	    
+
+	if(ctx->crls) {
+	    ret = xmlSecSymbianCryptoX509VerifyCertAgainstCrls(ctx->crls, cert);
+	    if(ret == 0) {
+		sk_X509_delete(certs2, i);
+		continue;
+	    } else if(ret != 1) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "xmlSecSymbianCryptoX509VerifyCertAgainstCrls",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		goto done;
+	    }
+	}
+	++i;
+    }	
+
+#endif //XMLSEC_NO_X509_CRL
+
+    /* get one cert after another and try to verify */
+    for(i = 0; i < sk_X509_num(certs2); ++i) { 
+	cert = sk_X509_value(certs2, i);
+	if(!xmlSecSymbianCryptoX509FindNextChainCert(certs2, cert)) {
+	    X509_STORE_CTX xsc; 
+
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+	    X509_VERIFY_PARAM * vpm = NULL;	    
+	    unsigned long vpm_flags = 0;
+
+	    vpm = X509_VERIFY_PARAM_new();
+	    if(!vpm) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "X509_VERIFY_PARAM_new",
+		    	    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+	        goto done;
+	    }
+	    vpm_flags = vpm->flags;
+/*
+	    vpm_flags &= (~X509_V_FLAG_X509_STRICT);
+*/
+	    vpm_flags &= (~X509_V_FLAG_CRL_CHECK);
+
+	    X509_VERIFY_PARAM_set_depth(vpm, 9);  
+	    X509_VERIFY_PARAM_set_flags(vpm, vpm_flags);
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+    
+
+	    X509_STORE_CTX_init (&xsc, ctx->xst, cert, certs2);
+
+	    if(keyInfoCtx->certsVerificationTime > 0) {	
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+		vpm_flags |= X509_V_FLAG_USE_CHECK_TIME;
+	        X509_VERIFY_PARAM_set_time(vpm, keyInfoCtx->certsVerificationTime);
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+		X509_STORE_CTX_set_time(&xsc, 0, keyInfoCtx->certsVerificationTime);
+	    }
+
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+	    X509_STORE_CTX_set0_param(&xsc, vpm);	    
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+
+	    
+	    ret 	= X509_verify_cert(&xsc); 
+	    err_cert 	= X509_STORE_CTX_get_current_cert(&xsc);
+	    err	 	= X509_STORE_CTX_get_error(&xsc);
+	    depth	= X509_STORE_CTX_get_error_depth(&xsc);
+	    
+	    X509_STORE_CTX_cleanup (&xsc);  
+	    
+	    if(ret == 1) {
+		res = cert;
+		goto done;
+	    } else if(ret < 0) {
+		const char* err_msg;
+		
+		buf[0] = '\0';
+	        X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf);
+		err_msg = X509_verify_cert_error_string(err);
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "X509_verify_cert",
+			    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    	    "subj=%s;err=%d;msg=%s", 
+			    xmlSecErrorsSafeString(buf),
+			    err, 
+			    xmlSecErrorsSafeString(err_msg));
+		goto done;
+	    } else if(ret == 0) {
+		const char* err_msg;
+		
+		buf[0] = '\0';
+	        X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf);
+		err_msg = X509_verify_cert_error_string(err);
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			    "X509_verify_cert",
+			    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    	    "subj=%s;err=%d;msg=%s", 
+			    xmlSecErrorsSafeString(buf),
+			    err, 
+			    xmlSecErrorsSafeString(err_msg));
+	    }
+	}
+    }
+
+    /* if we came here then we found nothing. do we have any error? */
+    if((err != 0) && (err_cert)) {
+	const char* err_msg;
+
+	err_msg = X509_verify_cert_error_string(err);
+	switch (err) {
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+	    X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, sizeof buf);
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			NULL,
+			XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,
+		        "err=%d;msg=%s;issuer=%s", 
+			err, 
+			xmlSecErrorsSafeString(err_msg),
+			xmlSecErrorsSafeString(buf));
+	    break;
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			NULL,
+			XMLSEC_ERRORS_R_CERT_NOT_YET_VALID,
+			"err=%d;msg=%s", err,
+			xmlSecErrorsSafeString(err_msg));
+	    break;
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			NULL,
+			XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,
+			"err=%d;msg=%s", err,
+			xmlSecErrorsSafeString(err_msg));
+	    break;
+	default:			
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			NULL,
+			XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+			"err=%d;msg=%s", err,
+			xmlSecErrorsSafeString(err_msg));
+	}		    
+    }
+    
+done:    
+
+    if(certs2) {
+	X509_free(certs2);
+    }
+    if(crls2) {
+	sk_X509_CRL_free(crls2);
+    }
+    
+#endif //XMLSEC_FUTURE_SUPPORT   
+    return(res);
+}
+
+/**
+ * xmlSecSymbianCryptoX509StoreAdoptCert:
+ * @store:		the pointer to X509 key data store klass.
+ * @cert:		the pointer to SymbianCrypto X509 certificate.
+ * @type:		the certificate type (trusted/untrusted).
+ *
+ * Adds trusted (root) or untrusted certificate to the store.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecSymbianCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, 
+                                                    X509* cert, 
+                                                    xmlSecKeyDataType type) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    int ret = -1;
+    
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), -1);
+    xmlSecAssert2(cert, -1);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, -1);
+
+    if((type & xmlSecKeyDataTypeTrusted) != 0) {
+        xmlSecAssert2(ctx->xst, -1);
+
+        ret = X509_STORE_add_cert(ctx->xst, cert);
+        if(ret != 0) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+                        "X509_STORE_add_cert",
+                        XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                        XMLSEC_ERRORS_NO_MESSAGE);
+            xmlSecSetErrorFlag( ret );
+            return(-1);
+        }
+        /* add cert increments the reference */
+        X509_free(cert);
+    } else {
+	xmlSecAssert2(ctx->untrusted, -1);
+
+	if(ret < 1) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+			"sk_X509_push",
+			XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+    }
+    return(0);
+}
+
+/**
+ * xmlSecSymbianCryptoX509StoreAddCertsPath:
+ * @store: the pointer to SymbianCrypto x509 store.
+ * @path: the path to the certs dir.
+ *
+ * Adds all certs in the @path to the list of trusted certs
+ * in @store.
+ *
+ * Returns 0 on success or a negative value otherwise.
+ */
+EXPORT_C
+int 
+xmlSecSymbianCryptoX509StoreAddCertsPath(xmlSecKeyDataStorePtr store, const char *path) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), -1);
+    xmlSecAssert2(path, -1);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, -1);
+    xmlSecAssert2(ctx->xst, -1);
+    /*
+    lookup = X509_STORE_add_lookup(ctx->xst, X509_LOOKUP_hash_dir());
+    if(lookup == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_add_lookup",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+    X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_DEFAULT);
+    */
+    return(0);
+}
+
+static int
+xmlSecSymbianCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store) {
+    const xmlChar* path;
+    
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId), -1);
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert2(ctx, -1);
+
+    memset(ctx, 0, sizeof(xmlSecSymbianCryptoX509StoreCtx));
+
+    ctx->xst = X509_STORE_new();
+    if(!ctx->xst) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_new",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+#ifdef XMLSEC_FUTURE_SUPPORT    
+    if(!X509_STORE_set_default_paths(ctx->xst)) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_set_default_paths",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    path = xmlSecSymbianCryptoGetDefaultTrustedCertsFolder();
+    if(path) {
+	X509_LOOKUP *lookup = NULL;
+	
+	lookup = X509_STORE_add_lookup(ctx->xst, X509_LOOKUP_hash_dir());
+        if(!lookup) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_STORE_add_lookup",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}    
+	X509_LOOKUP_add_dir(lookup, (char*)path, X509_FILETYPE_DEFAULT);
+    }
+
+    ctx->untrusted = sk_X509_new_null();
+    if(!ctx->untrusted) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "sk_X509_new_null",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+
+    ctx->crls = sk_X509_CRL_new_null();
+    if(!ctx->crls) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "sk_X509_CRL_new_null",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+    
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+    ctx->vpm = X509_VERIFY_PARAM_new();
+    if(!ctx->vpm) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+		    "X509_VERIFY_PARAM_new",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+    X509_VERIFY_PARAM_set_depth(ctx->vpm, 9); /* the default cert verification path in openssl */	
+    X509_STORE_set1_param(ctx->xst, ctx->vpm);
+    
+#else  /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+    ctx->xst->depth = 9; /* the default cert verification path in openssl */	
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+
+#endif	//XMLSEC_FUTURE_SUPPORT
+    return(0);    
+}
+
+static void
+xmlSecSymbianCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store) {
+    xmlSecSymbianCryptoX509StoreCtxPtr ctx;
+    xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecSymbianCryptoX509StoreId));
+
+    ctx = xmlSecSymbianCryptoX509StoreGetCtx(store);
+    xmlSecAssert(ctx);
+    
+    if(ctx->xst) {
+	X509_STORE_free(ctx->xst);
+    }
+    if(ctx->untrusted) {
+    }
+    if(ctx->crls) {
+    }
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+    if(ctx->vpm) {
+	X509_VERIFY_PARAM_free(ctx->vpm);
+    }
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+    memset(ctx, 0, sizeof(xmlSecSymbianCryptoX509StoreCtx));
+}
+
+
+/*****************************************************************************
+ *
+ * Low-level x509 functions
+ *
+ *****************************************************************************/
+static int
+xmlSecSymbianCryptoX509VerifyCrl(X509_STORE* xst, X509_CRL *crl ) {
+
+    EVP_PKEY *pkey;
+    int ret = 0;  
+#ifdef XMLSEC_FUTURE_SUPPORT   
+    xmlSecAssert2(xst, -1);
+    xmlSecAssert2(crl, -1);
+ 
+    X509_STORE_CTX_init(&xsc, xst, NULL, NULL);
+    ret = X509_STORE_get_by_subject(&xsc, X509_LU_X509, 
+				    X509_CRL_get_issuer(crl), &xobj);
+    if(ret <= 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_STORE_get_by_subject",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    pkey = X509_get_pubkey(xobj.data.x509);
+    X509_OBJECT_free_contents(&xobj);
+    if(!pkey) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_get_pubkey",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    ret = X509_CRL_verify(crl, pkey);
+    EVP_PKEY_free(pkey);    
+    if(ret != 1) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_CRL_verify",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+    }
+    X509_STORE_CTX_cleanup (&xsc);  
+#endif		//XMLSEC_FUTURE_SUPPORT    
+    return((ret == 1) ? 1 : 0);
+}
+
+/**
+ * xmlSecSymbianCryptoX509FindCert:
+ */
+static X509*		
+xmlSecSymbianCryptoX509FindCert(STACK_OF(X509) *certs, xmlChar *subjectName,
+			xmlChar *issuerName, xmlChar *issuerSerial,
+			xmlChar *ski) {
+    X509 *cert = NULL;
+    int i;
+
+    xmlSecAssert2(certs, NULL);
+#ifdef XMLSEC_FUTURE_SUPPORT    
+    /* may be this is not the fastest way to search certs */
+    if(subjectName) {
+	X509_NAME *nm;
+	X509_NAME *subj;
+
+	nm = xmlSecSymbianCryptoX509NameRead(subjectName, xmlStrlen(subjectName));
+	if(!nm) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecSymbianCryptoX509NameRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"subject=%s", 
+			xmlSecErrorsSafeString(subjectName));
+	    return(NULL);    
+	}
+
+	for(i = 0; i < certs->num; ++i) {
+	    cert = ((X509**)(certs->data))[i];
+	    subj = X509_get_subject_name(cert);
+	    if(xmlSecSymbianCryptoX509NamesCompare(nm, subj) == 0) {
+		X509_NAME_free(nm);
+		return(cert);
+	    }	    
+	}
+	X509_NAME_free(nm);
+    } else if((issuerName) && (issuerSerial)) {
+	X509_NAME *nm;
+	X509_NAME *issuer;
+	BIGNUM *bn;
+	ASN1_INTEGER *serial;
+
+	nm = xmlSecSymbianCryptoX509NameRead(issuerName, xmlStrlen(issuerName));
+	if(!nm) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecSymbianCryptoX509NameRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"issuer=%s", 
+			xmlSecErrorsSafeString(issuerName));
+	    return(NULL);    
+	}
+		
+	bn = BN_new();
+	if(!bn) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"BN_new",
+			XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    X509_NAME_free(nm);
+	    return(NULL);    
+	}
+	if(BN_dec2bn(&bn, (char*)issuerSerial) == 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"BN_dec2bn",
+			XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    BN_free(bn);
+	    X509_NAME_free(nm);
+	    return(NULL);    
+	}
+	
+	serial = BN_to_ASN1_INTEGER(bn, NULL);
+	if(!serial) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"BN_to_ASN1_INTEGER",
+			XMLSEC_ERRORS_R_CRYPTO_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    BN_free(bn);
+	    X509_NAME_free(nm);
+	    return(NULL);    
+	}
+	BN_free(bn); 
+
+
+	for(i = 0; i < certs->num; ++i) {
+	    cert = ((X509**)(certs->data))[i];
+	    if(ASN1_INTEGER_cmp(X509_get_serialNumber(cert), serial) != 0) {
+		continue;
+	    } 
+	    issuer = X509_get_issuer_name(cert);
+	    if(xmlSecSymbianCryptoX509NamesCompare(nm, issuer) == 0) {
+		ASN1_INTEGER_free(serial);
+		X509_NAME_free(nm);
+		return(cert);
+	    }	    
+	}
+
+        X509_NAME_free(nm);
+	ASN1_INTEGER_free(serial);
+    } else if(ski) {
+	int len;
+	int index;
+	X509_EXTENSION *ext;
+	ASN1_OCTET_STRING *keyId;
+	
+	/* our usual trick with base64 decode */
+	len = xmlSecBase64Decode(ski, (xmlSecByte*)ski, xmlStrlen(ski));
+	if(len < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecBase64Decode",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"ski=%s", 
+			xmlSecErrorsSafeString(ski));
+	    return(NULL);    	
+	}
+	for(i = 0; i < certs->num; ++i) {
+	    cert = ((X509**)(certs->data))[i];
+	    index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); 
+	    if(index >= 0) {
+	         ext = X509_get_ext(cert, index);
+	         if(ext){
+		    keyId = X509V3_EXT_d2i(ext);
+		    if((keyId) && (keyId->length == len) && 
+				    (memcmp(keyId->data, ski, len) == 0)) {
+		        M_ASN1_OCTET_STRING_free(keyId);
+		        return(cert);
+		        }
+		M_ASN1_OCTET_STRING_free(keyId);
+	        }
+	    }
+	}	
+    }
+#endif		//XMLSEC_FUTURE_SUPPORT
+    return(NULL);
+}
+
+/** 
+ * xmlSecSymbianCryptoX509FindNextChainCert:
+ */
+static X509*
+xmlSecSymbianCryptoX509FindNextChainCert(STACK_OF(X509) *chain, X509 *cert) {
+    unsigned long certSubjHash;
+    int i;
+
+    xmlSecAssert2(chain, NULL);
+    xmlSecAssert2(cert, NULL);
+/*    
+    certSubjHash = X509_subject_name_hash(cert);
+    for(i = 0; i < sk_X509_num(chain); ++i) {
+	if((sk_X509_value(chain, i) != cert) && 
+	   (X509_issuer_name_hash(sk_X509_value(chain, i)) == certSubjHash)) {
+
+	    return(sk_X509_value(chain, i));
+	}
+    }
+*/    
+    return(NULL);
+}
+
+/**
+ * xmlSecSymbianCryptoX509VerifyCertAgainstCrls:
+ */
+static int
+xmlSecSymbianCryptoX509VerifyCertAgainstCrls(STACK_OF(X509_CRL) *crls, X509* cert) {
+    X509_NAME *issuer;
+    X509_CRL *crl = NULL;
+#ifdef XMLSEC_FUTURE_SUPPORT    
+    X509_REVOKED *revoked;
+    int i, n;
+    int ret;  
+
+    xmlSecAssert2(crls, -1);
+    xmlSecAssert2(cert, -1);
+    
+    /*
+     * Try to retrieve a CRL corresponding to the issuer of
+     * the current certificate 
+     */    
+    n = sk_X509_CRL_num(crls);
+    for(i = 0; i < n; i++) {
+	crl = sk_X509_CRL_value(crls, i);     
+	issuer = X509_CRL_get_issuer(crl);
+	if(xmlSecSymbianCryptoX509NamesCompare(X509_CRL_get_issuer(crl), issuer) == 0) { 
+	    break;
+	}
+    }
+    if((i >= n) || (!crl)){
+	/* no crls for this issuer */
+	return(1);
+    }
+
+    /* 
+     * Check date of CRL to make sure it's not expired 
+     */
+    ret = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+    if (ret == 0) {
+	/* crl expired */
+	return(1);
+    }
+    
+    /* 
+     * Check if the current certificate is revoked by this CRL
+     */
+    n = sk_num(X509_CRL_get_REVOKED(crl));
+    for (i = 0; i < n; i++) {
+        revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
+        if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			NULL,
+			XMLSEC_ERRORS_R_CERT_REVOKED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(0);
+        }
+    }
+#endif		//XMLSEC_FUTURE_SUPPORT    
+    return(1);    
+}
+
+
+/**
+ * xmlSecSymbianCryptoX509NameRead:
+ */       
+static X509_NAME *
+xmlSecSymbianCryptoX509NameRead(xmlSecByte *str, int len) {
+    xmlSecByte name[256];
+    xmlSecByte value[256];
+    int nameLen, valueLen;
+    X509_NAME *nm = NULL;
+
+    xmlSecAssert2(str, NULL);
+    
+#ifdef XMLSEC_FUTURE_SUPPORT    
+    nm = X509_NAME_new();
+    if(!nm) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_NAME_new",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    while(len > 0) {
+	/* skip spaces after comma or semicolon */
+	while((len > 0) && isspace(*str)) {
+	    ++str; --len;
+	}
+
+	nameLen = xmlSecSymbianCryptoX509NameStringRead(&str, &len, name, sizeof(name), '=', 0);	
+	if(nameLen < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecSymbianCryptoX509NameStringRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    X509_NAME_free(nm);
+	    return(NULL);
+	}
+	name[nameLen] = '\0';
+	if(len > 0) {
+	    ++str; --len;
+	    if((*str) == '\"') {
+		++str; --len;
+		valueLen = xmlSecSymbianCryptoX509NameStringRead(&str, &len, 
+					value, sizeof(value), '"', 1);	
+		if(valueLen < 0) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				"xmlSecSymbianCryptoX509NameStringRead",
+				XMLSEC_ERRORS_R_XMLSEC_FAILED,
+				XMLSEC_ERRORS_NO_MESSAGE);
+		    X509_NAME_free(nm);
+		    return(NULL);
+    		}
+		
+		/* skip quote */
+		if((len <= 0) || ((*str) != '\"')) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				NULL,
+				XMLSEC_ERRORS_R_INVALID_DATA,
+				"quote is expected:%s",
+				xmlSecErrorsSafeString(str));
+		    X509_NAME_free(nm);
+		    return(NULL);
+		}
+                ++str; --len;
+
+		/* skip spaces before comma or semicolon */
+		while((len > 0) && isspace(*str)) {
+		    ++str; --len;
+		}
+		if((len > 0) && ((*str) != ',')) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				NULL,
+				XMLSEC_ERRORS_R_INVALID_DATA,
+				"comma is expected:%s",
+				xmlSecErrorsSafeString(str));
+		    X509_NAME_free(nm);
+		    return(NULL);
+		}
+		if(len > 0) {
+		    ++str; --len;
+		}
+		type = MBSTRING_ASC;
+	    } else if((*str) == '#') {
+		/* Not implemented currently */
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    NULL,
+			    XMLSEC_ERRORS_R_INVALID_DATA,
+			    "reading octect values is not implemented yet");
+    	        X509_NAME_free(nm);
+		return(NULL);
+	    } else {
+		valueLen = xmlSecSymbianCryptoX509NameStringRead(&str, &len, 
+					value, sizeof(value), ',', 1);	
+		if(valueLen < 0) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				"xmlSecSymbianCryptoX509NameStringRead",
+				XMLSEC_ERRORS_R_XMLSEC_FAILED,
+				XMLSEC_ERRORS_NO_MESSAGE);
+    	    	    X509_NAME_free(nm);
+		    return(NULL);
+    		}
+		type = MBSTRING_ASC;
+	    } 			
+	} else {
+	    valueLen = 0;
+	}
+	value[valueLen] = '\0';
+	if(len > 0) {
+	    ++str; --len;
+	}	
+	X509_NAME_add_entry_by_txt(nm, (char*)name, type, value, valueLen, -1, 0);
+    }
+#endif	//XMLSEC_FUTURE_SUPPORT    
+    return(nm);
+}
+
+
+
+/**
+ * xmlSecSymbianCryptoX509NameStringRead:
+ */
+static int 
+xmlSecSymbianCryptoX509NameStringRead(xmlSecByte **str, int *strLen, 
+			xmlSecByte *res, int resLen,
+			xmlSecByte delim, int ingoreTrailingSpaces) {
+    xmlSecByte *p, *q, *nonSpace; 
+
+    xmlSecAssert2(str, -1);
+    xmlSecAssert2(strLen, -1);
+    xmlSecAssert2(res, -1);
+    
+    p = (*str);
+    nonSpace = q = res;
+    while(((p - (*str)) < (*strLen)) && ((*p) != delim) && ((q - res) < resLen)) { 
+	if((*p) != '\\') {
+	    if(ingoreTrailingSpaces && !isspace(*p)) nonSpace = q;	
+	    *(q++) = *(p++);
+	} else {
+	    ++p;
+	    nonSpace = q;    
+	    if(xmlSecIsHex((*p))) {
+		if((p - (*str) + 1) >= (*strLen)) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				NULL,
+				XMLSEC_ERRORS_R_INVALID_DATA,
+				"two hex digits expected");
+	    	    return(-1);
+		}
+		*(q++) = xmlSecGetHex(p[0]) * 16 + xmlSecGetHex(p[1]);
+		p += 2;
+	    } else {
+		if(((++p) - (*str)) >= (*strLen)) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+				NULL,
+				XMLSEC_ERRORS_R_INVALID_DATA,
+				"escaped symbol missed");
+		    return(-1);
+		}
+		*(q++) = *(p++); 
+	    }
+	}	    
+    }
+    if(((p - (*str)) < (*strLen)) && ((*p) != delim)) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_INVALID_SIZE,
+		    "buffer is too small");
+	return(-1);
+    }
+    (*strLen) -= (p - (*str));
+    (*str) = p;
+    return((ingoreTrailingSpaces) ? nonSpace - res + 1 : q - res);
+}
+
+static
+int xmlSecSymbianCryptoX509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) {
+    int i,ret;
+/*    
+    const X509_NAME_ENTRY *na,*nb;
+
+    xmlSecAssert2(a != NULL, -1);
+    xmlSecAssert2(b != NULL, 1);
+	
+    if (sk_X509_NAME_ENTRY_num(a->entries) != sk_X509_NAME_ENTRY_num(b->entries)) {
+	return sk_X509_NAME_ENTRY_num(a->entries) - sk_X509_NAME_ENTRY_num(b->entries);
+    }
+	
+    for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--) {
+	na=sk_X509_NAME_ENTRY_value(a->entries,i);
+	nb=sk_X509_NAME_ENTRY_value(b->entries,i);
+	
+	ret = xmlSecSymbianCryptoX509_NAME_ENTRY_cmp(&na, &nb);
+	if(ret != 0) {
+	    return(ret);
+	}
+    }	
+*/
+    return(0);
+}
+
+
+/** 
+ * xmlSecSymbianCryptoX509NamesCompare:
+ *
+ * we have to sort X509_NAME entries to get correct results.
+ * This is ugly but SymbianCrypto does not support it
+ */
+static int		
+xmlSecSymbianCryptoX509NamesCompare(X509_NAME *a, X509_NAME *b) {
+    X509_NAME *a1 = NULL;
+    X509_NAME *b1 = NULL;
+    int ret = -1;
+    
+    xmlSecAssert2(a, -1);    
+    xmlSecAssert2(b, 1);    
+#ifdef XMLSEC_FUTURE_SUPPORT    
+    a1 = X509_NAME_dup(a);
+    if(!a1) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_NAME_dup",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+        return(-1);
+    }
+    b1 = X509_NAME_dup(b);
+    if(!b1) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "X509_NAME_dup",
+		    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+        return(1);
+    }
+        
+    /* sort both */
+    sk_X509_NAME_ENTRY_set_cmp_func(a1->entries, xmlSecSymbianCryptoX509_NAME_ENTRY_cmp);
+    sk_X509_NAME_ENTRY_sort(a1->entries);
+    sk_X509_NAME_ENTRY_set_cmp_func(b1->entries, xmlSecSymbianCryptoX509_NAME_ENTRY_cmp);
+    sk_X509_NAME_ENTRY_sort(b1->entries);
+
+    /* actually compare */
+    ret = xmlSecSymbianCryptoX509_NAME_cmp(a1, b1);
+    
+    /* cleanup */
+    X509_NAME_free(a1);
+    X509_NAME_free(b1);
+#endif		//XMLSEC_FUTURE_SUPPORT    
+    return(ret);
+}
+			
+
+/**
+ * xmlSecSymbianCryptoX509_NAME_ENTRY_cmp:
+ */
+#ifdef XMLSEC_FUTURE_SUPPORT
+static int 
+xmlSecSymbianCryptoX509_NAME_ENTRY_cmp(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b) {
+    int ret;
+    
+    xmlSecAssert2(a, -1);
+    xmlSecAssert2(b, 1);
+    xmlSecAssert2((*a), -1);
+    xmlSecAssert2((*b), 1);
+
+    /* first compare values */    
+    if((!((*a)->value)) && ((*b)->value)) {
+	return(-1);
+    } else if(((*a)->value) && (!((*b)->value))) {
+	return(1);
+    } else if((!((*a)->value)) && (!((*b)->value))) {
+	return(0);
+    }	
+    
+    ret = (*a)->value->length - (*b)->value->length;
+    if(ret != 0) {
+	return(ret);
+    }
+		
+    ret = memcmp((*a)->value->data, (*b)->value->data, (*a)->value->length);
+    if(ret != 0) {
+	return(ret);
+    }
+
+    /* next compare names */
+    return(OBJ_cmp((*a)->object, (*b)->object));
+}
+#endif	//XMLSEC_FUTURE_SUPPORT
+
+
+#endif /* XMLSEC_NO_X509 */
+
+