diff -r 000000000000 -r e35f40988205 xmlsecurityengine/xmlseccrypto/src/xmlsecc_x509vfy.cpp --- /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 + * 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 +#include +#include +#include +#include + +#include + +#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 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 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 */ + +