2008. 10. 9. 19:37

Selinux 컴파일 서버

시그윈과의 라이브러리 충돌로 인해 Linux서버를 구축하고 거기에서 정책컴파일을 수행 후 컴파일정보와
컴파일한 정책결과파일을 다시 서버로 넘겨주는 방법으로 구현하였습니다.

컴파일중에 생길수 있는 에러메시지를 정책관리서버가 알수 있기 위해서는 log파일 작성이 필요했습니다.( log.txt )

한글이 깨졌네요..ㅡㅡ;
그냥 편하게 putty로 작업합시다..ㅎ


허브를 두었고 컴파일서버의 현재 IP주소는 192.168.0.47 입니다. 정책관리서버의 IP주소는 위에처럼 49로
주었습니다.


정책관리서버의 IP주소와 컴파일서버의 IP주소를 설정해주고~~


정책서버에서 컴파일버튼을 누르면 컴파일서버에서는 작업할 파일을 받아 이러한 파일의 전송을 보여주는 정보가 보이고 정책을 컴파일한 후 다시 정책서버로 넘겨줍니다.
정책서버에서는 컴파일서버로 부터 받은 로그정보를 뿌려주어 윈도우에서도 리눅스상의 컴파일정보를 볼 수 있게 됩니다.

                          < 컴파일서버에게 넘겨줄 전체 정책파일을 압축한 policy.zip파일 >



  < 컴파일서버로부터 받은 링크정보에 대한 file_contexts파일과 정책이미지 policy.19, 컴파일로그인 log.txt >

 


                                                                 < 로그정보 >

2008. 10. 3. 17:38

Policy Compile Setting(Make Server)


커널과 cygwin과의 의존성 


 

windows 환경에서의 정책 컴파일을 위한 방법으로 처음에 cygwin을 선택했다. 

그러나 cygwin은 환경설정이 너무 많고 또한 selinux관련 lib를 설치함에 있어

cygwin내에는 원래 존재하지 않는 커널과의 의존성을 가지고 있었다.

별로 상관없을꺼 같은 커널내의 함수와 여러 매크로와의 충돌이 많았고 

이것들을 다 잡다가는 배보다 배꼽이 더 큰 격이 될 듯했다.

 

결국 PL은 cygwin을 포기하고 다른 방법을 모색했다 .

VM나 virtual PC를 이용한 방법이다. 

 


서버와 클라이언트 구축 


 

VM와 Virtual PC상에서 컴파일을 시행하기 위해서 linux쪽에 서버를 작성하고 

windows 프로그램쪽에 클라이언트을 작성하였다. 

클라이언트측에서 정책에 대한 파일을 묶어 보내주면 

그걸 받은 linux서버측에서 정책 컴파일을 수행한 후 생성된 정책 이미지와 contexts파일을  

다시 클라이언트측으로 전송시켜 주는 것이다. 

 


virtual PC에서의 환경 구축 


 

  • 좀 더 좋은 환경에서 작업하기 위하여 SSH 터미널을 이용하였다. 
  • 방화벽에 대한 문제가 있을 수 있으므로 주의 하도록 하자.

 

  

  1.   ->방화벽 설정
  •         -> .....> lokkit                                 (입력)  
  •        -> Customize                                 (선택)
  •        -> Trusted Devices:    [*] eth0         (체크!!)       
  •       lokkit_내부그림1.bmp 

 

lokkit_내부그림2.bmp 

 

       2.  -> IP주소 변경 - 사용할 IP주소를 변경하자.

  •      -> etc/sysconfig/network-scripts/ifcfg-eth0 파일 수정
  •      -> HWADDR 부분 수정

 

    lokkit_내부.bmp  

 

 

      3. aceept함수에서의 형변환에러 주의

  •  client_socket = accept( server_socket, (struct sockaddr*)&client_add, (socklen_t*)&client_addlen );
         -> (socklen_t*) :C++에서는 명시적 형변환을 해야함

 

 

     4. SSH터미널 설정이나 다른 세부사항은 동영상 참조. (동영상은 지환한테 있습니다.ㅎㅎㅎ) 

 


SSL서버에서의 window와 linux의 차이점 


 

SSL서버를 구축할 때 기본적으로 쓰이는 소켓생성이나 다른여러 함수는 각 환경에 따라 동일하게 쓰인다. 

한가지는 Windows에서 사용했던 Win32OpenSSL_0.9.8e버젼에서는  

#include "ssl/applink.c"에 대한 참조를 하였지만 내가 하는 리눅스 환경에서는 필요가 없었다. 

아마 리눅스에서 쓰인 openssl 버젼이나 환경에 따라 차이점때문에 그런것이겠지만 

기본적으로 알고 있으면 삽집하는 일이 없을 것이다. 

 

 


 컴파일 실행 


 -> ....> export LANG=euc_kr              - 에러 소스에 대해 깨질 때 쓰자.

 -> ....> g++ -lssl -o Server_SSL Server_SSL.c 

 리눅스환경_SSL서버_컴파일_및_동작그림.bmp


 SSL서버와 파일 송수신 소스 참조 


 Linux상의 SSL서버

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <sys/socket.h>
      5 #include <arpa/inet.h>
      6 #include <netinet/in.h>
      7 #include <sys/types.h>
      8 #include <unistd.h>
      9 #include <netdb.h>
     10 #include <stdbool.h>
     11 #include <strings.h>
     12
     13 #include <openssl/bio.h>
     14 #include <openssl/err.h>
     15 #include <openssl/rand.h>
     16 #include <openssl/evp.h>
     17 #include <openssl/crypto.h>
     18 #include <openssl/ssl.h>
     19 //#include <openssl/applink.c>
     20
     21
     22 #define FILE_BUFSIZES 4096
     23 #define PORT 9001
     24 #define SERVER_ADDRESS "210.118.75.59"
     25
     26 // 서버 인증서와 개인키 파일 정의
     27 #define CERT_FILE "rootcert.pem"
     28 #define PRIVKEY_FILE "rootkey.pem"
     29
     30 #include "common.h"
     31
     32 // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수
     33 void  ssl_info_callback(const SSL *s, int where, int ret);
     34 int recvn(SSL* ssl, char *buf, int len, int flags, struct sockaddr* addr, int* addrlen);
     35 int SendFile(SSL* ssl, struct sockaddr* addr, int* addrlen );
     36 int ReceiveFile(int Type, SSL* ssl, char* mf_fileName, int fm_fileSize);
     37 int SendFile(int Type, SSL* ssl, char* fm_fileName, int fm_fileSize);
     38 //DWORD Get_SendListFileSize(char* fm_Path);
     39
     40 // 화면에 표시 하기 위한 파일 BIO생성
     41 BIO * errBIO;
     42
     43 typedef unsigned int SOCKET;
     44
     45 int main( void )
     46 {
     47
     48       unsigned short port = PORT;

     49       char * serverAddress = SERVER_ADDRESS;
     50       // 서버의 소켓 타입은 TCP 같은 연결형이다.
     51       int socket_type = SOCK_STREAM;
     52       struct sockaddr_in server_add, client_add;
     53       //SOCKET
     54       int server_socket, client_socket;
     55
     56       socket_type = SOCK_STREAM;
     57
     58       // SSL 구조체 생성
     59       SSL_METHOD *meth;
     60       SSL_CTX* ctx;
     61       SSL*     ssl;
     62
     63       ///////////////////
     64       // 파일 전송 관련 변수
     65       int TotalFielSize;
     66       int addrlen;
     67       char filename[256];
     68
     69
     70       ///////////////////
     71
     72       int retval;
     73       /*
     74       // 윈속 DLL을 초기화 하고, 소켓 버전 2.2를 사용 한다는 것을 알린다.
     75       if ((retval = WSAStartup(0x202,&wsaData)) != 0) {
     76         fprintf(stderr,"WSAStartup 함수에서 에러 발생.");
     77         WSACleanup();
     78         exit(1);
     79       }
     80       // 버전이 2.2가 아니면 종료한다.
     81       if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) {
     82         WSACleanup();
     83         exit(1);
     84       }
     85       */
     86       // 화면 출력 BIO생성
     87       if ((errBIO=BIO_new(BIO_s_file())) != NULL)
     88         BIO_set_fp(errBIO,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
     89
     90       // 모든 에러 스트링 로드
     91       SSL_load_error_strings();
     92       // 모든 알고리즘 로드
     93       SSLeay_add_ssl_algorithms();
     94
     95       // SSL 버전3 프로토콜 사용
     96       meth = SSLv3_method();
     97       // SSL 컨텍스트 생성
     98       ctx = SSL_CTX_new(meth);
     99       if (ctx==NULL) {
    100         BIO_printf(errBIO,"SSL_CTX 생성 에러");
    101         ERR_print_errors(errBIO);
    102         exit(1);
    103       }
    104       // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수를 셋팅
    105       SSL_CTX_set_info_callback(ctx,ssl_info_callback);
    106       // 자신의 인증서를 파일에서 로딩한다.
    107       if (SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
    108         ERR_print_errors(errBIO);
    109         exit(1);
    110       }
    111       // 자신의 개인키를 파일에서 로딩한다.
    112       if (SSL_CTX_use_PrivateKey_file(ctx, PRIVKEY_FILE, SSL_FILETYPE_PEM) <= 0) {
    113         ERR_print_errors(errBIO);
    114         exit(1);
    115       }
    116       // 읽은 인증서와 개인키가 맞는지 확인 한다.
    117       if (!SSL_CTX_check_private_key(ctx)) {
    118         BIO_printf(errBIO,"인증서와 개인키가 맞지 않습니다.\n");
    119         ERR_print_errors(errBIO);
    120         exit(1);
    121        }
    122
    123       // 서버의 소켓 생성
    124       server_socket = socket(PF_INET, socket_type, 0);
    125       if(server_socket == -1)
    126       {
    127         printf("소켓생성 에러");
    128         exit(1);
    129       }
    130
    131       // sockaddr_in 구조체의 주소체계를 인터넷 주소체계로 한다.
    132       server_add.sin_family = AF_INET;
    133       // 서버의 주소를 인터넷32비트 주소로 변환하여 sockaddr_in에 넣는다.
    134       server_add.sin_addr.s_addr = inet_addr(serverAddress);
    135       // 네트워크 형식으로 포트번호를 변환 하여 sockaddr_in에 넣는다.
    136       server_add.sin_port = htons(port);
    137
    138       // bind 를 실행 하여 서버 소켓과 서버 주소를 연결 한다.
    139       retval = bind( server_socket, (struct sockaddr*)&server_add, sizeof(server_add) );
    140       if (retval == -1 ) {
    141           fprintf(stderr,"bind  에러");
    142       //  WSACleanup();
    143           exit(1);
    144       }
    145       // listen 함수를 실행 하여 클라이언트가 접속 할 수 있는 최대 버퍼수를 5로 정한다.
    146       retval = listen(server_socket,5);
    147       if (retval == -1 ) {
    148           fprintf(stderr,"listen 에러");
    149       //  WSACleanup();
    150           exit(1);
    151       }
    152
    153       printf("주소 %s , 포트 %d 에서 클라이언트의 연결 기다림.\n",serverAddress,port);
    154
    155       int client_addlen = sizeof(client_add);
    156       // accept함수를 실행 하여 클라이언트로부터의 접속을 기다린다.
    157       client_socket = accept( server_socket, (struct sockaddr*)&client_add, (socklen_t*)&client_addlen );
    158       if (client_socket == -1 )
    159       {
    160         fprintf(stderr,"accept 에러");
    161         //WSACleanup();
    162         exit(1);
    163       }
    164       // 클라이언트로 부터의 접속, 연결
    165       printf("클라이언트 연결, 주소: %s, 포트: %d\n",inet_ntoa(client_add.sin_addr),htons(client_add.sin_port)) ;
    166
    167       // SSL 구조체 생성
    168       ssl = SSL_new (ctx);
    169       if (ssl == NULL) {
    170         BIO_printf(errBIO,"SSL 생성 에러");
    171         ERR_print_errors(errBIO);
    172         exit(1);
    173       }
    174       // 연결된 소켓과 SSL과의 연결
    175       SSL_set_fd(ssl, client_socket);
    176       // 가장 중요한 함수, 클라이언트와의 초기 협상과정, 즉 핸드쉐이크 과정을 수행
    177       retval = SSL_accept(ssl);
    178       if (retval == -1)
    179       {
    180         BIO_printf(errBIO,"SSL accept 에러");
    181         ERR_print_errors(errBIO);
    182         exit(1);
    183       }
    184 //       현재 클라이언트와 정의된 암호화 파라메터정보를 얻음
    185       const char * currentChipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
    186       printf("SSL 연결, 사용 알고리즘 파라메터: [%s]\n",SSL_get_cipher(ssl));
    187       printf("SSL 연결, 사용 알고리즘 파라메터: [%s]\n",currentChipher);
    188
    189
    190       //////////////////////////////////////////////////////////////////////////
    191       //                           연결완료  통신시작.
    192       //////////////////////////////////////////////////////////////////////////
    193
    194       //////////////////////////////////////////////////////////////////////////
    195       //                파일 수신 - 컴파일할 정책 데이터를 받음
    196       //////////////////////////////////////////////////////////////////////////
    197       addrlen = sizeof (server_add);
    198
    199       // 파일 이름 받기
    200       //ZeroMemory(filename, 256);
    201       memset( filename, 0, sizeof(filename) );
    202 /*
    203       retval = recvn(ssl, filename, 256, 0, (SOCKADDR*) &server_add, &addrlen);
    204       if(retval == SOCKET_ERROR)
    205       {
    206           printf("recv()");
    207           close(client_socket);
    208       }
    209       printf("-> 받을 파일 이름: %s\n", filename);
    210
    211       // 파일 크기 받기
    212       retval = recvn(ssl, (char *)&TotalFielSize, sizeof(TotalFielSize), 0, (SOCKADDR*) &server_add, &addrlen);
    213       if(retval == SOCKET_ERROR)
    214       {
    215           printf("recv()");
    216           close(client_socket);
    217       }
    218       printf("-> 받을 파일 크기: %d\n", TotalFielSize);
    219 */
    220       retval = SSL_read( ssl, filename, sizeof(filename) );
    221       if(retval == SOCKET_ERROR)
    222       {
    223           printf("파일이름 수신에 실패했습니다.");
    224           close(client_socket);
    225           exit(1);
    226       }
    227       printf("->받은 파일 이름: %s\n", filename);
    228
    229       retval = SSL_read( ssl, (char *)&TotalFielSize, sizeof( int ) );
    230       if(retval == SOCKET_ERROR)
    231       {
    232           printf("파일크기 수신에 실패했습니다.");
    233           close(client_socket);
    234           exit(1);
    235       }
    236       printf("->받은 파일 크기: %d\n", TotalFielSize);
    237
    238       // 파일 수신
    239       ReceiveFile(0, ssl, filename, TotalFielSize );
    240       //////////////////////////////////////////////////////////////////////////
    241       //                        정책 컴파일 루틴
    242       //////////////////////////////////////////////////////////////////////////
    243
    244       // ....
    245
    246       //////////////////////////////////////////////////////////////////////////
    247       //             파일 송신 - 컴파일한 정책 이미지를 전송
    248       //////////////////////////////////////////////////////////////////////////
    249
    250       // 전송할 파일의 크기를 구함.
    251       //TotalFielSize = Get_SendListFileSize( "log.txt" );
    252       FILE* file_size;
    253       file_size = fopen( "log.txt", "rb" );
    254       if( file_size  == NULL )
    255       {
    256         printf(" file open error ");
    257         return 0;
    258       }
    259
    260       fseek( file_size, 0, SEEK_END );
    261       TotalFielSize = ftell( file_size );
    262       fclose( file_size );
    263
    264
    265       // 파일 이름 보내기
    266       //ZeroMemory(filename, 256);
    267       memset( filename, 0, sizeof(filename) );
    268       retval = SSL_write (ssl, "log.txt", 256);
    269       if(retval == SOCKET_ERROR) printf("send()");
    270
    271       // 파일 크기 보내기
    272       retval = SSL_write (ssl, (char *)&TotalFielSize, sizeof(TotalFielSize));
    273       if(retval == SOCKET_ERROR) printf("send()");
    274
    275       SendFile( 0, ssl, "log.txt", TotalFielSize );
    276
    277       // 연결 해제 및 객체 제거
    278       printf("연결 해제\n");
    279       close(client_socket);
    280       SSL_free (ssl);
    281       SSL_CTX_free (ctx);
    282
    283       system("pause");
    284       return 0;
    285 }
    286
    287 // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수
    288 void  ssl_info_callback(const SSL *s, int where, int ret)
    289 {
    290       char * writeString;
    291       int w;
    292       // 현재 어떤 메시지 교환 과정인지를 나타냄
    293       w = where & ~SSL_ST_MASK;
    294
    295       // 클라이언트가 연결 했을 때
    296       if (w & SSL_ST_CONNECT)
    297         writeString="SSL_connect";
    298       // 서버가 연결을 받았을 때
    299       else if (w & SSL_ST_ACCEPT)
    300         writeString="SSL_accept";
    301       // 알 수 없는 경우
    302       else
    303         writeString="undefined";
    304
    305       // 일반적인 핸드쉐이크 프로토콜 메시지일 경우
    306       if (where & SSL_CB_LOOP)
    307       {
    308         // SSL_state_string_long(s) 함수로 부터 현재 진행되는 메시지가 무엇인지 표시
    309         BIO_printf(errBIO,"%s:%s\n",writeString,SSL_state_string_long(s));
    310       }
    311       else if (where & SSL_CB_ALERT)
    312       { // alert 프로토콜일 경우
    313         //writeString=(where & SSL_CB_READ)?"read":"write";
    314         //BIO_printf(errBIO,"SSL3 alert %s:%s:%s\n",writeString,SSL_alert_type_string_long(ret),SSL_alert_desc_string_        long(ret));
    315       }
    316       else if (where & SSL_CB_EXIT)
    317       { // 종료 과정일 경우
    318         if (ret == 0)
    319           BIO_printf(errBIO,"%s:failed in %s\n",writeString,SSL_state_string_long(s));
    320         else if (ret < 0)
    321         {
    322           BIO_printf(errBIO,"%s:error in %s\n",writeString,SSL_state_string_long(s));
    323         }
    324       }
    325 }
    326
    327 int SendFile(SSL* ssl, struct sockaddr* addr, int* addrlen )
    328 {
    329
    330     return 0;
    331 }
    332
    333 // 사용자 정의 데이터 수신 함수
    334 int recvn(SSL* ssl, char *buf, int len, int flags, struct sockaddr* addr, int* addrlen)
    335 {
    336     int received;
    337     char *ptr = buf;
    338     int left = len;
    339
    340     while(left > 0){
    341         received = SSL_read (ssl, ptr, left);
    342 //      received = recvfrom(s, ptr, left, flags, addr, addrlen);
    343         if(received == SOCKET_ERROR)
    344             return SOCKET_ERROR;
    345         else if(received == 0)
    346             break;
    347         left -= received;
    348         ptr += received;
    349     }
    350
    351     return (len - left);
    352 }
    353
    354 ////////////////////////////////////////////////////////
    355 //
    356 //                   Receive File
    357 //
    358 ////////////////////////////////////////////////////////
    359 int ReceiveFile(int Type, SSL* ssl, char* mf_fileName, int fm_fileSize)
    360 {
    361     int retval;
    362
    363     struct sockaddr_in  clientaddr;
    364     int addrlen;
    365     int nblock = 0, endblock, size;
    366     char buf [FILE_BUFSIZES];
    367
    368     // 저장 경로 지정.
    369 //  CString S_Directory;
    370 //  S_Directory = Standard_Path + "\\certmanage\\policyserver\\embeddedcert\\";
    371 //  S_Directory += (CString)mf_fileName;
    372
    373     addrlen = sizeof(clientaddr);
    374
    375     while(1)
    376     {
    377         endblock = fm_fileSize / 4096;
    378
    379         // 파일 열기
    380         FILE *fp = fopen( "log.txt", "wb");
    381         if(fp == NULL){
    382             perror("파일 입출력 오류");
    383             SSL_free (ssl);
    384             continue;
    385         }
    386
    387         int numtotal = 0;
    388
    389         // 파일 데이터 받기
    390         while (1)
    391         {
    392             if (nblock == endblock)
    393                 size = fm_fileSize % 4096;
    394             else
    395                 size = 4096;
    396             retval = recvn(ssl, (char*)&buf, size, 0, (struct sockaddr*) &clientaddr, &addrlen);
    397             if (retval == SOCKET_ERROR)
    398             {
    399                 break;
    400             }
    401             else if(retval == 0)
    402                 break;
    403             else
    404             {
    405                 int written = fwrite(buf, 1, size, fp);
    406                 if(ferror(fp))
    407                 {
    408                     printf("파일 입출력 오류");
    409                     break;
    410                 }
    411                 if (written != size)
    412                 {
    413                     printf("파일 입출력 오류");
    414                     break;
    415                 }
    416
    417             //  Sleep(1000);
    418                 retval = SSL_write (ssl, (char*) &nblock, sizeof (int));
    419                 if (retval == SOCKET_ERROR)
    420                 {
    421                 //  err_display ("sendto()");
    422                     break;
    423                 }
    424                 else if (retval == 0)
    425                     break;
    426
    427                 nblock ++;
    428                 numtotal += size;
    429                 printf("%d ", nblock);
    430
    431                 if (nblock > endblock)
    432                     break;
    433             }
    434         }
    435         fclose(fp);
    436
    437         // 전송 결과 출력
    438         if(numtotal == fm_fileSize)
    439         {
    440             printf(" 수신 성공 ");
    441             return 1;
    442         }
    443         else
    444         {
    445             printf(" 수신 실패 ");
    446             return -1;
    447         }
    448
    449         break;
    450     }
    451     return 0;
    452 }
    453
    454
    455 ////////////////////////////////////////////////////////
    456 //
    457 //                     Send File - 사용.
    458 //
    459 ////////////////////////////////////////////////////////
    460 int SendFile(int Type, SSL* ssl, char* fm_fileName, int fm_fileSize)
    461 {
    462     int retval;
    463
    464     // 파일 열기
    465     FILE *fp = fopen( fm_fileName, "rb");
    466     if(fp == NULL){
    467         printf("파일 입출력 오류");
    468         return -1;
    469     }
    470
    471         // 파일 데이터 전송에 사용할 변수
    472     char buf[FILE_BUFSIZES];
    473     int numread;
    474     int numtotal = 0;
    475     int ack, nblock = 0, endblock = fm_fileSize / 4096, size;
    476
    477
    478
    479     // 파일 데이터 보내기
    480     rewind(fp); // 파일 포인터를 제일 앞으로 이동
    481     while(1){
    482         if (nblock == endblock)
    483             size = fm_fileSize % 4096;
    484         else
    485             size = 4096;
    486
    487         numread = fread(buf, 1, size, fp);
    488
    489         if(numread > 0)
    490         {
    491             retval = SSL_write (ssl, (char*) &buf, numread);
    492             if(retval == SOCKET_ERROR){
    493                 printf("sendto()");
    494                 break;
    495             }
    496             retval = SSL_read (ssl, (char*) &ack, sizeof (int));
    497             if (retval == SOCKET_ERROR)
    498             {
    499                 printf("recvfrom()");
    500                 break;
    501             }
    502             if (ack == nblock)
    503             {
    504                 nblock ++;
    505                 numtotal += numread;
    506                 printf ( "nblock = %d, numtotal = %d\n", nblock, numtotal );
    507             }
    508         }
    509         else if(numread == 0 && numtotal == fm_fileSize)
    510         {
    511             break;
    512         }
    513         else{
    514             break;
    515         }
    516     }
    517     fclose(fp);
    518
    519     return 0;
    520 }
 

 

 

 windows에서의 클라이언트

(TransFileClass : 파일전송 클래스 - linux서버의 파일전송소스와 동일)

 char* server_name= "210.118.75.59";
    unsigned short port = 9001;
 unsigned int addr;
 struct sockaddr_in server_add;
 struct hostent *host;
 int ret_data;
 
 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;

 m_List_FlowSystem.AddString("인증서버에 연결을 시작합니다.");

 // 파일 전송 플러그
 BOOL SendFile_Flag = FALSE;

 if ((retval = WSAStartup(0x202,&wsaData)) != 0)
 {
  m_List_FlowSystem.AddString("WSAStartup 함수에서 에러 발생.");
  WSACleanup();
  return;
 }
 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) {
  WSACleanup();
  return;
 }
   
 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 )
 {
     m_List_FlowSystem.AddString("SSL_CTX 생성 에러.");
  return;
 }
/*
 // 서버 이름이 알파벳인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 ) {
  m_List_FlowSystem.AddString("알 수 없는 주소입니다.");
  WSACleanup();
  return;
 }
*/
  
 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);
 */

 server_add.sin_family = AF_INET;
 server_add.sin_addr.s_addr = inet_addr( server_name );
 server_add.sin_port = htons( port );

 conn_socket = socket(AF_INET,socket_type,0); 
 if ( conn_socket <0 )
 {
  m_List_FlowSystem.AddString( "소켓 생성 에러" );  
  WSACleanup();
  return;
 }

 if ( connect( conn_socket,(struct sockaddr*)&server_add,sizeof(server_add) )== SOCKET_ERROR )
 {
  m_List_FlowSystem.AddString("connect 에러 : 서버와 연결할 수 없습니다.");
  m_List_FlowSystem.AddString("인증서버를 체크하세요.");
  return;
 }
 // 세션키를 만들기 위한 랜덤 수 를 위한 Seed공급
 m_List_FlowSystem.AddString("랜덤 수 생성중...."); 
 RAND_screen();
 m_List_FlowSystem.AddString("랜덤 수 생성 완료."); 

 ssl = SSL_new( ctx );
 if ( ssl == NULL )
 {
  m_List_FlowSystem.AddString("SSL 생성 에러");
  return;
 }
 SSL_set_fd( ssl, conn_socket );
 retval = SSL_connect( ssl );
 if (retval == -1)
 {
  m_List_FlowSystem.AddString("SSL accept 에러");
  return;
 }
 const char * currentChipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
    m_List_FlowSystem.AddString("SSL 연결, 사용 알고리즘 파라메터");
    m_List_FlowSystem.AddString( currentChipher );

 
 server_cert = SSL_get_peer_certificate (ssl);
 if ( server_cert == NULL )
 {
  m_List_FlowSystem.AddString("서버 인증서를 받을 수 없음.");
  return;
 }
   
 char * retString = NULL;

 // 주체의 DN을 문자열로 얻음
 retString = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
 if (retString == NULL)
 {
  m_List_FlowSystem.AddString("서버 인증서에서 주체의 DN을 읽을 수 없음.");
  return;
 }

 // 발급자의 DN을 문자열로 얻음
 retString = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
 if (retString == NULL)
 {
  m_List_FlowSystem.AddString("서버 인증서에서 발급자의 DN을 읽을 수 없음.");
  return;
 }

 X509_free (server_cert);

 //////////////////////////////////////////////////////////////////////////
 //                  연결 완료, 통신 시작
 //////////////////////////////////////////////////////////////////////////

 //////////////////////////////////////////////////////////////////////////
 //                  파일을 전송함 - 컴파일할 정책 파일
 //////////////////////////////////////////////////////////////////////////

 // 전송할 파일의 크기를 구함.

 int TotalFielSize = TransFileClass.Get_SendListFileSize( "comsetup.log" );
 
 // 파일 이름 보내기
 char filename[256];
 ZeroMemory(filename, 256);
 retval = SSL_write (ssl, "comsetup.log", 256);
 if(retval == SOCKET_ERROR) printf("send()"); 
 
 // 파일 크기 보내기
 retval = SSL_write (ssl, (char *)&TotalFielSize, sizeof(TotalFielSize));
 if(retval == SOCKET_ERROR) printf("send()");

 ret_data = TransFileClass.SendFile( 0, ssl, "comsetup.log", TotalFielSize );
 if( ret_data != 0 )
 {
  m_List_FlowSystem.AddString("정책파일 송신 에러");
 }
 else
 {
  m_List_FlowSystem.AddString("정책파일 송신 성공");
 }

 //////////////////////////////////////////////////////////////////////////
 //                 파일을 수신함 - 컴파일한 정책이미지 관련 파일
 //////////////////////////////////////////////////////////////////////////
    int addrlen = sizeof (server_add);

 // 파일 이름 받기
 ZeroMemory(filename, 256);

 retval = TransFileClass.recvn(ssl, filename, 256, 0, (SOCKADDR*) &server_add, &addrlen);
 if(retval == SOCKET_ERROR)
 {
   m_List_FlowSystem.AddString("파일이름 recv()에러");
  closesocket(conn_socket);
 }
 
 // 파일 크기 받기
 retval = TransFileClass.recvn(ssl, (char *)&TotalFielSize, sizeof(TotalFielSize), 0, (SOCKADDR*) &server_add, &addrlen);
 if(retval == SOCKET_ERROR)
 {
     m_List_FlowSystem.AddString("파일 사이즈 recv()에러");
  closesocket(conn_socket);
 }

 // 파일 수신
 ret_data = TransFileClass.ReceiveFile(0, ssl, filename, TotalFielSize );
 if( ret_data != 1 )
 {
  m_List_FlowSystem.AddString("정책 이미지 파일 수신 에러");
 }
 else
 {
  m_List_FlowSystem.AddString("정책 이미지 파일 수신 성공");
 }

 m_List_FlowSystem.AddString("정책서버 -> 컴파일 서버로의 연결 해제");
 SSL_shutdown (ssl); 

 closesocket(conn_socket);
 m_List_FlowSystem.AddString("소켓 해제.");
 SSL_free (ssl);
 SSL_CTX_free (ctx);

 WSACleanup();

 m_List_FlowSystem.AddString( "연결종료 ");

 

 windows에서의 ssl서버 ( 위의 windows서버와 동작 가능 )
 Server_SSL.zip