openssl 서버/클라이언트 응용 프로그램을 만드는 데 문제가 있습니다. 지금은 기본적으로 C에서 본 예제에서 복사 한 간단한 C++ 버전을 만들었습니다.
문제는 SSLV23 또는 TLSv1_2를 메서드로 사용하는지 여부에 따라 항상 SSL23_GET_SERVER_HELLO:unknown protocol
또는 SSL3_GET_RECORD:wrong version number
중 하나가 발생한다는 것입니다. 여기 읽어 Check Server security protocol using openssl를, 내가 지금처럼 제외 옵션 SSLv23를 사용하는 suposed있어 것을 : 설명 된 바와 같이 나는 unknown protocol
오류를 받고 있어요 때문에이 보이지 않는다"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();
}
그러나 작동 할 수 있습니다. I는 다음과 같은 명령을 사용하고있어 그것을 테스트 :
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;
}
- 전화 포트, certfile 및 키 파일
- 실행
start()
- 실행
accept_con()
와 생성자가 연결 사용할 수 있습니다 물건을 보내려면
내 기본 홈페이지 (당신은 성공적으로 생성 된 연결로 위의 코드와 ParsedConnection로 AdvancedServer을 볼 수 있습니다) :
#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
아마도 HTTPS가 아닌 HTTP를 제공하고있을 것입니다. 수락 할 때까지 개인 키와 인증서를로드하는 것을 포함하여 더 많은 서버 코드를 표시해야합니다. 또한 사용중인 OpenSSL 버전을 명시해야합니다. 'netcat'을 사용하여 사용중인 것을보십시오. 일반 텍스트 또는 임의의 문자가됩니다. OpenSSL 위키에서 [SSL/TLS 클라이언트] (https://wiki.openssl.org/index.php/SSL/TLS_Client)를 참조하십시오. 그들은 위키에 서버 예제를 가지고 있습니다. 그러나 인상적이지 않습니다. – jww
tcpdump를 사용해보십시오. 그게 뭔가를 나타낼 것입니다. – Prabhu