예전에 만든 자료인데, 기억 못할까봐 정리해둔다.
-----------------------------------------------
part 1. 10년짜리 사실 인증서 만들기
개발 서버에서는 공인인증서를 꼭 써야 할 필요는 없다. 만약 공인인증서를 쓰지 않았을 때를 위해서 만들어 놓은 환경을 설명한다. 테스트 환경에서만 작동하는 보안 서버를 구축하면 된다.
CA (Certificate Authority, 인증기관)을 구성하고, 인증기관 자체의 private key와 public key를 생성하고, 결과물로 나온 인증서를 보안서버에 올리고, 보안 서버와 통신하는 모든 개발 PC및 개발 장비에서 사용할 수 있는 방법을 설명한다.
Http 서버 설정을 제외하고는 모두 Root 계정을 이용해야 한다.
자료는 아래 링크를 참조하면 된다.
http://www.ipsec-howto.org/x595.html
http://tldp.org/HOWTO/SSL-Certificates-HOWTO/x195.html
<파일 수정>
첫번째, CentOS의 openssl.conf 파일을 수정한다.
Redhat 계통(CentOS포함)에서는 /usr/share/ssl/openssl.cnf 설정파일을 참조해서 조금 수정하면 된다. dev개발환경이라는 가정을 하고, 다음 dev-openssl.conf 파일을 생성한다.
dev-ssl.google.com 이라는 도메인에 대한 인증서를 작성한다. 추가적으로 commonName에 alpha-ssl.google.com, beta-ssl.google.com, dev-id.google.com, dev-member.google.com 와 같이 여러 개의 도메인을 한 번에 등록할 수 있다.
# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca' and 'req'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = ./demoCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.pem# The private key RANDFILE = $dir/private/.rand # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crl_extensions = crl_ext default_days = 1825 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = md5 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 1024 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert # Passwords for private keys if not present they will be prompted for # input_password = secret # output_password = secret # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString. # utf8only: only UTF8Strings. # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings # so use this option with caution! string_mask = nombstr # req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = localityName = Locality Name (eg, city) localityName_default = 0.organizationName = Organization Name (eg, company) 0.organizationName_default = # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = team commonName = Common Name (eg, your name or your server\'s hostname) commonName_default = dev-ssl.google.com commonName_max = 64 # 만약 하나의 인증서로 다른 서버도 같이 쓸 수 있음. 아래의 예제와 같이 진행하면 됨 #0.commonName = Common Name (eg, your name or your server\'s hostname) #0.commonName_default = dev-ssl.google.com #0.commonName_max = 64 #1.commonName = Common Name (eg, your name or your server\'s hostname) #1.commonName_default = alpha-ssl.google.com #1.commonName_max = 64 #2.commonName = Common Name (eg, your name or your server\'s hostname) #2.commonName_default = beta-ssl.google.com #2.commonName_max = 64 #3.commonName = Common Name (eg, your name or your server\'s hostname) #3.commonName_default = dev-id.google.com #3.commonName_max = 64 #4.commonName = Common Name (eg, your name or your server\'s hostname) #4.commonName_default = dev-member.google.com #4.commonName_max = 64 emailAddress = Email Address emailAddress.default = (메일) emailAddress_max = 64 # SET-ex3 = SET extension number 3 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ usr_cert ] # These extensions are added when 'ca' signs a request. # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer:always # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always # This is what PKIX recommends but some broken software chokes on critical # extensions. #basicConstraints = critical,CA:true # So we do this instead. basicConstraints = CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Some might want this also # nsCertType = sslCA, emailCA # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details # issuerAltName=issuer:copy # DER hex encoding of an extension: beware experts only! # obj=DER:02:03 # Where 'obj' is a standard or added object # You can even override a supported extension: # basicConstraints= critical, DER:30:03:01:01:FF [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always |
두번째 수정할 파일은 /usr/share/ssl/misc/CA 파일이다. CA 파일은 Shell script로 구성되어 있으며, 인증기관 역할을 해준다. 보안(Http) 서버를 리얼 장비에 사용할 때 패스워드에 등록하지만, 개발 장비에 사용될 경우에는 굳이 패스워드를 등록하지 않아도 된다.
이를 위해서 /usr/share/ssl/misc/CA 파일의 일부분을 수정하면 된다. REQ의 내용에 ‘-nodes’를 추가하면 된다.
REQ="openssl req $SSLEAY_CONFIG" -> REQ="openssl req $SSLEAY_CONFIG -nodes" |
<CA 구성>
CA(Certificate Authority, 인증기관)을 구성한다. 인증기관 자체의 private key와 public key 를 생성한다.
]# mkdir certs ]# cd certs ]# /usr/share/ssl/misc/CA –newca CA certificate filename (or enter to create) (엔터) Making CA certificate ... Generating a 1024 bit RSA private key .....................++++++ .........................++++++ writing new private key to './demoCA/private/./cakey.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [GB]:(입력) State or Province Name (full name) [Berkshire]:(입력) Locality Name (eg, city) [Newbury]:(입력) Organization Name (eg, company) [My Company Ltd]:(입력) Organizational Unit Name (eg, section) []:(입력) Common Name (eg, your name or your server's hostname) [dev-ssl.google.com]: (입력) Email Address []:(입력) |
demoCA 디렉토리가 생기고, cacert.pem가 생성된다. 이는 CA 인증서 생성됨을 의미한다.
demoCA/private/cakey.pem 파일은 1024bite private key 이다.
]# cd demoCA/ ]# openssl x509 -in cacert.pem -days 3650 -out cacert.pem -signkey ./private/cakey.pem Getting Private key Enter pass phrase for ./private/cakey.pem: ]# /usr/share/ssl/misc/CA -newreq Generating a 1024 bit RSA private key ......++++++ ..........................++++++ writing new private key to 'newreq.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [GB]:(엔터) State or Province Name (full name) [Berkshire]:(엔터) Locality Name (eg, city) [Newbury]:(엔터) Organization Name (eg, company) [My Company Ltd]:(엔터) Organizational Unit Name (eg, section) []:(엔터) Common Name (eg, your name or your server's hostname) [dev-ssl.google.com]:(dev-ssl.google.com 엔터) Email Address []:(입력) Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: (엔터) An optional company name []: (엔터) Request (and private key) is in newreq.pem |
만들어진 newreq.pem 파일을 원래 생성했던 위치에 두어 다음 작업을 쉽게 하도록 한다.
]# cp newreq.pem .. ]# cd .. ]# ls -al drwxr-xr-x 3 root root 4096 11 15:09 . drwxr-xr-x 8 root root 4096 11 15:06 .. drwxr-xr-x 6 root root 4096 11 15:07 demoCA -rw-r--r-- 1 root root 1667 11 15:09 newreq.pem |
그 후, 만들어진 private key 파일을 가지고 CA로부터 인증을 한다. 이 결과로 newcert.pem 이라는 공개키가 생성된다. CA –sign은 인증서 승인 후, 인증서의 정보를 보여준다.
]# /usr/share/ssl/misc/CA -sign Using configuration from /usr/share/ssl/openssl.cnf Enter pass phrase for ./demoCA/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Mar 11 06:10:07 2011 GMT Not After : Mar 10 06:10:07 2012 GMT Subject: countryName = stateOrProvinceName = localityName = organizationName = organizationalUnitName = commonName = dev-ssl.google.com emailAddress = 메일 X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 77:BC:33:80:3E:07:F3:10:40:71:D0:EE:49:F6:53:93:66:DB:6A:20 X509v3 Authority Key Identifier: keyid:B4:8A:40:59:12:D6:3A:44:FC:27:31:A9:3E:D6:D8:B7:CD:40:08:EB DirName:/C=/ST=/L=/O=/OU=test/CN=dev-ssl.google.com/emailAddress= serial:00 Certificate is to be certified until Mar 10 06:10:07 2012 GMT (365 days) Sign the certificate? [y/n]:(y엔터) 1 out of 1 certificate requests certified, commit? [y/n](y엔터) Write out database with 1 new entries Data Base Updated Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=, ST=, L=, O=, OU=, CN=dev-ssl.google.com/emailAddress=메일 Validity Not Before: Mar 11 06:10:07 2011 GMT Not After : Mar 10 06:10:07 2012 GMT Subject: C=, ST=, L=, O=, OU=, CN=dev-ssl.google.com/emailAddress=메일 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:ce:0d:60:77:08:7b:8b:35:6e:97:dd:58:d3:0e: 81:ed:1b:d7:55:f6:c1:49:dc:e2:07:93:08:ca:1d: 27:8e:cd:19:30:fc:98:b7:c3:89:0a:98:43:aa:cf: 7e:8c:24:53:1a:87:1c:c1:13:10:0e:db:a5:09:e4: c3:79:0f:9b:1a:48:4b:51:50:63:bb:9a:23:c9:8f: e4:b0:a3:5b:74:3c:a7:fe:98:06:3c:fc:47:0e:ed: d8:e5:b1:3e:e1:8c:c1:e9:11:6e:ec:d4:84:0a:51: 67:7c:2b:86:ac:7d:16:b6:65:90:77:95:88:d2:29: e4:60:4d:73:59:2e:82:70:c5 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 77:BC:33:80:3E:07:F3:10:40:71:D0:EE:49:F6:53:93:66:DB:6A:20 X509v3 Authority Key Identifier: keyid:B4:8A:40:59:12:D6:3A:44:FC:27:31:A9:3E:D6:D8:B7:CD:40:08:EB DirName:/C=/ST=/L=/O=/OU=/CN=dev-ssl.google.com/emailAddress=메일 serial:00 Signature Algorithm: md5WithRSAEncryption 3c:d4:9b:79:9c:e3:eb:45:52:26:6d:12:61:27:a0:e6:4e:dc: c3:3a:59:6d:6a:d0:a5:62:e3:88:f5:c9:26:e2:35:15:01:8d: 65:2f:1d:b6:2e:be:62:83:db:cf:80:0b:c6:cc:3c:00:b3:7f: 9a:ce:b0:35:fd:a5:c1:b7:aa:fb:5d:40:2c:4f:39:64:ba:f1: c3:f8:10:aa:26:d0:5c:30:a1:3b:81:00:a6:77:6e:c5:33:ef: 25:c8:be:c1:c5:2b:40:e2:83:32:a1:a4:e2:99:91:95:d2:da: 83:3e:64:66:45:d3:86:25:db:aa:67:98:d4:fb:2f:cd:31:24: 0a:d7 -----BEGIN CERTIFICATE----- MIIDqzCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCS1Ix EDAOBgNVBAgTB0t5dW5nZ2kxEDAOBgNVBAcTB0J1bmRhbmcxDDAKBgNVBAoTA05I TjENMAsGA1UECxMEdGVzdDEcMBoGA1UEAxMTZGV2LXNzbC5uaG5jb3JwLmNvbTEd MBsGCSqGSIb3DQEJARYOa25pZ2h0QG5obi5jb20wHhcNMTEwMzExMDYxMDA3WhcN MTIwMzEwMDYxMDA3WjCBjzELMAkGA1UEBhMCS1IxEDAOBgNVBAgTB0t5dW5nZ2kx EDAOBgNVBAcTB0J1bmRhbmcxDDAKBgNVBAoTA05ITjENMAsGA1UECxMEdGVhbTEc MBoGA1UEAxMTZGV2LXNzbC5uaG5jb3JwLmNvbTEhMB8GCSqGSIb3DQEJARYSa25p Z2h0QG5obmNvcnAuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDODWB3 CHuLNW6X3VjTDoHtG9dV9sFJ3OIHkwjKHSeOzRkw/Ji3w4kKmEOqz36MJFMahxzB ExAO26UJ5MN5D5saSEtRUGO7miPJj+Swo1t0PKf+mAY8/EcO7djlsT7hjMHpEW7s 1IQKUWd8K4asfRa2ZZB3lYjSKeRgTXNZLoJwxQIDAQABo4IBFzCCARMwCQYDVR0T BAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh dGUwHQYDVR0OBBYEFHe8M4A+B/MQQHHQ7kn2U5Nm22ogMIG4BgNVHSMEgbAwga2A FLSKQFkS1jpE/CcxqT7W2LfNQAjroYGRpIGOMIGLMQswCQYDVQQGEwJLUjEQMA4G A1UECBMHS3l1bmdnaTEQMA4GA1UEBxMHQnVuZGFuZzEMMAoGA1UEChMDTkhOMQ0w CwYDVQQLEwR0ZXN0MRwwGgYDVQQDExNkZXYtc3NsLm5obmNvcnAuY29tMR0wGwYJ KoZIhvcNAQkBFg5rbmlnaHRAbmhuLmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQA8 1Jt5nOPrRVImbRJhJ6DmTtzDOlltatClYuOI9ckm4jUVAY1lLx22Lr5ig9vPgAvG zDwAs3+azrA1/aXBt6r7XUAsTzlkuvHD+BCqJtBcMKE7gQCmd27FM+8lyL7BxStA 4oMyoaTimZGV0tqDPmRmRdOGJduqZ5jU+y/NMSQK1w== -----END CERTIFICATE----- Signed certificate is in newcert.pem ]# ls -al drwxr-xr-x 3 root root 4096 11 15:09 . drwxr-xr-x 8 root root 4096 11 15:06 .. drwxr-xr-x 6 root root 4096 11 15:10 demoCA -rw-r--r-- 1 root root 3616 11 15:10 newcert.pem -rw-r--r-- 1 root root 1667 11 15:09 newreq.pem |
이렇게 만든 newreq.pem는 키이고, newcert.pem은 인증서이므로, 의미 있는 파일이름으로 각각 변경한다.
]# mv newreq.pem dev-ssl.node.key ]# mv newcert.pem dev-ssl.node.crt |
<10년짜리 인증서 만들기>
CA 기본 shell script에서 디폴트로 1년로 만들기 때문에 매년 연장해야 하는 불편함이 존재할 수 있다. 이를 운영에서 편리하게 하기 위해서 ‘/usr/share/ssl/misc/CA –sign’의 결과의 내용을 살펴보면, 아래와 같이 1년으로 되어 있는 것으로 확인할 수 있다.
Validity Not Before: Mar 11 06:10:07 2011 GMT Not After : Mar 10 06:10:07 2012 GMT |
Sign할 때의 인증기간을 수정하면 된다. /usr/share/ssl/misc/CA 파일을 수정한다.
첫번째 수정사항은 기간을 수정한다.
DAYS=”-days 365” -> DAYS="-days 1280" |
두번째 수정사항은 Sign 파라미터에 들어가는 스크립트를 수정한다.
$CA -policy policy_anything -out newcert.pem -infiles newreq.pem -> $CA -policy policy_anything -out newcert.pem -in newreq.pem $DAYS |
그리고, 인증서를 만드는 작업을 다시 진행한다.
Sign 작업후에 콘솔로 나오는 화면에 10년 짜리 인증서가 만들어진 것을 확인할 수 있다.
Validity Not Before: Mar 11 10:46:21 2011 GMT Not After : Mar 8 10:46:21 2021 GMT |
-------------------------
part 2. 사설 인증서를 로딩한 웹 서버 사용하기
http서버에 10년 짜리 인증서를 설치한다는 것을 가정한다.
새로 만든 인증서와 키파일을 모두 /home/www/httpd/conf 파일에 위치한다. 암호를 설정하지 않았기 때문에 SSLPassPhraseDialog지시자에 builtin을 지정한다. 만약 암호를 설정하였을 때는 SSLPassPhraseDialog 지시자에 암호를 출력하는 스크립트를 넣을 수 있다.
<IfModule mod_ssl.c> SSLRandomSeed startup builtin SSLRandomSeed connect builtin Listen 443 AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl SSLPassPhraseDialog builtin SSLSessionCache dbm:/home/www/httpd/logs/ssl_scache SSLSessionCacheTimeout 300 SSLMutex file: /home/www/httpd/logs/ssl_mutex </IfModule> .. <VirtualHost *:443> DocumentRoot /home/www/deploy ServerName dev-ssl.google.com <Directory "/home/www/deploy/service"> Options -Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny Allow from all FileETag None </Directory> <IfModule mod_ssl.c> SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:!SSLv2:+EXP:+eNULL SSLCertificateFile /home/www/httpd/conf/dev-ssl.node.crt SSLCertificateKeyFile /home/www/httpd/conf/dev-ssl.node.key SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 </IfModule> |
위와 같이 설정하고, http 서버를 재시작한다.
<로컬 pc 에서 인증서 설치>
로컬 PC에서 웹 브라우져를 이용해서 dev-ssl.google.com으로 접속하면 다음과 같이 보안 인증서에 대한 경고 화면이 뜬다. (Window 7, IE8 기준) 바로 신뢰할 수 있는 루트 인증기관이 아닌 서버에서 인증한 보안 인증서이기 때문이다.
웹 브라우져에서 이런 화면이 나오지 않게 하기 위해서는 해당 서버의 인증서를 신뢰할 수 있는 서버로 등록하면 된다. 인증서를 다운받는 법은 2가지이다. 첫번째는 서버에서 인증서를 파일로 다운받는다. 두번째는 웹브라우져에서 ‘인증서 오류’ 라 나오는 버튼을 클릭하고 ‘인증서 보기’로 해서 창을 띄우는 방법을 사용한다.
인증서를 띄우면 아래와 같이 확인할 수 있다. 10년짜리 인증서이지만, 확인할 수 없는 인증서라고 문구가 나온다. 인증서 설치를 선택한다.
‘인증서 설치’ 버튼을 선택하면 인증서 가져오기 마법사 시작 팝업창이 뜬다. 다음을 선택한다.
인증서 가져오기 마법사에서 ‘모든 인증서를 다음 저장소에 저장’을 선택한다.
인증 저장서를 선택하는 팝업창에서 ‘신뢰할 수 있는 루트 인증 기관’을 선택하고 확인 버튼을 선택한다.
‘인증서 가져오기 마법사’에 대한 완료 팝업창이 뜬다. 마침 버튼을 선택한다.
인증서 설치에 대한 화면이 발생하고 인증서를 설치할 것인지 묻는 팝업창이 발생한다. ‘예’ 버튼을 선택한다.
인증서 설치가 완료되었다는 팝업창이 열린다.
웹 브라우져를 이용해서 dev-ssl.google.com을 접속하면 아래와 같이 ‘보안 인증서에 문제가 있습니다’라는 내용이 뜨지 않는다.
<리늑서 서버 설치>
리눅스 서버에서 wget으로 접근시에는 인증시에 대한 검증에서 실패가 되어 에러를 발생시킨다.
]# wget https://dev-ssl.google.com/ [root@e61127 certs2]# wget https://dev-ssl.google.com/ --14:51:58-- https://dev-ssl.google.com/ => `index.html' Resolving dev-ssl.google.com... 1.1.1.1 Connecting to dev-ssl.google.com|1.1.1.1|:443... connected. ERROR: Certificate verification error for dev-ssl.google.com: unable to get local issuer certificate To connect to dev-ssl.google.com insecurely, use `--no-check-certificate'. Unable to establish SSL connection. |
이 문제를 해결하기 위해서는 간단하게 ‘--no-check-certificate’ 파라미터를 추가하여 접근한다.
]# wget --no-check-certificate https://dev-ssl.google.com/ --14:55:21-- https://dev-ssl.google.com/ => `index.html.1' Resolving dev-ssl.google.com... 10.25.149.50 Connecting to dev-ssl.google.com|10.25.149.50|:443... connected. WARNING: Certificate verification error for dev-ssl.google.com: unable to get local issuer certificate HTTP request sent, awaiting response... 200 OK Length: 11 [text/html] 100%[===============================>] 11 --.--K/s 14:55:21 (565.38 KB/s) - `index.html' saved [11/11] |
<Java에 인증서 설치>
Java를 이용하여 개발 보안 서버에 접근시 에러가 발생한다. Validation Check에서 실패하기 때문이다.
Java의 KeyStore에 해당 보안 개발 서버에 대한 접근이 되도록 할 수 있다. 보안 개발 서버를 사용하는 Linux 또는 PC 서버의 java에 인증서를 설치한다.
참고 웹은 다음 싸이트이다.
http://blogs.sun.com/andreas/entry/no_more_unable_to_find
예제는 다음과 같다. Apache Common의 httpclient 3.0.1를 가지고 dev-ssl.google.com 접속하는 코드이다.
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; public class Test { public static void main(String[] args) throws Exception { byte[] responseBody = null; HttpClient client = new HttpClient(); GetMethod method = new GetMethod("https://dev-ssl.google.com"); int responseCode = client.executeMethod(method); if (responseCode != HttpStatus.SC_OK) { System.out.println("Method failed: " + method.getStatusLine()); } else { responseBody = method.getResponseBody(); System.out.println(new String(responseBody)); } } } |
테스트 코드를 실행하면 SSL handshake를 하면서 인증서에 대한 valid 체크에서 발생했다는 Exception이 발생한다.
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632) at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123) at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:827) at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:1975) at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:993) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:397) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324) at org.Test.main(Test.java:13) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217) at sun.security.validator.Validator.validate(Validator.java:218) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185) ... 17 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318) ... 23 more |
Java 에서 신뢰할만한 웹 사이트를 등록하여 인증서가 발생되지 않게 할 수 있다.
Andreas Sterbenz’s Blogs(http://blogs.sun.com/andreas/resource/InstallCert.java)에서 소스를 다운받고 컴파일한다.
]# javac InstallCert.java |
보안 개발 서버인 dev-ssl.google.com:443 을 파라미터로 넣고 java를 실행한다. 중간에 “
Enter certificate to add to trusted keystore”를 묻는 질문에 ‘1’을 입력한다.
]# java InstallCert dev-ssl.google.com:443 Loading KeyStore C:\Program Files\Java\jre6\lib\security\cacerts... Opening connection to dev-ssl.google.com:443... Starting SSL handshake... javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderExce ption: unable to find valid certification path to requested target at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unkno wn Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source ) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Un known Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Sou rce) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Sou rce) at org.InstallCert.main(InstallCert.java:88) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find vali d certification path to requested target at sun.security.validator.PKIXValidator.doBuild(Unknown Source) at sun.security.validator.PKIXValidator.engineValidate(Unknown Source) at sun.security.validator.Validator.validate(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown So urce) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted( Unknown Source) at org.InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.jav a:183) ... 9 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) at java.security.cert.CertPathBuilder.build(Unknown Source) ... 15 more Server sent 1 certificate(s): 1 Subject CN=dev-ssl.google.com, O=My Company Ltd, L=Newbury, ST=Berkshire, C= GB Issuer CN=dev-ssl.google.com, O=My Company Ltd, L=Newbury, ST=Berkshire, C= GB sha1 e6 69 34 03 ec f2 b8 2e eb 57 ad 96 9f 25 a9 69 16 87 fc 90 md5 f0 a8 d1 63 65 8f 5c c6 a0 9b ea 4f 48 58 85 3d Enter certificate to add to trusted keystore or 'q' to quit: [1] 1 [ [ Version: V3 Subject: CN=dev-ssl.google.com, O=My Company Ltd, L=Newbury, ST=Berkshire, C= GB Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4 Key: Sun RSA public key, 1024 bits modulus: 164347762420350693911866588325014644788520374516295193084948890924394 29081792855076590616988805837259808518029679131404902167803255295786539153611119 63396590676780565399712003063159189376410163690837891366179294614852352512484317 28761333574986219672551265326558528460114938587517180908714459949305597793224899 public exponent: 65537 Validity: [From: Sat Mar 12 14:05:07 KST 2011, To: Tue Mar 09 14:05:07 KST 2021] Issuer: CN=dev-ssl.google.com, O=, L=, ST=, C= SerialNumber: [ 01] Certificate Extensions: 4 [1]: ObjectId: 2.16.840.1.113730.1.13 Criticality=false Extension unknown: DER encoded OCTET string = 0000: 04 1F 16 1D 4F 70 65 6E 53 53 4C 20 47 65 6E 65 ....OpenSSL Gene 0010: 72 61 74 65 64 20 43 65 72 74 69 66 69 63 61 74 rated Certificat 0020: 65 e [2]: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 9E 6F 1F 00 01 A4 3F 8E 8D 03 B8 6C 0B B5 57 27 .o....?....l..W' 0010: 3A 11 0C 70 :..p ] ] [3]: ObjectId: 2.5.29.35 Criticality=false AuthorityKeyIdentifier [ KeyIdentifier [ 0000: F4 8D D1 BC BA 8F B4 17 3E 98 93 E9 04 59 5A 32 ........>....YZ2 0010: 41 3D DF 36 A=.6 ] [CN=dev-ssl.google.com, O=, L=, ST=, C=] SerialNumber: [ 00] ] [4]: ObjectId: 2.5.29.19 Criticality=false BasicConstraints:[ CA:false PathLen: undefined ] ] Algorithm: [MD5withRSA] Signature: 0000: 2A E4 E5 14 91 58 17 84 39 DE BA 8F 41 61 92 F3 *....X..9...Aa.. 0010: FA 9C 01 70 D9 F9 44 DD B1 02 E4 D9 1D 7C 58 2A ...p..D.......X* 0020: 5A D9 39 E2 24 F7 DD 09 DC 3C 62 C7 09 3D 87 43 Z.9.$....<b..=.C 0030: 44 DC 68 FE 12 89 8E 54 62 94 3D B7 F5 2E 4E 30 D.h....Tb.=...N0 0040: 99 B8 CB 8A 6D 8D 3A 47 0A E3 5C 81 5F AE 4B CF ....m.:G..\._.K. 0050: 8E 3D 70 64 EA E2 72 C5 E7 21 27 74 19 80 91 95 .=pd..r..!'t.... 0060: E8 D7 07 E1 9E 53 06 66 D0 4C 79 92 DC D7 4E 30 .....S.f.Ly...N0 0070: 8F 21 37 15 38 01 9F F1 E9 C1 E9 E5 99 03 FB F8 .!7.8........... ] Added certificate to keystore 'jssecacerts' using alias 'dev-ssl.google.com-1' |
실행 이후에 자바 인증서인 jssecacerts 파일이 생성된다.
이 파일을 $JAVA_HOME/jre/lib/security 에 복사하고 Http 연결 테스트 코드를 실행하면 기대하는 결과값이 출력되는 것을 확인할 수 있다. 이렇게 보안 개발 서버와 통신하는 서버들은 이렇게 사용하여 공인 인증서 없이 테스트 환경을 구축할 수 있다.
<Keytool 이용>
자바에서는 인증서 파일에 대한 정보를 keystore라고 불리며, cacerts, jssecacerts 두 개의 파일을 사용한다. 읽는 순서는 첫번째가 jssecacerts 파일이고, 그 다음은 cacerts파일이다. 관리가 잘 되어, overwrite되지 않도록 잘 관리되어야 한다.
추가적인 보안 개발 서버를 추가할 때마다 keytool 명령어를 이용해서 관리할 수 있다.
keytool에 대한 자세한 내용은 문서를 참조한다.
http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html
http://download.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html
리눅스를 이용하는 경우에 jssecacerts keystore 파일에 보안 개발 서버에 대한 인증서가 있는지 확인할 수 있다. 아래 싦행 명령어의 ‘실제 위치’는 ‘$JAVA_HOME/jre/lib/security’를 의미한다.
]# keytool -list –keystore 실제위치/jssecacerts -storepass changeit | grep dev-ssl dev-ssl.google.com-1, 2011. 3. 14, trustedCertEntry, |
더 이상 사용하지 않는다면 keystore 파일에서 보안 개발 서버를 삭제할 수 있다.
]# keytool -delete -alias dev-ssl.google.com-1 -keystore 실제위치/jssecacerts -storepass changeit ]# keytool -list -keystore 실제위치/jssecacerts -storepass changeit | grep dev (결과 없음) |
자바에서 http 서버로 보안 개발 서버로 접근하면, Exception이 발생되는 것을 확인할 수 있다.
윈도우를 사용하는 경우, cmd창을 실행하고, 창안에서 다음과 같이 확인 및 삭제가 가능하다.
]# keytool.exe -list -keystore 실제위치/jssecacerts -storepass changeit | findstr dev-ssl dev-ssl.google.com-1, 2011. 3. 14, trustedCertEntry, ]# keytool -delete -alias dev-ssl.google.com-1 -keystore 실제위치/jssecacerts -storepass changeit ]# keytool.exe -list -keystore 실제위치/jssecacerts -storepass changeit | findstr dev-ssl (결과 없음) |
'Web service' 카테고리의 다른 글
Apache Http 서버의 VirtualHost 설정 (0) | 2012.01.17 |
---|---|
Apache Http 서버의 ListenBackLog 지시자 (0) | 2012.01.17 |
hash dos 공격 with Tomcat (1) | 2012.01.17 |
2012년 초 Webwork / struts2 보안 이슈 (0) | 2012.01.16 |
카산드라(Cassandra)가 ivy에서 maven으로 바꾼 이유 (0) | 2011.12.15 |