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