我在创建openssl服务器/客户端应用程序时遇到问题。现在我已经创建了一个简单的c ++版本,基本上是从我为C看到的例子中复制的
问题是,我总是得到SSL23_GET_SERVER_HELLO:unknown protocol
或SSL3_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;
}
start()
accept_con()
,其中Connection可用于发送内容这里是我的基本主要(您可以看到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
答案 0 :(得分:0)
我实际上犯了一个愚蠢的错误。在我发现这篇文章"SSL23_GET_SERVER_HELLO:unknown protocol" Error Trying to Reach Outlook smtp Server后,我意识到,问题在某个地方完全不同。我忘了做SSL_accept
,所以实际的SSL部分根本没有运行。