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.io.IOException;
     21 import java.math.BigInteger;
     22 import java.security.KeyFactory;
     23 import java.security.interfaces.RSAPublicKey;
     24 import java.security.spec.RSAPublicKeySpec;
     25 
     26 /**
     27  *
     28  * Represents server key exchange message.
     29  * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.3.
     30  * Server key exchange message.</a>
     31  *
     32  */
     33 public class ServerKeyExchange extends Message {
     34 
     35                            //          ServerRSAParams        ServerDHParams
     36     final BigInteger par1; //            rsa_modulus               dh_p
     37     final byte[] bytes1;
     38 
     39     final BigInteger par2; //            rsa_exponent              dh_g
     40     final byte[] bytes2;
     41 
     42     final BigInteger par3; //                                      dh_Ys
     43     final byte[] bytes3;
     44 
     45     /**
     46      * Signature
     47      */
     48     final byte[] hash;
     49 
     50     private RSAPublicKey key;
     51 
     52     /**
     53      * Creates outbound message
     54      * @param par1 rsa_modulus or dh_p
     55      * @param par2 rsa_exponent or dh_g
     56      * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams
     57      * @param hash should be null for anonymous SignatureAlgorithm
     58      */
     59     public ServerKeyExchange(BigInteger par1, BigInteger par2, BigInteger par3,
     60             byte[] hash) {
     61         this.par1 = par1;
     62         this.par2 = par2;
     63         this.par3 = par3;
     64         this.hash = hash;
     65 
     66         bytes1 = toUnsignedByteArray(this.par1);
     67 
     68         bytes2 = toUnsignedByteArray(this.par2);
     69 
     70         length = 4 + bytes1.length + bytes2.length;
     71         if (hash != null) {
     72             length += 2 + hash.length;
     73         }
     74         if (par3 == null) {
     75             bytes3 = null;
     76             return;
     77         }
     78         bytes3 = toUnsignedByteArray(this.par3);
     79         length += 2 + bytes3.length;
     80     }
     81 
     82     /**
     83      * Remove first byte if 0. Needed because BigInteger.toByteArray() sometimes
     84      * returns a zero prefix.
     85      */
     86     public static byte[] toUnsignedByteArray(BigInteger bi) {
     87         if (bi == null) {
     88             return null;
     89         }
     90         byte[] bb = bi.toByteArray();
     91         // bb is not null, and has at least 1 byte - ZERO is represented as [0]
     92         if (bb[0] == 0) {
     93             byte[] noZero = new byte[bb.length - 1];
     94             System.arraycopy(bb, 1, noZero, 0, noZero.length);
     95             return noZero;
     96         } else {
     97             return bb;
     98         }
     99     }
    100 
    101     public static void updateSignatureRsa(DigitalSignature ds, BigInteger modulus,
    102             BigInteger publicExponent) {
    103         byte[] tmp;
    104         byte[] tmpLength = new byte[2];
    105         tmp = ServerKeyExchange.toUnsignedByteArray(modulus);
    106         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    107         tmpLength[1] = (byte) (tmp.length & 0xFF);
    108         ds.update(tmpLength);
    109         ds.update(tmp);
    110         tmp = ServerKeyExchange.toUnsignedByteArray(publicExponent);
    111         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    112         tmpLength[1] = (byte) (tmp.length & 0xFF);
    113         ds.update(tmpLength);
    114         ds.update(tmp);
    115     }
    116 
    117     public static void updateSignatureDh(DigitalSignature ds, BigInteger p, BigInteger g,
    118             BigInteger y) {
    119         byte[] tmp;
    120         byte[] tmpLength = new byte[2];
    121         tmp = ServerKeyExchange.toUnsignedByteArray(p);
    122         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    123         tmpLength[1] = (byte) (tmp.length & 0xFF);
    124         ds.update(tmpLength);
    125         ds.update(tmp);
    126         tmp = ServerKeyExchange.toUnsignedByteArray(g);
    127         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    128         tmpLength[1] = (byte) (tmp.length & 0xFF);
    129         ds.update(tmpLength);
    130         ds.update(tmp);
    131         tmp = ServerKeyExchange.toUnsignedByteArray(y);
    132         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    133         tmpLength[1] = (byte) (tmp.length & 0xFF);
    134         ds.update(tmpLength);
    135         ds.update(tmp);
    136     }
    137 
    138     public boolean verifySignature(DigitalSignature ds) {
    139         if (par3 != null) {
    140             updateSignatureDh(ds, par1, par2, par3);
    141         } else {
    142             updateSignatureRsa(ds, par1, par2);
    143         }
    144         return ds.verifySignature(hash);
    145     }
    146 
    147     /**
    148      * Will return {@code true} if the signature is {@code null} since this is
    149      * considered anonymous.
    150      */
    151     public boolean isAnonymous() {
    152         return hash == null;
    153     }
    154 
    155     /**
    156      * Creates inbound message
    157      * @param in
    158      * @param length
    159      * @param keyExchange
    160      * @throws IOException
    161      */
    162     public ServerKeyExchange(HandshakeIODataStream in, int length,
    163             int keyExchange) throws IOException {
    164 
    165         int size = in.readUint16();
    166         bytes1 = in.read(size);
    167         par1 = new BigInteger(1, bytes1);
    168         this.length = 2 + bytes1.length;
    169         size = in.readUint16();
    170         bytes2 = in.read(size);
    171         par2 = new BigInteger(1, bytes2);
    172         this.length += 2 + bytes2.length;
    173         if (keyExchange != CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    174             size = in.readUint16();
    175             bytes3 = in.read(size);
    176             par3 = new BigInteger(1, bytes3);
    177             this.length += 2 + bytes3.length;
    178         } else {
    179             par3 = null;
    180             bytes3 = null;
    181         }
    182         if (keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT
    183                 && keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon) {
    184             size = in.readUint16();
    185             hash = in.read(size);
    186             this.length += 2 + hash.length;
    187         } else {
    188             hash = null;
    189         }
    190         if (this.length != length) {
    191             fatalAlert(AlertProtocol.DECODE_ERROR,
    192                     "DECODE ERROR: incorrect ServerKeyExchange");
    193         }
    194     }
    195 
    196     /**
    197      * Sends message
    198      * @param out
    199      */
    200     @Override
    201     public void send(HandshakeIODataStream out) {
    202         out.writeUint16(bytes1.length);
    203         out.write(bytes1);
    204         out.writeUint16(bytes2.length);
    205         out.write(bytes2);
    206         if (bytes3 != null) {
    207             out.writeUint16(bytes3.length);
    208             out.write(bytes3);
    209         }
    210         if (hash != null) {
    211             out.writeUint16(hash.length);
    212             out.write(hash);
    213         }
    214     }
    215 
    216     /**
    217      * Returns RSAPublicKey generated using ServerRSAParams
    218      * (rsa_modulus and rsa_exponent).
    219      *
    220      * @return
    221      */
    222     public RSAPublicKey getRSAPublicKey() {
    223         if (key != null) {
    224             return key;
    225         }
    226         try {
    227             KeyFactory kf = KeyFactory.getInstance("RSA");
    228             key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1,
    229                     par2));
    230         } catch (Exception e) {
    231             return null;
    232         }
    233         return key;
    234     }
    235 
    236     /**
    237      * Returns message type
    238      * @return
    239      */
    240     @Override
    241     public int getType() {
    242         return Handshake.SERVER_KEY_EXCHANGE;
    243     }
    244 
    245 }
    246