2016-09-19 175 views
0

我無法創建一個OpenSSL的服務器/客戶端應用程序。現在我已經創建了一個簡單的C++版本,這基本上是從我看到C.
存在的問題是一個例子複製,即我總是得到要麼SSL23_GET_SERVER_HELLO:unknown protocolSSL3_GET_RECORD:wrong version number取決於我是否使用SSLv23或TLSv1_2作爲方法。我讀到這裏:Check Server security protocol using openssl,那我suposed使用SSLv23與排除的選項,如下所示:但是錯誤「SSL23_GET_SERVER_HELLO:未知協議」

SSL_library_init(); 
SSL_METHOD *method; 
SSL_CTX *ctx; 
OpenSSL_add_all_algorithms();  /* load & register all cryptos, etc. */ 
SSL_load_error_strings();   /* load all error messages */ 
method = const_cast<SSL_METHOD*>(TLSv1_2_server_method());  /* create new server-method instance */ 
if (method == NULL){ 
    exit(0); 
} 
ctx = SSL_CTX_new(method);   /* create new context from method */ 

const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; 
SSL_CTX_set_options(ctx, flags); 

if (ctx == NULL) 
{ 
    ERR_print_errors_fp(stderr); 
    abort(); 
} 

這似乎並不工作,所描述的,因爲我得到了unknown protocol錯誤。我使用下面的命令來測試它:

openssl s_client -connect localhost:5002 -tls1_2 
openssl s_client -connect localhost:5002 -tls1_1 
openssl s_client -connect localhost:5002 -tls1 

的響應總是:

CONNECTED(00000003) 
140310636811928:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong 

version number:s3_pkt.c:362: 
--- 
no peer certificate available 
--- 
No client certificate CA names sent 
--- 
SSL handshake has read 5 bytes and written 7 bytes 
--- 
New, (NONE), Cipher is (NONE) 
Secure Renegotiation IS NOT supported 
Compression: NONE 
Expansion: NONE 
No ALPN negotiated 
SSL-Session: 
    Protocol : TLSv1 
    Cipher : 0000 
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: 
    Key-Arg : None 
    PSK identity: None 
    PSK identity hint: None 
    SRP username: None 
    Start Time: 1474320796 
    Timeout : 7200 (sec) 
    Verify return code: 0 (ok) 
--- 

其中第二行中的兩個命名錯誤消息之間切換,這取決於該方法變量的狀態。

有什麼事,我完全missunderstood或位於某處完全不同的問題?

編輯: 服務器代碼的其餘部分:

#include <stdio.h> 
#include <unistd.h> 
#include <malloc.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <resolv.h> 
#include <openssl/ssl.h> 
#include <openssl/err.h> 



// Own libs 
#include "SSLServer.h" 
#include "Logger.h" 
#include "Connection.h" 


#define SERVER_LOG "./log/server.log" 
#define CONNECTION_LOG "./log/server.log" 

#define FATAL 0 
#define ERROR 1 
#define WARNING 2 
#define INFO 3 
#define DEBUG 4 
#define LOG_LEVEL 5 

using namespace std; 

#ifndef CLI_STRUCT 
#define CLI_STRUCT 
struct cli{ 
    int fdsock; 
    struct sockaddr *cli_addr; 
    socklen_t clilen; 
}; 
#endif 

// name is program 
string SSLServer::convert_int_to_string(int n){ 
    std::ostringstream ss; 
    int num = n; 
    ss << num; 
    return ss.str(); 
} 


SSL_CTX* SSLServer::InitServerCTX(void){ 
    SSL_library_init(); 
    SSL_METHOD *method; 
    SSL_CTX *ctx; 
    OpenSSL_add_all_algorithms();  /* load & register all cryptos, etc. */ 
    SSL_load_error_strings();   /* load all error messages */ 
    method = const_cast<SSL_METHOD*>(SSLv23_server_method());  /* create new server-method instance */ 
    if (method == NULL){ 
     exit(0); 
    } 
    ctx = SSL_CTX_new(method);   /* create new context from method */ 

    const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; 
    SSL_CTX_set_options(ctx, flags); 

    if (ctx == NULL) 
    { 
     ERR_print_errors_fp(stderr); 
     abort(); 
    } 
    return ctx; 
} 

void SSLServer::LoadCertificates(SSL_CTX* ctx, const char* CertFile, const 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(); 
    } 
} 

// Constructor which takes a portno 
SSLServer::SSLServer(unsigned short port, string CertFile, string KeyFile):logger(Logger{SERVER_LOG}){ 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    setFamily(AF_INET); 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    setPort(port); 
    backlog = 3; 
    logger.setLogLevel(LOG_LEVEL); 
    ctx = InitServerCTX(); 
    LoadCertificates(ctx, CertFile.c_str(), KeyFile.c_str()); 
    reload(); 
} 

// Reload all important information in case something changed 
void SSLServer::reload(){ 
    this->sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    int yes = 1; 
    // lose the pesky "Address already in use" error message 
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { 
     perror("setsockopt"); 
     exit(1); 
    } 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
    { 
     string error = "FATAL: could not bind socket! "; 
     error.append(strerror(errno)); 
     logger.log(FATAL, error); 

     exit(1); 
    } 
    state = READY; 
} 
void SSLServer::setLogLevel(int level){ 
    logger.setLogLevel(level); 
} 
// Setter 
void SSLServer::setPort(unsigned short port){ 
    this->portno = port; 

    // Convert portno to needed endian format 
    serv_addr.sin_port = htons(portno); 
} 
void SSLServer::setFamily(short fam){ 
    this->serv_addr.sin_family = fam; 
} 
void SSLServer::setAddr(struct in_addr sin_addr){ 
    this->serv_addr.sin_addr = sin_addr; 
} 

// Start listening to given Port 
void SSLServer::start(){ 
    string start = "start server on port "; 
    if(state == RUNNING){ 
     logger.log(WARNING, "Already running."); 
     return; 
    } 

    // message start port at No 
    start = start.append(convert_int_to_string(portno)); 
    logger.log(2, start); 
    if (listen(sockfd, backlog) < 0){ 
     logger.log(FATAL, "could not start server!"); 
    } 
    logger.log(DEBUG, "server started."); 
    state = RUNNING; 
} 

// Stop Server (may be restarted) 
int SSLServer::stop(){ 
    int fd = sockfd; 
    if (state != RUNNING) { 
     logger.log(WARNING, "Already stopped"); 
     perror("Already stopped"); 
     return 1; 
    } 
    if (fd >= 0) { 
     int err = 1; 
     socklen_t len = sizeof err; 
     if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &len)){ 
      perror("getsocketopt"); 
      return 1; 
     } 
     if (err) errno = err; 
     if (shutdown(fd, SHUT_RDWR) < 0) // secondly, terminate the 'reliable' delivery 
      if (errno != ENOTCONN && errno != EINVAL){ // SGI causes EINVAL 
       perror("shutdown"); 
       return 1; 
      } 

     if (::close(fd) < 0){ // finally call close() 
      perror("close"); 
      return 1; 
     } 

     SSL_CTX_free(ctx); 
     state = STOPPED; 
     return 0; 
    } 
    perror("wrong socket"); 
    return 1; 
} 

void SSLServer::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 SSLServer::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) <= 0)     /* 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 */ 
} 

// accept a connection and return struct cli (in definition; used for accept_con) 
cli SSLServer::accept_cli(){ 
    if(state != RUNNING){ 
     logger.log(FATAL, "Server not running"); 
     exit(1); 
    } 
    struct sockaddr_in addr; 
    socklen_t clilen = sizeof(addr); 
    struct cli ret; 
    logger.log(DEBUG, "wait for client..."); 
    ret.fdsock = accept(sockfd, (struct sockaddr *)&addr, &clilen); 
    if (ret.fdsock == -1){ 
     string msg = "FATAL: "; 
     msg.append(strerror(errno)); 
     logger.log(FATAL, msg); 
     exit(1); 
    } 
    ret.cli_addr = (struct sockaddr *)&addr; 
    ret.clilen = clilen; 
    SSL *ssl = SSL_new(ctx); 
    SSL_set_fd(ssl, ret.fdsock); 

    logger.log(DEBUG, "client added."); 
    return ret; 
} 


// accept a connection an return Connection object 
Connection SSLServer::accept_con(){ 
    fflush(stdout); 
    Connection con(accept_cli()); 
    string msg = con.getIp(); 
    logger.log(DEBUG, msg); 
    return con; 

} 
  1. 調用構造與端口,certFile中和密鑰文件
  2. 運行start()
  3. 運行accept_con(),其中可以使用連接送東西

這裏我的基本主(你可以看到AdvancedServer就像上面的代碼和ParsedConnection爲成功創建的連接):

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <thread> 
#include <unistd.h> 
#include <signal.h> 

#include "SSLServer.h" 
#include "AdvancedServer.h" 
#include "Connection.h" 
#include "ParsedConnection.h" 
#include "ConnectionThread.h" 
#include "SomeClientTest.h" 

static char* cert = "cert.pem"; 
static char* key = "key.pem"; 
AdvancedServer se(5002, cert,key); 
void run(ParsedConnection &con){ 
    sleep(10); 
    con.send("Hi there"); 
    con.close(); 
} 

void ctrl_c(int s){ 

      std::cout << "server returns: " << se.stop() << std::endl; 
      exit(1); 

} 



int main(int argc, char *argv[]){ 
    // The actual server 
    if (argc >= 2){ 
     se = AdvancedServer(atoi(argv[1]), cert, key); 
    } else { 
     std::cout << "usage: " << argv[0] << " <port> <cert> <key> [loglevel]" << std::endl; 
    } 

    if (argc >= 3){ 
     se.setLogLevel(atoi(argv[2])); 
    } 



    struct sigaction sigIntHandler; 

    sigIntHandler.sa_handler = ctrl_c; 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 

    sigaction(SIGINT, &sigIntHandler, NULL); 

    se.start(); 
    //Test ends 


    while(1){ 
     ParsedConnection con = se.accept_con(); 
     ConnectionThread tt; 
     std::thread t(&ConnectionThread::run, &tt, con); 
     t.detach(); 
    } 
    return 0; 
} 

編輯 我只能從TCP轉儲是,客戶端和服務器在看至少發送確認包,這裏是一個連接嘗試的輸出

14:23:30.734757 IP localhost.57954 > localhost.rfe: Flags [S], seq 3307815845, win 43690, options [mss 65495,sackOK,TS val 230050 ecr 0,nop,wscale 7], length 0 
14:23:30.734771 IP localhost.rfe > localhost.57954: Flags [S.], seq 347842069, ack 3307815846, win 43690, options [mss 65495,sackOK,TS val 230050 ecr 230050,nop,wscale 7], length 0 
14:23:30.734784 IP localhost.57954 > localhost.rfe: Flags [.], ack 1, win 342, options [nop,nop,TS val 230050 ecr 230050], length 0 
14:23:30.734907 IP localhost.57954 > localhost.rfe: Flags [P.], seq 1:198, ack 1, win 342, options [nop,nop,TS val 230050 ecr 230050], length 197 
14:23:30.735318 IP localhost.rfe > localhost.57954: Flags [P.], seq 1:25, ack 198, win 350, options [nop,nop,TS val 230050 ecr 230050], length 24 
14:23:30.735334 IP localhost.57954 > localhost.rfe: Flags [.], ack 25, win 342, options [nop,nop,TS val 230050 ecr 230050], length 0 
14:23:30.735359 IP localhost.57954 > localhost.rfe: Flags [P.], seq 198:205, ack 25, win 342, options [nop,nop,TS val 230050 ecr 230050], length 7 
14:23:30.735392 IP localhost.rfe > localhost.57954: Flags [F.], seq 25, ack 205, win 350, options [nop,nop,TS val 230050 ecr 230050], length 0 
14:23:30.735407 IP localhost.rfe > localhost.57954: Flags [R.], seq 26, ack 205, win 350, options [nop,nop,TS val 230050 ecr 230050], length 0 
+0

大概HTTP服務,而不是HTTPS。您需要顯示更多的服務器代碼,包括加載私鑰和證書,直至接受。您還需要聲明正在使用的OpenSSL版本。使用'netcat'來查看你正在使用的是什麼。它將是純文本或隨機字符。另請參閱OpenSSL wiki上的[SSL/TLS Client](https://wiki.openssl.org/index.php/SSL/TLS_Client)。他們在wiki上也有一個服務器示例。但它並不令人印象深刻。 – jww

+0

嘗試獲取tcpdump。這應該表明一些事情。 – Prabhu

回答

相關問題