1 /* AbstractHandshake.java -- abstract handshake handler.
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is a part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 USA
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version.  */
37 
38 
39 package gnu.javax.net.ssl.provider;
40 
41 import gnu.classpath.debug.Component;
42 import gnu.classpath.debug.SystemLogger;
43 import gnu.java.security.action.GetSecurityPropertyAction;
44 import gnu.java.security.prng.IRandom;
45 import gnu.java.security.prng.LimitReachedException;
46 import gnu.java.security.util.ByteArray;
47 import gnu.javax.security.auth.callback.CertificateCallback;
48 import gnu.javax.security.auth.callback.DefaultCallbackHandler;
49 
50 import java.nio.ByteBuffer;
51 import java.security.AccessController;
52 import java.security.DigestException;
53 import java.security.InvalidAlgorithmParameterException;
54 import java.security.InvalidKeyException;
55 import java.security.KeyManagementException;
56 import java.security.MessageDigest;
57 import java.security.NoSuchAlgorithmException;
58 import java.security.PrivilegedExceptionAction;
59 import java.security.SecureRandom;
60 import java.security.cert.CertificateException;
61 import java.security.cert.X509Certificate;
62 import java.util.Arrays;
63 import java.util.HashMap;
64 import java.util.LinkedList;
65 import java.util.zip.Deflater;
66 import java.util.zip.Inflater;
67 
68 import javax.crypto.Cipher;
69 import javax.crypto.KeyAgreement;
70 import javax.crypto.Mac;
71 import javax.crypto.NoSuchPaddingException;
72 import javax.crypto.SecretKey;
73 import javax.crypto.interfaces.DHPrivateKey;
74 import javax.crypto.interfaces.DHPublicKey;
75 import javax.crypto.spec.IvParameterSpec;
76 import javax.crypto.spec.SecretKeySpec;
77 import javax.net.ssl.SSLEngineResult;
78 import javax.net.ssl.SSLException;
79 import javax.net.ssl.X509TrustManager;
80 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
81 import javax.security.auth.callback.Callback;
82 import javax.security.auth.callback.CallbackHandler;
83 import javax.security.auth.callback.ConfirmationCallback;
84 
85 /**
86  * The base interface for handshake implementations. Concrete
87  * subclasses of this class (one for the server, one for the client)
88  * handle the HANDSHAKE content-type in communications.
89  */
90 public abstract class AbstractHandshake
91 {
92   protected static final SystemLogger logger = SystemLogger.SYSTEM;
93 
94   /**
95    * "server finished" -- TLS 1.0 and later
96    */
97   protected static final byte[] SERVER_FINISHED
98     = new byte[] {
99       115, 101, 114, 118, 101, 114,  32, 102, 105, 110, 105, 115,
100       104, 101, 100
101     };
102 
103   /**
104    * "client finished" -- TLS 1.0 and later
105    */
106   protected static final byte[] CLIENT_FINISHED
107     = new byte[] {
108        99, 108, 105, 101, 110, 116,  32, 102, 105, 110, 105, 115,
109       104, 101, 100
110     };
111 
112   /**
113    * "key expansion" -- TLS 1.0 and later
114    */
115   private static final byte[] KEY_EXPANSION =
116     new byte[] { 107, 101, 121,  32, 101, 120, 112,
117                   97, 110, 115, 105, 111, 110 };
118 
119   /**
120    * "master secret" -- TLS 1.0 and later
121    */
122   private static final byte[] MASTER_SECRET
123     = new byte[] {
124       109,  97, 115, 116, 101, 114,  32, 115, 101,  99, 114, 101, 116
125     };
126 
127   /**
128    * "client write key" -- TLS 1.0 exportable whitener.
129    */
130   private static final byte[] CLIENT_WRITE_KEY
131     = new byte[] {
132        99, 108, 105, 101, 110, 116,  32, 119, 114, 105, 116, 101,  32, 107,
133       101, 121
134     };
135 
136   /**
137    * "server write key" -- TLS 1.0 exportable whitener.
138    */
139   private static final byte[] SERVER_WRITE_KEY
140     = new byte[] {
141       115, 101, 114, 118, 101, 114,  32, 119, 114, 105, 116, 101,  32, 107,
142       101, 121
143     };
144 
145   private static final byte[] IV_BLOCK
146     = new byte[] {
147        73,  86,  32,  98, 108, 111,  99, 107
148     };
149 
150   /**
151    * SSL 3.0; the string "CLNT"
152    */
153   private static final byte[] SENDER_CLIENT
154     = new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
155 
156   /**
157    * SSL 3.0; the string "SRVR"
158    */
159   private static final byte[] SENDER_SERVER
160     = new byte[] { 0x53, 0x52, 0x56, 0x52 };
161 
162   /**
163    * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
164    * times.
165    */
166   protected static final byte[] PAD1 = new byte[48];
167 
168   /**
169    * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
170    * times.
171    */
172   protected static final byte[] PAD2 = new byte[48];
173 
174   static
175   {
Arrays.fill(PAD1, SSLHMac.PAD1)176     Arrays.fill(PAD1, SSLHMac.PAD1);
Arrays.fill(PAD2, SSLHMac.PAD2)177     Arrays.fill(PAD2, SSLHMac.PAD2);
178   }
179 
180   /**
181    * The currently-read handshake messages. There may be zero, or
182    * multiple, handshake messages in this buffer.
183    */
184   protected ByteBuffer handshakeBuffer;
185 
186   /**
187    * The offset into `handshakeBuffer' where the first unread
188    * handshake message resides.
189    */
190   protected int handshakeOffset;
191 
192   protected MessageDigest sha;
193   protected MessageDigest md5;
194 
195   protected final SSLEngineImpl engine;
196   protected KeyAgreement keyAgreement;
197   protected byte[] preMasterSecret;
198   protected InputSecurityParameters inParams;
199   protected OutputSecurityParameters outParams;
200   protected LinkedList<DelegatedTask> tasks;
201   protected Random serverRandom;
202   protected Random clientRandom;
203   protected CompressionMethod compression;
204 
AbstractHandshake(SSLEngineImpl engine)205   protected AbstractHandshake(SSLEngineImpl engine)
206     throws NoSuchAlgorithmException
207   {
208     this.engine = engine;
209     sha = MessageDigest.getInstance("SHA-1");
210     md5 = MessageDigest.getInstance("MD5");
211     tasks = new LinkedList<DelegatedTask>();
212   }
213 
214   /**
215    * Handles the next input message in the handshake. This is called
216    * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap}
217    * for a message with content-type HANDSHAKE.
218    *
219    * @param record The input record. The callee should not assume that
220    * the record's buffer is writable, and should not try to use it for
221    * output or temporary storage.
222    * @return An {@link SSLEngineResult} describing the result.
223    */
handleInput(ByteBuffer fragment)224   public final HandshakeStatus handleInput (ByteBuffer fragment)
225     throws SSLException
226   {
227     if (!tasks.isEmpty())
228       return HandshakeStatus.NEED_TASK;
229 
230     HandshakeStatus status = status();
231     if (status != HandshakeStatus.NEED_UNWRAP)
232       return status;
233 
234     // Try to read another...
235     if (!pollHandshake(fragment))
236       return HandshakeStatus.NEED_UNWRAP;
237 
238     while (hasMessage() && status != HandshakeStatus.NEED_WRAP)
239       {
240         int pos = handshakeOffset;
241         status = implHandleInput();
242         int len = handshakeOffset - pos;
243         if (len == 0)
244           {
245             // Don't bother; the impl is just telling us to go around
246             // again.
247             continue;
248           }
249         if (doHash())
250           {
251             if (Debug.DEBUG)
252               logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}",
253                           Util.hexDump((ByteBuffer) handshakeBuffer
254                                        .duplicate().position(pos)
255                                        .limit(pos+len), " >> "));
256             sha.update((ByteBuffer) handshakeBuffer.duplicate()
257                        .position(pos).limit(pos+len));
258             md5.update((ByteBuffer) handshakeBuffer.duplicate()
259                        .position(pos).limit(pos+len));
260           }
261       }
262     return status;
263   }
264 
265   /**
266    * Called to process more handshake data. This method will be called
267    * repeatedly while there is remaining handshake data, and while the
268    * status is
269    * @return
270    * @throws SSLException
271    */
implHandleInput()272   protected abstract HandshakeStatus implHandleInput()
273     throws SSLException;
274 
275   /**
276    * Produce more handshake output. This is called in response to a
277    * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake
278    * is still in progress.
279    *
280    * @param record The output record; the callee should put its output
281    * handshake message (or a part of it) in the argument's
282    * <code>fragment</code>, and should set the record length
283    * appropriately.
284    * @return An {@link SSLEngineResult} describing the result.
285    */
handleOutput(ByteBuffer fragment)286   public final HandshakeStatus handleOutput (ByteBuffer fragment)
287     throws SSLException
288   {
289     if (!tasks.isEmpty())
290       return HandshakeStatus.NEED_TASK;
291 
292     int orig = fragment.position();
293     SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment);
294     if (doHash())
295       {
296         if (Debug.DEBUG)
297           logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}",
298                       Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> "));
299         sha.update((ByteBuffer) fragment.duplicate().flip().position(orig));
300         md5.update((ByteBuffer) fragment.duplicate().flip().position(orig));
301       }
302     return status;
303   }
304 
305   /**
306    * Called to implement the underlying output handling. The callee should
307    * attempt to fill the given buffer as much as it can; this can include
308    * multiple, and even partial, handshake messages.
309    *
310    * @param fragment The buffer the callee should write handshake messages to.
311    * @return The new status of the handshake.
312    * @throws SSLException If an error occurs processing the output message.
313    */
implHandleOutput(ByteBuffer fragment)314   protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment)
315     throws SSLException;
316 
317   /**
318    * Return a new instance of input security parameters, initialized with
319    * the session key. It is, of course, only valid to invoke this method
320    * once the handshake is complete, and the session keys established.
321    *
322    * <p>In the presence of a well-behaving peer, this should be called once
323    * the <code>ChangeCipherSpec</code> message is recieved.
324    *
325    * @return The input parameters for the newly established session.
326    * @throws SSLException If the handshake is not complete.
327    */
getInputParams()328   final InputSecurityParameters getInputParams() throws SSLException
329   {
330     checkKeyExchange();
331     return inParams;
332   }
333 
334   /**
335    * Return a new instance of output security parameters, initialized with
336    * the session key. This should be called after the
337    * <code>ChangeCipherSpec</code> message is sent to the peer.
338    *
339    * @return The output parameters for the newly established session.
340    * @throws SSLException If the handshake is not complete.
341    */
getOutputParams()342   final OutputSecurityParameters getOutputParams() throws SSLException
343   {
344     checkKeyExchange();
345     return outParams;
346   }
347 
348   /**
349    * Fetch a delegated task waiting to run, if any.
350    *
351    * @return The task.
352    */
getTask()353   final Runnable getTask()
354   {
355     if (tasks.isEmpty())
356       return null;
357     return tasks.removeFirst();
358   }
359 
360   /**
361    * Used by the skeletal code to query the current status of the handshake.
362    * This <em>should</em> be the same value as returned by the previous call
363    * to {@link #implHandleOutput(ByteBuffer)} or {@link
364    *  #implHandleInput(ByteBuffer)}.
365    *
366    * @return The current handshake status.
367    */
status()368   abstract HandshakeStatus status();
369 
370   /**
371    * Check if the key exchange completed successfully, throwing an exception
372    * if not.
373    *
374    * <p>Note that we assume that the caller of our SSLEngine is correct, and
375    * that they did run the delegated tasks that encapsulate the key exchange.
376    * What we are primarily checking, therefore, is that no error occurred in the
377    * key exchange operation itself.
378    *
379    * @throws SSLException If the key exchange did not complete successfully.
380    */
checkKeyExchange()381   abstract void checkKeyExchange() throws SSLException;
382 
383   /**
384    * Handle an SSLv2 client hello. This is only used by SSL servers.
385    *
386    * @param hello The hello message.
387    */
handleV2Hello(ByteBuffer hello)388   abstract void handleV2Hello(ByteBuffer hello) throws SSLException;
389 
390   /**
391    * Attempt to read the next handshake message from the given
392    * record. If only a partial handshake message is available, then
393    * this method saves the incoming bytes and returns false. If a
394    * complete handshake is read, or if there was one buffered in the
395    * handshake buffer, this method returns true, and `handshakeBuffer'
396    * can be used to read the handshake.
397    *
398    * @param record The input record.
399    * @return True if a complete handshake is present in the buffer;
400    * false if only a partial one.
401    */
pollHandshake(final ByteBuffer fragment)402   protected boolean pollHandshake (final ByteBuffer fragment)
403   {
404     // Allocate space for the new fragment.
405     if (handshakeBuffer == null
406         || handshakeBuffer.remaining() < fragment.remaining())
407       {
408         // We need space for anything still unread in the handshake
409         // buffer...
410         int len = ((handshakeBuffer == null) ? 0
411                    : handshakeBuffer.position() - handshakeOffset);
412 
413         // Plus room for the incoming record.
414         len += fragment.remaining();
415         reallocateBuffer(len);
416       }
417 
418     if (Debug.DEBUG)
419       logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}",
420                   fragment, handshakeBuffer);
421 
422     // Put the fragment into the buffer.
423     handshakeBuffer.put(fragment);
424 
425     return hasMessage();
426   }
427 
doHash()428   protected boolean doHash()
429   {
430     return true;
431   }
432 
433   /**
434    * Tell if the handshake buffer currently has a full handshake
435    * message.
436    */
hasMessage()437   protected boolean hasMessage()
438   {
439     if (handshakeBuffer == null)
440       return false;
441     ByteBuffer tmp = handshakeBuffer.duplicate();
442     tmp.flip();
443     tmp.position(handshakeOffset);
444     if (Debug.DEBUG)
445       logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}",
446                   handshakeBuffer, tmp);
447     if (tmp.remaining() < 4)
448       return false;
449     Handshake handshake = new Handshake(tmp.slice());
450     if (Debug.DEBUG)
451       logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}",
452                   handshake.length(), tmp.remaining());
453     return (handshake.length() <= tmp.remaining() - 4);
454   }
455 
456   /**
457    * Reallocate the handshake buffer so it can hold `totalLen'
458    * bytes. The smallest buffer allocated is 1024 bytes, and the size
459    * doubles from there until the buffer is sufficiently large.
460    */
reallocateBuffer(final int totalLen)461   private void reallocateBuffer (final int totalLen)
462   {
463     int len = handshakeBuffer == null ? -1
464                                       : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset);
465     if (len >= totalLen)
466       {
467         // Big enough; no need to reallocate; but maybe shift the contents
468         // down.
469         if (handshakeOffset > 0)
470           {
471             handshakeBuffer.flip().position(handshakeOffset);
472             handshakeBuffer.compact();
473             handshakeOffset = 0;
474           }
475         return;
476       }
477 
478     // Start at 1K (probably the system's page size). Double the size
479     // from there.
480     len = 1024;
481     while (len < totalLen)
482       len = len << 1;
483     ByteBuffer newBuf = ByteBuffer.allocate (len);
484 
485     // Copy the unread bytes from the old buffer.
486     if (handshakeBuffer != null)
487       {
488         handshakeBuffer.flip ();
489         handshakeBuffer.position(handshakeOffset);
490         newBuf.put(handshakeBuffer);
491       }
492     handshakeBuffer = newBuf;
493 
494     // We just put only unread handshake messages in the new buffer;
495     // the offset of the next one is now zero.
496     handshakeOffset = 0;
497   }
498 
499   /**
500    * Generate a certificate verify message for SSLv3. In SSLv3, a different
501    * algorithm was used to generate this value was subtly different than
502    * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is
503    * just the digest over the handshake messages.
504    *
505    * <p>SSLv3 uses the algorithm:
506    *
507    * <pre>
508 CertificateVerify.signature.md5_hash
509   MD5(master_secret + pad_2 +
510       MD5(handshake_messages + master_secret + pad_1));
511 Certificate.signature.sha_hash
512   SHA(master_secret + pad_2 +
513       SHA(handshake_messages + master_secret + pad_1));</pre>
514    *
515    * @param md5 The running MD5 hash of the handshake.
516    * @param sha The running SHA-1 hash of the handshake.
517    * @param session The current session being negotiated.
518    * @return The computed to-be-signed value.
519    */
genV3CertificateVerify(MessageDigest md5, MessageDigest sha, SessionImpl session)520   protected byte[] genV3CertificateVerify(MessageDigest md5,
521                                           MessageDigest sha,
522                                           SessionImpl session)
523   {
524     byte[] md5value = null;
525     if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
526       {
527         md5.update(session.privateData.masterSecret);
528         md5.update(PAD1, 0, 48);
529         byte[] tmp = md5.digest();
530         md5.reset();
531         md5.update(session.privateData.masterSecret);
532         md5.update(PAD2, 0, 48);
533         md5.update(tmp);
534         md5value = md5.digest();
535       }
536 
537     sha.update(session.privateData.masterSecret);
538     sha.update(PAD1, 0, 40);
539     byte[] tmp = sha.digest();
540     sha.reset();
541     sha.update(session.privateData.masterSecret);
542     sha.update(PAD2, 0, 40);
543     sha.update(tmp);
544     byte[] shavalue = sha.digest();
545 
546     if (md5value != null)
547       return Util.concat(md5value, shavalue);
548 
549     return shavalue;
550   }
551 
552   /**
553    * Generate the session keys from the computed master secret.
554    *
555    * @param clientRandom The client's nonce.
556    * @param serverRandom The server's nonce.
557    * @param session The session being established.
558    * @return The derived keys.
559    */
generateKeys(Random clientRandom, Random serverRandom, SessionImpl session)560   protected byte[][] generateKeys(Random clientRandom, Random serverRandom,
561                                   SessionImpl session)
562   {
563     int maclen = 20; // SHA-1.
564     if (session.suite.macAlgorithm() == MacAlgorithm.MD5)
565       maclen = 16;
566     int ivlen = 0;
567     if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES
568         || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede)
569       ivlen = 8;
570     if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES)
571       ivlen = 16;
572     int keylen = session.suite.keyLength();
573 
574     byte[][] keys = new byte[6][];
575     keys[0] = new byte[maclen]; // client_write_MAC_secret
576     keys[1] = new byte[maclen]; // server_write_MAC_secret
577     keys[2] = new byte[keylen]; // client_write_key
578     keys[3] = new byte[keylen]; // server_write_key
579     keys[4] = new byte[ivlen];  // client_write_iv
580     keys[5] = new byte[ivlen];  // server_write_iv
581 
582     IRandom prf = null;
583     if (session.version == ProtocolVersion.SSL_3)
584       {
585         byte[] seed = new byte[clientRandom.length()
586                                + serverRandom.length()];
587         serverRandom.buffer().get(seed, 0, serverRandom.length());
588         clientRandom.buffer().get(seed, serverRandom.length(),
589                                   clientRandom.length());
590         prf = new SSLRandom();
591         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
592         attr.put(SSLRandom.SECRET, session.privateData.masterSecret);
593         attr.put(SSLRandom.SEED, seed);
594         prf.init(attr);
595       }
596     else
597       {
598         byte[] seed = new byte[KEY_EXPANSION.length
599                                + clientRandom.length()
600                                + serverRandom.length()];
601         System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length);
602         serverRandom.buffer().get(seed, KEY_EXPANSION.length,
603                                   serverRandom.length());
604         clientRandom.buffer().get(seed, (KEY_EXPANSION.length
605                                          + serverRandom.length()),
606                                   clientRandom.length());
607 
608         prf = new TLSRandom();
609         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
610         attr.put(TLSRandom.SECRET, session.privateData.masterSecret);
611         attr.put(TLSRandom.SEED, seed);
612         prf.init(attr);
613       }
614 
615     try
616       {
617         prf.nextBytes(keys[0], 0, keys[0].length);
618         prf.nextBytes(keys[1], 0, keys[1].length);
619         prf.nextBytes(keys[2], 0, keys[2].length);
620         prf.nextBytes(keys[3], 0, keys[3].length);
621 
622         if (session.suite.isExportable())
623           {
624             if (session.version == ProtocolVersion.SSL_3)
625               {
626                 MessageDigest md5 = MessageDigest.getInstance("MD5");
627                 md5.update(clientRandom.buffer());
628                 md5.update(serverRandom.buffer());
629                 byte[] d = md5.digest();
630                 System.arraycopy(d, 0, keys[4], 0, keys[4].length);
631 
632                 md5.reset();
633                 md5.update(serverRandom.buffer());
634                 md5.update(clientRandom.buffer());
635                 d = md5.digest();
636                 System.arraycopy(d, 0, keys[5], 0, keys[5].length);
637 
638                 md5.reset();
639                 md5.update(keys[2]);
640                 md5.update(clientRandom.buffer());
641                 md5.update(serverRandom.buffer());
642                 keys[2] = Util.trim(md5.digest(), 8);
643 
644                 md5.reset();
645                 md5.update(keys[3]);
646                 md5.update(serverRandom.buffer());
647                 md5.update(clientRandom.buffer());
648                 keys[3] = Util.trim(md5.digest(), 8);
649               }
650             else
651               {
652                 TLSRandom prf2 = new TLSRandom();
653                 HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
654                 attr.put(TLSRandom.SECRET, keys[2]);
655                 byte[] seed = new byte[CLIENT_WRITE_KEY.length +
656                                        clientRandom.length() +
657                                        serverRandom.length()];
658                 System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0,
659                                  CLIENT_WRITE_KEY.length);
660                 clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length,
661                                           clientRandom.length());
662                 serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length
663                                           + clientRandom.length(),
664                                           serverRandom.length());
665                 attr.put(TLSRandom.SEED, seed);
666                 prf2.init(attr);
667                 keys[2] = new byte[8];
668                 prf2.nextBytes(keys[2], 0, keys[2].length);
669 
670                 attr.put(TLSRandom.SECRET, keys[3]);
671                 seed = new byte[SERVER_WRITE_KEY.length +
672                                 serverRandom.length() +
673                                 clientRandom.length()];
674                 System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0,
675                                  SERVER_WRITE_KEY.length);
676                 serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length,
677                                           serverRandom.length());
678                 clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length
679                                           + serverRandom.length(),
680                                           + clientRandom.length());
681                 attr.put(TLSRandom.SEED, seed);
682                 prf2.init(attr);
683                 keys[3] = new byte[8];
684                 prf2.nextBytes(keys[3], 0, keys[3].length);
685 
686                 attr.put(TLSRandom.SECRET, new byte[0]);
687                 seed = new byte[IV_BLOCK.length +
688                                 clientRandom.length() +
689                                 serverRandom.length()];
690                 System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length);
691                 clientRandom.buffer().get(seed, IV_BLOCK.length,
692                                           clientRandom.length());
693                 serverRandom.buffer().get(seed, IV_BLOCK.length
694                                           + clientRandom.length(),
695                                           serverRandom.length());
696                 attr.put(TLSRandom.SEED, seed);
697                 prf2.init(attr);
698                 prf2.nextBytes(keys[4], 0, keys[4].length);
699                 prf2.nextBytes(keys[5], 0, keys[5].length);
700               }
701           }
702         else
703           {
704             prf.nextBytes(keys[4], 0, keys[4].length);
705             prf.nextBytes(keys[5], 0, keys[5].length);
706           }
707       }
708     catch (LimitReachedException lre)
709       {
710         // Won't happen with our implementation.
711         throw new Error(lre);
712       }
713     catch (NoSuchAlgorithmException nsae)
714       {
715         throw new Error(nsae);
716       }
717 
718     if (Debug.DEBUG_KEY_EXCHANGE)
719       logger.logv(Component.SSL_KEY_EXCHANGE,
720                   "keys generated;\n  [0]: {0}\n  [1]: {1}\n  [2]: {2}\n" +
721                   "  [3]: {3}\n  [4]: {4}\n  [5]: {5}",
722                   Util.toHexString(keys[0], ':'),
723                   Util.toHexString(keys[1], ':'),
724                   Util.toHexString(keys[2], ':'),
725                   Util.toHexString(keys[3], ':'),
726                   Util.toHexString(keys[4], ':'),
727                   Util.toHexString(keys[5], ':'));
728     return keys;
729   }
730 
731   /**
732    * Generate a "finished" message. The hashes passed in are modified
733    * by this function, so they should be clone copies of the digest if
734    * the hash function needs to be used more.
735    *
736    * @param md5 The MD5 computation.
737    * @param sha The SHA-1 computation.
738    * @param isClient Whether or not the client-side finished message is
739    *  being computed.
740    * @param session The current session.
741    * @return A byte buffer containing the computed finished message.
742    */
generateFinished(MessageDigest md5, MessageDigest sha, boolean isClient, SessionImpl session)743   protected ByteBuffer generateFinished(MessageDigest md5,
744                                         MessageDigest sha,
745                                         boolean isClient,
746                                         SessionImpl session)
747   {
748     ByteBuffer finishedBuffer = null;
749     if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
750       {
751         finishedBuffer = ByteBuffer.allocate(12);
752         TLSRandom prf = new TLSRandom();
753         byte[] md5val = md5.digest();
754         byte[] shaval = sha.digest();
755         if (Debug.DEBUG)
756           logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}",
757                       Util.toHexString(md5val, ':'),
758                       Util.toHexString(shaval, ':'));
759         byte[] seed = new byte[CLIENT_FINISHED.length
760                                + md5val.length
761                                + shaval.length];
762         if (isClient)
763           System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length);
764         else
765           System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length);
766         System.arraycopy(md5val, 0,
767                          seed, CLIENT_FINISHED.length,
768                          md5val.length);
769         System.arraycopy(shaval, 0,
770                          seed, CLIENT_FINISHED.length + md5val.length,
771                          shaval.length);
772         HashMap<String, Object> params = new HashMap<String, Object>(2);
773         params.put(TLSRandom.SECRET, session.privateData.masterSecret);
774         params.put(TLSRandom.SEED, seed);
775         prf.init(params);
776         byte[] buf = new byte[12];
777         prf.nextBytes(buf, 0, buf.length);
778         finishedBuffer.put(buf).position(0);
779       }
780     else
781       {
782         // The SSLv3 algorithm is:
783         //
784         //   enum { client(0x434C4E54), server(0x53525652) } Sender;
785         //
786         //   struct {
787         //     opaque md5_hash[16];
788         //     opaque sha_hash[20];
789         //   } Finished;
790         //
791         //   md5_hash       MD5(master_secret + pad2 +
792         //                      MD5(handshake_messages + Sender +
793         //                          master_secret + pad1));
794         //   sha_hash        SHA(master_secret + pad2 +
795         //                       SHA(handshake_messages + Sender +
796         //                           master_secret + pad1));
797         //
798 
799         finishedBuffer = ByteBuffer.allocate(36);
800 
801         md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
802         md5.update(session.privateData.masterSecret);
803         md5.update(PAD1);
804 
805         byte[] tmp = md5.digest();
806         md5.reset();
807         md5.update(session.privateData.masterSecret);
808         md5.update(PAD2);
809         md5.update(tmp);
810         finishedBuffer.put(md5.digest());
811 
812         sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
813         sha.update(session.privateData.masterSecret);
814         sha.update(PAD1, 0, 40);
815 
816         tmp = sha.digest();
817         sha.reset();
818         sha.update(session.privateData.masterSecret);
819         sha.update(PAD2, 0, 40);
820         sha.update(tmp);
821         finishedBuffer.put(sha.digest()).position(0);
822       }
823     return finishedBuffer;
824   }
825 
initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)826   protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)
827     throws SSLException
828   {
829     try
830       {
831         keyAgreement = KeyAgreement.getInstance("DH");
832         keyAgreement.init(dhKey, random);
833       }
834     catch (InvalidKeyException ike)
835       {
836         throw new SSLException(ike);
837       }
838     catch (NoSuchAlgorithmException nsae)
839       {
840         throw new SSLException(nsae);
841       }
842   }
843 
generateMasterSecret(Random clientRandom, Random serverRandom, SessionImpl session)844   protected void generateMasterSecret(Random clientRandom,
845                                       Random serverRandom,
846                                       SessionImpl session)
847     throws SSLException
848   {
849     assert(clientRandom != null);
850     assert(serverRandom != null);
851     assert(session != null);
852 
853     if (Debug.DEBUG_KEY_EXCHANGE)
854       logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
855                   new ByteArray(preMasterSecret));
856 
857     if (session.version == ProtocolVersion.SSL_3)
858       {
859         try
860           {
861             MessageDigest _md5 = MessageDigest.getInstance("MD5");
862             MessageDigest _sha = MessageDigest.getInstance("SHA");
863             session.privateData.masterSecret = new byte[48];
864 
865             _sha.update((byte) 'A');
866             _sha.update(preMasterSecret);
867             _sha.update(clientRandom.buffer());
868             _sha.update(serverRandom.buffer());
869             _md5.update(preMasterSecret);
870             _md5.update(_sha.digest());
871             _md5.digest(session.privateData.masterSecret, 0, 16);
872 
873             _sha.update((byte) 'B');
874             _sha.update((byte) 'B');
875             _sha.update(preMasterSecret);
876             _sha.update(clientRandom.buffer());
877             _sha.update(serverRandom.buffer());
878             _md5.update(preMasterSecret);
879             _md5.update(_sha.digest());
880             _md5.digest(session.privateData.masterSecret, 16, 16);
881 
882             _sha.update((byte) 'C');
883             _sha.update((byte) 'C');
884             _sha.update((byte) 'C');
885             _sha.update(preMasterSecret);
886             _sha.update(clientRandom.buffer());
887             _sha.update(serverRandom.buffer());
888             _md5.update(preMasterSecret);
889             _md5.update(_sha.digest());
890             _md5.digest(session.privateData.masterSecret, 32, 16);
891           }
892         catch (DigestException de)
893           {
894             throw new SSLException(de);
895           }
896         catch (NoSuchAlgorithmException nsae)
897           {
898             throw new SSLException(nsae);
899           }
900       }
901     else // TLSv1.0 and later
902       {
903         byte[] seed = new byte[clientRandom.length()
904                                + serverRandom.length()
905                                + MASTER_SECRET.length];
906         System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length);
907         clientRandom.buffer().get(seed, MASTER_SECRET.length,
908                                   clientRandom.length());
909         serverRandom.buffer().get(seed,
910                                   MASTER_SECRET.length + clientRandom.length(),
911                                   serverRandom.length());
912         TLSRandom prf = new TLSRandom();
913         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
914         attr.put(TLSRandom.SECRET, preMasterSecret);
915         attr.put(TLSRandom.SEED, seed);
916         prf.init(attr);
917 
918         session.privateData.masterSecret = new byte[48];
919         prf.nextBytes(session.privateData.masterSecret, 0, 48);
920       }
921 
922     if (Debug.DEBUG_KEY_EXCHANGE)
923       logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}",
924                  new ByteArray(session.privateData.masterSecret));
925 
926     // Wipe out the preMasterSecret.
927     for (int i = 0; i < preMasterSecret.length; i++)
928       preMasterSecret[i] = 0;
929   }
930 
setupSecurityParameters(byte[][] keys, boolean isClient, SSLEngineImpl engine, CompressionMethod compression)931   protected void setupSecurityParameters(byte[][] keys, boolean isClient,
932                                          SSLEngineImpl engine,
933                                          CompressionMethod compression)
934     throws SSLException
935   {
936     assert(keys.length == 6);
937     assert(engine != null);
938     assert(compression != null);
939 
940     try
941       {
942         CipherSuite s = engine.session().suite;
943         Cipher inCipher = s.cipher();
944         Mac inMac = s.mac(engine.session().version);
945         Inflater inflater = (compression == CompressionMethod.ZLIB
946                              ? new Inflater() : null);
947         inCipher.init(Cipher.DECRYPT_MODE,
948                       new SecretKeySpec(keys[isClient ? 3 : 2],
949                                         s.cipherAlgorithm().toString()),
950                       new IvParameterSpec(keys[isClient ? 5 : 4]));
951         inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0],
952                                      inMac.getAlgorithm()));
953         inParams = new InputSecurityParameters(inCipher, inMac,
954                                                inflater,
955                                                engine.session(), s);
956 
957         Cipher outCipher = s.cipher();
958         Mac outMac = s.mac(engine.session().version);
959         Deflater deflater = (compression == CompressionMethod.ZLIB
960                              ? new Deflater() : null);
961         outCipher.init(Cipher.ENCRYPT_MODE,
962                        new SecretKeySpec(keys[isClient ? 2 : 3],
963                                          s.cipherAlgorithm().toString()),
964                        new IvParameterSpec(keys[isClient ? 4 : 5]));
965         outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1],
966                                       outMac.getAlgorithm()));
967         outParams = new OutputSecurityParameters(outCipher, outMac,
968                                                  deflater,
969                                                  engine.session(), s);
970       }
971     catch (InvalidAlgorithmParameterException iape)
972       {
973         throw new SSLException(iape);
974       }
975     catch (InvalidKeyException ike)
976       {
977         throw new SSLException(ike);
978       }
979     catch (NoSuchAlgorithmException nsae)
980       {
981         throw new SSLException(nsae);
982       }
983     catch (NoSuchPaddingException nspe)
984       {
985         throw new SSLException(nspe);
986       }
987   }
988 
generatePSKSecret(String identity, byte[] otherkey, boolean isClient)989   protected void generatePSKSecret(String identity, byte[] otherkey,
990                                    boolean isClient)
991     throws SSLException
992   {
993     SecretKey key = null;
994     try
995       {
996         key = engine.contextImpl.pskManager.getKey(identity);
997       }
998     catch (KeyManagementException kme)
999       {
1000       }
1001     if (key != null)
1002       {
1003         byte[] keyb = key.getEncoded();
1004         if (otherkey == null)
1005           {
1006             otherkey = new byte[keyb.length];
1007           }
1008         preMasterSecret = new byte[otherkey.length + keyb.length + 4];
1009         preMasterSecret[0] = (byte) (otherkey.length >>> 8);
1010         preMasterSecret[1] = (byte)  otherkey.length;
1011         System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length);
1012         preMasterSecret[otherkey.length + 2]
1013           = (byte) (keyb.length >>> 8);
1014         preMasterSecret[otherkey.length + 3]
1015           = (byte)  keyb.length;
1016         System.arraycopy(keyb, 0, preMasterSecret,
1017                          otherkey.length + 4, keyb.length);
1018       }
1019     else
1020       {
1021         // Generate a random, fake secret.
1022         preMasterSecret = new byte[8];
1023         preMasterSecret[1] = 2;
1024         preMasterSecret[5] = 2;
1025         preMasterSecret[6] = (byte) engine.session().random().nextInt();
1026         preMasterSecret[7] = (byte) engine.session().random().nextInt();
1027       }
1028 
1029     if (Debug.DEBUG_KEY_EXCHANGE)
1030       logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}",
1031                   identity, key);
1032 
1033     generateMasterSecret(clientRandom, serverRandom,
1034                          engine.session());
1035     byte[][] keys = generateKeys(clientRandom, serverRandom,
1036                                  engine.session());
1037     setupSecurityParameters(keys, isClient, engine, compression);
1038   }
1039 
1040   protected class DHPhase extends DelegatedTask
1041   {
1042     private final DHPublicKey key;
1043     private final boolean full;
1044 
DHPhase(DHPublicKey key)1045     protected DHPhase(DHPublicKey key)
1046     {
1047       this(key, true);
1048     }
1049 
DHPhase(DHPublicKey key, boolean full)1050     protected DHPhase(DHPublicKey key, boolean full)
1051     {
1052       this.key = key;
1053       this.full = full;
1054     }
1055 
implRun()1056     protected void implRun() throws InvalidKeyException, SSLException
1057     {
1058       keyAgreement.doPhase(key, true);
1059       preMasterSecret = keyAgreement.generateSecret();
1060       if (full)
1061         {
1062           generateMasterSecret(clientRandom, serverRandom, engine.session());
1063           byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1064           setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression);
1065         }
1066     }
1067   }
1068 
1069   protected class CertVerifier extends DelegatedTask
1070   {
1071     private final boolean clientSide;
1072     private final X509Certificate[] chain;
1073     private boolean verified;
1074 
CertVerifier(boolean clientSide, X509Certificate[] chain)1075     protected CertVerifier(boolean clientSide, X509Certificate[] chain)
1076     {
1077       this.clientSide = clientSide;
1078       this.chain = chain;
1079     }
1080 
verified()1081     boolean verified()
1082     {
1083       return verified;
1084     }
1085 
implRun()1086     protected void implRun()
1087     {
1088       X509TrustManager tm = engine.contextImpl.trustManager;
1089       if (clientSide)
1090         {
1091           try
1092             {
1093               tm.checkServerTrusted(chain, null);
1094               verified = true;
1095             }
1096           catch (CertificateException ce)
1097             {
1098               if (Debug.DEBUG)
1099                 logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce);
1100               // For client connections, ask the user if the certificate is OK.
1101               CallbackHandler verify = new DefaultCallbackHandler();
1102               GetSecurityPropertyAction gspa
1103                 = new GetSecurityPropertyAction("jessie.certificate.handler");
1104               String clazz = AccessController.doPrivileged(gspa);
1105               try
1106                 {
1107                   ClassLoader cl =
1108                     AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
1109                       {
1110                         public ClassLoader run() throws Exception
1111                         {
1112                           return ClassLoader.getSystemClassLoader();
1113                         }
1114                       });
1115                   verify = (CallbackHandler) cl.loadClass(clazz).newInstance();
1116                 }
1117               catch (Exception x)
1118                 {
1119                   // Ignore.
1120                   if (Debug.DEBUG)
1121                     logger.log(Component.SSL_DELEGATED_TASK,
1122                                "callback handler loading", x);
1123                 }
1124               // XXX Internationalize
1125               CertificateCallback confirm =
1126                 new CertificateCallback(chain[0],
1127                 "The server's certificate could not be verified. There is no proof " +
1128                 "that this server is who it claims to be, or that their certificate " +
1129                 "is valid. Do you wish to continue connecting? ");
1130 
1131               try
1132                 {
1133                   verify.handle(new Callback[] { confirm });
1134                   verified = confirm.getSelectedIndex() == ConfirmationCallback.YES;
1135                 }
1136               catch (Exception x)
1137                 {
1138                   if (Debug.DEBUG)
1139                     logger.log(Component.SSL_DELEGATED_TASK,
1140                                "callback handler exception", x);
1141                   verified = false;
1142                 }
1143             }
1144         }
1145       else
1146         {
1147           try
1148             {
1149               tm.checkClientTrusted(chain, null);
1150             }
1151           catch (CertificateException ce)
1152             {
1153               verified = false;
1154             }
1155         }
1156 
1157       if (verified)
1158         engine.session().setPeerVerified(true);
1159     }
1160   }
1161 
1162   protected class DHE_PSKGen extends DelegatedTask
1163   {
1164     private final DHPublicKey dhKey;
1165     private final SecretKey psKey;
1166     private final boolean isClient;
1167 
DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)1168     protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)
1169     {
1170       this.dhKey = dhKey;
1171       this.psKey = psKey;
1172       this.isClient = isClient;
1173     }
1174 
1175     /* (non-Javadoc)
1176      * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun()
1177      */
implRun()1178     @Override protected void implRun() throws Throwable
1179     {
1180       keyAgreement.doPhase(dhKey, true);
1181       byte[] dhSecret = keyAgreement.generateSecret();
1182       byte[] psSecret = null;
1183       if (psKey != null)
1184         psSecret = psKey.getEncoded();
1185       else
1186         {
1187           psSecret = new byte[8];
1188           engine.session().random().nextBytes(psSecret);
1189         }
1190 
1191       preMasterSecret = new byte[dhSecret.length + psSecret.length + 4];
1192       preMasterSecret[0] = (byte) (dhSecret.length >>> 8);
1193       preMasterSecret[1] = (byte)  dhSecret.length;
1194       System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length);
1195       preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8);
1196       preMasterSecret[dhSecret.length + 3] = (byte)  psSecret.length;
1197       System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4,
1198                        psSecret.length);
1199 
1200       generateMasterSecret(clientRandom, serverRandom, engine.session());
1201       byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1202       setupSecurityParameters(keys, isClient, engine, compression);
1203     }
1204   }
1205 }
1206