001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Boris Kuznetsov
020: * @version $Revision$
021: */package org.apache.harmony.xnet.provider.jsse;
022:
023: import org.apache.harmony.xnet.provider.jsse.Message;
024:
025: import java.io.IOException;
026: import java.math.BigInteger;
027: import java.security.KeyFactory;
028: import java.security.interfaces.RSAPublicKey;
029: import java.security.spec.RSAPublicKeySpec;
030:
031: /**
032: *
033: * Represents server key exchange message.
034: * @see TLS 1.0 spec., 7.4.3. Server key exchange message.
035: * (http://www.ietf.org/rfc/rfc2246.txt)
036: *
037: */
038: public class ServerKeyExchange extends Message {
039:
040: // ServerRSAParams ServerDHParams
041: final BigInteger par1; // rsa_modulus dh_p
042: final byte[] bytes1;
043:
044: final BigInteger par2; // rsa_exponent dh_g
045: final byte[] bytes2;
046:
047: final BigInteger par3; // dh_Ys
048: final byte[] bytes3;
049:
050: /**
051: * Signature
052: */
053: final byte[] hash;
054:
055: private RSAPublicKey key;
056:
057: /**
058: * Creates outbound message
059: * @param par1 rsa_modulus or dh_p
060: * @param par2 rsa_exponent or dh_g
061: * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams
062: * @param hash should be null for anonymous SignatureAlgorithm
063: */
064: public ServerKeyExchange(BigInteger par1, BigInteger par2,
065: BigInteger par3, byte[] hash) {
066: this .par1 = par1;
067: this .par2 = par2;
068: this .par3 = par3;
069: this .hash = hash;
070:
071: byte[] bb = this .par1.toByteArray();
072: if (bb[0] == 0) {
073: // XXX check for par1 == 0 or bb.length > 1
074: bytes1 = new byte[bb.length - 1];
075: System.arraycopy(bb, 1, bytes1, 0, bytes1.length);
076: } else {
077: bytes1 = bb;
078: }
079:
080: bb = this .par2.toByteArray();
081: if (bb[0] == 0) {
082: bytes2 = new byte[bb.length - 1];
083: System.arraycopy(bb, 1, bytes2, 0, bytes2.length);
084: } else {
085: bytes2 = bb;
086: }
087:
088: length = 4 + bytes1.length + bytes2.length;
089: if (hash != null) {
090: length += 2 + hash.length;
091: }
092: if (par3 == null) {
093: bytes3 = null;
094: return;
095: }
096: bb = this .par3.toByteArray();
097: if (bb[0] == 0) {
098: bytes3 = new byte[bb.length - 1];
099: System.arraycopy(bb, 1, bytes3, 0, bytes3.length);
100: } else {
101: bytes3 = bb;
102: }
103: length += 2 + bytes3.length;
104: }
105:
106: /**
107: * Creates inbound message
108: * @param in
109: * @param length
110: * @param keyExchange
111: * @throws IOException
112: */
113: public ServerKeyExchange(HandshakeIODataStream in, int length,
114: int keyExchange) throws IOException {
115:
116: int size = in.readUint16();
117: bytes1 = in.read(size);
118: par1 = new BigInteger(1, bytes1);
119: this .length = 2 + bytes1.length;
120: size = in.readUint16();
121: bytes2 = in.read(size);
122: par2 = new BigInteger(1, bytes2);
123: this .length += 2 + bytes2.length;
124: if (keyExchange != CipherSuite.KeyExchange_RSA_EXPORT) {
125: size = in.readUint16();
126: bytes3 = in.read(size);
127: par3 = new BigInteger(1, bytes3);
128: this .length += 2 + bytes3.length;
129: } else {
130: par3 = null;
131: bytes3 = null;
132: }
133: if (keyExchange != CipherSuite.KeyExchange_DH_anon_EXPORT
134: && keyExchange != CipherSuite.KeyExchange_DH_anon) {
135: size = in.readUint16();
136: hash = in.read(size);
137: this .length += 2 + hash.length;
138: } else {
139: hash = null;
140: }
141: if (this .length != length) {
142: fatalAlert(AlertProtocol.DECODE_ERROR,
143: "DECODE ERROR: incorrect ServerKeyExchange");
144: }
145: }
146:
147: /**
148: * Sends message
149: * @param out
150: */
151: public void send(HandshakeIODataStream out) {
152: out.writeUint16(bytes1.length);
153: out.write(bytes1);
154: out.writeUint16(bytes2.length);
155: out.write(bytes2);
156: if (bytes3 != null) {
157: out.writeUint16(bytes3.length);
158: out.write(bytes3);
159: }
160: if (hash != null) {
161: out.writeUint16(hash.length);
162: out.write(hash);
163: }
164: }
165:
166: /**
167: * Returns RSAPublicKey generated using ServerRSAParams
168: * (rsa_modulus and rsa_exponent).
169: *
170: * @return
171: */
172: public RSAPublicKey getRSAPublicKey() {
173: if (key != null) {
174: return key;
175: }
176: try {
177: KeyFactory kf = KeyFactory.getInstance("RSA");
178: key = (RSAPublicKey) kf
179: .generatePublic(new RSAPublicKeySpec(par1, par2));
180: } catch (Exception e) {
181: return null;
182: }
183: return key;
184: }
185:
186: /**
187: * Returns message type
188: * @return
189: */
190: public int getType() {
191: return Handshake.SERVER_KEY_EXCHANGE;
192: }
193:
194: }
|