Biến một ổ cắm đơn giản thành một ổ cắm SSL


115

Tôi đã viết các chương trình C đơn giản, đang sử dụng các ổ cắm ('máy khách' và 'máy chủ'). (Sử dụng UNIX / Linux)

Phía máy chủ chỉ cần tạo một ổ cắm:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

Và sau đó liên kết nó với sockaddr:

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

Và lắng nghe (và chấp nhận và đọc):

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

Máy khách tạo ổ cắm, và sau đó ghi vào nó.

Bây giờ, tôi muốn chuyển đổi kết nối đơn giản này thành kết nối SSL, theo cách dễ hiểu nhất, bình dị nhất, gọn gàng nhất và nhanh chóng nhất.

Tôi đã cố gắng thêm OpenSSL vào dự án của mình, nhưng tôi không thể tìm thấy cách dễ dàng để thực hiện những gì tôi muốn.


Nếu bạn đang tìm kiếm "một kết nối an toàn" hơn là SSL nói riêng, bạn có thể xem một cái gì đó như proxychains.sourceforge.net nằm bên ngoài ứng dụng của bạn và thiết lập để gửi lưu lượng truy cập qua kết nối SSH. Đối với SSL trong ứng dụng, OpenSSL khá dễ dàng nếu bạn hiểu cách SSL / TLS hoạt động. Nếu bạn muốn thay thế, hãy thử yaSSL hoặc gnuTLS.
Borealid

3
Xác định 'cách dễ dàng'. OpenSSl là tiêu chuẩn cho các lập trình viên C. Nếu bạn gặp khó khăn với nó, bạn nên hỏi về điều đó.
Marquis of Lorne,

Kiểm tra phần này Giới thiệu về Lập trình OpenSSL (Phần I) . Phần II quá nâng cao và khó đối với tôi. Nhưng phần 2 rất đáng để xem.
Rick

Cũng kiểm tra Lập trình an toàn với API OpenSSL . Nhưng tôi vừa nghe ý kiến ​​về việc Openssl tệ như thế nào và các lựa chọn thay thế khác đáng để thử.
Rick

Một lựa chọn khác là sử dụng một công cụ wrapper SSL bên ngoài như stunnel, các stunnel4gói là trong distro Debian-based và thật dễ dàng để sử dụng. Có một số hạn chế so với việc thêm hỗ trợ SSL thích hợp trong máy chủ của bạn, nhưng nó có thể tốt cho một giải pháp nhanh chóng. Tôi thích stunnel vì nó có vẻ phù hợp với cách tiếp cận công cụ phần mềm UNIX.
Sam Watkins

Câu trả lời:


150

Có một số bước khi sử dụng OpenSSL. Bạn phải có chứng chỉ SSL được tạo, chứng chỉ này có thể chứa chứng chỉ với khóa cá nhân, hãy chắc chắn chỉ định vị trí chính xác của chứng chỉ (ví dụ này có nó trong thư mục gốc). Có rất nhiều hướng dẫn tốt trên mạng.

Một số bao gồm:

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

Bạn sẽ cần khởi tạo 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);
}

Bây giờ cho phần lớn các chức năng. Bạn có thể muốn thêm một vòng lặp trong khi kết nối.

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();
}

Sau đó, bạn có thể đọc hoặc viết bằng:

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

Cập nhật Sự SSL_CTX_newnên được gọi là phương pháp TLS phù hợp nhất với nhu cầu của bạn để hỗ trợ các phiên bản mới hơn của an ninh, thay vì SSLv23_server_method(). Xem: Mô tả OpenSSL SSL_CTX_new

TLS_method (), TLS_server_method (), TLS_client_method (). Đây là các phương pháp SSL / TLS phiên bản linh hoạt có mục đích chung . Phiên bản giao thức thực tế được sử dụng sẽ được thương lượng với phiên bản cao nhất được hỗ trợ lẫn nhau bởi máy khách và máy chủ. Các giao thức được hỗ trợ là SSLv3, TLSv1, TLSv1.1, TLSv1.2 và TLSv1.3.


9
không quá "đơn giản" như tôi nghĩ, nhưng cuối cùng (tạ ơn Chúa!) Tôi thấy một số mã. Đây là nền tảng chéo hay chỉ dành cho các hệ thống giống unix / unix?
juliomalegria

3
Tôi đã sử dụng mã tương tự trên nhiều nền tảng: arm, linux và windows.
CaptainBli

2
Cuối cùng iflà sai mặc dù. Nó chỉ nên xảy ra if (ssl_err <= 0) {sau đó là một lỗi. SSL_accept()trả 1về thành công, 0về "thất bại có kiểm soát" và -1"thất bại chết người". Xem trang người đàn ông.
Jite

2
Ngoài ra, mật mã DH sẽ không hoạt động nếu SSL_CTX_set_tmp_dh[_callback]()không được gọi. Chỉ cần phát hiện ra cách cứng mà aNULL mật mã sẽ không làm việc mà không có nó, tạo ra cảnh báo số 40.
La Mã Dmitrienko

5
@DevNull Trạng SSLv23_server_method()thái rằng máy chủ hiểu SSLv2 và v3 và hiện không được dùng nữa. Để hỗ trợ TLS 1.1 và 1.2, hãy thay thế phương pháp đó bằng TLS_server_method(). nguồn
ezPaint

17

OpenSSL khá khó. Thật dễ dàng vô tình vứt bỏ tất cả bảo mật của bạn bằng cách không thực hiện thương lượng một cách chính xác. (Rất tiếc, cá nhân tôi đã bị cắn bởi một lỗi mà curl không đọc chính xác các cảnh báo OpenSSL và không thể nói chuyện với một số trang web.)

Nếu bạn thực sự muốn nhanh chóng và đơn giản, hãy đặt stud trước chương trình của bạn và gọi nó là một ngày. Có SSL trong một quy trình khác sẽ không làm chậm bạn: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html


11
Đây là một câu trả lời thực tế, nhưng nó không thực sự trả lời câu hỏi.
Thụy Sĩ

4
STUD đã bị bỏ rơi vào năm 2016. Readme đề xuất: github.com/varnish/hitch
Charles

7

Đối với những người khác như tôi:

Đã từng có một ví dụ trong nguồn SSL trong thư mục demos/ssl/với mã ví dụ trong C ++. Hiện nó chỉ khả dụng qua lịch sử: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Bạn có thể sẽ phải tìm một phiên bản làm việc, ban đầu tôi đã đăng câu trả lời này vào ngày 6 tháng 11 năm 2015. Và tôi đã phải chỉnh sửa nguồn - không nhiều.

Chứng chỉ: .pem trong demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps


-1

Đây là chuỗi máy chủ ssl ví dụ của tôi (nhiều kết nối) 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;
}

Vui lòng bao gồm giải pháp trực tiếp trong bài đăng SO của bạn.
Maciej Jureczko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.