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.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     /**
    102      * Creates inbound message
    103      * @param in
    104      * @param length
    105      * @param keyExchange
    106      * @throws IOException
    107      */
    108     public ServerKeyExchange(HandshakeIODataStream in, int length,
    109             int keyExchange) throws IOException {
    110 
    111         int size = in.readUint16();
    112         bytes1 = in.read(size);
    113         par1 = new BigInteger(1, bytes1);
    114         this.length = 2 + bytes1.length;
    115         size = in.readUint16();
    116         bytes2 = in.read(size);
    117         par2 = new BigInteger(1, bytes2);
    118         this.length += 2 + bytes2.length;
    119         if (keyExchange != CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    120             size = in.readUint16();
    121             bytes3 = in.read(size);
    122             par3 = new BigInteger(1, bytes3);
    123             this.length += 2 + bytes3.length;
    124         } else {
    125             par3 = null;
    126             bytes3 = null;
    127         }
    128         if (keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT
    129                 && keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon) {
    130             size = in.readUint16();
    131             hash = in.read(size);
    132             this.length += 2 + hash.length;
    133         } else {
    134             hash = null;
    135         }
    136         if (this.length != length) {
    137             fatalAlert(AlertProtocol.DECODE_ERROR,
    138                     "DECODE ERROR: incorrect ServerKeyExchange");
    139         }
    140     }
    141 
    142     /**
    143      * Sends message
    144      * @param out
    145      */
    146     @Override
    147     public void send(HandshakeIODataStream out) {
    148         out.writeUint16(bytes1.length);
    149         out.write(bytes1);
    150         out.writeUint16(bytes2.length);
    151         out.write(bytes2);
    152         if (bytes3 != null) {
    153             out.writeUint16(bytes3.length);
    154             out.write(bytes3);
    155         }
    156         if (hash != null) {
    157             out.writeUint16(hash.length);
    158             out.write(hash);
    159         }
    160     }
    161 
    162     /**
    163      * Returns RSAPublicKey generated using ServerRSAParams
    164      * (rsa_modulus and rsa_exponent).
    165      *
    166      * @return
    167      */
    168     public RSAPublicKey getRSAPublicKey() {
    169         if (key != null) {
    170             return key;
    171         }
    172         try {
    173             KeyFactory kf = KeyFactory.getInstance("RSA");
    174             key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1,
    175                     par2));
    176         } catch (Exception e) {
    177             return null;
    178         }
    179         return key;
    180     }
    181 
    182     /**
    183      * Returns message type
    184      * @return
    185      */
    186     @Override
    187     public int getType() {
    188         return Handshake.SERVER_KEY_EXCHANGE;
    189     }
    190 
    191 }
    192