Roumen Petrov wrote:
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.



======================================================
Miscellaneous:

In a method we can put part of code in "figure brackets" to make source more readable.
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);
 }
 

Reply via email to