001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Boris Kuznetsov
020: * @version $Revision$
021: */package org.apache.harmony.xnet.provider.jsse;
022:
023: import java.math.BigInteger;
024: import java.security.GeneralSecurityException;
025: import java.security.KeyFactory;
026: import java.security.MessageDigest;
027: import java.security.NoSuchAlgorithmException;
028: import java.security.PublicKey;
029: import java.security.interfaces.RSAKey;
030: import java.security.spec.InvalidKeySpecException;
031: import java.security.spec.RSAPublicKeySpec;
032: import java.util.Arrays;
033: import java.util.Vector;
034:
035: import javax.net.ssl.SSLEngineResult;
036: import javax.net.ssl.SSLException;
037: import javax.net.ssl.SSLHandshakeException;
038:
039: /**
040: * Base class for ClientHandshakeImpl and ServerHandshakeImpl classes.
041: * @see TLS 1.0 spec., 7.4. Handshake protocol
042: * (http://www.ietf.org/rfc/rfc2246.txt)
043: *
044: */
045: public abstract class HandshakeProtocol {
046:
047: /**
048: * Handshake status NEED_UNWRAP - HandshakeProtocol needs to receive data
049: */
050: public final static int NEED_UNWRAP = 1;
051:
052: /**
053: * Handshake status NOT_HANDSHAKING - is not currently handshaking
054: */
055: public final static int NOT_HANDSHAKING = 2;
056:
057: /**
058: * Handshake status FINISHED - HandshakeProtocol has just finished
059: */
060: public final static int FINISHED = 3;
061:
062: /**
063: * Handshake status NEED_TASK - HandshakeProtocol needs the results of delegated task
064: */
065: public final static int NEED_TASK = 4;
066:
067: /**
068: * Current handshake status
069: */
070: protected int status = NOT_HANDSHAKING;
071:
072: /**
073: * IO stream for income/outcome handshake data
074: */
075: protected HandshakeIODataStream io_stream = new HandshakeIODataStream();
076:
077: /**
078: * SSL Record Protocol implementation.
079: */
080: protected SSLRecordProtocol recordProtocol;
081:
082: /**
083: * SSLParameters suplied by SSLSocket or SSLEngine
084: */
085: protected SSLParameters parameters;
086:
087: /**
088: * Delegated tasks for this handshake implementation
089: */
090: protected Vector delegatedTasks = new Vector();
091:
092: /**
093: * Indicates non-blocking handshake
094: */
095: protected boolean nonBlocking;
096:
097: /**
098: * Pending session
099: */
100: protected SSLSessionImpl session;
101:
102: /**
103: * Sended and received handshake messages
104: */
105: protected ClientHello clientHello;
106: protected ServerHello serverHello;
107: protected CertificateMessage serverCert;
108: protected ServerKeyExchange serverKeyExchange;
109: protected CertificateRequest certificateRequest;
110: protected ServerHelloDone serverHelloDone;
111: protected CertificateMessage clientCert;
112: protected ClientKeyExchange clientKeyExchange;
113: protected CertificateVerify certificateVerify;
114: protected Finished clientFinished;
115: protected Finished serverFinished;
116:
117: /**
118: * Indicates that change cipher spec message has been received
119: */
120: protected boolean changeCipherSpecReceived = false;
121:
122: /**
123: * Indicates previous session resuming
124: */
125: protected boolean isResuming = false;
126:
127: /**
128: * Premaster secret
129: */
130: protected byte[] preMasterSecret;
131:
132: /**
133: * Exception occured in delegated task
134: */
135: protected Exception delegatedTaskErr;
136:
137: // reference verify_data used to verify finished message
138: private byte[] verify_data = new byte[12];
139:
140: // Encoding of "master secret" string: "master secret".getBytes()
141: private byte[] master_secret_bytes = { 109, 97, 115, 116, 101, 114,
142: 32, 115, 101, 99, 114, 101, 116 };
143:
144: // indicates whether protocol needs to send change cipher spec message
145: private boolean needSendCCSpec = false;
146:
147: // indicates whether protocol needs to send change cipher spec message
148: protected boolean needSendHelloRequest = false;
149:
150: /**
151: * SSLEngine owning this HandshakeProtocol
152: */
153: public SSLEngineImpl engineOwner;
154:
155: /**
156: * SSLSocket owning this HandshakeProtocol
157: */
158: public SSLSocketImpl socketOwner;
159:
160: /**
161: * Creates HandshakeProtocol instance
162: * @param owner
163: */
164: protected HandshakeProtocol(Object owner) {
165: if (owner instanceof SSLEngineImpl) {
166: engineOwner = (SSLEngineImpl) owner;
167: nonBlocking = true;
168: this .parameters = (SSLParameters) engineOwner.sslParameters;
169: } else if (owner instanceof SSLSocketImpl) {
170: socketOwner = (SSLSocketImpl) owner;
171: nonBlocking = false;
172: this .parameters = (SSLParameters) socketOwner.sslParameters;
173: }
174: }
175:
176: /**
177: * Sets SSL Record Protocol
178: * @param recordProtocol
179: */
180: public void setRecordProtocol(SSLRecordProtocol recordProtocol) {
181: this .recordProtocol = recordProtocol;
182: }
183:
184: /**
185: * Start session negotiation
186: * @param session
187: */
188: public abstract void start();
189:
190: /**
191: * Stops the current session renegotiation process.
192: * Such functionality is needed when it is session renegotiation
193: * process and no_renegotiation alert message is received
194: * from another peer.
195: * @param session
196: */
197: protected void stop() {
198: clearMessages();
199: status = NOT_HANDSHAKING;
200: }
201:
202: /**
203: * Returns handshake status
204: * @return
205: */
206: public SSLEngineResult.HandshakeStatus getStatus() {
207: if (io_stream.hasData() || needSendCCSpec
208: || needSendHelloRequest || delegatedTaskErr != null) {
209: return SSLEngineResult.HandshakeStatus.NEED_WRAP;
210: }
211: if (!delegatedTasks.isEmpty()) {
212: return SSLEngineResult.HandshakeStatus.NEED_TASK;
213: }
214:
215: switch (status) {
216: case HandshakeProtocol.NEED_UNWRAP:
217: return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
218: case HandshakeProtocol.FINISHED:
219: status = NOT_HANDSHAKING;
220: clearMessages();
221: return SSLEngineResult.HandshakeStatus.FINISHED;
222: default: // HandshakeProtocol.NOT_HANDSHAKING:
223: return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
224: }
225: }
226:
227: /**
228: * Returns pending session
229: * @return session
230: */
231: public SSLSessionImpl getSession() {
232: return session;
233: }
234:
235: protected void sendChangeCipherSpec() {
236: needSendCCSpec = true;
237: }
238:
239: protected void sendHelloRequest() {
240: needSendHelloRequest = true;
241: }
242:
243: /**
244: * Proceses inbound ChangeCipherSpec message
245: */
246: abstract void receiveChangeCipherSpec();
247:
248: /**
249: * Creates and sends finished message
250: */
251: abstract void makeFinished();
252:
253: /**
254: * Proceses inbound handshake messages
255: * @param bytes
256: */
257: public abstract void unwrap(byte[] bytes);
258:
259: /**
260: * Processes SSLv2 Hello message
261: * @param bytes
262: */
263: public abstract void unwrapSSLv2(byte[] bytes);
264:
265: /**
266: * Proceses outbound handshake messages
267: * @return
268: */
269: public byte[] wrap() {
270: if (delegatedTaskErr != null) {
271: // process error occured in delegated task
272: Exception e = delegatedTaskErr;
273: delegatedTaskErr = null;
274: fatalAlert(
275: AlertProtocol.HANDSHAKE_FAILURE,
276: "Error occured in delegated task:" + e.getMessage(),
277: e);
278: }
279: if (io_stream.hasData()) {
280: return recordProtocol
281: .wrap(ContentType.HANDSHAKE, io_stream);
282: } else if (needSendCCSpec) {
283: makeFinished();
284: needSendCCSpec = false;
285: return recordProtocol
286: .getChangeCipherSpecMesage(getSession());
287: } else if (needSendHelloRequest) {
288: needSendHelloRequest = false;
289: return recordProtocol.wrap(ContentType.HANDSHAKE,
290: // hello request message
291: // (see TLS v 1 specification:
292: // http://www.ietf.org/rfc/rfc2246.txt)
293: new byte[] { 0, 0, 0, 0 }, 0, 4);
294: } else {
295: return null; // nothing to send;
296: }
297: }
298:
299: /**
300: * Sends fatal alert, breaks execution
301: *
302: * @param description
303: */
304: protected void sendWarningAlert(byte description) {
305: recordProtocol.alert(AlertProtocol.WARNING, description);
306: }
307:
308: /**
309: * Sends fatal alert, breaks execution
310: *
311: * @param description
312: * @param reason
313: */
314: protected void fatalAlert(byte description, String reason) {
315: throw new AlertException(description,
316: new SSLHandshakeException(reason));
317: }
318:
319: /**
320: * Sends fatal alert, breaks execution
321: *
322: * @param description
323: * @param reason
324: * @param cause
325: */
326: protected void fatalAlert(byte description, String reason,
327: Exception cause) {
328: throw new AlertException(description, new SSLException(reason,
329: cause));
330: }
331:
332: /**
333: * Sends fatal alert, breaks execution
334: *
335: * @param description
336: * @param cause
337: */
338: protected void fatalAlert(byte description, SSLException cause) {
339: throw new AlertException(description, cause);
340: }
341:
342: /**
343: * Computers reference TLS verify_data that is used to verify finished message
344: * @see TLS spec. 7.4.9. Finished
345: * @param label
346: */
347: protected void computerReferenceVerifyDataTLS(String label) {
348: computerVerifyDataTLS(label, verify_data);
349: }
350:
351: /**
352: * Computer TLS verify_data
353: * @see TLS spec. 7.4.9. Finished
354: * @param label
355: * @param buf
356: */
357: protected void computerVerifyDataTLS(String label, byte[] buf) {
358: byte[] md5_digest = io_stream.getDigestMD5();
359: byte[] sha_digest = io_stream.getDigestSHA();
360:
361: byte[] digest = new byte[md5_digest.length + sha_digest.length];
362: System.arraycopy(md5_digest, 0, digest, 0, md5_digest.length);
363: System.arraycopy(sha_digest, 0, digest, md5_digest.length,
364: sha_digest.length);
365: try {
366: PRF.computePRF(buf, session.master_secret,
367: label.getBytes(), digest);
368: } catch (GeneralSecurityException e) {
369: fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
370: }
371: }
372:
373: /**
374: * Computer reference SSLv3 verify_data that is used to verify finished message
375: * @see SSLv3 spec. 7.6.9. Finished
376: * @param label
377: */
378: protected void computerReferenceVerifyDataSSLv3(byte[] sender) {
379: verify_data = new byte[36];
380: computerVerifyDataSSLv3(sender, verify_data);
381: }
382:
383: /**
384: * Computer SSLv3 verify_data
385: * @see SSLv3 spec. 7.6.9. Finished
386: * @param label
387: * @param buf
388: */
389: protected void computerVerifyDataSSLv3(byte[] sender, byte[] buf) {
390: MessageDigest md5;
391: MessageDigest sha;
392: try {
393: md5 = MessageDigest.getInstance("MD5");
394: sha = MessageDigest.getInstance("SHA-1");
395: } catch (Exception e) {
396: fatalAlert(AlertProtocol.INTERNAL_ERROR,
397: "Could not initialize the Digest Algorithms.", e);
398: return;
399: }
400: try {
401: byte[] hanshake_messages = io_stream.getMessages();
402: md5.update(hanshake_messages);
403: md5.update(sender);
404: md5.update(session.master_secret);
405: byte[] b = md5.digest(SSLv3Constants.MD5pad1);
406: md5.update(session.master_secret);
407: md5.update(SSLv3Constants.MD5pad2);
408: System.arraycopy(md5.digest(b), 0, buf, 0, 16);
409:
410: sha.update(hanshake_messages);
411: sha.update(sender);
412: sha.update(session.master_secret);
413: b = sha.digest(SSLv3Constants.SHApad1);
414: sha.update(session.master_secret);
415: sha.update(SSLv3Constants.SHApad2);
416: System.arraycopy(sha.digest(b), 0, buf, 16, 20);
417: } catch (Exception e) {
418: fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR",
419: e);
420:
421: }
422: }
423:
424: /**
425: * Verifies finished data
426: *
427: * @param data
428: * @param isServer
429: */
430: protected void verifyFinished(byte[] data) {
431: if (!Arrays.equals(verify_data, data)) {
432: fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
433: "Incorrect FINISED");
434: }
435: }
436:
437: /**
438: * Sends fatal alert "UNEXPECTED MESSAGE"
439: *
440: */
441: protected void unexpectedMessage() {
442: fatalAlert(AlertProtocol.UNEXPECTED_MESSAGE,
443: "UNEXPECTED MESSAGE");
444: }
445:
446: /**
447: * Writes message to HandshakeIODataStream
448: *
449: * @param message
450: */
451: public void send(Message message) {
452: io_stream.writeUint8(message.getType());
453: io_stream.writeUint24(message.length());
454: message.send(io_stream);
455: }
456:
457: /**
458: * Computers master secret
459: *
460: */
461: public void computerMasterSecret() {
462: byte[] seed = new byte[64];
463: System.arraycopy(clientHello.getRandom(), 0, seed, 0, 32);
464: System.arraycopy(serverHello.getRandom(), 0, seed, 32, 32);
465: session.master_secret = new byte[48];
466: if (serverHello.server_version[1] == 1) { // TLSv1
467: try {
468: PRF.computePRF(session.master_secret, preMasterSecret,
469: master_secret_bytes, seed);
470: } catch (GeneralSecurityException e) {
471: fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
472: }
473: } else { // SSL3.0
474: PRF.computePRF_SSLv3(session.master_secret,
475: preMasterSecret, seed);
476: }
477:
478: //delete preMasterSecret from memory
479: Arrays.fill(preMasterSecret, (byte) 0);
480: preMasterSecret = null;
481: }
482:
483: /**
484: * Returns a delegated task.
485: * @return Delegated task or null
486: */
487: public Runnable getTask() {
488: if (delegatedTasks.isEmpty()) {
489: return null;
490: } else {
491: Runnable task = (Runnable) delegatedTasks.firstElement();
492: delegatedTasks.remove(0);
493: return task;
494: }
495: }
496:
497: /**
498: *
499: * Clears previously sended and received handshake messages
500: */
501: protected void clearMessages() {
502: io_stream.clearBuffer();
503: clientHello = null;
504: serverHello = null;
505: serverCert = null;
506: serverKeyExchange = null;
507: certificateRequest = null;
508: serverHelloDone = null;
509: clientCert = null;
510: clientKeyExchange = null;
511: certificateVerify = null;
512: clientFinished = null;
513: serverFinished = null;
514: }
515:
516: /**
517: * Returns RSA key length
518: * @param pk
519: * @return
520: * @throws NoSuchAlgorithmException
521: * @throws InvalidKeySpecException
522: */
523: protected static int getRSAKeyLength(PublicKey pk)
524: throws NoSuchAlgorithmException, InvalidKeySpecException {
525:
526: BigInteger mod;
527: if (pk instanceof RSAKey) {
528: mod = ((RSAKey) pk).getModulus();
529: } else {
530: KeyFactory kf = KeyFactory.getInstance("RSA");
531: mod = ((RSAPublicKeySpec) kf.getKeySpec(pk,
532: RSAPublicKeySpec.class)).getModulus();
533: }
534: return mod.bitLength();
535: }
536:
537: /**
538: * Shutdownes the protocol. It will be impossiblke to use the instance
539: * after the calling of this method.
540: */
541: protected void shutdown() {
542: clearMessages();
543: session = null;
544: preMasterSecret = null;
545: delegatedTasks.clear();
546: }
547: }
|