2012-07-26 1 views
1

SSL 클라이언트/서버 예 : http://simplestcodings.blogspot.com.br/2010/08/secure-server-client-using-openssl-in-c.html을 사용하여 SSLv3을 사용하여 보안 연결을 만들려고합니다. 성공하지 못했습니다.내 서버가 항상 "인증서 없음"으로 응답하는 이유는 무엇입니까?

클라이언트 측에서 인증서를로드하려고 클라이언트를 변경하고 서버 예제에있는 LoadCertificates 함수를 추가했습니다. this tutorial 다음에 인증서를 만들었습니다.

제 문제는 서버에 연결할 때 클라이언트 쪽에서 서버 인증서에 대한 정보를 볼 수 있지만 서버가 클라이언트 인증서 정보를로드하지 않는다는 것입니다.

//SSL-Client.c 
#include <stdio.h> 
#include <errno.h> 
#include <unistd.h> 
#include <malloc.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <resolv.h> 
#include <netdb.h> 
#include <openssl/ssl.h> 
#include <openssl/err.h> 

#define FAIL -1 

    //Added the LoadCertificates how in the server-side makes.  
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile) 
{ 
/* set the local certificate from CertFile */ 
    if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* set the private key from KeyFile (may be the same as CertFile) */ 
    if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* verify private key */ 
    if (!SSL_CTX_check_private_key(ctx)) 
    { 
     fprintf(stderr, "Private key does not match the public certificate\n"); 
     abort(); 
    } 
} 

int OpenConnection(const char *hostname, int port) 
{ int sd; 
    struct hostent *host; 
    struct sockaddr_in addr; 

    if ((host = gethostbyname(hostname)) == NULL) 
    { 
     perror(hostname); 
     abort(); 
    } 
    sd = socket(PF_INET, SOCK_STREAM, 0); 
    bzero(&addr, sizeof(addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_port = htons(port); 
    addr.sin_addr.s_addr = *(long*)(host->h_addr); 
    if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0) 
    { 
     close(sd); 
     perror(hostname); 
     abort(); 
    } 
    return sd; 
} 

SSL_CTX* InitCTX(void) 
{ SSL_METHOD *method; 
    SSL_CTX *ctx; 

    OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ 
    SSL_load_error_strings(); /* Bring in and register error messages */ 
    method = SSLv3_client_method(); /* Create new client-method instance */ 
    ctx = SSL_CTX_new(method); /* Create new context */ 
    if (ctx == NULL) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    return ctx; 
} 

void ShowCerts(SSL* ssl) 
{ X509 *cert; 
    char *line; 

    cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */ 
    if (cert != NULL) 
    { 
     printf("Server certificates:\n"); 
     line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 
     printf("Subject: %s\n", line); 
     free(line);  /* free the malloc'ed string */ 
     line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 
     printf("Issuer: %s\n", line); 
     free(line);  /* free the malloc'ed string */ 
     X509_free(cert);  /* free the malloc'ed certificate copy */ 
    } 
    else 
     printf("No certificates.\n"); 
} 

int main(int count, char *strings[]) 
{ SSL_CTX *ctx; 
    int server; 
    SSL *ssl; 
    char buf[1024]; 
    int bytes; 
    char *hostname, *portnum; 
    char CertFile[] = "/home/myCA/cacert.pem"; 
    char KeyFile[] = "/home/myCA/private/cakey.pem"; 

    SSL_library_init(); 
hostname=strings[1]; 
portnum=strings[2]; 

    ctx = InitCTX(); 
    LoadCertificates(ctx, CertFile, KeyFile); 
    server = OpenConnection(hostname, atoi(portnum)); 
    ssl = SSL_new(ctx);  /* create new SSL connection state */ 
    SSL_set_fd(ssl, server); /* attach the socket descriptor */ 
    if (SSL_connect(ssl) == FAIL) /* perform the connection */ 
     ERR_print_errors_fp(stderr); 
    else 
    { char *msg = "Hello???"; 

     printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); 
     ShowCerts(ssl);  /* get any certs */ 
     SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */ 
     bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */ 
     buf[bytes] = 0; 
     printf("Received: \"%s\"\n", buf); 
     SSL_free(ssl);  /* release connection state */ 
    } 
    close(server);   /* close socket */ 
    SSL_CTX_free(ctx);  /* release context */ 
    return 0; 
} 

그리고 서버 :

여기 내 클라이언트 코드

//SSL-Server.c 
#include <errno.h> 
#include <unistd.h> 
#include <malloc.h> 
#include <string.h> 
#include <arpa/inet.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <resolv.h> 
#include "openssl/ssl.h" 
#include "openssl/err.h" 

#define FAIL -1 

int OpenListener(int port) 
{ int sd; 
    struct sockaddr_in addr; 

    sd = socket(PF_INET, SOCK_STREAM, 0); 
    bzero(&addr, sizeof(addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_port = htons(port); 
    addr.sin_addr.s_addr = INADDR_ANY; 
    if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0) 
    { 
     perror("can't bind port"); 
     abort(); 
    } 
    if (listen(sd, 10) != 0) 
    { 
     perror("Can't configure listening port"); 
     abort(); 
    } 
    return sd; 
} 

SSL_CTX* InitServerCTX(void) 
{ SSL_METHOD *method; 
    SSL_CTX *ctx; 

    OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ 
    SSL_load_error_strings(); /* load all error messages */ 
    method = SSLv3_server_method(); /* create new server-method instance */ 
    ctx = SSL_CTX_new(method); /* create new context from method */ 
    if (ctx == NULL) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    return ctx; 
} 

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile) 
{ 
/* set the local certificate from CertFile */ 
    if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* set the private key from KeyFile (may be the same as CertFile) */ 
    if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* verify private key */ 
    if (!SSL_CTX_check_private_key(ctx)) 
    { 
     fprintf(stderr, "Private key does not match the public certificate\n"); 
     abort(); 
    } 
} 

void ShowCerts(SSL* ssl) 
{ X509 *cert; 
    char *line; 

    cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */ 
    if (cert != NULL) 
    { 
     printf("Server certificates:\n"); 
     line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 
     printf("Subject: %s\n", line); 
     free(line); 
     line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 
     printf("Issuer: %s\n", line); 
     free(line); 
     X509_free(cert); 
    } 
    else 
     printf("No certificates.\n"); 
} 

void Servlet(SSL* ssl) /* Serve the connection -- threadable */ 
{ char buf[1024]; 
    char reply[1024]; 
    int sd, bytes; 
    const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n"; 

    if (SSL_accept(ssl) == FAIL)  /* do SSL-protocol accept */ 
     ERR_print_errors_fp(stderr); 
    else 
    { 
     ShowCerts(ssl);  /* get any certificates */ 
     bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */ 
     if (bytes > 0) 
     { 
      buf[bytes] = 0; 
      printf("Client msg: \"%s\"\n", buf); 
      sprintf(reply, HTMLecho, buf); /* construct reply */ 
      SSL_write(ssl, reply, strlen(reply)); /* send reply */ 
     } 
     else 
      ERR_print_errors_fp(stderr); 
    } 
    sd = SSL_get_fd(ssl);  /* get socket connection */ 
    SSL_free(ssl);   /* release SSL state */ 
    close(sd);   /* close connection */ 
} 

int main(int count, char *strings[]) 
{ SSL_CTX *ctx; 
    int server; 
    char *portnum; 

    char CertFile[] = "/home/myCA/cacert.pem"; 
    char KeyFile[] = "/home/myCA/private/cakey.pem"; 

    SSL_library_init(); 

    portnum = strings[1]; 
    ctx = InitServerCTX();  /* initialize SSL */ 
    LoadCertificates(ctx, CertFile, KeyFile); /* load certs */ 
    server = OpenListener(atoi(portnum)); /* create server socket */ 
    while (1) 
    { struct sockaddr_in addr; 
     socklen_t len = sizeof(addr); 
     SSL *ssl; 

     int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */ 
     printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 
     ssl = SSL_new(ctx);    /* get new SSL state with context */ 
     SSL_set_fd(ssl, client);  /* set connection socket to SSL state */ 
     Servlet(ssl);   /* service connection */ 
    } 
    close(server);   /* close server socket */ 
    SSL_CTX_free(ctx);   /* release context */ 
} 

편집 : 다음과 같이 지금 서버에 LoadCertificates을 변경 한

. LoadCertificates에서 이러한 변경 후

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile) 
{ 
    //New lines 
    if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1) 
     ERR_print_errors_fp(stderr); 

    if (SSL_CTX_set_default_verify_paths(ctx) != 1) 
     ERR_print_errors_fp(stderr); 
    //End new lines 

    /* set the local certificate from CertFile */ 
    if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* set the private key from KeyFile (may be the same as CertFile) */ 
    if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    /* verify private key */ 
    if (!SSL_CTX_check_private_key(ctx)) 
    { 
     fprintf(stderr, "Private key does not match the public certificate\n"); 
     abort(); 
    } 

    //New lines 
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); 
    SSL_CTX_set_verify_depth(ctx, 4); 
    //End new lines 
} 

, 내가 서버를 시작하고 클라이언트에서 연결을 할 때, 그것은 서버의 인증서에 대한 정보를 볼 수 있으며, 서버가 이제 클라이언트의 인증서에 대한 정보를로드하지만, 프로토콜 , Wireshar에 의해 보인대로, 변화하지 않는다.

사실, 서버 측과 클라이언트 측 모두 인증서를 볼 수 있지만 Wireshark의 연결을 보면 프로토콜 SSLv3 (SSLv23, SSLv2, SSLv1)이 작동하지 않는 것으로 나타납니다. 나는 그 문제가 무엇인지 이해하지 못한다. Wireshark는 프로토콜 TCP 또는 IPA를 보여주고 IPA 패킷의 경우 정보는 항상 RSL Malformed Packet입니다. 존재하는 경우

+0

문제는, 완전히 다른 질문처럼 들리 (또는 2 개를 조합) . 이 경우 다른 질문을하는 것이 좋습니다. 하지만 [이 답변] (http://stackoverflow.com/a/10532296/372643)에서 설명한 것과 같은 문제가 발생하므로 필요하지 않습니다. – Bruno

+0

다시 한 번, 초기 텍스트를 변경하여 다시 편집하지 마십시오. 질문에 대한 추가 사항이 있다면 끝 부분에 놓으십시오. 최근 변경 사항 (10 분 전)에 이어 이제는 대답이 문제와 관련이 없습니다. (이전에 언급 한 내용에서 [this] (http://stackoverflow.com/a/10532296/372643)을 읽어보십시오.) – Bruno

+0

새로운 문제를 발견하여 질문을 변경했습니다.첫 번째 문제는 서버 측에서 클라이언트 인증서를로드하지 않았고 해결 한 후에 프로토콜을 테스트했으며 통신 TLS/SSL처럼 작동하지 않는다는 것입니다. JAVA에서 SSL을 사용하는 소켓 예제 클라이언트와 서버를 사용하는 경우 wireshark는/info SSLv3/SSLv23 프로토콜을 보여 주며 C/C++을 사용하여 수행하려는 예제에는 동일한 동작이 없습니다. 문제는 많은 문제가 있으며 모두 해결하고 싶습니다. –

답변

3

http://www.openssl.org/docs/ssl/SSL_get_peer_certificate.html

에서 인해 프로토콜 정의하려면 TLS/SSL 서버는 항상하는 인증서를 보내드립니다. 클라이언트는 이 서버에 명시 적으로 요청한 경우에만 인증서를 보냅니다 ( SSL_CTX_set_verify (3) 참조).

서버 같은 것을 호출해야합니다 :

SSL_CTX_set_verify(SSL_get_SSL_CTX(ssl), SSL_VERIFY_PEER, NULL); 

전에 : 당신이 지금 그것을 편집 한으로

if (SSL_accept(ssl) == FAIL) 
+0

가 호출 사이트를 변경하도록 편집되었습니다. –

+0

고맙습니다 .. 답변을 찾았 기 때문에 "Network Security with OpenSSL"이라는 책인 server2.c를 발견했습니다. –

+0

예제를보고 코드를 변경했습니다. 감사합니다! –

관련 문제