From d02fe5f60f65676d946a85725bbcfc92a2687b0f Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 20 Apr 2020 19:43:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=B0=D0=B3=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../keyshare/ClientKeyShareExtension.java | 2 +- .../tls/numbers/HandshakeType.java | 8 ++--- .../tls/records/HandshakeRecord.java | 16 +++++++--- .../handshakes/BasicRecordContent.java | 32 +++++++++++++++++++ .../HelloHandshakeRecordContent.java | 2 +- .../handshakes/UnknownRecordContent.java | 27 ---------------- .../ru/serega6531/packmate/TlsPacketTest.java | 2 +- src/test/resources/tls-wolfram.pkmt | 12 +++++++ 8 files changed, 62 insertions(+), 39 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java delete mode 100644 src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/UnknownRecordContent.java create mode 100644 src/test/resources/tls-wolfram.pkmt diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java index 1834e8f..c834da3 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java @@ -16,7 +16,7 @@ public class ClientKeyShareExtension extends KeyShareExtension { super(type, extensionLength); this.keyShareLength = ByteArrays.getShort(rawData, KEY_SHARE_LENGTH_OFFSET + offset); // the field is not always there int cursor = KEY_SHARE_ENTRY_OFFSET + offset; - ByteArrays.validateBounds(rawData, cursor + offset, keyShareLength); + ByteArrays.validateBounds(rawData, cursor, keyShareLength); readEntries(rawData, KEY_SHARE_ENTRY_OFFSET + offset, offset + keyShareLength); } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java index 5e02c67..228f68b 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java @@ -34,17 +34,15 @@ public class HandshakeType extends NamedNumber { public static final HandshakeType COMPRESSED_CERTIFICATE = new HandshakeType((byte) 25, "Compressed Certificate"); public static final HandshakeType MESSAGE_HASH = new HandshakeType((byte) 254, "Message Hash"); + public static final HandshakeType ENCRYPTED_HANDSHAKE_MESSAGE = new HandshakeType((byte) 255, "Encrypted Handshake Message"); + public HandshakeType(Byte value, String name) { super(value, name); registry.put(value, this); } public static HandshakeType getInstance(Byte value) { - if (registry.containsKey(value)) { - return registry.get(value); - } else { - throw new IllegalArgumentException("Unknown handshake type " + value); - } + return registry.getOrDefault(value, ENCRYPTED_HANDSHAKE_MESSAGE); } @Override diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java index 6cb742e..bffc1a5 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java @@ -2,10 +2,10 @@ package ru.serega6531.packmate.service.optimization.tls.records; import org.pcap4j.util.ByteArrays; import ru.serega6531.packmate.service.optimization.tls.numbers.HandshakeType; +import ru.serega6531.packmate.service.optimization.tls.records.handshakes.BasicRecordContent; import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ClientHelloHandshakeRecordContent; import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent; import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.UnknownRecordContent; import ru.serega6531.packmate.utils.BytesUtils; import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; @@ -29,11 +29,19 @@ public class HandshakeRecord implements TlsRecord { public static HandshakeRecord newInstance(byte[] rawData, int offset, int length) { ByteArrays.validateBounds(rawData, offset, length); - return new HandshakeRecord(rawData, offset); + return new HandshakeRecord(rawData, offset, length); } - private HandshakeRecord(byte[] rawData, int offset) { + private HandshakeRecord(byte[] rawData, int offset, int length) { this.handshakeType = HandshakeType.getInstance(ByteArrays.getByte(rawData, HANDSHAKE_TYPE_OFFSET + offset)); + + if (handshakeType == HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE) { + this.content = BasicRecordContent.newInstance( + rawData, offset, handshakeLength); + this.handshakeLength = length; + return; + } + this.handshakeLength = BytesUtils.getThreeBytesInt(rawData, LENGTH_OFFSET + offset); if (handshakeType == HandshakeType.CLIENT_HELLO) { @@ -43,7 +51,7 @@ public class HandshakeRecord implements TlsRecord { this.content = ServerHelloHandshakeRecordContent.newInstance( rawData, offset + CONTENT_OFFSET, handshakeLength); } else { - this.content = UnknownRecordContent.newInstance( + this.content = BasicRecordContent.newInstance( rawData, offset + CONTENT_OFFSET, handshakeLength); } } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java new file mode 100644 index 0000000..3053cbb --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java @@ -0,0 +1,32 @@ +package ru.serega6531.packmate.service.optimization.tls.records.handshakes; + +import org.pcap4j.util.ByteArrays; + +public class BasicRecordContent implements HandshakeRecordContent { + + /** + * 0x0 - Content + * 0x0 + length - End + */ + + private byte[] content; + + public static BasicRecordContent newInstance(byte[] rawData, int offset, int length) { + if(length > 0) { + ByteArrays.validateBounds(rawData, offset, length); + } + return new BasicRecordContent(rawData, offset, length); + } + + public BasicRecordContent(byte[] rawData, int offset, int length) { + content = new byte[length]; + if (length > 0) { + System.arraycopy(rawData, offset, content, 0, length); + } + } + + @Override + public String toString() { + return " [" + content.length + " bytes]"; + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java index b8d7c68..b39d246 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java @@ -58,7 +58,7 @@ public abstract class HelloHandshakeRecordContent implements HandshakeRecordCont @Override public String toString() { return " TLS version: " + version + "\n" + - " Client random: " + ByteArrays.toHexString(random, "") + "\n" + + " Random: " + ByteArrays.toHexString(random, "") + "\n" + " Session id: " + (sessionIdLength > 0 ? ByteArrays.toHexString(sessionId, "") : "null") + "\n" + " Extensions: " + extensions.toString(); } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/UnknownRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/UnknownRecordContent.java deleted file mode 100644 index bf93d55..0000000 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/UnknownRecordContent.java +++ /dev/null @@ -1,27 +0,0 @@ -package ru.serega6531.packmate.service.optimization.tls.records.handshakes; - -import org.pcap4j.util.ByteArrays; - -public class UnknownRecordContent implements HandshakeRecordContent { - - /** - * 0x0 - Content - * 0x0 + length - End - */ - - private byte[] content; - - public static UnknownRecordContent newInstance(byte[] rawData, int offset, int length) { - ByteArrays.validateBounds(rawData, offset, length); - return new UnknownRecordContent(rawData, offset, length); - } - - public UnknownRecordContent(byte[] rawData, int offset, int length) { - System.arraycopy(rawData, offset, content, 0, length); - } - - @Override - public String toString() { - return " [" + content.length + " bytes]"; - } -} diff --git a/src/test/java/ru/serega6531/packmate/TlsPacketTest.java b/src/test/java/ru/serega6531/packmate/TlsPacketTest.java index 6bff830..b4bdc62 100644 --- a/src/test/java/ru/serega6531/packmate/TlsPacketTest.java +++ b/src/test/java/ru/serega6531/packmate/TlsPacketTest.java @@ -12,7 +12,7 @@ public class TlsPacketTest { @Test public void testHandshake() throws IOException, IllegalRawDataException { - List packets = new PackmateDumpFileLoader("tls.pkmt").getPackets(); + List packets = new PackmateDumpFileLoader("tls-wolfram.pkmt").getPackets(); for (int i = 0; i < packets.size(); i++) { Packet packet = packets.get(i); diff --git a/src/test/resources/tls-wolfram.pkmt b/src/test/resources/tls-wolfram.pkmt new file mode 100644 index 0000000..8d6a11d --- /dev/null +++ b/src/test/resources/tls-wolfram.pkmt @@ -0,0 +1,12 @@ +in +16030102080100020403033cacafd80da2c7b6507ad4a82dd44469a5ede59b3f1d3f5595b8533147e51a322007571463d48695c8ef338d64d4ca58829ce8c82f40f1119f4262fe18ae5bb43a0022aaaa130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035000a010001994a4a00000000001900170000147777772e776f6c6672616d616c7068612e636f6d00170000ff01000100000a000a00083a3a001d00170018000b00020100002300d032cc6da13ecb9a423fdaeee85ac3c111698f6e1bfb0b23cb4b0aa834049fb66969e3a3c78099562f7a56df248c819f1364c69b72d7cd1cd194c6386ecf6d1c80d291a90796082b7349b17fd0bfccf3db57ca1067756e5b93e1d300c239b693787d392889c43954d5dfc7f80405768fcfcb794c3efb2334c521a4b63777c240a2eb0e323265d3d96399c75af9502cd351995d1a7405ffdbbf79ee9196ad223c4e2a95001cd0822182640df1bb9b96ac604d99371e4ce1bbfe226b557977c1f4c52114288ce0e43fa924ea2739d104a2a70010000e000c02683208687474702f312e31000500050100000000000d00140012040308040401050308050501080606010201001200000033002b00293a3a000100001d0020ee0e132bfe9596d5ae8bbc24c6028eda34234bea39c3e669691a1ee161559113002d00020101002b000b0aeaea0304030303020301001b00030200025a5a000100 +out +16030300410200003d03035e9dc313cbb7f3eac9fa8c65d2eceff70245667880a2b4b411b292930823d21600c02f00001500000000ff01000100000b00040300010200230000 +160303142e0b00142a0014270006c2308206be308205a6a0030201020208282df9ff6f0fbd7f300d06092a864886f70d01010b05003081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d204732301e170d3139303131363139353431385a170d3231303131363139353431385a30403121301f060355040b1318446f6d61696e20436f6e74726f6c2056616c696461746564311b301906035504030c122a2e776f6c6672616d616c7068612e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100cc32bc417eb7ad0b53caac654a295d2b21a3962e748c03fd83409e663134a321f05b1b80707dd3944c04d503f85c46f230a8f8d9b5ca1a293f411386066b7af589d3fdd180ebe4422222955931221065addaea9b5d8461c8bea94620cf8d21c6e828e64fa34eb34092c1355c07ec3c8af0aea72620df1d8ef7c54686ee3ca243caa55a2ca746dd0ff19fa24f80f18ac0a59139df8714471d0f4c10bdeee4ecd36e26c17e73a06310deb24762e473c6d4f0b0454531b174a25123b99105dde04c136414dca747a3a303b508bfc86536fd6f4f7ed5e5cc05bf3036a06876b9bc2850c926b698761c3968b312f8d718aa7e6811fac6e72a9ac06e2eb3f1b48930330203010001a382034530820341300c0603551d130101ff04023000301d0603551d250416301406082b0601050507030106082b06010505070302300e0603551d0f0101ff0404030205a030370603551d1f0430302e302ca02aa0288626687474703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d3930372e63726c305d0603551d20045630543048060b6086480186fd6d010717013039303706082b06010505070201162b687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f3008060667810c010201307606082b06010505070101046a3068302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b060105050730028634687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f67646967322e637274301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b42c80ce302f0603551d110428302682122a2e776f6c6672616d616c7068612e636f6d8210776f6c6672616d616c7068612e636f6d301d0603551d0e04160414ad7962c67d71f16ec954a7172e0a822595208eb03082017f060a2b06010401d6790204020482016f0482016b0169007600a4b90990b418581487bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc1000000168583a9c040000040300473045022048e3d869c091a5acb1fa7a6f5dbb62b44941b75f945948e27c44a85b12273e14022100b2e85859da20a9c63b7372e09c95a4298bbcff2afdd9b02a313cb461a312af40007700ee4bbdb775ce60bae142691fabe19e66a30f7e5fb072d88300c47b897aa8fdcb00000168583a9d6c0000040300483046022100dcba67948e0831c649f9607aba1ca1b49a7b7d3f97d2f1dada43016a1d85db53022100fb9330cc24e523185879643c5dcb537b99dc423e85d364173f7d29a519565fdf0076004494652eb0eeceafc44007d8a8fe28c0dae682bed8cb31b53fd33396b5b681a800000168583aa24300000403004730450220129e12ac21b519ff3ad7274615b12c3c0183d15155ffabf8de708aa3bf8dc4b2022100a1633c63c181cbd453e6395629231cbb678a3583913eb481acda388bd66f53d3300d06092a864886f70d01010b0500038201010079e399f3a4adb47505781034b6e94c033971fb5e557cb2b8c2cf82e9500a15a7b2795929b62319a2c0257c8717214f855aa0d8559b14a9bbcacd1b052dd7227392681df33954e5b18d433ec4b7f8434f5cfe2b6b1852206f54d97af5cf5ece31b189bc150c36e8e350cbf912c50e11ba3fa7ff72c4c85f0ffca1be56adf0526ad092e06bffa45986d0fa3e8328d22d5ff028e7f77122c34970470e59ad559918a1d5f8713cda60ee551e9d3b3944951908edd90cde7a68db3e676636d01d2555f48133cf6db20e563b39d887f07228c9a76997ec053e360526bf5a2a84bb8baee098c4149f267c153166d189c248742b28014812293d7798b543e75e192cbe2f0004d4308204d0308203b8a003020102020107300d06092a864886f70d01010b0500308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d204732301e170d3131303530333037303030305a170d3331303530333037303030305a3081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010004813082047d30820365a00302010202031be715300d06092a864886f70d01010b05003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3134303130313037303030305a170d3331303533303037303030305a308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e0470203010001a382011730820113300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1345f6477184051df8c30a6af00040430820400308202e8a003020102020100300d06092a864886f70d01010505003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3034303632393137303632305a170d3334303632393137303632305a3063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f7269747930820120300d06092a864886f70d01010105000382010d00308201080282010100de9dd7ea571849a15bebd75f4886eabeddffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2ccd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f72364ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a2132dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c6447b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf020103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479820100300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a002126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320ce42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f +160303014d0c0001490300174104a6597b80cf773fa31ff1feb9999ac8af9ef7249de5679d3212cc56e76efbe796ff06baf7186d8bf5c33053779eaf0ef560139a9405813238167f2743d24f21f30401010067e524e5c265f39cd8b0fa60c88e07936d7b14c3da4034156d140a4dd20de3e819789911956afe97e19fbc4975c477c982d3a504fcf0b1f560a6a2c9df8fe2c83efff710bcdba1c127817aa3e1960ecac7e21e11c4efd24ce53ca0d51a52c1f1dec4924a442adc22853613e15a6b9b118909b04cebad1d413b11b87799ac9db84fb1c3f1380776ca243175d5237ff31e200fd380c00cb48b7abc539fa3d9870a276ac54b33d2579b964831efd0238df2455fc5ddbade451b6d160eb49e86e47187e3c248a45fb437b6d60ffaedba91e522ff75b6bc39540927e28520a79bfaa7ff64ad1e1d6415d134b72f5a60c0373b3e231b54a0a0143e67b89fb3eb5af09416030300040e000000 +in +1603030046100000424104d19edcdc25f96f94535af6ad13d3eed143a5d9578e6eb032bffe3366f6f05d177e8ba7b0180c633f2dd840daa88059d49b4694ec478cea5dae8489222c7adb5414030300010116030300280000000000000000d3313dba0b45962f68599291aff278149c2533d2be074f6adaee660a38abce27 +out +16030300da040000d60000012c00d0ab99aa4957c3bb4136c3ba78b8336f9fbc18b6b963cf89eae4856faced407b70f0b15ba2777aaf7a0b8ea6ee79a13a1a42c73d39aebb625f296d421eadbffe1429276391b3c257e175949d1cb1ca67239ce6726340de4bd46e56e15ec5566c4168941085b6dd3dc9c158e37e52dd1ecde908635e73f0826ba068793fc73a4350a4c4881471d5e848de45f258357e590403b271538a3b05a978664d044585b20007c750c9a2bb930c107338338959e987938d3858ddbedefe6d11bf4caa2718717495ff300e058267089b163ba198092d1403030001011603030028473e0c496206364b850e5fb95bb8c21e2e0f3726f233d323ff01a91d48db03b4396a5aaadc7f45b0 +in +17030302e30000000000000001d1b7489da691fe047432696ef1eb14e17029b379f35621e2d066d49bcfad48db3ae58893753344cfabbd1c021cd8f89ea7ce89b3cffeae7175784e3895d4bef4fb7a47e36732594bfdcc2144ecac486b23858a0bbb231d498bc2fb89bc8422c8ff9330cb705ff4af82b4ebbc2705f43c869ff8d95948168e49c96af6cc3649d0dc1d98c796096bd024f48d665e5f4da719a21fb7363e1f7b44e27b2954efd9cbc5add833f9fe1eb807922c162e78b9e1e8855ff0d8ae75ea1392ecb5169875b61249ac48a0c2952fe0ad60e150294e7ebab0c09cf92ec955c1d280ef04a691b05a42a3eccbd2ef14e8b6179a8bd80352c0ceaa242afe966e587b6b19c8fb256e6903065ffd7c4a3d1fe8fd056e9fee5f236082ee407c738603d9fdf979e13e051d2049df6ac3ac085d591d0c7ee019037ac7c0477de9aefab2f7a1f1e3c50ae3dfb320fa55a020989239d53a8b174950f970a9c772780fafc7b6a77bc7dce612bb21eb0cca85b4a0c0f2e4798e6ffeef43d80789bdd6e3102ff94c7dfd014e232afc51b80644b6dab149e2da1dd9e3f9f2969f6fd42d84a794f796294dbe1b03739a60b9216eb533662fab15db8d059964b3a6c4686da3437d5f9e94bf901a036784da90e38d787450789bc0cba68992086f6909967309005efadfb654d01f5edc40fa4555a24273b4ae3f1baf17f148910d26c847df201795a01e901c5dd240ae8512a22f63a5c34ce43c293930a27cb092d2ea3a015e37e06c7258fc72bbda0bdf1361d3c7997ed23703433f002af4df019f29d3853472cb8c1125605c6257e357a9e50f917e8e991733529d6d422a9948aa2d290dbca1446aacead7294486e05f1fb0dd81699aa450665e66c8435fc2b324be690f0fba817fd534dd49722427bd7dc22a04c0e4181b0b39bc3bd20460f2c30936c01f9ff14b9326d0db3e771fb30867474debf05473a98d2a80e56bf6e9d365ba1ebf13024c9ef7480d8c5f2ed486d17dfb4282d028c53a2b5523e324e645954b14b2197f39ec \ No newline at end of file