macOS 에서 외장 모니터 레터박스 문제 해결

2015년에 나온 맥북을 델 U2713H 에 연결하니 화면 꽉차도록 출력하는게 아니라 주변이 검게 레터박스처럼 나오더라.

모니터 주변부가 화면 출력없이 검게 나온 상태

해상도를 잘못 설정하고 있나 봤는데, 우선 위 사진에서 처럼 정상적인 해상도고 모니터 상태 정보에서도 원하는 해상도 (2560 × 1440 @ 60㎐) 로 나오고 있다.

흔히 생각하는 케이블 문제는 아니고 — 얼마 전에 썼던 글에서 새로 구입한 케이블과 동일한 HDMI 2.0 스펙의 케이블을 구매했다 — 뭐가 문제일까 어리둥절. 혹시나 하는 마음으로 화면을 한 번 90도 돌려봤다.

왜죠. 화면이 가득 차더라. 그래서 트위터와 IRC에서 지인들에게 의견을 구하니 몇 가지 조언이 나왔다.

  • macOS 버전 문제일 수 있다. 최근 업데이트 후에 썬더볼트 디스플레이 색상 문제가 수정되었다 => HDMI 연결이고 최신 OS라 이건 문제가 아님.
  • 모니터에 오버스캔하는 기능이 있을 것이다 => 모니터가 그런 기능이 없는 저가 버전.
  • HDMI 케이블 문제 => 아님

오버스캔을 OS 수준에서 할 수 있는게 아닐까하고 구글 검색을 해봤다. 내가 겪는 문제의 해결법이 있다고 하는 글을 발견! 특정 모니터에 대한 설정이 언더스캔으로 되어있을 수 있다는 것. 위 글에서 언급한 `/var/db/.com.apple.iokit.graphics` 파일을 확인해보니 실로 그런 설정이 한 개 있더라. 아래 과정을 거쳐서 수정했다.

  1. 해당 파일 위치가 macOS의 시스템 무결성 보호 (System Integrity Protection; SIP) 기능으로 보호받는 영역이다. 그래서 우선 맥북을 끄고 Command + R을 누르면서 전원을 켠다.
  2. 유틸리티로 터미널을 실행하고 csrutil disable 명령을 입력해서 SPI 기능을 끈다. (정말로 꺼졌는지는 csrutil status명령으로 확인할 수 있다)
  3. 이제 저 파일을 열고 pscn 값이 10000 (=100%)이하인 항목을 찾아서 10000 으로 수정하고 저장.
  4. 다시 SPI를 활성화 한다. csrutil clear명령을 쓰고, 재부팅한다.

이러고 나면 아래처럼 내가 원하는데로 화면이 꽉차게 보인다. 별 이상한 내용으로 엄하게 삽질하다니 Orz

TLS 연결 디버깅: Forward Secrecy 재확인하기

앞선 글과 같이 쓰려고 했던 내용 정리. 글이 길어지고 쓸 시간도 모자라서 쪼개서 옮긴다.

SSL/TLS 연결로 메시지를 주고 받는 서버/클라이언트를 디버깅하는 작업이라 우선 wireshark 를 써서 덤프를 떴다. 아래 내용은 해당 디버깅 세션의 덤프는 아니고, 임의로 비슷한 TLS 설정을 쓰고,  거기서 HTTP GET을 보내고 응답을 받는 과정을 실행해서 해당 덤프를 얻었다. 이 메시지 덤프를 분석해서 “왜 이 메시지를 wireshark 에서 디코딩 할 수 없는지” 그리고 “TLS의 이런 기능 덕분에 우리의 사생활이 더 잘 키져지는지” 를 정리해보겠다.

TLS 메시지를 wireshark 에서 분석하려면 서버의 비밀키 (private key) 를 등록해야한다. Wireshark UI 상에서 추가하거나 (설정의 프로토콜 ssl 이하) ~/.config/wireshark/ssl_keys 파일에 디코딩할 서버 주소 (IP:port) 와 키에 해당하는 .pem 파일 위치를 지정하면 끝.

TLS 패킷 덤프 열어보기

이 설정으로 wireshark 에서 열어보면 아래처럼 분석이 불가능한 내용이 나온다.

비밀키를 알고 있는데 왜 분석을 할 수 없을까? 이는 TLS의 특정 키 교환 방식 때문이다. 실제로 어떤 메시지를 주고 받았는지 확인해보면 아래와 같다.

서버가 보낸 TLS 설정: Ephemeral ECDH 키교환 / RSA 로 키 교환 서명 / AES-256-GCM 으로 블럭 암호화 (AEAD) / SHA2 – 384 메시지 체크섬

서버와 클라이언트 사이에 사용할 암호화 키(=세션 키)를 서버가 바로 정해서 보내는게 아니라 타원곡선 (elliptic curve; EC) 을 사용한 디피-헬만 (DH) 키 교환 알고리즘을 이용하고, 이를 완전히 랜덤하고 이 세션에서만 쓰고 버릴 데이터를 이용하는 (ephemeral) 방식을 썼다. 즉, 서버의 비밀키는 세션 키와는 관련성이 없다.
서버의 비밀키는 서버가 ECDH 를 위한 메시지를 보낼 때, 해당 메시지를 서버가 보냈다고 전자 서명하는데 썼다. 이 메시지 내용은 다음과 같다.

서버가 보낸 ECDH 키 교환 과정에 해당하는 메시지

서버 인증서가 서명한 공개키가 RSA 알고리즘 기반이라, 서버가 보낸 메시지의 서명부분(Signature Algorithm 및 그 데이터)도 이 RSA 알고리즘을 써서 만든걸 확인할 수 있다.

디코딩할 수 없는 이유를 정리하면 다음과 같다.

  • 서버와 클라이언트 사이에 공유할 세션 키 (=둘만 알면되는 랜덤한 값) 를 생성하는데 서버 인증서의 비밀키 값을 쓰지 않는다.
  • 서버 인증서에 해당하는 비밀키는 이 공유 세션 키의 서버 부분을 보낼 때, 이 데이터가 “서버가 보냈음을 증명” 하는 용도로 전자서명할 때만 쓴다.
  • Server Key Exchange 에 해당하는 메시지는 서버 비밀키를 이용해서 이를 해석(=디코딩)할 수 없다. 비밀 키를 모르는 상태와 이 문제를 푸는 난이도가 동일하다. 그래서 서버에서 생성한 랜덤 값을 추측할 수 없다.
  • 클라이언트는 키 교환 메시지(Client Key Exchange) 를 보내고, 중간에 이걸 해석할 수 없다. 이 이후부터 서버와 클라이언트는 공유 비밀 정보를 만들고 이를 써서 세션 키를 초기화한다.

복호화 가능한 TLS 설정 시험하기

이런 이유로 오고 가는 메시지를 제대로 디코딩 할 수 없었던 것. 그럼 반대로(??) 서버의 비밀 키를 알고 있는 경우엔 디코딩 가능하게 하려면 어떻게 해야할까? 서버의 TLS 알고리즘에서 키를 생성할 때 임시 키를 안전하게 생성하는 방식을 쓰지 않도록 강제하면 된다. 예를 들어서 원래 사용하던 ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384;대신에, ssl_ciphers AES128-GCM-SHA256; 같은 걸로 설정하란 소리. 이렇게 바꾸면 아래처럼 암호화 푼 내용을 볼 수 있다.

위에서 말한 것처럼 TLS 설정이 RSA 기반의 세션 키 생성으로 바꿨다. 그리고 이 약한 알고리즘을 쓰는 경우에는 오고가는 HTTP 메시지를 원래 상태 그대로 확인할 수 있다.
알고리즘을 바꾸면 어떻게 서버 키로 암호화를 풀 수 있는지는, 키 교환 과정을 살펴보면 이해할 수 있다.

RSA 로 암호화한 PreMaster Secret 을 클라이언트에서 서버로 전송한다. 이 정보를 가지고 세션 키를 생성하게 된다. 그런데 이 RSA 키는 서버의 비밀 키에 해당한다. 즉, 키 교환 시점 이전부터 메시지를 덤프해두고 있다면 나중에 다시 이걸 복호화해서 볼 수 있다.

인터넷 상에서 사생활에 민감한 이들에겐 다행인 소식. 지난 8월 (2018년 8월) 에 표준화 작업을 마무리한 TLS 1.3 버전부터는 이런 방식을 쓸 수 없다. 앞서 디코딩할 수 없었던 ECDH처럼 “나중에 비밀키를 탈취해도 해석할 수 없는” 방법만 사용하게 바뀌었다. (이렇게 미래에 비밀키를 탈취당해도 문제 없는 방식이라 forward secrecy 라고 부른다)

다만 이런 FS 방식을 지원하는 경우에도, a. 서버 비밀키를 탈취하고 b. 서버 클라이언트 연결 사이에 끼어들어가서 능동적으로 중간자 공격 (man-in-the-middle attack) 을 하는 경우에는 복호화가 가능하다는 점은 참고하시길.

디버깅 방법 요약