C/C++ OpenSSL 프로그래밍

황제낙엽 2007.09.27 21:53 조회 수 : 1363 추천:104

sitelink1  
sitelink2  
sitelink3  
sitelink4  
extra_vars5  
extra_vars6  
http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/openssl_programing

소개

이미 OpenSSL(12)을 이용한 파일 암호화에서 OpenSSL(12)에 대한 기본적인 내용은 다루었으므로 여기에서는 실제 OpenSSL에서 제공하는 함수들을 이용해서 SSL(12)세션을 만들고 이 세션을 통해서 데이터를 통신하는 방법에 대해서 알아보도록 하겠다.

참고로 OpenSSL을 이용한 파일 암호화과는 내용이 좀 다르다. 앞서 다루었던 내용은 SSL세션을 통한 통신이 아닌 OpenSSL에서 제공하는 암호화 알고리즘을 통한 암호화 기법에 대한 것으로 여기에서 다루고자 하는 내용과는 성격에 있어서 차이가 난다.

SSL 이란 무엇인가

[[Include(Term_SSL)]]

OpenSSL 이란 무엇인가

[[Include(Term_OpenSSL)]]

OpenSSL 프로그래밍

OpenSSL은 통신과 관련된 완전한 API를 제공하고 있다. 이들 API는 소켓에서 볼 수 있는 연결생성, 읽기/쓰기, 닫기와 같은 함수들을 제공하며, 입출력 다중화와 같은 시스템 프로그래밍 기술들과 함께 사용할 수 있다.

또한 보안연결과 관련된 함수 뿐만 아니라, 보안연결을 통하지 않은 일반 데이터 제어를 위한 함수도 포함하고 있다.

즉 개발자는 소켓과 OpenSSL을 (복잡하게)섞어서 사용할 필요 없이 OpenSSL에서 제공하는 함수들만을 가지고 완전한 애플리케이션을 작성할 수 있다.

공통 자료타입 과 헤더파일들

OpenSSL을 이용한 응용을 작성하기 원한다면, 다음의 헤더파일들을 필수 적으로 포함해야 한다. 물론 그전에 OpenSSL관련 라이브러리는 당연히 설치되어 있어야 한다. 리눅스운영체제는 거의 대부분 포함하고 있음으로 신경쓸 필요 없을 것이다. 윈도우 환경에서의 OpenSSL이용은 윈도우에서의 openssl 프로그래밍을 참고하기 바란다.
#include <openssl/bio.h>#include <openssl/ssl.h>#include <openssl/err.h>

다음은 OpenSSL 초기화 관련 함수들로 반드시 포함되어야 하는 함수들이다.
void SSL_load_error_strings(void);void OpenSSL_add_all_algorithms(void);void ERR_load_BIO_strings(void);
ERR_load_error_strings는 libcrypto함수와 관련된 모든 에러메시지를 가지고 있있다. OpenSSL_add_all_algorithm은 데이터 축약과 ciphers를 위한 알고리즘을 지원시키기 위해서 사용한다.

OpenSSL의 핵심적인 자료구조로 BIO라는 자료구조가 제공한다. 이것은 struct bio_st 의 typedef로 정의되어 있는데, 보안연결과 관련된 자료들을 가지고 있으며, 대부분의 OpenSSL 함수들은 BIO를 이용해서 필요한 일을 하게 된다.
BIO *bio
혹시나 심심해서 bio_st 구조체를 살펴보고 싶다면 openssl/bio.h 파일을 참고하기 바란다.

공통 함수

연결 관련 함수

앞서 설명했듯이 OpenSSL은 자체적으로 완전한 통신지원을 위한 모든 함수들을 포함하고 있다. 이중 비 보안 연결을 위해서 BIO_new_connect와 BIO_new_accept 라는 함수를 사용한다.
BIO *BIO_new_connect(char *hostinfo);BIO *BIO_new_accept(char *hostinfo);
이 함수들은 연결하고자 하는 호스트의 인터넷정보(인터넷 주소와 포트)를 인자로 받아서 실행하고 BIO 객체를 되돌려 준다. _connect함수는 클라이언트 측어 연결을 위해서, _new_accept는 서버측에서 BIO 객체를 만들기 위해서 사용한다. 만약 비 보안 연결(일반 소켓연결)만을 위한 서버를 작성하다면 BIO_new_accept를 사용한다.

연결의 성공여부는 BIO가 NULL인지를 검사하는 것으로 이루어진다. 일단 BIO객체가 만들어 졌다면 BIO_do_connect와 BIO_do_accept등의 함수를 이용해서 연결을 시도하거나 연결을 받아들인다.
#include <openssl/bio.h> int BIO_do_accept(BIO *b);int BIO_do_connect(BIO *b);

다음은 간단한 사용방법이다.
BIO *bio;bio = BIO_new_connect("127.0.0.1:1010");if (bio == NULL){    // 에러처리}// 연결을 시도한다.if (BIO_do_connect(bio) <= 0){}
위의 경우는 클라이언트 측에서의 방법인데, 서버측의 경우에는 BIO_new_accept와 BIO_do_accept함수를 사용한다. BIO_do_accept는 듣기 소켓으로 부터 연결이 있는지를 검사한다.

읽기/쓰기

보안 연결이든 아니든간에 공통적으로 사용가능 한 함수를 제공한다.
#inlcude <openssl/bio.h>int    BIO_read(BIO *b, void *buf, int len);int    BIO_write(BIO *b, const void *buf, int len);int    BIO_gets(BIO *b, char *buf, int size);int    BIO_puts(BIO *b, const char *buf);
기본적인 시스템 함수인 read(2), write(2)와 고수준 입출력 함수인 gets(3), puts(3)와 동일 하게 사용할 수 있으므로 사용하는데 있어서 어려움이 없을 것이다.

주어진 SSL객체 b로 부터 데이터를 제대로 읽어 들였다면 0보다 더큰 값을 리턴한다. 만약 에러가 발생했다면, 0이나 -1을 리턴한다. 0이 리턴되는 경우는 주로 반대쪽에서 연결을 끊었을 경우다. 이들 함수는 입출력 다중화를 위한 select(), poll()등과 같이 사용할 수 있다. 단지 read()/write()대신 위의 함수들을 사용해주기만 하면 된다. 실제 적용에 대해서는 나중에 따로 다루도록 하겠다.


보안 연결을 위한 추가 함수

보안 연결도 공통 연결에서 사용되는 각종 SSL API들을 그대로 사용해서 연결을 만들고 통신을 하지만, 보안 연결을 만들기 전에 몇가지 과정이 추가 된다. 추가 되는 부분은 응용에서 SSL을 사용하기 위해서 CTX객체를 생성과 관련된 것으로 이들에 대해서 알아보도록 하겠다.

이를 위해서 다음과 같은 함수를 제공한다.
#include <openssl/ssl.h>SSL_CTX *SSL_CTX_new(SSL_METHOD *method);int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,                const char *CApath);
SSL_CTX_new 는 TLS(12)/SSL연결을 할수 있는 SSL_CTX객체를 생성한다. 어떠한 연결방식을 사용할 것인지를 method인자를 통해 결정할 수 있는데, SSL혹은 TLS을 사용할것인지, 어떠한 버젼을 사용할 것인지에 따라 적당한 메서드 함수를 사용할 수 있다.

SSL 버젼 2와 3을 모두 지원하는 클라이언트를 위해서는 SSLv23_client_method(void), 서버를 위해서는 SSLv23_server_method(void)를 사용하면 된다. 참고로 버젼 2는 SSLv2_server_method/SSLv2_client_method등을 사용할 수 있다. TLS을 이용하고 싶다면 SSL을 TLS로 변경해서 사용하면 된다.

SSL_CTX_load_verity_locations함수는 CTX객체에서 참조할 CA 증명서(certificate)파일의 위치를 알려주기 위해서 사용한다. CAfile은 파일의 이름이고 CApath는 경로이름이다. 일반적으로 /usr/share/ssl 밑에 사용가능한 CA파일이 존재하니 이것을 참고하면 된다.

일단 CTX객체를 생성하고 성공적으로 CA파일을 로드했다면, ctx를 이용해서 ssl 연결을 만들어야 한다. 이를 위해서 BIO_new_ssl_connect함수를 사용한다.
BIO *BIO_new_ssl_connect(SSL_CTX *ctx);

마지막으로 SSL 연결 모드를 설정해주면 된다.
BIO_get_ssl(BIO *bio, SSL *ssl); BIO_set_mode(SSL *ssl, MODE); 

예제

기본적인 내용을 다루었으므로 실제 응용이 가능한지 확인을 위해서 간단한 예제를 만들어 보기로 했다. 이미 몇번 다루어본 echo 서버/클라이언트를SSH비보안 모드와 보안모드로 작성을 해보도록 하고 마지막에는 서버와 클라이언트에서 동시에 보안/비보안 모드를 지원가능 하도록 만들어볼 생각이다.

비 보안 연결 관련 예제

#include <openssl/ssl.h>#include <openssl/bio.h>#include <openssl/err.h>#include <stdio.h>#include <string.h>#include <unistd.h>int main(int argc, char **argv){  BIO *abio, *cbio;  char buf[256];  ERR_load_BIO_strings();  SSL_load_error_strings();  OpenSSL_add_all_algorithms();    // 1111 포트로 듣기 소켓을 생성한다.  abio = BIO_new_accept("1111");    // 듣기 소켓의 초기화  if (BIO_do_accept(abio) <= 0)  {    ERR_print_errors_fp(stderr);    exit(0);  }  while(1)  {        // 듣기 소켓으로 부터 연결을 기다린다.    printf("연결을 기다림n");    if (BIO_do_accept(abio) <= 0)    {      ERR_print_errors_fp(stderr);      exit(0);    }        // 만약 연결이루어 졌다면         // 해당 연결을 가지고 온다.    cbio = BIO_pop(abio);    memset(buf, 0x00, 256);        // 읽고 쓴다.    if (BIO_read(cbio, buf, 255) <= 0)    {      perror("Read Error");    }    BIO_write(cbio, buf, 255);    BIO_free(cbio);  }}
코드는 매우 간단하며 쉽게 이해할 수 있을 것이다. telnet를 이용해서 쉽게 테스트 가능하다.

보안 연결 관련 예제

보안 연결 예제를 테스트 하기 위해서는 우선 CA파일이 있어야 한다. 이 파일은 /usr/share/ssl/cert 밑에 cert.pem이라는 이름으로 있다. cert.pem의 위치는 배포판과 패키지 설치 방법에 따라서 달라질 수 있으니 잘 찾아보기 바란다. 참고로 이 위치는 fedora core2 에서의 위치다.

예제는 www.verisign.com에 https(12)를 통해서 연결하고 인덱스 페이지를 읽어온다. 예제 프로그램 만들기 귀찮아서 http://www.kennethballard.com/Download/intro-openssl.zip에 있는 코드를 그대로 사용했다.
#include "openssl/ssl.h"#include "openssl/bio.h"#include "openssl/err.h"#include "stdio.h"#include "string.h"int main(){    BIO * bio;    SSL * ssl;    SSL_CTX * ctx;    int p;    char * request = "GET / HTTP/1.1x0Dx0AHost: www.verisign.comx0Dx0Ax43onnection: Closex0Dx0Ax0Dx0A";    char r[1024];    /* Set up the library */    ERR_load_BIO_strings();    SSL_load_error_strings();    OpenSSL_add_all_algorithms();    /* Set up the SSL context */    ctx = SSL_CTX_new(SSLv23_client_method());    /* Load the trust store */    if(! SSL_CTX_load_verify_locations(ctx, "cert.pem", "/usr/share/ssl"))    {        fprintf(stderr, "Error loading trust storen");        ERR_print_errors_fp(stderr);        SSL_CTX_free(ctx);        return 0;    }    /* Setup the connection */    bio = BIO_new_ssl_connect(ctx);    /* Set the SSL_MODE_AUTO_RETRY flag */    BIO_get_ssl(bio, & ssl);    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);    /* Create and setup the connection */    BIO_set_conn_hostname(bio, "www.verisign.com:https");    if(BIO_do_connect(bio) <= 0)    {        fprintf(stderr, "Error attempting to connectn");        ERR_print_errors_fp(stderr);        BIO_free_all(bio);        SSL_CTX_free(ctx);        return 0;    }    /* Check the certificate */    if(SSL_get_verify_result(ssl) != X509_V_OK)    {        fprintf(stderr, "Certificate verification error: %in", SSL_get_verify_result(ssl));        BIO_free_all(bio);        SSL_CTX_free(ctx);        return 0;    }    /* Send the request */    BIO_write(bio, request, strlen(request));    /* Read in the response */    for(;;)    {        p = BIO_read(bio, r, 1023);        if(p <= 0) break;        r[p] = 0;        printf("%s", r);    }    /* Close the connection and free the context */    BIO_free_all(bio);    SSL_CTX_free(ctx);    return 0;}


번호 제목 sitelink1 글쓴이 날짜 조회 수
공지 [계속 추가중] SBOM 용어 정의   황제낙엽 2025.04.10 52
공지 [계속 추가중] Keycloak 용어 및 설정 옵션 정의   황제낙엽 2024.02.02 631
25 blowfish 알고리즘 file http://www.schneier.com/blowfish.html  황제낙엽 2008.01.22 239
24 OpenSSL을 이용한 보안 통신 API의 설계 및 구현 file   황제낙엽 2007.10.01 193
23 Windows환경에서의 OpenSSL설치 file   황제낙엽 2007.09.28 145
22 OpenSSL Command-Line HOWTO   황제낙엽 2007.09.27 437
21 Certificate Server의 설치 와 Client인증 http://wiki.kldp.org/wiki.php/LinuxdocSgml/OpenSSL-KLDP  황제낙엽 2007.09.27 310
20 OpenSSL의 설치 및 운영 http://user.chol.com/~laday/solaris/openssl.html  황제낙엽 2007.09.27 200
» OpenSSL 프로그래밍   황제낙엽 2007.09.27 1363
18 OpenSSL 을 통한 파일 암호화   황제낙엽 2007.09.27 361
17 OpenSSL 과 OpenSSH 소스 파일 (Language : C)   황제낙엽 2007.09.24 181
16 RSA 암호화 알고리즘을 구현한 C++ 예제 file http://labs.jong10.com/category/cryptology  황제낙엽 2007.09.17 1400
15 RSA암호화를 이용한 로그인 ID/패스워드 정보 관리 http://blog.dalsu.net/61  황제낙엽 2007.09.05 258
14 PHP와 OpenSSL http://www.ecoop.net/memo/2007-04-26-3.html  황제낙엽 2007.09.27 272
13 RSA 공개키 암호화 알고리즘 - PHP 구현[2] file   황제낙엽 2007.09.27 393
12 RSA 공개키 암호화 알고리즘 - PHP 구현[1] file   황제낙엽 2007.09.05 179
11 OpenSSL사용방법 메모, RSA암호의 최대 사이즈, JCA/JCE가이드   황제낙엽 2007.09.27 173
10 Java Cryptography Extension (JCE) 개요   황제낙엽 2007.09.27 345
9 Java에서 암호화하고 C++에서 복호화하는 방법   황제낙엽 2007.09.27 378
8 비밀키를 Keytool에서 취급할 수 있는 형식으로 변환방법 http://java-house.jp/ml/archive/j-h-b/051472.html  황제낙엽 2007.09.27 229
7 공개키 암호화의 수학적 알고리즘과 자바 구현   황제낙엽 2007.09.22 207
6 RSA 암호화 알고리즘을 구현한 자바예제 (산술계산)   황제낙엽 2007.09.17 326