please find attached file x509-sn_is__.patch.gz with latest changes.Well, this patch still has some problems: 0) The "writer" approach you use is less flexible than "flags" approach I have suggested. For example, it does not allow you to write *both* subject name and issuer serial nodes which might be required. 1) The patch erases the content of the X509Data node when it writes data out. This seems wrong to me. For example, application might want to put a pointer common cert (say, with X509SubjectName) and write key specific certs in X509Certificate. The only way to do it is to write X509SubjectName node manually and put a placeholder for X509Certificate in the template: <X509Data> <X509SubjectName>some subject</X509SubjectName> <X509Certificate/> </X509Data> I think it's a good idea to keep this ability to "add" data to X509Data node as we do now. 2) You changed the code to skip "empty" nodes. In most cases it can cause no harm but some applications may decide that it's not acceptable. I think a flag in xmlSecKeyInfoCtx should solve this issue. 3) There were few memory leaks in the *Read functions with the same pattern: get node content, check that it's empty, return 0 w/o freeing content. 4) After fixing the code I realized that the new xmlSecKeyInfoCtx flag XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_WRITE_CRLS you have added is not necessary. If application does not want to write CRLs then it just uses following template: <X509Data> <X509Certificate/> </X509Data> Anyway, I have fixed all the issues above (see attached patch). It is checked in CVS along with a new test case to make sure it actually works. I hope that Tej would be able to do similar thing in xmlsec-nss. Roumen, I would appreciate if you can try this new code and check that after my changes it is still doing what you need. Well, your points are valid. The only thing I have to object is that there are already a lot of code in xmlsec written w/o using this trick. It makes very difficult (for me at least) to switch from one code style to another inside the same source file. I am trying to preserve the exisiting code style. It makes much more easier to read the code when everything is written in one style. Even if this style is not the best one :) Aleksey |
Index: include/xmlsec/keyinfo.h
===================================================================
RCS file: /cvs/gnome/xmlsec/include/xmlsec/keyinfo.h,v
retrieving revision 1.28
diff -u -r1.28 keyinfo.h
--- include/xmlsec/keyinfo.h 21 Jul 2003 03:12:37 -0000 1.28
+++ include/xmlsec/keyinfo.h 28 Jul 2003 19:01:39 -0000
@@ -137,6 +137,14 @@
*/
#define XMLSEC_KEYINFO_FLAGS_ENCKEY_DONT_STOP_ON_FAILED_DECRYPTION 0x00001000
+/**
+ * XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE:
+ *
+ * If the flag is set then we'll stop when we found an empty node.
+ * Otherwise we just ignore it.
+ */
+#define XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE 0x00002000
+
/**
* xmlSecKeyInfoCtx:
* @userData: the pointer to user data (xmlsec and xmlsec-crypto
Index: include/xmlsec/xmltree.h
===================================================================
RCS file: /cvs/gnome/xmlsec/include/xmlsec/xmltree.h,v
retrieving revision 1.17
diff -u -r1.17 xmltree.h
--- include/xmlsec/xmltree.h 21 Jul 2003 03:12:37 -0000 1.17
+++ include/xmlsec/xmltree.h 28 Jul 2003 19:01:39 -0000
@@ -67,6 +67,9 @@
XMLSEC_EXPORT xmlDocPtr xmlSecCreateTree (const xmlChar*
rootNodeName,
const xmlChar* rootNodeNs);
+XMLSEC_EXPORT int xmlSecIsEmptyNode (xmlNodePtr node);
+XMLSEC_EXPORT int xmlSecIsEmptyString (const xmlChar* str);
+
/**
* xmlSecIsHex:
* @c: the character.
Index: src/xmltree.c
===================================================================
RCS file: /cvs/gnome/xmlsec/src/xmltree.c,v
retrieving revision 1.25
diff -u -r1.25 xmltree.c
--- src/xmltree.c 21 Jul 2003 03:12:48 -0000 1.25
+++ src/xmltree.c 28 Jul 2003 19:01:39 -0000
@@ -616,4 +616,48 @@
return(doc);
}
+/**
+ * xmlSecIsEmptyNode:
+ * @node: the node to check
+ *
+ * Checks whethere the @node is empty (i.e. has only whitespaces children).
+ *
+ * Returns 1 if @node is empty, 0 otherwise or a negative value if an error occurs.
+ */
+int
+xmlSecIsEmptyNode(xmlNodePtr node) {
+ xmlChar* content;
+ int res;
+
+ xmlSecAssert2(node != NULL, -1);
+
+ content = xmlNodeGetContent(node);
+ if(content == NULL) {
+ return(1);
+ }
+
+ res = xmlSecIsEmptyString(content);
+ xmlFree(content);
+ return(res);
+}
+
+/**
+ * xmlSecIsEmptyString:
+ * @str: the string to check
+ *
+ * Checks whethere the @str is empty (i.e. has only whitespaces children).
+ *
+ * Returns 1 if @str is empty, 0 otherwise or a negative value if an error occurs.
+ */
+int
+xmlSecIsEmptyString(const xmlChar* str) {
+ xmlSecAssert2(str != NULL, -1);
+
+ for( ;*str != '\0'; ++str) {
+ if(!isspace((int)(*str))) {
+ return(0);
+ }
+ }
+ return(1);
+}
Index: src/openssl/x509.c
===================================================================
RCS file: /cvs/gnome/xmlsec/src/openssl/x509.c,v
retrieving revision 1.37
diff -u -r1.37 x509.c
--- src/openssl/x509.c 21 Jul 2003 03:12:55 -0000 1.37
+++ src/openssl/x509.c 28 Jul 2003 19:01:39 -0000
@@ -45,23 +45,38 @@
*
************************************************************************/
static int xmlSecOpenSSLX509DataNodeRead (xmlSecKeyDataPtr data,
- xmlNodePtr node,
+ xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLX509CertificateNodeRead (xmlSecKeyDataPtr data,
xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
+static int xmlSecOpenSSLX509CertificateNodeWrite (X509* cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLX509SubjectNameNodeRead (xmlSecKeyDataPtr data,
xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
+static int xmlSecOpenSSLX509SubjectNameNodeWrite (X509* cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLX509IssuerSerialNodeRead (xmlSecKeyDataPtr data,
xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
+static int xmlSecOpenSSLX509IssuerSerialNodeWrite (X509* cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLX509SKINodeRead (xmlSecKeyDataPtr data,
xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
+static int xmlSecOpenSSLX509SKINodeWrite (X509* cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLX509CRLNodeRead (xmlSecKeyDataPtr data,
xmlNodePtr node,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
+static int xmlSecOpenSSLX509CRLNodeWrite (X509_CRL* crl,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr
keyInfoCtx);
static int xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr
data,
xmlSecKeyPtr key,
xmlSecKeyInfoCtxPtr
keyInfoCtx);
@@ -76,6 +91,9 @@
static X509_CRL* xmlSecOpenSSLX509CrlBase64DerRead (xmlChar* buf);
static xmlChar* xmlSecOpenSSLX509CrlBase64DerWrite (X509_CRL*
crl,
int base64LineWrap);
+static xmlChar* xmlSecOpenSSLX509NameWrite (X509_NAME*
nm);
+static xmlChar* xmlSecOpenSSLASN1IntegerWrite (ASN1_INTEGER
*asni);
+static xmlChar* xmlSecOpenSSLX509SKIWrite (X509* cert);
static void xmlSecOpenSSLX509CertDebugDump (X509* cert,
FILE* output);
static void xmlSecOpenSSLX509CertDebugXmlDump (X509* cert,
@@ -83,6 +101,12 @@
static int xmlSecOpenSSLX509CertGetTime (ASN1_TIME* t,
time_t* res);
+#define XMLSEC_OPENSSL_X509_CERTIFICATE_NODE 0x00000001
+#define XMLSEC_OPENSSL_X509_SUBJECTNAME_NODE 0x00000002
+#define XMLSEC_OPENSSL_X509_ISSUERSERIAL_NODE 0x00000004
+#define XMLSEC_OPENSSL_X509_SKI_NODE 0x00000008
+#define XMLSEC_OPENSSL_X509_CRL_NODE 0x00000010
+
/*************************************************************************
*
* Internal OpenSSL X509 data CTX
@@ -679,22 +703,65 @@
xmlSecOpenSSLKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key,
xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlSecKeyDataPtr data;
- xmlNodePtr cur;
- xmlChar* buf;
+ xmlNodePtr cur, next;
X509* cert;
X509_CRL* crl;
xmlSecSize size, pos;
-
+ unsigned int content = 0;
+ int deleteCurNode;
+ int ret;
+
xmlSecAssert2(id == xmlSecOpenSSLKeyDataX509Id, -1);
xmlSecAssert2(key != NULL, -1);
xmlSecAssert2(node != NULL, -1);
xmlSecAssert2(keyInfoCtx != NULL, -1);
- /* todo: flag in ctx remove all existing content */
- if(0) {
- xmlNodeSetContent(node, NULL);
+ /* determine the current node content */
+ cur = xmlSecGetNextElementNode(node->children);
+ while(cur != NULL) {
+ deleteCurNode = 0;
+ if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_OPENSSL_X509_CERTIFICATE_NODE;
+ deleteCurNode = 1;
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_OPENSSL_X509_SUBJECTNAME_NODE;
+ deleteCurNode = 1;
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_OPENSSL_X509_ISSUERSERIAL_NODE;
+ deleteCurNode = 1;
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_OPENSSL_X509_SKI_NODE;
+ deleteCurNode = 1;
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_OPENSSL_X509_CRL_NODE;
+ deleteCurNode = 1;
+ }
+ } else {
+ /* todo: fail on unknown child node? */
+ }
+ next = xmlSecGetNextElementNode(cur->next);
+ if(deleteCurNode) {
+ /* remove "template" nodes */
+ xmlUnlinkNode(cur);
+ xmlFreeNode(cur);
+ }
+ cur = next;
+ }
+ if(content == 0) {
+ /* by default we are writing certificates and crls */
+ content = XMLSEC_OPENSSL_X509_CERTIFICATE_NODE | XMLSEC_OPENSSL_X509_CRL_NODE;
}
+ /* get x509 data */
data = xmlSecKeyGetData(key, id);
if(data == NULL) {
/* no x509 data in the key */
@@ -714,79 +781,85 @@
return(-1);
}
- /* set base64 lines size from context */
- buf = xmlSecOpenSSLX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize);
- if(buf == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
- "xmlSecOpenSSLX509CertBase64DerWrite",
- XMLSEC_ERRORS_R_XMLSEC_FAILED,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
- }
-
- cur = xmlSecAddChild(node, xmlSecNodeX509Certificate, xmlSecDSigNs);
- if(cur == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
- "xmlSecAddChild",
- XMLSEC_ERRORS_R_XMLSEC_FAILED,
- "node=%s",
- xmlSecErrorsSafeString(xmlSecNodeX509Certificate));
- xmlFree(buf);
- return(-1);
+ if((content & XMLSEC_OPENSSL_X509_CERTIFICATE_NODE) != 0) {
+ ret = xmlSecOpenSSLX509CertificateNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLX509CertificateNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
}
- /* todo: add \n around base64 data - from context */
- /* todo: add errors check */
- xmlNodeSetContent(cur, xmlSecStringCR);
- xmlNodeSetContent(cur, buf);
- xmlFree(buf);
- }
- /* write crls */
- size = xmlSecOpenSSLKeyDataX509GetCrlsSize(data);
- for(pos = 0; pos < size; ++pos) {
- crl = xmlSecOpenSSLKeyDataX509GetCrl(data, pos);
- if(crl == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
- "xmlSecOpenSSLKeyDataX509GetCrl",
- XMLSEC_ERRORS_R_XMLSEC_FAILED,
- "pos=%d", pos);
- return(-1);
+ if((content & XMLSEC_OPENSSL_X509_SUBJECTNAME_NODE) != 0) {
+ ret = xmlSecOpenSSLX509SubjectNameNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLX509SubjectNameNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
}
-
- /* set base64 lines size from context */
- buf = xmlSecOpenSSLX509CrlBase64DerWrite(crl, keyInfoCtx->base64LineSize);
- if(buf == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
- "xmlSecOpenSSLX509CrlBase64DerWrite",
- XMLSEC_ERRORS_R_XMLSEC_FAILED,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+
+ if((content & XMLSEC_OPENSSL_X509_ISSUERSERIAL_NODE) != 0) {
+ ret = xmlSecOpenSSLX509IssuerSerialNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLX509IssuerSerialNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
}
-
- cur = xmlSecAddChild(node, xmlSecNodeX509CRL, xmlSecDSigNs);
- if(cur == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
- "xmlSecAddChild",
- XMLSEC_ERRORS_R_XMLSEC_FAILED,
- "new_node=%s",
- xmlSecErrorsSafeString(xmlSecNodeX509CRL));
- xmlFree(buf);
- return(-1);
+
+ if((content & XMLSEC_OPENSSL_X509_SKI_NODE) != 0) {
+ ret = xmlSecOpenSSLX509SKINodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLX509SKINodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
}
- /* todo: add \n around base64 data - from context */
- /* todo: add errors check */
- xmlNodeSetContent(cur, xmlSecStringCR);
- xmlNodeSetContent(cur, buf);
}
+
+ /* write crls if needed */
+ if((content & XMLSEC_OPENSSL_X509_CRL_NODE) != 0) {
+ size = xmlSecOpenSSLKeyDataX509GetCrlsSize(data);
+ for(pos = 0; pos < size; ++pos) {
+ crl = xmlSecOpenSSLKeyDataX509GetCrl(data, pos);
+ if(crl == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLKeyDataX509GetCrl",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+
+ ret = xmlSecOpenSSLX509CRLNodeWrite(crl, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecOpenSSLX509SKINodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+ }
+ }
return(0);
}
+
static xmlSecKeyDataType
xmlSecOpenSSLKeyDataX509GetType(xmlSecKeyDataPtr data) {
xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id),
xmlSecKeyDataTypeUnknown);
@@ -928,13 +1001,19 @@
xmlSecAssert2(keyInfoCtx != NULL, -1);
content = xmlNodeGetContent(node);
- if(content == NULL){
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
- xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
- XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+ if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) {
+ if(content != NULL) {
+ xmlFree(content);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
}
cert = xmlSecOpenSSLX509CertBase64DerRead(content);
@@ -964,6 +1043,46 @@
return(0);
}
+static int
+xmlSecOpenSSLX509CertificateNodeWrite(X509* cert, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar* buf;
+ xmlNodePtr cur;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ /* set base64 lines size from context */
+ buf = xmlSecOpenSSLX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLX509CertBase64DerWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, xmlSecNodeX509Certificate, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509Certificate));
+ xmlFree(buf);
+ return(-1);
+ }
+
+ /* todo: add \n around base64 data - from context */
+ /* todo: add errors check */
+ xmlNodeSetContent(cur, xmlSecStringCR);
+ xmlNodeSetContent(cur, buf);
+ xmlFree(buf);
+ return(0);
+}
+
static int
xmlSecOpenSSLX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlSecKeyDataStorePtr x509Store;
@@ -988,13 +1107,19 @@
}
subject = xmlNodeGetContent(node);
- if(subject == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
- xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
- XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+ if((subject == NULL) || (xmlSecIsEmptyString(subject) == 1)) {
+ if(subject != NULL) {
+ xmlFree(subject);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
}
cert = xmlSecOpenSSLX509StoreFindCert(x509Store, subject, NULL, NULL, NULL,
keyInfoCtx);
@@ -1040,6 +1165,40 @@
return(0);
}
+static int
+xmlSecOpenSSLX509SubjectNameNodeWrite(X509* cert, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlChar* buf = NULL;
+ xmlNodePtr cur = NULL;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ buf = xmlSecOpenSSLX509NameWrite(X509_get_subject_name(cert));
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLX509NameWrite(X509_get_subject_name)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, xmlSecNodeX509SubjectName, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SubjectName));
+ xmlFree(buf);
+ return(-1);
+ }
+ xmlNodeSetContent(cur, buf);
+ xmlFree(buf);
+ return(0);
+}
+
static int
xmlSecOpenSSLX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlSecKeyDataStorePtr x509Store;
@@ -1066,9 +1225,21 @@
}
cur = xmlSecGetNextElementNode(node->children);
-
+ if(cur == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName),
+ XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+ return(-1);
+ }
+ return(0);
+ }
+
/* the first is required node X509IssuerName */
- if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerName,
xmlSecDSigNs)) {
+ if(!xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs)) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
xmlSecErrorsSafeString(xmlSecNodeX509IssuerName),
@@ -1172,6 +1343,79 @@
return(0);
}
+static int
+xmlSecOpenSSLX509IssuerSerialNodeWrite(X509* cert, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlNodePtr cur;
+ xmlNodePtr issuerNameNode;
+ xmlNodePtr issuerNumberNode;
+ xmlChar* buf;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ /* create xml nodes */
+ cur = xmlSecAddChild(node, xmlSecNodeX509IssuerSerial, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial));
+ return(-1);
+ }
+
+ issuerNameNode = xmlSecAddChild(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs);
+ if(issuerNameNode == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName));
+ return(-1);
+ }
+
+ issuerNumberNode = xmlSecAddChild(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs);
+ if(issuerNumberNode == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber));
+ return(-1);
+ }
+
+ /* write data */
+ buf = xmlSecOpenSSLX509NameWrite(X509_get_issuer_name(cert));
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLX509NameWrite(X509_get_issuer_name)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ xmlNodeSetContent(issuerNameNode, buf);
+ xmlFree(buf);
+
+ buf = xmlSecOpenSSLASN1IntegerWrite(X509_get_serialNumber(cert));
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLASN1IntegerWrite(X509_get_serialNumber)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ xmlNodeSetContent(issuerNumberNode, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
+
static int
xmlSecOpenSSLX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlSecKeyDataStorePtr x509Store;
@@ -1196,14 +1440,20 @@
}
ski = xmlNodeGetContent(node);
- if(ski == NULL) {
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
- xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
- XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
- "node=%s",
- xmlSecErrorsSafeString(xmlSecNodeX509SKI));
- return(-1);
+ if((ski == NULL) || (xmlSecIsEmptyString(ski) == 1)) {
+ if(ski != NULL) {
+ xmlFree(ski);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SKI));
+ return(-1);
+ }
+ return(0);
}
cert = xmlSecOpenSSLX509StoreFindCert(x509Store, NULL, NULL, NULL, ski,
keyInfoCtx);
@@ -1249,6 +1499,41 @@
return(0);
}
+static int
+xmlSecOpenSSLX509SKINodeWrite(X509* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr
keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlChar *buf = NULL;
+ xmlNodePtr cur = NULL;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ buf = xmlSecOpenSSLX509SKIWrite(cert);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLX509SKIWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, xmlSecNodeX509SKI, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "new_node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SKI));
+ xmlFree(buf);
+ return(-1);
+ }
+ xmlNodeSetContent(cur, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
static int
xmlSecOpenSSLX509CRLNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlChar *content;
@@ -1260,13 +1545,19 @@
xmlSecAssert2(keyInfoCtx != NULL, -1);
content = xmlNodeGetContent(node);
- if(content == NULL){
- xmlSecError(XMLSEC_ERRORS_HERE,
- xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
- xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
- XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+ if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) {
+ if(content != NULL) {
+ xmlFree(content);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
}
crl = xmlSecOpenSSLX509CrlBase64DerRead(content);
@@ -1297,6 +1588,46 @@
}
static int
+xmlSecOpenSSLX509CRLNodeWrite(X509_CRL* crl, xmlNodePtr node, xmlSecKeyInfoCtxPtr
keyInfoCtx) {
+ xmlChar* buf = NULL;
+ xmlNodePtr cur = NULL;
+
+ xmlSecAssert2(crl != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ /* set base64 lines size from context */
+ buf = xmlSecOpenSSLX509CrlBase64DerWrite(crl, keyInfoCtx->base64LineSize);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLX509CrlBase64DerWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, xmlSecNodeX509CRL, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "new_node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509CRL));
+ xmlFree(buf);
+ return(-1);
+ }
+ /* todo: add \n around base64 data - from context */
+ /* todo: add errors check */
+ xmlNodeSetContent(cur, xmlSecStringCR);
+ xmlNodeSetContent(cur, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
+static int
xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, xmlSecKeyPtr key,
xmlSecKeyInfoCtxPtr keyInfoCtx) {
xmlSecOpenSSLX509DataCtxPtr ctx;
@@ -1776,6 +2107,160 @@
}
BIO_free_all(mem);
+ return(res);
+}
+
+static xmlChar*
+xmlSecOpenSSLX509NameWrite(X509_NAME* nm) {
+ xmlChar *res = NULL;
+ BIO *mem = NULL;
+ long size;
+
+ xmlSecAssert2(nm != NULL, NULL);
+
+ mem = BIO_new(BIO_s_mem());
+ if(mem == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "BIO_new",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "BIO_s_mem");
+ return(NULL);
+ }
+
+ if (X509_NAME_print_ex(mem, nm, 0, XN_FLAG_RFC2253) <=0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "X509_NAME_print_ex",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ BIO_free_all(mem);
+ return(NULL);
+ }
+
+ BIO_flush(mem); /* should call flush ? */
+
+ size = BIO_pending(mem);
+ res = xmlMalloc(size + 1);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "ASN1_INTEGER_to_BN",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ BIO_free_all(mem);
+ return(NULL);
+ }
+
+ size = BIO_read(mem, res, size);
+ res[size] = '\0';
+
+ BIO_free_all(mem);
+ return(res);
+}
+
+static xmlChar*
+xmlSecOpenSSLASN1IntegerWrite(ASN1_INTEGER *asni) {
+ xmlChar *res = NULL;
+ BIGNUM *bn;
+ char *p;
+
+ xmlSecAssert2(asni != NULL, NULL);
+
+ bn = ASN1_INTEGER_to_BN(asni, NULL);
+ if(bn == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "ASN1_INTEGER_to_BN",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ p = BN_bn2dec(bn);
+ if (p == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "BN_bn2dec",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ BN_free(bn);
+ return(NULL);
+ }
+ BN_free(bn);
+ bn = NULL;
+
+ /* OpenSSL and LibXML2 can have different memory callbacks, i.e.
+ when data is allocated in OpenSSL should be freed with OpenSSL
+ method, not with LibXML2 method.
+ */
+ res = xmlCharStrdup(p);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlCharStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ OPENSSL_free(p);
+ return(NULL);
+ }
+ OPENSSL_free(p);
+ p = NULL;
+ return(res);
+}
+
+static xmlChar*
+xmlSecOpenSSLX509SKIWrite(X509* cert) {
+ xmlChar *res = NULL;
+ int index;
+ X509_EXTENSION *ext;
+ ASN1_OCTET_STRING *keyId;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
+ if (index < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "Certificate without SubjectKeyIdentifier extension",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ ext = X509_get_ext(cert, index);
+ if (ext == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "X509_get_ext",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ keyId = X509V3_EXT_d2i(ext);
+ if (keyId == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "X509V3_EXT_d2i",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ M_ASN1_OCTET_STRING_free(keyId);
+ return(NULL);
+ }
+
+ res = xmlSecBase64Encode(M_ASN1_STRING_data(keyId), M_ASN1_STRING_length(keyId),
0);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Encode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ M_ASN1_OCTET_STRING_free(keyId);
+ return(NULL);
+ }
+ M_ASN1_OCTET_STRING_free(keyId);
+
return(res);
}
