summaryrefslogtreecommitdiff
path: root/src/nss/x509vfy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nss/x509vfy.c')
-rw-r--r--src/nss/x509vfy.c808
1 files changed, 808 insertions, 0 deletions
diff --git a/src/nss/x509vfy.c b/src/nss/x509vfy.c
new file mode 100644
index 00000000..fdb866fe
--- /dev/null
+++ b/src/nss/x509vfy.c
@@ -0,0 +1,808 @@
+/**
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (c) 2003 America Online, Inc. All rights reserved.
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <cert.h>
+#include <secerr.h>
+
+#include <libxml/tree.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/keysmngr.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/nss/crypto.h>
+#include <xmlsec/nss/x509.h>
+
+/**************************************************************************
+ *
+ * Internal NSS X509 store CTX
+ *
+ *************************************************************************/
+typedef struct _xmlSecNssX509StoreCtx xmlSecNssX509StoreCtx,
+ *xmlSecNssX509StoreCtxPtr;
+struct _xmlSecNssX509StoreCtx {
+ /* Two uses:
+ *
+ * 1) Just keeping a reference to destroy later.
+ *
+ * 2) NSS doesn't update it's cache correctly when new certs are added
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=211051
+ * we use this list to perform search ourselves.
+ */
+
+ CERTCertList* certsList; /* just keeping a reference to destroy later */
+};
+
+/****************************************************************************
+ *
+ * xmlSecNssKeyDataStoreX509Id:
+ *
+ * xmlSecNssX509StoreCtx is located after xmlSecTransform
+ *
+ ***************************************************************************/
+#define xmlSecNssX509StoreGetCtx(store) \
+ ((xmlSecNssX509StoreCtxPtr)(((xmlSecByte*)(store)) + \
+ sizeof(xmlSecKeyDataStoreKlass)))
+#define xmlSecNssX509StoreSize \
+ (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecNssX509StoreCtx))
+
+static int xmlSecNssX509StoreInitialize (xmlSecKeyDataStorePtr store);
+static void xmlSecNssX509StoreFinalize (xmlSecKeyDataStorePtr store);
+static int xmlSecNssX509NameStringRead (xmlSecByte **str,
+ int *strLen,
+ xmlSecByte *res,
+ int resLen,
+ xmlSecByte delim,
+ int ingoreTrailingSpaces);
+static xmlSecByte * xmlSecNssX509NameRead (xmlSecByte *str,
+ int len);
+
+static int xmlSecNssNumToItem (SECItem *it,
+ PRUint64 num);
+
+
+static xmlSecKeyDataStoreKlass xmlSecNssX509StoreKlass = {
+ sizeof(xmlSecKeyDataStoreKlass),
+ xmlSecNssX509StoreSize,
+
+ /* data */
+ xmlSecNameX509Store, /* const xmlChar* name; */
+
+ /* constructors/destructor */
+ xmlSecNssX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */
+ xmlSecNssX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+static CERTCertificate* xmlSecNssX509FindCert(CERTCertList* certsList,
+ const xmlChar *subjectName,
+ const xmlChar *issuerName,
+ const xmlChar *issuerSerial,
+ xmlChar *ski);
+
+
+/**
+ * xmlSecNssX509StoreGetKlass:
+ *
+ * The NSS X509 certificates key data store klass.
+ *
+ * Returns: pointer to NSS X509 certificates key data store klass.
+ */
+xmlSecKeyDataStoreId
+xmlSecNssX509StoreGetKlass(void) {
+ return(&xmlSecNssX509StoreKlass);
+}
+
+/**
+ * xmlSecNssX509StoreFindCert:
+ * @store: the pointer to X509 key data store klass.
+ * @subjectName: the desired certificate name.
+ * @issuerName: the desired certificate issuer name.
+ * @issuerSerial: the desired certificate issuer serial number.
+ * @ski: the desired certificate SKI.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Searches @store for a certificate that matches given criteria.
+ *
+ * Returns: pointer to found certificate or NULL if certificate is not found
+ * or an error occurs.
+ */
+CERTCertificate *
+xmlSecNssX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName,
+ xmlChar *issuerName, xmlChar *issuerSerial,
+ xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) {
+ xmlSecNssX509StoreCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ ctx = xmlSecNssX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ return xmlSecNssX509FindCert(ctx->certsList, subjectName, issuerName, issuerSerial, ski);
+}
+
+/**
+ * xmlSecNssX509StoreVerify:
+ * @store: the pointer to X509 key data store klass.
+ * @certs: the untrusted certificates stack.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Verifies @certs list.
+ *
+ * Returns: pointer to the first verified certificate from @certs.
+ */
+CERTCertificate *
+xmlSecNssX509StoreVerify(xmlSecKeyDataStorePtr store, CERTCertList* certs,
+ xmlSecKeyInfoCtx* keyInfoCtx) {
+ xmlSecNssX509StoreCtxPtr ctx;
+ CERTCertListNode* head;
+ CERTCertificate* cert = NULL;
+ CERTCertListNode* head1;
+ CERTCertificate* cert1 = NULL;
+ SECStatus status = SECFailure;
+ int64 timeboundary;
+ int64 tmp1, tmp2;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), NULL);
+ xmlSecAssert2(certs != NULL, NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ ctx = xmlSecNssX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ for (head = CERT_LIST_HEAD(certs);
+ !CERT_LIST_END(head, certs);
+ head = CERT_LIST_NEXT(head)) {
+ cert = head->cert;
+ if(keyInfoCtx->certsVerificationTime > 0) {
+ /* convert the time since epoch in seconds to microseconds */
+ LL_UI2L(timeboundary, keyInfoCtx->certsVerificationTime);
+ tmp1 = (int64)PR_USEC_PER_SEC;
+ tmp2 = timeboundary;
+ LL_MUL(timeboundary, tmp1, tmp2);
+ } else {
+ timeboundary = PR_Now();
+ }
+
+ /* if cert is the issuer of any other cert in the list, then it is
+ * to be skipped */
+ for (head1 = CERT_LIST_HEAD(certs);
+ !CERT_LIST_END(head1, certs);
+ head1 = CERT_LIST_NEXT(head1)) {
+
+ cert1 = head1->cert;
+ if (cert1 == cert) {
+ continue;
+ }
+
+ if (SECITEM_CompareItem(&cert1->derIssuer, &cert->derSubject)
+ == SECEqual) {
+ break;
+ }
+ }
+
+ if (!CERT_LIST_END(head1, certs)) {
+ continue;
+ }
+
+ status = CERT_VerifyCertificate(CERT_GetDefaultCertDB(),
+ cert, PR_FALSE,
+ (SECCertificateUsage)0,
+ timeboundary , NULL, NULL, NULL);
+ if (status == SECSuccess) {
+ break;
+ }
+ }
+
+ if (status == SECSuccess) {
+ return (cert);
+ }
+
+ switch(PORT_GetError()) {
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ case SEC_ERROR_CA_CERT_INVALID:
+ case SEC_ERROR_UNKNOWN_SIGNER:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,
+ "cert with subject name %s could not be verified because the issuer's cert is expired/invalid or not found",
+ cert->subjectName);
+ break;
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,
+ "cert with subject name %s has expired",
+ cert->subjectName);
+ break;
+ case SEC_ERROR_REVOKED_CERTIFICATE:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_REVOKED,
+ "cert with subject name %s has been revoked",
+ cert->subjectName);
+ break;
+ default:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+ "cert with subject name %s could not be verified, errcode %d",
+ cert->subjectName,
+ PORT_GetError());
+ break;
+ }
+
+ return (NULL);
+}
+
+/**
+ * xmlSecNssX509StoreAdoptCert:
+ * @store: the pointer to X509 key data store klass.
+ * @cert: the pointer to NSS 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.
+ */
+int
+xmlSecNssX509StoreAdoptCert(xmlSecKeyDataStorePtr store, CERTCertificate* cert, xmlSecKeyDataType type ATTRIBUTE_UNUSED) {
+ xmlSecNssX509StoreCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecNssX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ if(ctx->certsList == NULL) {
+ ctx->certsList = CERT_NewCertList();
+ if(ctx->certsList == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CERT_NewCertList",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "error code=%d", PORT_GetError());
+ return(-1);
+ }
+ }
+
+ ret = CERT_AddCertToListTail(ctx->certsList, cert);
+ if(ret != SECSuccess) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CERT_AddCertToListTail",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "error code=%d", PORT_GetError());
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecNssX509StoreInitialize(xmlSecKeyDataStorePtr store) {
+ xmlSecNssX509StoreCtxPtr ctx;
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), -1);
+
+ ctx = xmlSecNssX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecNssX509StoreCtx));
+
+ return(0);
+}
+
+static void
+xmlSecNssX509StoreFinalize(xmlSecKeyDataStorePtr store) {
+ xmlSecNssX509StoreCtxPtr ctx;
+ xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId));
+
+ ctx = xmlSecNssX509StoreGetCtx(store);
+ xmlSecAssert(ctx != NULL);
+
+ if (ctx->certsList) {
+ CERT_DestroyCertList(ctx->certsList);
+ ctx->certsList = NULL;
+ }
+
+ memset(ctx, 0, sizeof(xmlSecNssX509StoreCtx));
+}
+
+
+/*****************************************************************************
+ *
+ * Low-level x509 functions
+ *
+ *****************************************************************************/
+static CERTName *
+xmlSecNssGetCertName(const xmlChar * name) {
+ xmlChar *tmp, *name2;
+ xmlChar *p;
+ CERTName *res;
+
+ xmlSecAssert2(name != NULL, NULL);
+
+ /* nss doesn't support emailAddress (see https://bugzilla.mozilla.org/show_bug.cgi?id=561689)
+ * This code is not bullet proof and may produce incorrect results if someone has
+ * "emailAddress=" string in one of the fields, but it is best I can suggest to fix
+ * this problem.
+ */
+ name2 = xmlStrdup(name);
+ if(name2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "xmlStrlen(name)=%d",
+ xmlStrlen(name));
+ return(NULL);
+ }
+ while( (p = (xmlChar*)xmlStrstr(name2, BAD_CAST "emailAddress=")) != NULL) {
+ memcpy(p, " E=", 13);
+ }
+
+ tmp = xmlSecNssX509NameRead(name2, xmlStrlen(name2));
+ if(tmp == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssX509NameRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "name2=\"%s\"",
+ xmlSecErrorsSafeString(name2));
+ xmlFree(name2);
+ return(NULL);
+ }
+
+ res = CERT_AsciiToName((char*)tmp);
+ if (name == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "CERT_AsciiToName",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "ascii=\"%s\", error code=%d",
+ xmlSecErrorsSafeString((char*)tmp),
+ PORT_GetError());
+ PORT_Free(tmp);
+ xmlFree(name2);
+ return(NULL);
+ }
+
+ PORT_Free(tmp);
+ return(res);
+}
+
+static CERTCertificate*
+xmlSecNssX509FindCert(CERTCertList* certsList, const xmlChar *subjectName,
+ const xmlChar *issuerName, const xmlChar *issuerSerial,
+ xmlChar *ski) {
+ CERTCertificate *cert = NULL;
+ CERTName *name = NULL;
+ SECItem *nameitem = NULL;
+ CERTCertListNode* head;
+ SECItem tmpitem;
+ SECStatus status;
+ PRArenaPool *arena = NULL;
+ int rv;
+
+ if ((cert == NULL) && (subjectName != NULL)) {
+ name = xmlSecNssGetCertName(subjectName);
+ if (name == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssGetCertName",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "subject=%s",
+ xmlSecErrorsSafeString(subjectName));
+ goto done;
+ }
+
+ if(arena == NULL) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "PORT_NewArena",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ }
+
+ nameitem = SEC_ASN1EncodeItem(arena, NULL, (void *)name,
+ SEC_ASN1_GET(CERT_NameTemplate));
+ if (nameitem == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "SEC_ASN1EncodeItem",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "error code=%d", PORT_GetError());
+ goto done;
+ }
+
+ cert = CERT_FindCertByName(CERT_GetDefaultCertDB(), nameitem);
+ }
+
+ if((cert == NULL) && (issuerName != NULL) && (issuerSerial != NULL)) {
+ CERTIssuerAndSN issuerAndSN;
+ PRUint64 issuerSN = 0;
+
+ name = xmlSecNssGetCertName(issuerName);
+ if (name == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssGetCertName",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "issuer=%s",
+ xmlSecErrorsSafeString(issuerName));
+ goto done;
+ }
+
+ if(arena == NULL) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "PORT_NewArena",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ }
+
+ nameitem = SEC_ASN1EncodeItem(arena, NULL, (void *)name,
+ SEC_ASN1_GET(CERT_NameTemplate));
+ if (nameitem == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "SEC_ASN1EncodeItem",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "error code=%d", PORT_GetError());
+ goto done;
+ }
+
+ memset(&issuerAndSN, 0, sizeof(issuerAndSN));
+
+ issuerAndSN.derIssuer.data = nameitem->data;
+ issuerAndSN.derIssuer.len = nameitem->len;
+
+ /* TBD: serial num can be arbitrarily long */
+ if(PR_sscanf((char *)issuerSerial, "%llu", &issuerSN) != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "PR_sscanf",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "error code=%d", PR_GetError());
+ SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE);
+ goto done;
+ }
+
+ rv = xmlSecNssNumToItem(&issuerAndSN.serialNumber, issuerSN);
+ if(rv <= 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssNumToItem",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "error code=%d", PR_GetError());
+ SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE);
+ goto done;
+ }
+
+ cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerAndSN);
+ SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE);
+ }
+
+ if((cert == NULL) && (ski != NULL)) {
+ SECItem subjKeyID;
+ int len;
+
+ 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));
+ goto done;
+ }
+
+ memset(&subjKeyID, 0, sizeof(subjKeyID));
+ subjKeyID.data = ski;
+ subjKeyID.len = len;
+ cert = CERT_FindCertBySubjectKeyID(CERT_GetDefaultCertDB(),
+ &subjKeyID);
+
+ /* try to search in our list - NSS doesn't update it's cache correctly
+ * when new certs are added https://bugzilla.mozilla.org/show_bug.cgi?id=211051
+ */
+ if((cert == NULL) && (certsList != NULL)) {
+
+ for(head = CERT_LIST_HEAD(certsList);
+ (cert == NULL) && !CERT_LIST_END(head, certsList) &&
+ (head != NULL) && (head->cert != NULL);
+ head = CERT_LIST_NEXT(head)
+ ) {
+
+ memset(&tmpitem, 0, sizeof(tmpitem));
+ status = CERT_FindSubjectKeyIDExtension(head->cert, &tmpitem);
+ if (status != SECSuccess) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "CERT_FindSubjectKeyIDExtension",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "ski");
+ SECITEM_FreeItem(&tmpitem, PR_FALSE);
+ goto done;
+ }
+
+ if((tmpitem.len == subjKeyID.len) &&
+ (memcmp(tmpitem.data, subjKeyID.data, subjKeyID.len) == 0)
+ ) {
+ cert = CERT_DupCertificate(head->cert);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "CERT_DupCertificate",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "error code=%d", PORT_GetError());
+ SECITEM_FreeItem(&tmpitem, PR_FALSE);
+ goto done;
+ }
+ }
+ SECITEM_FreeItem(&tmpitem, PR_FALSE);
+ }
+ }
+ }
+
+done:
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ if (name != NULL) {
+ CERT_DestroyName(name);
+ }
+
+ return(cert);
+}
+
+static xmlSecByte *
+xmlSecNssX509NameRead(xmlSecByte *str, int len) {
+ xmlSecByte name[256];
+ xmlSecByte value[256];
+ xmlSecByte *retval = NULL;
+ xmlSecByte *p = NULL;
+ int nameLen, valueLen;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ /* return string should be no longer than input string */
+ retval = (xmlSecByte *)PORT_Alloc(len+1);
+ if(retval == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "PORT_Alloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ p = retval;
+
+ while(len > 0) {
+ /* skip spaces after comma or semicolon */
+ while((len > 0) && isspace(*str)) {
+ ++str; --len;
+ }
+
+ nameLen = xmlSecNssX509NameStringRead(&str, &len, name, sizeof(name), '=', 0);
+ if(nameLen < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssX509NameStringRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ memcpy(p, name, nameLen);
+ p+=nameLen;
+ *p++='=';
+ if(len > 0) {
+ ++str; --len;
+ if((*str) == '\"') {
+ valueLen = xmlSecNssX509NameStringRead(&str, &len,
+ value, sizeof(value), '"', 1);
+ if(valueLen < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssX509NameStringRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ /* 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");
+ goto done;
+ }
+ if(len > 0) {
+ ++str; --len;
+ }
+ *p++='\"';
+ memcpy(p, value, valueLen);
+ p+=valueLen;
+ *p++='\"';
+ } else if((*str) == '#') {
+ /* TODO: read octect values */
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "reading octect values is not implemented yet");
+ goto done;
+ } else {
+ valueLen = xmlSecNssX509NameStringRead(&str, &len,
+ value, sizeof(value), ',', 1);
+ if(valueLen < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecNssX509NameStringRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ memcpy(p, value, valueLen);
+ p+=valueLen;
+ if (len > 0)
+ *p++=',';
+ }
+ } else {
+ valueLen = 0;
+ }
+ if(len > 0) {
+ ++str; --len;
+ }
+ }
+
+ *p = 0;
+ return(retval);
+
+done:
+ PORT_Free(retval);
+ return (NULL);
+}
+
+static int
+xmlSecNssX509NameStringRead(xmlSecByte **str, int *strLen,
+ xmlSecByte *res, int resLen,
+ xmlSecByte delim, int ingoreTrailingSpaces) {
+ xmlSecByte *p, *q, *nonSpace;
+
+ xmlSecAssert2(str != NULL, -1);
+ xmlSecAssert2(strLen != NULL, -1);
+ xmlSecAssert2(res != NULL, -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);
+}
+
+/* code lifted from NSS */
+static int
+xmlSecNssNumToItem(SECItem *it, PRUint64 ui)
+{
+ unsigned char bb[9];
+ unsigned int zeros_len;
+
+ xmlSecAssert2(it != NULL, -1);
+
+ bb[0] = 0; /* important: we should have 0 at the beginning! */
+ bb[1] = (unsigned char) (ui >> 56);
+ bb[2] = (unsigned char) (ui >> 48);
+ bb[3] = (unsigned char) (ui >> 40);
+ bb[4] = (unsigned char) (ui >> 32);
+ bb[5] = (unsigned char) (ui >> 24);
+ bb[6] = (unsigned char) (ui >> 16);
+ bb[7] = (unsigned char) (ui >> 8);
+ bb[8] = (unsigned char) (ui);
+
+ /*
+ ** Small integers are encoded in a single byte. Larger integers
+ ** require progressively more space. Start from 1 because byte at
+ ** position 0 is zero
+ */
+ for(zeros_len = 1; (zeros_len < sizeof(bb)) && (bb[zeros_len] == 0); ++zeros_len);
+
+ it->len = sizeof(bb) - (zeros_len - 1);
+ it->data = (unsigned char *)PORT_Alloc(it->len);
+ if (it->data == NULL) {
+ it->len = 0;
+ return (-1);
+ }
+
+ PORT_Memcpy(it->data, bb + (zeros_len - 1), it->len);
+ return(it->len);
+}
+#endif /* XMLSEC_NO_X509 */
+
+