Openssl을 이용한 암호화 통신

 서버는 암호화 통신을 위하여 가장 먼저 SSL_CTX와 SSL 구조체를 선언하여 암호화 통신을 위한 정보를 관리할 수 있도록 한다. 그리고, SSL 세션을 시작하기 위한 초기값을 설정하고, SSL_CTX_new() 함수를 이용하여 SSL 컨텍스트를 생성한다.

 다음 단계는 인증서를 이용하여 서버와 클라이언트 간의 인증을 수행할 경우 SS_CTX_use_certificate_file()를 이요하여 인증서 파일을 생성하며, SSL_CTX_use_PrivateKey_file()를 이용하여 개인 키를 생성한다.

 이런 준비 단계 후에 SSL_new() 함수를 이용하여 SSL 세션을 생성하고, 이후의 단계는 기존의 소켓 서버와 유사한 방법으로 처리를 수행할 수 있다. SSL을 이용한 송수신은 SSL_accept(), SSL_read(), SSL_write() 등의 함수를 이용할 수 있으며, 이 과정은 기종의 소켓 프로그래밍과 유사한 방법으로 수행된다.

serv.c (Language : c)
  1. /*
  2. *      serv.c
  3. *     
  4. *      Copyright 2008 Kim Sung-tae <pchero21@gmail.com>
  5. *     
  6. *      This program is free software; you can redistribute it and/or modify
  7. *      it under the terms of the GNU General Public License as published by
  8. *      the Free Software Foundation; either version 2 of the License, or
  9. *      (at your option) any later version.
  10. *     
  11. *      This program is distributed in the hope that it will be useful,
  12. *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. *      GNU General Public License for more details.
  15. *     
  16. *      You should have received a copy of the GNU General Public License
  17. *      along with this program; if not, write to the Free Software
  18. *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. *      MA 02110-1301, USA.
  20. */
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <memory.h>
  27. #include <errno.h>
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30. #include <netinet/in.h>
  31. #include <arpa/inet.h>
  32. #include <netdb.h>
  33.  
  34. /*
  35. * openssl 관련 헤더 파일을 include 한다.
  36. */
  37. #include <openssl/rsa.h>        /* SSLeay stuff */
  38. #include <openssl/crypto.h>
  39. #include <openssl/x509.h>
  40. #include <openssl/pem.h>
  41. #include <openssl/ssl.h>
  42. #include <openssl/err.h>
  43.  
  44. /* define HOME to be dir for key and cert files…. */
  45. #define HOME “./”
  46.  
  47. /* Make these what you want for cert & key files */
  48. #define CERTF HOME “server.crt”
  49. #define KEYF HOME “server.key”
  50.  
  51. #define CHK_NULL(x) if((x) == NULL) exit(1);
  52. #define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }
  53. #define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr); exit(2); }
  54.  
  55.  
  56. int main(void)
  57. {
  58.     int err;
  59.     int listen_sd;
  60.     int sd;
  61.     struct sockaddr_in sa_serv;
  62.     struct sockaddr_in sa_cli;
  63.     size_t client_len;
  64.    
  65.     /* SSL Context 및 관련 구조체를 선언한다. */
  66.     SSL_CTX  *ctx;
  67.     SSL    *ssl;
  68.     X509                *client_cert;
  69.     char                *str;
  70.     char                buf[4096];
  71.     SSL_METHOD  *meth;
  72.    
  73.     /* SSL 관련 초기화 작업을 수행한다. */
  74.     SSL_load_error_strings();
  75.     SSLeay_add_ssl_algorithms();
  76.     meth = SSLv23_server_method();    // 서버 메소드.
  77.     ctx = SSL_CTX_new(meth);                // 지정된 초기 값을 이용하여 SSL Context를 생성한다.
  78.    
  79.     if(!ctx) {
  80.         ERR_print_errors_fp(stderr);
  81.         exit(2);
  82.     }
  83.    
  84.     /* 사용하게 되는 인증서 파일을 설정한다. */
  85.     if(SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {      // 인증서를 파일로 부터 로딩할때 사용함.
  86.         ERR_print_errors_fp(stderr);
  87.         exit(3);
  88.     }
  89.    
  90.     /* 암호화 통신을 위해서 이용하는 개인 키를 설정한다. */
  91.     if(SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
  92.         ERR_print_errors_fp(stderr);
  93.         exit(4);
  94.     }
  95.    
  96.     /* 개인 키가 사용 가능한 것인지 확인한다. */
  97.     if(!SSL_CTX_check_private_key(ctx)) {
  98.         fprintf(stderr, “Private key does not match the certificate public keyn);
  99.         exit(5);
  100.     }
  101.    
  102.     /* Prepare TCP socket for receiving connections */
  103.     listen_sd = socket(AF_INET, SOCK_STREAM, 0);
  104.     CHK_ERR(listen_sd, “socket”);
  105.    
  106.     memset(&sa_serv, , sizeof(sa_serv));
  107.     sa_serv.sin_family = AF_INET;
  108.     sa_serv.sin_addr.s_addr = INADDR_ANY;
  109.     sa_serv.sin_port = htons(1111); /* Server Port number */
  110.  
  111.     err = bind(listen_sd, (struct sockaddr*)&sa_serv, sizeof(sa_serv));
  112.     CHK_ERR(err, “bimd”);
  113.    
  114.     /* Receive a TCP connection. */
  115.      err = listen(listen_sd, 5);
  116.      CHK_ERR(err, “listen”);
  117.     
  118.      client_len = sizeof(sa_cli);
  119.      sd = accept(listen_sd, (struct sockaddr*)&sa_cli, &client_len);
  120.      CHK_ERR(sd, “accept”);
  121.      close(listen_sd);
  122.     
  123.      printf(“Connection from %1x, port %xn, sa_cli.sin_addr.s_addr, sa_cli.sin_port);
  124.     
  125.      /* TCP connection is ready. Do server side SSL. */
  126.     ssl = SSL_new(ctx); // 설정된 Context를 이용하여 SSL 세션의 초기화 작업을 수행한다.
  127.     CHK_NULL(ssl);
  128.     SSL_set_fd(ssl, sd);
  129.     err = SSL_accept(ssl);    // SSL 세션을 통해 클라이언트의 접속을 대기한다.
  130.     CHK_SSL(err);
  131.    
  132.     /* Get the cipher – opt */
  133.     printf(“SSL connection using %sn, SSL_get_cipher(ssl));
  134.    
  135.     /* 클라이언트의 인증서를 받음 – opt */
  136.     client_cert = SSL_get_peer_certificate(ssl);
  137.     if(client_cert != NULL) {
  138.         printf(“Client certificate:n);
  139.        
  140.         str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
  141.         CHK_NULL(str);
  142.         printf(t subject: %sn, str);
  143.         OPENSSL_free(str);
  144.        
  145.         str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
  146.         CHK_NULL(str);
  147.         printf(t issuer: %sn, str);
  148.         OPENSSL_free(str);
  149.        
  150.         /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */
  151.         X509_free(client_cert);
  152.     } else {
  153.         printf(“Client does not have certificate.n);
  154.     }
  155.    
  156.     /* SSL 세션을 통해서 클라이언트와 데이터를 송수신한다. */
  157.     err = SSL_read(ssl, buf, sizeof(buf)1);
  158.     CHK_SSL(err);
  159.     buf[err] = ;
  160.     printf(“Got %d chars: ‘%s’n, err, buf);
  161.    
  162.     err = SSL_write(ssl, “I hear you/”, strlen(“I hear you.”));
  163.     CHK_SSL(err);
  164.    
  165.     /* 설정한 자원을 반환하고 종료한다. */
  166.     close(sd);
  167.     SSL_free(ssl);
  168.     SSL_CTX_free(ctx);
  169.    
  170.     return(0);
  171. }
  172.  

cli.c (Language : c)
  1. /*
  2. *      cli.c
  3. *     
  4. *      Copyright 2008 Kim Sung-tae <pchero21@gmail.com>
  5. *     
  6. *      This program is free software; you can redistribute it and/or modify
  7. *      it under the terms of the GNU General Public License as published by
  8. *      the Free Software Foundation; either version 2 of the License, or
  9. *      (at your option) any later version.
  10. *     
  11. *      This program is distributed in the hope that it will be useful,
  12. *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. *      GNU General Public License for more details.
  15. *     
  16. *      You should have received a copy of the GNU General Public License
  17. *      along with this program; if not, write to the Free Software
  18. *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. *      MA 02110-1301, USA.
  20. */
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <memory.h>
  25. #include <errno.h>
  26. #include <sys/types.h>
  27. #include <sys/socket.h>
  28. #include <netinet/in.h>
  29. #include <arpa/inet.h>
  30. #include <netdb.h>
  31.  
  32. #include <openssl/crypto.h>
  33. #include <openssl/x509.h>
  34. #include <openssl/pem.h>
  35. #include <openssl/ssl.h>
  36. #include <openssl/err.h>
  37.  
  38. #define CHK_NULL(x) if((x) == NULL) exit(1);
  39. #define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }
  40. #define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr); exit(2); }
  41.  
  42.  
  43. int main(void)
  44. {
  45.     int err;
  46.     int sd;
  47.     struct sockaddr_in sa;
  48.    
  49.     /* SSL 관련 정보를 관리할 구조체를 선언한다. */
  50.     SSL_CTX   *ctx;
  51.     SSL     *ssl;
  52.     X509                    *server_cert;
  53.     char                    *str;
  54.     char                    buf[4096];
  55.     SSL_METHOD    *meth;
  56.    
  57.     /* 암호화 통신을 위한 초기화 작업을 수행한다. */
  58.     SSL_load_error_strings();
  59.     SSLeay_add_ssl_algorithms();
  60.     meth = SSLv3_client_method();
  61.     ctx = SSL_CTX_new(meth);
  62.     CHK_NULL(ctx);
  63.    
  64.     /* 사용하게 되는 인증서 파일을 설정한다. – opt*/
  65.     if(SSL_CTX_use_certificate_file(ctx, “./client.crt”, SSL_FILETYPE_PEM) <= 0) {    // 인증서를 파일로 부터 로딩할때 사용함.
  66.         ERR_print_errors_fp(stderr);
  67.         exit(3);
  68.     }
  69.    
  70.     /* 암호화 통신을 위해서 이용하는 개인 키를 설정한다. – opt */
  71.     if(SSL_CTX_use_PrivateKey_file(ctx, “./client.key”, SSL_FILETYPE_PEM) <= 0) {
  72.         ERR_print_errors_fp(stderr);
  73.         exit(4);
  74.     }
  75.    
  76.     /* 개인 키가 사용 가능한 것인지 확인한다. – opt */
  77.     if(!SSL_CTX_check_private_key(ctx)) {
  78.         fprintf(stderr, “Private key does not match the certificate public keyn);
  79.         exit(5);
  80.     }
  81.    
  82.     //CHK_SSL(err);
  83.    
  84.     /* Create a socket and connect to server using normal socket calls. */
  85.     sd = socket(AF_INET, SOCK_STREAM, 0);
  86.     CHK_ERR(sd, “socket”);
  87.    
  88.     memset(&sa, , sizeof(sa));
  89.     sa.sin_family = AF_INET;
  90.     sa.sin_addr.s_addr = inet_addr(“127.0.0.1”);        // Server IP Address
  91.     sa.sin_port = htons(1111);                // Server Port Number
  92.    
  93.     err = connect(sd, (struct sockaddr*)&sa, sizeof(sa));
  94.     CHK_ERR(err, “connect”);
  95.    
  96.     /* Now we have TCP connection. Start SSL negotiation. */
  97.     ssl = SSL_new(ctx);  // 세션을 위한 자원을 할당받는다.
  98.     CHK_NULL(ssl);
  99.    
  100.     SSL_set_fd(ssl, sd);
  101.     err = SSL_connect(ssl); // 기존의 connect() 함수 대신 사용하여 서버로 접속한다.
  102.     CHK_NULL(err);
  103.    
  104.     /* Following two steps are optional and not required for data exchange to be successful. */
  105.    
  106.     /* Get the Cipher – opt */
  107.     printf(“SSL connection using %sn, SSL_get_cipher(ssl));
  108.    
  109.     /* Get server’s certificate (note: beware of dynamic allocation) – opt */
  110.     /* 서버의 인증서를 받는다. */
  111.     server_cert = SSL_get_peer_certificate(ssl);
  112.     CHK_NULL(server_cert);
  113.     printf(“Server certificate:n);
  114.    
  115.     /* 인증서의 이름을 출력한다. */
  116.     str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
  117.     CHK_NULL(str);
  118.     printf(t subject: %sn, str);
  119.     OPENSSL_free(str);
  120.    
  121.     /* 인증서의 issuer를 출력한다. */
  122.     str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
  123.     CHK_NULL(str);
  124.     printf(t issuer: %sn, str);
  125.     OPENSSL_free(str);
  126.    
  127.     /* We could do all sorts of certificate verification stuff here before deallocating the certificate */
  128.     X509_free(server_cert);
  129.    
  130.     /* 서버와 데이터를 송수신 한다. */
  131.     err = SSL_write(ssl, “Hello World!”, strlen(“Hello World!”));
  132.     CHK_SSL(err);
  133.    
  134.     err = SSL_read(ssl, buf, sizeof(buf)1);
  135.     CHK_SSL(err);
  136.     buf[err] = ;
  137.     printf(“Got %d chars: ‘%s’n, err, buf);
  138.     SSL_shutdown(ssl);    // SSL로 연결된 접속을 해지한다.
  139.    
  140.     /* 할당된 자원을 반환하고 종료한다. */
  141.     close(sd);
  142.     SSL_free(ssl);
  143.     SSL_CTX_free(ctx);
  144.    
  145.     return 0;
  146. }
  147.  
  148.  

Tags: , ,

6 Comments on Openssl을 이용한 암호화 통신

  1. 신입사원 says:

    감사합니다!

  2. 파크종 says:

    감사합니다 !
    파일 받아볼 수 있나요 ?

  3. Soon says:

    안녕하세요 ~ 글 내용 잘 보앗습니다!!

    혹시 rootca 인증서로 체이닝 되어있는 인증서또한
    끝단의 인증서랑 개인키를 넣어도 세션을 맺을 수 있나요??

    기존의 자체 인증서는 SSL연동이 잘 되었는데
    체이닝 되어있는 인증서의 제일 마지막 인증서를 소스처럼 연결하니 Ssl 세션연결이 안되서요ㅠㅠㅠ

    제가 초보라 ㅠ 혹시나 여쭤봅니다 ㅠㅠ

    • pchero says:

      에러 메시지가 어떻게 나오나요? 실행환경과 에러 메시지를 올려주시면 확인하기가 수월합니다. 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.