我無法創建一個OpenSSL的服務器/客戶端應用程序。現在我已經創建了一個簡單的C++版本,這基本上是從我看到C.
存在的問題是一個例子複製,即我總是得到要麼SSL23_GET_SERVER_HELLO:unknown protocol
或SSL3_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;
}
- 調用構造與端口,certFile中和密鑰文件
- 運行
start()
- 運行
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
大概HTTP服務,而不是HTTPS。您需要顯示更多的服務器代碼,包括加載私鑰和證書,直至接受。您還需要聲明正在使用的OpenSSL版本。使用'netcat'來查看你正在使用的是什麼。它將是純文本或隨機字符。另請參閱OpenSSL wiki上的[SSL/TLS Client](https://wiki.openssl.org/index.php/SSL/TLS_Client)。他們在wiki上也有一個服務器示例。但它並不令人印象深刻。 – jww
嘗試獲取tcpdump。這應該表明一些事情。 – Prabhu