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 org.apache.harmony.xnet.provider.jsse.Message;
     21 
     22 import java.io.IOException;
     23 import java.math.BigInteger;
     24 import java.security.KeyFactory;
     25 import java.security.interfaces.RSAPublicKey;
     26 import java.security.spec.RSAPublicKeySpec;
     27 
     28 /**
     29  *
     30  * Represents server key exchange message.
     31  * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.3.
     32  * Server key exchange message.</a>
     33  *
     34  */
     35 public class ServerKeyExchange extends Message {
     36 
     37                            //          ServerRSAParams        ServerDHParams
     38     final BigInteger par1; //            rsa_modulus               dh_p
     39     final byte[] bytes1;
     40 
     41     final BigInteger par2; //            rsa_exponent              dh_g
     42     final byte[] bytes2;
     43 
     44     final BigInteger par3; //                                      dh_Ys
     45     final byte[] bytes3;
     46 
     47     /**
     48      * Signature
     49      */
     50     final byte[] hash;
     51 
     52     private RSAPublicKey key;
     53 
     54     /**
     55      * Creates outbound message
     56      * @param par1 rsa_modulus or dh_p
     57      * @param par2 rsa_exponent or dh_g
     58      * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams
     59      * @param hash should be null for anonymous SignatureAlgorithm
     60      */
     61     public ServerKeyExchange(BigInteger par1, BigInteger par2, BigInteger par3,
     62             byte[] hash) {
     63         this.par1 = par1;
     64         this.par2 = par2;
     65         this.par3 = par3;
     66         this.hash = hash;
     67 
     68         bytes1 = toUnsignedByteArray(this.par1);
     69 
     70         bytes2 = toUnsignedByteArray(this.par2);
     71 
     72         length = 4 + bytes1.length + bytes2.length;
     73         if (hash != null) {
     74             length += 2 + hash.length;
     75         }
     76         if (par3 == null) {
     77             bytes3 = null;
     78             return;
     79         }
     80         bytes3 = toUnsignedByteArray(this.par3);
     81         length += 2 + bytes3.length;
     82     }
     83 
     84     /**
     85      * Remove first byte if 0. Needed because BigInteger.toByteArray() sometimes
     86      * returns a zero prefix.
     87      */
     88     public static byte[] toUnsignedByteArray(BigInteger bi) {
     89         if (bi == null) {
     90             return null;
     91         }
     92         byte[] bb = bi.toByteArray();
     93         // bb is not null, and has at least 1 byte - ZERO is represented as [0]
     94         if (bb[0] == 0) {
     95             byte[] noZero = new byte[bb.length - 1];
     96             System.arraycopy(bb, 1, noZero, 0, noZero.length);
     97             return noZero;
     98         } else {
     99             return bb;
    100         }
    101     }
    102 
    103     /**
    104      * Creates inbound message
    105      * @param in
    106      * @param length
    107      * @param keyExchange
    108      * @throws IOException
    109      */
    110     public ServerKeyExchange(HandshakeIODataStream in, int length,
    111             int keyExchange) throws IOException {
    112 
    113         int size = in.readUint16();
    114         bytes1 = in.read(size);
    115         par1 = new BigInteger(1, bytes1);
    116         this.length = 2 + bytes1.length;
    117         size = in.readUint16();
    118         bytes2 = in.read(size);
    119         par2 = new BigInteger(1, bytes2);
    120         this.length += 2 + bytes2.length;
    121         if (keyExchange != CipherSuite.KeyExchange_RSA_EXPORT) {
    122             size = in.readUint16();
    123             bytes3 = in.read(size);
    124             par3 = new BigInteger(1, bytes3);
    125             this.length += 2 + bytes3.length;
    126         } else {
    127             par3 = null;
    128             bytes3 = null;
    129         }
    130         if (keyExchange != CipherSuite.KeyExchange_DH_anon_EXPORT
    131                 && keyExchange != CipherSuite.KeyExchange_DH_anon) {
    132             size = in.readUint16();
    133             hash = in.read(size);
    134             this.length += 2 + hash.length;
    135         } else {
    136             hash = null;
    137         }
    138         if (this.length != length) {
    139             fatalAlert(AlertProtocol.DECODE_ERROR,
    140                     "DECODE ERROR: incorrect ServerKeyExchange");
    141         }
    142     }
    143 
    144     /**
    145      * Sends message
    146      * @param out
    147      */
    148     @Override
    149     public void send(HandshakeIODataStream out) {
    150         out.writeUint16(bytes1.length);
    151         out.write(bytes1);
    152         out.writeUint16(bytes2.length);
    153         out.write(bytes2);
    154         if (bytes3 != null) {
    155             out.writeUint16(bytes3.length);
    156             out.write(bytes3);
    157         }
    158         if (hash != null) {
    159             out.writeUint16(hash.length);
    160             out.write(hash);
    161         }
    162     }
    163 
    164     /**
    165      * Returns RSAPublicKey generated using ServerRSAParams
    166      * (rsa_modulus and rsa_exponent).
    167      *
    168      * @return
    169      */
    170     public RSAPublicKey getRSAPublicKey() {
    171         if (key != null) {
    172             return key;
    173         }
    174         try {
    175             KeyFactory kf = KeyFactory.getInstance("RSA");
    176             key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1,
    177                     par2));
    178         } catch (Exception e) {
    179             return null;
    180         }
    181         return key;
    182     }
    183 
    184     /**
    185      * Returns message type
    186      * @return
    187      */
    188     @Override
    189     public int getType() {
    190         return Handshake.SERVER_KEY_EXCHANGE;
    191     }
    192 
    193 }
    194