<!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">
Hi, Aleksey,<br>
<br>
We just tried your patch, it is good for both positive sn and negative
sn.<br>
<br>
Anyway, we still made 2 little improvements on your patch.<br>
<br>
1)&nbsp; remove the assertion in xmlSecBnAdd<br>
<br>
<tt>int <br>
xmlSecBnAdd(xmlSecBnPtr bn, int delta) {<br>
...<br>
&nbsp;&nbsp;&nbsp; xmlSecAssert2(bn != NULL, -1);<br>
<b>&nbsp;&nbsp;&nbsp; //xmlSecAssert2(delta &gt;= 0, -1);</b><br>
<br>
&nbsp;&nbsp;&nbsp; if(delta == 0) {<br>
...<br>
</tt><br>
2) add some code to support serial number = 0<br>
<br>
<tt>int <br>
xmlSecBnFromString(xmlSecBnPtr bn, const xmlChar* str, xmlSecSize base)
{<br>
...<br>
&nbsp;&nbsp;&nbsp; /* check if we need to add 00 prefix */<br>
&nbsp;&nbsp;&nbsp; data = xmlSecBufferGetData(bn);<br>
&nbsp;&nbsp;&nbsp; size = xmlSecBufferGetSize(bn);<br>
<br>
<b>&nbsp;&nbsp;&nbsp; /* when the string is "00", we need to avoid a zero-length bn to
be returned */</b><br>
&nbsp;&nbsp;&nbsp; if((size &gt; 0 &amp;&amp; data[0] &gt; 127)<b>||(size==0)</b>) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = xmlSecBufferPrepend(bn, &amp;ch, 1);<br>
...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
...<br>
<br>
}<br>
<br>
<br>
Thanks for your great help!<br>
<br>
Michael<br>
</tt><br>
<br>
Aleksey Sanin wrote:<br>
<blockquote type="cite" cite="mid421AB4ED.7080205@aleksey.com">I think
I have a patch that should fix the problem with negative
  <br>
serial numbers (see attached). I would appreciate if you can try
  <br>
it to make sure that it works for you.
  <br>
  <br>
Also if you have an example with certificate having negative
  <br>
serial number, I would appreciate if you can share it so I
  <br>
can create a test case. I failed to get a negative serial
  <br>
number from openssl :)
  <br>
  <br>
Thanks,
  <br>
Aleksey
  <br>
  <pre wrap="">
<hr width="90%" size="4">
Index: src/bn.c
===================================================================
RCS file: /cvs/gnome/xmlsec/src/bn.c,v
retrieving revision 1.14
diff -u -w -r1.14 bn.c
--- src/bn.c        26 Jan 2005 16:52:09 -0000        1.14
+++ src/bn.c        22 Feb 2005 04:12:38 -0000
@@ -170,9 +170,10 @@
  */
 int 
 xmlSecBnFromString(xmlSecBnPtr bn, const xmlChar* str, xmlSecSize base) {
-    xmlSecSize i, len;
+    xmlSecSize i, len, size;
     xmlSecByte ch;
     xmlSecByte* data;
+    int positive;
     int nn;
     int ret;
 
@@ -192,7 +193,7 @@
      * In truth, it would be likely less than 1/2 input string length
      * because each byte is represented by 2 chars. If needed, 
      * buffer size would be increased by Mul/Add functions.
-     * Finally, we add one byte for 00 prefix if first byte is &gt; 127.
+     * Finally, we can add one byte for 00 or 10 prefix.
      */
     ret = xmlSecBufferSetMaxSize(bn, xmlSecBufferGetSize(bn) + len / 2 + 1 + 1);
     if(ret &lt; 0) {
@@ -204,8 +205,49 @@
         return (-1);
     }
 
-    for(i = 0; i &lt; len; i++) {
-        ch = str[i];
+    /* figure out if it is positive or negative number */
+    positive = 1;
+    i = 0;
+    while(i &lt; len) {
+        ch = str[i++];
+
+        /* skip spaces */
+        if(isspace(ch)) {
+                continue;
+        } 
+        
+        /* check if it is + or - */
+        if(ch == '+') {
+            positive = 1;
+            break;
+        } else if(ch == '-') {
+            positive = 0;
+            break;
+        }
+
+        /* otherwise, it must be start of the number */
+        nn = xmlSecBnLookupTable[ch];
+        if((nn &gt;= 0) &amp;&amp; ((xmlSecSize)nn &lt; base)) {
+            xmlSecAssert2(i &gt; 0, -1);
+
+            /* no sign, positive by default */
+            positive = 1;
+            --i; /* make sure that we will look at this character in next loop */
+            break;
+        } else {
+                xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        NULL,
+                        XMLSEC_ERRORS_R_INVALID_DATA,
+                        "char=%c;base=%d", 
+                        ch, base);
+                    return (-1);
+        }
+    }
+
+    /* now parse the number itself */
+    while(i &lt; len) {
+        ch = str[i++];
         if(isspace(ch)) {
             continue;
         }
@@ -243,9 +285,10 @@
         }        
     }
 
-    /* check whether need to add 00 prefix */
+    /* check if we need to add 00 prefix */
     data = xmlSecBufferGetData(bn);
-    if(data[0] &gt; 127) {
+    size = xmlSecBufferGetSize(bn);
+    if(size &gt; 0 &amp;&amp; data[0] &gt; 127) {
         ch = 0;
         ret = xmlSecBufferPrepend(bn, &amp;ch, 1);
         if(ret &lt; 0) {
@@ -257,6 +300,26 @@
             return (-1);
         }
     }
+
+    /* do 2's compliment and add 1 to represent negative value */
+    if(positive == 0) {
+        data = xmlSecBufferGetData(bn);
+        size = xmlSecBufferGetSize(bn);
+        for(i = 0; i &lt; size; ++i) {
+            data[i] ^= 0xFF;
+        }
+        
+        ret = xmlSecBnAdd(bn, 1);
+        if(ret &lt; 0) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                NULL,
+                "xmlSecBnAdd",
+                XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                "base=%d", base);
+            return (-1);
+        }
+    }
+
     return(0);
 }
 
@@ -272,8 +335,12 @@
  */
 xmlChar* 
 xmlSecBnToString(xmlSecBnPtr bn, xmlSecSize base) {
+    xmlSecBn bn2;
+    int positive = 1;
     xmlChar* res;
-    xmlSecSize i, len;
+    xmlSecSize i, len, size;
+    xmlSecByte* data;
+    int ret;
     int nn;
     xmlChar ch;
 
@@ -281,12 +348,61 @@
     xmlSecAssert2(base &gt; 1, NULL);
     xmlSecAssert2(base &lt;= sizeof(xmlSecBnRevLookupTable), NULL);
 
+
+    /* copy bn */
+    data = xmlSecBufferGetData(bn);
+    size = xmlSecBufferGetSize(bn);
+    ret = xmlSecBnInitialize(&amp;bn2, size);
+    if(ret &lt; 0) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+            NULL,
+            "xmlSecBnCreate",
+            XMLSEC_ERRORS_R_XMLSEC_FAILED,
+            "size=%d", size);
+        return (NULL);
+    }
+    
+    ret = xmlSecBnSetData(&amp;bn2, data, size);
+    if(ret &lt; 0) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+            NULL,
+            "xmlSecBnSetData",
+            XMLSEC_ERRORS_R_XMLSEC_FAILED,
+            "size=%d", size);
+        xmlSecBnFinalize(&amp;bn2);
+        return (NULL);
+    }
+
+    /* check if it is a negative number or not */
+    data = xmlSecBufferGetData(&amp;bn2);
+    size = xmlSecBufferGetSize(&amp;bn2);
+    if((size &gt; 0) &amp;&amp; (data[0] &gt; 127)) {
+        /* subtract 1 and do 2's compliment */
+        ret = xmlSecBnAdd(&amp;bn2, -1);
+        if(ret &lt; 0) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        "xmlSecBnAdd",
+                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                        "size=%d", size);
+            xmlSecBnFinalize(&amp;bn2);
+            return (NULL);
+        }
+        for(i = 0; i &lt; size; ++i) {
+            data[i] ^= 0xFF;
+        }
+
+        positive = 0;
+    } else {
+        positive = 1;
+    }
+
     /* Result string len is
      *            len = log base (256) * &lt;bn size&gt;
      * Since the smallest base == 2 then we can get away with 
      *            len = 8 * &lt;bn size&gt;
      */
-    len = 8 * xmlSecBufferGetSize(bn) + 1;
+    len = 8 * size + 1 + 1;
     res = (xmlChar*)xmlMalloc(len + 1);
     if(res == NULL) {
         xmlSecError(XMLSEC_ERRORS_HERE,
@@ -294,18 +410,20 @@
                     NULL,
                     XMLSEC_ERRORS_R_MALLOC_FAILED,
                     "len=%d", len);
+        xmlSecBnFinalize(&amp;bn2);
         return (NULL);
     }
     memset(res, 0, len + 1);
 
-    for(i = 0; (xmlSecBufferGetSize(bn) &gt; 0) &amp;&amp; (i &lt; len); i++) {
-        if(xmlSecBnDiv(bn, base, &amp;nn) &lt; 0) {
+    for(i = 0; (xmlSecBufferGetSize(&amp;bn2) &gt; 0) &amp;&amp; (i &lt; len); i++) {
+        if(xmlSecBnDiv(&amp;bn2, base, &amp;nn) &lt; 0) {
             xmlSecError(XMLSEC_ERRORS_HERE,
                         NULL,
                         "xmlSecBnDiv",
                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
                         "base=%d", base);
             xmlFree(res);
+            xmlSecBnFinalize(&amp;bn2);
                 return (NULL);
         }
         xmlSecAssert2((size_t)nn &lt; sizeof(xmlSecBnRevLookupTable), NULL);
@@ -317,6 +435,12 @@
     for(len = i; (len &gt; 1) &amp;&amp; (res[len - 1] == '0'); len--);
     res[len] = '\0';
 
+    /* add "-" for negative numbers */
+    if(positive == 0) {
+        res[len] = '-';
+        res[++len] = '\0';
+    }
+
     /* swap the string because we wrote it in reverse order */
     for(i = 0; i &lt; len / 2; i++) {
         ch = res[i];
@@ -324,6 +448,7 @@
         res[len - i - 1] = ch;
     }
 
+    xmlSecBnFinalize(&amp;bn2);
     return(res);
 }
 
@@ -408,7 +533,9 @@
     }
 
     data = xmlSecBufferGetData(bn);
-    for(over = 0, i = xmlSecBufferGetSize(bn); i &gt; 0;) {
+    i = xmlSecBufferGetSize(bn);
+    over = 0; 
+    while(i &gt; 0) {
         xmlSecAssert2(data != NULL, -1);
 
         over        = over + multiplier * data[--i];
Index: src/mscrypto/x509vfy.c
===================================================================
RCS file: /cvs/gnome/xmlsec/src/mscrypto/x509vfy.c,v
retrieving revision 1.3
diff -u -w -r1.3 x509vfy.c
--- src/mscrypto/x509vfy.c        27 Sep 2003 03:12:22 -0000        1.3
+++ src/mscrypto/x509vfy.c        22 Feb 2005 04:12:40 -0000
@@ -568,9 +568,28 @@
     if((pCert == NULL) &amp;&amp; (NULL != issuerName) &amp;&amp; (NULL != issuerSerial)) {
         xmlSecBn issuerSerialBn;        
         CERT_NAME_BLOB cnb;
+    CRYPT_INTEGER_BLOB cib;
         BYTE *cName = NULL; 
         DWORD cNameLen = 0;        
 
+
+    /* get issuer name */
+        cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                                           issuerName,
+                                           CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
+                                           &amp;cNameLen);
+        if(cName == NULL) {
+            xmlSecError(XMLSEC_ERRORS_HERE,
+                        NULL,
+                        "xmlSecMSCryptoCertStrToName",
+                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+                        XMLSEC_ERRORS_NO_MESSAGE);
+            return (NULL);
+        }
+        cnb.pbData = cName;
+        cnb.cbData = cNameLen;
+
+    /* get serial number */
         ret = xmlSecBnInitialize(&amp;issuerSerialBn, 0);
         if(ret &lt; 0) {
             xmlSecError(XMLSEC_ERRORS_HERE,
@@ -578,6 +597,7 @@
                         "xmlSecBnInitialize",
                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
                         XMLSEC_ERRORS_NO_MESSAGE);
+            xmlFree(cName);
             return(NULL);
         }
 
@@ -589,25 +609,29 @@
                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
                         XMLSEC_ERRORS_NO_MESSAGE);
             xmlSecBnFinalize(&amp;issuerSerialBn);
+                xmlFree(cName);
             return(NULL);
         }
 
-        cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
-                                           issuerName,
-                                           CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
-                                           &amp;cNameLen);
-        if(cName == NULL) {
+        /* I have no clue why at a sudden a swap is needed to 
+     * convert from lsb... This code is purely based upon 
+         * trial and error :( WK
+         */
+    ret = xmlSecBnReverse(&amp;issuerSerialBn);
+        if(ret &lt; 0) {
             xmlSecError(XMLSEC_ERRORS_HERE,
                         NULL,
-                        "xmlSecMSCryptoCertStrToName",
+                        "xmlSecBnReverse",
                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
                         XMLSEC_ERRORS_NO_MESSAGE);
             xmlSecBnFinalize(&amp;issuerSerialBn);
+                xmlFree(cName);
             return (NULL);
         }
 
-        cnb.pbData = cName;
-        cnb.cbData = cNameLen;
+    cib.pbData = xmlSecBufferGetData(&amp;issuerSerialBn);
+    cib.cbData = xmlSecBufferGetSize(&amp;issuerSerialBn);
+
         while((pCert = CertFindCertificateInStore(store, 
                                                   PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                                   0,
@@ -622,9 +646,8 @@
             if((pCert-&gt;pCertInfo != NULL) &amp;&amp; 
                (pCert-&gt;pCertInfo-&gt;SerialNumber.pbData != NULL) &amp;&amp; 
                (pCert-&gt;pCertInfo-&gt;SerialNumber.cbData &gt; 0) &amp;&amp; 
-               (0 == xmlSecBnCompareReverse(&amp;issuerSerialBn, pCert-&gt;pCertInfo-&gt;SerialNumber.pbData, 
-                                     pCert-&gt;pCertInfo-&gt;SerialNumber.cbData))) {
-                
+           (CertCompareIntegerBlob(&amp;(pCert-&gt;pCertInfo-&gt;SerialNumber), &amp;cib) == TRUE)
+           ) {                
                 break;
             }
         }
  </pre>
  <pre wrap="">
<hr width="90%" size="4">
_______________________________________________
xmlsec mailing list
<a class="moz-txt-link-abbreviated" href="mailto:xmlsec@aleksey.com">xmlsec@aleksey.com</a>
<a class="moz-txt-link-freetext" href="http://www.aleksey.com/mailman/listinfo/xmlsec">http://www.aleksey.com/mailman/listinfo/xmlsec</a>
  </pre>
</blockquote>
</body>
</html>