ServerKeyExchange.java revision aacf6f9741dea0f12fbff5e7696e53f251177280
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
18package org.apache.harmony.xnet.provider.jsse;
19
20import org.apache.harmony.xnet.provider.jsse.Message;
21
22import java.io.IOException;
23import java.math.BigInteger;
24import java.security.KeyFactory;
25import java.security.interfaces.RSAPublicKey;
26import 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 */
35public 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.KEY_EXCHANGE_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.KEY_EXCHANGE_DH_anon_EXPORT
131                && keyExchange != CipherSuite.KEY_EXCHANGE_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