1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.xnet.provider.jsse;
19
20import java.math.BigInteger;
21import java.security.GeneralSecurityException;
22import java.security.KeyFactory;
23import java.security.MessageDigest;
24import java.security.NoSuchAlgorithmException;
25import java.security.PublicKey;
26import java.security.interfaces.RSAKey;
27import java.security.spec.InvalidKeySpecException;
28import java.security.spec.RSAPublicKeySpec;
29import java.util.Arrays;
30import java.util.Vector;
31import javax.net.ssl.SSLEngineResult;
32import javax.net.ssl.SSLException;
33import javax.net.ssl.SSLHandshakeException;
34
35/**
36 * Base class for ClientHandshakeImpl and ServerHandshakeImpl classes.
37 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.
38 * Handshake protocol</a>
39 *
40 */
41public abstract class HandshakeProtocol {
42
43    /**
44     * Handshake status NEED_UNWRAP - HandshakeProtocol needs to receive data
45     */
46    public static final int NEED_UNWRAP = 1;
47
48    /**
49     * Handshake status NOT_HANDSHAKING - is not currently handshaking
50     */
51    public static final int NOT_HANDSHAKING = 2;
52
53    /**
54     * Handshake status FINISHED - HandshakeProtocol has just finished
55     */
56    public static final int FINISHED = 3;
57
58    /**
59     * Handshake status NEED_TASK - HandshakeProtocol needs the results of delegated task
60     */
61    public static final int NEED_TASK = 4;
62
63    /**
64     * Current handshake status
65     */
66    protected int status = NOT_HANDSHAKING;
67
68    /**
69     * IO stream for income/outcome handshake data
70     */
71    protected HandshakeIODataStream io_stream = new HandshakeIODataStream();
72
73    /**
74     * SSL Record Protocol implementation.
75     */
76    protected SSLRecordProtocol recordProtocol;
77
78    /**
79     * SSLParametersImpl suplied by SSLSocket or SSLEngine
80     */
81    protected SSLParametersImpl parameters;
82
83    /**
84     * Delegated tasks for this handshake implementation
85     */
86    protected Vector<DelegatedTask> delegatedTasks = new Vector<DelegatedTask>();
87
88    /**
89     * Indicates non-blocking handshake
90     */
91    protected boolean nonBlocking;
92
93    /**
94     * Pending session
95     */
96    protected SSLSessionImpl session;
97
98    /**
99     * Sent and received handshake messages
100     */
101    protected ClientHello clientHello;
102    protected ServerHello serverHello;
103    protected CertificateMessage serverCert;
104    protected ServerKeyExchange serverKeyExchange;
105    protected CertificateRequest certificateRequest;
106    protected ServerHelloDone serverHelloDone;
107    protected CertificateMessage clientCert;
108    protected ClientKeyExchange clientKeyExchange;
109    protected CertificateVerify certificateVerify;
110    protected Finished clientFinished;
111    protected Finished serverFinished;
112
113    /**
114     * Indicates that change cipher spec message has been received
115     */
116    protected boolean changeCipherSpecReceived = false;
117
118    /**
119     * Indicates previous session resuming
120     */
121    protected boolean isResuming = false;
122
123    /**
124     *  Premaster secret
125     */
126    protected byte[] preMasterSecret;
127
128    /**
129     * Exception occured in delegated task
130     */
131    protected Exception delegatedTaskErr;
132
133    // reference verify_data used to verify finished message
134    private byte[] verify_data = new byte[12];
135
136    // Encoding of "master secret" string: "master secret".getBytes()
137    private byte[] master_secret_bytes =
138            {109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
139
140    // indicates whether protocol needs to send change cipher spec message
141    private boolean needSendCCSpec = false;
142
143    // indicates whether protocol needs to send change cipher spec message
144    protected boolean needSendHelloRequest = false;
145
146    /**
147     * SSLEngine owning this HandshakeProtocol
148     */
149    public SSLEngineImpl engineOwner;
150
151    /**
152     * SSLSocket owning this HandshakeProtocol
153     */
154    public SSLSocketImpl socketOwner;
155
156    /**
157     * Creates HandshakeProtocol instance
158     * @param owner
159     */
160    protected HandshakeProtocol(Object owner) {
161        if (owner instanceof SSLEngineImpl) {
162            engineOwner = (SSLEngineImpl) owner;
163            nonBlocking = true;
164            this.parameters = engineOwner.sslParameters;
165        }
166        else if (owner instanceof SSLSocketImpl) {
167            socketOwner = (SSLSocketImpl) owner;
168            nonBlocking = false;
169            this.parameters = socketOwner.sslParameters;
170        }
171    }
172
173    /**
174     * Sets SSL Record Protocol
175     * @param recordProtocol
176     */
177    public void setRecordProtocol(SSLRecordProtocol recordProtocol) {
178        this.recordProtocol = recordProtocol;
179    }
180
181    /**
182     * Start session negotiation
183     * @param session
184     */
185    public abstract void start();
186
187    /**
188     * Stops the current session renegotiation process.
189     * Such functionality is needed when it is session renegotiation
190     * process and no_renegotiation alert message is received
191     * from another peer.
192     * @param session
193     */
194    protected void stop() {
195        clearMessages();
196        status = NOT_HANDSHAKING;
197    }
198
199    /**
200     * Returns handshake status
201     * @return
202     */
203    public SSLEngineResult.HandshakeStatus getStatus() {
204        if (io_stream.hasData() || needSendCCSpec ||
205                needSendHelloRequest || delegatedTaskErr != null) {
206            return SSLEngineResult.HandshakeStatus.NEED_WRAP;
207        }
208        if (!delegatedTasks.isEmpty()) {
209            return SSLEngineResult.HandshakeStatus.NEED_TASK;
210        }
211
212        switch (status) {
213        case HandshakeProtocol.NEED_UNWRAP:
214            return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
215        case HandshakeProtocol.FINISHED:
216            status = NOT_HANDSHAKING;
217            clearMessages();
218            return SSLEngineResult.HandshakeStatus.FINISHED;
219        default: // HandshakeProtocol.NOT_HANDSHAKING:
220            return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
221        }
222    }
223
224    /**
225     * Returns pending session
226     * @return session
227     */
228    public SSLSessionImpl getSession() {
229        return session;
230    }
231
232    protected void sendChangeCipherSpec() {
233        needSendCCSpec = true;
234    }
235
236    protected void sendHelloRequest() {
237        needSendHelloRequest = true;
238    }
239
240    /**
241     * Proceses inbound ChangeCipherSpec message
242     */
243    abstract void receiveChangeCipherSpec();
244
245    /**
246     * Creates and sends finished message
247     */
248    abstract void makeFinished();
249
250    /**
251     * Proceses inbound handshake messages
252     * @param bytes
253     */
254    public abstract void unwrap(byte[] bytes);
255
256    /**
257     * Processes SSLv2 Hello message
258     * @param bytes
259     */
260    public abstract void unwrapSSLv2(byte[] bytes);
261
262    /**
263     * Proceses outbound handshake messages
264     * @return
265     */
266    public byte[] wrap() {
267        if (delegatedTaskErr != null) {
268            // process error occured in delegated task
269            Exception e = delegatedTaskErr;
270            delegatedTaskErr = null;
271            fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
272                    "Error occured in delegated task:" + e.getMessage(), e);
273        }
274        if (io_stream.hasData()) {
275            return recordProtocol.wrap(ContentType.HANDSHAKE, io_stream);
276        } else if (needSendCCSpec) {
277            makeFinished();
278            needSendCCSpec = false;
279            return recordProtocol.getChangeCipherSpecMesage(getSession());
280        } else if (needSendHelloRequest) {
281            needSendHelloRequest = false;
282            return recordProtocol.wrap(ContentType.HANDSHAKE,
283                    // hello request message
284                    // (see TLS v 1 specification:
285                    // http://www.ietf.org/rfc/rfc2246.txt)
286                    new byte[] {0, 0, 0, 0}, 0, 4);
287        } else {
288            return null; // nothing to send;
289        }
290    }
291
292    /**
293     * Sends fatal alert, breaks execution
294     *
295     * @param description
296     */
297    protected void sendWarningAlert(byte description) {
298        recordProtocol.alert(AlertProtocol.WARNING, description);
299    }
300
301    /**
302     * Sends fatal alert, breaks execution
303     *
304     * @param description
305     * @param reason
306     */
307    protected void fatalAlert(byte description, String reason) {
308        throw new AlertException(description, new SSLHandshakeException(reason));
309    }
310
311    /**
312     * Sends fatal alert, breaks execution
313     *
314     * @param description
315     * @param reason
316     * @param cause
317     */
318    protected void fatalAlert(byte description, String reason, Exception cause) {
319        throw new AlertException(description, new SSLException(reason, cause));
320    }
321
322    /**
323     * Sends fatal alert, breaks execution
324     *
325     * @param description
326     * @param cause
327     */
328    protected void fatalAlert(byte description, SSLException cause) {
329        throw new AlertException(description, cause);
330    }
331
332    /**
333     * Computers reference TLS verify_data that is used to verify finished message
334     * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a>
335     * @param label
336     */
337    protected void computerReferenceVerifyDataTLS(String label) {
338        computerVerifyDataTLS(label, verify_data);
339    }
340
341    /**
342     * Computer TLS verify_data
343     * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a>
344     * @param label
345     * @param buf
346     */
347    protected void computerVerifyDataTLS(String label, byte[] buf) {
348        byte[] md5_digest = io_stream.getDigestMD5();
349        byte[] sha_digest = io_stream.getDigestSHA();
350
351        byte[] digest = new byte[md5_digest.length + sha_digest.length];
352        System.arraycopy(md5_digest, 0, digest, 0, md5_digest.length);
353        System.arraycopy(sha_digest, 0, digest, md5_digest.length,
354                sha_digest.length);
355        try {
356            PRF.computePRF(buf, session.master_secret,
357                    label.getBytes(), digest);
358        } catch (GeneralSecurityException e) {
359            fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
360        }
361    }
362
363    /**
364     * Computer reference SSLv3 verify_data that is used to verify finished message
365     * @see "SSLv3 spec. 7.6.9. Finished"
366     * @param label
367     */
368    protected void computerReferenceVerifyDataSSLv3(byte[] sender) {
369        verify_data = new byte[36];
370        computerVerifyDataSSLv3(sender, verify_data);
371    }
372
373    /**
374     * Computer SSLv3 verify_data
375     * @see "SSLv3 spec. 7.6.9. Finished"
376     * @param label
377     * @param buf
378     */
379    protected void computerVerifyDataSSLv3(byte[] sender, byte[] buf) {
380        MessageDigest md5;
381        MessageDigest sha;
382        try {
383            md5 = MessageDigest.getInstance("MD5");
384            sha = MessageDigest.getInstance("SHA-1");
385        } catch (Exception e) {
386            fatalAlert(AlertProtocol.INTERNAL_ERROR,
387                       "Could not initialize the Digest Algorithms.",
388                       e);
389            return;
390        }
391        try {
392            byte[] handshake_messages = io_stream.getMessages();
393            md5.update(handshake_messages);
394            md5.update(sender);
395            md5.update(session.master_secret);
396            byte[] b = md5.digest(SSLv3Constants.MD5pad1);
397            md5.update(session.master_secret);
398            md5.update(SSLv3Constants.MD5pad2);
399            System.arraycopy(md5.digest(b), 0, buf, 0, 16);
400
401            sha.update(handshake_messages);
402            sha.update(sender);
403            sha.update(session.master_secret);
404            b = sha.digest(SSLv3Constants.SHApad1);
405            sha.update(session.master_secret);
406            sha.update(SSLv3Constants.SHApad2);
407            System.arraycopy(sha.digest(b), 0, buf, 16, 20);
408        } catch (Exception e) {
409            fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
410
411        }
412    }
413
414    /**
415     * Verifies finished data
416     *
417     * @param data
418     * @param isServer
419     */
420    protected void verifyFinished(byte[] data) {
421        if (!Arrays.equals(verify_data, data)) {
422            fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Incorrect FINISED");
423        }
424    }
425
426    /**
427     * Sends fatal alert "UNEXPECTED MESSAGE"
428     *
429     */
430    protected void unexpectedMessage() {
431        fatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, "UNEXPECTED MESSAGE");
432    }
433
434    /**
435     * Writes message to HandshakeIODataStream
436     *
437     * @param message
438     */
439    public void send(Message message) {
440        io_stream.writeUint8(message.getType());
441        io_stream.writeUint24(message.length());
442        message.send(io_stream);
443    }
444
445    /**
446     * Computers master secret
447     *
448     */
449    public void computerMasterSecret() {
450        byte[] seed = new byte[64];
451        System.arraycopy(clientHello.getRandom(), 0, seed, 0, 32);
452        System.arraycopy(serverHello.getRandom(), 0, seed, 32, 32);
453        session.master_secret = new byte[48];
454        if (serverHello.server_version[1] == 1) { // TLSv1
455            try {
456                PRF.computePRF(session.master_secret, preMasterSecret,
457                        master_secret_bytes, seed);
458            } catch (GeneralSecurityException e) {
459                fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
460            }
461        } else { // SSL3.0
462            PRF.computePRF_SSLv3(session.master_secret, preMasterSecret, seed);
463        }
464
465        //delete preMasterSecret from memory
466        Arrays.fill(preMasterSecret, (byte)0);
467        preMasterSecret = null;
468    }
469
470    /**
471     * Returns a delegated task.
472     * @return Delegated task or null
473     */
474    public Runnable getTask() {
475        if (delegatedTasks.isEmpty()) {
476            return null;
477        }
478        return delegatedTasks.remove(0);
479    }
480
481    /**
482     * Clears previously sent and received handshake messages
483     */
484    protected void clearMessages() {
485        io_stream.clearBuffer();
486        clientHello = null;
487        serverHello = null;
488        serverCert = null;
489        serverKeyExchange = null;
490        certificateRequest = null;
491        serverHelloDone = null;
492        clientCert = null;
493        clientKeyExchange = null;
494        certificateVerify = null;
495        clientFinished = null;
496        serverFinished = null;
497    }
498
499    /**
500     * Returns RSA key length
501     * @param pk
502     * @return
503     * @throws NoSuchAlgorithmException
504     * @throws InvalidKeySpecException
505     */
506    protected static int getRSAKeyLength(PublicKey pk)
507            throws NoSuchAlgorithmException, InvalidKeySpecException {
508
509        BigInteger mod;
510        if (pk instanceof RSAKey) {
511            mod = ((RSAKey) pk).getModulus();
512        } else {
513            KeyFactory kf = KeyFactory.getInstance("RSA");
514            mod = kf.getKeySpec(pk, RSAPublicKeySpec.class)
515                    .getModulus();
516        }
517        return mod.bitLength();
518    }
519
520    /**
521     * Shuts down the protocol. It will be impossible to use the instance
522     * after calling this method.
523     */
524    protected void shutdown() {
525        clearMessages();
526        session = null;
527        preMasterSecret = null;
528        delegatedTasks.clear();
529    }
530}
531