[xmlsec] Re: core methods for write of <X509SubjectName/> and <X509IssuerSerial/>

Aleksey Sanin aleksey@aleksey.com
Mon, 28 Jul 2003 17:39:04 -0700


This is a multi-part message in MIME format.
--------------030809080703000507090303
Content-Type: multipart/alternative;
 boundary="------------010109080105070607050303"


--------------010109080105070607050303
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

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





--------------010109080105070607050303
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1">
  <title></title>
</head>
<body text="#000000" bgcolor="#ffffff">
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1">
<title></title>
Roumen Petrov wrote:<br>
<blockquote type="cite" cite="mid3F253598.9010705@roumenpetrov.info">please
find attached file x509-sn_is__.patch.gz with latest changes. <br>
</blockquote>
Well, this patch still has some problems:<br>
&nbsp;&nbsp;&nbsp; 0) The "writer" approach you use is less flexible than "flags"
approach<br>
&nbsp;&nbsp;&nbsp; I have suggested. For example, it does not allow you to write *both*<br>
&nbsp;&nbsp;&nbsp; subject name and issuer serial nodes which might be required.<br>
&nbsp;&nbsp;&nbsp; 1) The patch erases the content of the X509Data node when it writes<br>
&nbsp;&nbsp;&nbsp; data out. This seems wrong to me. For example, application might
want <br>
&nbsp;&nbsp;&nbsp; to put a pointer common cert (say, with X509SubjectName) and write
key <br>
&nbsp;&nbsp;&nbsp; specific certs in X509Certificate. The only way to do it is to
write X509SubjectName<br>
&nbsp;&nbsp;&nbsp; node manually and put a placeholder for X509Certificate in the
template:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;X509Data&gt;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &lt;X509SubjectName&gt;some
subject&lt;/X509SubjectName&gt;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;X509Certificate/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/X509Data&gt;<br>
&nbsp;&nbsp;&nbsp; I think it's a good idea to keep this ability to "add" data to
X509Data node as <br>
&nbsp;&nbsp;&nbsp; we do now.<br>
&nbsp;&nbsp;&nbsp; 2) You changed the code to skip "empty" nodes. In most cases it can
cause no<br>
&nbsp;&nbsp;&nbsp; harm but some applications may decide that it's not acceptable. I
think a flag<br>
&nbsp;&nbsp;&nbsp; in xmlSecKeyInfoCtx should solve this issue.&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 3) There were few memory leaks in the *Read functions with the same
pattern: <br>
&nbsp;&nbsp;&nbsp; get node content, check that it's empty, return 0 w/o freeing
content.<br>
&nbsp;&nbsp;&nbsp; 4) After fixing the code I realized that the new xmlSecKeyInfoCtx
flag <br>
&nbsp;&nbsp;&nbsp; XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_WRITE_CRLS you have added<br>
&nbsp;&nbsp;&nbsp; is not necessary. If application does not want to write CRLs then
it just uses <br>
&nbsp;&nbsp;&nbsp; following template:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;X509Data&gt;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;X509Certificate/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/X509Data&gt;<br>
<br>
Anyway, I have fixed all the issues above (see attached patch). It is
checked in CVS<br>
along with a new test case to make sure it actually works. I hope that
Tej would be able<br>
to do similar thing in xmlsec-nss.<br>
<br>
Roumen, I would appreciate if you can try this new code and check that
after my changes<br>
it is still doing what you need.<br>
<br>
<br>
<blockquote type="cite" cite="mid3F253598.9010705@roumenpetrov.info"><br>
====================================================== <br>
Miscellaneous: <br>
  <br>
In a method we can put part of code in "figure brackets" to make source
more readable. <br>
</blockquote>
Well, your points are valid. The only thing I have to object is that
there are already <br>
a lot of code in xmlsec written w/o using this trick. It makes very
difficult (for me at least)<br>
to switch from one code style to another inside the same source file. I
am trying to preserve<br>
the exisiting code style. It makes much more easier to read the code
when&nbsp; everything<br>
is written in one style. Even if this style is not the best one :)<br>
<br>
<br>
Aleksey<br>
<br>
<br>
<br>
<br>
</body>
</html>

--------------010109080105070607050303--

--------------030809080703000507090303
Content-Type: text/plain;
 name="x509data.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="x509data.diff"

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);
 }
 


--------------030809080703000507090303--