/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/gnutls/x509vfy.c
1 406 строк
44 KB
lsh123
Update file headers for doxygen, use common copyright header, bump copyright to 2026 (#1122)
07 апр 2026, 04:13
Не верифицирован
07 апр 2026, 04:13
2e557ee
Код
Авторство
О чём код?
/** * XML Security Library (http://www.aleksey.com/xmlsec). * * This is free software; see the Copyright file in the source distribution for precise wording. * * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. */ /** * @addtogroup xmlsec_gnutls_x509 * @brief X509 certificates verification support functions for GnuTLS. */ #include "globals.h" #ifndef XMLSEC_NO_X509 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/keyinfo.h> #include <xmlsec/keysmngr.h> #include <xmlsec/base64.h> #include <xmlsec/errors.h> #include <xmlsec/private.h> #include <xmlsec/gnutls/crypto.h> #include <xmlsec/gnutls/x509.h> #include "private.h" #include "../cast_helpers.h" /****************************************************************************** * * Internal GnuTLS X509 store CTX * *****************************************************************************/ typedef struct _xmlSecGnuTLSX509StoreCtx xmlSecGnuTLSX509StoreCtx, *xmlSecGnuTLSX509StoreCtxPtr; struct _xmlSecGnuTLSX509StoreCtx { xmlSecPtrList certsTrusted; xmlSecPtrList certsUntrusted; xmlSecPtrList crls; }; /****************************************************************************** * * xmlSecGnuTLSKeyDataStoreX509Id: * *****************************************************************************/ XMLSEC_KEY_DATA_STORE_DECLARE(GnuTLSX509Store, xmlSecGnuTLSX509StoreCtx) #define xmlSecGnuTLSX509StoreSize XMLSEC_KEY_DATA_STORE_SIZE(GnuTLSX509Store) static int xmlSecGnuTLSX509StoreInitialize (xmlSecKeyDataStorePtr store); static void xmlSecGnuTLSX509StoreFinalize (xmlSecKeyDataStorePtr store); static xmlSecKeyDataStoreKlass xmlSecGnuTLSX509StoreKlass = { sizeof(xmlSecKeyDataStoreKlass), xmlSecGnuTLSX509StoreSize, /* data */ xmlSecNameX509Store, /* const xmlChar* name; */ /* constructors/destructor */ xmlSecGnuTLSX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */ xmlSecGnuTLSX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */ /* reserved for the future */ NULL, /* void* reserved0; */ NULL, /* void* reserved1; */ }; static gnutls_x509_crt_t xmlSecGnuTLSX509FindCert (xmlSecPtrListPtr certs, xmlSecGnuTLSX509FindCertCtxPtr findCertCtx); static gnutls_x509_crt_t xmlSecGnuTLSX509FindSignedCert (xmlSecPtrListPtr certs, gnutls_x509_crt_t cert); static gnutls_x509_crt_t xmlSecGnuTLSX509FindSignerCert (xmlSecPtrListPtr certs, gnutls_x509_crt_t cert); static int xmlSecGnuTLSX509StoreVerifyCert (xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crt_t* certs_chain, xmlSecSize certs_chain_size, gnutls_x509_crt_t* trusted, xmlSecSize trusted_size, gnutls_x509_crl_t* crls, xmlSecSize crls_size, const xmlSecKeyInfoCtx* keyInfoCtx); /** * @brief The GnuTLS X509 certificates key data store klass. * @return pointer to GnuTLS X509 certificates key data store klass. */ xmlSecKeyDataStoreId xmlSecGnuTLSX509StoreGetKlass(void) { return(&xmlSecGnuTLSX509StoreKlass); } gnutls_x509_crt_t xmlSecGnuTLSX509StoreFindCertByValue(xmlSecKeyDataStorePtr store, xmlSecKeyX509DataValuePtr x509Value) { xmlSecGnuTLSX509StoreCtxPtr ctx; xmlSecGnuTLSX509FindCertCtx findCertCtx; int ret; gnutls_x509_crt_t res = NULL; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), NULL); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, NULL); ret = xmlSecGnuTLSX509FindCertCtxInitializeFromValue(&findCertCtx, x509Value); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509FindCertCtxInitializeFromValue", NULL); xmlSecGnuTLSX509FindCertCtxFinalize(&findCertCtx); return(NULL); } if(res == NULL) { res = xmlSecGnuTLSX509FindCert(&(ctx->certsTrusted), &findCertCtx); } if(res == NULL) { res = xmlSecGnuTLSX509FindCert(&(ctx->certsUntrusted), &findCertCtx); } /* done */ xmlSecGnuTLSX509FindCertCtxFinalize(&findCertCtx); return(res); } xmlSecKeyPtr xmlSecGnuTLSX509FindKeyByValue(xmlSecPtrListPtr keysList, xmlSecKeyX509DataValuePtr x509Value) { xmlSecGnuTLSX509FindCertCtx findCertCtx; xmlSecSize keysListSize, ii; xmlSecKeyPtr res = NULL; int ret; xmlSecAssert2(keysList != NULL, NULL); xmlSecAssert2(x509Value != NULL, NULL); ret = xmlSecGnuTLSX509FindCertCtxInitializeFromValue(&findCertCtx, x509Value); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509FindCertCtxInitializeFromValue", NULL); xmlSecGnuTLSX509FindCertCtxFinalize(&findCertCtx); return(NULL); } keysListSize = xmlSecPtrListGetSize(keysList); for(ii = 0; ii < keysListSize; ++ii) { xmlSecKeyPtr key; xmlSecKeyDataPtr keyData; gnutls_x509_crt_t keyCert; /* get key's cert from x509 key data */ key = (xmlSecKeyPtr)xmlSecPtrListGetItem(keysList, ii); if(key == NULL) { continue; } keyData = xmlSecKeyGetData(key, xmlSecGnuTLSKeyDataX509Id); if(keyData == NULL) { continue; } keyCert = xmlSecGnuTLSKeyDataX509GetKeyCert(keyData); if(keyCert == NULL) { continue; } /* does it match? */ ret = xmlSecGnuTLSX509FindCertCtxMatch(&findCertCtx, keyCert); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509FindCertCtxMatch", NULL); xmlSecGnuTLSX509FindCertCtxFinalize(&findCertCtx); return(NULL); } else if(ret == 1) { res = key; break; } } /* done */ xmlSecGnuTLSX509FindCertCtxFinalize(&findCertCtx); return(res); } static int xmlSecGnuTLSX509CheckCrtTime(const gnutls_x509_crt_t cert, time_t ts) { time_t notValidBefore, notValidAfter; xmlSecAssert2(cert != NULL, -1); xmlSecAssert2(ts >= 0, -1); /* get expiration times */ notValidBefore = gnutls_x509_crt_get_activation_time(cert); if(notValidBefore == (time_t)-1) { xmlSecGnuTLSError("gnutls_x509_crt_get_activation_time", GNUTLS_E_SUCCESS, NULL); return(-1); } notValidAfter = gnutls_x509_crt_get_expiration_time(cert); if(notValidAfter == (time_t)-1) { xmlSecGnuTLSError("gnutls_x509_crt_get_expiration_time", GNUTLS_E_SUCCESS, NULL); return(-1); } /* check */ if(ts < notValidBefore) { /* TODO: print cert subject */ xmlSecOtherError(XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, NULL, NULL); return(0); } if(ts > notValidAfter) { /* TODO: print cert subject */ xmlSecOtherError(XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, NULL, NULL); return(0); } /* good! */ return(1); } static int xmlSecGnuTLSX509CheckCrtsTime(const gnutls_x509_crt_t * cert_list, xmlSecSize cert_list_size, time_t ts) { xmlSecSize ii; int ret; xmlSecAssert2(cert_list != NULL, -1); for(ii = 0; ii < cert_list_size; ++ii) { const gnutls_x509_crt_t cert = cert_list[ii]; if(cert == NULL) { continue; } ret = xmlSecGnuTLSX509CheckCrtTime(cert, ts); if(ret < 0) { xmlSecInternalError("", NULL); return(-1); } else if(ret == 0) { /* cert not valid yet or expired */ return(0); } } /* GOOD! */ return(1); } static int xmlSecGnuTLSX509StoreGetTrustedCerts(xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crt_t** trusted, xmlSecSize* trusted_size ) { gnutls_x509_crt_t* res; xmlSecSize ii, res_size; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(trusted != NULL, -1); xmlSecAssert2(trusted_size != NULL, -1); /* get sizes */ res_size = xmlSecPtrListGetSize(&(ctx->certsTrusted)); if(res_size <= 0) { (*trusted) = NULL; (*trusted_size) = 0; return(0); } /* copy list */ res = (gnutls_x509_crt_t *)xmlMalloc(sizeof(gnutls_x509_crt_t) * res_size); if(res == NULL) { xmlSecMallocError(sizeof(gnutls_x509_crt_t) * res_size, NULL); return(-1); } for(ii = 0; ii < res_size; ++ii) { res[ii] = xmlSecPtrListGetItem(&(ctx->certsTrusted), ii); if(res[ii] == NULL) { xmlSecInternalError("xmlSecPtrListGetItem(certsTrusted)", NULL); xmlFree(res); return(-1); } } /* done */ (*trusted) = res; (*trusted_size) = res_size; return(0); } static int xmlSecGnuTLSX509StoreGetCrls(xmlSecGnuTLSX509StoreCtxPtr ctx, xmlSecPtrListPtr extra_crls, gnutls_x509_crl_t** crls, xmlSecSize* crls_size ) { gnutls_x509_crl_t* res; xmlSecSize ii, res_size, res_pos = 0; xmlSecSize extra_crls_size, ctx_crls_size; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(extra_crls != NULL, -1); xmlSecAssert2(crls != NULL, -1); xmlSecAssert2(crls_size != NULL, -1); /* get sizes */ extra_crls_size = xmlSecPtrListGetSize(extra_crls); ctx_crls_size = xmlSecPtrListGetSize(&(ctx->crls)); res_size = extra_crls_size + ctx_crls_size; if(res_size <= 0) { (*crls) = NULL; (*crls_size) = 0; return(0); } /* copy lists */ res = (gnutls_x509_crl_t *)xmlMalloc(sizeof(gnutls_x509_crl_t) * res_size); if(res == NULL) { xmlSecMallocError(sizeof(gnutls_x509_crl_t) * res_size, NULL); return(-1); } for(ii = 0; ii < extra_crls_size; ++ii, ++res_pos) { res[res_pos] = xmlSecPtrListGetItem(extra_crls, ii); if(res[res_pos] == NULL) { xmlSecInternalError("xmlSecPtrListGetItem(extra_crls)", NULL); xmlFree(res); return(-1); } } for(ii = 0; ii < ctx_crls_size; ++ii, ++res_pos) { res[res_pos] = xmlSecPtrListGetItem(&(ctx->crls), ii); if(res[res_pos] == NULL) { xmlSecInternalError("xmlSecPtrListGetItem(crls)", NULL); xmlFree(res); return(-1); } } /* done */ (*crls) = res; (*crls_size) = res_size; return(0); } static int xmlSecGnuTLSX509StoreGetCertsChain(xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crt_t cert_to_verify, xmlSecPtrListPtr extra_certs, gnutls_x509_crt_t* certs_chain, xmlSecSize certs_chain_max_size, xmlSecSize* certs_chain_cur_size ) { gnutls_x509_crt_t cert, tmp; xmlSecSize ii, extra_certs_size, ctx_certs_size; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(extra_certs != NULL, -1); xmlSecAssert2(cert_to_verify != NULL, -1); xmlSecAssert2(certs_chain != NULL, -1); xmlSecAssert2(certs_chain_cur_size != NULL, -1); /* get sizes */ extra_certs_size = xmlSecPtrListGetSize(extra_certs); ctx_certs_size = xmlSecPtrListGetSize(&(ctx->certsUntrusted)); xmlSecAssert2((extra_certs_size + ctx_certs_size + 1) <= certs_chain_max_size, -1); /* construct the chain starting at cert_to_verify */ for(cert = cert_to_verify, ii = 0; ((cert != NULL) && (ii < certs_chain_max_size)); ++ii) { certs_chain[ii] = cert; /* find the cert that signed this one */ tmp = xmlSecGnuTLSX509FindSignerCert(extra_certs, cert); if(tmp == NULL) { tmp = xmlSecGnuTLSX509FindSignerCert(&(ctx->certsUntrusted), cert); } if(tmp == cert) { break; } cert = tmp; } (*certs_chain_cur_size) = ii; return(0); } static int xmlSecGnuTLSX509GetVerificationFlags(const xmlSecKeyInfoCtx* keyInfoCtx, unsigned int * flags) { xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(flags != NULL, -1); (*flags) = 0; /* gnutls doesn't allow to specify "verification" timestamp so * we have to do it ourselves. Unfortunately it doesn't work * for CRLs yet: https://github.com/lsh123/xmlsec/issues/579 */ if(keyInfoCtx->certsVerificationTime > 0) { (*flags) |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS; } if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_SKIP_TIME_CHECKS) != 0) { (*flags) |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS; } (*flags) |= GNUTLS_VERIFY_ALLOW_UNSORTED_CHAIN; if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_SKIP_STRICT_CHECKS) != 0) { /* Compatibility mode requested by the caller/test harness. */ (*flags) |= GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2; (*flags) |= GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5; (*flags) |= GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1; } return(0); } /* Verify issuer certificate chain against trusted certs: 1 if valid, 0 if not, < 0 if error */ static int xmlSecGnuTLSX509StoreVerifyIssuerCert(xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crt_t issuer_cert, const xmlSecKeyInfoCtx* keyInfoCtx ) { gnutls_x509_crt_t* certs_chain = NULL; xmlSecSize certs_chain_size, certs_chain_cur_size = 0; gnutls_x509_crt_t* trusted = NULL; xmlSecSize trusted_size = 0; int ret; int res = -1; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(issuer_cert != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); ret = xmlSecGnuTLSX509StoreGetTrustedCerts(ctx, &trusted, &trusted_size); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreGetTrustedCerts", NULL); goto done; } if(trusted_size <= 0) { res = 0; goto done; } certs_chain_size = xmlSecPtrListGetSize(&(ctx->certsUntrusted)) + 1; certs_chain = (gnutls_x509_crt_t*)xmlMalloc(sizeof(gnutls_x509_crt_t) * certs_chain_size); if(certs_chain == NULL) { xmlSecMallocError(sizeof(gnutls_x509_crt_t) * certs_chain_size, NULL); goto done; } /* Build issuer chain using untrusted certs from store. */ certs_chain[0] = issuer_cert; certs_chain_cur_size = 1; if((xmlSecGnuTLSX509CertIsSelfSigned(issuer_cert) != 1) && (certs_chain_size > 1)) { xmlSecSize ii; gnutls_x509_crt_t cert = issuer_cert; for(ii = 1; ii < certs_chain_size; ++ii) { gnutls_x509_crt_t tmp; tmp = xmlSecGnuTLSX509FindSignerCert(&(ctx->certsUntrusted), cert); if((tmp == NULL) || (tmp == cert)) { break; } certs_chain[ii] = tmp; certs_chain_cur_size = ii + 1; cert = tmp; } } ret = xmlSecGnuTLSX509StoreVerifyCert(ctx, certs_chain, certs_chain_cur_size, trusted, trusted_size, NULL, 0, keyInfoCtx); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyCert", NULL); goto done; } res = ret; done: if(certs_chain != NULL) { xmlFree(certs_chain); } if(trusted != NULL) { xmlFree(trusted); } return(res); } /* returns 1 if verified, 0 if not, and < 0 value if an error occurs */ static int xmlSecGnuTLSX509StoreVerifyCert(xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crt_t* certs_chain, xmlSecSize certs_chain_size, gnutls_x509_crt_t* trusted, xmlSecSize trusted_size, gnutls_x509_crl_t* crls, xmlSecSize crls_size, const xmlSecKeyInfoCtx* keyInfoCtx ) { unsigned int certs_chain_len, trusted_len, crls_len; unsigned int flags = 0; unsigned int verify = 0; int err; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(certs_chain != NULL, -1); xmlSecAssert2(certs_chain_size >= 1, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); /* do we even need to verify the cert? */ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) != 0) { return(1); } ret = xmlSecGnuTLSX509GetVerificationFlags(keyInfoCtx, &flags); if (ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509GetVerificationFlags", NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_TO_UINT(certs_chain_size, certs_chain_len, return(-1), NULL); XMLSEC_SAFE_CAST_SIZE_TO_UINT(trusted_size, trusted_len, return(-1), NULL); XMLSEC_SAFE_CAST_SIZE_TO_UINT(crls_size, crls_len, return(-1), NULL); err = gnutls_x509_crt_list_verify( certs_chain, certs_chain_len, trusted, trusted_len, crls, crls_len, flags, &verify); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_list_verify", err, NULL); return(-1); } /* The certificate verification output will be put in verify and will be one or more of the * gnutls_certificate_status_t enumerated elements bitwise or'd. */ if(verify != 0) { xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, NULL, "gnutls_x509_crt_list_verify: verification failed: status=%u", verify); return(0); } /* gnutls doesn't allow to specify "verification" timestamp so * we have to do it ourselves */ if(keyInfoCtx->certsVerificationTime > 0) { ret = xmlSecGnuTLSX509CheckCrtsTime(certs_chain, certs_chain_size, keyInfoCtx->certsVerificationTime); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509CheckCrtsTime", NULL); return(-1); } if(ret != 1) { return(0); } } /* done! */ return(1); } /** * @brief Verifies @p key with the keys manager @p mngr created with #xmlSecCryptoAppDefaultKeysMngrInit * @param store the pointer to X509 key data store klass. * @param key the pointer to key. * @param keyInfoCtx the key info context for verification. * * function: * - Checks that key certificate is present * - Checks that key certificate is valid * * Adds @p key to the keys manager @p mngr created with #xmlSecCryptoAppDefaultKeysMngrInit * function. * * @return 1 if key is verified, 0 otherwise, or a negative value if an error occurs. */ int xmlSecGnuTLSX509StoreVerifyKey(xmlSecKeyDataStorePtr store, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecGnuTLSX509StoreCtxPtr ctx; xmlSecKeyDataPtr x509Data; gnutls_x509_crt_t key_cert; xmlSecPtrListPtr key_certs; xmlSecPtrListPtr key_crls; gnutls_x509_crt_t * certs_chain = NULL; xmlSecSize certs_chain_size = 0; xmlSecSize certs_chain_cur_size = 0; gnutls_x509_crt_t* trusted = NULL; xmlSecSize trusted_size = 0; gnutls_x509_crl_t* crls = NULL; xmlSecSize crls_size = 0; int ret; int res = -1; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, -1); /* retrieve X509 data and get key cert, other certs and crls */ x509Data = xmlSecKeyGetData(key, xmlSecGnuTLSKeyDataX509Id); if(x509Data == NULL) { xmlSecInternalError("xmlSecKeyGetData(xmlSecGnuTLSKeyDataX509Id)", xmlSecKeyDataStoreGetName(store)); res = 0; /* key cannot be verified w/o key cert */ goto done; } key_cert = xmlSecGnuTLSKeyDataX509GetKeyCert(x509Data); if(key_cert == NULL) { xmlSecInternalError("xmlSecGnuTLSKeyDataX509GetKeyCert", xmlSecKeyDataStoreGetName(store)); res = 0; /* key cannot be verified w/o key cert */ goto done; } key_certs = xmlSecGnuTLSKeyDataX509GetCerts(x509Data); if(key_certs == NULL) { xmlSecInternalError("xmlSecGnuTLSKeyDataX509GetCerts", xmlSecKeyDataStoreGetName(store)); goto done; } key_crls = xmlSecGnuTLSKeyDataX509GetCrls(x509Data); if(key_crls == NULL) { xmlSecInternalError("xmlSecGnuTLSKeyDataX509GetCrls", xmlSecKeyDataStoreGetName(store)); goto done; } /* get trusted certs and crls lists */ ret = xmlSecGnuTLSX509StoreGetTrustedCerts(ctx, &trusted, &trusted_size); if(ret< 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreGetTrustedCerts", xmlSecKeyDataStoreGetName(store)); goto done; } ret = xmlSecGnuTLSX509StoreGetCrls(ctx, key_crls, &crls, &crls_size); if(ret< 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreGetCrls", xmlSecKeyDataStoreGetName(store)); goto done; } /* prepare buffer for the certs chain */ certs_chain_size = xmlSecPtrListGetSize(key_certs) + xmlSecPtrListGetSize(&(ctx->certsUntrusted)) + 1; if(certs_chain_size > 0) { certs_chain = (gnutls_x509_crt_t *)xmlMalloc(sizeof(gnutls_x509_crt_t) * certs_chain_size); if(certs_chain == NULL) { xmlSecMallocError(sizeof(gnutls_x509_crt_t) * certs_chain_size, xmlSecKeyDataStoreGetName(store)); goto done; } } /* build the chain */ ret = xmlSecGnuTLSX509StoreGetCertsChain(ctx, key_cert, key_certs, certs_chain, certs_chain_size, &certs_chain_cur_size); if(ret < 0) { xmlSecInternalError("xmlSecPtrListGetItem(certs)", xmlSecKeyDataStoreGetName(store)); goto done; } /* try to verify */ ret = xmlSecGnuTLSX509StoreVerifyCert(ctx, certs_chain, certs_chain_cur_size, trusted, trusted_size, crls, crls_size, keyInfoCtx); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyCert(certs)", xmlSecKeyDataStoreGetName(store)); goto done; } /* done! */ if(ret == 1) { res = 1; } else { res = 0; } done: /* cleanup */ if(certs_chain != NULL) { xmlFree(certs_chain); } if(trusted != NULL) { xmlFree(trusted); } if(crls != NULL) { xmlFree(crls); } return(res); } /** * @brief Verifies @p certs list. * @param store the pointer to X509 key data store klass. * @param certs the untrusted certificates. * @param crls the crls. * @param keyInfoCtx the pointer to <dsig:KeyInfo/> element processing context. * @return pointer to the first verified certificate from @p certs. */ gnutls_x509_crt_t xmlSecGnuTLSX509StoreVerify(xmlSecKeyDataStorePtr store, xmlSecPtrListPtr certs, xmlSecPtrListPtr crls, const xmlSecKeyInfoCtx* keyInfoCtx) { xmlSecGnuTLSX509StoreCtxPtr ctx; gnutls_x509_crt_t res = NULL; xmlSecSize certs_size = 0; gnutls_x509_crt_t * certs_chain = NULL; xmlSecSize certs_chain_size = 0; gnutls_x509_crt_t * trusted = NULL; xmlSecSize trusted_size = 0; gnutls_x509_crl_t * all_crls = NULL; xmlSecSize all_crls_size = 0; xmlSecSize ii; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), NULL); xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(crls != NULL, NULL); xmlSecAssert2(keyInfoCtx != NULL, NULL); certs_size = xmlSecPtrListGetSize(certs); if(certs_size <= 0) { /* nothing to do */ return(NULL); } ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, NULL); /* get trusted certs and crls lists */ ret = xmlSecGnuTLSX509StoreGetTrustedCerts(ctx, &trusted, &trusted_size); if(ret< 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreGetTrustedCerts", xmlSecKeyDataStoreGetName(store)); goto done; } ret = xmlSecGnuTLSX509StoreGetCrls(ctx, crls, &all_crls, &all_crls_size); if(ret< 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreGetCrls", xmlSecKeyDataStoreGetName(store)); goto done; } /* prepare buffer for the certs chain */ certs_chain_size = certs_size + xmlSecPtrListGetSize(&(ctx->certsUntrusted)) + 1; if(certs_chain_size > 0) { certs_chain = (gnutls_x509_crt_t *)xmlMalloc(sizeof(gnutls_x509_crt_t) * certs_chain_size); if(certs_chain == NULL) { xmlSecMallocError(sizeof(gnutls_x509_crt_t) * certs_chain_size, xmlSecKeyDataStoreGetName(store)); goto done; } } /* we are going to build all possible cert chains and try to verify them */ for(ii = 0; (ii < certs_size) && (res == NULL); ++ii) { gnutls_x509_crt_t cert; xmlSecSize certs_chain_cur_size = 0; cert = xmlSecPtrListGetItem(certs, ii); if(cert == NULL) { xmlSecInternalError("xmlSecPtrListGetItem(certs)", xmlSecKeyDataStoreGetName(store)); goto done; } if(xmlSecGnuTLSX509CertIsSelfSigned(cert) != 1) { /* check if we are the "leaf" node in the certs chain */ if(xmlSecGnuTLSX509FindSignedCert(certs, cert) != NULL) { continue; } /* build the chain */ ret = xmlSecGnuTLSX509StoreGetCertsChain(ctx, cert, certs, certs_chain, certs_chain_size, &certs_chain_cur_size); if(ret < 0) { xmlSecInternalError("xmlSecPtrListGetItem(certs)", xmlSecKeyDataStoreGetName(store)); goto done; } } else if (certs_size == 1) { /* only do self signed cert when it is the only cert */ /* chain for self signed cert is easy */ certs_chain[0] = cert; certs_chain_cur_size = 1; } else { continue; } /* try to verify */ ret = xmlSecGnuTLSX509StoreVerifyCert(ctx, certs_chain, certs_chain_cur_size, trusted, trusted_size, all_crls, all_crls_size, keyInfoCtx); if(ret < 0) { /* ignore all errors, don't stop, continue! */ xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyCert(certs)", xmlSecKeyDataStoreGetName(store)); continue; } else if (ret != 1) { /* ignore if chain can't be verified, don't stop, continue! */ continue; } /* DONE! */ res = cert; } done: /* cleanup */ if(certs_chain != NULL) { xmlFree(certs_chain); } if(trusted != NULL) { xmlFree(trusted); } if(all_crls != NULL) { xmlFree(all_crls); } return(res); } /** * @brief Adds cert to the trusted or untrusted store. * @details Adds trusted (root) or untrusted certificate to the store. * @param store the pointer to X509 key data store klass. * @param cert the pointer to GnuTLS X509 certificate. * @param type the certificate type (trusted/untrusted). * @return 0 on success or a negative value if an error occurs. */ int xmlSecGnuTLSX509StoreAdoptCert(xmlSecKeyDataStorePtr store, gnutls_x509_crt_t cert, xmlSecKeyDataType type) { xmlSecGnuTLSX509StoreCtxPtr ctx; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1); xmlSecAssert2(cert != NULL, -1); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, -1); if((type & xmlSecKeyDataTypeTrusted) != 0) { ret = xmlSecPtrListAdd(&(ctx->certsTrusted), cert); if(ret < 0) { xmlSecInternalError("xmlSecPtrListAdd(trusted)", xmlSecKeyDataStoreGetName(store)); return(-1); } } else { ret = xmlSecPtrListAdd(&(ctx->certsUntrusted), cert); if(ret < 0) { xmlSecInternalError("xmlSecPtrListAdd(untrusted)", xmlSecKeyDataStoreGetName(store)); return(-1); } } /* done */ return(0); } /** * @brief Adds CRL to the store. * @param store the pointer to X509 key data store klass. * @param crl the pointer to GnuTLS X509 CRL. * @return 0 on success or a negative value if an error occurs. */ int xmlSecGnuTLSX509StoreAdoptCrl(xmlSecKeyDataStorePtr store, gnutls_x509_crl_t crl) { xmlSecGnuTLSX509StoreCtxPtr ctx; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1); xmlSecAssert2(crl != NULL, -1); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, -1); ret = xmlSecPtrListAdd(&(ctx->crls), crl); if(ret < 0) { xmlSecInternalError("xmlSecPtrListAdd(crls)", xmlSecKeyDataStoreGetName(store)); return(-1); } /* done */ return(0); } /* Verify CRL time validity: 1 if valid, 0 if not valid, < 0 if error */ static int xmlSecGnuTLSX509StoreVerifyCrlTimeValidity(gnutls_x509_crl_t crl, xmlSecKeyInfoCtxPtr keyInfoCtx, const xmlChar* storeName ) { time_t this_update, next_update, verification_time; int err; xmlSecAssert2(crl != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); /* Get verification time */ verification_time = (keyInfoCtx->certsVerificationTime > 0) ? keyInfoCtx->certsVerificationTime : time(NULL); /* Verify this_update */ this_update = gnutls_x509_crl_get_this_update(crl); if(this_update == (time_t)-1) { xmlSecGnuTLSError("gnutls_x509_crl_get_this_update", GNUTLS_E_SUCCESS, storeName); return(-1); } if(this_update > verification_time) { /* CRL not yet valid */ size_t dn_size = 256; char dn_buf[256]; err = gnutls_x509_crl_get_issuer_dn(crl, dn_buf, &dn_size); if(err == GNUTLS_E_SUCCESS) { xmlSecOtherError2(XMLSEC_ERRORS_R_CRL_NOT_YET_VALID, storeName, "issuer=%s", dn_buf); } else { xmlSecOtherError(XMLSEC_ERRORS_R_CRL_NOT_YET_VALID, storeName, NULL); } return(0); } /* Verify next_update */ next_update = gnutls_x509_crl_get_next_update(crl); if(next_update != (time_t)-1) { if(next_update < verification_time) { /* CRL expired */ size_t dn_size = 256; char dn_buf[256]; err = gnutls_x509_crl_get_issuer_dn(crl, dn_buf, &dn_size); if(err == GNUTLS_E_SUCCESS) { xmlSecOtherError2(XMLSEC_ERRORS_R_CRL_HAS_EXPIRED, storeName, "issuer=%s", dn_buf); } else { xmlSecOtherError(XMLSEC_ERRORS_R_CRL_HAS_EXPIRED, storeName, NULL); } return(0); } } /* Success */ return(1); } /* Verify CRL signature: 1 if verified, 0 if not verified, < 0 if error */ static int xmlSecGnuTLSX509StoreVerifyCrlSignature(xmlSecGnuTLSX509StoreCtxPtr ctx, gnutls_x509_crl_t crl, xmlSecKeyInfoCtxPtr keyInfoCtx, const xmlChar* storeName ) { gnutls_x509_crt_t issuer_cert = NULL; xmlChar *issuer_dn = NULL; unsigned int verify_result = 0; xmlSecSize ii, trusted_size, untrusted_size; unsigned int flags = 0; int err; int res = -1; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(crl != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); /* Find the issuer certificate using gnutls_x509_crl_check_issuer - search trusted certs first */ trusted_size = xmlSecPtrListGetSize(&(ctx->certsTrusted)); for(ii = 0; ii < trusted_size; ++ii) { gnutls_x509_crt_t cert = xmlSecPtrListGetItem(&(ctx->certsTrusted), ii); unsigned int is_issuer; if(cert == NULL) { continue; } is_issuer = gnutls_x509_crl_check_issuer(crl, cert); if(is_issuer != 0) { issuer_cert = cert; break; } } /* If not found in trusted, search untrusted */ if(issuer_cert == NULL) { untrusted_size = xmlSecPtrListGetSize(&(ctx->certsUntrusted)); for(ii = 0; ii < untrusted_size; ++ii) { gnutls_x509_crt_t cert = xmlSecPtrListGetItem(&(ctx->certsUntrusted), ii); unsigned int is_issuer; if(cert == NULL) { continue; } is_issuer = gnutls_x509_crl_check_issuer(crl, cert); if(is_issuer != 0) { ret = xmlSecGnuTLSX509StoreVerifyIssuerCert(ctx, cert, keyInfoCtx); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyIssuerCert", storeName); goto done; } else if(ret == 1) { issuer_cert = cert; break; } } } } if(issuer_cert == NULL) { /* Get issuer DN for error message */ issuer_dn = xmlSecGnuTLSX509CrlGetIssuerDN(crl); if(issuer_dn != NULL) { xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_NOT_FOUND, storeName, "issuer=%s", xmlSecErrorsSafeString((const char*)issuer_dn)); } else { xmlSecOtherError(XMLSEC_ERRORS_R_CERT_NOT_FOUND, storeName, NULL); } res = 0; goto done; } ret = xmlSecGnuTLSX509GetVerificationFlags(keyInfoCtx, &flags); if (ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509GetVerificationFlags", NULL); return(-1); } err = gnutls_x509_crl_verify(crl, &issuer_cert, 1, flags, &verify_result); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crl_verify", err, storeName); goto done; } /* Check if verification failed (ignoring allowed failures like insecure algorithms) */ if(verify_result != 0) { /* CRL verification failed - get issuer DN for error message */ if(issuer_dn == NULL) { issuer_dn = xmlSecGnuTLSX509CrlGetIssuerDN(crl); } if(issuer_dn != NULL) { xmlSecOtherError3(XMLSEC_ERRORS_R_CRL_VERIFY_FAILED, storeName, "verify_result=%u; issuer=%s", verify_result, xmlSecErrorsSafeString((const char*)issuer_dn)); } else { xmlSecOtherError2(XMLSEC_ERRORS_R_CRL_VERIFY_FAILED, storeName, "verify_result=%u", verify_result); } res = 0; goto done; } /* Success */ res = 1; done: if(issuer_dn != NULL) { xmlFree(issuer_dn); } return(res); } /** * @brief Verifies @p crl by checking: * @param store the pointer to X509 key data store klass. * @param crl the CRL to verify. * @param keyInfoCtx the key info context for verification parameters. * * 1. Signature is valid (signed by issuer cert in store) * 2. thisUpdate <= verification_time <= nextUpdate * * @return 1 if verified, 0 if not verified, or a negative value on error. */ int xmlSecGnuTLSX509StoreVerifyCrl(xmlSecKeyDataStorePtr store, gnutls_x509_crl_t crl, xmlSecKeyInfoCtxPtr keyInfoCtx ) { xmlSecGnuTLSX509StoreCtxPtr ctx; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1); xmlSecAssert2(crl != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); /* do we even need to verify the CRL? */ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) != 0) { return(1); } ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, -1); /* Verify time validity first (fast check) */ ret = xmlSecGnuTLSX509StoreVerifyCrlTimeValidity(crl, keyInfoCtx, xmlSecKeyDataStoreGetName(store)); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyCrlTimeValidity", xmlSecKeyDataStoreGetName(store)); return(-1); } else if(ret != 1) { /* Time validity check failed */ return(0); } /* Verify CRL signature (slower check) */ ret = xmlSecGnuTLSX509StoreVerifyCrlSignature(ctx, crl, keyInfoCtx, xmlSecKeyDataStoreGetName(store)); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509StoreVerifyCrlSignature", xmlSecKeyDataStoreGetName(store)); return(-1); } else if(ret != 1) { /* Signature verification failed */ return(0); } /* Success: verified */ return(1); } static int xmlSecGnuTLSX509StoreInitialize(xmlSecKeyDataStorePtr store) { xmlSecGnuTLSX509StoreCtxPtr ctx; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, -1); memset(ctx, 0, sizeof(xmlSecGnuTLSX509StoreCtx)); ret = xmlSecPtrListInitialize(&(ctx->certsTrusted), xmlSecGnuTLSX509CrtListId); if(ret < 0) { xmlSecInternalError("xmlSecPtrListInitialize(trusted)", xmlSecKeyDataStoreGetName(store)); return(-1); } ret = xmlSecPtrListInitialize(&(ctx->certsUntrusted), xmlSecGnuTLSX509CrtListId); if(ret < 0) { xmlSecInternalError("xmlSecPtrListInitialize(untrusted)", xmlSecKeyDataStoreGetName(store)); return(-1); } ret = xmlSecPtrListInitialize(&(ctx->crls), xmlSecGnuTLSX509CrlListId); if(ret < 0) { xmlSecInternalError("xmlSecPtrListInitialize(crls)", xmlSecKeyDataStoreGetName(store)); return(-1); } return(0); } static void xmlSecGnuTLSX509StoreFinalize(xmlSecKeyDataStorePtr store) { xmlSecGnuTLSX509StoreCtxPtr ctx; xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId)); ctx = xmlSecGnuTLSX509StoreGetCtx(store); xmlSecAssert(ctx != NULL); xmlSecPtrListFinalize(&(ctx->certsTrusted)); xmlSecPtrListFinalize(&(ctx->certsUntrusted)); xmlSecPtrListFinalize(&(ctx->crls)); memset(ctx, 0, sizeof(xmlSecGnuTLSX509StoreCtx)); } /****************************************************************************** * * Low-level x509 functions * *****************************************************************************/ #define XMLSEC_GNUTLS_DN_ATTRS_SIZE 1024 int xmlSecGnuTLSX509DnsEqual(const xmlChar * ll, const xmlChar * rr) { xmlSecGnuTLSDnAttr ll_attrs[XMLSEC_GNUTLS_DN_ATTRS_SIZE]; xmlSecGnuTLSDnAttr rr_attrs[XMLSEC_GNUTLS_DN_ATTRS_SIZE]; int ret; int res = -1; xmlSecAssert2(ll != NULL, -1); xmlSecAssert2(rr != NULL, -1); /* fast version first */ if(xmlStrEqual(ll, rr)) { return(1); } /* prepare */ xmlSecGnuTLSDnAttrsInitialize(ll_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); xmlSecGnuTLSDnAttrsInitialize(rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); /* parse */ ret = xmlSecGnuTLSDnAttrsParse(ll, ll_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSDnAttrsParse(ll)", NULL); goto done; } ret = xmlSecGnuTLSDnAttrsParse(rr, rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSDnAttrsParse(rr)", NULL); goto done; } /* compare */ ret = xmlSecGnuTLSDnAttrsEqual(ll_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE, rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); if(ret == 1) { res = 1; } else if(ret == 0) { res = 0; } else { xmlSecInternalError("xmlSecGnuTLSDnAttrsEqual", NULL); goto done; } done: xmlSecGnuTLSDnAttrsDeinitialize(ll_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); xmlSecGnuTLSDnAttrsDeinitialize(rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE); return(res); } /** * @brief Returns 0 if SKI matches, 1 if SKI doesn't match and a negative value if an error occurs. */ int xmlSecGnuTLSX509CertCompareSKI(gnutls_x509_crt_t cert, const xmlSecByte * ski, xmlSecSize skiSize) { xmlSecByte* buf = NULL; size_t bufSizeT = 0; xmlSecSize bufSize; unsigned int critical = 0; int err; int res = -1; xmlSecAssert2(cert != NULL, -1); xmlSecAssert2(ski != NULL, -1); xmlSecAssert2(skiSize > 0, -1); /* get ski size */ err = gnutls_x509_crt_get_subject_key_id(cert, NULL, &bufSizeT, &critical); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSizeT <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_subject_key_id", err, NULL); goto done; } XMLSEC_SAFE_CAST_SIZE_T_TO_SIZE(bufSizeT, bufSize, goto done, NULL); if(skiSize != bufSize) { /* doesn't match */ res = 1; goto done; } /* allocate buffer */ buf = (xmlSecByte *)xmlMalloc(bufSizeT + 1); if(buf == NULL) { xmlSecMallocError(bufSizeT + 1, NULL); goto done; } /* write ski out */ err = gnutls_x509_crt_get_subject_key_id(cert, buf, &bufSizeT, &critical); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_get_subject_key_id", err, NULL); goto done; } /* compare */ if(memcmp(ski, buf, bufSize) != 0) { /* doesn't match */ res = 1; goto done; } /* match! */ res = 0; done: /* cleanup */ if(buf != NULL) { xmlFree(buf); } return(res); } static gnutls_x509_crt_t xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs, xmlSecGnuTLSX509FindCertCtxPtr findCertCtx) { xmlSecSize ii, sz; int ret; xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(findCertCtx != NULL, NULL); /* todo: this is not the fastest way to search certs */ sz = xmlSecPtrListGetSize(certs); for(ii = 0; (ii < sz); ++ii) { gnutls_x509_crt_t cert = xmlSecPtrListGetItem(certs, ii); if(cert == NULL) { xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=" XMLSEC_SIZE_FMT, ii); return(NULL); } /* returns 1 for match, 0 for no match, and a negative value if an error occurs */ ret = xmlSecGnuTLSX509FindCertCtxMatch(findCertCtx, cert); if(ret < 0) { xmlSecInternalError2("xmlSecGnuTLSX509FindCertCtxMatch", NULL, "pos=" XMLSEC_SIZE_FMT, ii); return(NULL); } else if(ret == 1) { return(cert); } } /* not found */ return(NULL); } /* signed cert has issuer dn equal to our's subject dn */ static gnutls_x509_crt_t xmlSecGnuTLSX509FindSignedCert(xmlSecPtrListPtr certs, gnutls_x509_crt_t cert) { gnutls_x509_crt_t res = NULL; xmlChar * subject = NULL; xmlSecSize ii, sz; xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(cert != NULL, NULL); /* get subject */ subject = xmlSecGnuTLSX509CertGetSubjectDN(cert); if(subject == NULL) { xmlSecInternalError("xmlSecGnuTLSX509CertGetSubjectDN", NULL); goto done; } /* todo: this is not the fastest way to search certs */ sz = xmlSecPtrListGetSize(certs); for(ii = 0; (ii < sz) && (res == NULL); ++ii) { gnutls_x509_crt_t tmp; xmlChar * issuer; tmp = xmlSecPtrListGetItem(certs, ii); if(tmp == NULL) { xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=" XMLSEC_SIZE_FMT, ii); goto done; } issuer = xmlSecGnuTLSX509CertGetIssuerDN(tmp); if(issuer == NULL) { xmlSecInternalError2("xmlSecGnuTLSX509CertGetIssuerDN", NULL, "pos=" XMLSEC_SIZE_FMT, ii); goto done; } /* are we done? */ if(xmlSecGnuTLSX509DnsEqual(subject, issuer) == 1) { res = tmp; } xmlFree(issuer); } done: if(subject != NULL) { xmlFree(subject); } return(res); } /* signer cert has subject dn equal to our's issuer dn */ static gnutls_x509_crt_t xmlSecGnuTLSX509FindSignerCert(xmlSecPtrListPtr certs, gnutls_x509_crt_t cert) { gnutls_x509_crt_t res = NULL; xmlChar * issuer = NULL; xmlSecSize ii, sz; xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(cert != NULL, NULL); /* get issuer */ issuer = xmlSecGnuTLSX509CertGetIssuerDN(cert); if(issuer == NULL) { xmlSecInternalError("xmlSecGnuTLSX509CertGetIssuerDN", NULL); goto done; } /* todo: this is not the fastest way to search certs */ sz = xmlSecPtrListGetSize(certs); for(ii = 0; (ii < sz) && (res == NULL); ++ii) { gnutls_x509_crt_t tmp; xmlChar * subject; tmp = xmlSecPtrListGetItem(certs, ii); if(tmp == NULL) { xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=" XMLSEC_SIZE_FMT, ii); goto done; } subject = xmlSecGnuTLSX509CertGetSubjectDN(tmp); if(subject == NULL) { xmlSecInternalError2("xmlSecGnuTLSX509CertGetSubjectDN", NULL, "pos=" XMLSEC_SIZE_FMT, ii); goto done; } /* are we done? */ if((xmlSecGnuTLSX509DnsEqual(issuer, subject) == 1)) { res = tmp; } xmlFree(subject); } done: if(issuer != NULL) { xmlFree(issuer); } return(res); } #endif /* XMLSEC_NO_X509 */