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