< 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 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  35 import java.security.spec.MGF1ParameterSpec;
  36 import java.security.spec.PSSParameterSpec;
  37 import static java.security.spec.PSSParameterSpec.DEFAULT;
  38 
  39 /**
  40  * This class implements the PSS parameters used with the RSA
  41  * signatures in PSS padding. Here is its ASN.1 definition:
  42  * RSASSA-PSS-params ::= SEQUENCE {
  43  *   hashAlgorithm      [0] HashAlgorithm     DEFAULT sha1,
  44  *   maskGenAlgorithm   [1] MaskGenAlgorithm  DEFAULT mgf1SHA1,
  45  *   saltLength         [2] INTEGER           DEFAULT 20
  46  *   trailerField       [3] TrailerField      DEFAULT trailerFieldBC
  47  * }
  48  *
  49  * @author Valerie Peng
  50  *
  51  */
  52 
  53 public final class PSSParameters extends AlgorithmParametersSpi {
  54 
  55     private String mdName;
  56     private MGF1ParameterSpec mgfSpec;
  57     private int saltLength;
  58     private int trailerField;
  59 
  60     private static final ObjectIdentifier OID_MGF1 =
  61            ObjectIdentifier.newInternal(new int[] {1,2,840,113549,1,1,8});
  62 
  63     public PSSParameters() {
  64     }
  65 
  66     @Override
  67     protected void engineInit(AlgorithmParameterSpec paramSpec)
  68             throws InvalidParameterSpecException {
  69         if (!(paramSpec instanceof PSSParameterSpec)) {
  70             throw new InvalidParameterSpecException
  71                 ("Inappropriate parameter specification");
  72         }
  73         PSSParameterSpec spec = (PSSParameterSpec) paramSpec;
  74         this.mdName = spec.getDigestAlgorithm();
  75         String mgfName = spec.getMGFAlgorithm();
  76         if (!mgfName.equalsIgnoreCase("MGF1")) {
  77             throw new InvalidParameterSpecException("Unsupported mgf " +
  78                 mgfName + "; MGF1 only");
  79         }
  80         AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
  81         if (!(mgfSpec instanceof MGF1ParameterSpec)) {
  82             throw new InvalidParameterSpecException("Inappropriate mgf " +
  83                 "parameters; non-null MGF1ParameterSpec only");
  84         }
  85         this.mgfSpec = (MGF1ParameterSpec) mgfSpec;
  86         this.saltLength = spec.getSaltLength();
  87         this.trailerField = spec.getTrailerField();
  88     }
  89 
  90     @Override
  91     protected void engineInit(byte[] encoded) throws IOException {
  92         // first initialize with the DEFAULT values before
  93         // retrieving from the encoding bytes
  94         this.mdName = DEFAULT.getDigestAlgorithm();
  95         this.mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
  96         this.saltLength = DEFAULT.getSaltLength();
  97         this.trailerField = DEFAULT.getTrailerField();
  98 
  99         DerInputStream der = new DerInputStream(encoded);
 100         DerValue[] datum = der.getSequence(4);

 101         for (DerValue d : datum) {
 102             if (d.isContextSpecific((byte) 0x00)) {
 103                 // hash algid
 104                 this.mdName = AlgorithmId.parse
 105                     (d.data.getDerValue()).getName();
 106             } else if (d.isContextSpecific((byte) 0x01)) {
 107                 // mgf algid
 108                 AlgorithmId val = AlgorithmId.parse(d.data.getDerValue());
 109                 if (!val.getOID().equals(OID_MGF1)) {
 110                     throw new IOException("Only MGF1 mgf is supported");
 111                 }
 112                 AlgorithmId params = AlgorithmId.parse(
 113                     new DerValue(val.getEncodedParams()));
 114                 String mgfDigestName = params.getName();
 115                 switch (mgfDigestName) {
 116                 case "SHA-1":
 117                     this.mgfSpec = MGF1ParameterSpec.SHA1;
 118                     break;
 119                 case "SHA-224":
 120                     this.mgfSpec = MGF1ParameterSpec.SHA224;
 121                     break;
 122                 case "SHA-256":
 123                     this.mgfSpec = MGF1ParameterSpec.SHA256;
 124                     break;
 125                 case "SHA-384":
 126                     this.mgfSpec = MGF1ParameterSpec.SHA384;
 127                     break;
 128                 case "SHA-512":
 129                     this.mgfSpec = MGF1ParameterSpec.SHA512;
 130                     break;
 131                 case "SHA-512/224":
 132                     this.mgfSpec = MGF1ParameterSpec.SHA512_224;
 133                     break;
 134                 case "SHA-512/256":
 135                     this.mgfSpec = MGF1ParameterSpec.SHA512_256;
 136                     break;
 137                 default:
 138                     throw new IOException
 139                         ("Unrecognized message digest algorithm " +
 140                         mgfDigestName);
 141                 }
 142             } else if (d.isContextSpecific((byte) 0x02)) {
 143                 // salt length
 144                 this.saltLength = d.data.getDerValue().getInteger();
 145                 if (this.saltLength < 0) {
 146                     throw new IOException("Negative value for saltLength");
 147                 }
 148             } else if (d.isContextSpecific((byte) 0x03)) {
 149                 // trailer field
 150                 this.trailerField = d.data.getDerValue().getInteger();
 151                 if (this.trailerField != 1) {
 152                     throw new IOException("Unsupported trailerField value " +
 153                     this.trailerField);
 154                 }
 155             } else {
 156                 throw new IOException("Invalid encoded PSSParameters");
 157             }
 158         }



 159     }
 160 
 161     @Override
 162     protected void engineInit(byte[] encoded, String decodingMethod)
 163             throws IOException {
 164         if ((decodingMethod != null) &&
 165             (!decodingMethod.equalsIgnoreCase("ASN.1"))) {
 166             throw new IllegalArgumentException("Only support ASN.1 format");
 167         }
 168         engineInit(encoded);
 169     }
 170 
 171     @Override
 172     protected <T extends AlgorithmParameterSpec>
 173             T engineGetParameterSpec(Class<T> paramSpec)
 174             throws InvalidParameterSpecException {
 175         if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) {
 176             return paramSpec.cast(
 177                 new PSSParameterSpec(mdName, "MGF1", mgfSpec,
 178                                      saltLength, trailerField));
 179         } else {
 180             throw new InvalidParameterSpecException
 181                 ("Inappropriate parameter specification");
 182         }
 183     }
 184 
 185     @Override
 186     protected byte[] engineGetEncoded() throws IOException {



































 187         DerOutputStream tmp = new DerOutputStream();
 188         DerOutputStream tmp2, tmp3;
 189 
 190         // MD
 191         AlgorithmId mdAlgId;
 192         try {
 193             mdAlgId = AlgorithmId.get(mdName);
 194         } catch (NoSuchAlgorithmException nsae) {
 195             throw new IOException("AlgorithmId " + mdName +
 196                                   " impl not found");






 197         }
 198         tmp2 = new DerOutputStream();
 199         mdAlgId.derEncode(tmp2);
 200         tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0),
 201                       tmp2);
 202 
 203         // MGF
 204         tmp2 = new DerOutputStream();
 205         tmp2.putOID(OID_MGF1);
 206         AlgorithmId mgfDigestId;
 207         try {
 208             mgfDigestId = AlgorithmId.get(mgfSpec.getDigestAlgorithm());
 209         } catch (NoSuchAlgorithmException nase) {
 210             throw new IOException("AlgorithmId " +
 211                     mgfSpec.getDigestAlgorithm() + " impl not found");










 212         }
 213         mgfDigestId.encode(tmp2);
 214         tmp3 = new DerOutputStream();
 215         tmp3.write(DerValue.tag_Sequence, tmp2);
 216         tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)1),
 217                   tmp3);
 218 
 219         // SaltLength
 220         tmp2 = new DerOutputStream();
 221         tmp2.putInteger(saltLength);
 222         tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)2),
 223                   tmp2);


 224 
 225         // TrailerField
 226         tmp2 = new DerOutputStream();
 227         tmp2.putInteger(trailerField);
 228         tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3),
 229                   tmp2);


 230 
 231         // Put all together under a SEQUENCE tag
 232         DerOutputStream out = new DerOutputStream();
 233         out.write(DerValue.tag_Sequence, tmp);
 234         return out.toByteArray();
 235     }
 236 
 237     @Override
 238     protected byte[] engineGetEncoded(String encMethod) throws IOException {
 239         if ((encMethod != null) &&
 240             (!encMethod.equalsIgnoreCase("ASN.1"))) {
 241             throw new IllegalArgumentException("Only support ASN.1 format");
 242         }
 243         return engineGetEncoded();
 244     }
 245 
 246     @Override
 247     protected String engineToString() {
 248         StringBuilder sb = new StringBuilder();
 249         sb.append("MD: " + mdName + "\n")
 250             .append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n")
 251             .append("SaltLength: " + saltLength + "\n")
 252             .append("TrailerField: " + trailerField + "\n");
 253         return sb.toString();
 254     }
 255 }
   1 /*
   2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  35 import java.security.spec.MGF1ParameterSpec;
  36 import java.security.spec.PSSParameterSpec;
  37 import static java.security.spec.PSSParameterSpec.DEFAULT;
  38 
  39 /**
  40  * This class implements the PSS parameters used with the RSA
  41  * signatures in PSS padding. Here is its ASN.1 definition:
  42  * RSASSA-PSS-params ::= SEQUENCE {
  43  *   hashAlgorithm      [0] HashAlgorithm     DEFAULT sha1,
  44  *   maskGenAlgorithm   [1] MaskGenAlgorithm  DEFAULT mgf1SHA1,
  45  *   saltLength         [2] INTEGER           DEFAULT 20
  46  *   trailerField       [3] TrailerField      DEFAULT trailerFieldBC
  47  * }
  48  *
  49  * @author Valerie Peng
  50  *
  51  */
  52 
  53 public final class PSSParameters extends AlgorithmParametersSpi {
  54 
  55     private PSSParameterSpec spec;






  56 
  57     public PSSParameters() {
  58     }
  59 
  60     @Override
  61     protected void engineInit(AlgorithmParameterSpec paramSpec)
  62             throws InvalidParameterSpecException {
  63         if (!(paramSpec instanceof PSSParameterSpec)) {
  64             throw new InvalidParameterSpecException
  65                 ("Inappropriate parameter specification");
  66         }
  67         PSSParameterSpec spec = (PSSParameterSpec) paramSpec;
  68 
  69         String mgfName = spec.getMGFAlgorithm();
  70         if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1")) {
  71             throw new InvalidParameterSpecException("Unsupported mgf " +
  72                 mgfName + "; MGF1 only");
  73         }
  74         AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
  75         if (!(mgfSpec instanceof MGF1ParameterSpec)) {
  76             throw new InvalidParameterSpecException("Inappropriate mgf " +
  77                 "parameters; non-null MGF1ParameterSpec only");
  78         }
  79         this.spec = spec;


  80     }
  81 
  82     @Override
  83     protected void engineInit(byte[] encoded) throws IOException {
  84         // first initialize with the DEFAULT values before
  85         // retrieving from the encoding bytes
  86         String mdName = DEFAULT.getDigestAlgorithm();
  87         MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
  88         int saltLength = DEFAULT.getSaltLength();
  89         int trailerField = DEFAULT.getTrailerField();
  90 
  91         DerInputStream der = new DerInputStream(encoded);
  92         DerValue[] datum = der.getSequence(4);
  93 
  94         for (DerValue d : datum) {
  95             if (d.isContextSpecific((byte) 0x00)) {
  96                 // hash algid
  97                 mdName = AlgorithmId.parse
  98                     (d.data.getDerValue()).getName();
  99             } else if (d.isContextSpecific((byte) 0x01)) {
 100                 // mgf algid
 101                 AlgorithmId val = AlgorithmId.parse(d.data.getDerValue());
 102                 if (!val.getOID().equals(AlgorithmId.mgf1_oid)) {
 103                     throw new IOException("Only MGF1 mgf is supported");
 104                 }
 105                 AlgorithmId params = AlgorithmId.parse(
 106                     new DerValue(val.getEncodedParams()));
 107                 String mgfDigestName = params.getName();
 108                 switch (mgfDigestName) {
 109                 case "SHA-1":
 110                     mgfSpec = MGF1ParameterSpec.SHA1;
 111                     break;
 112                 case "SHA-224":
 113                     mgfSpec = MGF1ParameterSpec.SHA224;
 114                     break;
 115                 case "SHA-256":
 116                     mgfSpec = MGF1ParameterSpec.SHA256;
 117                     break;
 118                 case "SHA-384":
 119                     mgfSpec = MGF1ParameterSpec.SHA384;
 120                     break;
 121                 case "SHA-512":
 122                     mgfSpec = MGF1ParameterSpec.SHA512;
 123                     break;
 124                 case "SHA-512/224":
 125                     mgfSpec = MGF1ParameterSpec.SHA512_224;
 126                     break;
 127                 case "SHA-512/256":
 128                     mgfSpec = MGF1ParameterSpec.SHA512_256;
 129                     break;
 130                 default:
 131                     throw new IOException
 132                         ("Unrecognized message digest algorithm " +
 133                         mgfDigestName);
 134                 }
 135             } else if (d.isContextSpecific((byte) 0x02)) {
 136                 // salt length
 137                 saltLength = d.data.getDerValue().getInteger();
 138                 if (saltLength < 0) {
 139                     throw new IOException("Negative value for saltLength");
 140                 }
 141             } else if (d.isContextSpecific((byte) 0x03)) {
 142                 // trailer field
 143                 trailerField = d.data.getDerValue().getInteger();
 144                 if (trailerField != 1) {
 145                     throw new IOException("Unsupported trailerField value " +
 146                     trailerField);
 147                 }
 148             } else {
 149                 throw new IOException("Invalid encoded PSSParameters");
 150             }
 151         }
 152 
 153         this.spec = new PSSParameterSpec(mdName, "MGF1", mgfSpec,
 154                 saltLength, trailerField);
 155     }
 156 
 157     @Override
 158     protected void engineInit(byte[] encoded, String decodingMethod)
 159             throws IOException {
 160         if ((decodingMethod != null) &&
 161             (!decodingMethod.equalsIgnoreCase("ASN.1"))) {
 162             throw new IllegalArgumentException("Only support ASN.1 format");
 163         }
 164         engineInit(encoded);
 165     }
 166 
 167     @Override
 168     protected <T extends AlgorithmParameterSpec>
 169             T engineGetParameterSpec(Class<T> paramSpec)
 170             throws InvalidParameterSpecException {
 171         if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) {
 172             return paramSpec.cast(spec);


 173         } else {
 174             throw new InvalidParameterSpecException
 175                 ("Inappropriate parameter specification");
 176         }
 177     }
 178 
 179     @Override
 180     protected byte[] engineGetEncoded() throws IOException {
 181         return getEncoded(spec);
 182     }
 183 
 184     @Override
 185     protected byte[] engineGetEncoded(String encMethod) throws IOException {
 186         if ((encMethod != null) &&
 187             (!encMethod.equalsIgnoreCase("ASN.1"))) {
 188             throw new IllegalArgumentException("Only support ASN.1 format");
 189         }
 190         return engineGetEncoded();
 191     }
 192 
 193     @Override
 194     protected String engineToString() {
 195         return spec.toString();
 196     }
 197 
 198     /**
 199      * Returns the encoding of a {@link PSSParameterSpec} object. This method
 200      * is used in this class and {@link AlgorithmId}.
 201      *
 202      * @param spec a {@code PSSParameterSpec} object
 203      * @return its DER encoding
 204      * @throws IOException if the name of a MessageDigest or MaskGenAlgorithm
 205      *          is unsupported
 206      */
 207     public static byte[] getEncoded(PSSParameterSpec spec) throws IOException {
 208 
 209         AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
 210         if (!(mgfSpec instanceof MGF1ParameterSpec)) {
 211             throw new IOException("Cannot encode " + mgfSpec);
 212         }
 213 
 214         MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec)mgfSpec;
 215 
 216         DerOutputStream tmp = new DerOutputStream();
 217         DerOutputStream tmp2, tmp3;
 218 
 219         // MD
 220         AlgorithmId mdAlgId;
 221         try {
 222             mdAlgId = AlgorithmId.get(spec.getDigestAlgorithm());
 223         } catch (NoSuchAlgorithmException nsae) {
 224             throw new IOException("AlgorithmId " + spec.getDigestAlgorithm() +
 225                     " impl not found");
 226         }
 227         if (!mdAlgId.getOID().equals(AlgorithmId.SHA_oid)) {
 228             tmp2 = new DerOutputStream();
 229             mdAlgId.derEncode(tmp2);
 230             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
 231                     tmp2);
 232         }




 233 
 234         // MGF


 235         AlgorithmId mgfDigestId;
 236         try {
 237             mgfDigestId = AlgorithmId.get(mgf1Spec.getDigestAlgorithm());
 238         } catch (NoSuchAlgorithmException nase) {
 239             throw new IOException("AlgorithmId " +
 240                     mgf1Spec.getDigestAlgorithm() + " impl not found");
 241         }
 242 
 243         if (!mgfDigestId.getOID().equals(AlgorithmId.SHA_oid)) {
 244             tmp2 = new DerOutputStream();
 245             tmp2.putOID(AlgorithmId.mgf1_oid);
 246             mgfDigestId.encode(tmp2);
 247             tmp3 = new DerOutputStream();
 248             tmp3.write(DerValue.tag_Sequence, tmp2);
 249             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1),
 250                     tmp3);
 251         }





 252 
 253         // SaltLength
 254         if (spec.getSaltLength() != 20) {
 255             tmp2 = new DerOutputStream();
 256             tmp2.putInteger(spec.getSaltLength());
 257             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2),
 258                     tmp2);
 259         }
 260 
 261         // TrailerField
 262         if (spec.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
 263             tmp2 = new DerOutputStream();
 264             tmp2.putInteger(spec.getTrailerField());
 265             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3),
 266                     tmp2);
 267         }
 268 
 269         // Put all together under a SEQUENCE tag
 270         DerOutputStream out = new DerOutputStream();
 271         out.write(DerValue.tag_Sequence, tmp);
 272         return out.toByteArray();



















 273     }
 274 }
< prev index next >