001: /*
002: * @(#)SignedObject.java 1.44 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.security;
029:
030: import java.io.*;
031:
032: /**
033: * <p> SignedObject is a class for the purpose of creating authentic
034: * runtime objects whose integrity cannot be compromised without being
035: * detected.
036: *
037: * <p> More specifically, a SignedObject contains another Serializable
038: * object, the (to-be-)signed object and its signature.
039: *
040: * <p> The signed object is a "deep copy" (in serialized form) of an
041: * original object. Once the copy is made, further manipulation of
042: * the original object has no side effect on the copy.
043: *
044: * <p> The underlying signing algorithm is designated by the Signature
045: * object passed to the constructor and the <code>verify</code> method.
046: * A typical usage for signing is the following:
047: *
048: * <p> <code> <pre>
049: * Signature signingEngine = Signature.getInstance(algorithm,
050: * provider);
051: * SignedObject so = new SignedObject(myobject, signingKey,
052: * signingEngine);
053: * </pre> </code>
054: *
055: * <p> A typical usage for verification is the following (having
056: * received SignedObject <code>so</code>):
057: *
058: * <p> <code> <pre>
059: * Signature verificationEngine =
060: * Signature.getInstance(algorithm, provider);
061: * if (so.verify(publickey, verificationEngine))
062: * try {
063: * Object myobj = so.getObject();
064: * } catch (java.lang.ClassNotFoundException e) {};
065: * </pre> </code>
066: *
067: * <p> Several points are worth noting. First, there is no need to
068: * initialize the signing or verification engine, as it will be
069: * re-initialized inside the constructor and the <code>verify</code>
070: * method. Secondly, for verification to succeed, the specified
071: * public key must be the public key corresponding to the private key
072: * used to generate the SignedObject.
073: *
074: * <p> More importantly, for flexibility reasons, the
075: * constructor and <code>verify</code> method allow for
076: * customized signature engines, which can implement signature
077: * algorithms that are not installed formally as part of a crypto
078: * provider. However, it is crucial that the programmer writing the
079: * verifier code be aware what <code>Signature</code> engine is being
080: * used, as its own implementation of the <code>verify</code> method
081: * is invoked to verify a signature. In other words, a malicious
082: * <code>Signature</code> may choose to always return true on
083: * verification in an attempt to bypass a security check.
084: *
085: * <p> The signature algorithm can be, among others, the NIST standard
086: * DSA, using DSA and SHA-1. The algorithm is specified using the
087: * same convention as that for signatures. The DSA algorithm using the
088: * SHA-1 message digest algorithm can be specified, for example, as
089: * "SHA/DSA" or "SHA-1/DSA" (they are equivalent). In the case of
090: * RSA, there are multiple choices for the message digest algorithm,
091: * so the signing algorithm could be specified as, for example,
092: * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA". The algorithm name must be
093: * specified, as there is no default.
094: *
095: * <p> The name of the Cryptography Package Provider is designated
096: * also by the Signature parameter to the constructor and the
097: * <code>verify</code> method. If the provider is not
098: * specified, the default provider is used. Each installation can
099: * 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: * @version 1.37, 02/02/00
119: * @author Li Gong
120: */
121:
122: public final class SignedObject implements Serializable {
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.
191: */
192: public byte[] getSignature() {
193: // return only a clone, for integrity reasons
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: }
|