본문 바로가기
자습

node-forge를 이용한 RSA 암호화, CSR 생성

by litaro 2021. 1. 16.

SSL/TLS

인터넷을 통해 데이터를 주고 받기 위해서는 그 기반이 되는 SSL/TLS 보안 프로토콜에 맞게 데이터를 주고 받아야한다. 

SSL/TLS 를 보통 같이 쓰고 있는데 역사적으로 보면 SSL은 deprecated 되었고 TLS를 사용하는데 보통 SSL이 사람들에게 익숙해서 같은 의미로 SSL 과 TLS 가 사용된다고 한다.

www.globalsign.com/en/blog/ssl-vs-tls-difference

 

SSL vs TLS - What's the Difference?

What's the difference between SSL and TLS? And how do you know which one is right for you? Everything is explained in this blog.

www.globalsign.com

그리고 SSL/TLS 프로토콜을 사용할수 있는 Opensource toolkit을 OpenSSL에서 제공한다.

OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols.

www.openssl.org/

 

/index.html

OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. It is also a general-purpose cryptography library. For more information about the team and community around th

www.openssl.org

 

SSL/TLS 통신을 위한 준비

서버와 클라이언트간에 SSL/TLS 통신을 하기 위해서는 기본적으로 아래 2가지가 필요하다.

  • 클라이어트와 서버간 약속한 알고리즘으로 정보를 암호화하여 주고 받기
  • 인증된 3rd party CA (Certificate Authority) 로 부터 인증서 발급받기

인증서가 궁금하면 브라우저 주소창의 자물쇠 아이콘을 클릭해보자~ Tistory의 경우 아래와 같다.

DigiCert CA로 부터 인증서를 발급받아서 사용하고 있는것을 알수 있다. 그리고 서버 인증서는 아래와 같은 chain 구조안에서 발급된다.

https://www.thesslstore.com/blog/what-is-a-certificate-authority-ca-and-what-do-they-do/#what-is-a-certificate-authority-ca

Root certificates는 Self-signed signed certificate으로 CA가 당연히 소량의 인증서만 발급하고 이 인증서의 유효기간은 확장될수 있다. 이 인증서는 각 Browser와 OS에서 이미 공유되어 pre-installed 상태이다.

일반적으로 Root certificate로 직접 SSL certificate를 발급하지 않고 Interfediate certificates를 여러개 발급하고 이것으로 Server certificate를 발급한다. 그리고 이 Server certificate는 약 1년의 유효기간을 갖게 된다. (chrome이 예전에는 2년의 유효기간 정책을 사용했는데 Safari의 1년 정책으로 변경했다는 뉴스가 있다. 이게 중요한 것인지... 초보자인 나에게는 해석불가 ㅠㅠ)

아래는 규모가 큰 CA들.

CA로 부터 인증서를 받기 위해서는 Public Key, Private Key, CSR (certificate signing request) 생성이 필요하다. 

https://www.ssl.com/faqs/what-is-a-certificate-authority/

 

방법1: openssl로 key, csr 생성

먼저 openssl 을 설치하자

# check if it's already installed
brew info openssl
# if not
brew install openssl
# check it's version
openssl version -a

RSA private key를 만들자

openssl genrsa -out private.key 2048

이제 이 private key와 쌍을 이루는 public key를 만들자

openssl rsa -in private.key -out public.key -pubout -outform PEM

 

private key로 csr 생성하기

openssl req -new -key private-key.pem -out test.csr \
-subj "/C=KR/ST=Seoul/L=Seoul/O=Tistory/OU=IT/CN=litaro"

 

방법2: node-forge 이용

openssl 이 아니라 node 앱에서 바로 생성해야하는 경우를 위해 node-forge library에서는 API로 제공된다.

www.npmjs.com/package/node-forge

 

node-forge

JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilities.

www.npmjs.com

node-forge install

npm install node-forge

key 생성하기

var forge = require('node-forge');

// library 로 생성
var keyPair = forge.pki.rsa.generateKeyPair(2048)
var priveKey = keyPair.privateKey
var publicKey = keyPair.publicKey

// openssl에서 읽어오기
var publicKeyPem = fs.readFileSync(path.join(__dirname, 'public-key.pem'), 'utf8');
var privateKeyPem = fs.readFileSync(path.join(__dirname, 'private-key.pem'), 'utf8');
var publicKey = forge.pki.publicKeyFromPem(publicKeyPem);
var privatekey = forge.pki.privateKeyFromPem(privateKeyPem);

csr 생성하기

// create csr
var csr = forge.pki.createCertificationRequest();
csr.publicKey = publicKey;
csr.setSubject([{
    name: 'commonName',
    value: 'litaro'
}, {
    name: 'countryName',
    value: 'KR'
}, {
    shortName: 'ST',
    value: 'Seoul'
}, {
    name: 'localityName',
    value: 'Seoul'
}, {
    name: 'organizationName',
    value: 'Tistory'
}, {
    shortName: 'OU',
    value: 'IT'
}]);
// sign csr
csr.sign(privatekey);
// verify csr
csr.verify();
// convert csr to PEM-format
var csrPem = forge.pki.certificationRequestToPem(csr);

sha256 hash csr을 RSA로 암호화하기

  • 보통 암호화할때 random number를 함께 붙여서 하기에 byte concat을 하고
  • 서버에서 받은 public key를 sign key로 해서 RSA 암호화를 한다.
  • 서버에 다시 보내기 위해 base64로 encoding까지하면 완료
var hashedCsr = forge.md.sha256.create().update(csr).digest().getBytes()
var randomNumber = forge.random.getBytesSync(8)

// randomNumber + hashed csr
var bytes = randomNumber.concat(hashedCsr)

// rsa encrypt
var signKey = forge.pki.publicKeyFromPem(serverPublicKey);
// encrypt data with a sign key (defaults to RSAES PKCS#1 v1.5)
var cipherbytes = signKey.encrypt(bytes);
var ciphertext = forge.util.encode64(cipherbytes)

 

요약

  • 안전한 인터넷으로 통신을 위해 SSL/TLS 프로토콜 규격이 정의되어 있다.
  • SSL/TLS 보안을 위해 CA 라고 불리는 인증 기관이 통신하는 두 주체들을 서로 신뢰할만하지 체크할수 있도록 인증서를 발급한다. 예를 들어 브라우저와 웹서버의 경우, 브라우저는 이미 CA에서 root certificate를 pre installed 하여 보유하고 있을 것이고, 웹서버는 CA에 비용을 대고 server certificate를 받아서 인증 프로세스에 참여하게 된다.
  • 기본적인 CA로 certificate 발급 받는 프로세스를 이해해보려는 차원에서 rsa key 와 csr 생성 방법에 대해 많이 알려진 openssl 방법과 node-forge library를 이용한 방법을 알아보았다.

'자습' 카테고리의 다른 글

React + Gin + Emqx Chat App  (0) 2021.02.27
Go OAuth2.0 서버  (0) 2021.01.31
Electron + Bootstrap 초보의 간단 앱 만들기  (0) 2021.01.09
Electron Quick Start  (0) 2021.01.06
Gin (Go web framework) 앱을 Docker로 실행하기  (0) 2020.12.31