hello all,

the attached patch --already committed-- caters for x.509 certificates with 
absent or null parameters in an AlgorithmIdentifier element (of a 
SubjectPublicKeyInfo).

all 100 Mauve tests in gnu.testlet.java.security.cert.pkix.pkits should now 
pass!

2006-08-05  Raif S. Naffah  <[EMAIL PROTECTED]>

        * gnu/java/security/key/dss/DSSKey.java: Updated documentation.
        (hasInheritedParameters): New method.
        (equals): Updated documentation.
        Take into consideration the outcome of hasInheritedParameters 
invocation.
        (toString): Call hasInheritedParameters and adjust the result 
accordingly.
        * gnu/java/security/key/dss/DSSKeyPairX509Codec.java (encodePublicKey):
        Updated documentation.
        Handle case of public keys with null p, q, and g MPIs.
        (decodePublicKey): Handle case of absent or NULL p, q and g MPIs.


cheers;
rsn
Index: DSSKeyPairX509Codec.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java,v
retrieving revision 1.4
diff -u -r1.4 DSSKeyPairX509Codec.java
--- DSSKeyPairX509Codec.java	20 Jun 2006 11:24:43 -0000	1.4
+++ DSSKeyPairX509Codec.java	5 Aug 2006 03:12:27 -0000
@@ -94,9 +94,15 @@
    *     g   INTEGER
    *   }
    * </pre>
-   *
-   * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
-   * DER-encoded form of the DSA public key as an INTEGER.</p>
+   * <p>
+   * Note that RFC-3280 (page 79) implies that some certificates MAY have an
+   * absent, or NULL, parameters field in their AlgorithmIdentifier element,
+   * implying that those parameters MUST be <i>inherited</i> from another
+   * certificate. This implementation, encodes a <i>NULL</i> element as the DER
+   * value of the parameters field when such is the case.
+   * <p>
+   * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the DSA public key as an INTEGER.
    *
    * <pre>
    *       DSAPublicKey ::= INTEGER -- public key, Y
@@ -118,20 +124,25 @@
     DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);

     DSSPublicKey dssKey = (DSSPublicKey) key;
-    BigInteger p = dssKey.getParams().getP();
-    BigInteger q = dssKey.getParams().getQ();
-    BigInteger g = dssKey.getParams().getG();
-    BigInteger y = dssKey.getY();
-
-    DERValue derP = new DERValue(DER.INTEGER, p);
-    DERValue derQ = new DERValue(DER.INTEGER, q);
-    DERValue derG = new DERValue(DER.INTEGER, g);
-
-    ArrayList params = new ArrayList(3);
-    params.add(derP);
-    params.add(derQ);
-    params.add(derG);
-    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+    DERValue derParams;
+    if (dssKey.hasInheritedParameters())
+      derParams = new DERValue(DER.NULL, null);
+    else
+      {
+        BigInteger p = dssKey.getParams().getP();
+        BigInteger q = dssKey.getParams().getQ();
+        BigInteger g = dssKey.getParams().getG();
+
+        DERValue derP = new DERValue(DER.INTEGER, p);
+        DERValue derQ = new DERValue(DER.INTEGER, q);
+        DERValue derG = new DERValue(DER.INTEGER, g);
+
+        ArrayList params = new ArrayList(3);
+        params.add(derP);
+        params.add(derQ);
+        params.add(derG);
+        derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+      }

     ArrayList algorithmID = new ArrayList(2);
     algorithmID.add(derOID);
@@ -139,6 +150,7 @@
     DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
                                            algorithmID);

+    BigInteger y = dssKey.getY();
     DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y);
     byte[] yBytes = derDSAPublicKey.getEncoded();
     DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
@@ -185,7 +197,10 @@
     if (input == null)
       throw new InvalidParameterException("Input bytes MUST NOT be null");

-    BigInteger p, g, q, y;
+    BigInteger p = null;
+    BigInteger g = null;
+    BigInteger q = null;
+    BigInteger y;
     DERReader der = new DERReader(input);
     try
       {
@@ -203,20 +218,35 @@
         if (! algOID.equals(DSA_ALG_OID))
           throw new InvalidParameterException("Unexpected OID: " + algOID);

-        DERValue derParams = der.read();
-        DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
-
         DERValue val = der.read();
-        DerUtil.checkIsBigInteger(val, "Wrong P field");
-        p = (BigInteger) val.getValue();
-        val = der.read();
-        DerUtil.checkIsBigInteger(val, "Wrong Q field");
-        q = (BigInteger) val.getValue();
-        val = der.read();
-        DerUtil.checkIsBigInteger(val, "Wrong G field");
-        g = (BigInteger) val.getValue();
+        // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the
+        // certificate contains an algorithm field with null parameters or
+        // parameters are omitted, compare the certificate subjectPublicKey
+        // algorithm to the working_public_key_algorithm.  If the certificate
+        // subjectPublicKey algorithm and the working_public_key_algorithm are
+        // different, set the working_public_key_parameters to null."
+        // in other words, the parameters field of an AlgorithmIdentifier
+        // element MAY NOT be present at all, or if present MAY be NULL!
+        // the Mauve test ValidDSAParameterInheritenceTest5, in
+        // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because
+        // of this.
+        if (val.getTag() == DER.NULL)
+          val = der.read();
+        else if (val.isConstructed())
+          {
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong P field");
+            p = (BigInteger) val.getValue();
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong Q field");
+            q = (BigInteger) val.getValue();
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong G field");
+            g = (BigInteger) val.getValue();
+
+            val = der.read();
+          }

-        val = der.read();
         if (! (val.getValue() instanceof BitString))
           throw new InvalidParameterException("Wrong SubjectPublicKey field");

Index: DSSKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/dss/DSSKey.java,v
retrieving revision 1.9
diff -u -r1.9 DSSKey.java
--- DSSKey.java	11 Jul 2006 16:04:00 -0000	1.9
+++ DSSKey.java	5 Aug 2006 03:17:10 -0000
@@ -60,6 +60,10 @@
  * of the byte sequences and the implementation details are given in each of the
  * relevant <code>getEncoded()</code> methods of each of the private and
  * public keys.
+ * <p>
+ * <b>IMPORTANT</b>: Under certain circumstances (e.g. in an X.509 certificate
+ * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo
+ * element) these three MPIs may be <code>null</code>.
  *
  * @see DSSPrivateKey#getEncoded
  * @see DSSPublicKey#getEncoded
@@ -145,6 +149,11 @@
    * Returns <code>true</code> if the designated object is an instance of
    * [EMAIL PROTECTED] DSAKey} and has the same DSS (Digital Signature Standard) parameter
    * values as this one.
+   * <p>
+   * Always returns <code>false</code> if the MPIs of this key are
+   * <i>inherited</i>. This may be the case when the key is re-constructed from
+   * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters
+   * field.
    *
    * @param obj the other non-null DSS key to compare to.
    * @return <code>true</code> if the designated object is of the same type
@@ -152,6 +161,9 @@
    */
   public boolean equals(Object obj)
   {
+    if (hasInheritedParameters())
+      return false;
+
     if (obj == null)
       return false;

@@ -168,17 +180,32 @@
   {
     if (str == null)
       {
-        String ls = (String) AccessController.doPrivileged
-            (new GetPropertyAction("line.separator"));
-        str = new StringBuilder(ls)
-            .append("defaultFormat=").append(defaultFormat).append(",").append(ls)
-            .append("p=0x").append(p.toString(16)).append(",").append(ls)
-            .append("q=0x").append(q.toString(16)).append(",").append(ls)
-            .append("g=0x").append(g.toString(16))
-            .toString();
+        String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator"));
+        StringBuilder sb = new StringBuilder(ls)
+            .append("defaultFormat=").append(defaultFormat).append(",")
+            .append(ls);
+        if (hasInheritedParameters())
+          sb.append("p=inherited,").append(ls)
+              .append("q=inherited,").append(ls)
+              .append("g=inherited");
+        else
+          sb.append("p=0x").append(p.toString(16)).append(",").append(ls)
+              .append("q=0x").append(q.toString(16)).append(",").append(ls)
+              .append("g=0x").append(g.toString(16));
+        str = sb.toString();
       }
     return str;
   }

   public abstract byte[] getEncoded(int format);
+
+  /**
+   * @return <code>true</code> if <code>p</code>, <code>q</code> and
+   *         <code>g</code> are all <code>null</code>. Returns
+   *         <code>false</code> otherwise.
+   */
+  public boolean hasInheritedParameters()
+  {
+    return p == null && q == null && g == null;
+  }
 }

Reply via email to