//      SSL_Client.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <arpa/inet.h>

#define PORT 7921
#define SERVER_ADDRESS “127.0.0.1”

int main(int argc, char** argv)
{
    char *server_name = SERVER_ADDRESS;
    unsigned short port = PORT;
    
    unsigned int addr;
    struct sockaddr_in server_add;
    struct hostent *host;
    
    int conn_socket;
    int socket_type = SOCK_STREAM;
    int retval;
    
    char *retString = NULL;
    
    const char *currentCipher;
    char buffer[1000];
    char message[100] = “이것은 클라이언트가 보내는 메시지입니다.”;
    
    // SSL 구조체 생성
    SSL_METHOD *meth;
    SSL_CTX *ctx;
    SSL *ssl;
    X509 *server_cert;
    
    BIO *errBIO;
    
    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] 입니다!n”, server_name);
        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, “소켓 생성 에러!n”);
        exit(1);
    }
    
    printf(“[%s] 서버에 연결중…n”, server_name);
    if(connect(conn_socket, (struct sockaddr*)&server_add, sizeof(server_add)) == -1) {
        fprintf(stderr, “connect 에러!n”);
        exit(1);
    }
    
    // 세션 키를 만들기 위한 랜덤 수를 위한 Seed 공급
    printf(“랜덤 수 생성중…n”);
    RAND_status();
    printf(“랜덤 수 생성 완료!b”);
    
    ssl = SSL_new(ctx);
    if(ssl == NULL) {
        BIO_printf(errBIO, “SSL 생성 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    SSL_set_fd(ssl, conn_socket);
    retval = SSL_connect(ssl);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL connect 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    currentCipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
    printf(“SSL 연결, 사용 알고리즘 파라메터: [%s]n”, currentCipher);
    
    server_cert = SSL_get_peer_certificate(ssl);
    if(server_cert == NULL) {
        BIO_printf(errBIO, “서버 인증서를 받을 수 없음.”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    printf(“Server certificate:n”);
    
    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: %sn”, 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: %sn”, retString);
    free(retString);
    
    X509_free(server_cert);
    
    retval = SSL_write(ssl, “hi!!_from client”, strlen(“hi!!_from client”));
    if(retval == -1) {
        BIO_printf(errBIO, “SSL write 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    retval = SSL_read(ssl, buffer, sizeof(buffer) – 1);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL read 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    buffer[retval] = ‘’;
    printf(“서버로부터 데이터 전송: [%s], 길이:%dn”, buffer, retval);
    
    SSL_shutdown(ssl);
    
    close(conn_socket);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    
    return 0;
}
XUA8jQk84Z.c

Tags: ,

1 Comment on OpenlSSL – SSL 통신 클라이언트

  1. 조영욱 says:

    저는 지금 서버와 클라이언트를 만들고 있습니다.
    그런데 조심해야 하는 정보를 주고 받아야 돌아가는 네트웍을 구상하고 있습니다.
    공인 인증서로 위와 같은 방법을 구사할 수 있는 자료가 있는지 문의드립니다.
    웹프로그램이 아닙니다.
    좀 도와 주십시요. 감사합니다.

Leave a Reply

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