OpenSSL 윈도우에서 컴파일 및 설치하기
OpenSSL 1.0.0 버전을 활용했다.
윈도우에서 컴파일하는 방법은 OpenSSL을 다운로드 받으면
INSTALL.W32 파일에 자세하게 나와있다.
INSTALL.W32파일에 보면 다음 두개의 툴을 요구하는것을 알 수 있다.
http://www.activestate.com/ActivePerl.
http://nasm.sourceforge.net/
perl과 nasm을 다운받아 설치한다.
OpenSSL 빌드시 nasm을 사용하므로 nasm.exe가 존재하는 폴더를 PATH로 잡아줘야한다.
OpenSSL 폴더로 이동해서 설치를 진행한다.
다음절차를 통해 설치될 경로를 설정하여준다.
> perl Configure VC-WIN32 --prefix=c:\some\openssl\dir
만일 설치될 폴더를 지정해주지 않는다면 현재 openssl폴더의 out32dll위치에 설치된다.
다음과 같이 nasm을 수행한다.
> ms\do_nasm
nmake를 활용하여 빌드한다.
> nmake -f ms\ntdll.mak
정상적으로 빌드되었는지 테스트하고
> nmake -f ms\ntdll.mak test
앞서 설정된 폴더에 설치를 시작한다.
> nmake -f ms\ntdll.mak install
VC++에서 컴파일하기
설치된 폴더에 존재하는 lib파일과 dll파일을 활용한다.
테스트를 위해 다음과 같은 코드를 준비한 뒤 환경을 설정하도록 한다.
SERVER_ADDRESS에 접속하여 SSL을 맺은 후 간단한 메시지 통신을 하는 클라이언트 코드이다.
#include <stdio.h>
#include <winsock2.h> #include <stdlib.h> #include <string.h> #include <openssl/bio.h> #include <openssl/err.h> #include <openssl/rand.h> #include <openssl/evp.h> #include <openssl/crypto.h> #include <openssl/ssl.h>
#define PORT 443
#define SERVER_ADDRESS "202.30.50.88" int main( ) { char * server_name= SERVER_ADDRESS; unsigned short port = PORT; unsigned int addr; struct sockaddr_in server_add; struct hostent *host; WSADATA wsaData; SOCKET conn_socket;
int socket_type = SOCK_STREAM;
int retval;
// SSL 구조체 생성
SSL_METHOD *meth; SSL_CTX* ctx; SSL* ssl; X509* server_cert;
BIO * errBIO;
if ((retval = WSAStartup(0x202,&wsaData)) != 0) { fprintf(stderr,"WSAStartup 함수에서 에러 발생."); WSACleanup(); exit(1); } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup(); exit(1); }
if ((errBIO=BIO_new(BIO_s_file())) != NULL)
BIO_set_fp(errBIO,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = SSLv3_method();
ctx = SSL_CTX_new(meth); if (ctx==NULL) { BIO_printf(errBIO,"SSL_CTX 생성 에러"); ERR_print_errors(errBIO); exit(1); } // 서버 이름이 알파벳인DNS로 되어 있을 경우 if (isalpha(server_name[0])) { host = gethostbyname(server_name); } // 서버 이름이 IP로 되어 있을 경우 else { addr = inet_addr(server_name); host = gethostbyaddr((char *)&addr,4,AF_INET); } if (host == NULL ) { fprintf(stderr,"알 수 없는 주소[%s] 입니다, 에러 코드: %d\n",server_name,WSAGetLastError()); WSACleanup(); exit(1); } memset(&server_add,0,sizeof(server_add)); memcpy(&(server_add.sin_addr),host->h_addr,host->h_length); server_add.sin_family = host->h_addrtype; server_add.sin_port = htons(port);
conn_socket = socket(AF_INET,socket_type,0);
if (conn_socket <0 ) { fprintf(stderr,"소켓 생성 에러, 에러 코드:%d\n",WSAGetLastError()); WSACleanup(); exit(1); }
printf("[%s] 서버에 연결중..\n",server_name);
if (connect(conn_socket,(struct sockaddr*)&server_add,sizeof(server_add))== SOCKET_ERROR) { fprintf(stderr,"connect 에러, 에러 코드:%d\n",WSAGetLastError()); WSACleanup(); exit(1); } // 세션키를 만들기 위한 랜덤 수 를 위한 Seed공급 printf("랜덤 수 생성중...."); RAND_screen(); printf("랜덤 수 생성 완료.\n");
ssl = SSL_new(ctx);
if (ssl == NULL) { BIO_printf(errBIO,"SSL 생성 에러"); ERR_print_errors(errBIO); exit(1); } SSL_set_fd(ssl, conn_socket); retval = SSL_connect(ssl); if (retval == -1) { BIO_printf(errBIO,"SSL accept 에러"); ERR_print_errors(errBIO); exit(1); } const char * currentChipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); printf("SSL 연결, 사용 알고리즘 파라메터: [%s]\n",currentChipher); server_cert = SSL_get_peer_certificate (ssl); if (server_cert == NULL) { BIO_printf(errBIO,"서버 인증서를 받을 수 없음."); ERR_print_errors(errBIO); exit(1); } printf ("Server certificate:\n"); char * retString = NULL;
// 주체의 DN을 문자열로 얻음
retString = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); if (retString == NULL) { BIO_printf(errBIO,"서버 인증서에서 주체의 DN을 읽을 수 없음."); ERR_print_errors(errBIO); exit(1); } printf ("\t subject: %s\n", retString); // free (retString); // 발급자의 DN을 문자열로 얻음 retString = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); if (retString == NULL) { BIO_printf(errBIO,"서버 인증서에서 발급자의 DN을 읽을 수 없음."); ERR_print_errors(errBIO); exit(1); } printf ("\t issuer: %s\n", retString); // free (retString); X509_free (server_cert); char buffer[1000]; char message[100] = "GET / HTTP1.1\r\n\r\n."; retval = SSL_write (ssl, message, strlen(message)); if (retval == -1) { BIO_printf(errBIO,"SSL write 에러"); ERR_print_errors(errBIO); exit(1); } retval = SSL_read (ssl, buffer, sizeof(buffer) - 1); if (retval == -1) { BIO_printf(errBIO,"SSL read 에러"); ERR_print_errors(errBIO); exit(1); } buffer[retval] = '\0'; printf ("서버로 부터 데이터 전송 :[%s], 길이:%d\n",buffer,retval); SSL_shutdown (ssl);
closesocket(conn_socket);
SSL_free (ssl); SSL_CTX_free (ctx);
WSACleanup();
}
|
openssl\include 폴더가 아니라
openssl\inc32 폴더를 VC의 도구->옵션->디렉토리의 포함파일에 포함한다.
라이브러리파일은 OpenSSL을 컴파일하면서 생성된 폴더를 지정해준다.
즉 openssl\out32dll 폴더를 VC의 도구->옵션->디렉토리의 라이브러리파일에 포함한다.
다음 코드를 프로젝트에 포함한다.
openssl\ms\applink.c
위 소스코드를 돌리기 위해 프로젝트의 링크옵션에 포함된 라이브러리 파일은 다음과 같다.
ws2_32.lib ssleay32.lib libeay32.lib
dll 오류가 발생한다면, openssl\out32dll위치에 있는 dll파일을 실행파일 위치에 두면 정상적으로 동작할 것이다.
댓글 없음:
댓글 쓰기