< prev index next >

src/java.base/share/classes/sun/security/rsa/PSSParameters.java

Print this page
rev 51972 : 8215694: keytool cannot generate RSASSA-PSS certificates
Reviewed-by: xuelei

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -50,17 +50,11 @@
  *
  */
 
 public final class PSSParameters extends AlgorithmParametersSpi {
 
-    private String mdName;
-    private MGF1ParameterSpec mgfSpec;
-    private int saltLength;
-    private int trailerField;
-
-    private static final ObjectIdentifier OID_MGF1 =
-           ObjectIdentifier.newInternal(new int[] {1,2,840,113549,1,1,8});
+    private PSSParameterSpec spec;
 
     public PSSParameters() {
     }
 
     @Override

@@ -69,95 +63,97 @@
         if (!(paramSpec instanceof PSSParameterSpec)) {
             throw new InvalidParameterSpecException
                 ("Inappropriate parameter specification");
         }
         PSSParameterSpec spec = (PSSParameterSpec) paramSpec;
-        this.mdName = spec.getDigestAlgorithm();
+
         String mgfName = spec.getMGFAlgorithm();
-        if (!mgfName.equalsIgnoreCase("MGF1")) {
+        if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1")) {
             throw new InvalidParameterSpecException("Unsupported mgf " +
                 mgfName + "; MGF1 only");
         }
         AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
         if (!(mgfSpec instanceof MGF1ParameterSpec)) {
             throw new InvalidParameterSpecException("Inappropriate mgf " +
                 "parameters; non-null MGF1ParameterSpec only");
         }
-        this.mgfSpec = (MGF1ParameterSpec) mgfSpec;
-        this.saltLength = spec.getSaltLength();
-        this.trailerField = spec.getTrailerField();
+        this.spec = spec;
     }
 
     @Override
     protected void engineInit(byte[] encoded) throws IOException {
         // first initialize with the DEFAULT values before
         // retrieving from the encoding bytes
-        this.mdName = DEFAULT.getDigestAlgorithm();
-        this.mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
-        this.saltLength = DEFAULT.getSaltLength();
-        this.trailerField = DEFAULT.getTrailerField();
+        String mdName = DEFAULT.getDigestAlgorithm();
+        MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
+        int saltLength = DEFAULT.getSaltLength();
+        int trailerField = DEFAULT.getTrailerField();
 
         DerInputStream der = new DerInputStream(encoded);
         DerValue[] datum = der.getSequence(4);
+
         for (DerValue d : datum) {
             if (d.isContextSpecific((byte) 0x00)) {
                 // hash algid
-                this.mdName = AlgorithmId.parse
+                mdName = AlgorithmId.parse
                     (d.data.getDerValue()).getName();
             } else if (d.isContextSpecific((byte) 0x01)) {
                 // mgf algid
                 AlgorithmId val = AlgorithmId.parse(d.data.getDerValue());
-                if (!val.getOID().equals(OID_MGF1)) {
+                if (!val.getOID().equals(AlgorithmId.mgf1_oid)) {
                     throw new IOException("Only MGF1 mgf is supported");
                 }
                 AlgorithmId params = AlgorithmId.parse(
                     new DerValue(val.getEncodedParams()));
                 String mgfDigestName = params.getName();
                 switch (mgfDigestName) {
                 case "SHA-1":
-                    this.mgfSpec = MGF1ParameterSpec.SHA1;
+                    mgfSpec = MGF1ParameterSpec.SHA1;
                     break;
                 case "SHA-224":
-                    this.mgfSpec = MGF1ParameterSpec.SHA224;
+                    mgfSpec = MGF1ParameterSpec.SHA224;
                     break;
                 case "SHA-256":
-                    this.mgfSpec = MGF1ParameterSpec.SHA256;
+                    mgfSpec = MGF1ParameterSpec.SHA256;
                     break;
                 case "SHA-384":
-                    this.mgfSpec = MGF1ParameterSpec.SHA384;
+                    mgfSpec = MGF1ParameterSpec.SHA384;
                     break;
                 case "SHA-512":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512;
+                    mgfSpec = MGF1ParameterSpec.SHA512;
                     break;
                 case "SHA-512/224":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512_224;
+                    mgfSpec = MGF1ParameterSpec.SHA512_224;
                     break;
                 case "SHA-512/256":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512_256;
+                    mgfSpec = MGF1ParameterSpec.SHA512_256;
                     break;
                 default:
                     throw new IOException
                         ("Unrecognized message digest algorithm " +
                         mgfDigestName);
                 }
             } else if (d.isContextSpecific((byte) 0x02)) {
                 // salt length
-                this.saltLength = d.data.getDerValue().getInteger();
-                if (this.saltLength < 0) {
+                saltLength = d.data.getDerValue().getInteger();
+                if (saltLength < 0) {
                     throw new IOException("Negative value for saltLength");
                 }
             } else if (d.isContextSpecific((byte) 0x03)) {
                 // trailer field
-                this.trailerField = d.data.getDerValue().getInteger();
-                if (this.trailerField != 1) {
+                trailerField = d.data.getDerValue().getInteger();
+                if (trailerField != 1) {
                     throw new IOException("Unsupported trailerField value " +
-                    this.trailerField);
+                    trailerField);
                 }
             } else {
                 throw new IOException("Invalid encoded PSSParameters");
             }
         }
+
+        this.spec = new PSSParameterSpec(mdName, "MGF1", mgfSpec,
+                saltLength, trailerField);
     }
 
     @Override
     protected void engineInit(byte[] encoded, String decodingMethod)
             throws IOException {

@@ -171,85 +167,108 @@
     @Override
     protected <T extends AlgorithmParameterSpec>
             T engineGetParameterSpec(Class<T> paramSpec)
             throws InvalidParameterSpecException {
         if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) {
-            return paramSpec.cast(
-                new PSSParameterSpec(mdName, "MGF1", mgfSpec,
-                                     saltLength, trailerField));
+            return paramSpec.cast(spec);
         } else {
             throw new InvalidParameterSpecException
                 ("Inappropriate parameter specification");
         }
     }
 
     @Override
     protected byte[] engineGetEncoded() throws IOException {
+        return getEncoded(spec);
+    }
+
+    @Override
+    protected byte[] engineGetEncoded(String encMethod) throws IOException {
+        if ((encMethod != null) &&
+            (!encMethod.equalsIgnoreCase("ASN.1"))) {
+            throw new IllegalArgumentException("Only support ASN.1 format");
+        }
+        return engineGetEncoded();
+    }
+
+    @Override
+    protected String engineToString() {
+        return spec.toString();
+    }
+
+    /**
+     * Returns the encoding of a {@link PSSParameterSpec} object. This method
+     * is used in this class and {@link AlgorithmId}.
+     *
+     * @param spec a {@code PSSParameterSpec} object
+     * @return its DER encoding
+     * @throws IOException if the name of a MessageDigest or MaskGenAlgorithm
+     *          is unsupported
+     */
+    public static byte[] getEncoded(PSSParameterSpec spec) throws IOException {
+
+        AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
+        if (!(mgfSpec instanceof MGF1ParameterSpec)) {
+            throw new IOException("Cannot encode " + mgfSpec);
+        }
+
+        MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec)mgfSpec;
+
         DerOutputStream tmp = new DerOutputStream();
         DerOutputStream tmp2, tmp3;
 
         // MD
         AlgorithmId mdAlgId;
         try {
-            mdAlgId = AlgorithmId.get(mdName);
+            mdAlgId = AlgorithmId.get(spec.getDigestAlgorithm());
         } catch (NoSuchAlgorithmException nsae) {
-            throw new IOException("AlgorithmId " + mdName +
-                                  " impl not found");
+            throw new IOException("AlgorithmId " + spec.getDigestAlgorithm() +
+                    " impl not found");
+        }
+        if (!mdAlgId.getOID().equals(AlgorithmId.SHA_oid)) {
+            tmp2 = new DerOutputStream();
+            mdAlgId.derEncode(tmp2);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
+                    tmp2);
         }
-        tmp2 = new DerOutputStream();
-        mdAlgId.derEncode(tmp2);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0),
-                      tmp2);
 
         // MGF
-        tmp2 = new DerOutputStream();
-        tmp2.putOID(OID_MGF1);
         AlgorithmId mgfDigestId;
         try {
-            mgfDigestId = AlgorithmId.get(mgfSpec.getDigestAlgorithm());
+            mgfDigestId = AlgorithmId.get(mgf1Spec.getDigestAlgorithm());
         } catch (NoSuchAlgorithmException nase) {
             throw new IOException("AlgorithmId " +
-                    mgfSpec.getDigestAlgorithm() + " impl not found");
+                    mgf1Spec.getDigestAlgorithm() + " impl not found");
+        }
+
+        if (!mgfDigestId.getOID().equals(AlgorithmId.SHA_oid)) {
+            tmp2 = new DerOutputStream();
+            tmp2.putOID(AlgorithmId.mgf1_oid);
+            mgfDigestId.encode(tmp2);
+            tmp3 = new DerOutputStream();
+            tmp3.write(DerValue.tag_Sequence, tmp2);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1),
+                    tmp3);
         }
-        mgfDigestId.encode(tmp2);
-        tmp3 = new DerOutputStream();
-        tmp3.write(DerValue.tag_Sequence, tmp2);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)1),
-                  tmp3);
 
         // SaltLength
-        tmp2 = new DerOutputStream();
-        tmp2.putInteger(saltLength);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)2),
-                  tmp2);
+        if (spec.getSaltLength() != 20) {
+            tmp2 = new DerOutputStream();
+            tmp2.putInteger(spec.getSaltLength());
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2),
+                    tmp2);
+        }
 
         // TrailerField
-        tmp2 = new DerOutputStream();
-        tmp2.putInteger(trailerField);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3),
-                  tmp2);
+        if (spec.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
+            tmp2 = new DerOutputStream();
+            tmp2.putInteger(spec.getTrailerField());
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3),
+                    tmp2);
+        }
 
         // Put all together under a SEQUENCE tag
         DerOutputStream out = new DerOutputStream();
         out.write(DerValue.tag_Sequence, tmp);
         return out.toByteArray();
     }
-
-    @Override
-    protected byte[] engineGetEncoded(String encMethod) throws IOException {
-        if ((encMethod != null) &&
-            (!encMethod.equalsIgnoreCase("ASN.1"))) {
-            throw new IllegalArgumentException("Only support ASN.1 format");
-        }
-        return engineGetEncoded();
-    }
-
-    @Override
-    protected String engineToString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("MD: " + mdName + "\n")
-            .append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n")
-            .append("SaltLength: " + saltLength + "\n")
-            .append("TrailerField: " + trailerField + "\n");
-        return sb.toString();
-    }
 }
< prev index next >