간단한 소켓을 SSL 소켓으로 전환


115

소켓 ( '클라이언트'와 '서버')을 사용하는 간단한 C 프로그램을 작성했습니다. (UNIX / Linux 사용)

서버 측은 단순히 소켓을 만듭니다.

sockfd = socket(AF_INET, SOCK_STREAM, 0);

그런 다음이를 sockaddr에 바인딩합니다.

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

그리고 듣고 (그리고 받아들이고 읽습니다) :

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
read(newsockfd,buffer,255);

클라이언트는 소켓을 만든 다음 여기에 씁니다.

이제이 간단한 연결을 가장 평범하고 가장 목가적이고 간결하고 가장 빠른 방법으로 SSL 연결로 변환하고 싶습니다.

내 프로젝트 에 OpenSSL 을 추가하려고했지만 원하는 것을 구현하는 쉬운 방법을 찾을 수 없습니다.


특히 SSL이 아닌 "보안 연결"을 찾고 있다면 애플리케이션 외부에있는 proxychains.sourceforge.net 과 같은 것을 살펴보고 SSH 연결을 통해 트래픽을 전송하도록 설정할 수 있습니다. 인 애플리케이션 SSL에 관한 한 OpenSSL은 SSL / TLS의 작동 방식을 이해하면 매우 쉽습니다. 대안을 원하면 yaSSL 또는 gnuTLS를 사용해보십시오.
Borealid 2011 년

3
'쉬운 방법'을 정의하십시오. OpenSSl은 C 프로그래머를위한 표준입니다. 만약 당신이 그것에 어려움이 있다면 그것에 대해 물어봐야합니다.
Marquis of Lorne 2013

이 항목을 확인하십시오. OpenSSL 프로그래밍 소개 (Par t I) . 파트 II는 나에게 너무 진보되고 어렵습니다. 그러나 part2는 살펴볼 가치가 있습니다.
Rick은

또한 OpenSSL API로 보안 프로그래밍을 확인하십시오 . 그러나 Openssl이 얼마나 나쁜지에 대한 의견과 시도해 볼만한 다른 대안에 대한 의견을 들었습니다.
Rick은

또 다른 옵션은와 같은 외부 SSL 래퍼 도구를 사용하는 것입니다 stunnel. stunnel4패키지는 데비안 기반 배포판에 있으며 사용하기 쉽습니다. 서버에 적절한 SSL 지원을 추가하는 것에 비해 몇 가지 제한 사항이 있지만 빠른 솔루션에 적합 할 수 있습니다. 나는 stunnel이 UNIX 소프트웨어 도구 접근 방식에 적합하기 때문에 좋아합니다.
Sam Watkins

답변:


150

OpenSSL을 사용할 때 몇 가지 단계가 있습니다. 개인 키가있는 인증서를 포함 할 수있는 SSL 인증서가 있어야합니다. 인증서의 정확한 위치를 지정해야합니다 (이 예에서는 루트에 있음). 좋은 튜토리얼이 많이 있습니다.

일부는 다음을 포함합니다.

#include <openssl/applink.c>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

OpenSSL을 초기화해야합니다.

void InitializeSSL()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void DestroySSL()
{
    ERR_free_strings();
    EVP_cleanup();
}

void ShutdownSSL()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}

이제 대부분의 기능에 대해 설명합니다. 연결에 while 루프를 추가 할 수 있습니다.

int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}

그러면 다음을 사용하여 읽거나 쓸 수 있습니다.

SSL_read(cSSL, (char *)charBuffer, nBytesToRead);
SSL_write(cSSL, "Hi :3\n", 6);

업데이트SSL_CTX_new위해 귀하의 요구에 가장 잘 맞는 대신에, 보안의 최신 버전을 지원하는 TLS 방법으로 호출해야합니다 SSLv23_server_method(). 참조 : OpenSSL SSL_CTX_new 설명

TLS_method (), TLS_server_method (), TLS_client_method (). 이는 범용 버전 유연성 SSL / TLS 방법입니다. 사용되는 실제 프로토콜 버전은 클라이언트와 서버가 상호 지원하는 가장 높은 버전으로 협상됩니다. 지원되는 프로토콜은 SSLv3, TLSv1, TLSv1.1, TLSv1.2 및 TLSv1.3입니다.


9
내가 생각했던 것만 큼 "간단"하지는 않지만 마침내 (하나님 감사합니다!) 몇 가지 코드가 보입니다. 크로스 플랫폼입니까 아니면 유닉스 / 유닉스 계열 시스템 용입니까?
juliomalegria

3
arm, linux 및 windows와 같은 여러 플랫폼에서 유사한 코드를 사용했습니다.
CaptainBli

2
마지막 if은 잘못되었습니다. 그래야만 if (ssl_err <= 0) {오류입니다. 성공, "제어 된 실패"및 "치명적인 실패"에 대해 SSL_accept()반환합니다 . 매뉴얼 페이지를 참조하십시오. 10-1
Jite 2014-08-25

2
또한를 SSL_CTX_set_tmp_dh[_callback]()호출 하지 않으면 DH 암호가 작동 하지 않습니다. 그냥 aNULL 암호가 경고 번호 (40)를없이하지 작업, 생산하는 것을 어렵게 발견
로마 Dmitrienko을

5
@DevNull SSLv23_server_method()서버가 SSLv2 및 v3을 이해하고 현재 사용되지 않음을 나타냅니다. TLS 1.1 및 1.2를 지원하려면 해당 메서드를 TLS_server_method(). 소스
ezPaint

17

OpenSSL은 매우 어렵습니다. 협상을 정확하게 수행하지 않으면 실수로 모든 보안을 포기하기 쉽습니다. (Heck, 저는 curl이 OpenSSL 경고를 정확하게 읽지 못하고 일부 사이트와 대화 할 수없는 버그에 개인적으로 물었습니다.)

정말 빠르고 간단하게하고 싶다면 프로그램 앞에 스터드 를 넣어 하루에 전화하세요. 다른 프로세스에서 SSL을 사용한다고해서 속도가 느려지지 않습니다. http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html


11
이것은 실용적인 대답이지만 실제로 질문에 대한 대답은 아닙니다.
Swiss

4
STUD 2016 포기 된 추가 정보는 권장 github.com/varnish/hitch
찰스

7

나 같은 다른 사람 :

한때 디렉토리의 SSL 소스 demos/ssl/에 C ++의 예제 코드가있는 예제가있었습니다. 이제 기록을 통해서만 사용할 수 있습니다 : https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

아마도 작동하는 버전을 찾아야 할 것입니다. 저는 원래이 답변을 2015 년 11 월 6 일에 게시했습니다. 그리고 소스를 편집해야했습니다.

인증서 : .pem in demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps


-1

여기 내 예제 ssl 소켓 서버 스레드 (다중 연결) https://github.com/breakermind/CppLinux/blob/master/QtSslServerThreads/breakermindsslserver.cpp

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <iostream>

#include <breakermindsslserver.h>

using namespace std;

int main(int argc, char *argv[])
{
    BreakermindSslServer boom;
    boom.Start(123,"/home/user/c++/qt/BreakermindServer/certificate.crt", "/home/user/c++/qt/BreakermindServer/private.key");
    return 0;
}

SO 게시물에 직접 솔루션을 포함하십시오.
Maciej Jureczko 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.