Self-Signed Certificate
openssl에서 인증서를 만드는 기본적인 방법은
- key -> csr -> crt 로 만드는 것이 일반적입니다.
- openssl 명령으로는 openssl genrsa -> openssl req -> openssl x509 입니다.
- crt의 포맷은 바이너리 crt, 읽을 수 있는 pem, 또다른 포맷인 der 3가지가 있습니다.
기본적인 방법으로 만들어 보면 다음과 같습니다.
openssl genrsa -out private.key 2048
openssl req -new -key private.key -out server.csr
openssl x509 -req -in server.csr -signkey private.key -out server.pem -outform PEM
단축버전으로는 다음과 같음 명령어가 있습니다.
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
csr 정보
csr안에는 key정보 이외에 Subject라는 정보가 함께 들어갑니다.
csr 만들 때, 직접 입력하려면 다음과 같이 -subj
옵션을 함께 사용합니다.
openssl req -new -key private.key -out server.csr -config openssl.cnf -subj "/C=US/ST=California/L=San Francisco/O=My Company, Inc./CN=*.*.tkim.info/"
Subject 항목에는 다음과 같은 내용이 들어갑니다.
String X.500 AttributeType
------------------------------
CN commonName
L localityName
ST stateOrProvinceName
O organizationName
OU organizationalUnitName
C countryName
STREET streetAddress
DC domainComponent
UID userid
내용은 RFC2253 LDAP Distinguished Names 에 정의되어 있습니다. 정의에 따라서 복수개의 Common Name을 설정할 수 있습니다.
복수개를 사용하는 경우는 the Subject Alternative Name (SAN) Certificate 라고 부릅니다.
Subject의 예는 다음과 같습니다.
- “CN=Patti Fuller,OU=UserAccounts,DC=corp,DC=contoso,DC=com”
- “CN=Patti Fuller”
- “E=patti.fuller@contoso.com,CN=Patti Fuller”
what is subject in certificate?
The subject field identifies the entity associated with the public key stored in the subject public key field. The subject name MAY be carried in the subject field and/or the subjectAltName extension.
Subject (Distinguished Name)
“CN=yourname” or “O=yourorganization”.”
“CN=Mark Sutton, OU=Developers, O=Mycompany C=UK”
“CN=Patti Fuller,OU=UserAccounts,DC=corp,DC=contoso,DC=com”
“UID=12345,N=Kurt Zeilenga,OU=Engineering,L=Redwood Shores”
openssl help
openssl genrsa
비밀키(private key)를 생성하는 방법
openssl genrsa -out private.key 2048
실행결과는 다음과 같습니다.
root on goorm in ~
❯ openssl genrsa -out private.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
....................................................................+++++
................+++++
e is 65537 (0x010001)
확인
file private.key
root on goorm in ~
❯ file private.key
private.key: PEM RSA private key
다른 사람은 접근하지 못하게 권한 변경
chmod 400 private.key
비밀키(private key)로 공개키(public key)만들기
openssl rsa -in private.key -pubout -out public.key
root on goorm in ~
❯ openssl rsa -in private.key -pubout -out public.key
writing RSA key
비밀키를 암호를 넣어서 생성하는 방법
openssl genrsa -out private.key -aes256 2048
root on goorm in ~
❯ openssl genrsa -out private.key -aes256 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
........................+++++
.........................+++++
e is 65537 (0x010001)
Enter pass phrase for private.key:
Verifying - Enter pass phrase for private.key:
openssl s_client
TLS 서버에 접속해 보기
openssl s_client -connect gmo.jp:443
❯ openssl s_client -connect gmo.jp:443
CONNECTED(00000005)
depth=2 OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
verify return:1
depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign Extended Validation CA - SHA256 - G3
verify return:1
depth=0 businessCategory = Private Organization, serialNumber = 0110-01-029526, jurisdictionC = JP, C = JP, ST = Tokyo, L = Shibuya-ku, street = "26-1,Sakuragaoka-cho", OU = Business Division, O = "GMO internet,Inc.", CN = www.gmo.jp
verify return:1
---
Certificate chain
0 s:businessCategory = Private Organization, serialNumber = 0110-01-029526, jurisdictionC = JP, C = JP, ST = Tokyo, L = Shibuya-ku, street = "26-1,Sakuragaoka-cho", OU = Business Division, O = "GMO internet,Inc.", CN = www.gmo.jp
i:C = BE, O = GlobalSign nv-sa, CN = GlobalSign Extended Validation CA - SHA256 - G3
1 s:C = BE, O = GlobalSign nv-sa, CN = GlobalSign Extended Validation CA - SHA256 - G3
i:OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
실행결과만 간략하게 보기
openssl s_client -connect gmo.jp:443 -brief
❯ openssl s_client -connect gmo.jp:443 -brief
CONNECTION ESTABLISHED
Protocol version: TLSv1.2
Ciphersuite: ECDHE-RSA-AES256-GCM-SHA384
Peer certificate: businessCategory = Private Organization, serialNumber = 0110-01-029526, jurisdictionC = JP, C = JP, ST = Tokyo, L =
Shibuya-ku, street = "26-1,Sakuragaoka-cho", OU = Business Division, O = "GMO internet,Inc.", CN = www.gmo.jp
Hash used: SHA256
Signature type: RSA
Verification: OK
Supported Elliptic Curve Point Formats: uncompressed
Server Temp Key: ECDH, P-256, 256 bits
tls 버전을 지정해서 접속해보기
openssl s_client -connect gmo.jp:443 -tls1 -brief # NG
openssl s_client -connect gmo.jp:443 -tls1_1 -brief # NG
openssl s_client -connect gmo.jp:443 -tls1_2 -brief # OK
openssl s_client -connect www.example.com:443 -tls1 -brief # OK
openssl s_client -connect www.example.com:443 -tls1_1 -brief # OK
인증서 체인을 보기
root CA 에 도달하기까지의 인증서 체인을 살펴봅니다.
openssl s_client -connect www.example.com:443 -showcerts < /dev/null
root on goorm in ~ took 5s
❯ openssl s_client -connect www.example.com:443 -quiet < /dev/null
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, OU = Technology, CN = www.example.org
verify return:1
인증서 체인을 간략하게 봅니다.
openssl s_client -connect www.example.com:443 -quiet
TLS 메시지를 표시합니다.
TLS 서버와 클라이언트가 주고 받는 메시지를 표시합니다.
openssl s_client -connect www.example.com:443 -msg
openssl s_client -connect www.example.com:443 -msg |grep -e “»>” -e “«<”
root on goorm in ~ took 1m
❯ openssl s_client -connect www.example.com:443 -msg |grep -e ">>>" -e "<<<"
>>> ??? [length 0005]
>>> TLS 1.3, Handshake [length 0138], ClientHello
<<< ??? [length 0005]
<<< TLS 1.3, Handshake [length 0058], ServerHello
>>> ??? [length 0005]
>>> TLS 1.3, ChangeCipherSpec [length 0001]
>>> ??? [length 0005]
>>> TLS 1.3, Handshake [length 0159], ClientHello
<<< ??? [length 0005]
<<< ??? [length 0005]
<<< TLS 1.3, Handshake [length 009b], ServerHello
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 0006], EncryptedExtensions
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 0fa6], Certificate
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, OU = Technology, CN = www.example.org
verify return:1
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 0108], CertificateVerify
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 0034], Finished
>>> ??? [length 0005]
>>> TLS 1.3 [length 0001]
>>> TLS 1.3, Handshake [length 0034], Finished
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 00d9], NewSessionTicket
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Handshake [length 00d9], NewSessionTicket
<<< ??? [length 0005]
<<< TLS 1.3 [length 0001]
<<< TLS 1.3, Alert [length 0002], warning close_notify
>>> ??? [length 0005]
>>> TLS 1.3 [length 0001]
>>> TLS 1.3, Alert [length 0002], warning close_notify
root on goorm in ~ took 1m1s
❯
증명서를 파일로 저장하기
openssl s_client -connect www.example.com:443 -showcerts < /dev/null 2>/dev/null| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'> example.pem
openssl s_server 커맨드
사전작업(비밀키, 서버인증서 작성)
필요한 사전작업은 다음의 파일들을 준비하는 것입니다. 다시 한 번, 절차는 key -> csr -> crt 순입니다.
- private.key:비밀키
- server.csr:인증서요구 Distinguished Name 정보가 들어 있습니다.
- server.crt:인증서
(1) private.key
openssl genrsa -out private.key 2048
(2) server.csr
# openssl req -new -key private.key -out server.csr
# openssl req -new -key private.key -out server.csr -subj "/C=JP/ST=Tokyo/L=Setagaya/O=My Company, Inc./CN=*.*.tkim.info/"
openssl req -new -key private.key -out server.csr -subj "/CN=KUBERNETES-CA/DC=TKIM/DC=INFO"
만일 Can’t load /home/ubuntu/.rnd into RNG 의 에러가 난다면, /etc/ssl/openssl.cnf 의 이하의 라인을 삭제하면 됩니다. openssl의 버전에 따라 발생하는 경우가 있습니다.
vim /etc/ssl/openssl.cnf
# RANDFILE = $ENV::HOME/.rnd
(3) server.crt
openssl x509 -req -in server.csr -signkey private.key -out server.crt
윈도우즈에서는 openssl의 상태에 따라서 정상작동하지 않을 수도 있습니다.
root on goorm in ~
❯ ls server.crt private.key
private.key server.crt
TSL 서버를 기동합니다.
root on goorm in ~
❯ openssl s_server -cert server.crt -key private.key
Using default temp DH parameters
ACCEPT
다른 터미널에서 작동하는 지 확인해 봅니다.
root on goorm in ~
❯ lsof -i:4433 -P
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
openssl 786 root 5u IPv6 6158796 0t0 TCP *:4433 (LISTEN)
클라이언트로 접속해봅니다. 커맨드는 openssl s_client -connect localhost:4433
root on goorm in ~
❯ openssl s_client -connect localhost:4433
CONNECTED(00000005)
depth=0 CN = KUBERNETES-CA, DC = TKIM, DC = INFO
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = KUBERNETES-CA, DC = TKIM, DC = INFO
verify return:1
---
Certificate chain
0 s:CN = KUBERNETES-CA, DC = TKIM, DC = INFO
i:CN = KUBERNETES-CA, DC = TKIM, DC = INFO
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDDzCCAfcCFFhHUO7ZrAswd5RPHPxL1liMjxBZMA0GCSqGSIb3DQEBCwUAMEQx
FjAUBgNVBAMMDUtVQkVSTkVURVMtQ0ExFDASBgoJkiaJk/IsZAEZFgRUS0lNMRQw
EgYKCZImiZPyLGQBGRYESU5GTzAeFw0yMDA5MjcwNTQyMzhaFw0yMDEwMjcwNTQy
MzhaMEQxFjAUBgNVBAMMDUtVQkVSTkVURVMtQ0ExFDASBgoJkiaJk/IsZAEZFgRU
S0lNMRQwEgYKCZImiZPyLGQBGRYESU5GTzCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBALK7+tV5yqfOHhjIzF1x2MX9P4vKFF+rFUiT3AfB+1Erztn4u9sH
잘 접속이 됩니다. 기본포트가 4433 이므로 443 포트로 TSL서버를 실행해 봅니다.
openssl s_server -accept 443 -cert server.crt -key private.key
www 서버로 작동시켜 봅니다.
echo "hello world" > index.html
firewall-cmd --add-port=443/tcp
openssl s_server -accept 443 -cert server.crt -key private.key -WWW
서버에 접속해 봅니다.
curl -k https://localhost:443/index.html
서버 인증서의 정보를 보기
먼저 인증서를 PEM으로 저장합니다.
openssl s_client -connect gmo.jp:443 -showcerts < /dev/null 2>/dev/null| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'> gmo.pem
저장한 pem 정보를 텍스트로 출력합니다.
openssl x509 -in gmo.pem -noout -text
결과는 다음과 같습니다.
root on goorm in ~
❯ openssl x509 -in gmo.pem -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
28🆎b8:56:bc:8a:ca:dc:4a:72:52:c6
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = BE, O = GlobalSign nv-sa, CN = GlobalSign Extended Validation CA - SHA256 - G3
Validity
Not Before: Nov 11 06:41:07 2019 GMT
Not After : Feb 3 07:21:02 2021 GMT
Subject: businessCategory = Private Organization, serialNumber = 0110-01-029526, jurisdictionC = JP, C = JP, ST = Tokyo, L = Shibuya-ku, street = "26-1,Sakuragaoka-cho", OU = Business Division, O = "GMO internet,Inc.", CN = www.gmo.jp
Subject Public Key Info:
...
openssl x509
PEM에서 Subject만 확인하기
openssl x509 -in example.pem -noout -subject
PEM에서 시리얼번호만 확인하기
openssl x509 -in example.pem -noout -serial
PEM에서 중간 CA만만 확인하기
openssl x509 -in example.pem -noout -issuer
인증서에서 공개키를 추출하기
openssl x509 -in example.pem -noout -pubkey
PEM형식 인증서 만들기 (-outform PEM)
보통은 key -> csr -> crt 인데, key -> csr -> pem 을 합니다.
openssl genrsa -out private.key 2048
openssl req -new -key private.key -out server.csr
openssl x509 -req -in server.csr -signkey private.key -out server.pem -outform PEM
ls server.pem
file server.pem
openssl x509 -req -in server.csr -signkey private.key -out server.crt
마찬가지로 DER형식으로도 만들 수 있습니다.(-outform DER)
openssl x509 -req -in server.csr -signkey private.key -out server.der -outform DER
ls server.der
file server.der
DER형식에서 PEM형식으로도 만들 수 있습니다.(-inform,-outform)
ls server.der
openssl x509 -in server.der -inform DER -out server.pem -outform PEM
ls server.pem
openssl ciphers
사용할 수 있는 암호스위트를 확인합니다.
openssl ciphers -v
root on goorm in ~
❯ openssl ciphers -v
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
...
openssl dgst
다이제스트를 계산합니다.
fallocate -l 1K 1K.txt
ls -l 1K.txt
openssl dgst -sha512 1K.txt
openssl dgst -rsa1 1K.txt
root on goorm in ~
❯ fallocate -l 1K 1K.txt
root on goorm in ~
❯ ls -l 1K.txt
-rw-rw-r-- 1 root root 1024 Sep 27 09:40 1K.txt
root on goorm in ~
❯ openssl dgst -sha512 1K.txt
SHA512(1K.txt)= 8efb4f73c5655351c444eb109230c556d39e2c7624e9c11abc9e3fb4b9b9254218cc5085b454a9698d085cfa92198491f07a723be4574adc70617b73eb0b6461
echo “1234567890” > test.txt
openssl genrsa -out priv.key 2048
openssl rsa -in priv.key -pubout -out pub.key
openssl rsautl -encrypt -pubin -inkey pub.key -in test.txt -out test.txt.enc
rm test.txt
openssl rsautl -decrypt -inkey priv.key -in test.txt.enc -out test.txt
cat test.txt
openssl s_server
커맨드와 openssl s_client
커맨드는 연결이 된 후에는 입력을 기다리는데, 이 상태에서 문자열을 전달하는 것이 가능합니다.
key, csr, crt가 일치하는 지 확인하는 방법
openssl rsa -noout -modulus -in private.key |openssl md5
openssl req -noout -modulus -in server.csr |openssl md5
openssl x509 -noout -modulus -in server.crt |openssl md5
root on goorm in ~
❯ openssl rsa -noout -modulus -in private.key |openssl md5
(stdin)= c462527182d8d396e31365d36bc54aa8
root on goorm in ~
❯ openssl req -noout -modulus -in server.csr |openssl md5
(stdin)= c462527182d8d396e31365d36bc54aa8
root on goorm in ~
❯ openssl x509 -noout -modulus -in server.crt |openssl md5
(stdin)= c462527182d8d396e31365d36bc54aa8
openssl req -new
-key “$PRIVATE_KEY”
-sha256
-config “$OPTIONS_FILE”
-subj “/C=US/ST=California/L=San Francisco/O=My Company, Inc./CN=*.*.$DOMAIN/”
-out “$CSR_FILENAME”
openssl.cnf path
openssl.cnf는 어디에 있지?
/usr/lib/ssl/openssl.cnf
❯ find / -name openssl.cnf
/usr/lib/ssl/openssl.cnf
/etc/ssl/openssl.cnf
root on goorm in ~
❯ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
아 이렇게 보는거야?
/usr/bin/openssl version -a | grep OPENSSLDIR
윈도우즈라면
C:/Strawberry/c/ssl/openssl.cnf
C:\Strawberry\c\bin\openssl.EXE
C:\temp>openssl version -a
OpenSSL 1.1.1d 10 Sep 2019
built on: Fri Feb 7 14:26:55 2020 UTC
platform: mingw64
options: bn(64,64) rc4(16x,int) des(long) idea(int) blowfish(ptr)
compiler: gcc -m64 -Wall -O3 -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DUNICODE -D_UNICODE -DWIN32_LEAN_AND_MEAN -D_MT -DZLIB -DNDEBUG -I/z/extlib/_2020Q1-small__/include -D__MINGW_USE_VC2005_COMPAT -DOPENSSLBIN="\"/z/extlib/_2020Q1-small__/bin\""
OPENSSLDIR: "Z:/extlib/_2020Q1-small__/ssl"
ENGINESDIR: "Z:/extlib/_2020Q1-small__/lib/engines-1_1"
Seeding source: os-specific
마치며
이상으로 openssl로도 인증서를 이리저리 다루어 보았습니다. 감사합니다.