일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 람다 칼큘러스
- Java
- Collections
- solid
- 스택
- javscript
- 겨울카카오인턴
- 프로그래머스
- 자바
- Python
- Rails
- JavaScript
- design-pattern
- JDBC
- 로버트마틴
- exception
- DesignPattern
- tcp
- 함수형 프로그래밍
- functional programming
- lambda calculus
- 파이썬
- Spring
- Network
- Collection
- Pattern
- 큐
- Eclipse
- 디자인패턴
- 백준
- Today
- Total
개발자 노트
TLS 통신 패킷 분석 본문
tls 통신 패킷 분석
참고
- https://en.wikipedia.org/wiki/Transport_Layer_Security
- https://datatracker.ietf.org/doc/html/rfc5246
이전에 TCP 3way handshake까지 살펴보았는데요.
이번 글에선 TLS 통신을 살펴보겠습니다.
TLS 통신에 대한 간략한 내용은 많은 블로그 분들이 다뤄주셨기 때문에 개인 공부겸 RFC 문서와 비교해가면서 작성해보겠습니다.
그리고 다음 글에선 그리고 암호화된 application layer data를 복호화까지 진행해보겠습니다.
TLS또한 stateful connection oriented protocol이라는 것을 명심해주시고 보면 좋겠습니다.
통신 내용
TCP
TCP에서 Push flag가 1인 상태로 client → server로 전송합니다.
PSH의 의미는 도착하는 즉시 upper layer에 push 하라는 의미이지요.
TCP payload를 살펴보겠습니다.
TLS의 값들이 쭉 나열되어 있네요.
TLS Record Layer
https://datatracker.ietf.org/doc/html/rfc5246#section-6.2
higher layers로부터 생 데이터(uninterpreted data)를 받는 layer라고 보시면 됩니다. 그리고 그 데이터는 다음 3가지로 분류되죠
- ProtocolVersion
- ContentType
- TLSPlaintext
구조는 아래와 같습니다.
struct {
uint8 major;
uint8 minor;
} ProtocolVersion;
enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
TLSPlaintext
https://datatracker.ietf.org/doc/html/rfc5246#section-6.2
구조는 다음과 같습니다.
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
ContentType
메모리를 보시면 16진수로 16을 나타내고 있습니다. 즉 22라는 값이죠. 이는 ContentType enum부분을 보시면 handshake(22)
를 의미합니다.
네, 핸드쉐이크를 요청하는 패킷입니다.
Version
Version에 해당하는 인덱스의 값들은 03 01
을 가리키고 있습니다.
RFC 문서에서는 TLS 1.0을 나타낸다고 적혀 있네요.
Record Layer의 버전입니다. Client Hello에 적인 TLS 버전이 아닙니다. 이는 ClientHello에서 결정된다고 하네요. 임의로 1.0으로 보낸 것 같습니다.
주목하실 사항은 TLS PlainText
의 버전이 1.0으로 표기되어 있지만 이후 나오는 Fragment에서의 client_version은 1.2로 표기됩니다. client_version은 클라이언트가 지원가능한 최신 버전을 적도록 되어있는 것을 보니, TLS PlainText의 tls version은 클라이언트가 지원 가능한 최소 지원 버전으로 이해하면? 될 것 같습니다.
Length
TLSPlaintext fragment의 길이라고 합니다. 512bytes 라는 뜻이죠.
Fragment
application data를 의미합니다.
아래 값들이 모두 application data입니다!
HandShake Protocol in Fragment
여기서 부터가 바로 Client Hello니 Server Hello 같은 data들을 볼 수 있습니다.
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4
Handshake Type
여기에 나오는 값으로 1일 경우에 client_hello네요.
struct에서 보시는 대로, HandShakeType 별로 body의 타입이 달라집니다. ClientHello의 body먼저 볼 예정입니다.
Length
3바이트를 할당받습니다. body의 길이를 알려주죠.
TLS Full HandShake
tls session 관리를 session ticket으로 진행하기 때문에
https://datatracker.ietf.org/doc/html/rfc5077
에 나오는 TLS FullHandShake로 플로우가 진행되겠습니다.
Client Hello
구조는 아래와 같습니다.
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
다음 것들을 확인하실 수 있습니다.
client_version
클라이언트가 통신하기 원하는 tls 버전입니다.
Random
client가 생성한 random structure입니다. 형식은 아래와 같습니다.
struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;
Session ID
opaque SessionID<0..32>;
variable length vector 표현식이라 길이, 그리고 실제 값이 따라옵니다.
0~32는 1바이트로도 충분하기 때문에 1바이트를 할당받아서 총 33바이트로 표현이 됩니다.
이 값이 비어있지 않다면 클라이언트가 session을 재사용하기 원한다는 것이죠.
여기선 session id 값이 존재하므로 한 번 연결했었고 이 아이디를 재사용하겠다는 뜻입니다.
Cipher Suites
client가 지원가능한 암호화 알고리즘 목록들을 사용하길 원하는 순서대로 나열하여 전달합니다.
uint8 CipherSuite[2];
여기선 1순위가 Reserved (GREASE) 라는데,… https://datatracker.ietf.org/doc/html/rfc8701 에 정의되어 있습니다. TLS echo system이 미동작하는 것을 방지하기 위한 값이라는데, 위 문서를 읽어보면 되겠지요… 이 글에서 다루는 범위가 너무 넓어져서 넘어가겠습니다.
결국 TLS_AES_128_GCM_SHA256
을 클라이언트가 원한다고 볼 수 있겠네요.
Compression Method
클라이언트가 지원하는 압축 알고리즘
Extentions
client가 server에게 확장 기능을 요청할 수 있는데 그 목록들을 나타냅니다.
struct {
ExtensionType extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
enum {
signature_algorithms(13), (65535)
} ExtensionType;
상단의 3번째 라인의 server_name쪽을 보면 Extension이 어떤 구조로 되어 있는지 확인하실 수 있습니다.
Cliient Hello 이후엔 Ack를 보낸 다음에야 Server Hello 패킷을 전달해주네요.
Server Hello
HandShake이 (2)로, Server Hello 메세지의 구조입니다.
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
Client Hello와 크게 다를 게 없으므로 필드 별 와이어 샤크는 생략하겠습니다.
Version
client가 지원가능한 version 중 가장 낮은 버전 중 서버가 지원 가능한 가장 높은 버전을 의미합니다.
Random
서버가 생성한 random structure입니다. 반드시 client와 독립적으로 생성되어야 하죠.
SessionID
이 연결에 상응하는 session id를 의미합니다.
만약에 clientHello에서 보낸 session_id가 비어 있지 않으면 server는 session cache에서 session id를 찾아볼 것입니다. 만약 찾았다면 특정한 session state를 이용하여 새로운 connection을 생성하여 client에게 제공할 것입니다. 그리고나서 바로 Finished messages를 전달합니다.
만약에 비어있다면 세션이 비어 있어서 재사용할 수 없다는 뜻을 나타냅니다.
위에서 보시듯 Session Length가 0이므로 클라이언트가 보낸 세션 아이디를 재사용할 수 없다는 뜻이네요.
cipherSuite
clientHello에서 보낸 cipher_suites 중에서 server가 고른 cipher suite를 나타냅니다.
만약에 기존 세션을 재활용했다면, 그때 사용한 cipherSuite가 그 값이여야 합니다.
위에서 보시듯 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
를 선택했네요.
Compression Method
ClientHello에서 보낸 압축 알고리즘 중 서버가 선택한 알고리즘을 나타냅니다.
Extensions
extension리스트를 나타냅니다. client가 제공한 리스트만 server list에 나타납니다.
Certificate
패킷이 3개가 합쳐서!
Certificate의 경우 파일 사이즈가 크다 보니까 패킷 3개에 거쳐서 완성되네요.
[3 Reassembled TCP Segments (3877 bytes): #88(1363), #89(1448), #90(1066)]
이 보시면 88번에서 90번까지 보낸 패킷을 바탕으로 TLS의 Certificate를 보여줍니다.
Certificate Handshake Protocol의 Application data size가 3877 bytes라는 것을 의미합니다.
Segment 최대 사이즈(헤더20바이트일 경우)가 1460bytes라는 것을 생각해보면 쪼개질만 했네요.
Handshake Type: Certificate의 구조
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
Java로 Certificate 생성 및 확인
Certificate가 어떻게 생겨먹었는지 java로 확인해보겠습니다. 이용할 것은 다음 3가지 입니다.
- HexEncoding된 Certificate 값
- bouncycastle libarary (cryptophy 라이브러리)
- JCA (java Cryptography Architecture)
- Hex Encoding된 값은 wireshark에서 손쉽게 획득할 수 있습니다.
- gradle에 library 의존성을 추가하시고,
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
- 다음처럼 코드를 작성해주시면 됩니다.
Security.addProvider(new BouncyCastleProvider());
String hexCertificate = "308209b130820799a00302010202137f00150b27cd290d88d4c892bc000000150b27300d06092a864886f70d01010b0500304f310b3009060355040613025553311e301c060355040a13154d6963726f736f667420436f72706f726174696f6e3120301e060355040313174d6963726f736f66742052534120544c53204341203032301e170d3231303732383137353832345a170d3232303732383137353832345a30818c310b3009060355040613025553310b30090603550408130257413110300e060355040713075265646d6f6e64311e301c060355040a13154d6963726f736f667420436f72706f726174696f6e311e301c060355040b13154d6963726f736f667420436f72706f726174696f6e311e301c06035504031315737570706f72742e6d6963726f736f66742e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100aa3c3bb829e93bc07f4ea3b90d653e1f0f7b657ae4af2a6451ff06da9c58920ada5f5530f0551fbcbf36a99e336edd7bb0591bd4380919f6612458d479a9137d729a5f2342bddc692ca10b2223889cf7af192f2626729786d3c49b673ff1e9cd74d1baee63ae81a1b11fa3360f3df50950d91a407196a56a91413c87861c4360364498609c1d1c979565cf4ca1be772a2a55382b5d323e7c99fdc3f6f4ab61e5ba4073d99d22b2216b6e6872da2f9d553f6385870bfd47b242a4e35bc17cd4558471c4e7146e0aedf9bfc2723d79c49f7d19086ba82ec210d35ca1b20657800da71c4df5a43e5eeb81abacfdb861ec41fa10a103e12bd0bdb49fcd2a511814af0203010001a3820546308205423082017c060a2b06010401d6790204020482016c0482016801660075002979bef09e393921f056739f63a577e5be577d9c600af8f94d5d265c255dc7840000017aee4db4980000040300463044022052d90c744f88166316f58613ce16b2b7590edcf28082bc01287c144f4ed0852702200d457d54e362cbc61b4cd9d180fcc1890c8850dd2a6550944005a8c59f88130300750051a3b0f5fd01799c566db837788f0ca47acc1b27cbf79e88429a0dfed48b05e50000017aee4db5fb000004030046304402200f76d95542f7fa4f334a1c5730532a1dbd26f4bb159c376b03de75ad5c516d8f02204f52bc92ca9f4e1b186fdf7893687dcb499d848ef5cb8b50987a65d396ddb2ba0076005581d4c2169036014aea0b9b573c53f0c0e43878702508172fa3aa1d0713d30c0000017aee4db57f0000040300473045022100bdb5691041d6700f81ca049bc55102000ebed0bf50a5b71f847f7e16125979e7022075a3791567669b1c34397250ff8cec35bcddf4241441effaa87790d58cfad89b302706092b060104018237150a041a3018300a06082b06010505070302300a06082b06010505070301303d06092b06010401823715070430302e06262b060104018237150887da867583eed90182c9851b81b59e6185f4eb60815db9f8108691d07802016402012530818706082b06010505070101047b3079305306082b060105050730028647687474703a2f2f7777772e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f4d6963726f736f6674253230525341253230544c53253230434125323030322e637274302206082b060105050730018616687474703a2f2f6f6373702e6d736f6373702e636f6d301d0603551d0e0416041414067f67af0163c4e43244b2df239494bd81d4ad300e0603551d0f0101ff0404030204b0308201510603551d1104820148308201448216737570706f7274322e6d6963726f736f66742e636f6d8215737570706f72742e6d6963726f736f66742e636f6d821a737570706f72742d756174322e6d6963726f736f66742e636f6d8219537570706f72742d7561742e6d6963726f736f66742e636f6d822070726f66657373696f6e616c6469726563742e6d6963726f736f66742e636f6d82187072656d6965727561742e6d6963726f736f66742e636f6d82157072656d6965722e6d6963726f736f66742e636f6d821068656c702e67726f75706d652e636f6d821b646576696365737570706f72742e6d6963726f736f66742e636f6d821f646576696365737570706f72742d7561742e6d6963726f736f66742e636f6d82202a2e737570706f72742e73657276696365732e6d6963726f736f66742e636f6d82172a2e737570706f72742e6d6963726f736f66742e636f6d3081b00603551d1f0481a83081a53081a2a0819fa0819c864d687474703a2f2f6d7363726c2e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f63726c2f4d6963726f736f6674253230525341253230544c53253230434125323030322e63726c864b687474703a2f2f63726c2e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f63726c2f4d6963726f736f6674253230525341253230544c53253230434125323030322e63726c30570603551d200450304e304206092b0601040182372a013035303306082b060105050702011627687474703a2f2f7777772e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f6370733008060667810c010202301f0603551d23041830168014ff2f7fe106f438f32ded258d98c2fe0ef66cfcfa301d0603551d250416301406082b0601050507030206082b06010505070301300d06092a864886f70d01010b05000382020100e969c59870e4c1cd447dc61319a5f2fc5b4a99832dbfdba479c2c9d5a3fed5a405c8f2fd2ad797817eb4e88cfcc43aeec5d7ef62b695841ab5dceace2f5bd26bed24c02c7bf4618ac257b5d583a277d96fc6726cf70cc5f7b4e0b33cc2fcc9d26cf7e8bdec59b3abc8ef0161e5cbc3f5acd68d5e559f48e6e0241fff66a6c0cd4952d2921b89cd9bf4ac41d0e89437a8d5faa4248bdd1832695a4a30dc6f6290c5271648c627469d945f9390b0edac8586a7e6d081ae5953e7bb1a5c9ce0a39b69119f0f65de306e6e4d292c31f957a0b61add9ae14d881f7adbac9000ba4324c3f37513572b5c6a44de93ddb48fdb81fe4fde48de8eb855571a0d5cabf5fd1d23e696d5fd746cf2544a36997eee7bd198fa52a475c4a33919a5969757049801cdce9a2ef5809ead033100850199e073f60e8de84f5c623c3de8808779eaa959373d82663e4b12e0549df33f7009ea82786b418fdfcd56a0c6086bd8ce97fcb2a625c52e3d7db5a8312153e29f388a6e95ff8baa80cce4911d2a81e3cb546ee2efa4778da38d4ef5cf9dfb8b0a5a23f298da1a0e1e5e9f6af94610215bd68c9f675bd60bb34487679708c3804156e85727bd37ab0605a9f2352b152f03511e6a12d1782872504220a8fe5e1d61da5dbba6e05b8e6561276a0e59e7982e2dff0df5ad08cb9783fad85674eaefeb41c9c03640b8867d3af742497c515ef635c579";
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate certificate = cf.generateCertificate(new ByteArrayInputStream(Hex.decode(hexCertificate)));
Files.write(Paths.get("./cert.der"), certificate.getEncoded());
이로써 der 인코딩된 certificate 파일을 획득할 수 있죠.
다음으로 생성한 파일을 openssl을 통하여 열어주시면,
openssl x509 -inform der -in cert.pem -noout -text
다음과 같은 인증서 내용을 확인하실 수 있습니다.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
7f:00:15:0b:27:cd:29:0d:88:d4:c8:92:bc:00:00:00:15:0b:27
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Microsoft Corporation, CN = Microsoft RSA TLS CA 02
Validity
Not Before: Jul 28 17:58:24 2021 GMT
Not After : Jul 28 17:58:24 2022 GMT
Subject: C = US, ST = WA, L = Redmond, O = Microsoft Corporation, OU = Microsoft Corporation, CN = support.microsoft.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:aa:3c:3b:b8:29:e9:3b:c0:7f:4e:a3:b9:0d:65:
3e:1f:0f:7b:65:7a:e4:af:2a:64:51:ff:06:da:9c:
58:92:0a:da:5f:55:30:f0:55:1f:bc:bf:36:a9:9e:
33:6e:dd:7b:b0:59:1b:d4:38:09:19:f6:61:24:58:
d4:79:a9:13:7d:72:9a:5f:23:42:bd:dc:69:2c:a1:
0b:22:23:88:9c:f7:af:19:2f:26:26:72:97:86:d3:
c4:9b:67:3f:f1:e9:cd:74:d1:ba:ee:63:ae:81:a1:
b1:1f:a3:36:0f:3d:f5:09:50:d9:1a:40:71:96:a5:
6a:91:41:3c:87:86:1c:43:60:36:44:98:60:9c:1d:
1c:97:95:65:cf:4c:a1:be:77:2a:2a:55:38:2b:5d:
32:3e:7c:99:fd:c3:f6:f4:ab:61:e5:ba:40:73:d9:
9d:22:b2:21:6b:6e:68:72:da:2f:9d:55:3f:63:85:
87:0b:fd:47:b2:42:a4:e3:5b:c1:7c:d4:55:84:71:
c4:e7:14:6e:0a:ed:f9:bf:c2:72:3d:79:c4:9f:7d:
19:08:6b:a8:2e:c2:10:d3:5c:a1:b2:06:57:80:0d:
a7:1c:4d:f5:a4:3e:5e:eb:81:ab:ac:fd:b8:61:ec:
41:fa:10:a1:03:e1:2b:d0:bd:b4:9f:cd:2a:51:18:
14:af
Exponent: 65537 (0x10001)
X509v3 extensions:
CT Precertificate SCTs:
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 29:79:BE:F0:9E:39:39:21:F0:56:73:9F:63:A5:77:E5:
BE:57:7D:9C:60:0A:F8:F9:4D:5D:26:5C:25:5D:C7:84
Timestamp : Jul 28 18:08:27.800 2021 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:44:02:20:52:D9:0C:74:4F:88:16:63:16:F5:86:13:
CE:16:B2:B7:59:0E:DC:F2:80:82:BC:01:28:7C:14:4F:
4E:D0:85:27:02:20:0D:45:7D:54:E3:62:CB:C6:1B:4C:
D9:D1:80:FC:C1:89:0C:88:50:DD:2A:65:50:94:40:05:
A8:C5:9F:88:13:03
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 51:A3:B0:F5:FD:01:79:9C:56:6D:B8:37:78:8F:0C:A4:
7A:CC:1B:27:CB:F7:9E:88:42:9A:0D:FE:D4:8B:05:E5
Timestamp : Jul 28 18:08:28.155 2021 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:44:02:20:0F:76:D9:55:42:F7:FA:4F:33:4A:1C:57:
30:53:2A:1D:BD:26:F4:BB:15:9C:37:6B:03:DE:75:AD:
5C:51:6D:8F:02:20:4F:52:BC:92:CA:9F:4E:1B:18:6F:
DF:78:93:68:7D:CB:49:9D:84:8E:F5:CB:8B:50:98:7A:
65:D3:96:DD:B2:BA
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 55:81:D4:C2:16:90:36:01:4A:EA:0B:9B:57:3C:53:F0:
C0:E4:38:78:70:25:08:17:2F:A3:AA:1D:07:13:D3:0C
Timestamp : Jul 28 18:08:28.031 2021 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:45:02:21:00:BD:B5:69:10:41:D6:70:0F:81:CA:04:
9B:C5:51:02:00:0E:BE:D0:BF:50:A5:B7:1F:84:7F:7E:
16:12:59:79:E7:02:20:75:A3:79:15:67:66:9B:1C:34:
39:72:50:FF:8C:EC:35:BC:DD:F4:24:14:41:EF:FA:A8:
77:90:D5:8C:FA:D8:9B
1.3.6.1.4.1.311.21.10:
0.0
..+.......0
..+.......
1.3.6.1.4.1.311.21.7:
0..&+.....7.....u...........a...`.]......x..d..%
Authority Information Access:
CA Issuers - URI:http://www.microsoft.com/pki/mscorp/Microsoft%20RSA%20TLS%20CA%2002.crt
OCSP - URI:http://ocsp.msocsp.com
X509v3 Subject Key Identifier:
14:06:7F:67:AF:01:63:C4:E4:32:44:B2:DF:23:94:94:BD:81:D4:AD
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
DNS:support2.microsoft.com, DNS:support.microsoft.com, DNS:support-uat2.microsoft.com, DNS:Support-uat.microsoft.com, DNS:professionaldirect.microsoft.com, DNS:premieruat.microsoft.com, DNS:premier.microsoft.com, DNS:help.groupme.com, DNS:devicesupport.microsoft.com, DNS:devicesupport-uat.microsoft.com, DNS:*.support.services.microsoft.com, DNS:*.support.microsoft.com
X509v3 CRL Distribution Points:
Full Name:
URI:http://mscrl.microsoft.com/pki/mscorp/crl/Microsoft%20RSA%20TLS%20CA%2002.crl
URI:http://crl.microsoft.com/pki/mscorp/crl/Microsoft%20RSA%20TLS%20CA%2002.crl
X509v3 Certificate Policies:
Policy: 1.3.6.1.4.1.311.42.1
CPS: http://www.microsoft.com/pki/mscorp/cps
Policy: 2.23.140.1.2.2
X509v3 Authority Key Identifier:
keyid:FF:2F:7F:E1:06:F4:38:F3:2D:ED:25:8D:98:C2:FE:0E:F6:6C:FC:FA
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
e9:69:c5:98:70:e4:c1:cd:44:7d:c6:13:19:a5:f2:fc:5b:4a:
99:83:2d:bf:db:a4:79:c2:c9:d5:a3:fe:d5:a4:05:c8:f2:fd:
2a:d7:97:81:7e:b4:e8:8c:fc:c4:3a:ee:c5:d7:ef:62:b6:95:
84:1a:b5:dc:ea:ce:2f:5b:d2:6b:ed:24:c0:2c:7b:f4:61:8a:
c2:57:b5:d5:83:a2:77:d9:6f:c6:72:6c:f7:0c:c5:f7:b4:e0:
b3:3c:c2:fc:c9:d2:6c:f7:e8:bd:ec:59:b3:ab:c8:ef:01:61:
e5:cb:c3:f5:ac:d6:8d:5e:55:9f:48:e6:e0:24:1f:ff:66:a6:
c0:cd:49:52:d2:92:1b:89:cd:9b:f4:ac:41:d0:e8:94:37:a8:
d5:fa:a4:24:8b:dd:18:32:69:5a:4a:30:dc:6f:62:90:c5:27:
16:48:c6:27:46:9d:94:5f:93:90:b0:ed:ac:85:86:a7:e6:d0:
81:ae:59:53:e7:bb:1a:5c:9c:e0:a3:9b:69:11:9f:0f:65:de:
30:6e:6e:4d:29:2c:31:f9:57:a0:b6:1a:dd:9a:e1:4d:88:1f:
7a:db:ac:90:00:ba:43:24:c3:f3:75:13:57:2b:5c:6a:44:de:
93:dd:b4:8f:db:81:fe:4f:de:48:de:8e:b8:55:57:1a:0d:5c:
ab:f5:fd:1d:23:e6:96:d5:fd:74:6c:f2:54:4a:36:99:7e:ee:
7b:d1:98:fa:52:a4:75:c4:a3:39:19:a5:96:97:57:04:98:01:
cd:ce:9a:2e:f5:80:9e:ad:03:31:00:85:01:99:e0:73:f6:0e:
8d:e8:4f:5c:62:3c:3d:e8:80:87:79:ea:a9:59:37:3d:82:66:
3e:4b:12:e0:54:9d:f3:3f:70:09:ea:82:78:6b:41:8f:df:cd:
56:a0:c6:08:6b:d8:ce:97:fc:b2:a6:25:c5:2e:3d:7d:b5:a8:
31:21:53:e2:9f:38:8a:6e:95:ff:8b:aa:80:cc:e4:91:1d:2a:
81:e3:cb:54:6e:e2:ef:a4:77:8d:a3:8d:4e:f5:cf:9d:fb:8b:
0a:5a:23:f2:98:da:1a:0e:1e:5e:9f:6a:f9:46:10:21:5b:d6:
8c:9f:67:5b:d6:0b:b3:44:87:67:97:08:c3:80:41:56:e8:57:
27:bd:37:ab:06:05:a9:f2:35:2b:15:2f:03:51:1e:6a:12:d1:
78:28:72:50:42:20:a8:fe:5e:1d:61:da:5d:bb:a6:e0:5b:8e:
65:61:27:6a:0e:59:e7:98:2e:2d:ff:0d:f5:ad:08:cb:97:83:
fa:d8:56:74:ea:ef:eb:41:c9:c0:36:40:b8:86:7d:3a:f7:42:
49:7c:51:5e:f6:35:c5:79
한편, 중간에 resolve되지 않은 extension oid도 존재하네요.. 1.3.6.1.4.1.311.21.10
이놈이요.
와이어 샤크에서는 잘 resolve 되어 있습니다.
이름을 대충 보니 마이크로소프트가 정의한 oid로 보이긴 하네요.
복수의 Certificate
그리고 보시면 Certificates라고하여 2개의 certificate를 서버에서 전달해줍니다.
하나는 support.microsoft.com 해당 도메인의 서버가 가지고 있는 인증서입니다.
subject가 인증서의 주인, (common name이 support.microsoft.com 이라고 나와있죠?)
issuer가 인증서를 발행한 기관이라고 보시면 됩니다. (Microsoft RSA TLS CA 02)
다른 하나는 서버 인증서를 발행해준 intermediate CA의 인증서입니다.
Chain of Trust라고하여 재귀적으로 인증서를 검증할 수 있도록 발행기관의 인증서도 전달해줍니다.
그래서 이 인증서의 subject는 Microsoft RSA TLS CA 02 가 됩니다. 서버인증서의 issuer였죠?
그리고 이 인증서의 issuer는 Baltimore CyberTrust Root 라는 RootCA입니다.
그렇다면 RootCA의 인증서는 어디에 있는걸까요?
보안 상 이유로 RootCA의 인증서는 운영체제에서 관리합니다. 따라서, MAC의 경우 키체인 접근으로 들어가서 좌측 시스템 키체인 중 시스템 루트로 들어가시면 rootCA의 인증서를 확인하실 수 있습니다.
handshake 중 Certificate 단계에서는 서버 검증을 위한 인증서를 제공해주고 종료가 됩니다.
그리고 이 인증서에! 가장 중요한 public key도 존재하지요.
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:aa:3c:3b:b8:29:e9:3b:c0:7f:4e:a3:b9:0d:65:
3e:1f:0f:7b:65:7a:e4:af:2a:64:51:ff:06:da:9c:
58:92:0a:da:5f:55:30:f0:55:1f:bc:bf:36:a9:9e:
33:6e:dd:7b:b0:59:1b:d4:38:09:19:f6:61:24:58:
d4:79:a9:13:7d:72:9a:5f:23:42:bd:dc:69:2c:a1:
0b:22:23:88:9c:f7:af:19:2f:26:26:72:97:86:d3:
c4:9b:67:3f:f1:e9:cd:74:d1:ba:ee:63:ae:81:a1:
b1:1f:a3:36:0f:3d:f5:09:50:d9:1a:40:71:96:a5:
6a:91:41:3c:87:86:1c:43:60:36:44:98:60:9c:1d:
1c:97:95:65:cf:4c:a1:be:77:2a:2a:55:38:2b:5d:
32:3e:7c:99:fd:c3:f6:f4:ab:61:e5:ba:40:73:d9:
9d:22:b2:21:6b:6e:68:72:da:2f:9d:55:3f:63:85:
87:0b:fd:47:b2:42:a4:e3:5b:c1:7c:d4:55:84:71:
c4:e7:14:6e:0a:ed:f9:bf:c2:72:3d:79:c4:9f:7d:
19:08:6b:a8:2e:c2:10:d3:5c:a1:b2:06:57:80:0d:
a7:1c:4d:f5:a4:3e:5e:eb:81:ab:ac:fd:b8:61:ec:
41:fa:10:a1:03:e1:2b:d0:bd:b4:9f:cd:2a:51:18:
14:af
Exponent: 65537 (0x10001)
여기에 public key의 구성요소인 modulus와 exponent가 인증서에서 제공됩니다.
암
이제 다음으로 Server Key Exchange를 알아보겠습니다.
Server Key Exchange
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.3
RFC에서 Server Certificate message 이후 곧바로 이 메세지가 보내진다고 하네요. 와이어샤크에서도 동일하게 서버에서 Certificate 다음에 곧바로 Server Key Exchange를 보냈네요.
클라이언트와 premaster secret을 어떻게 교환할 지 server Certificate message에서 보내지 않았다면 이 메세지가 전송된다고 합니다.
Structure
struct {
select (KeyExchangeAlgorithm) {
case dh_anon:
ServerDHParams params;
case dhe_dss:
case dhe_rsa:
ServerDHParams params;
digitally-signed struct {
opaque client_random[32];
opaque server_random[32];
ServerDHParams params;
} signed_params;
case rsa:
case dh_dss:
case dh_rsa:
struct {} ;
/* message is omitted for rsa, dh_dss, and dh_rsa */
/* may be extended, e.g., for ECDH -- see [TLSECC] */
};
} ServerKeyExchange;
params
The server's key exchange parameters.
enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
/* may be extended, e.g., for ECDH -- see [TLSECC] */
} KeyExchangeAlgorithm;
struct {
opaque dh_p<1..2^16-1>;
opaque dh_g<1..2^16-1>;
opaque dh_Ys<1..2^16-1>;
} ServerDHParams; /* Ephemeral DH parameters */
Client Hello에서 signature_algorithms
extension을 제공했다면 signature algorthm과 hash algorithm 쌍이 반드시 extension에 존재해야 한다고 합니다.
RFC 5246에서 안나오는 내용…
EC Diffie-Hellman Server Params
Curv Type: named_curve
등등으로 어쩌고 적혀있는데…
https://datatracker.ietf.org/doc/html/rfc4492#section-5.4
에서 자세히 설명되어 있습니다.
enum { explicit_prime (1), explicit_char2 (2),
named_curve (3), reserved(248..255) } ECCurveType;
이래서 named_curv가 (0x03)이네요.
named_curv일 경우엔 아래 보시는 바와 같이 NamedCurve
타입이 나오는데요.
struct {
ECCurveType curve_type;
select (curve_type) {
case explicit_prime:
opaque prime_p <1..2^8-1>;
ECCurve curve;
ECPoint base;
opaque order <1..2^8-1>;
opaque cofactor <1..2^8-1>;
case explicit_char2:
uint16 m;
ECBasisType basis;
select (basis) {
case ec_trinomial:
opaque k <1..2^8-1>;
case ec_pentanomial:
opaque k1 <1..2^8-1>;
opaque k2 <1..2^8-1>;
opaque k3 <1..2^8-1>;
};
ECCurve curve;
ECPoint base;
opaque order <1..2^8-1>;
opaque cofactor <1..2^8-1>;
case named_curve:
NamedCurve namedcurve;
};
} ECParameters;
RFC에 이렇게 적혀있는데요
namedcurve: Specifies a recommended set of elliptic curve domain
parameters. All those values of NamedCurve are allowed that refer
to a specific curve. Values of NamedCurve that indicate support
for a class of explicitly defined curves are not allowed here
(they are only permissible in the ClientHello extension); this
applies to arbitrary_explicit_prime_curves(0xFF01) and
arbitrary_explicit_char2_curves(0xFF02).
struct {
ECParameters curve_params;
ECPoint public;
} ServerECDHParams;
curve_params: Specifies the elliptic curve domain parameters
associated with the ECDH public key.
public: The ephemeral ECDH public key.
와이어샤크를 보면
ECParameters에 해당하는 것이 Named Curv: secp256r1
이고,
ECPoint에 해당하는 것이 Publickey Length: 65, PubKey: 048....
이라는 것을 알 수 있습니다.
ClientHello의 extensions에서 rsa_pss_rsae_sha256
을 사요가능하다고 전달해줬더니,
이렇게 Server Key Exchange에서 해당 알고리즘을 선택했네요.
Client Request
선택적으로 서버는 client에게 certificate를 요청할 수도 있습니다. 아마 mTLS 통신할 때 사용되는 옵션인가 보네요. 일반적으로 인터넷에 연결된 서버는 임의의 사용자에게 제공되는 서비스이므로 client request는 생략되리라 봅니다.
Server Hello Done
ServerHello 및 그 관련된 메세지가 끝나면 보내는 메세지입니다. 이 메세지가 보내진 후에는 클라이언트의 응답을 기다리죠.
이 메세지를 보냈다는 뜻은,
- key exchange를 지원하기 위한 메세지를 보내는 것을 완료했다는 것.
- 클라이언트는 key exchange단계 중 자신의 차례를 처리할 수 있음.
이 이후에 클라이언트는
- 유요한 인증서인지 검증하고
- server hello parameters를 받아들일 수 있는지 확인해야 합니다.
Client Certificate
서버가 클라이언트에게 인증서를 요구했을 때 전달하는 메세지입니다. 서버가 요구하지 않았으므로 이 메세지는 없습니다.
Client Key Exchange Message
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.7
여기서 premaster secret이 설정됩니다. RSA-encrypted secret을 전달해주거나, Diffie-Hellman paramters를 전달 해줌으로써 동일한 premaster secret을 가지도록 합니다.
Structure
어떠한 key exchange method가 선택되었는지 알려줍니다.
struct {
select (KeyExchangeAlgorithm) {
case rsa:
EncryptedPreMasterSecret;
case dhe_dss:
case dhe_rsa:
case dh_dss:
case dh_rsa:
case dh_anon:
ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.7.2
와이어샤크에서 받은 타입은 ClientDiffieHellmanPublic으로 보입니다.
struct {
select (PublicValueEncoding) {
case implicit: struct { };
case explicit: opaque dh_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;
Change Cipher Spec
https://datatracker.ietf.org/doc/html/rfc5246#section-7.
암호화 전략의 변경을 알려주기 위해 사용됩니다.
값이 1인걸 보아 변경한다고 하네요.
그리고 이 이후부터 Handshake Message가 암호화 됩니다. 이것에 대해 조금더 알아봐야겠습니다?
https://datatracker.ietf.org/doc/html/rfc5246#section-6.1
여기 내용을 보면, connection state와 관련이 있는 것 같습니다.
TLS connections state는 TLS REcord Protocol의 운영 환경을 의미하는데요, 이것은 압축 알고리즘, 암호화 알고리즘, 맥 알고리즘과 같은 것들을 의미합니다.
Connection states는 논리적으로 다음 4가지로 분류됩니다.
- current read state
- current write state
- peding read state
- peding write state
pending 상태인 동안 security parameters가 설정되고, ChangeCipherSpec
이 pending states를 current states로 변경한다고 하네요. 또는 역으로도요.
그렇다면~~ Handshake 과정에서 인증서, 키교환 알고리즘, 전자서명 등등 모두 결정했잖아요? 그렇기 때문에 이제부터 암호화하여 전송한다는 의미로 ChangeCipherSpec
메세지를 보낸 것 같습니다.
그리고 다음 메세지부터는 암호화되서 전송된 거네요.
이제 payload의 값을 wireshark가 보기 편하게 알려주지 않고 Handshake Message가 암호화되었다고 알려줍니다.
암호화된 HandShake message는 preMasterSecret 으로 보입니다.
New Session Ticket
https://datatracker.ietf.org/doc/html/rfc5077
흠 처음 들어본 New Session Ticket이라는 handshake type을 서버에서 보냈습니다.
ClientHello의 extension에 Session Ticket의 값을 빈 값으로 두어 지원할 수 있다고 말해야만, 서버에서 이것을 지원해준다고 하네요.
session state를 서버가 아닌 클라이언트가 기억하도록하여 서버의 session state 유지 코스트를 줄이고자하는 목적이랍니다.
session id로 전달하면 server가 session state를 유지해야하기 때문에 서버에 부담이 크답니다.
자세한 건 나중에 다뤄야겠습니다.
Change Cipher Spec Message, Encrypted Handshake Message
서버도 마찬가지로 Change Cipher spec message를 통해 current state로 변경한 뒤 암호화된 메세지를 전송합니다.
아무래도 Finished 메세지겠지요??
암호화 전송
위 과정을 모두 거치고 나면 각자 지닌 동일한 master secret을 통해서 메세지를 암호화 전송을 합니다.
Transport Layer Security의 Record Layer에서 받은 Application Data들이 암호화되었다고 표시되네요.
끝!
이번 글은 잘 모르는 부분도 있고... 세부적으로 들어가서 분량이 너무 많아졌습니다. 욕심으로는 암복호화까지 다루려고 했는데 말이죠. 부족한 부분은 계속 수정해 나가도록 하겠습니다. 참조링크도 두었으니, 혹시나 제가 잘못이해한 게 있으면 해당 링크를 참조하시면 좋을 것 같네요. 다음 암복호화 글로 만나뵙겠습니다.
'컴퓨터과학 기초 > 네트워크' 카테고리의 다른 글
TCP, IP 패킷 분석 with wireshark (1) | 2022.06.22 |
---|---|
[computer networking] Chapter 3.2 Multiplexing and Demultiplexing (0) | 2021.05.30 |
TCP server의 포트 번호에 대해 - 두 소켓의 포트 번호는 같을 수 있다. (5) | 2021.05.30 |
[computer networking] Chapter 3.1 Introduction and Transport-Layer Services (0) | 2021.05.23 |
TCP 소켓 (0) | 2021.05.03 |