File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\cli\src\main\java\hudson\cli\Connection.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2011, CloudBees, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.cli;
25
26 import hudson.remoting.SocketInputStream;
27 import hudson.remoting.SocketOutputStream;
28 import org.apache.commons.codec.binary.Base64;
29
30 import javax.crypto.Cipher;
31 import javax.crypto.CipherInputStream;
32 import javax.crypto.CipherOutputStream;
33 import javax.crypto.KeyAgreement;
34 import javax.crypto.SecretKey;
35 import javax.crypto.interfaces.DHPublicKey;
36 import javax.crypto.spec.DHParameterSpec;
37 import javax.crypto.spec.IvParameterSpec;
38 import javax.crypto.spec.SecretKeySpec;
39 import java.io.DataInputStream;
40 import java.io.DataOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.ObjectInputStream;
44 import java.io.ObjectOutputStream;
45 import java.io.OutputStream;
46 import java.net.Socket;
47 import java.security.AlgorithmParameterGenerator;
48 import java.security.GeneralSecurityException;
49 import java.security.Key;
50 import java.security.KeyFactory;
51 import java.security.KeyPair;
52 import java.security.KeyPairGenerator;
53 import java.security.PublicKey;
54 import java.security.Signature;
55 import java.security.interfaces.DSAPublicKey;
56 import java.security.interfaces.RSAPublicKey;
57 import java.security.spec.X509EncodedKeySpec;
58
59 public class Connection {
60 public final InputStream in;
61 public final OutputStream out;
62
63 public final DataInputStream din;
64 public final DataOutputStream dout;
65
66 public Connection(Socket socket) throws IOException {
67 this(new SocketInputStream(socket),new SocketOutputStream(socket));
68 }
69
70 public Connection(InputStream in, OutputStream out) {
71 this.in = in;
72 this.out = out;
73 this.din = new DataInputStream(in);
74 this.dout = new DataOutputStream(out);
75 }
76
77 //
78 //
79 // Convenience methods
80 //
81 //
82 public void writeUTF(String msg) throws IOException {
83 dout.writeUTF(msg);
84 }
85
86 public String readUTF() throws IOException {
87 return din.readUTF();
88 }
89
90 public void writeBoolean(boolean b) throws IOException {
91 dout.writeBoolean(b);
92 }
93
94 public boolean readBoolean() throws IOException {
95 return din.readBoolean();
96 }
97
98 /**
99 * Sends a serializable object.
100 */
101 public void writeObject(Object o) throws IOException {
102 ObjectOutputStream oos = new ObjectOutputStream(out);
103 oos.writeObject(o);
104 // don't close oss, which will close the underlying stream
105 // no need to flush either, given the way oos is implemented
106 }
107
108 /**
109 * Receives an object sent by {@link #writeObject(Object)}
110 */
111 public <T> T readObject() throws IOException, ClassNotFoundException {
112 ObjectInputStream ois = new ObjectInputStream(in);
113 return (T)ois.readObject();
114 }
115
116 public void writeKey(Key key) throws IOException {
117 writeUTF(new String(Base64.encodeBase64(key.getEncoded())));
118 }
119
120 public X509EncodedKeySpec readKey() throws IOException {
121 byte[] otherHalf = Base64.decodeBase64(readUTF()); // for historical reasons, we don't use readByteArray()
122 return new X509EncodedKeySpec(otherHalf);
123 }
124
125 public void writeByteArray(byte[] data) throws IOException {
126 dout.writeInt(data.length);
127 dout.write(data);
128 }
129
130 public byte[] readByteArray() throws IOException {
131 byte[] buf = new byte[din.readInt()];
132 din.readFully(buf);
133 return buf;
134 }
135
136 /**
137 * Performs a Diffie-Hellman key exchange and produce a common secret between two ends of the connection.
138 *
139 * <p>
140 * DH is also useful as a coin-toss algorithm. Two parties get the same random number without trusting
141 * each other.
142 */
143 public KeyAgreement diffieHellman(boolean side) throws IOException, GeneralSecurityException {
144 return diffieHellman(side,512);
145 }
146 public KeyAgreement diffieHellman(boolean side, int keySize) throws IOException, GeneralSecurityException {
147 KeyPair keyPair;
148 PublicKey otherHalf;
149
150 if (side) {
151 AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH");
152 paramGen.init(keySize);
153
154 KeyPairGenerator dh = KeyPairGenerator.getInstance("DH");
155 dh.initialize(paramGen.generateParameters().getParameterSpec(DHParameterSpec.class));
156 keyPair = dh.generateKeyPair();
157
158 // send a half and get a half
159 writeKey(keyPair.getPublic());
160 otherHalf = KeyFactory.getInstance("DH").generatePublic(readKey());
161 } else {
162 otherHalf = KeyFactory.getInstance("DH").generatePublic(readKey());
163
164 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH");
165 keyPairGen.initialize(((DHPublicKey) otherHalf).getParams());
166 keyPair = keyPairGen.generateKeyPair();
167
168 // send a half and get a half
169 writeKey(keyPair.getPublic());
170 }
171
172 KeyAgreement ka = KeyAgreement.getInstance("DH");
173 ka.init(keyPair.getPrivate());
174 ka.doPhase(otherHalf, true);
175
176 return ka;
177 }
178
179 /**
180 * Upgrades a connection with transport encryption by the specified symmetric cipher.
181 *
182 * @return
183 * A new {@link Connection} object that includes the transport encryption.
184 */
185 public Connection encryptConnection(SecretKey sessionKey, String algorithm) throws IOException, GeneralSecurityException {
186 Cipher cout = Cipher.getInstance(algorithm);
187 cout.init(Cipher.ENCRYPT_MODE, sessionKey, new IvParameterSpec(sessionKey.getEncoded()));
188 CipherOutputStream o = new CipherOutputStream(out, cout);
189
190 Cipher cin = Cipher.getInstance(algorithm);
191 cin.init(Cipher.DECRYPT_MODE, sessionKey, new IvParameterSpec(sessionKey.getEncoded()));
192 CipherInputStream i = new CipherInputStream(in, cin);
193
194 return new Connection(i,o);
195 }
196
197 /**
198 * Given a byte array that contains arbitrary number of bytes, digests or expands those bits into the specified
199 * number of bytes without loss of entropy.
200 *
201 * Cryptographic utility code.
202 */
203 public static byte[] fold(byte[] bytes, int size) {
204 byte[] r = new byte[size];
205 for (int i=Math.max(bytes.length,size)-1; i>=0; i-- ) {
206 r[i%r.length] ^= bytes[i%bytes.length];
207 }
208 return r;
209 }
210
211 private String detectKeyAlgorithm(KeyPair kp) {
212 return detectKeyAlgorithm(kp.getPublic());
213 }
214
215 private String detectKeyAlgorithm(PublicKey kp) {
216 if (kp instanceof RSAPublicKey) return "RSA";
217 if (kp instanceof DSAPublicKey) return "DSA";
218 throw new IllegalArgumentException("Unknown public key type: "+kp);
219 }
220
221 /**
222 * Used in conjunction with {@link #verifyIdentity(byte[])} to prove
223 * that we actually own the private key of the given key pair.
224 */
225 public void proveIdentity(byte[] sharedSecret, KeyPair key) throws IOException, GeneralSecurityException {
226 String algorithm = detectKeyAlgorithm(key);
227 writeUTF(algorithm);
228 writeKey(key.getPublic());
229
230 Signature sig = Signature.getInstance("SHA1with"+algorithm);
231 sig.initSign(key.getPrivate());
232 sig.update(key.getPublic().getEncoded());
233 sig.update(sharedSecret);
234 writeObject(sig.sign());
235 }
236
237 /**
238 * Verifies that we are talking to a peer that actually owns the private key corresponding to the public key we get.
239 */
240 public PublicKey verifyIdentity(byte[] sharedSecret) throws IOException, GeneralSecurityException {
241 try {
242 String serverKeyAlgorithm = readUTF();
243 PublicKey spk = KeyFactory.getInstance(serverKeyAlgorithm).generatePublic(readKey());
244
245 // verify the identity of the server
246 Signature sig = Signature.getInstance("SHA1with"+serverKeyAlgorithm);
247 sig.initVerify(spk);
248 sig.update(spk.getEncoded());
249 sig.update(sharedSecret);
250 sig.verify((byte[]) readObject());
251
252 return spk;
253 } catch (ClassNotFoundException e) {
254 throw new Error(e); // impossible
255 }
256 }
257
258 public void close() throws IOException {
259 in.close();
260 out.close();
261 }
262 }
263