1 /* 2 * Copyright (c) 1997, 2017, 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 23 * questions. 24 */ 25 26 package java.security; 27 28 import java.io.*; 29 30 /** 31 * <p> SignedObject is a class for the purpose of creating authentic 32 * runtime objects whose integrity cannot be compromised without being 33 * detected. 34 * 35 * <p> More specifically, a SignedObject contains another Serializable 36 * object, the (to-be-)signed object and its signature. 37 * 38 * <p> The signed object is a "deep copy" (in serialized form) of an 39 * original object. Once the copy is made, further manipulation of 40 * the original object has no side effect on the copy. 41 * 42 * <p> The underlying signing algorithm is designated by the Signature 43 * object passed to the constructor and the {@code verify} method. 44 * A typical usage for signing is the following: 45 * 46 * <pre>{@code 47 * Signature signingEngine = Signature.getInstance(algorithm, 48 * provider); 49 * SignedObject so = new SignedObject(myobject, signingKey, 50 * signingEngine); 51 * }</pre> 52 * 53 * <p> A typical usage for verification is the following (having 54 * received SignedObject {@code so}): 55 * 56 * <pre>{@code 57 * Signature verificationEngine = 58 * Signature.getInstance(algorithm, provider); 59 * if (so.verify(publickey, verificationEngine)) 60 * try { 61 * Object myobj = so.getObject(); 62 * } catch (java.lang.ClassNotFoundException e) {}; 63 * }</pre> 64 * 65 * <p> Several points are worth noting. First, there is no need to 66 * initialize the signing or verification engine, as it will be 67 * re-initialized inside the constructor and the {@code verify} 68 * method. Secondly, for verification to succeed, the specified 69 * public key must be the public key corresponding to the private key 70 * used to generate the SignedObject. 71 * 72 * <p> More importantly, for flexibility reasons, the 73 * constructor and {@code verify} method allow for 74 * customized signature engines, which can implement signature 75 * algorithms that are not installed formally as part of a crypto 76 * provider. However, it is crucial that the programmer writing the 77 * verifier code be aware what {@code Signature} engine is being 78 * used, as its own implementation of the {@code verify} method 79 * is invoked to verify a signature. In other words, a malicious 80 * {@code Signature} may choose to always return true on 81 * verification in an attempt to bypass a security check. 82 * 83 * <p> The signature algorithm can be, among others, the NIST standard 84 * DSA, using DSA and SHA-256. The algorithm is specified using the 85 * same convention as that for signatures. The DSA algorithm using the 86 * SHA-256 message digest algorithm can be specified, for example, as 87 * "SHA256withDSA". In the case of 88 * RSA the signing algorithm could be specified as, for example, 89 * "SHA256withRSA". The algorithm name must be 90 * specified, as there is no default. 115 * @author Li Gong 116 * @since 1.2 117 */ 118 119 public final class SignedObject implements Serializable { 120 121 private static final long serialVersionUID = 720502720485447167L; 122 123 /* 124 * The original content is "deep copied" in its serialized format 125 * and stored in a byte array. The signature field is also in the 126 * form of byte array. 127 */ 128 129 private byte[] content; 130 private byte[] signature; 131 private String thealgorithm; 132 133 /** 134 * Constructs a SignedObject from any Serializable object. 135 * The given object is signed with the given signing key, using the 136 * designated signature engine. 137 * 138 * @param object the object to be signed. 139 * @param signingKey the private key for signing. 140 * @param signingEngine the signature signing engine. 141 * 142 * @exception IOException if an error occurs during serialization 143 * @exception InvalidKeyException if the key is invalid. 144 * @exception SignatureException if signing fails. 145 */ 146 public SignedObject(Serializable object, PrivateKey signingKey, 147 Signature signingEngine) 148 throws IOException, InvalidKeyException, SignatureException { 149 // creating a stream pipe-line, from a to b 150 ByteArrayOutputStream b = new ByteArrayOutputStream(); 151 ObjectOutput a = new ObjectOutputStream(b); 152 153 // write and flush the object content to byte array 154 a.writeObject(object); 155 a.flush(); 156 a.close(); 157 this.content = b.toByteArray(); 158 b.close(); 159 160 // now sign the encapsulated object 161 this.sign(signingKey, signingEngine); 162 } 163 164 /** 165 * Retrieves the encapsulated object. 166 * The encapsulated object is de-serialized before it is returned. 167 * 168 * @return the encapsulated object. 169 * 170 * @exception IOException if an error occurs during de-serialization 171 * @exception ClassNotFoundException if an error occurs during 172 * de-serialization 173 */ 174 public Object getObject() 175 throws IOException, ClassNotFoundException 176 { 177 // creating a stream pipe-line, from b to a 178 ByteArrayInputStream b = new ByteArrayInputStream(this.content); 179 ObjectInput a = new ObjectInputStream(b); 180 Object obj = a.readObject(); 181 b.close(); 182 a.close(); 183 return obj; 184 } 185 186 /** 187 * Retrieves the signature on the signed object, in the form of a 188 * byte array. 189 * 190 * @return the signature. Returns a new array each time this 191 * method is called. 192 */ 193 public byte[] getSignature() { 194 return this.signature.clone(); 195 } 196 197 /** 198 * Retrieves the name of the signature algorithm. 199 * 200 * @return the signature algorithm name. 201 */ 202 public String getAlgorithm() { 203 return this.thealgorithm; 204 } 205 206 /** 207 * Verifies that the signature in this SignedObject is the valid 208 * signature for the object stored inside, with the given 209 * verification key, using the designated verification engine. 210 * 211 * @param verificationKey the public key for verification. 212 * @param verificationEngine the signature verification engine. 213 * 214 * @exception SignatureException if signature verification failed (an 215 * exception prevented the signature verification engine from completing 216 * normally). 217 * @exception InvalidKeyException if the verification key is invalid. 218 * 219 * @return {@code true} if the signature 220 * is valid, {@code false} otherwise 221 */ 222 public boolean verify(PublicKey verificationKey, 223 Signature verificationEngine) 224 throws InvalidKeyException, SignatureException { 225 verificationEngine.initVerify(verificationKey); 226 verificationEngine.update(this.content.clone()); 227 return verificationEngine.verify(this.signature.clone()); 228 } 229 230 /* 231 * Signs the encapsulated object with the given signing key, using the 232 * designated signature engine. 233 * 234 * @param signingKey the private key for signing. 235 * @param signingEngine the signature signing engine. 236 * 237 * @exception InvalidKeyException if the key is invalid. 238 * @exception SignatureException if signing fails. 239 */ 240 private void sign(PrivateKey signingKey, Signature signingEngine) 241 throws InvalidKeyException, SignatureException { 242 // initialize the signing engine 243 signingEngine.initSign(signingKey); 244 signingEngine.update(this.content.clone()); 245 this.signature = signingEngine.sign().clone(); 246 this.thealgorithm = signingEngine.getAlgorithm(); 247 } 248 249 /** 250 * readObject is called to restore the state of the SignedObject from 251 * a stream. 252 */ 253 private void readObject(java.io.ObjectInputStream s) 254 throws java.io.IOException, ClassNotFoundException { 255 java.io.ObjectInputStream.GetField fields = s.readFields(); 256 content = ((byte[])fields.get("content", null)).clone(); 257 signature = ((byte[])fields.get("signature", null)).clone(); 258 thealgorithm = (String)fields.get("thealgorithm", null); 259 } 260 } | 1 /* 2 * Copyright (c) 1997, 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 23 * questions. 24 */ 25 26 package java.security; 27 28 import java.io.*; 29 import java.security.spec.AlgorithmParameterSpec; 30 31 /** 32 * <p> SignedObject is a class for the purpose of creating authentic 33 * runtime objects whose integrity cannot be compromised without being 34 * detected. 35 * 36 * <p> More specifically, a SignedObject contains another Serializable 37 * object, the (to-be-)signed object and its signature. 38 * 39 * <p> The signed object is a "deep copy" (in serialized form) of an 40 * original object. Once the copy is made, further manipulation of 41 * the original object has no side effect on the copy. 42 * 43 * <p> The underlying signing algorithm is designated by the Signature 44 * object passed to the constructor and the {@code verify} method. 45 * A typical usage for signing is the following: 46 * 47 * <pre>{@code 48 * Signature signingEngine = Signature.getInstance(algorithm, 49 * provider); 50 * SignedObject so = new SignedObject(myobject, signingKey, 51 * signingParams, signingEngine); 52 * }</pre> 53 * 54 * <p> A typical usage for verification is the following (having 55 * received SignedObject {@code so}): 56 * 57 * <pre>{@code 58 * Signature verificationEngine = 59 * Signature.getInstance(algorithm, provider); 60 * if (so.verify(verificationKey, verificationParams, verificationEngine)) 61 * try { 62 * Object myobj = so.getObject(); 63 * } catch (java.lang.ClassNotFoundException e) {}; 64 * }</pre> 65 * 66 * <p> Several points are worth noting. First, there is no need to 67 * initialize the signing or verification engine, as it will be 68 * re-initialized inside the constructor and the {@code verify} 69 * method. Secondly, for verification to succeed, the specified 70 * public key must be the public key corresponding to the private key 71 * used to generate the SignedObject. If signing parameters are used, 72 * the same parameters must be specified when calling {@code verify} 73 * method for verification to succeed. 74 * 75 * <p> More importantly, for flexibility reasons, the 76 * constructor and {@code verify} method allow for 77 * customized signature engines, which can implement signature 78 * algorithms that are not installed formally as part of a crypto 79 * provider. However, it is crucial that the programmer writing the 80 * verifier code be aware what {@code Signature} engine is being 81 * used, as its own implementation of the {@code verify} method 82 * is invoked to verify a signature. In other words, a malicious 83 * {@code Signature} may choose to always return true on 84 * verification in an attempt to bypass a security check. 85 * 86 * <p> The signature algorithm can be, among others, the NIST standard 87 * DSA, using DSA and SHA-256. The algorithm is specified using the 88 * same convention as that for signatures. The DSA algorithm using the 89 * SHA-256 message digest algorithm can be specified, for example, as 90 * "SHA256withDSA". In the case of 91 * RSA the signing algorithm could be specified as, for example, 92 * "SHA256withRSA". The algorithm name must be 93 * specified, as there is no default. 118 * @author Li Gong 119 * @since 1.2 120 */ 121 122 public final class SignedObject implements Serializable { 123 124 private static final long serialVersionUID = 720502720485447167L; 125 126 /* 127 * The original content is "deep copied" in its serialized format 128 * and stored in a byte array. The signature field is also in the 129 * form of byte array. 130 */ 131 132 private byte[] content; 133 private byte[] signature; 134 private String thealgorithm; 135 136 /** 137 * Constructs a SignedObject from any Serializable object. 138 * The given object is signed with the given signing key with 139 * no signature parameters, using the designated signature engine. 140 * 141 * @param object the object to be signed. 142 * @param signingKey the private key for signing. 143 * @param signingEngine the signature signing engine. 144 * 145 * @exception IOException if an error occurs during serialization 146 * @exception InvalidKeyException if the key is invalid. 147 * @exception SignatureException if signing fails. 148 */ 149 public SignedObject(Serializable object, PrivateKey signingKey, 150 Signature signingEngine) 151 throws IOException, InvalidKeyException, SignatureException { 152 // creating a stream pipe-line, from a to b 153 ByteArrayOutputStream b = new ByteArrayOutputStream(); 154 ObjectOutput a = new ObjectOutputStream(b); 155 156 // write and flush the object content to byte array 157 a.writeObject(object); 158 a.flush(); 159 a.close(); 160 this.content = b.toByteArray(); 161 b.close(); 162 163 // now sign the encapsulated object 164 try { 165 this.sign(signingKey, null, signingEngine); 166 } catch (InvalidAlgorithmParameterException e) { 167 // should not happen, re-throw just in case 168 throw new SignatureException(e); 169 } 170 } 171 172 /** 173 * Constructs a SignedObject from any Serializable object. 174 * The given object is signed with the given signing key and 175 * signature parameters, using the designated signature engine. 176 * If the signature algorithm does not use any signature parameters, 177 * {@code signingParams} should be null. 178 * 179 * @param object the object to be signed. 180 * @param signingKey the private key for signing. 181 * @param signingParams the signature parameters used for signing, 182 * may be null. 183 * @param signingEngine the signature signing engine. 184 * 185 * @exception IOException if an error occurs during serialization 186 * @exception InvalidKeyException if the key is invalid. 187 * @exception InvalidAlgorithmParameterException if the given signature 188 * parameters is invalid. 189 * @exception SignatureException if signing fails. 190 * @since 11 191 */ 192 public SignedObject(Serializable object, PrivateKey signingKey, 193 AlgorithmParameterSpec signingParams, 194 Signature signingEngine) 195 throws IOException, InvalidKeyException, 196 InvalidAlgorithmParameterException, SignatureException { 197 // creating a stream pipe-line, from a to b 198 ByteArrayOutputStream b = new ByteArrayOutputStream(); 199 ObjectOutput a = new ObjectOutputStream(b); 200 201 // write and flush the object content to byte array 202 a.writeObject(object); 203 a.flush(); 204 a.close(); 205 this.content = b.toByteArray(); 206 b.close(); 207 208 // now sign the encapsulated object 209 this.sign(signingKey, signingParams, signingEngine); 210 } 211 212 /** 213 * Retrieves the encapsulated object. 214 * The encapsulated object is de-serialized before it is returned. 215 * 216 * @return the encapsulated object. 217 * 218 * @exception IOException if an error occurs during de-serialization 219 * @exception ClassNotFoundException if an error occurs during 220 * de-serialization 221 */ 222 public Object getObject() 223 throws IOException, ClassNotFoundException { 224 // creating a stream pipe-line, from b to a 225 ByteArrayInputStream b = new ByteArrayInputStream(this.content); 226 ObjectInput a = new ObjectInputStream(b); 227 Object obj = a.readObject(); 228 b.close(); 229 a.close(); 230 return obj; 231 } 232 233 /** 234 * Retrieves the signature on the signed object, in the form of a 235 * byte array. 236 * 237 * @return the signature. Returns a new array each time this 238 * method is called. 239 */ 240 public byte[] getSignature() { 241 return this.signature.clone(); 242 } 243 244 /** 245 * Retrieves the name of the signature algorithm. 246 * 247 * @return the signature algorithm name. 248 */ 249 public String getAlgorithm() { 250 return this.thealgorithm; 251 } 252 253 /** 254 * Verifies that the signature in this SignedObject is the valid 255 * signature for the object stored inside, with the given 256 * verification key with no signature parameters, using the designated 257 * verification engine. 258 * 259 * @param verificationKey the public key for verification. 260 * @param verificationEngine the signature verification engine. 261 * 262 * @exception SignatureException if signature verification failed (an 263 * exception prevented the signature verification engine from completing 264 * normally). 265 * @exception InvalidKeyException if the verification key is invalid. 266 * 267 * @return {@code true} if the signature 268 * is valid, {@code false} otherwise 269 */ 270 public boolean verify(PublicKey verificationKey, 271 Signature verificationEngine) 272 throws InvalidKeyException, SignatureException { 273 try { 274 return verify(verificationKey, null, verificationEngine); 275 } catch (InvalidAlgorithmParameterException e) { 276 // should not happen, re-throw just in case 277 throw new SignatureException(e); 278 } 279 } 280 281 /** 282 * Verifies that the signature in this SignedObject is the valid 283 * signature for the object stored inside, with the given 284 * verification key and signature parameters, using the designated 285 * verification engine. If the signature algorithm does not use any 286 * signature parameters, {@code verificationParams} should be null. 287 * When signature parameters are used in signing, the same parameters 288 * must be specified when calling {@code verify} method for the 289 * verification to succeed. 290 * 291 * @param verificationKey the public key for verification. 292 * @param verificationParams the signature parameters for verification. 293 * @param verificationEngine the signature verification engine. 294 * 295 * @exception SignatureException if signature verification failed (an 296 * exception prevented the signature verification engine from completing 297 * normally). 298 * @exception InvalidKeyException if the verification key is invalid. 299 * @exception InvalidAlgorithmParameterException if the given signature 300 * parameters is invalid 301 * @return {@code true} if the signature is valid, {@code false} otherwise 302 * @since 11 303 */ 304 public boolean verify(PublicKey verificationKey, 305 AlgorithmParameterSpec verificationParams, 306 Signature verificationEngine) 307 throws InvalidKeyException, InvalidAlgorithmParameterException, 308 SignatureException { 309 // set parameteres before Signature.initSign/initVerify call, 310 // so key can be checked when it's set 311 try { 312 verificationEngine.setParameter(verificationParams); 313 } catch (UnsupportedOperationException e) { 314 // for backward compatibility, only re-throw when 315 // parameters is not null 316 if (verificationParams != null) throw e; 317 } 318 verificationEngine.initVerify(verificationKey); 319 verificationEngine.update(this.content.clone()); 320 return verificationEngine.verify(this.signature.clone()); 321 } 322 323 /* 324 * Signs the encapsulated object with the given signing key, using the 325 * designated signature engine. 326 * 327 * @param signingKey the private key for signing. 328 * @param signingParams the signature parameters for signing. 329 * @param signingEngine the signature signing engine. 330 * 331 * @exception InvalidKeyException if the key is invalid. 332 * @exception InvalidAlgorithmParameterException if the given signature 333 * parameters is invalid 334 * @exception SignatureException if signing fails. 335 */ 336 private void sign(PrivateKey signingKey, 337 AlgorithmParameterSpec signingParams, 338 Signature signingEngine) 339 throws InvalidKeyException, InvalidAlgorithmParameterException, 340 SignatureException { 341 // set parameteres before Signature.initSign/initVerify call, 342 // so key can be checked when it's set 343 try { 344 signingEngine.setParameter(signingParams); 345 } catch (UnsupportedOperationException e) { 346 // for backward compatibility, only re-throw when 347 // parameters is not null 348 if (signingParams != null) throw e; 349 } 350 signingEngine.initSign(signingKey); 351 signingEngine.update(this.content.clone()); 352 this.signature = signingEngine.sign().clone(); 353 this.thealgorithm = signingEngine.getAlgorithm(); 354 } 355 356 /** 357 * readObject is called to restore the state of the SignedObject from 358 * a stream. 359 */ 360 private void readObject(java.io.ObjectInputStream s) 361 throws java.io.IOException, ClassNotFoundException { 362 java.io.ObjectInputStream.GetField fields = s.readFields(); 363 content = ((byte[])fields.get("content", null)).clone(); 364 signature = ((byte[])fields.get("signature", null)).clone(); 365 thealgorithm = (String)fields.get("thealgorithm", null); 366 } 367 } |