错误" SSL23_GET_SERVER_HELLO:未知协议"

时间:2016-09-19 21:42:35

标签: c++ openssl version tls1.2

我在创建openssl服务器/客户端应用程序时遇到问题。现在我已经创建了一个简单的c ++版本,基本上是从我为C看到的例子中复制的 问题是,我总是得到SSL23_GET_SERVER_HELLO:unknown protocolSSL3_GET_RECORD:wrong version number,具体取决于我是使用SSLv23还是TLSv1_2作为方法。我在这里读到:Check Server security protocol using openssl,我倾向于使用SSLv23并排除这样的选项:

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)
---

其中第二行在两个命名的错误消息之间切换,具体取决于方法变量的状态。

有什么东西,我完全被误解了,或者问题位于完全不同的地方?

修改 其余的服务器代码:

#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. 使用port,certfile和keyfile
  2. 调用构造函数
  3. 运行start()
  4. 运行accept_con(),其中Connection可用于发送内容
  5. 这里是我的基本主要(您可以看到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转储中看到的是,客户端和服务器至少发送Acknowlagment包,这里是一次连接尝试的输出

    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
    

1 个答案:

答案 0 :(得分:0)

我实际上犯了一个愚蠢的错误。在我发现这篇文章"SSL23_GET_SERVER_HELLO:unknown protocol" Error Trying to Reach Outlook smtp Server后,我意识到,问题在某个地方完全不同。我忘了做SSL_accept,所以实际的SSL部分根本没有运行。