blob: dd42cb1b0c4672a8d656ef570c0dd4e61ce42ab6 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.tlswire.handshake;
import libcore.tlswire.util.TlsProtocolVersion;
import libcore.tlswire.util.IoUtils;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
/**
* {@link ClientHello} {@link HandshakeMessage} from TLS 1.2 RFC 5246.
*/
public class ClientHello extends HandshakeMessage {
public TlsProtocolVersion clientVersion;
public byte[] random;
public byte[] sessionId;
public List<CipherSuite> cipherSuites;
public List<CompressionMethod> compressionMethods;
/** Extensions or {@code null} for no extensions. */
public List<HelloExtension> extensions;
@Override
protected void parseBody(DataInput in) throws IOException {
clientVersion = TlsProtocolVersion.read(in);
random = new byte[32];
in.readFully(random);
sessionId = IoUtils.readTlsVariableLengthByteVector(in, 32);
int[] cipherSuiteCodes = IoUtils.readTlsVariableLengthUnsignedShortVector(in, 0xfffe);
cipherSuites = new ArrayList<CipherSuite>(cipherSuiteCodes.length);
for (int i = 0; i < cipherSuiteCodes.length; i++) {
cipherSuites.add(CipherSuite.valueOf(cipherSuiteCodes[i]));
}
byte[] compressionMethodCodes = IoUtils.readTlsVariableLengthByteVector(in, 0xff);
compressionMethods = new ArrayList<CompressionMethod>(compressionMethodCodes.length);
for (int i = 0; i < compressionMethodCodes.length; i++) {
int code = compressionMethodCodes[i] & 0xff;
compressionMethods.add(CompressionMethod.valueOf(code));
}
int extensionsSectionSize;
try {
extensionsSectionSize = in.readUnsignedShort();
} catch (EOFException e) {
// No extensions present
extensionsSectionSize = 0;
}
if (extensionsSectionSize > 0) {
extensions = new ArrayList<HelloExtension>();
byte[] extensionsBytes = new byte[extensionsSectionSize];
in.readFully(extensionsBytes);
ByteArrayInputStream extensionsIn = new ByteArrayInputStream(extensionsBytes);
DataInput extensionsDataIn = new DataInputStream(extensionsIn);
while (extensionsIn.available() > 0) {
try {
extensions.add(HelloExtension.read(extensionsDataIn));
} catch (IOException e) {
throw new IOException(
"Failed to read HelloExtension #" + (extensions.size() + 1));
}
}
}
}
public HelloExtension findExtensionByType(int extensionType) {
if (extensions == null) {
return null;
}
for (HelloExtension extension : extensions) {
if (extension.type == extensionType) {
return extension;
}
}
return null;
}
@Override
public String toString() {
return "ClientHello{client version: " + clientVersion
+ ", random: " + new BigInteger(1, random).toString(16)
+ ", sessionId: " + new BigInteger(1, sessionId).toString(16)
+ ", cipher suites: " + cipherSuites
+ ", compression methods: " + compressionMethods
+ ((extensions != null) ? (", extensions: " + String.valueOf(extensions)) : "")
+ "}";
}
}