#dokydoky

HTTPS - 2. HTTPS의 Ciphersuite, Handshake, Key derivation 본문

Network & Encryption

HTTPS - 2. HTTPS의 Ciphersuite, Handshake, Key derivation

dokydoky 2018.04.15 22:12

그림으로 살펴보는 포스팅을 시작으로, 3편의 포스팅을 통해 HTTPS에 대해서 알아보겠습니다.

이전 포스팅을 읽어보시지 않으셨다면, 읽어보시는 것을 추천드립니다!

들어가며

1편에서는 HTTPS의 동작방식을 그림으로 간단하게 살펴봤습니다.

전편에서는 RSA 기반의 키교환 중심으로 설명했지만, ECDHE와 같이 Diffie-hellman 기반의 알고리즘도 많이 사용됩니다.

이번편에서는 TLS에서 사용되는 Cipher suites, Handshake를 알아보며 Perfect Forward Secrecy, ECC에 대해서도 알아봅시다.

그리고 키교환을 통해 얻은 pre-master secret은 4가지의 key로 유도(Derive)되는 것을 알고 계셨나요?

어떤 key들이 필요하고 어떻게 유도하는지에 대해서도 자세히 알아봅시다.


Cipher suites


HTTPS에서 사용되는 Cipher suite는 크게 2가지 부분으로 나눠 볼 수 있습니다.

  • 안전한 키 교환을 위한 키교환 방법(Key establishment)와 인증서 검증 방법(Authentication).
  • 메시지 암호화를 위한 암호화 알고리즘(Cipher)과 메시지의 무결성을 검증하기 위한 Data integrity.


자 그럼 하나씩 살펴봅시다.

Key establishment

키교환은 크게 RSA기반과 Diffie hellman(DH)기반 방법이 있으며, DHE, ECDH, ECDHE는 DH(Diffie-Hellman)의 변형입니다.

RSA, DH 키교환과 Forward secrecy, ECC에 대해 알아봅시다.


  • RSA key exchange

Alice가 symmetric key를 생성 후 Bob의 RSA public key로 암호화하여 Bob에게 전송합니다.


  • Diffie-Hellman Key exchange

RSA와는 달리, Alice와 Bob이 각자 생성 후 교환한 파라미터를 이용해 shared secret를 만듭니다.

  1. Alice가 secret값 a를 갖고, g^a 값을 Bob에게 전송.
  2. Bob은 secret값 b를 갖고, g^b 값을 Alice에게 전송.
  3. Alice 키 계산. shared secret = (g^b)^a = g^(ab)
  4. Bob 키 계산. shared secret = (g^a)^b = g^(ab)

Alice와 Bob은 shared secret을 공유했지만, 엿듣고 있는 Mallory는 g^a, g^b값으로 동일한 값을 만들어 내지 못합니다.

참고) 실제로는 수학적 해결이 힘들도록, 큰 소수로 modular 연산을 한 결과를 사용합니다.


  • PFS(Perfect Forward secrecy)란?

PFS는 서버의 private key가 누출되더라도, 해당 key쌍을 사용했던 과거의 TLS session들이 보호되는 특성입니다.

위 그릠에서와 같이 RSA 키교환 방식에서는 Mallory가 Alice와 Bob간의 암호화된 메시지를 기록해놓은 상황에서, 

Bob의 private key가 누출될 경우 과거의 암호화된 메시지를 복호화할 수 있게 됩니다.


  • ECC(Elliptic curves cryptography)란?

타원곡선(elliptic-curve)의 수학적 특성을 이용하는 암호화 알고리즘으로써, non-elliptic curve 알고리즘에 비해 key 사이즈가 현저하게 작습니다.

따라서 동일한 보안성을 제공할 때, 다른 알고리즘에 비해 작은 key를 사용하여 더 빠른 속도를 제공해줍니다.

Symmetric Key LengthStandard asymmetric Key LengthElliptic Curve Key Length
801024160
1122048224
1283072256
1927680384
25615360512

https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography


(Certificate) Authentication

CA에 의해 서명된 Certificate의 signature를 확인할 때 사용되는 알고리즘으로, RSA나 ECC 기반의 ECDSA가 많이 사용됩니다.

Key establishment와 Authentication 조합으로 인증된 키 교환(Authenticated Key exchange)을 제공합니다.


Cipher

키교환을 완료 한 뒤, 메시지 암호화에 사용되는 symmetric 암호화 알고리즘입니다.

AES_256_GCM 의 경우. 암호화 알고리즘은 AES, key size는 256bit, mode는 GCM를 사용한다는 뜻입니다.

https://en.wikipedia.org/wiki/Transport_Layer_Security#Cipher


Data Integrity

데이터 암호화는 기밀성을 제공해주지만, 무결성을 제공해주지 않기 때문에 별도의 무결성 검증 방식을 사용합니다.

HMAC으로 인증값을 생성하거나, 애초 암호화할 때 인증값을 포함한 Authenticated Encryption(ex.CCM, GCM)을 사용할 수 있습니다.

HMAC값을 생성할 때 필요한 key는 pre-master key에서 유도(derive)해서 사용합니다.
(유도 과정은 이 글의 마지막에서 자세히 다루겠습니다.)


https://en.wikipedia.org/wiki/Transport_Layer_Security#Data_integrity


TLS 1.3부터는 AEAD(Authenticated Encryption with Associated Data)만을 지원하는데, AEAD는 GCM와 CCM 모드와 같이

암호화 과정에서 인증값도 함께 추가하는 방식입니다. 암호화와 메시지 인증을 함께 합쳐놓은 인증된 암호화(Authentication Encryption) 방식입니다. 


Handshake

2가지 키교환 방식(RSA, Ephermeral Diffie-Hellman)에 대해 handshake 과정을 살펴보겠습니다.

특히, Ephermeral Diffie-Hellman 키교환은 PFS(Perfect Forward Secrecy)를 지원하는 방식입니다!

이 내용은 CloudFlare 블로그 글 중 Keyless SSL: The Nitty Gritty Technical Details에 설명이 잘 되어 있습니다.

특히 그림을 너무 잘 그려주셔서, 이 그림을 가져와서 간단히 짚고 가보겠습니다. 더 상세한 내용은 원문도 확인해보세요!


RSA handshake

(a nice figure, thanks CloudFlare!) https://blog.cloudflare.com/content/images/2014/Sep/ssl_handshake_rsa.jpg


  1. "Client Hello"
    client random와 클라이언트가 지원하는 protocol version, client cipher suite 리스트, SNI extension(옵션), curve 리스트(ECDHE의 경우) 전송합니다.

  2. "Server Hello"
    서버는 client hello를 받고 protocol version, cipher suite, curve를 결정합니다. 그리고 클라이언트에게 server random, cipher suite, server의 certificate를 전송합니다. 

  3. "Client Key Exchange"
    Client는 certificate을 검증한 후에, pre-master secret을 만들고 certificate에 포함된 public key로 암호화하여 서버에서 전송합니다.

    서버는 암호화된 pre-master secret을 자신의 private key로 복호화함으로써 client와 server는 pre-master secret을 공유했습니다.
    이후에는 pre-master secret과 client random, server random을 이용해 session key를 유도한 뒤, session key를 이용해 암호화된 데이터 통신을 합니다.


Ephermeral Diffie-Hellman handshake


  1. "Client Hello"
    RSA의 경우와 동일하게, client random, 클라이언트가 지원하는 protocol version, client cipher suite 리스트, SNI extension(옵션), curve 리스트(ECDHE의 경우) 전송합니다.

  2. "Server Hello"
    서버는 client hello를 받고 protocol version, cipher suite, curve를 결정합니다. 그리고 클라이언트에게 server random, cipher suite, server의 certificate를 전송합니다. 

  3. "Server Key Exchange"
    diffie-hellman 키교환을 위해 서버는 DH parameter를 생성합니다. 그리고 DH parameter의 인증(authentication)을 위해 자신의 private key로 signature를 생성 후 함께 보냅니다.

  4. "Client Key Exchange"
    클라이언트는 certificate와 DH parameter의 signature를 검증 한 뒤, 클라이언트의 DH parameter를 보냅니다.

    이후 클라이언트와 서버는 각각 주고받은 DH parameter를 이용해 premaster secret을 유도한 뒤,
    premaster secret과 client random, server random을 조합하여 session key를 유도합니다.


Ephermeral Diffie-Hell의 경우에는 session마다 새로운 random key가 생성되며, DH의 특성상 중간자는 premaster secret을 유추할 수 없게 되므로 PFS가 보장됩니다.


Key Derivation

앞에서 잠시 언급했지만, 키교환 과정을 통해 얻은 Pre-master secret을 바로 암호화 키로 사용하지 않습니다.

어떤 키들을, 어떻게 유도하는지 확인해봅시다!

 

우선, Pre-master secret은 키교환에 사용한 알고리즘에 따라 길이가 다르므로, 48bit의 master secret으로 변환합니다.

코드는 RFC에서 참조했습니다.
(PRF 함수에 대해서는 밑에서 자세히 다룹니다. 지금은 특정입력값을 seed값으로 안전한 랜덤 바이트열을 출력하는 함수로 이해합시다.)

master_secret = PRF(pre_master_secret, "master secret",
                  ClientHello.random + ServerHello.random)
                  [0..47];

 

이제 이 master secret을 확장시킨 후, 순서대로 4개 key를 유도합니다. 
"client/server write IV"는 AEAD cipher를 사용할 때만 추가적으로 필요한 것으로, AEAD cipher를 사용할 경우 4개의 key와 더불어 함께 유도(derive)합니다.

  • a client write MAC key
  • a server write MAC key
  • a client write encryption key
  • a server write encryption key
  • (a client write IV)
  • (a server write IV)

 

코드는 RFC에서 참조했습니다.

// master secret을 entorpy source로 key material을 계산
key_block = PRF(SecurityParameters.master_secret,
                "key expansion",
                SecurityParameters.server_random +
                SecurityParameters.client_random);
 
// 충분한 길이가 될 때까지 반복하여 생성한 뒤, 순서대로 아래 key들로 사용.
client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]

 

PRF(PseudoRandom Function)

PRF는은 secret, seed, identifying label을 입력받아 임의 길이의 출력을 만드는 함수입니다.


TLS 1.2에서 사용되는 PRF는 이쪽, TLS 1.1에서 사용되는 PRF는 이쪽에서 확인할 수 있으며, 구현이 꽤 다릅니다.
재밌는 것은 TLS 1.2에 사용되는 PRF가 더 간단하다는 겁니다. 

여기서는 TLS 1.2 기준으로 PRF를 알아보겠습니다.

PRF는 아래와 같이 정의되며, hash함수는 SHA-256 혹은 더 강한 해쉬 알고리즘을 사용해야 합니다.

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

P_hash함수는 데이터 길이를 늘려주는 함수로 내부적으로 HMAC을 사용합니다.

P_hash(secret, seed) =  HMAC_hash(secret, A(1) + seed) +
                        HMAC_hash(secret, A(2) + seed) +
                        HMAC_hash(secret, A(3) + seed) + ...
 
 
where + indicates concatenation.
 
 
A() is defined as:
  A(0) = seed
  A(i) = HMAC_hash(secret, A(i-1))

예를 들어, 80byte 길이의 데이터를 만들고 싶고 P_SHA256을 이용할 경우,

SHA256기반의 HMAC 함수를 3번 사용해 데이터를 붙이면 32*3=96 byte의 데이터가 되고,
이중 16 byte를 버려서 80 byte의 데이터를 만듭니다.

 

마치며

이번 편에서는 TLS의 Cipher suites, Handshake, Key derivation에 대해서 알아봤습니다.

다음편에서는 TLS 버전별 차이점들과 몇가지 취약점들에 대해서 알아봅시다.

 

Reference


0 Comments
댓글쓰기 폼