001 /*
002 * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.security;
027
028 import java.io.*;
029
030 /**
031 * <p> SignedObject is a class for the purpose of creating authentic
032 * runtime objects whose integrity cannot be compromised without being
033 * detected.
034 *
035 * <p> More specifically, a SignedObject contains another Serializable
036 * object, the (to-be-)signed object and its signature.
037 *
038 * <p> The signed object is a "deep copy" (in serialized form) of an
039 * original object. Once the copy is made, further manipulation of
040 * the original object has no side effect on the copy.
041 *
042 * <p> The underlying signing algorithm is designated by the Signature
043 * object passed to the constructor and the <code>verify</code> method.
044 * A typical usage for signing is the following:
045 *
046 * <p> <code> <pre>
047 * Signature signingEngine = Signature.getInstance(algorithm,
048 * provider);
049 * SignedObject so = new SignedObject(myobject, signingKey,
050 * signingEngine);
051 * </pre> </code>
052 *
053 * <p> A typical usage for verification is the following (having
054 * received SignedObject <code>so</code>):
055 *
056 * <p> <code> <pre>
057 * Signature verificationEngine =
058 * Signature.getInstance(algorithm, provider);
059 * if (so.verify(publickey, verificationEngine))
060 * try {
061 * Object myobj = so.getObject();
062 * } catch (java.lang.ClassNotFoundException e) {};
063 * </pre> </code>
064 *
065 * <p> Several points are worth noting. First, there is no need to
066 * initialize the signing or verification engine, as it will be
067 * re-initialized inside the constructor and the <code>verify</code>
068 * method. Secondly, for verification to succeed, the specified
069 * public key must be the public key corresponding to the private key
070 * used to generate the SignedObject.
071 *
072 * <p> More importantly, for flexibility reasons, the
073 * constructor and <code>verify</code> method allow for
074 * customized signature engines, which can implement signature
075 * algorithms that are not installed formally as part of a crypto
076 * provider. However, it is crucial that the programmer writing the
077 * verifier code be aware what <code>Signature</code> engine is being
078 * used, as its own implementation of the <code>verify</code> method
079 * is invoked to verify a signature. In other words, a malicious
080 * <code>Signature</code> may choose to always return true on
081 * verification in an attempt to bypass a security check.
082 *
083 * <p> The signature algorithm can be, among others, the NIST standard
084 * DSA, using DSA and SHA-1. The algorithm is specified using the
085 * same convention as that for signatures. The DSA algorithm using the
086 * SHA-1 message digest algorithm can be specified, for example, as
087 * "SHA/DSA" or "SHA-1/DSA" (they are equivalent). In the case of
088 * RSA, there are multiple choices for the message digest algorithm,
089 * so the signing algorithm could be specified as, for example,
090 * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA". The algorithm name must be
091 * specified, as there is no default.
092 *
093 * <p> The name of the Cryptography Package Provider is designated
094 * also by the Signature parameter to the constructor and the
095 * <code>verify</code> method. If the provider is not
096 * specified, the default provider is used. Each installation can
097 * be configured to use a particular provider as default.
098 *
099 * <p> Potential applications of SignedObject include:
100 * <ul>
101 * <li> It can be used
102 * internally to any Java runtime as an unforgeable authorization
103 * token -- one that can be passed around without the fear that the
104 * token can be maliciously modified without being detected.
105 * <li> It
106 * can be used to sign and serialize data/object for storage outside
107 * the Java runtime (e.g., storing critical access control data on
108 * disk).
109 * <li> Nested SignedObjects can be used to construct a logical
110 * sequence of signatures, resembling a chain of authorization and
111 * delegation.
112 * </ul>
113 *
114 * @see Signature
115 *
116 * @version 1.50, 05/05/07
117 * @author Li Gong
118 */
119
120 public final class SignedObject implements Serializable {
121
122 private static final long serialVersionUID = 720502720485447167L;
123
124 /*
125 * The original content is "deep copied" in its serialized format
126 * and stored in a byte array. The signature field is also in the
127 * form of byte array.
128 */
129
130 private byte[] content;
131 private byte[] signature;
132 private String thealgorithm;
133
134 /**
135 * Constructs a SignedObject from any Serializable object.
136 * The given object is signed with the given signing key, using the
137 * designated signature engine.
138 *
139 * @param object the object to be signed.
140 * @param signingKey the private key for signing.
141 * @param signingEngine the signature signing engine.
142 *
143 * @exception IOException if an error occurs during serialization
144 * @exception InvalidKeyException if the key is invalid.
145 * @exception SignatureException if signing fails.
146 */
147 public SignedObject(Serializable object, PrivateKey signingKey,
148 Signature signingEngine) throws IOException,
149 InvalidKeyException, SignatureException {
150 // creating a stream pipe-line, from a to b
151 ByteArrayOutputStream b = new ByteArrayOutputStream();
152 ObjectOutput a = new ObjectOutputStream(b);
153
154 // write and flush the object content to byte array
155 a.writeObject(object);
156 a.flush();
157 a.close();
158 this .content = b.toByteArray();
159 b.close();
160
161 // now sign the encapsulated object
162 this .sign(signingKey, signingEngine);
163 }
164
165 /**
166 * Retrieves the encapsulated object.
167 * The encapsulated object is de-serialized before it is returned.
168 *
169 * @return the encapsulated object.
170 *
171 * @exception IOException if an error occurs during de-serialization
172 * @exception ClassNotFoundException if an error occurs during
173 * de-serialization
174 */
175 public Object getObject() throws IOException,
176 ClassNotFoundException {
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 byte[] sig = (byte[]) this .signature.clone();
195 return sig;
196 }
197
198 /**
199 * Retrieves the name of the signature algorithm.
200 *
201 * @return the signature algorithm name.
202 */
203 public String getAlgorithm() {
204 return this .thealgorithm;
205 }
206
207 /**
208 * Verifies that the signature in this SignedObject is the valid
209 * signature for the object stored inside, with the given
210 * verification key, using the designated verification engine.
211 *
212 * @param verificationKey the public key for verification.
213 * @param verificationEngine the signature verification engine.
214 *
215 * @exception SignatureException if signature verification failed.
216 * @exception InvalidKeyException if the verification key is invalid.
217 *
218 * @return <tt>true</tt> if the signature
219 * is valid, <tt>false</tt> otherwise
220 */
221 public boolean verify(PublicKey verificationKey,
222 Signature verificationEngine) throws InvalidKeyException,
223 SignatureException {
224 verificationEngine.initVerify(verificationKey);
225 verificationEngine.update((byte[]) this .content.clone());
226 return verificationEngine.verify((byte[]) this .signature
227 .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((byte[]) this .content.clone());
245 this .signature = (byte[]) 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 s.defaultReadObject();
256 content = (byte[]) content.clone();
257 signature = (byte[]) signature.clone();
258 }
259 }
|