[xmlsec] add dn parser to fix cert lookup issues
- From: Aleksey Sanin <aleksey src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [xmlsec] add dn parser to fix cert lookup issues
- Date: Mon, 24 May 2010 22:36:18 +0000 (UTC)
commit 8ad508073a9d17e4ea77559c75ca3008589fc568
Author: Aleksey Sanin <aleksey aleksey com>
Date: Mon May 24 14:15:31 2010 -0700
add dn parser to fix cert lookup issues
src/gnutls/app.c | 1 -
src/gnutls/x509utils.c | 387 ++++++++++++++++++++++++++++++++++++++++++++++++
src/gnutls/x509utils.h | 25 +++
src/gnutls/x509vfy.c | 72 +++++++++-
4 files changed, 479 insertions(+), 6 deletions(-)
---
diff --git a/src/gnutls/app.c b/src/gnutls/app.c
index e510cee..467e36e 100644
--- a/src/gnutls/app.c
+++ b/src/gnutls/app.c
@@ -361,7 +361,6 @@ xmlSecGnuTLSAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
gnutls_x509_privkey_t priv_key = NULL;
gnutls_x509_crt_t key_cert = NULL;
xmlSecSize certsSize;
- int err;
int ret;
xmlSecAssert2(data != NULL, NULL);
diff --git a/src/gnutls/x509utils.c b/src/gnutls/x509utils.c
index 7417ed8..6812e8a 100644
--- a/src/gnutls/x509utils.c
+++ b/src/gnutls/x509utils.c
@@ -976,6 +976,393 @@ xmlSecGnuTLSCreateKeyDataAndAdoptPrivKey(gnutls_x509_privkey_t priv_key) {
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 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 */
+ tmp = (xmlChar *)xmlMalloc(xmlStrlen(dn) + 1);
+ if(tmp == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)(xmlStrlen(dn) + 1));
+ 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "Not enough space: size=%d", (int)attrsSize);
+ goto done;
+ }
+ attrs[pos].key = xmlStrdup(tmp);
+ if(attrs[pos].key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)(xmlStrlen(tmp) + 1));
+ 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)(xmlStrlen(tmp) + 1));
+ 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)(xmlStrlen(tmp) + 1));
+ 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 {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "Unexpected character %c (expected space or ',' or ';')",
+ ch);
+ goto done;
+ }
+ } else {
+ /* just skip space */
+ }
+ break;
+ }
+
+ if(ch == '\0') {
+ /* done */
+ break;
+ }
+ }
+
+ /* check end state */
+ if(state != xmlSecGnuTLSDnParseState_BeforeNameComponent) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "Unexpected state %d at the end of parsing",
+ (int)state);
+ goto done;
+ }
+
+ /* debug
+ {
+ xmlSecSize ii;
+ for(ii = 0; ii < attrsSize; ++ii) {
+ if(attrs[ii].key != NULL) {
+ printf("DEBUG: attrs - %s=>%s\n", attrs[ii].key, attrs[ii].value);
+ }
+ }
+ }
+ */
+
+ /* done */
+ res = 0;
+
+done:
+ if(tmp != NULL) {
+ xmlFree(tmp);
+ }
+ return(res);
+}
#endif /* XMLSEC_NO_X509 */
diff --git a/src/gnutls/x509utils.h b/src/gnutls/x509utils.h
index 33bb3eb..b859a01 100644
--- a/src/gnutls/x509utils.h
+++ b/src/gnutls/x509utils.h
@@ -72,6 +72,31 @@ int xmlSecGnuTLSPkcs12LoadMemory (const xmlSecByt
xmlSecKeyDataPtr xmlSecGnuTLSCreateKeyDataAndAdoptPrivKey(gnutls_x509_privkey_t priv_key);
+
+/*************************************************************************
+ *
+ * LDAP DN parser
+ *
+ ************************************************************************/
+typedef struct _xmlSecGnuTLSDnAttr {
+ xmlChar * key;
+ xmlChar * value;
+} xmlSecGnuTLSDnAttr;
+
+void xmlSecGnuTLSDnAttrsInitialize (xmlSecGnuTLSDnAttr * attrs,
+ xmlSecSize attrsSize);
+void xmlSecGnuTLSDnAttrsDeinitialize (xmlSecGnuTLSDnAttr * attrs,
+ xmlSecSize attrsSize);
+const xmlSecGnuTLSDnAttr * xmlSecGnuTLSDnAttrrsFind (const xmlSecGnuTLSDnAttr * attrs,
+ xmlSecSize attrsSize,
+ const xmlChar * key);
+int xmlSecGnuTLSDnAttrsEqual (const xmlSecGnuTLSDnAttr * ll,
+ xmlSecSize llSize,
+ const xmlSecGnuTLSDnAttr * rr,
+ xmlSecSize rrSize);
+int xmlSecGnuTLSDnAttrsParse (const xmlChar * dn,
+ xmlSecGnuTLSDnAttr * attrs,
+ xmlSecSize attrsSize);
#endif /* XMLSEC_NO_X509 */
#ifdef __cplusplus
diff --git a/src/gnutls/x509vfy.c b/src/gnutls/x509vfy.c
index c87b6aa..e9ac28d 100644
--- a/src/gnutls/x509vfy.c
+++ b/src/gnutls/x509vfy.c
@@ -584,6 +584,69 @@ xmlSecGnuTLSX509StoreFinalize(xmlSecKeyDataStorePtr store) {
* Low-level x509 functions
*
*****************************************************************************/
+#define XMLSEC_GNUTLS_DN_ATTRS_SIZE 1024
+static 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSDnAttrsParse(ll)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ ret = xmlSecGnuTLSDnAttrsParse(rr, rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSDnAttrsParse(rr)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ 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 {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSDnAttrsEqual",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+done:
+ xmlSecGnuTLSDnAttrsDeinitialize(ll_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE);
+ xmlSecGnuTLSDnAttrsDeinitialize(rr_attrs, XMLSEC_GNUTLS_DN_ATTRS_SIZE);
+ return(res);
+}
+
static gnutls_x509_crt_t
xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs,
const xmlChar *subjectName,
@@ -594,7 +657,6 @@ xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs,
xmlSecAssert2(certs != NULL, NULL);
-
/* todo: this is not the fastest way to search certs */
sz = xmlSecPtrListGetSize(certs);
for(ii = 0; (ii < sz); ++ii) {
@@ -621,7 +683,7 @@ xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs,
return(NULL);
}
- if(xmlStrEqual(subjectName, tmp)) {
+ if(xmlSecGnuTLSX509DnsEqual(subjectName, tmp) == 1) {
xmlFree(tmp);
return(cert);
}
@@ -651,7 +713,7 @@ xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs,
return(NULL);
}
- if(xmlStrEqual(issuerName, tmp1) && xmlStrEqual(issuerSerial, tmp2)) {
+ if((xmlSecGnuTLSX509DnsEqual(issuerName, tmp1) == 1) && xmlStrEqual(issuerSerial, tmp2)) {
xmlFree(tmp1);
xmlFree(tmp2);
return(cert);
@@ -730,7 +792,7 @@ xmlSecGnuTLSX509FindSignedCert(xmlSecPtrListPtr certs, gnutls_x509_crt_t cert) {
}
/* are we done? */
- if(xmlStrEqual(subject, issuer)) {
+ if(xmlSecGnuTLSX509DnsEqual(subject, issuer) == 1) {
res = tmp;
}
xmlFree(issuer);
@@ -791,7 +853,7 @@ xmlSecGnuTLSX509FindSignerCert(xmlSecPtrListPtr certs, gnutls_x509_crt_t cert) {
}
/* are we done? */
- if(xmlStrEqual(issuer, subject)) {
+ if((xmlSecGnuTLSX509DnsEqual(issuer, subject) == 1)) {
res = tmp;
}
xmlFree(subject);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]