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.
  94  *
  95  * <p> The name of the Cryptography Package Provider is designated
  96  * also by the Signature parameter to the constructor and the
  97  * {@code verify} method.  If the provider is not
  98  * specified, the default provider is used.  Each installation can
  99  * be configured to use a particular provider as default.
 100  *
 101  * <p> Potential applications of SignedObject include:
 102  * <ul>
 103  * <li> It can be used
 104  * internally to any Java runtime as an unforgeable authorization
 105  * token -- one that can be passed around without the fear that the
 106  * token can be maliciously modified without being detected.
 107  * <li> It
 108  * can be used to sign and serialize data/object for storage outside
 109  * the Java runtime (e.g., storing critical access control data on
 110  * disk).
 111  * <li> Nested SignedObjects can be used to construct a logical
 112  * sequence of signatures, resembling a chain of authorization and
 113  * delegation.
 114  * </ul>
 115  *
 116  * @see Signature
 117  *
 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 }