/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/gnutls/x509utils.c
1 594 строки
46 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 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 <time.h> #include <gnutls/gnutls.h> #include <gnutls/abstract.h> #include <gnutls/x509.h> #include <gnutls/pkcs12.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/keyinfo.h> #include <xmlsec/keysmngr.h> #include <xmlsec/x509.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" #include "../x509_helpers.h" /****************************************************************************** * * X509 crt list * *****************************************************************************/ static xmlSecPtr xmlSecGnuTLSX509CrtListDuplicateItem (xmlSecPtr ptr); static void xmlSecGnuTLSX509CrtListDestroyItem (xmlSecPtr ptr); static void xmlSecGnuTLSX509CrtListDebugDumpItem (xmlSecPtr ptr, FILE* output); static void xmlSecGnuTLSX509CrtListDebugXmlDumpItem (xmlSecPtr ptr, FILE* output); static xmlSecPtrListKlass xmlSecGnuTLSX509CrtListKlass = { BAD_CAST "gnutls-x509-crt-list", xmlSecGnuTLSX509CrtListDuplicateItem, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ xmlSecGnuTLSX509CrtListDestroyItem, /* xmlSecPtrDestroyItemMethod destroyItem; */ xmlSecGnuTLSX509CrtListDebugDumpItem, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ xmlSecGnuTLSX509CrtListDebugXmlDumpItem, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ }; xmlSecPtrListId xmlSecGnuTLSX509CrtListGetKlass(void) { return(&xmlSecGnuTLSX509CrtListKlass); } static xmlSecPtr xmlSecGnuTLSX509CrtListDuplicateItem(xmlSecPtr ptr) { xmlSecAssert2(ptr != NULL, NULL); return xmlSecGnuTLSX509CertDup((gnutls_x509_crt_t)ptr); } static void xmlSecGnuTLSX509CrtListDestroyItem(xmlSecPtr ptr) { xmlSecAssert(ptr != NULL); gnutls_x509_crt_deinit((gnutls_x509_crt_t)ptr); } static void xmlSecGnuTLSX509CrtListDebugDumpItem(xmlSecPtr ptr, FILE* output) { xmlSecAssert(ptr != NULL); xmlSecAssert(output != NULL); xmlSecGnuTLSX509CertDebugDump((gnutls_x509_crt_t)ptr, output); } static void xmlSecGnuTLSX509CrtListDebugXmlDumpItem(xmlSecPtr ptr, FILE* output) { xmlSecAssert(ptr != NULL); xmlSecAssert(output != NULL); xmlSecGnuTLSX509CertDebugXmlDump((gnutls_x509_crt_t)ptr, output); } /****************************************************************************** * * X509 crl list * *****************************************************************************/ static xmlSecPtr xmlSecGnuTLSX509CrlListDuplicateItem (xmlSecPtr ptr); static void xmlSecGnuTLSX509CrlListDestroyItem (xmlSecPtr ptr); static void xmlSecGnuTLSX509CrlListDebugDumpItem (xmlSecPtr ptr, FILE* output); static void xmlSecGnuTLSX509CrlListDebugXmlDumpItem (xmlSecPtr ptr, FILE* output); static xmlSecPtrListKlass xmlSecGnuTLSX509CrlListKlass = { BAD_CAST "gnutls-x509-crl-list", xmlSecGnuTLSX509CrlListDuplicateItem, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ xmlSecGnuTLSX509CrlListDestroyItem, /* xmlSecPtrDestroyItemMethod destroyItem; */ xmlSecGnuTLSX509CrlListDebugDumpItem, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ xmlSecGnuTLSX509CrlListDebugXmlDumpItem, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ }; xmlSecPtrListId xmlSecGnuTLSX509CrlListGetKlass(void) { return(&xmlSecGnuTLSX509CrlListKlass); } static xmlSecPtr xmlSecGnuTLSX509CrlListDuplicateItem(xmlSecPtr ptr) { xmlSecAssert2(ptr != NULL, NULL); return xmlSecGnuTLSX509CrlDup((gnutls_x509_crl_t)ptr); } static void xmlSecGnuTLSX509CrlListDestroyItem(xmlSecPtr ptr) { xmlSecAssert(ptr != NULL); gnutls_x509_crl_deinit((gnutls_x509_crl_t)ptr); } static void xmlSecGnuTLSX509CrlListDebugDumpItem(xmlSecPtr ptr, FILE* output) { xmlSecAssert(ptr != NULL); xmlSecAssert(output != NULL); xmlSecGnuTLSX509CrlDebugDump((gnutls_x509_crl_t)ptr, output); } static void xmlSecGnuTLSX509CrlListDebugXmlDumpItem(xmlSecPtr ptr, FILE* output) { xmlSecAssert(ptr != NULL); xmlSecAssert(output != NULL); xmlSecGnuTLSX509CrlDebugXmlDump((gnutls_x509_crl_t)ptr, output); } /****************************************************************************** * * x509 certs utils/helpers * *****************************************************************************/ /* HACK: gnutls doesn't have cert duplicate function, so we simply write cert out and then read it back */ gnutls_x509_crt_t xmlSecGnuTLSX509CertDup(gnutls_x509_crt_t src) { xmlSecBuffer buf; gnutls_x509_crt_t res = NULL; int ret; xmlSecAssert2(src != NULL, NULL); ret = xmlSecBufferInitialize(&buf, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return (NULL); } ret = xmlSecGnuTLSX509CertDerWrite(src, &buf); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509CertDerWrite", NULL); xmlSecBufferFinalize(&buf); return (NULL); } res = xmlSecGnuTLSX509CertRead(xmlSecBufferGetData(&buf), xmlSecBufferGetSize(&buf), xmlSecKeyDataFormatCertDer); if(res == NULL) { xmlSecInternalError("xmlSecGnuTLSX509CertRead", NULL); xmlSecBufferFinalize(&buf); return (NULL); } /* done */ xmlSecBufferFinalize(&buf); return (res); } /* returns 1 if self signed; 0 - if not; <0 on error*/ int xmlSecGnuTLSX509CertIsSelfSigned(gnutls_x509_crt_t cert) { unsigned ret; xmlSecAssert2(cert != NULL, -1); ret = gnutls_x509_crt_check_issuer(cert, cert); return ((ret != 0) ? 1 : 0); } xmlChar * xmlSecGnuTLSX509CertGetSubjectDN(gnutls_x509_crt_t cert) { char* buf = NULL; size_t bufSize = 0; int err; xmlSecAssert2(cert != NULL, NULL); /* get subject size */ err = gnutls_x509_crt_get_dn(cert, NULL, &bufSize); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_dn", err, NULL); return(NULL); } /* allocate buffer */ buf = (char *)xmlMalloc(bufSize + 1); if(buf == NULL) { xmlSecMallocError(bufSize + 1, NULL); return(NULL); } /* finally write it out */ err = gnutls_x509_crt_get_dn(cert, buf, &bufSize); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_get_dn", err, NULL); xmlFree(buf); return(NULL); } /* done */ return(BAD_CAST buf); } xmlChar * xmlSecGnuTLSX509CertGetIssuerDN(gnutls_x509_crt_t cert) { char* buf = NULL; size_t bufSize = 0; int err; xmlSecAssert2(cert != NULL, NULL); /* get issuer size */ err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &bufSize); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_issuer_dn", err, NULL); return(NULL); } /* allocate buffer */ buf = (char *)xmlMalloc(bufSize + 1); if(buf == NULL) { xmlSecMallocError(bufSize + 1, NULL); return(NULL); } /* finally write it out */ err = gnutls_x509_crt_get_issuer_dn(cert, buf, &bufSize); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_get_issuer_dn", err, NULL); xmlFree(buf); return(NULL); } /* done */ return(BAD_CAST buf); } xmlChar * xmlSecGnuTLSX509CertGetIssuerSerial(gnutls_x509_crt_t cert) { xmlChar * res = NULL; unsigned char* buf = NULL; size_t bufSize = 0; int err; xmlSecAssert2(cert != NULL, NULL); /* get issuer serial size */ err = gnutls_x509_crt_get_serial(cert, NULL, &bufSize); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_serial", err, NULL); return(NULL); } /* allocate buffer */ buf = (unsigned char *)xmlMalloc(bufSize + 1); if(buf == NULL) { xmlSecMallocError(bufSize + 1, NULL); return(NULL); } /* write it out */ err = gnutls_x509_crt_get_serial(cert, buf, &bufSize); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_get_serial", err, NULL); xmlFree(buf); return(NULL); } /* convert to string */ res = xmlSecX509SerialNumberWrite((const xmlSecByte*)buf, (xmlSecSize)bufSize); if(res == NULL) { xmlSecInternalError("xmlSecX509SerialNumberWrite", NULL); xmlFree(buf); return(NULL); } /* done */ xmlFree(buf); return(res); } int xmlSecGnuTLSX509DigestWrite(gnutls_x509_crt_t cert, const xmlChar* algorithm, xmlSecBufferPtr buf) { gnutls_digest_algorithm_t digestAlgo; xmlSecByte md[XMLSEC_GNUTLS_MAX_DIGEST_SIZE]; size_t mdLen = sizeof(md); xmlSecSize mdSize; int err; int ret; xmlSecAssert2(cert != NULL, -1); xmlSecAssert2(buf != NULL, -1); digestAlgo = xmlSecGnuTLSX509GetDigestFromAlgorithm(algorithm); if(digestAlgo == GNUTLS_DIG_UNKNOWN) { xmlSecInternalError("xmlSecGnuTLSX509GetDigestFromAlgorithm", NULL); return(-1); } err = gnutls_x509_crt_get_fingerprint(cert, digestAlgo, md, &mdLen); if((err != GNUTLS_E_SUCCESS) || (mdLen <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_fingerprint", err, NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_T_TO_SIZE(mdLen, mdSize, return(-1), NULL); ret = xmlSecBufferSetData(buf, md, mdSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData", NULL); return(-1); } /* success */ return(0); } gnutls_x509_crt_t xmlSecGnuTLSX509CertRead(const xmlSecByte* buf, xmlSecSize size, xmlSecKeyDataFormat format) { gnutls_x509_crt_t cert = NULL; gnutls_x509_crt_fmt_t fmt; gnutls_datum_t data; unsigned int bufLen; int err; xmlSecAssert2(buf != NULL, NULL); xmlSecAssert2(size > 0, NULL); /* figure out format */ switch(format) { case xmlSecKeyDataFormatPem: case xmlSecKeyDataFormatCertPem: fmt = GNUTLS_X509_FMT_PEM; break; case xmlSecKeyDataFormatDer: case xmlSecKeyDataFormatCertDer: fmt = GNUTLS_X509_FMT_DER; break; default: xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "format=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(format)); return(NULL); } XMLSEC_SAFE_CAST_SIZE_TO_UINT(size, bufLen, return(NULL), NULL); /* read cert */ err = gnutls_x509_crt_init(&cert); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_init", err, NULL); return(NULL); } data.data = (unsigned char*)buf; data.size = bufLen; err = gnutls_x509_crt_import(cert, &data, fmt); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_import", err, NULL); gnutls_x509_crt_deinit(cert); return(NULL); } return(cert); } int xmlSecGnuTLSX509CertDerWrite(gnutls_x509_crt_t cert, xmlSecBufferPtr buf) { size_t bufSizeT = 0; xmlSecSize bufSize; xmlSecByte * bufData; int ret; int err; xmlSecAssert2(cert != NULL, -1); xmlSecAssert2(buf != NULL, -1); /* get size */ err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, NULL, &bufSizeT); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSizeT <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)", err, NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_T_TO_SIZE(bufSizeT, bufSize, return(-1), NULL); /* allocate buffer */ ret = xmlSecBufferSetSize(buf, bufSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "bufSize=" XMLSEC_SIZE_FMT, bufSize); return(-1); } bufData = xmlSecBufferGetData(buf); xmlSecAssert2(bufData != NULL, -1); /* write it out */ err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, bufData, &bufSizeT); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)", err, NULL); return(-1); } /* success */ return(0); } void xmlSecGnuTLSX509CertDebugDump(gnutls_x509_crt_t cert, FILE* output) { xmlChar * buf; xmlSecAssert(cert != NULL); xmlSecAssert(output != NULL); buf = xmlSecGnuTLSX509CertGetSubjectDN(cert); if(buf != NULL) { fprintf(output, "==== Subject Name: %s\n", buf); xmlFree(buf); } else { fprintf(output, "==== Subject Name: unknown\n"); } buf = xmlSecGnuTLSX509CertGetIssuerDN(cert); if(buf != NULL) { fprintf(output, "==== Issuer Name: %s\n", buf); xmlFree(buf); } else { fprintf(output, "==== Issuer Name: unknown\n"); } buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert); if(buf != NULL) { fprintf(output, "==== Issuer Serial: %s\n", buf); xmlFree(buf); } else { fprintf(output, "==== Issuer Serial: unknown\n"); } } void xmlSecGnuTLSX509CertDebugXmlDump(gnutls_x509_crt_t cert, FILE* output) { xmlChar * buf; xmlSecAssert(cert != NULL); xmlSecAssert(output != NULL); buf = xmlSecGnuTLSX509CertGetSubjectDN(cert); if(buf != NULL) { fprintf(output, "<SubjectName>%s</SubjectName>\n", buf); xmlFree(buf); } else { fprintf(output, "<SubjectName>unknown</SubjectName>\n"); } buf = xmlSecGnuTLSX509CertGetIssuerDN(cert); if(buf != NULL) { fprintf(output, "<IssuerName>%s</IssuerName>\n", buf); xmlFree(buf); } else { fprintf(output, "<IssuerName>unknown</IssuerName>\n"); } buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert); if(buf != NULL) { fprintf(output, "<SerialNumber>%s</SerialNumber>\n", buf); xmlFree(buf); } else { fprintf(output, "<SerialNumber>unknown</SerialNumber>\n"); } } /****************************************************************************** * * x509 certs search ctx * *****************************************************************************/ int xmlSecGnuTLSX509FindCertCtxInitialize(xmlSecGnuTLSX509FindCertCtxPtr ctx, const xmlChar *subjectName, const xmlChar *issuerName, const xmlChar *issuerSerial, const xmlSecByte * ski, xmlSecSize skiSize ) { xmlSecAssert2(ctx != NULL, -1); memset(ctx, 0, sizeof(*ctx)); /* TODO: figure out if we can convert the X509 Data into any faster representation */ if(subjectName != NULL) { ctx->subjectName = subjectName; } if((issuerName != NULL) && (issuerSerial != NULL)) { ctx->issuerName = issuerName; ctx->issuerSerial = issuerSerial; } if((ski != NULL) && (skiSize > 0)) { ctx->ski = ski; ctx->skiSize = skiSize; } /* done! */ return(0); } int xmlSecGnuTLSX509FindCertCtxInitializeFromValue(xmlSecGnuTLSX509FindCertCtxPtr ctx, xmlSecKeyX509DataValuePtr x509Value) { int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(x509Value != NULL, -1); ret = xmlSecGnuTLSX509FindCertCtxInitialize(ctx, x509Value->subject, x509Value->issuerName, x509Value->issuerSerial, xmlSecBufferGetData(&(x509Value->ski)), xmlSecBufferGetSize(&(x509Value->ski)) ); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509FindCertCtxInitialize", NULL); xmlSecGnuTLSX509FindCertCtxFinalize(ctx); return(-1); } if((!xmlSecBufferIsEmpty(&(x509Value->digest))) && (x509Value->digestAlgorithm != NULL)) { ctx->digestValue = xmlSecBufferGetData(&(x509Value->digest)); ctx->digestLen = xmlSecBufferGetSize(&(x509Value->digest)); ctx->digestAlgo = xmlSecGnuTLSX509GetDigestFromAlgorithm(x509Value->digestAlgorithm); if(ctx->digestAlgo == GNUTLS_DIG_UNKNOWN) { xmlSecInternalError("xmlSecGnuTLSX509GetDigestFromAlgorithm", NULL); xmlSecGnuTLSX509FindCertCtxFinalize(ctx); return(-1); } } return(0); } void xmlSecGnuTLSX509FindCertCtxFinalize(xmlSecGnuTLSX509FindCertCtxPtr ctx) { xmlSecAssert(ctx != NULL); memset(ctx, 0, sizeof(*ctx)); } static int xmlSecGnuTLSX509MatchBySubjectName(gnutls_x509_crt_t cert, const xmlChar* subjectName) { xmlChar * certSubjectName; xmlSecAssert2(cert != NULL, -1); if(subjectName == NULL) { return(0); } certSubjectName = xmlSecGnuTLSX509CertGetSubjectDN(cert); if(certSubjectName == NULL) { return(0); } /* returns 1 if equal */ if(xmlSecGnuTLSX509DnsEqual(subjectName, certSubjectName) != 1) { xmlFree(certSubjectName); return(0); } /* success */ xmlFree(certSubjectName); return(1); } static int xmlSecGnuTLSX509MatchByIssuer(gnutls_x509_crt_t cert, const xmlChar* issuerName, const xmlChar* issuerSerial) { xmlChar* certIssuerSerial; xmlChar* certIssuerName; xmlSecAssert2(cert != NULL, -1); if((issuerName == NULL) || (issuerSerial == NULL)) { return(0); } certIssuerName = xmlSecGnuTLSX509CertGetIssuerDN(cert); if((certIssuerName == NULL) || (xmlSecGnuTLSX509DnsEqual(issuerName, certIssuerName) != 1)) { xmlFree(certIssuerName); return(0); } xmlFree(certIssuerName); certIssuerSerial = xmlSecGnuTLSX509CertGetIssuerSerial(cert); if((certIssuerSerial == NULL) || (!xmlStrEqual(issuerSerial, certIssuerSerial))) { xmlFree(certIssuerSerial); return(0); } xmlFree(certIssuerSerial); /* success */ return(1); } static int xmlSecGnuTLSX509MatchBySki(gnutls_x509_crt_t cert, const xmlSecByte* ski, xmlSecSize skiSize) { int ret; xmlSecAssert2(cert != NULL, -1); if((ski == NULL) || (skiSize <= 0)) { return(0); } /* TODO: get rid of xmlSecGnuTLSX509CertCompareSKI */ /* returns 0 if matched */ ret = xmlSecGnuTLSX509CertCompareSKI(cert, ski, skiSize); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509CertCompareSKI", NULL); return(-1); } else if(ret != 0) { /* not match */ return(0); } /* success */ return(1); } static int xmlSecGnuTLSX509MatchByDigest(gnutls_x509_crt_t cert, const xmlSecByte * digestValue, size_t digestLen, gnutls_digest_algorithm_t digestAlgo) { xmlSecByte md[XMLSEC_GNUTLS_MAX_DIGEST_SIZE]; size_t mdLen = sizeof(md); int err; xmlSecAssert2(cert != NULL, -1); if((digestValue == NULL) || (digestLen <= 0) || (digestAlgo == GNUTLS_DIG_UNKNOWN)) { return(0); } err = gnutls_x509_crt_get_fingerprint(cert, digestAlgo, md, &mdLen); if((err != GNUTLS_E_SUCCESS) || (mdLen <= 0)) { xmlSecGnuTLSError("gnutls_x509_crt_get_fingerprint", err, NULL); return(-1); } if((mdLen != digestLen) || (memcmp(md, digestValue, digestLen) != 0)) { return(0); } /* success */ return(1); } /* returns 1 for match, 0 for no match, and a negative value if an error occurs */ int xmlSecGnuTLSX509FindCertCtxMatch(xmlSecGnuTLSX509FindCertCtxPtr ctx, gnutls_x509_crt_t cert) { int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(cert != NULL, -1); ret = xmlSecGnuTLSX509MatchBySubjectName(cert, ctx->subjectName); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509MatchBySubjectName", NULL); return(-1); } else if(ret == 1) { /* success! */ return(1); } ret = xmlSecGnuTLSX509MatchByIssuer(cert, ctx->issuerName, ctx->issuerSerial); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509MatchByIssuer", NULL); return(-1); } else if(ret == 1) { /* success! */ return(1); } ret = xmlSecGnuTLSX509MatchBySki(cert, ctx->ski, ctx->skiSize); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509MatchBySki", NULL); return(-1); } else if(ret == 1) { /* success! */ return(1); } ret = xmlSecGnuTLSX509MatchByDigest(cert, ctx->digestValue, ctx->digestLen, ctx->digestAlgo); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509MatchByDigest", NULL); return(-1); } else if(ret == 1) { /* success! */ return(1); } /* not found */ return(0); } gnutls_digest_algorithm_t xmlSecGnuTLSX509GetDigestFromAlgorithm(const xmlChar* href) { /* use SHA256 by default */ if(href == NULL) { #ifndef XMLSEC_NO_SHA256 return(GNUTLS_DIG_SHA256); #else /* XMLSEC_NO_SHA256 */ xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "SHA256 is disabled; href=%s", xmlSecErrorsSafeString(href)); return(GNUTLS_DIG_UNKNOWN); #endif /* XMLSEC_NO_SHA256 */ } else #ifndef XMLSEC_NO_SHA1 if(xmlStrcmp(href, xmlSecHrefSha1) == 0) { return(GNUTLS_DIG_SHA1); } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 if(xmlStrcmp(href, xmlSecHrefSha224) == 0) { return(GNUTLS_DIG_SHA224); } else #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 if(xmlStrcmp(href, xmlSecHrefSha256) == 0) { return(GNUTLS_DIG_SHA256); } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlStrcmp(href, xmlSecHrefSha384) == 0) { return(GNUTLS_DIG_SHA384); } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlStrcmp(href, xmlSecHrefSha512) == 0) { return(GNUTLS_DIG_SHA512); } else #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 if(xmlStrcmp(href, xmlSecHrefSha3_224) == 0) { return(GNUTLS_DIG_SHA3_224); } else if(xmlStrcmp(href, xmlSecHrefSha3_256) == 0) { return(GNUTLS_DIG_SHA3_256); } else if(xmlStrcmp(href, xmlSecHrefSha3_384) == 0) { return(GNUTLS_DIG_SHA3_384); } else if(xmlStrcmp(href, xmlSecHrefSha3_512) == 0) { return(GNUTLS_DIG_SHA3_512); } else #endif /* XMLSEC_NO_SHA3 */ { xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "href=%s", xmlSecErrorsSafeString(href)); return(GNUTLS_DIG_UNKNOWN); } } /****************************************************************************** * * x509 crls utils/helpers * *****************************************************************************/ /* HACK: gnutls doesn't have crl duplicate function, so we simply write crl out and then read it back */ gnutls_x509_crl_t xmlSecGnuTLSX509CrlDup(gnutls_x509_crl_t src) { xmlSecBuffer buf; gnutls_x509_crl_t res = NULL; int ret; xmlSecAssert2(src != NULL, NULL); ret = xmlSecBufferInitialize(&buf, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return (NULL); } ret = xmlSecGnuTLSX509CrlDerWrite(src, &buf); if(ret < 0) { xmlSecInternalError("xmlSecGnuTLSX509CrlDerWrite", NULL); xmlSecBufferFinalize(&buf); return (NULL); } res = xmlSecGnuTLSX509CrlRead(xmlSecBufferGetData(&buf), xmlSecBufferGetSize(&buf), xmlSecKeyDataFormatCertDer); if(res == NULL) { xmlSecInternalError("xmlSecGnuTLSX509CrlRead", NULL); xmlSecBufferFinalize(&buf); return (NULL); } /* done */ xmlSecBufferFinalize(&buf); return (res); } xmlChar * xmlSecGnuTLSX509CrlGetIssuerDN(gnutls_x509_crl_t crl) { char* buf = NULL; size_t bufSize = 0; int err; xmlSecAssert2(crl != NULL, NULL); /* get issuer size */ err = gnutls_x509_crl_get_issuer_dn(crl, NULL, &bufSize); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) { xmlSecGnuTLSError("gnutls_x509_crl_get_issuer_dn", err, NULL); return(NULL); } /* allocate buffer */ buf = (char *)xmlMalloc(bufSize + 1); if(buf == NULL) { xmlSecMallocError(bufSize + 1, NULL); return(NULL); } /* finally write it out */ err = gnutls_x509_crl_get_issuer_dn(crl, buf, &bufSize); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crl_get_issuer_dn", err, NULL); xmlFree(buf); return(NULL); } /* done */ return(BAD_CAST buf); } gnutls_x509_crl_t xmlSecGnuTLSX509CrlRead(const xmlSecByte* buf, xmlSecSize size, xmlSecKeyDataFormat format) { gnutls_x509_crl_t crl = NULL; gnutls_x509_crt_fmt_t fmt; gnutls_datum_t data; unsigned int bufLen; int err; xmlSecAssert2(buf != NULL, NULL); xmlSecAssert2(size > 0, NULL); /* figure out format */ switch(format) { case xmlSecKeyDataFormatPem: case xmlSecKeyDataFormatCertPem: fmt = GNUTLS_X509_FMT_PEM; break; case xmlSecKeyDataFormatDer: case xmlSecKeyDataFormatCertDer: fmt = GNUTLS_X509_FMT_DER; break; default: xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "format=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(format)); return(NULL); } XMLSEC_SAFE_CAST_SIZE_TO_UINT(size, bufLen, return(NULL), NULL); /* read crl */ err = gnutls_x509_crl_init(&crl); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crl_init", err, NULL); return(NULL); } data.data = (unsigned char*)buf; data.size = bufLen; err = gnutls_x509_crl_import(crl, &data, fmt); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crl_import", err, NULL); gnutls_x509_crl_deinit(crl); return(NULL); } return(crl); } int xmlSecGnuTLSX509CrlDerWrite(gnutls_x509_crl_t crl, xmlSecBufferPtr buf) { size_t bufSizeT = 0; xmlSecSize bufSize; xmlSecByte * bufData; int ret; int err; xmlSecAssert2(crl != NULL, -1); xmlSecAssert2(buf != NULL, -1); /* get size */ err = gnutls_x509_crl_export(crl, GNUTLS_X509_FMT_DER, NULL, &bufSizeT); if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSizeT <= 0)) { xmlSecGnuTLSError("gnutls_x509_crl_export(GNUTLS_X509_FMT_DER)", err, NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_T_TO_SIZE(bufSizeT, bufSize, return(-1), NULL); /* allocate buffer */ ret = xmlSecBufferSetSize(buf, bufSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "bufSize=" XMLSEC_SIZE_FMT, bufSize); return(-1); } bufData = xmlSecBufferGetData(buf); xmlSecAssert2(bufData != NULL, -1); /* write it out */ err = gnutls_x509_crl_export(crl,GNUTLS_X509_FMT_DER, bufData, &bufSizeT); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crl_export(GNUTLS_X509_FMT_DER)", err, NULL); return(-1); } /* success */ return(0); } void xmlSecGnuTLSX509CrlDebugDump(gnutls_x509_crl_t crl, FILE* output) { xmlChar * buf; xmlSecAssert(crl != NULL); xmlSecAssert(output != NULL); buf = xmlSecGnuTLSX509CrlGetIssuerDN(crl); if(buf != NULL) { fprintf(output, "==== Issuer Name: %s\n", buf); xmlFree(buf); } else { fprintf(output, "==== Issuer Name: unknown\n"); } } void xmlSecGnuTLSX509CrlDebugXmlDump(gnutls_x509_crl_t crl, FILE* output) { xmlChar * buf; xmlSecAssert(crl != NULL); xmlSecAssert(output != NULL); buf = xmlSecGnuTLSX509CrlGetIssuerDN(crl); if(buf != NULL) { fprintf(output, "<IssuerName>%s</IssuerName>\n", buf); xmlFree(buf); } else { fprintf(output, "<IssuerName>unknown</IssuerName>\n"); } } /****************************************************************************** * * pkcs12 utils/helpers * *****************************************************************************/ int xmlSecGnuTLSPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, const char *pwd, gnutls_x509_privkey_t * priv_key, gnutls_x509_crt_t * key_cert, xmlSecPtrListPtr certsList, xmlChar ** keyName ) { gnutls_pkcs12_t pkcs12 = NULL; gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_crt_t cert = NULL; gnutls_datum_t datum; xmlSecSize certsSize; unsigned int dataLen; int res = -1; int idx; int err; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(dataSize > 0, -1); xmlSecAssert2(priv_key != NULL, -1); xmlSecAssert2((*priv_key) == NULL, -1); xmlSecAssert2(key_cert!= NULL, -1); xmlSecAssert2((*key_cert) == NULL, -1); xmlSecAssert2(certsList != NULL, -1); xmlSecAssert2(keyName != NULL, -1); xmlSecAssert2((*keyName) == NULL, -1); XMLSEC_SAFE_CAST_SIZE_TO_UINT(dataSize, dataLen, return(-1), NULL); /* read pkcs12 in internal structure */ err = gnutls_pkcs12_init(&pkcs12); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_init", err, NULL); goto done; } datum.data = (unsigned char *)data; datum.size = dataLen; err = gnutls_pkcs12_import(pkcs12, &datum, GNUTLS_X509_FMT_DER, 0); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_import", err, NULL); goto done; } /* verify */ err = gnutls_pkcs12_verify_mac(pkcs12, pwd); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_verify_mac", err, NULL); goto done; } /* scan the pkcs structure and find the first private key */ for(idx = 0; ; ++idx) { int bag_type; int elements_in_bag; unsigned int num, ii; err = gnutls_pkcs12_bag_init(&bag); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_bag_init", err, NULL); goto done; } err = gnutls_pkcs12_get_bag(pkcs12, idx, bag); if(err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { /* scanned the whole pkcs12, stop */ break; } else if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_get_bag", err, NULL); goto done; } /* check if we need to decrypt the bag */ bag_type = gnutls_pkcs12_bag_get_type(bag, 0); if(bag_type < 0) { xmlSecGnuTLSError("gnutls_pkcs12_bag_get_type", bag_type, NULL); goto done; } if(bag_type == GNUTLS_BAG_ENCRYPTED) { err = gnutls_pkcs12_bag_decrypt(bag, pwd); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_bag_decrypt", err, NULL); goto done; } } /* scan elements in bag */ elements_in_bag = gnutls_pkcs12_bag_get_count(bag); if(elements_in_bag < 0) { xmlSecGnuTLSError("gnutls_pkcs12_bag_get_count", elements_in_bag, NULL); goto done; } XMLSEC_SAFE_CAST_INT_TO_UINT(elements_in_bag, num, goto done, NULL); for(ii = 0; ii < num; ++ii) { bag_type = gnutls_pkcs12_bag_get_type(bag, ii); if(bag_type < 0) { xmlSecGnuTLSError("gnutls_pkcs12_bag_get_type", bag_type, NULL); goto done; } err = gnutls_pkcs12_bag_get_data(bag, ii, &datum); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_bag_get_data", err, NULL); goto done; } switch(bag_type) { case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: case GNUTLS_BAG_PKCS8_KEY: /* we want only the first private key */ if((*priv_key) == NULL) { err = gnutls_x509_privkey_init(priv_key); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_privkey_init", err, NULL); goto done; } err = gnutls_x509_privkey_import_pkcs8((*priv_key), &datum, GNUTLS_X509_FMT_DER, pwd, (bag_type == GNUTLS_BAG_PKCS8_KEY) ? GNUTLS_PKCS_PLAIN : 0); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_privkey_import_pkcs8", err, NULL); goto done; } if((*keyName) == NULL) { char * name = NULL; err = gnutls_pkcs12_bag_get_friendly_name(bag, ii, &name); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_pkcs12_bag_get_friendly_name", err, NULL); goto done; } if(name != NULL) { (*keyName) = xmlStrdup(BAD_CAST name); if((*keyName) == NULL) { xmlSecStrdupError(BAD_CAST name, NULL); goto done; } } } } break; case GNUTLS_BAG_CERTIFICATE: err = gnutls_x509_crt_init(&cert); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_init", err, NULL); goto done; } err = gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_import", err, NULL); goto done; } ret = xmlSecPtrListAdd(certsList, cert); if(ret < 0) { xmlSecInternalError("xmlSecPtrListAdd(certsList)", NULL); goto done; } cert = NULL; /* owned by certsList now */ break; default: /* ignore unknown bag element */ break; } } /* done with bag */ gnutls_pkcs12_bag_deinit(bag); bag = NULL; } /* check we have private key */ if((*priv_key) == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_KEY_NOT_FOUND, NULL, "Private key was not found in pkcs12 object"); goto done; } /* we will search for key cert using the key id */ certsSize = xmlSecPtrListGetSize(certsList); if(certsSize > 0) { size_t cert_id_size = 0; size_t key_id_size = 0; xmlSecByte cert_id[100]; xmlSecByte key_id[100]; xmlSecSize ii; key_id_size = sizeof(key_id); err = gnutls_x509_privkey_get_key_id((*priv_key), 0, key_id, &key_id_size); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_privkey_get_key_id", err, NULL); goto done; } for(ii = 0; ii < certsSize; ++ii) { gnutls_x509_crt_t tmp; tmp = xmlSecPtrListGetItem(certsList, ii); if(tmp == NULL) { continue; } cert_id_size = sizeof(cert_id); err = gnutls_x509_crt_get_key_id(tmp, 0, cert_id, &cert_id_size); if(err != GNUTLS_E_SUCCESS) { xmlSecGnuTLSError("gnutls_x509_crt_get_key_id", err, NULL); goto done; } /* if key ids match, then this is THE key cert!!! */ if((key_id_size == cert_id_size) && (memcmp(key_id, cert_id, key_id_size) == 0)) { (*key_cert) = xmlSecGnuTLSX509CertDup(tmp); if((*key_cert) == NULL) { xmlSecInternalError("xmlSecGnuTLSX509CertDup", NULL); goto done; } break; } } /* check we have key cert */ if((*key_cert) == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_CERT_NOT_FOUND, NULL, "Certificate for the private key was not found in pkcs12 object"); goto done; } } /* success!!! */ res = 0; done: if(cert != NULL) { gnutls_x509_crt_deinit(cert); } if(bag != NULL) { gnutls_pkcs12_bag_deinit(bag); } if(pkcs12 != NULL) { gnutls_pkcs12_deinit(pkcs12); } return(res); } /****************************************************************************** * * LDAP DN parser * *****************************************************************************/ void xmlSecGnuTLSDnAttrsInitialize(xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize) { xmlSecAssert(attrs != NULL); xmlSecAssert(attrsSize > 0); memset(attrs, 0, attrsSize * sizeof(xmlSecGnuTLSDnAttr)); } void xmlSecGnuTLSDnAttrsDeinitialize(xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize) { xmlSecSize ii; xmlSecAssert(attrs != NULL); xmlSecAssert(attrsSize > 0); for(ii = 0; ii < attrsSize; ++ii) { if(attrs[ii].key != NULL) { xmlFree(attrs[ii].key); } if(attrs[ii].value != NULL) { xmlFree(attrs[ii].value); } } memset(attrs, 0, attrsSize * sizeof(xmlSecGnuTLSDnAttr)); } const xmlSecGnuTLSDnAttr * xmlSecGnuTLSDnAttrrsFind(const xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize, const xmlChar * key) { xmlSecSize ii; xmlSecAssert2(attrs != NULL, NULL); xmlSecAssert2(attrsSize > 0, NULL); xmlSecAssert2(key != NULL, NULL); for(ii = 0; ii < attrsSize; ++ii) { /* simple case */ if(xmlStrcasecmp(key, attrs[ii].key) == 0) { return(&(attrs[ii])); } /* special case for emailAddress (as usual) */ if((xmlStrcasecmp(key, BAD_CAST "emailAddress") == 0) && (xmlStrcasecmp(attrs[ii].key, BAD_CAST "email") == 0)) { return(&(attrs[ii])); } if((xmlStrcasecmp(key, BAD_CAST "email") == 0) && (xmlStrcasecmp(attrs[ii].key, BAD_CAST "emailAddress") == 0)) { return(&(attrs[ii])); } } /* not found :( */ return(NULL); } int xmlSecGnuTLSDnAttrsEqual(const xmlSecGnuTLSDnAttr * ll, xmlSecSize llSize, const xmlSecGnuTLSDnAttr * rr, xmlSecSize rrSize) { xmlSecSize llNum = 0; xmlSecSize rrNum = 0; const xmlSecGnuTLSDnAttr * tmp; xmlSecSize ii; xmlSecAssert2(ll != NULL, -1); xmlSecAssert2(llSize > 0, -1); xmlSecAssert2(rr != NULL, -1); xmlSecAssert2(rrSize > 0, -1); /* compare number of non-nullattributes */ for(ii = 0; ii < llSize; ++ii) { if(ll[ii].key != NULL) { ++llNum; } } for(ii = 0; ii < rrSize; ++ii) { if(rr[ii].key != NULL) { ++rrNum; } } if(llNum != rrNum) { return(0); } /* make sure that all ll attrs are equal to rr attrs */ for(ii = 0; ii < llSize; ++ii) { if(ll[ii].key == NULL) { continue; } tmp = xmlSecGnuTLSDnAttrrsFind(rr, rrSize, ll[ii].key); if(tmp == NULL) { return(0); /* attribute was not found */ } if(!xmlStrEqual(ll[ii].value, tmp->value)) { return(0); /* different values */ } } /* good!!! */ return(1); } /* Distinguished name syntax The formal syntax for a Distinguished Name (DN) is based on RFC 2253. The Backus Naur Form (BNF) syntax is defined as follows: <name> ::= <name-component> ( <spaced-separator> ) | <name-component> <spaced-separator> <name> <spaced-separator> ::= <optional-space> <separator> <optional-space> <separator> ::= "," | ";" <optional-space> ::= ( <CR> ) *( " " ) <name-component> ::= <attribute> | <attribute> <optional-space> "+" <optional-space> <name-component> <attribute> ::= <string> | <key> <optional-space> "=" <optional-space> <string> <key> ::= 1*( <keychar> ) | "OID." <oid> | "oid." <oid> <keychar> ::= letters, numbers, and space <oid> ::= <digitstring> | <digitstring> "." <oid> <digitstring> ::= 1*<digit> <digit> ::= digits 0-9 <string> ::= *( <stringchar> | <pair> ) | '"' *( <stringchar> | <special> | <pair> ) '"' | "#" <hex> <special> ::= "," | "=" | <CR> | "+" | "<" | ">" | "#" | ";" <pair> ::= "\" ( <special> | "\" | '"') <stringchar> ::= any character except <special> or "\" or '"' <hex> ::= 2*<hexchar> <hexchar> ::= 0-9, a-f, A-F A semicolon (;) character can be used to separate RDNs in a distinguished name, although the comma (,) character is the typical notation. White-space characters (spaces) might be present on either side of the comma or semicolon. The white-space characters are ignored, and the semicolon is replaced with a comma. In addition, space (' ' ASCII 32) characters may be present either before or after a '+' or '='. These space characters are ignored when parsing. */ enum xmlSecGnuTLSDnParseState { xmlSecGnuTLSDnParseState_BeforeNameComponent = 0, xmlSecGnuTLSDnParseState_Key, xmlSecGnuTLSDnParseState_BeforeString, xmlSecGnuTLSDnParseState_String, xmlSecGnuTLSDnParseState_QuotedString, xmlSecGnuTLSDnParseState_AfterQuotedString }; #define XMLSEC_GNUTLS_IS_SPACE(ch) \ (((ch) == ' ') || ((ch) == '\n') || ((ch) == '\r')) int xmlSecGnuTLSDnAttrsParse(const xmlChar * dn, xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize) { xmlChar * tmp = NULL; xmlChar * p; xmlChar ch; enum xmlSecGnuTLSDnParseState state; int slash; xmlSecSize size, pos; int res = -1; xmlSecAssert2(dn != NULL, -1); xmlSecAssert2(attrs != NULL, -1); xmlSecAssert2(attrsSize > 0, -1); /* allocate buffer, we don't need more than string */ size = xmlSecStrlen(dn); tmp = (xmlChar *)xmlMalloc(size + 1); if(tmp == NULL) { xmlSecMallocError(size + 1, NULL); goto done; } /* state machine */ state = xmlSecGnuTLSDnParseState_BeforeNameComponent; slash = 0; pos = 0; p = tmp; for(ch = (*dn); ; ch = *(++dn)) { switch(state) { case xmlSecGnuTLSDnParseState_BeforeNameComponent: if(!XMLSEC_GNUTLS_IS_SPACE(ch)) { *(p++) = ch; /* we are sure we have enough buffer */ state = xmlSecGnuTLSDnParseState_Key; } else { /* just skip space */ } break; case xmlSecGnuTLSDnParseState_Key: /* we don't support 1) <attribute><optional-space>"+"<optional-space><name-component> 2) <attribute> ::= <string> */ if(ch != '=') { *(p++) = ch; /* we are sure we have enough buffer */ } else { *(p) = '\0'; /* remove spaces back */ while((p > tmp) && (XMLSEC_GNUTLS_IS_SPACE(*(p - 1)))) { *(--p) = '\0'; } /* insert into the attrs */ if(pos >= attrsSize) { xmlSecInvalidSizeLessThanError("Attributes", attrsSize, pos, NULL); goto done; } attrs[pos].key = xmlStrdup(tmp); if(attrs[pos].key == NULL) { xmlSecStrdupError(tmp, NULL); goto done; } state = xmlSecGnuTLSDnParseState_BeforeString; p = tmp; } break; case xmlSecGnuTLSDnParseState_BeforeString: if(!XMLSEC_GNUTLS_IS_SPACE(ch)) { if(ch != '\"') { state = xmlSecGnuTLSDnParseState_String; slash = 0; --dn; /* small hack, so we can look at the same char again with the correct state */ } else { state = xmlSecGnuTLSDnParseState_QuotedString; slash = 0; } } else { /* just skip space */ } break; case xmlSecGnuTLSDnParseState_String: if(slash == 1) { *(p++) = ch; /* we are sure we have enough buffer */ slash = 0; } else if(ch == '\\') { slash = 1; } else if((ch == ',') || (ch == ';') || (ch == '\0')) { *(p) = '\0'; /* remove spaces back */ while((p > tmp) && (XMLSEC_GNUTLS_IS_SPACE(*(p - 1)))) { *(--p) = '\0'; } attrs[pos].value = xmlStrdup(tmp); if(attrs[pos].value == NULL) { xmlSecStrdupError(tmp, NULL); goto done; } state = xmlSecGnuTLSDnParseState_BeforeNameComponent; ++pos; p = tmp; } else { *(p++) = ch; /* we are sure we have enough buffer */ } break; case xmlSecGnuTLSDnParseState_QuotedString: if(slash == 1) { *(p++) = ch; /* we are sure we have enough buffer */ slash = 0; } else if(ch == '\\') { slash = 1; } else if(ch == '\"') { *(p) = '\0'; /* don't remove spaces for quoted string */ attrs[pos].value = xmlStrdup(tmp); if(attrs[pos].value == NULL) { xmlSecStrdupError(tmp, NULL); goto done; } state = xmlSecGnuTLSDnParseState_AfterQuotedString; ++pos; p = tmp; } else { *(p++) = ch; /* we are sure we have enough buffer */ } break; case xmlSecGnuTLSDnParseState_AfterQuotedString: if(!XMLSEC_GNUTLS_IS_SPACE(ch)) { if((ch == ',') || (ch == ';') || (ch == '\0')) { state = xmlSecGnuTLSDnParseState_BeforeNameComponent; } else { xmlSecInvalidIntegerDataError("ch", ch, "space,',',';','\\0'", NULL); goto done; } } else { /* just skip space */ } break; } if(ch == '\0') { /* done */ break; } } /* check end state */ if(state != xmlSecGnuTLSDnParseState_BeforeNameComponent) { xmlSecUnsupportedEnumValueError("state", state, NULL); goto done; } /* done */ res = 0; done: if(tmp != NULL) { xmlFree(tmp); } return(res); } #endif /* XMLSEC_NO_X509 */