본문 바로가기

Engineering/Tomcat

SSL cipher suite ordering - Linux

728x90

웹 브라우저로 https:// 주소로 접속할때, 클라이언트와 서버 간에 교환하는 보안 알고리즘 집합인 cipher suite 의 우선 순위를 조정할 필요가 생긴다. 주로 메시지 인증 알고리즘을 sha2 로 바꿔달라는 요구사항이 발생한다. (쇼핑몰, 특히 CC 인증 ㅠㅠ 요구사항인 경우가 많다.)


인증서 생성

- Tomcat : JKS 타입

# keytool -genkey -alias KeystoreAlias -keysize 2048 -keyalg RSA -keystore mykeystore -dname "CN=mycompany.com, OU=webteam, O=MyCompany, L=seoul, ST=seoul, C=kr"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 로 설정

※ keytool 은 keysize 2048 로 설정하면 서명 알고리즘이 sha256 으로 설정된다. 


- Tomcat : PKCS12  타입

1. openssl req -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr -subj "/C=kr/ST=seoul/L=seoul/O=MyCompany/OU=webteam/CN=mycompany.com"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 , 서명 알고리즘은 sha256 으로 설정.

-> server.key : 서버 개인키(private key), server.csr : 서버 인증 요구서.


2. openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt -sha256

-> -sha256 : 서명 알고리즘은 sha256  으로 설정. 만일 이 옵션이 없으면 sha1 으로 설정된다.

-> server.crt : self signed 인증서.


3. openssl pkcs12 -export -in server.crt -inkey server.key -out mykeystore

-> 1,2 번에서 생성한 파일들을 가지고 PKCS12 타입으로 키저장소(mykeystore) 파일 생성.


- Apache HTTPD

1. openssl req -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr -subj "/C=kr/ST=seoul/L=seoul/O=MyCompany/OU=webteam/CN=mycompany.com"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 , 서명 알고리즘은 sha256 으로 설정.

-> server.key : 서버 개인키(private key), server.csr : 서버 인증 요구서.


2. openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt -sha256

-> -sha256 : 서명 알고리즘은 sha256  으로 설정. 만일 이 옵션이 없으면 sha1 으로 설정된다.

-> server.crt : self signed 인증서.


3. openssl x509 -in server.crt -noout -text

-> 인증서 내용 확인

-> -noout : PEM 부분을 출력안하도록 설정.


Tomcat 설정

- server.xml 설정 : GCM 이 선택되도록 하기 위해서는 sslProtocol TLSv1.2 로 선택해야함.

        <Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLSv1.2" sslEnabledProtocols="TLSv1.2"

                  ciphers="TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore" keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />


- server.xml 설정 2 : 어떤 환경에서는 sslProtocol 을 TLS 로 설정해야 연결되는 경우도 있다. 

<Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLS"

          ciphers="TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore"                keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />


- server.xml 설정 3 : IE11 에서 "TLS_RSA_WITH_AES_256_CBC_SHA256" 먼저 선택되도록 하기 위한 설정.(크롬 브라우저에서는 TLS_RSA_WITH_AES_256_CBC_SHA 가 선택된다.)

<Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLS"

                ciphers="TLS_ECDH_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore" keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />


※ cipher : 공개키 알고리즘(RSA, Diffie-Hellman, ...) + 대칭키 알고리즘(RC4, DES, AES, ...) + 해쉬 알고리즘(MD5, SHA, ...)의 집합


Apache 설정

# yum install httpd

# yum install mod_ssl


httpd.conf 설정

<VirtualHost *:443>

    SSLEngine on

    SSLCertificateFile /etc/httpd/conf/server.crt

    SSLCertificateKeyFile /etc/httpd/conf/server.key

    SSLCertificateChainFile /etc/httpd/conf/server.csr

    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown

    CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    DocumentRoot /var/www.html

    SSLProtocol             all

    SSLCipherSuite          ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK

    SSLHonorCipherOrder     on

#    SSLCompression          off

</VirtualHost>


테스트

IE 11 브라우저에서는 https:// 로 접속시,  443 포트 패킷을 캡쳐해보면 SSL handshake 과정에서 "Server Hello" 가 "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" 로 응답하는 것을 확인했다. 

그런데, 이해가 안되지만 크롬 최신버전(37.0.2062.120 m)에서는 동일한 인증서 파일인데도  "Server Hello" 가 "TLS_DHE_RSA_WITH_AES_128_GCM_SHA1" 으로 응답했다. 


- openssl 으로 접속 테스트

# openssl s_client -connect localhost:443

CONNECTED(00000003)

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify error:num=18:self signed certificate

verify return:1

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify return:1

...

...

...

---

SSL handshake has read 1463 bytes and written 477 bytes

---

New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA384

Server public key is 2048 bit

Secure Renegotiation IS supported

Compression: NONE

Expansion: NONE

SSL-Session:

    Protocol  : TLSv1.2

    Cipher    : ECDHE-RSA-AES256-SHA384

    Session-ID: 541C0297D25D7219750A92F8D17EE82762D7505C79B96F58DECFBF2D420D5FBF

    Session-ID-ctx:

    Master-Key: C50822A4CA025BE58961E3427F8A6F9F04B5F954B9F1D6C1A091D12CF91DE4BF06BDF77F0CEEDB96FB0BC617E60E3EC2

    Key-Arg   : None

    Krb5 Principal: None

    PSK identity: None

    PSK identity hint: None

    Start Time: 1411121874

    Timeout   : 300 (sec)

    Verify return code: 18 (self signed certificate)



openssl version

CentOS 5.X 대는 기본 설치되어 있는 openssl(라이브러리가 아닌 실행 프로그램이다) 의 버전이 0.9.8e 이다. 접속하려고 하면 다음과 같은 오류가 날수 있다. openssl 의 버그일 가능성이 높다.

# openssl s_client -connect localhost:443

CONNECTED(00000003)

31789:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:583: 


무시하고 1.X 버전의 openssl 에서 테스트해보자. openssl 을 업데이트한다.(yum update openssl) 

# openssl s_client -connect localhost:443

CONNECTED(00000003)

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify error:num=18:self signed certificate

verify return:1

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify return:1

139902702569288:error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group:ec_curve.c:316:

139902702569288:error:1408D010:SSL routines:SSL3_GET_KEY_EXCHANGE:EC lib:s3_clnt.c:1641:


openssl 의 버전이 "openssl-1.0.1e-15.el6_5.15.x86_64" (rpm -qa | grep openssl) 이라면  아마 위의 마지막에 나오는 "error: elliptic curve" 이하의 오류를 볼 수 있을 것이다. 관련 내용을 찾아보면 openssl 버그라고 나온다.

이때에는 openssl 을 업데이트(yum update openssl)하면 오류 메시지가 안 나온다. openssl 의 버전도 확인해보면 중간의 15가 16으로 바뀔것이다.(관련 링크1관련 링크2 )


그외

* 인증서에서 pem 정보만 뽑아내는 스크립트

# echo -n | openssl s_client -connect localhost:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./site.pem



참고한 사이트 :

http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html

https://www.ssllabs.com/ssltest/analyze.html?d=github.com&s=192.30.252.131

http://mail-archives.apache.org/mod_mbox/tomcat-users/201405.mbox/%3CCALAJ+5Aa9_yBJbvJxUwpUM4ytDXSQ+7KHd29+fcvpKfYn6Sk1Q@mail.gmail.com%3E

https://wiki.kldp.org/wiki.php/DocbookSgml/SSL-Certificates-HOWTO

http://opentutorials.org/course/228/4894

http://coffeenix.net/board_view.php?bd_code=1661

https://www.openssl.org/docs/apps/ciphers.html#TLS_v1_2_cipher_suites


'Engineering > Tomcat' 카테고리의 다른 글

인증서의 fingerprint(sha1, sha256) 확인  (0) 2014.09.03
tomcat keygen 간단 명령어  (0) 2014.08.22