diff options
author | Alex Klyubin <klyubin@google.com> | 2014-11-13 21:59:42 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-11-13 21:59:42 +0000 |
commit | 5dddfb59b6d53e46eb88f574cfd87e668d08ceaf (patch) | |
tree | 7b5c7790f8ffe03ad90945022be6b190ee60e769 /support/src | |
parent | c9b535f4976f3b0546625912a71232c5699f0b72 (diff) | |
parent | 5dbbe8317afd79d21bdbe931fe476ccf9a4bf269 (diff) | |
download | libcore-5dddfb59b6d53e46eb88f574cfd87e668d08ceaf.zip libcore-5dddfb59b6d53e46eb88f574cfd87e668d08ceaf.tar.gz libcore-5dddfb59b6d53e46eb88f574cfd87e668d08ceaf.tar.bz2 |
am 5dbbe831: Merge "Basic library for parsing TLS/SSL ClientHellos in tests."
* commit '5dbbe8317afd79d21bdbe931fe476ccf9a4bf269':
Basic library for parsing TLS/SSL ClientHellos in tests.
Diffstat (limited to 'support/src')
11 files changed, 1194 insertions, 0 deletions
diff --git a/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java b/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java new file mode 100644 index 0000000..959379d --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/CipherSuite.java @@ -0,0 +1,473 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +/** + * {@code CipherSuite} enum from TLS 1.2 RFC 5246. + */ +public class CipherSuite { + // The list of cipher suites below is based on IANA registry + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] { + new CipherSuite(0x0000, "TLS_NULL_WITH_NULL_NULL"), + new CipherSuite(0x0001, "TLS_RSA_WITH_NULL_MD5"), + new CipherSuite(0x0002, "TLS_RSA_WITH_NULL_SHA"), + new CipherSuite(0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"), + new CipherSuite(0x0004, "TLS_RSA_WITH_RC4_128_MD5"), + new CipherSuite(0x0005, "TLS_RSA_WITH_RC4_128_SHA"), + new CipherSuite(0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"), + new CipherSuite(0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"), + new CipherSuite(0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x0009, "TLS_RSA_WITH_DES_CBC_SHA"), + new CipherSuite(0x000a, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x000b, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x000c, "TLS_DH_DSS_WITH_DES_CBC_SHA"), + new CipherSuite(0x000d, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x000e, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x000f, "TLS_DH_RSA_WITH_DES_CBC_SHA"), + new CipherSuite(0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA"), + new CipherSuite(0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA"), + new CipherSuite(0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"), + new CipherSuite(0x0018, "TLS_DH_anon_WITH_RC4_128_MD5"), + new CipherSuite(0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"), + new CipherSuite(0x001a, "TLS_DH_anon_WITH_DES_CBC_SHA"), + new CipherSuite(0x001b, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x001e, "TLS_KRB5_WITH_DES_CBC_SHA"), + new CipherSuite(0x001f, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0020, "TLS_KRB5_WITH_RC4_128_SHA"), + new CipherSuite(0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"), + new CipherSuite(0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"), + new CipherSuite(0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"), + new CipherSuite(0x0024, "TLS_KRB5_WITH_RC4_128_MD5"), + new CipherSuite(0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"), + new CipherSuite(0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"), + new CipherSuite(0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"), + new CipherSuite(0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"), + new CipherSuite(0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"), + new CipherSuite(0x002a, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"), + new CipherSuite(0x002b, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"), + new CipherSuite(0x002c, "TLS_PSK_WITH_NULL_SHA"), + new CipherSuite(0x002d, "TLS_DHE_PSK_WITH_NULL_SHA"), + new CipherSuite(0x002e, "TLS_RSA_PSK_WITH_NULL_SHA"), + new CipherSuite(0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x003a, "TLS_DH_anon_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x003b, "TLS_RSA_WITH_NULL_SHA256"), + new CipherSuite(0x003c, "TLS_RSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x003d, "TLS_RSA_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x003e, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x003f, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"), + new CipherSuite(0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5"), + new CipherSuite(0x0061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5"), + new CipherSuite(0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA"), + new CipherSuite(0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"), + new CipherSuite(0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA"), + new CipherSuite(0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"), + new CipherSuite(0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA"), + new CipherSuite(0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x006a, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x006b, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x006c, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x006d, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"), + new CipherSuite(0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"), + new CipherSuite(0x008a, "TLS_PSK_WITH_RC4_128_SHA"), + new CipherSuite(0x008b, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x008c, "TLS_PSK_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x008d, "TLS_PSK_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x008e, "TLS_DHE_PSK_WITH_RC4_128_SHA"), + new CipherSuite(0x008f, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"), + new CipherSuite(0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"), + new CipherSuite(0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"), + new CipherSuite(0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"), + new CipherSuite(0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"), + new CipherSuite(0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"), + new CipherSuite(0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"), + new CipherSuite(0x009a, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"), + new CipherSuite(0x009b, "TLS_DH_anon_WITH_SEED_CBC_SHA"), + new CipherSuite(0x009c, "TLS_RSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x009d, "TLS_RSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x009e, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x009f, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00a0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00a1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00a2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00a3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00a4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00a5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00a6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00a7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00a8, "TLS_PSK_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00a9, "TLS_PSK_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00aa, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00ab, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00ac, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0x00ad, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0x00ae, "TLS_PSK_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x00af, "TLS_PSK_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0x00b0, "TLS_PSK_WITH_NULL_SHA256"), + new CipherSuite(0x00b1, "TLS_PSK_WITH_NULL_SHA384"), + new CipherSuite(0x00b2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x00b3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0x00b4, "TLS_DHE_PSK_WITH_NULL_SHA256"), + new CipherSuite(0x00b5, "TLS_DHE_PSK_WITH_NULL_SHA384"), + new CipherSuite(0x00b6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0x00b7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0x00b8, "TLS_RSA_PSK_WITH_NULL_SHA256"), + new CipherSuite(0x00b9, "TLS_RSA_PSK_WITH_NULL_SHA384"), + new CipherSuite(0x00ba, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00bb, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00bc, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00bd, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00be, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00bf, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0x00c0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00c1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00c2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00c3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00c4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00c5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"), + new CipherSuite(0x00ff, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"), + new CipherSuite(0x5600, "TLS_FALLBACK_SCSV"), + new CipherSuite(0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"), + new CipherSuite(0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"), + new CipherSuite(0xc003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"), + new CipherSuite(0xc007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"), + new CipherSuite(0xc008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc00a, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc00b, "TLS_ECDH_RSA_WITH_NULL_SHA"), + new CipherSuite(0xc00c, "TLS_ECDH_RSA_WITH_RC4_128_SHA"), + new CipherSuite(0xc00d, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc00e, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc00f, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc010, "TLS_ECDHE_RSA_WITH_NULL_SHA"), + new CipherSuite(0xc011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"), + new CipherSuite(0xc012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc015, "TLS_ECDH_anon_WITH_NULL_SHA"), + new CipherSuite(0xc016, "TLS_ECDH_anon_WITH_RC4_128_SHA"), + new CipherSuite(0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc01a, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc01b, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc01c, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc01d, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc01e, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc01f, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0xc024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0xc025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0xc026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0xc027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0xc028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0xc029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0xc02a, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0xc02d, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0xc02e, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0xc031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"), + new CipherSuite(0xc032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"), + new CipherSuite(0xc033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"), + new CipherSuite(0xc034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"), + new CipherSuite(0xc035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"), + new CipherSuite(0xc036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"), + new CipherSuite(0xc037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"), + new CipherSuite(0xc038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"), + new CipherSuite(0xc039, "TLS_ECDHE_PSK_WITH_NULL_SHA"), + new CipherSuite(0xc03a, "TLS_ECDHE_PSK_WITH_NULL_SHA256"), + new CipherSuite(0xc03b, "TLS_ECDHE_PSK_WITH_NULL_SHA384"), + new CipherSuite(0xc03c, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc03d, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc03e, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc03f, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc04a, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc04b, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc04c, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc04d, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc04e, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc04f, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc05a, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc05b, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc05c, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc05d, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc05e, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc05f, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc06a, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc06b, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc06c, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc06d, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc06e, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"), + new CipherSuite(0xc06f, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"), + new CipherSuite(0xc070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"), + new CipherSuite(0xc071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"), + new CipherSuite(0xc072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc07a, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc07b, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc07c, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc07d, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc07e, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc07f, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc08a, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc08b, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc08c, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc08d, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc08e, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc08f, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"), + new CipherSuite(0xc093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"), + new CipherSuite(0xc094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc09a, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"), + new CipherSuite(0xc09b, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"), + new CipherSuite(0xc09c, "TLS_RSA_WITH_AES_128_CCM"), + new CipherSuite(0xc09d, "TLS_RSA_WITH_AES_256_CCM"), + new CipherSuite(0xc09e, "TLS_DHE_RSA_WITH_AES_128_CCM"), + new CipherSuite(0xc09f, "TLS_DHE_RSA_WITH_AES_256_CCM"), + new CipherSuite(0xc0a0, "TLS_RSA_WITH_AES_128_CCM_8"), + new CipherSuite(0xc0a1, "TLS_RSA_WITH_AES_256_CCM_8"), + new CipherSuite(0xc0a2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"), + new CipherSuite(0xc0a3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"), + new CipherSuite(0xc0a4, "TLS_PSK_WITH_AES_128_CCM"), + new CipherSuite(0xc0a5, "TLS_PSK_WITH_AES_256_CCM"), + new CipherSuite(0xc0a6, "TLS_DHE_PSK_WITH_AES_128_CCM"), + new CipherSuite(0xc0a7, "TLS_DHE_PSK_WITH_AES_256_CCM"), + new CipherSuite(0xc0a8, "TLS_PSK_WITH_AES_128_CCM_8"), + new CipherSuite(0xc0a9, "TLS_PSK_WITH_AES_256_CCM_8"), + new CipherSuite(0xc0aa, "TLS_PSK_DHE_WITH_AES_128_CCM_8"), + new CipherSuite(0xc0ab, "TLS_PSK_DHE_WITH_AES_256_CCM_8"), + new CipherSuite(0xc0ac, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"), + new CipherSuite(0xc0ad, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"), + new CipherSuite(0xc0ae, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"), + new CipherSuite(0xc0af, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"), + new CipherSuite(0xcc13, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"), + new CipherSuite(0xcc14, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"), + new CipherSuite(0xcc15, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305"), + }; + + private static final Map<Integer, CipherSuite> CODE_TO_CIPHER_SUITE; + private static final Map<String, CipherSuite> NAME_TO_CIPHER_SUITE; + + + static { + Map<Integer, CipherSuite> byCode = new HashMap<Integer, CipherSuite>(); + Map<String, CipherSuite> byName = new HashMap<String, CipherSuite>(); + for (CipherSuite cipherSuite : CIPHER_SUITES) { + if (byCode.put(cipherSuite.code, cipherSuite) != null) { + throw new RuntimeException( + "Cipher suite multiply defined: " + Integer.toHexString(cipherSuite.code)); + } + if (byName.put(cipherSuite.name, cipherSuite) != null) { + throw new RuntimeException( + "Cipher suite multiply defined: " + cipherSuite.name); + } + } + + // Add alternative names used in Android's platform-default TLS/SSL stack. + addAltName(byName, + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + addAltName(byName, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); + addAltName(byName, "TLS_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA"); + addAltName(byName, + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); + addAltName(byName, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); + addAltName(byName, "TLS_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA"); + addAltName(byName, + "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); + addAltName(byName, + "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"); + addAltName(byName, + "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); + addAltName(byName, "TLS_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_DES_CBC_SHA"); + addAltName(byName, "TLS_DH_anon_WITH_RC4_128_MD5", "SSL_DH_anon_WITH_RC4_128_MD5"); + addAltName(byName, + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"); + addAltName(byName, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_RC4_40_MD5"); + addAltName(byName, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"); + addAltName(byName, "TLS_RSA_WITH_DES_CBC_SHA", "SSL_RSA_WITH_DES_CBC_SHA"); + addAltName(byName, "TLS_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_NULL_MD5"); + addAltName(byName, "TLS_RSA_WITH_NULL_SHA", "SSL_RSA_WITH_NULL_SHA"); + addAltName(byName, "TLS_RSA_WITH_RC4_128_MD5", "SSL_RSA_WITH_RC4_128_MD5"); + addAltName(byName, "TLS_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA"); + + CODE_TO_CIPHER_SUITE = byCode; + NAME_TO_CIPHER_SUITE = byName; + } + + private static void addAltName(Map<String, CipherSuite> byName, String name, String altName) { + CipherSuite cipherSuite = byName.get(name); + if (cipherSuite == null) { + throw new IllegalArgumentException("Cipher suite not found: " + name); + } + byName.put(altName, cipherSuite); + } + + public final int code; + public final String name; + + private CipherSuite(int code, String name) { + this.code = code; + this.name = name; + } + + public static CipherSuite valueOf(String name) { + CipherSuite result = NAME_TO_CIPHER_SUITE.get(name); + if (result != null) { + return result; + } + throw new IllegalArgumentException("Unknown cipher suite: " + name); + } + + public static CipherSuite valueOf(int code) { + CipherSuite result = CODE_TO_CIPHER_SUITE.get(code); + if (result != null) { + return result; + } + return new CipherSuite(code, Integer.toHexString(code)); + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + code; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + CipherSuite other = (CipherSuite) obj; + if (code != other.code) { + return false; + } + return true; + } +} diff --git a/support/src/test/java/libcore/tlswire/handshake/ClientHello.java b/support/src/test/java/libcore/tlswire/handshake/ClientHello.java new file mode 100644 index 0000000..8d25cd5 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/ClientHello.java @@ -0,0 +1,108 @@ +/* + * 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.HexEncoding; +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.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: " + HexEncoding.encode(random) + + ", sessionId: " + HexEncoding.encode(sessionId) + + ", cipher suites: " + cipherSuites + + ", compression methods: " + compressionMethods + + ((extensions != null) ? (", extensions: " + String.valueOf(extensions)) : "") + + "}"; + } +} diff --git a/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java b/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java new file mode 100644 index 0000000..0f4f619 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/CompressionMethod.java @@ -0,0 +1,76 @@ +/* + * 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; + +/** + * {@code CompressionMethod} enum from TLS 1.2 RFC 5246. + */ +public class CompressionMethod { + + public static final CompressionMethod NULL = new CompressionMethod(0, "null"); + public static final CompressionMethod DEFLATE = new CompressionMethod(1, "deflate"); + + public final int type; + public final String name; + + private CompressionMethod(int type, String name) { + this.type = type; + this.name = name; + } + + public static CompressionMethod valueOf(int type) { + switch (type) { + case 0: + return NULL; + case 1: + return DEFLATE; + default: + return new CompressionMethod(type, String.valueOf(type)); + } + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + type; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + CompressionMethod other = (CompressionMethod) obj; + if (type != other.type) { + return false; + } + return true; + } +} diff --git a/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java b/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java new file mode 100644 index 0000000..a855b46 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/HandshakeMessage.java @@ -0,0 +1,62 @@ +/* + * 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.IoUtils; +import java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Handshake Protocol message from TLS 1.2 RFC 5246. + */ +public class HandshakeMessage { + public static final int TYPE_CLIENT_HELLO = 1; + + public int type; + public byte[] body; + + /** + * Parses the provided TLS record as a handshake message. + */ + public static HandshakeMessage read(DataInput in) throws IOException { + int type = in.readUnsignedByte(); + HandshakeMessage result; + switch (type) { + case TYPE_CLIENT_HELLO: + result = new ClientHello(); + break; + default: + result = new HandshakeMessage(); + break; + } + result.type = type; + int bodyLength = IoUtils.readUnsignedInt24(in); + result.body = new byte[bodyLength]; + in.readFully(result.body); + result.parseBody(new DataInputStream(new ByteArrayInputStream(result.body))); + return result; + } + + /** + * Parses the provided body. The default implementation does nothing. + * + * @throws IOException if an I/O error occurs. + */ + protected void parseBody(@SuppressWarnings("unused") DataInput in) throws IOException {} +} diff --git a/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java new file mode 100644 index 0000000..e3361b9 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java @@ -0,0 +1,100 @@ +/* + * 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.HexEncoding; +import libcore.tlswire.util.IoUtils; +import java.io.DataInput; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * {@code HelloExtension} struct from TLS 1.2 RFC 5246. + */ +public class HelloExtension { + + public static final int TYPE_SERVER_NAME = 0; + public static final int TYPE_PADDING = 21; + public static final int TYPE_SESSION_TICKET = 35; + + private static final Map<Integer, String> TYPE_TO_NAME = new HashMap<Integer, String>(); + static { + TYPE_TO_NAME.put(TYPE_SERVER_NAME, "server_name"); + TYPE_TO_NAME.put(1, "max_fragment_length"); + TYPE_TO_NAME.put(2, "client_certificate_url"); + TYPE_TO_NAME.put(3, "trusted_ca_keys"); + TYPE_TO_NAME.put(4, "truncated_hmac"); + TYPE_TO_NAME.put(5, "status_request"); + TYPE_TO_NAME.put(6, "user_mapping"); + TYPE_TO_NAME.put(7, "client_authz"); + TYPE_TO_NAME.put(8, "server_authz"); + TYPE_TO_NAME.put(9, "cert_type"); + TYPE_TO_NAME.put(10, "elliptic_curves"); + TYPE_TO_NAME.put(11, "ec_point_formats"); + TYPE_TO_NAME.put(12, "srp"); + TYPE_TO_NAME.put(13, "signature_algorithms"); + TYPE_TO_NAME.put(14, "use_srtp"); + TYPE_TO_NAME.put(15, "heartbeat"); + TYPE_TO_NAME.put(16, "application_layer_protocol_negotiation"); + TYPE_TO_NAME.put(17, "status_request_v2"); + TYPE_TO_NAME.put(18, "signed_certificate_timestamp"); + TYPE_TO_NAME.put(19, "client_certificate_type"); + TYPE_TO_NAME.put(20, "server_certificate_type"); + TYPE_TO_NAME.put(TYPE_PADDING, "padding"); + TYPE_TO_NAME.put(TYPE_SESSION_TICKET, "SessionTicket"); + TYPE_TO_NAME.put(13172, "next_protocol_negotiation"); + TYPE_TO_NAME.put(30031, "Channel ID (old)"); + TYPE_TO_NAME.put(30032, "Channel ID (new)"); + TYPE_TO_NAME.put(65281, "renegotiation_info"); + } + + public int type; + public String name; + public byte[] data; + + public static HelloExtension read(DataInput in) throws IOException { + int type = in.readUnsignedShort(); + HelloExtension result; + switch (type) { + case TYPE_SERVER_NAME: + result = new ServerNameHelloExtension(); + break; + default: + result = new HelloExtension(); + break; + } + result.type = type; + result.name = TYPE_TO_NAME.get(result.type); + if (result.name == null) { + result.name = String.valueOf(result.type); + } + result.data = IoUtils.readTlsVariableLengthByteVector(in, 0xffff); + result.parseData(); + return result; + } + + /** + * @throws IOException + */ + protected void parseData() throws IOException {} + + @Override + public String toString() { + return "HelloExtension{type: " + name + ", data: " + HexEncoding.encode(data) + "}"; + } +} diff --git a/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java b/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java new file mode 100644 index 0000000..afc9cfe --- /dev/null +++ b/support/src/test/java/libcore/tlswire/handshake/ServerNameHelloExtension.java @@ -0,0 +1,56 @@ +/* + * 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.IoUtils; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * {@code server_name} (SNI) {@link HelloExtension} from TLS 1.2 RFC 5246. + */ +public class ServerNameHelloExtension extends HelloExtension { + private static final int TYPE_HOST_NAME = 0; + + private List<String> hostnames; + + @Override + protected void parseData() throws IOException { + byte[] serverNameListBytes = IoUtils.readTlsVariableLengthByteVector( + new DataInputStream(new ByteArrayInputStream(data)), 0xffff); + ByteArrayInputStream serverNameListIn = new ByteArrayInputStream(serverNameListBytes); + DataInputStream in = new DataInputStream(serverNameListIn); + hostnames = new ArrayList<String>(); + while (serverNameListIn.available() > 0) { + int type = in.readUnsignedByte(); + if (type != TYPE_HOST_NAME) { + throw new IOException("Unsupported ServerName type: " + type); + } + byte[] hostnameBytes = IoUtils.readTlsVariableLengthByteVector(in, 0xffff); + String hostname = new String(hostnameBytes, "US-ASCII"); + hostnames.add(hostname); + } + } + + @Override + public String toString() { + return "HelloExtension{type: server_name, hostnames: " + hostnames + "}"; + } +} diff --git a/support/src/test/java/libcore/tlswire/record/TlsProtocols.java b/support/src/test/java/libcore/tlswire/record/TlsProtocols.java new file mode 100644 index 0000000..0ce0d35 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/record/TlsProtocols.java @@ -0,0 +1,30 @@ +/* + * 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.record; + +/** + * Protocols that can run over the TLS Record Protocol from TLS 1.2 RFC 5246. + */ +public class TlsProtocols { + public static final int CHANGE_CIPHER_SPEC = 20; + public static final int ALERT = 21; + public static final int HANDSHAKE = 22; + public static final int APPLICATION_DATA = 23; + public static final int HEARTBEAT = 24; + + private TlsProtocols() {} +} diff --git a/support/src/test/java/libcore/tlswire/record/TlsRecord.java b/support/src/test/java/libcore/tlswire/record/TlsRecord.java new file mode 100644 index 0000000..1b60407 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/record/TlsRecord.java @@ -0,0 +1,40 @@ +/* + * 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.record; + +import libcore.tlswire.util.TlsProtocolVersion; +import java.io.DataInput; +import java.io.IOException; + +/** + * TLS Record Protocol record from TLS 1.2 RFC 5246. + */ +public class TlsRecord { + public int type; + public TlsProtocolVersion version; + public byte[] fragment; + + public static TlsRecord read(DataInput in) throws IOException { + TlsRecord result = new TlsRecord(); + result.type = in.readUnsignedByte(); + result.version = TlsProtocolVersion.read(in); + int fragmentLength = in.readUnsignedShort(); + result.fragment = new byte[fragmentLength]; + in.readFully(result.fragment); + return result; + } +} diff --git a/support/src/test/java/libcore/tlswire/util/HexEncoding.java b/support/src/test/java/libcore/tlswire/util/HexEncoding.java new file mode 100644 index 0000000..2061fcc --- /dev/null +++ b/support/src/test/java/libcore/tlswire/util/HexEncoding.java @@ -0,0 +1,93 @@ +/* + * 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.util; + +import java.nio.ByteBuffer; + +/** + * Hexadecimal encoding where each byte is represented by two hexadecimal digits. + */ +public class HexEncoding { + + /** Hidden constructor to prevent instantiation. */ + private HexEncoding() {} + + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + + /** + * Encodes the provided data as a hexadecimal string. + */ + public static String encode(byte[] data) { + return encode(data, 0, data.length); + } + + /** + * Encodes the provided data as a hexadecimal string. + */ + public static String encode(byte[] data, int offset, int len) { + StringBuilder result = new StringBuilder(len * 2); + for (int i = 0; i < len; i++) { + byte b = data[offset + i]; + result.append(HEX_DIGITS[(b >>> 4) & 0x0f]); + result.append(HEX_DIGITS[b & 0x0f]); + } + return result.toString(); + } + + /** + * Encodes the provided data as a hexadecimal string. + */ + public static String encode(ByteBuffer buf) { + return encode(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining()); + } + + /** + * Decodes the provided hexadecimal string into an array of bytes. + */ + public static byte[] decode(String encoded) { + // IMPLEMENTATION NOTE: Special care is taken to permit odd number of hexadecimal digits. + int resultLengthBytes = (encoded.length() + 1) / 2; + byte[] result = new byte[resultLengthBytes]; + int resultOffset = 0; + int encodedCharOffset = 0; + if ((encoded.length() % 2) != 0) { + // Odd number of digits -- the first digit is the lower 4 bits of the first result byte. + result[resultOffset++] = + (byte) getHexadecimalDigitValue(encoded.charAt(encodedCharOffset)); + encodedCharOffset++; + } + for (int len = encoded.length(); encodedCharOffset < len; encodedCharOffset += 2) { + result[resultOffset++] = (byte) ( + (getHexadecimalDigitValue(encoded.charAt(encodedCharOffset)) << 4) + | getHexadecimalDigitValue(encoded.charAt(encodedCharOffset + 1))); + } + return result; + } + + private static int getHexadecimalDigitValue(char c) { + if ((c >= 'a') && (c <= 'f')) { + return (c - 'a') + 0x0a; + } else if ((c >= 'A') && (c <= 'F')) { + return (c - 'A') + 0x0a; + } else if ((c >= '0') && (c <= '9')) { + return c - '0'; + } else { + throw new IllegalArgumentException("Invalid hexadecimal digit at position : '" + c + + "' (0x" + Integer.toHexString(c) + ")"); + } + } +} diff --git a/support/src/test/java/libcore/tlswire/util/IoUtils.java b/support/src/test/java/libcore/tlswire/util/IoUtils.java new file mode 100644 index 0000000..1e2d8f2 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/util/IoUtils.java @@ -0,0 +1,59 @@ +/* + * 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.util; + +import java.io.DataInput; +import java.io.IOException; + +public class IoUtils { + + public static int readUnsignedInt24(DataInput in) throws IOException { + return (in.readUnsignedByte() << 16) | in.readUnsignedShort(); + } + + public static byte[] readTlsVariableLengthByteVector(DataInput in, int maxSizeBytes) + throws IOException { + int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes); + byte[] result = new byte[sizeBytes]; + in.readFully(result); + return result; + } + + public static int[] readTlsVariableLengthUnsignedShortVector(DataInput in, int maxSizeBytes) + throws IOException { + int sizeBytes = readTlsVariableLengthVectorSizeBytes(in, maxSizeBytes); + int elementCount = sizeBytes / 2; + int[] result = new int[elementCount]; + for (int i = 0; i < elementCount; i++) { + result[i] = in.readUnsignedShort(); + } + return result; + } + + private static int readTlsVariableLengthVectorSizeBytes(DataInput in, int maxSizeBytes) + throws IOException { + if (maxSizeBytes < 0x100) { + return in.readUnsignedByte(); + } else if (maxSizeBytes < 0x10000) { + return in.readUnsignedShort(); + } else if (maxSizeBytes < 0x1000000) { + return readUnsignedInt24(in); + } else { + return in.readInt(); + } + } +} diff --git a/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java b/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java new file mode 100644 index 0000000..f58faf2 --- /dev/null +++ b/support/src/test/java/libcore/tlswire/util/TlsProtocolVersion.java @@ -0,0 +1,97 @@ +/* + * 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.util; + +import java.io.DataInput; +import java.io.IOException; + +/** + * {@code ProtovolVersion} struct from TLS 1.2 RFC 5246. + */ +public class TlsProtocolVersion { + public static final TlsProtocolVersion SSLV3 = new TlsProtocolVersion(3, 0, "SSLv3"); + public static final TlsProtocolVersion TLSv1_0 = new TlsProtocolVersion(3, 1, "TLSv1.0"); + public static final TlsProtocolVersion TLSv1_1 = new TlsProtocolVersion(3, 2, "TLSv1.1"); + public static final TlsProtocolVersion TLSv1_2 = new TlsProtocolVersion(3, 3, "TLSv1.2"); + + public final int major; + public final int minor; + public final String name; + + private TlsProtocolVersion(int major, int minor, String name) { + this.major = major; + this.minor = minor; + this.name = name; + } + + public static TlsProtocolVersion valueOf(int major, int minor) { + if (major == 3) { + switch (minor) { + case 0: + return SSLV3; + case 1: + return TLSv1_0; + case 2: + return TLSv1_1; + case 3: + return TLSv1_2; + } + } + return new TlsProtocolVersion(major, minor, major + "." + minor); + } + + public static TlsProtocolVersion read(DataInput in) throws IOException { + int major = in.readUnsignedByte(); + int minor = in.readUnsignedByte(); + return TlsProtocolVersion.valueOf(major, minor); + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + major; + result = prime * result + minor; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + TlsProtocolVersion other = (TlsProtocolVersion) obj; + if (major != other.major) { + return false; + } + if (minor != other.minor) { + return false; + } + return true; + } +} |