Home | History | Annotate | Download | only in jsse
      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 
     18 package org.apache.harmony.xnet.provider.jsse;
     19 
     20 import java.math.BigInteger;
     21 import java.security.GeneralSecurityException;
     22 import java.security.KeyFactory;
     23 import java.security.MessageDigest;
     24 import java.security.NoSuchAlgorithmException;
     25 import java.security.PublicKey;
     26 import java.security.interfaces.RSAKey;
     27 import java.security.spec.InvalidKeySpecException;
     28 import java.security.spec.RSAPublicKeySpec;
     29 import java.util.Arrays;
     30 import java.util.Vector;
     31 import javax.net.ssl.SSLEngineResult;
     32 import javax.net.ssl.SSLException;
     33 import 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  */
     41 public abstract class HandshakeProtocol {
     42 
     43     /**
     44      * Handshake status NEED_UNWRAP - HandshakeProtocol needs to receive data
     45      */
     46     public final static int NEED_UNWRAP = 1;
     47 
     48     /**
     49      * Handshake status NOT_HANDSHAKING - is not currently handshaking
     50      */
     51     public final static int NOT_HANDSHAKING = 2;
     52 
     53     /**
     54      * Handshake status FINISHED - HandshakeProtocol has just finished
     55      */
     56     public final static int FINISHED = 3;
     57 
     58     /**
     59      * Handshake status NEED_TASK - HandshakeProtocol needs the results of delegated task
     60      */
     61     public final static 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      * Sended 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      *
    483      * Clears previously sended and received handshake messages
    484      */
    485     protected void clearMessages() {
    486         io_stream.clearBuffer();
    487         clientHello = null;
    488         serverHello = null;
    489         serverCert = null;
    490         serverKeyExchange = null;
    491         certificateRequest = null;
    492         serverHelloDone = null;
    493         clientCert = null;
    494         clientKeyExchange = null;
    495         certificateVerify = null;
    496         clientFinished = null;
    497         serverFinished = null;
    498     }
    499 
    500     /**
    501      * Returns RSA key length
    502      * @param pk
    503      * @return
    504      * @throws NoSuchAlgorithmException
    505      * @throws InvalidKeySpecException
    506      */
    507     protected static int getRSAKeyLength(PublicKey pk)
    508             throws NoSuchAlgorithmException, InvalidKeySpecException {
    509 
    510         BigInteger mod;
    511         if (pk instanceof RSAKey) {
    512             mod = ((RSAKey) pk).getModulus();
    513         } else {
    514             KeyFactory kf = KeyFactory.getInstance("RSA");
    515             mod = kf.getKeySpec(pk, RSAPublicKeySpec.class)
    516                     .getModulus();
    517         }
    518         return mod.bitLength();
    519     }
    520 
    521     /**
    522      * Shutdownes the protocol. It will be impossiblke to use the instance
    523      * after the calling of this method.
    524      */
    525     protected void shutdown() {
    526         clearMessages();
    527         session = null;
    528         preMasterSecret = null;
    529         delegatedTasks.clear();
    530     }
    531 }
    532