Home | History | Annotate | Download | only in conscrypt
      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.conscrypt;
     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 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      */
    184     public abstract void start();
    185 
    186     /**
    187      * Stops the current session renegotiation process.
    188      * Such functionality is needed when it is session renegotiation
    189      * process and no_renegotiation alert message is received
    190      * from another peer.
    191      * @param session
    192      */
    193     protected void stop() {
    194         clearMessages();
    195         status = NOT_HANDSHAKING;
    196     }
    197 
    198     /**
    199      * Returns handshake status
    200      */
    201     public SSLEngineResult.HandshakeStatus getStatus() {
    202         if (io_stream.hasData() || needSendCCSpec ||
    203                 needSendHelloRequest || delegatedTaskErr != null) {
    204             return SSLEngineResult.HandshakeStatus.NEED_WRAP;
    205         }
    206         if (!delegatedTasks.isEmpty()) {
    207             return SSLEngineResult.HandshakeStatus.NEED_TASK;
    208         }
    209 
    210         switch (status) {
    211         case HandshakeProtocol.NEED_UNWRAP:
    212             return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
    213         case HandshakeProtocol.FINISHED:
    214             status = NOT_HANDSHAKING;
    215             clearMessages();
    216             return SSLEngineResult.HandshakeStatus.FINISHED;
    217         default: // HandshakeProtocol.NOT_HANDSHAKING:
    218             return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
    219         }
    220     }
    221 
    222     /**
    223      * Returns pending session
    224      * @return session
    225      */
    226     public SSLSessionImpl getSession() {
    227         return session;
    228     }
    229 
    230     protected void sendChangeCipherSpec() {
    231         needSendCCSpec = true;
    232     }
    233 
    234     protected void sendHelloRequest() {
    235         needSendHelloRequest = true;
    236     }
    237 
    238     /**
    239      * Proceses inbound ChangeCipherSpec message
    240      */
    241     abstract void receiveChangeCipherSpec();
    242 
    243     /**
    244      * Creates and sends finished message
    245      */
    246     abstract void makeFinished();
    247 
    248     /**
    249      * Proceses inbound handshake messages
    250      * @param bytes
    251      */
    252     public abstract void unwrap(byte[] bytes);
    253 
    254     /**
    255      * Processes SSLv2 Hello message
    256      * @param bytes
    257      */
    258     public abstract void unwrapSSLv2(byte[] bytes);
    259 
    260     /**
    261      * Processes outbound handshake messages
    262      */
    263     public byte[] wrap() {
    264         if (delegatedTaskErr != null) {
    265             // process error occured in delegated task
    266             Exception e = delegatedTaskErr;
    267             delegatedTaskErr = null;
    268             fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
    269                     "Error occured in delegated task:" + e.getMessage(), e);
    270         }
    271         if (io_stream.hasData()) {
    272             return recordProtocol.wrap(ContentType.HANDSHAKE, io_stream);
    273         } else if (needSendCCSpec) {
    274             makeFinished();
    275             needSendCCSpec = false;
    276             return recordProtocol.getChangeCipherSpecMesage(getSession());
    277         } else if (needSendHelloRequest) {
    278             needSendHelloRequest = false;
    279             return recordProtocol.wrap(ContentType.HANDSHAKE,
    280                     // hello request message
    281                     // (see TLS v 1 specification:
    282                     // http://www.ietf.org/rfc/rfc2246.txt)
    283                     new byte[] {0, 0, 0, 0}, 0, 4);
    284         } else {
    285             return null; // nothing to send;
    286         }
    287     }
    288 
    289     /**
    290      * Sends fatal alert, breaks execution
    291      *
    292      * @param description
    293      */
    294     protected void sendWarningAlert(byte description) {
    295         recordProtocol.alert(AlertProtocol.WARNING, description);
    296     }
    297 
    298     /**
    299      * Sends fatal alert, breaks execution
    300      *
    301      * @param description
    302      * @param reason
    303      */
    304     protected void fatalAlert(byte description, String reason) {
    305         throw new AlertException(description, new SSLHandshakeException(reason));
    306     }
    307 
    308     /**
    309      * Sends fatal alert, breaks execution
    310      *
    311      * @param description
    312      * @param reason
    313      * @param cause
    314      */
    315     protected void fatalAlert(byte description, String reason, Exception cause) {
    316         throw new AlertException(description, new SSLException(reason, cause));
    317     }
    318 
    319     /**
    320      * Sends fatal alert, breaks execution
    321      *
    322      * @param description
    323      * @param cause
    324      */
    325     protected void fatalAlert(byte description, SSLException cause) {
    326         throw new AlertException(description, cause);
    327     }
    328 
    329     /**
    330      * Computers reference TLS verify_data that is used to verify finished message
    331      * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a>
    332      * @param label
    333      */
    334     protected void computerReferenceVerifyDataTLS(String label) {
    335         computerVerifyDataTLS(label, verify_data);
    336     }
    337 
    338     /**
    339      * Computer TLS verify_data
    340      * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a>
    341      * @param label
    342      * @param buf
    343      */
    344     protected void computerVerifyDataTLS(String label, byte[] buf) {
    345         byte[] md5_digest = io_stream.getDigestMD5();
    346         byte[] sha_digest = io_stream.getDigestSHA();
    347 
    348         byte[] digest = new byte[md5_digest.length + sha_digest.length];
    349         System.arraycopy(md5_digest, 0, digest, 0, md5_digest.length);
    350         System.arraycopy(sha_digest, 0, digest, md5_digest.length,
    351                 sha_digest.length);
    352         try {
    353             PRF.computePRF(buf, session.master_secret,
    354                     label.getBytes(), digest);
    355         } catch (GeneralSecurityException e) {
    356             fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
    357         }
    358     }
    359 
    360     /**
    361      * Computer reference SSLv3 verify_data that is used to verify finished message
    362      * @see "SSLv3 spec. 7.6.9. Finished"
    363      * @param label
    364      */
    365     protected void computerReferenceVerifyDataSSLv3(byte[] sender) {
    366         verify_data = new byte[36];
    367         computerVerifyDataSSLv3(sender, verify_data);
    368     }
    369 
    370     /**
    371      * Computer SSLv3 verify_data
    372      * @see "SSLv3 spec. 7.6.9. Finished"
    373      * @param label
    374      * @param buf
    375      */
    376     protected void computerVerifyDataSSLv3(byte[] sender, byte[] buf) {
    377         MessageDigest md5;
    378         MessageDigest sha;
    379         try {
    380             md5 = MessageDigest.getInstance("MD5");
    381             sha = MessageDigest.getInstance("SHA-1");
    382         } catch (Exception e) {
    383             fatalAlert(AlertProtocol.INTERNAL_ERROR,
    384                        "Could not initialize the Digest Algorithms.",
    385                        e);
    386             return;
    387         }
    388         try {
    389             byte[] handshake_messages = io_stream.getMessages();
    390             md5.update(handshake_messages);
    391             md5.update(sender);
    392             md5.update(session.master_secret);
    393             byte[] b = md5.digest(SSLv3Constants.MD5pad1);
    394             md5.update(session.master_secret);
    395             md5.update(SSLv3Constants.MD5pad2);
    396             System.arraycopy(md5.digest(b), 0, buf, 0, 16);
    397 
    398             sha.update(handshake_messages);
    399             sha.update(sender);
    400             sha.update(session.master_secret);
    401             b = sha.digest(SSLv3Constants.SHApad1);
    402             sha.update(session.master_secret);
    403             sha.update(SSLv3Constants.SHApad2);
    404             System.arraycopy(sha.digest(b), 0, buf, 16, 20);
    405         } catch (Exception e) {
    406             fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
    407 
    408         }
    409     }
    410 
    411     /**
    412      * Verifies finished data
    413      *
    414      * @param data
    415      * @param isServer
    416      */
    417     protected void verifyFinished(byte[] data) {
    418         if (!Arrays.equals(verify_data, data)) {
    419             fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Incorrect FINISED");
    420         }
    421     }
    422 
    423     /**
    424      * Sends fatal alert "UNEXPECTED MESSAGE"
    425      *
    426      */
    427     protected void unexpectedMessage() {
    428         fatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, "UNEXPECTED MESSAGE");
    429     }
    430 
    431     /**
    432      * Writes message to HandshakeIODataStream
    433      *
    434      * @param message
    435      */
    436     public void send(Message message) {
    437         io_stream.writeUint8(message.getType());
    438         io_stream.writeUint24(message.length());
    439         message.send(io_stream);
    440     }
    441 
    442     /**
    443      * Computers master secret
    444      *
    445      */
    446     public void computerMasterSecret() {
    447         byte[] seed = new byte[64];
    448         System.arraycopy(clientHello.getRandom(), 0, seed, 0, 32);
    449         System.arraycopy(serverHello.getRandom(), 0, seed, 32, 32);
    450         session.master_secret = new byte[48];
    451         if (serverHello.server_version[1] == 1) { // TLSv1
    452             try {
    453                 PRF.computePRF(session.master_secret, preMasterSecret,
    454                         master_secret_bytes, seed);
    455             } catch (GeneralSecurityException e) {
    456                 fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e);
    457             }
    458         } else { // SSL3.0
    459             PRF.computePRF_SSLv3(session.master_secret, preMasterSecret, seed);
    460         }
    461 
    462         //delete preMasterSecret from memory
    463         Arrays.fill(preMasterSecret, (byte)0);
    464         preMasterSecret = null;
    465     }
    466 
    467     /**
    468      * Returns a delegated task.
    469      * @return Delegated task or null
    470      */
    471     public Runnable getTask() {
    472         if (delegatedTasks.isEmpty()) {
    473             return null;
    474         }
    475         return delegatedTasks.remove(0);
    476     }
    477 
    478     /**
    479      * Clears previously sent and received handshake messages
    480      */
    481     protected void clearMessages() {
    482         io_stream.clearBuffer();
    483         clientHello = null;
    484         serverHello = null;
    485         serverCert = null;
    486         serverKeyExchange = null;
    487         certificateRequest = null;
    488         serverHelloDone = null;
    489         clientCert = null;
    490         clientKeyExchange = null;
    491         certificateVerify = null;
    492         clientFinished = null;
    493         serverFinished = null;
    494     }
    495 
    496     /**
    497      * Returns RSA key length
    498      * @param pk
    499      * @return
    500      * @throws NoSuchAlgorithmException
    501      * @throws InvalidKeySpecException
    502      */
    503     protected static int getRSAKeyLength(PublicKey pk)
    504             throws NoSuchAlgorithmException, InvalidKeySpecException {
    505 
    506         BigInteger mod;
    507         if (pk instanceof RSAKey) {
    508             mod = ((RSAKey) pk).getModulus();
    509         } else {
    510             KeyFactory kf = KeyFactory.getInstance("RSA");
    511             mod = kf.getKeySpec(pk, RSAPublicKeySpec.class)
    512                     .getModulus();
    513         }
    514         return mod.bitLength();
    515     }
    516 
    517     /**
    518      * Shuts down the protocol. It will be impossible to use the instance
    519      * after calling this method.
    520      */
    521     protected void shutdown() {
    522         clearMessages();
    523         session = null;
    524         preMasterSecret = null;
    525         delegatedTasks.clear();
    526     }
    527 }
    528