자바 암호 프로그래밍 Java Cryptography Programming 2017. 3. 중부대학교 정보보호학과 이병천 교수
차례 1. 강의 개요 2. 암호와 정보보호 3. 자바프로그래밍 기초 4. 자바 네트워크 프로그래밍 5. JCA/JCE 암호 프로그래밍 6. 해쉬함수, MAC, 패스워드 기반 키생성 7. 대칭키 암호, 파일 암호화/복호화 8. 공개키 암호 9. 전자서명 10. 인증서와 공개키기반구조(PKI) 11. 암호 알고리즘/프로토콜 구현
10. 인증서와 공개키기반구조
1. 공개키인증서 On the Internet, nobody knows you’re a dog © The New Yorker Collection 1993 Peter Steiner from cartoonlink.com. All rights reserved.
+ = 공개키인증서 공개키인증서(Certificate)란? 개인이 사용하는 공개키를 인증기관이 인증해주는 전자문서 개인정보와 공개키가 포함된 전자문서를 인증기관이 전자서명한 문서 인증기관을 신뢰하는 범위 내에서 사용자 인증을 위해 널리 호환 되어 사용 가능 사용자 A의 공개키 사용자 A의 공개키에 대한 인증기관(CA)의 전자서명 사용자 A의 인증서(사용자 A의 공개키와 이것을 증명코자 하는 신뢰(인증)기관의 전자서명 포함) + = 당 공개키는 사용자 A의 공개키 임을 증명함
공개키인증서 보기 일반 자세히 인증경로
공개키인증서 공개키인증서 표준 인증서의 구성 X.509, The Directory: Authentication Framework, 1993. 인증서의 구성
공개키인증서의 확장 필드 발급자키식별자(Authority Key Identifier): 이 인증서를 확인할 때 사용할 발급자의 공개키를 독특하게 식별하는 식별자 자체 서명 인증서를 제외한 모든 인증서의 필수 요소 주체키식별자(Subject Key Identifier): 이 인증서에 포함된 공개키 를 독특하게 식별하는 식별자 인증기관 인증서의 경우에는 필수 요소 키용도(Key Usage): 이 인증서에 바인딩되어 있는 공개키의 사용용 도를 한정하기 위해 사용 전자서명, 부인방지, 키 암호화, 데이터 암호화, 키 동의 등 인증기관의 경우 keyCertSign, cRLSign이 설정되어 있어야 함 CRL 분배점(CRL distribution point): 이 인증서의 폐지 여부를 확 인하기 위한 인증서 폐지 목록이 있는 위치 Basic-Constraints: 이 인증서가 인증기관의 인증서임을 나타내기 위해 사용됨
공개키인증서 인증서 (기본영역)
공개키인증서 인증서 (확장영역)
2. 공개키기반구조(PKI) 공개키기반구조(public key infrastructure, PKI) 인증서 표준 공개키 암호 방식을 바탕으로 한 인증서를 활용하는 소프트웨어, 하드웨어, 사용자, 정책 및 제도 등을 총칭하는 용어 공개키암호기술이 안전하게 사용될 수 있는 환경을 제공 인증서 표준 X.509, The Directory: Authentication Framework, 1993. 공개키기반구조 표준 PKIX: Internet X.509 Public Key Certificate Infrastructure. https://datatracker.ietf.org/wg/pkix/charter/
인증기관 인증기관의 계층구조 정책승인기관(PAA, Policy approval authority) 정책인증기관(PCA, policy certification authority) 인증기관(CA, certification authority) 인증서를 발급하는 기관 등록기관(RA, registration authority) 사용자의 신분을 확인하고 등록요청을 대행하는 기관 사용자 대면 신분인증 필요 화살표는 인증서 발급관계를 나타냄 상위 인증기관이 하위 인증기관의 인증서를 발급
인증기관 인증기관의 업무 인증서 발급 인증서 관리 인증서 배포 인증서 사용 인증서 저장 인증서 취소
PKI 서비스 흐름도
3. 공인인증서 공인인증서 공인인증기관이 발행하는 인증서 널리 호환되어 이용 가능
공인인증서 공인인증기관
RA의 소속기관 지방청, 16개 시·도 내 시·군·구 공인인증체계 기관, 개인, 특별용도 정부인증관리센터 (정부전산정보관리소) 국가정보원, 국방부, 대검찰청, 대통령비서실, 병무청, 교육부. 행정자치부 정보통신부 외 10개 중앙행정기관, 16개 시도 Root-CA 가입자 RA LRA CA Root CA 등록기관 (RA) 인증기관 (CA) 디렉 토리 디렉토리 원격등록기관 (LRA) RA의 소속기관 지방청, 16개 시·도 내 시·군·구 기업, 서버, 개인, 특별용도 전자서명인증관리센터 (한국정보보호진흥원) 한국정보인증, 한국증권전산, 금융결제원, 한국전산원, 한국전자인증, 무역정보통신 은행, 증권 기타 기업 및 공공기관 GPKI NPKI 최상위 인증기관 정부, 행정 영역 민간 영역
전자정부에서의 활용 교육행정정보서비스 (NEIS) 특허넷시스템 전자조달시스템 (G2B) 전자민원 (G4C) 행정 대민 지역교육청 전산실 담당자 RA 이중화 행정업무 중요 정보의 암호화, 전자서명 공인인증 공인인증(교육부용) RA 교육부 CA X 인증센터 구축 사설인증서, 공인인증서 공인인증서 운영인원 필요 RA 운영인원(X) 운용관리(10~20명) 사설 CA시스템 센터 운영 전자출원 적용 입찰업무 전자입찰서 (XML 기반) 전자결재 민원신청서 적용 사설인증, 전자관인 전자관인 , 공인인증 전자관인 특허청 조달청 행정자치부 인증 시스템 인원 운영 인증·보안 적용 인증서 사용
공인인증서 발급 절차
공인인증기관이 제공하는 서비스 기본 서비스 부가 서비스 인증서 발급 인증서 갱신 인증서 재발급 인증서 폐지 인증서 효력정지 인증서 효력회복 인증서 관리 부가 서비스 실시간 상태조회 서비스 시점확인 서비스
공인인증서 공인인증서의 저장 위치 Windows XP Windows 7 이후 C: > Program files > NPKI Windows 7 이후 C: > 사용자 > 사용중인 계정이름 > AppData > LocalLow > NPKI User 폴더 공개키: signCert.der 개인키: signPri.key 개인키는 패스워드 암호화 저장됨
공인인증서 정보 보기 서명 해시 알고리즘: sha256 공개키: RSA 2048 bits 키 사용: 전자서명, 부인방지 인증서 정책: http://www.yessign.or.kr/cps.htm
실시간 상태조회 서비스(OCSP) OCSP (Online Certificate Status Protocol) 사용자의 실수 또는 고의로 폐지된 공인인증서가 사용되는 것을 방지하기 위해 공인인증서의 유효성을 실시간으로 검증하여 결 과를 제공하는 서비스
시점확인 서비스(TSA) TSA (Time Stamping Authority) 전자문서 생성시점의 법률적 증명과 위·변조 방지를 위해 특정 시점에 존재하였으며, 그 이후 변경되지 않았음을 증명해 주는 서비스
4. 인증서 폐기 생성한 전자문서를 폐기할 수 있는가? 발급한 인증서를 무효화시킬 수 있는가? 전자문서는 여러 곳에 복사 가능 사생활, 명예훼손 잊혀질 권리 발급한 인증서를 무효화시킬 수 있는가? 인증서 분실로 사용이 불가능해진 경우 재발급 필요 사용자의 신분이 변경되어 더 이상 사용하지 못하는 경우
WANTED! 공개수배전단
인증서 폐기 목록 Certificate Revocation List (CRL) RFC 5280으로 표준화 해지되었거나 더 이상 유효하지 않은 인증서의 목록을 인증기관 이 서명한 문서 CRL에 포함된 인증서는 유효하지 않으므로 신뢰해서는 안됨 RFC 5280으로 표준화 Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
인증서 폐기 목록 인증서취소목록(CRL)의 기본 영역 서명 알고리즘 : CRL에 서명한 서명 알고리즘 ID 및 관련 데이터 발급자 : 발급자 CA의 X.509 이름 최근 수정 일자 : 최근 수정 일자(UTC Time) 차후 수정 일자 : 다음 수정 일자(UTC Time) 취소 인증서 목록 : 취소된 인증서 목록들 CRL확장자 : CRL 확장자 유무 및 내용 발급자 서명문 : 발급자의 서명문 CRL의 확장 영역 : 기본 확장자 + 개체 확장자 기본 확장자 CA 키 고유 번호 : CRL에 서명한 키 번호 발급자 대체 이름 : CRL 발급자의 대체 이름(e-mail, IP 주소 등) CRL 발급번호 : CRL에 대한 일련 번호 발급 분배점 : CRL 분배점 이름 델타 CRL지시자 : 최근에 취소된 목록만을 저장한 델타 CRL 지시자 개체 확장자 취소 이유 부호 : 인증서가 취소된 이유 명령 부호 : 해당 인증서를 만났을 경우 취해져야 할 명령 무효화 날짜 : 해당 인증서가 무효화된 날짜 인증서 발급자 : 간접 CRL에서의 해당 인증서 발급자
인증서 폐기 목록 인증서 폐기 이유 명시 (CRL reason code) unspecified (0) keyCompromise (1) CACompromise (2) affiliationChanged (3) superseded (4) cessationOfOperation (5) certificateHold (6) removeFromCRL (8) privilegeWithdrawn (9) AACompromise (10)
5. 인코딩과 저장형식 Base64 ASN.1 (Abstract Syntax Notation One) DER (Distinguished Encoding Rules) PEM (Privacy-enhanced Electronic Mail)
Base64 인코딩 Base64 인코딩 8비트 이진 데이터(예를 들어 실행 파일이나, ZIP 파일 등)를 문 자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루 어진 일련의 문자열로 바꾸는 인코딩 방식 64 = 26은 화면에 표시되는 ASCII 문자들을 써서 표현할 수 있는 가장 큰 진법 알파벳 대소문자(A-Z, a-z)와 숫자(0-9) 그리고 두 개의 기호(“+”, “/”)로 이루어져 있으며, 패딩 문자로 “=”를 사용 바이너리 데이터 3바이트를 4개의 Base64 문자로 변환 (8*3=6*4) 입력되는 데이터가 3바이트로 나누어 떨어지지 않는 경우에는 “=”를 패딩 문자로 사용 저장, 전송, 화면 표시 등에 편리. 그러나 데이터가 확대되는 단점
ASCII 와 Base64 ASCII (8비트) Base64 (6비트)
Base64 인코딩 ASCII 데이터 “Man”을 Base64 인코딩하면 “TWFu”로 변 환 https://www.base64encode.org/
ASN.1 표현법 Abstract Syntax Notation One (ASN.1) 데이터 구조를 나타내기 위한 표현언어 이기종 시스템간의 데이터 전송을 위한 표준 방식 적용 사례 PKCS group of cryptography standards X.400 electronic mail X.500 Lightweight Directory Access Protocol (LDAP) H.323 (VoIP) Kerberos BACnet simple network management protocol (SNMP) UMTS, LTE, and WiMAX 2
X.509 인증서의 ASN.1 표현 X.509 인증서 아래 문서를 인증기관이 서명 인증서 양식
인증서 인코딩 DER (Distinguished Encoding Rules) 바이너리 인코딩 (화면 표시가 어려움) 인증서 저장에 사용 CER 또는 CRT 확장자로 사용되기도 함 PEM (Privacy-enhanced Electronic Mail) Base64 인코딩 (화면 출력 가능) X.509v3 에서 사용되는 여러 파일 양식들을 저장하는데 사용 인증서, 개인키, 인증서 발급 요청 양식 등 “—– BEGIN …” 으로 시작됨 openssl x509 -in certificate.der -inform der -text -noout openssl x509 -in cert.pem -text -noout openssl x509 -in cert.cer -text -noout openssl x509 -in cert.crt -text -noout
인증서 관련 확장자 .DER .CRT .CER .KEY 인증서 저장에 사용되는 확장자 인증서 저장에 사용 (Unix 방식) The CRT extension is used for certificates. The certificates may be encoded as binary DER or as ASCII PEM. The CER and CRT extensions are nearly synonymous. .CER 인증서 저장에 사용 (마이크로소프트 방식) alternate form of .crt (Microsoft Convention) .KEY PKCS#8 형식으로 공개키, 개인키 저장에 사용 The keys may be encoded as binary DER or as ASCII PEM
6. OpenSSL Secure Sockets Layer (SSL) 이란? OpenSSL이란? 넷스케이프 사에서 최초 개발 서버와 클라이언트 사이의 통신 보안을 제공하는 프로토콜 IETF 에서 TLS (Transport Layer Security) 라는 이름으로 표준화 OpenSSL이란? SSL/TLS 통신보안을 제공하는 오픈소스 툴킷 인증서 생성 및 이용 기능 제공 https://www.openssl.org/
OpenSSL 설치 리눅스 환경 윈도우 환경 대부분의 리눅스 운영체제에 기본 설치되어 있음 # sudo apt-get install openssl 윈도우 환경 http://slproweb.com/products/Win32OpenSSL.html Win64 OpenSSL v1.0.2k 다운로드 및 설치 환경변수에 설치 디렉토리 등록, C:\OpenSSL-Win64\bin openssl.cfg 파일을 C:\OpenSSL-Win64 폴더에 복사 참고 http://zero-gravity.tistory.com/239 http://blog.daum.net/coy486/15
OpenSSL 자주 쓰는 명령어 사용법 인터넷 검색 명령어 https://www.lesstif.com/spaces/flyingpdf/pdfpageexport.action? pageId=7635159 https://www.lesstif.com/pages/viewpage.action?pageId=763515 9 명령어 인증서 정보 보기 인코딩 변환 개인키 생성, 암호 설정, 암호 변경
OpenSSL 명령어 활용 RSA 키 생성 OpensSSL> genrsa -des3 -out private.pem 2048 개인키 암호화 저장을 위한 패스워드 입력 *.pem 형식으로 개인키 저장 private.pem
OpenSSL 명령어 활용 RSA 공개키 생성 앞에서 생성한 개인키 파일에 공개키 정보도 포함되어 있음 개인키 파일로부터 공개키를 추출하여 파일로 저장 가능 OpenSSL> rsa -in private.pem -outform PEM -pubout -out public.pem public.pem
OpenSSL 명령어 활용 자체서명인증서(Self-signed certificate) 생성 루트 인증기관은 상위에 인증기관이 없음 자신의 개인키로 자신의 공개키를 서명한 자체서명인증서를 생 성하여 사용 가능 (대외적인 신뢰도는 없음) 개인키 사용을 위한 접근암호 입력 필요 인증서 생성에 필요한 정보 입력 OpenSSL> req -new -x509 -days 365 -key private.pem -out ca.crt
OpenSSL 명령어 활용 생성된 인증서 보기 ca.crt 파일 클릭
OpenSSL로 인증기관 운영하기 운영 방법 (시뮬레이션) 1. DemoCA 환경 설정 2. 인증서버 준비 폴더생성, 파일생성 2. 인증서버 준비 인증기관 키쌍 생성 RootCA 자체서명인증서 생성 3. 사용자의 인증서 발급 요청 사용자는 키쌍을 생성하여 인증기관에 인증서 발급 요청서 작성 4. 인증기관이 인증서를 발급 인증기관의 개인키로 서명하여 인증서 생성
OpenSSL로 인증기관 운영하기 작업 순서 1. Demo CA 설정 (환경 설정) 1) 현재 디렉토리에 demoCA 디렉토리 생성 : mkdir demoCA 2) demoCA 디렉토리 안에 시리얼 파일 생성 : serial 이란 이름의 text 파일에 00 을 적는다. 3) index 파일 생성 : index.txt 란 이름으로 빈 파일을 만든다. 2. 인증서버 준비 (인증서버의 자체서명인증서 생성) 현재 디렉토리에서 작업 수행 (demoCA 폴더에서 수행하지 않음) 1) CA 개인키 생성 (ca.key) openssl genrsa -des3 -out ca.key 1024 2) 자체서명 인증서 생성 (ca.crt) openssl req -new -x509 -days 365 -key ca.key -out ca.crt
OpenSSL로 인증기관 운영하기 작업 순서 3. 사용자 웹서버의 인증서 발급 요청서 생성 (예: cris Web 서버용) 1) server 개인키 생성 (server.key) openssl genrsa -des3 -out server.key 1024 2) server 인증서 발급을 위한 요청서 생성 (server.csr) openssl req -new -days 365 -key server.key -out server.csr 4. 인증서 발급 1) server 인증서 발급 (server.crt) openssl ca -in server.csr -out server.crt -keyfile ca.key -cert ca.crt -outdir .
OpenSSL로 인증기관 운영하기 F:\workspace\openssl\CAtest>openssl ca -in server.csr -out server.crt -keyfile ca.key -cert ca.crt -outdir . Using configuration from C:\OpenSSL-Win64\bin\openssl.cfg Enter pass phrase for ca.key: Check that the request matches the signature Signature ok Certificate Details: Serial Number: 0 (0x0) Validity Not Before: Apr 29 02:29:33 2017 GMT Not After : Apr 29 02:29:33 2018 GMT Subject: countryName = kr stateOrProvinceName = Gyeonggi-do organizationName = Joongbu Univ. organizationalUnitName = Information Security commonName = cris emailAddress = sultan@joongbu.ac.kr X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 9B:94:8B:22:FF:27:74:3A:50:91:19:77:B6:06:A5:77:19:E2:5C:DC X509v3 Authority Key Identifier: keyid:07:35:2C:60:76:4A:A0:D9:A9:97:59:47:8B:4E:3D:62:50:90:8F:A4 Certificate is to be certified until Apr 29 02:29:33 2018 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
발급된 서버 인증서 Server.crt 인증기관이 발급한 인증서 Server.key 웹서버의 개인키 Server.csr 인증서 발급 요청서
인증서 포맷 변경 Crt der 포맷 변경 openssl x509 -in ca.crt -out ca.der -outform DER
인증서 내용 보기 인증서 내용 보기 openssl x509 -in ca.crt -text (PEM 포맷인 경우) openssl x509 -in ca.der -inform DER -text (DER 포맷인 경우)
SSL 인증서 활용 예제 인증서 생성 (jdk에 포함된 keytool.exe을 이용) 임의 폴더에서 실행 가능하도록 Path 환경변수에 자바의 bin 폴 더를 추가
SSL 인증서 활용 예제 Keytool 명령어 Generate a Java keystore and key pair keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048 Generate a certificate signing request (CSR) for an existing Java keystore keytool -certreq -alias mydomain -keystore keystore.jks -file mydomain.csr Import a root or intermediate CA certificate to an existing Java keystore keytool -import -trustcacerts -alias root -file Thawte.crt -keystore keystore.jks Import a signed primary certificate to an existing Java keystore keytool -import -trustcacerts -alias mydomain -file mydomain.crt -keystore keystore.jks Generate a keystore and self-signed certificate keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048
SSL 인증서 활용 예제 인증서 생성 프로젝트 폴더 밑의 bin 폴더에서 keytool로 인증서 생성 키저장소 지정 및 비밀번호 입력 필요 (비밀번호: 123456) keytool -genkey -keystore mySrvKeystore -keyalg RSA
SSL 인증서 활용 예제 서버 : EchoServer.java 클라이언트 : EchoClient.java import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class EchoServer { public static void main(String[] arstring) { try { SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(9999); SSLSocket sslsocket = (SSLSocket) sslserversocket.accept(); InputStream inputstream = sslsocket.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); String string = null; while ((string = bufferedreader.readLine()) != null) { System.out.println(string); System.out.flush(); } } catch (Exception exception) { exception.printStackTrace(); import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.io.*; public class EchoClient { public static void main(String[] arstring) { try { SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 9999); InputStream inputstream = System.in; InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); OutputStream outputstream = sslsocket.getOutputStream(); OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream); BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter); String string = null; while ((string = bufferedreader.readLine()) != null) { bufferedwriter.write(string + '\n'); bufferedwriter.flush(); } } catch (Exception exception) { exception.printStackTrace(); SSL을 이용한 보안통신 적용 클라이언트의 입력을 서버는 그대로 에코
SSL 인증서 활용 예제 서버 실행 (bin 폴더) 클라이언트 실행 (bin 폴더) 키저장소이름, 비밀번호를 옵션으로 지정하여 실행 클라이언트 실행 (bin 폴더) trustStore 비밀번호 입력 필요 java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 EchoServer java -Djavax.net.ssl.trustStore=mySrvKeystore -Djavax.net.ssl.trustStorePassword=123456 EchoClient
SSL 인증서 활용 예제 디버깅 (상세 실행 내용을 콘솔에 출력) 서버, 클라이언트 실행시 다음 옵션 추가 -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl 서버 실행 java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl EchoServer 클라이언트 실행 java -Djavax.net.ssl.trustStore=mySrvKeystore -Djavax.net.ssl.trustStorePassword=123456 -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl EchoClient
SSL 인증서 활용 예제 EchoServer EchoClient
7. 인증서 프로그래밍 JCA/JCE는 인증서 관련 제공하는 기능이 부족 BouncyCastle 패키지 이용 가능 암호/보안 관련 다양한 기능 제공 X.509 인증서 관련 엔진 org.bouncycastle.x509.X509V3CertificateGenerator bcprov-jdk15on-159.jar 파일을 다운로드하여 프로젝트 폴더에 저장 Add External JARs로 등록하여 사용 Java 소스 내에서 프로바이더 추가 Security.addProvider(new BouncyCastleProvider());
Bouncycastle 활용 Jar 파일 다운로드 https://www.bouncycastle.org/latest_releases.html bcprov-jdk15on-159.jar 파일을 다운로드하여 현재 프로젝트 폴 더에 저장
Bouncycastle 활용 이클립스에서 외부 JAR 파일 추가하기: 프로젝트폴더->오른쪽마우스->속성(Properties)->Java Build Path->Libraries->Add External JARs->다운로드 받은 jar파일 선 택->OK
인증서 저장 파일 포맷 DER (Distinguished Encoding Rules) 대부분의 브라우저에서 기본 형식이며 ASN.1 DER 형식에 따라 바이너리 형태로 저장됨. ASN.1으로 정의한 인증서 데이터를 바이너리 스트림으로 변환한 것으로 TLV(Type, Length, Value) 형태의 구조를 가짐 파일 확장자: *.crt, *.cer, *.der 를 사용 PEM (Privacy Enhanced Mail) “-----BEGIN CERTIFICATE-----”와 “-----END CERTIFICATE-----” 사이에 Base64로 인코딩된 ASCII 영역의 문자들로만 저장 파일 확장자: *.pem, *.crt, *.cer, *.key -----BEGIN CERTIFICATE----- MIIDOjCCAqOgAwIBAgIQNtMvw8xQuEEQOm0RKtWXsjANBgkqhkiG9w0BAQQFADBM MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg .............................. MREbZZxocDgCDBvw0zg1cVxjlQWN5+sZ8TdqfipqTaIHsdlyGXIeeGvVgjdaXdIA 7rERx21tL4inO0pGk9FpRJvnmR4IAwcmNzG4Oi8tOpM7q5HPqVOCh4ADoZ1aPCDz ppyCZR9e2/8IYgVMyVo= -----END CERTIFICATE-----
인증서 저장 파일 포맷 PKCS#7 (Cryptographic Message Syntax Standard) “-----BEGIN PKCS7----” 과 “-----END PKCS7----”사이에 Base64 인코딩된 데이터를 저장 서명 자료구조와 인증서를 저장 파일 확장자: *.p7b, *.p7c PKCS#12 (Personal Information Exchange Syntax Standard) 바이너리 형식으로 저장되며 pkcs#12 포맷의 파일은 인증서, 개 인키 내용을 파일 하나에 모두 담고 있음. 백업 또는 이동용으로 주로 사용됨. 파일 확장자: *.pfx , *.p12
공인인증서 읽어오기 기존의 발급된 인증서를 읽어오기 예제 공인인증서 이용시 다음 파일을 프로젝트 폴더에 복사 signCert.der 인증서 signPri.key 개인키 예제: CertViewExample.java
예제: CertViewExample.java import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public class CertViewExample { public static void main(String[] args) throws Exception { File certFile = new File("signCert.der"); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); X509Certificate cert = null; InputStream input = new BufferedInputStream(new FileInputStream(certFile)); try { cert = (X509Certificate) certificateFactory.generateCertificate(input); } finally { try { input.close(); } catch(IOException ie) {} } System.out.println(cert); 자신의 공인인증서 signCert.der를 프로젝트 폴더에 복사 후 실행
공인인증서 검증하기 인증서를 검증하기 위해서는 인증기관의 인증서가 필요 인증기관의 인증서는 KISA 에서 다운로드 http://rootca.kisa.or.kr/kor/accredited/accredited03_01List.jsp Kisa rootCA 인증서 Yessign 인증서 내 인증서
인증경로 내 인증서 yessignCA Class 2 KISA RootCA 4 signCert.der yessign.der root-rsa-sha2.der 프로젝트 폴더에 3개 파일을 다운로드하여 저장
공인인증서 검증하기 예제: CertValidateExample.java // 애플리케이션 실행 시 Bouncy Castle Provider를 추가한다. Security.addProvider(new BouncyCastleProvider()); // 인증서 읽어오기 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); File certFile = new File("signCert.der"); X509Certificate cert = generateCertificate(certificateFactory, certFile); File yessginFile = new File("yessign.der"); X509Certificate yessign = generateCertificate(certificateFactory, yessginFile); File trustFile = new File("root-rsa-sha2.der"); X509Certificate trust = generateCertificate(certificateFactory, trustFile); // 인증서 검증을 위한 인증경로 생성 List<X509Certificate> certificates = new ArrayList<X509Certificate>(); certificates.add(cert); // 공인인증서 추가 certificates.add(yessign); // yessign 인증서 추가 CertPath certPath = certificateFactory.generateCertPath(certificates); TrustAnchor anchor = new TrustAnchor(trust, null); // 루트인증서를 TrustAnchor로 등록 PKIXParameters params = new PKIXParameters(Collections.singleton(anchor)); params.setRevocationEnabled(false); // 폐기 정보 비활성화, CRL 검증은 건너뜀 CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); PKIXCertPathValidatorResult result; // 검증결과를 저장
공인인증서 검증하기 검증 결과
인증서 종합 예제 예제: CertificateTest.java 포함하는 기능 인증서 발급 인증서취소목록 (CRL) 이용하기 루트 인증기관 인증서 중간 인증기관 인증서 사용자 Alice의 인증서 인증서취소목록 (CRL) 이용하기 인증서를 파일로 저장, 파일에서 읽어오기 개인키를 파일로 저장, 파일에서 읽어오기 RSA 암호화(공개키), 복호화(개인키) RSA 서명 생성(개인키), 서명 검증(공개키) CRL로 인증서 폐기 여부 검증 인증경로 생성, 검증
3개의 함수 선언 1. RSA 키생성 함수 // 1. RSA 키생성 함수 - KeyPair를 리턴 public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); return kpg.genKeyPair(); } 필요시 키길이를 선택할 수 있도록 수정 가능 // 1. RSA 키생성 함수 - KeyPair를 리턴 public static KeyPair generateRSAKeyPair(int keyLength) throws NoSuchAlgorithmException { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(keylength); return kpg.genKeyPair(); }
3개의 함수 선언 2. 인증서 생성 함수 // 2. 인증서 생성 함수 public static X509Certificate generateCertificate( X500Principal subjectDN, // 1. 주체 PublicKey pubKey, // 2. 주체 공개키 PrivateKey signatureKey, // 3. 발급자의 서명키 X509Certificate caCert, // 4. 발급자 인증서 CertType type) // 5. 인증서 종류 throws CertificateEncodingException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, CertificateParsingException { X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); // 인증서 필드 정보 입력 … // 확장영역 정보 입력 … return certGen.generate(signatureKey,"BC"); // 인증서를 생성하여 결과로 리턴 } 5개의 입력 파라메터 에러 발생시의 예외처리 인증서 객체 생성 발급자의 서명키로 서명하여 인증서 생성
3개의 함수 선언 2. 인증서 생성 함수 // 인증서 필드정보 입력 certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); // 인증서 일련번호를 BigInteger 형식으로 입력. // 편의상 현재시간 정보로부터 설정 (인증기관의 정책에 따름) if(type==CertType.ROOT) // 루트인증서인 경우 발급자와 주체를 똑같이 루트로 설정 certGen.setIssuerDN(subjectDN); else // 일반 사용자 인증서인 경우 발급자는 caCert에 있는 subjectDN을 이용 certGen.setIssuerDN(caCert.getSubjectX500Principal()); certGen.setSubjectDN(subjectDN); // 주체(사용자)의 DN을 설정 GregorianCalendar currentDate = new GregorianCalendar(); // 발급시간은 현재 시간으로 GregorianCalendar expiredDate // 만료시간, 인증서의 유효기간은 2년으로 설정했음 = new GregorianCalendar(currentDate.get(Calendar.YEAR)+2,currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DAY_OF_MONTH)); certGen.setNotBefore(currentDate.getTime()); // 유효기간 시작 설정 certGen.setNotAfter(expiredDate.getTime()); // 유효기간 만료 설정 certGen.setPublicKey(pubKey); // 공개키 설정 certGen.setSignatureAlgorithm("SHA1withRSAEncryption"); // 서명알고리즘 설정
3개의 함수 선언 2. 인증서 생성 함수 // 확장영역 정보 입력 // 루트인증서가 아닌 경우의 확장영역 설정 if(type!=CertType.ROOT){ certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert)); } // 개인인증서가 아닌 경우의 확장영역 설정. 키의 사용용도를 전자서명, 인증서 서명, // CRL 서명의 용도로 사용할 수 있음 if(type!=CertType.ENDENTITY){ certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0)); certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); else // 개인인증서인 경우의 확장영역. 키의 사용용도는 전자서명용, 키암호화용으로 사용 가능 new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment)); return certGen.generate(signatureKey,"BC"); // 인증서를 생성하여 결과로 리턴
3개의 함수 선언 3. CRL(인증서취소목록) 생성 함수 // 3. CRL 생성 함수. CRL은 인증기관이 생성하여 공표 public static X509CRL generateCRL( X509Certificate caCert, // 1. CRL 발급자 인증서 PrivateKey signatureKey, // 2. CRL 발급자 서명키 BigInteger serialNumber) // 3. 폐지할 인증서 일련번호 throws CRLException,NoSuchProviderException,NoSuchAlgorithmException, SignatureException,InvalidKeyException{ X509V2CRLGenerator crlGen = new X509V2CRLGenerator(); // CRL을 위한 객체 생성 crlGen.setIssuerDN(caCert.getSubjectX500Principal()); // CRL의 발급자 설정 - CRL의 발급자는 인증기관임 GregorianCalendar currentDate = new GregorianCalendar(); // 발급시간 GregorianCalendar nextDate // 다음 업데이트 시간 - 1년 1개월? = new GregorianCalendar(currentDate.get(Calendar.YEAR)+1, (currentDate.get(Calendar.MONTH)+1)%12,currentDate.get(Calendar.DAY_OF_MONTH)); crlGen.setThisUpdate(currentDate.getTime()); crlGen.setNextUpdate(nextDate.getTime()); crlGen.setSignatureAlgorithm("SHA1withRSAEncryption"); // 서명알고리즘 설정 if(serialNumber!=null) // 폐지할 인증서의 일련번호를 엔트리에 추가 crlGen.addCRLEntry(serialNumber, currentDate.getTime(), CRLReason.superseded); return crlGen.generate(signatureKey,"BC"); // 서명하여 CRL생성, 출력 }
인증서폐지목록 (CRL)
인증서폐지목록 (CRL) BouncyCastle org.bouncycastle.x509.X509V2CRLGenerator 엔진 이용 X509V2CRLGenerator crlGen = new X509V2CRLGenerator(); crlGen.setIssuerDN(caCert.getSubjectX500Principal()); GregorianCalendar currentDate = new GregorianCalendar(); GregorianCalendar nextDate = new GregorianCalendar(currentDate.get(Calendar.YEAR)+1, (currentDate.get(Calendar.MONTH)+1)%12, currentDate.get(Calendar.DAY_OF_MONTH)); crlGen.setThisUpdate(currentDate.getTime()); crlGen.setNextUpdate(nextDate.getTime()); crlGen.setSignatureAlgorithm("SHA1withRSAEncryption"); crlGen.addCRLEntry(revokeCert.getSerialNumber(), currentDate.getTime(), CRLReason.superseded); X509CRL crl = crlGen.generate(signatureKey,"BC");
인증서폐지목록 (CRL) 인증서 폐지 사유
1. 키생성 및 인증서 발급 KeyPair rootKeyPair = generateRSAKeyPair(); // 루트인증기관 키생성 및 인증서 발급 X509Certificate rootCert = generateCertificate( new X500Principal("C=KR,CN=ROOT"), rootKeyPair.getPublic(), rootKeyPair.getPrivate(), null, CertType.ROOT); System.out.println("- 루트인증기관 인증서 "); //System.out.println(rootCert); KeyPair interKeyPair = generateRSAKeyPair(); // 중간인증기관의 키생성 및 인증서 발급 X509Certificate interCert = generateCertificate( new X500Principal("C=KR,CN=INTER"), interKeyPair.getPublic(), rootKeyPair.getPrivate(), rootCert, CertType.INTER); System.out.println("- 중간인증기관 인증서 "); //System.out.println(interCert); KeyPair aliceKeyPair = generateRSAKeyPair(); // 사용자 Alice의 키생성 및 인증서 발급 X509Certificate aliceCert = generateCertificate( new X500Principal("C=KR,CN=Alice"), aliceKeyPair.getPublic(), interKeyPair.getPrivate(), interCert, CertType.ENDENTITY); System.out.println("- 사용자 Alice의 인증서 "); //System.out.println(aliceCert); System.out.println("Alice의 인증서의 일련번호: "+aliceCert.getSerialNumber()); KeyPair bobKeyPair = generateRSAKeyPair(); // 사용자 Bob의 키생성 및 인증서 발급 X509Certificate bobCert = generateCertificate( new X500Principal("C=KR,CN=Bob"), bobKeyPair.getPublic(), System.out.println("- 사용자 Bob의 인증서 "); //System.out.println(bobCert);
1. 키생성 및 인증서 발급 인증서의 유효성 검증 (서명검증) 인증서의 유효기간 검증 인증서의 사용 용도 확인 void verify(PublicKey key) 문제가 있으면 각종 예외 발생 인증서의 유효기간 검증 void checkValidity() 인증서의 사용 용도 확인 인증서의 폐지 여부 확인 (CRL 검증) // 1.1 인증서의 유효성 검증 (서명 검증) System.out.println("1.1 인증서의 유효성 검증 (서명검증) : 에러메시지가 나타나지 않으면 유효한 것임"); rootCert.verify(rootCert.getPublicKey()); // 루트인증기관의 인증서 유효성 검증, 루트인증기관의 공개키 이용 interCert.verify(rootCert.getPublicKey()); // 중간인증기관의 인증서 유효성 검증, 루트인증기관의 공개키 이용 aliceCert.verify(interCert.getPublicKey()); // 사용자의 인증서 유효성 검증, 중간인증기관의 공개키 이용 bobCert.verify(interCert.getPublicKey()); // 사용자의 인증서 유효성 검증, 중간인증기관의 공개키 이용 // 1.2 인증서의 유효성 검증 (유효기간 검증) System.out.println("1.2 인증서의 유효성 검증 (유효기간 검증) : 에러메시지가 나타나지 않으면 유효한 것임"); try{ rootCert.checkValidity(new Date()); // 현재시간과 유효기간의 비교 interCert.checkValidity(new Date()); // 현재시간과 유효기간의 비교 aliceCert.checkValidity(new Date()); // 현재시간과 유효기간의 비교 bobCert.checkValidity(new Date()); // 현재시간과 유효기간의 비교 }
2. 인증서취소목록(CRL) 생성 및 검증 CRL은 인증기관이 서명하여 생성 유효성 검증시 생성한 인증기관의 공개키 이용 에러메시지가 나타나지 않으면 유효한 것임 // 2. 인증서취소목록(CRL) 생성 // 루트인증기관의 CRL 생성 X509CRL rootCRL = generateCRL(rootCert,rootKeyPair.getPrivate(),null); // 중간인증기관의 CRL 생성 - 취소된 인증서가 없는 경우 X509CRL interCRL = generateCRL(interCert,interKeyPair.getPrivate(),null); // 중간인증기관의 CRL 생성 - Alice의 인증서를 취소시키는 경우 // X509CRL interCRL = generateCRL(interCert,interKeyPair.getPrivate(),aliceCert.getSerialNumber()); // 2.1 CRL의 유효성 검증 System.out.println("2.1 CRL의 유효성 검증 : 에러메시지가 나타나지 않으면 유효한 것임"); rootCRL.verify(rootCert.getPublicKey()); interCRL.verify(interCert.getPublicKey());
3. 인증서 파일 저장, 읽어오기 인증서를 파일로 저장 인증서를 파일에서 읽어오기 인증서 객체를 바이너리 인코딩하여 *.der 파일로 저장 인증서를 파일에서 읽어오기 CertificateFactory를 이용하여 인증서 형식으로 읽기 // 3. 인증서의 파일 처리 // 3.1 Alice의 인증서를 파일로 저장 FileOutputStream fos = new FileOutputStream(new File("aliceCert.der")); fos.write(aliceCert.getEncoded()); // 파일로 저장 fos.close(); // 3.2 Alice의 인증서를 파일에서 읽어오기 CertificateFactory cf = CertificateFactory.getInstance("X.509"); FileInputStream fis = new FileInputStream(new File("aliceCert.der")); X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); fis.close();
4. 개인키 파일저장, 읽어오기 개인키 파일저장 java.security.KeyStore 엔진 사용 PKCS#8 규격 이용 키스토어에 저장시 인증체인 정보 필요 java.security.KeyStore 엔진 사용 KeyStore는 패스워드를 이용하여 저장할 키를 보호함 개인키를 저장할 경우에는 인증경로를 제공해야 함 인증경로 배열은 계층구조 트리에서 아래부터 위쪽으로 만듬 개인키를 식별하기 위한 정보 Alias 정보 이용 “AlicePrivateKeyAlias”
4. 개인키 파일저장, 읽어오기 // 4.1 개인키를 파일에 저장하기 String secretkey="SuperSecretKey"; // 개인키 암호화 저장을 위한 비밀키 char[] code = secretkey.toCharArray(); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // 키스토어라는 형태로 저장하게 됨 ks.load(null,null); // 키스토어 초기화 // 키스토어에 저장시 인증체인 정보 필요. 루트로부터 사용자까지의 인증서 정보 X509Certificate[] chain = new X509Certificate[3]; chain[0] = aliceCert; // 사용자 인증서 chain[1] = interCert; // 중간인증기관 인증서 (중간인증기관이 Alice에게 인증서를 발급) chain[2] = rootCert; // 루트인증기관 인증서 (루트인증기관이 중간인증기관에게 인증서를 발급) ks.setKeyEntry("AlicePrivateKeyAlias",aliceKeyPair.getPrivate(),code,chain); // 필요한 정보를 키스토어에 암호화하여 저장 fos = new FileOutputStream(new File("alicePriv.key")); ks.store(fos,code); // 키스토어의 내용을 code로 암호화하여 파일로 저장 fos.close(); // 4.2 개인키를 파일에서 읽어오기 // 개인키를 읽어오기 위해서는 복호화를 위해 키 코드가 필요 System.out.println("* 4.2 개인키를 파일에서 읽어오기 "); fis = new FileInputStream(new File("alicePriv.key")); ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(fis,code); // 파일에서 읽어와서 키스토어에 로드 fis.close(); PrivateKey alicePrivateKey = (PrivateKey)ks.getKey("AlicePrivateKeyAlias",code); // 키스토어에서 개인키를 code 필요 System.out.println(" - Alice 개인키 : 파일에서 읽어온 것 "); System.out.println(alicePrivateKey); System.out.println(ByteUtils.toHexString(alicePrivateKey.getEncoded())); System.out.println();
5. RSA 암호화, 복호화 수신자 Alice (복호화) <---------------------- 송신자 Bob (암호화) // 5. RSA 암호화 /복호화 (송신자 Bob이 수신자 Alice에게 암호문 전송) // 5.1 RSA 암호화 - 인증서에 저장된 공개키 이용 System.out.println(" 5.1 Bob은 Alice의 인증서에서 읽어온 공개키로 RSA 암호화"); String plaintext = "Hello world!"; System.out.println(" 평문 : "+plaintext); byte[] t0 = plaintext.getBytes(); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey()); byte[] b0 = cipher.doFinal(t0); System.out.println("암호문 : " + ByteUtils.toHexString(b0)); // 5.2 RSA 복호화 - 개인키 파일에서 읽어온 개인키 이용 System.out.println(" 5.2 Alice는 자신의 개인키 파일에서 읽어온 개인키로 RSA 복호화"); cipher.init(Cipher.DECRYPT_MODE, alicePrivateKey); byte[] b1 = cipher.doFinal(b0); System.out.println(" 복호화된 평문 : "+ new String(b1)); System.out.println();
5. RSA 암호화, 복호화 * 5. RSA 암호화 / 복호화 (송신자 Bob이 수신자 Alice에게 암호화된 메시지 전송) 5.1 Bob은 Alice의 인증서에서 읽어온 공개키로 RSA 암호화 평문 : Hello world! 암호문 : 29bbc4aa48023f000af0d7e38f16629e8cf203e5c5c45828d8cda7d4e05440c9f1c645336412a5dda8a0c95cea71e2d51c9979ef90bf532a1a54b60d54f2a521def67dc5e106f80802fb71015e0c5f75df479f1fab2c1ef4f723934bde1e12c594c49beaebf13a18a0bb2e856f5e4b4af0771cb0487374b8619b1a9bca7c1b38 5.2 Alice는 자신의 개인키 파일에서 읽어온 개인키로 RSA 복호화 복호화된 평문 : Hello world!
6. RSA 서명, 검증 송신자 Alice (서명) <---------------------- 수신자 Bob (검증) System.out.println("* 6. RSA 서명 / 검증 (Alice가 Bob에게 서명된 메시지 전송 )"); // 6.1 RSA 서명 (Alice의 개인키 이용) System.out.println(" 6.1 RSA 서명 (Alice의 개인키로 서명)"); String sigData="전자서명 테스트"; byte[] data = sigData.getBytes("UTF8"); System.out.println(" Plaintext : "+sigData); Signature sig = Signature.getInstance("MD5WithRSA"); fis = new FileInputStream(new File("alicePriv.key")); ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(fis,code); // 파일에서 읽어와서 키스토어에 로드 fis.close(); PrivateKey alicePrivateKey1 = (PrivateKey)ks.getKey("AlicePrivateKeyAlias",code); sig.initSign(alicePrivateKey1); sig.update(data); byte[] signatureBytes = sig.sign(); System.out.println(" 서명문 : " + ByteUtils.toHexString(signatureBytes)); // 6.2 RSA 서명 검증 (Alice의 인증서에 있는 공개키 이용) System.out.println(" 6.2 RSA 서명검증 (Alice의 공개키로 서명검증)"); CertificateFactory cf1 = CertificateFactory.getInstance("X.509"); FileInputStream fis1 = new FileInputStream(new File("aliceCert.der")); X509Certificate cert1 = (X509Certificate)cf1.generateCertificate(fis1); // 파일에서 읽어서 인증서 형식으로 할당 fis1.close(); sig.initVerify(cert1.getPublicKey()); System.out.println(" Verification: "+sig.verify(signatureBytes)); // 서명결과 출력 System.out.println();
6. RSA 서명, 검증 * 6. RSA 서명 / 검증 (Alice가 Bob에게 서명된 메시지 전송 ) Plaintext : 전자서명 테스트 서명문 : 69ab63e8435f1384f5bb84d8fe41938e7f1f269f5726cf10c46d12879c02f396e4a5984485e4cb59961d60502c56f099be388b2d7eb3148630d9421e7f9f02edc3a92fb3fe9def57412d476e306572f0f8f6ca817466caef85935547ff8e83357f301b89238c042cdcad045c03548764014e29b15d51c3532b42c12bed268b82 6.2 RSA 서명검증 (Alice의 공개키로 서명검증) Verification: true
7. 인증서 유효성 검사 인증서 유효성(폐기 여부) 검사 CRL 검증 * 7. 인증서 폐지 여부 검사 // 7. 인증서 폐기 여부 검사 System.out.println("* 7. 인증서 폐지 여부 검사 "); X509CRLEntry entry = interCRL.getRevokedCertificate(bobCert.getSerialNumber()); // 지정된 인증서의 serialNumber를 가지는 CRL 엔트리를 취득 (존재하는 경우) if(entry!=null){ System.out.printf("폐지된 인증서 번호: %d%n", entry.getSerialNumber()); if(entry.getCertificateIssuer()==null) System.out.printf("발급자: %s%n", interCRL.getIssuerX500Principal()); else System.out.printf("발급자: %s%n", entry.getCertificateIssuer()); } System.out.println(); * 7. 인증서 폐지 여부 검사 폐지된 인증서 번호: 1528175571035 발급자: C=KR, CN=INTER
8. CRL의 파일 저장, 파일에서 읽어오기 // 8.1 CRL 파일 저장 System.out.println(" 8.1 CRL 파일 저장 "); fos = new FileOutputStream(new File("inter.crl")); fos.write(interCRL.getEncoded()); fos.close(); // 8.2 CRL 파일에서 읽어오기 System.out.println(" 8.2 CRL 파일에서 읽어오기 "); cf = CertificateFactory.getInstance("X.509"); fis = new FileInputStream(new File("inter.crl")); X509CRL newcrl = (X509CRL)cf.generateCRL(fis); fis.close(); entry = newcrl.getRevokedCertificate(bobCert.getSerialNumber()); System.out.println("* CRL : 저장 후 읽어온 것 "); if(entry!=null){ System.out.printf("폐기된 인증서 번호: %d%n", entry.getSerialNumber()); if(entry.getCertificateIssuer()==null) System.out.printf("발급자: %s%n", newcrl.getIssuerX500Principal()); else System.out.printf("발급자: %s%n", entry.getCertificateIssuer()); } System.out.println();
8. CRL의 파일 저장, 파일에서 읽어오기 인증서 폐기 여부 확인 getRevokedCertificate() 메소드를 호출하여 이 값이 null이면 해당 인증서는 폐기 되지 않았다는 것을 의미 폐기된 경우 getCertificateIssuer() 메소드를 통해 폐지된 인증서의 발급자 정보 를 획득할 수 있음. 이 때 이 값이 null이면 CRL 발급자가 인증서의 발급자라는 것을 의미. X509Entry entry = crl.getRevokedCertificate(bobCert.getSerialNumber()); if(entry!=null){ System.out.printf("인증서번호: %d%n", entry.getSerialNumber()); if(entry.getCertificateIssuer()==null) System.out.printf("발급자: %s%n", crl.getIssuerX500Principal()); else System.out.printf("발급자: %s%n", entry.getCertificateIssuer()); }
9. 인증서 디렉토리 인증서 디렉토리 생성 java.security.cert.CertStore를 이용 System.out.println(" 9. 인증서 디렉토리 생성 "); List<X509Extension> list = new ArrayList<X509Extension>(); list.add(rootCert); list.add(interCert); list.add(aliceCert); list.add(bobCert); list.add(rootCRL); list.add(interCRL); //System.out.println(list);
10. 인증 경로 생성 및 검증 인증경로 생성 (java.security.cert.CertPath 이용) 인증경로 검증 (java.security.CertPathValidator 이용) // 10. 인증 경로 생성 및 검증 System.out.println(" 10. 인증 경로 생성 및 확인 "); cf = CertificateFactory.getInstance("X.509"); // 인증 경로 생성 List<Certificate> certChain = new ArrayList<Certificate>(); certChain.add(bobCert); certChain.add(interCert); CertPath certPath = cf.generateCertPath(certChain); // 루트인증서를 TrustAnchor로 지정 Set<TrustAnchor> trust = Collections.singleton(new TrustAnchor(rootCert,null)); // CertPathValidator 객체 생성 CertPathValidator validator = CertPathValidator.getInstance("PKIX","BC"); // PKIXParameter 생성 PKIXParameters param = new PKIXParameters(trust); param.addCertStore(store); param.setDate(new Date()); try{ PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath,param); System.out.println(result); // 인증경로 검증에 성공한 경우 } catch(CertPathValidatorException e){ // 인증경로 검증에 실패한 경우 인증경로와 검증실패 사유 표시 System.out.println("* 인증 경로"); System.out.println(e.getCertPath()); System.out.println("* 검증 실패 사유"); System.out.println("validation failed "+e.getIndex()+" detail: "+e.getMessage());
10. 인증 경로 생성 및 검증 인증서가 유효한 경우 Alice의 인증서가 CRL에 포함되지 않은 경우
10. 인증 경로 생성 및 검증 인증서가 유효하지 않은 경우 Alice의 인증서가 CRL에 포함된 경우
실습과제 #4. 인터넷 지불 서비스 설계 인터넷 지불(페이먼트) 서비스 설계 예상 기능 지금까지 배운 암호 기술을 적극 활용하여 강화된 보안성을 제공 할 수 있는 인터넷 지불 서비스를 설계하시오. 인터넷 지불 서비스에 필요한 기능들과 각 기능의 보안요구사항 을 분석하고 이를 구현하기 위한 상세 기능을 설계하시오. 암호를 이용하는 기능들의 동작을 시뮬레이션으로 점검하시오. 예상 기능 사용자 등록, 사용자 인증(로그인) 계좌 개설, 입금, 출금, 계좌정보 확인 타인에게 지불 신용거래 휴대폰을 이용한 모바일 페이먼트 등등