c++ - C++ Openssl 中的服务器 key 交换

标签 c++ ssl encryption openssl

我在 C++ 项目中使用 openssl。通过我在没有 Serverkey Exchange 的情况下完成的代码握手,我需要这样做。如何将握手过程中的服务器 key 交换添加到我的代码中?

服务器代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  "/home/a.seifpour/Desktop/SSL Tutorial/cert.pem"
#define KEYF  "/home/a.seifpour/Desktop/SSL Tutorial/key.pem"


#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr);     exit(2); }

int main() {
    int err;
    int listen_sd;
    int sd;
    struct sockaddr_in sa_serv;
    struct sockaddr_in sa_cli;
    unsigned int client_len;
    SSL_CTX* ctx;
    SSL* ssl;
    X509* client_cert;
    char* str;
    char buf [4096];
    const SSL_METHOD *meth;

    /* SSL preliminaries. We keep the certificate and key with the     context. */

    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
    meth = TLSv1_2_server_method();
    ctx = SSL_CTX_new(meth);
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(2);
    }

    if (SSL_CTX_load_verify_locations(ctx, CERTF, KEYF) != 1){
        ERR_print_errors_fp(stderr);
    }

    if (SSL_CTX_set_default_verify_paths(ctx) != 1){
        ERR_print_errors_fp(stderr);
    }

    if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <=     0) {
        ERR_print_errors_fp(stderr);
        exit(3);
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)     {
        ERR_print_errors_fp(stderr);
        exit(4);
    }

    if (!SSL_CTX_check_private_key(ctx)) {
        fprintf(stderr, "Private key does not match the certificate     public key\n");
        exit(5);
    }

//    SSL_CTX_set_verify(ctx,SSL_VERIFY_CLIENT_ONCE, 0);

    /* ----------------------------------------------- */
    /* Prepare TCP socket for receiving connections */

    listen_sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(listen_sd, "socket");

    memset(&sa_serv, 0, sizeof (sa_serv));
    sa_serv.sin_family = AF_INET;
    sa_serv.sin_addr.s_addr = INADDR_ANY;
    sa_serv.sin_port = htons(9999); /* Server Port number */

    err = bind(listen_sd, (struct sockaddr*) &sa_serv,
            sizeof (sa_serv));
    CHK_ERR(err, "bind");

    /* Receive a TCP connection. */

    err = listen(listen_sd, 5);
    CHK_ERR(err, "listen");

    client_len = sizeof (sa_cli);
    sd = accept(listen_sd, (struct sockaddr*) &sa_cli, &client_len);
    CHK_ERR(sd, "accept");
    close(listen_sd);

    printf("Connection from %lx, port %x\n",
            sa_cli.sin_addr.s_addr, sa_cli.sin_port);

    /* ----------------------------------------------- */
    /* TCP connection is ready. Do server side SSL. */

    ssl = SSL_new(ctx);
    CHK_NULL(ssl);
    SSL_set_fd(ssl, sd);    

    err = SSL_accept(ssl);
    CHK_SSL(err);

    /* Get the cipher - opt */

    printf("SSL connection using %s\n", SSL_get_cipher(ssl));

    /* Get client's certificate (note: beware of dynamic allocation) -     opt */

    client_cert = SSL_get_peer_certificate(ssl);
    if (client_cert != NULL) {
        printf("Client certificate:\n");

        str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0,     0);
        CHK_NULL(str);
        printf("\t subject: %s\n", str);
        OPENSSL_free(str);

        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0,     0);
        CHK_NULL(str);
        printf("\t issuer: %s\n", str);
        OPENSSL_free(str);

        /* We could do all sorts of certificate verification stuff     here before
           deallocating the certificate. */

        X509_free(client_cert);
    } else
        printf("Client does not have certificate.\n");

    /* DATA EXCHANGE - Receive message and send reply. */

    err = SSL_read(ssl, buf, sizeof (buf) - 1);
    CHK_SSL(err);
    buf[err] = '\0';
    printf("Got %d chars:'%s'\n", err, buf);

    err = SSL_write(ssl, "I hear you.", strlen("I hear you."));
    CHK_SSL(err);

    /* Clean up. */

    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
}
/* EOF - serv.cpp */

客户端代码:

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  "/home/a.seifpour/Desktop/SSL Tutorial/cert.pem"
#define KEYF  "/home/a.seifpour/Desktop/SSL Tutorial/key.pem"

#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr);     exit(2); }

int main() {
    int err;
    int sd;
    struct sockaddr_in sa;
    SSL_CTX* ctx;
    SSL* ssl;
    X509* server_cert;
    char* str;
    char buf [4096];
    const SSL_METHOD *meth;

    OpenSSL_add_ssl_algorithms();
    meth = TLSv1_2_client_method();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(meth);
    CHK_NULL(ctx);

//    if (SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES256-GCM-    SHA384") != 1)
//        ERR_print_errors_fp(stderr);

    /* ----------------------------------------------- */
    /* Create a socket and connect to server using normal socket     calls. */

    sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(sd, "socket");

    memset(&sa, 0, sizeof (sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP */
    sa.sin_port = htons(9999); /* Server Port number */

    err = connect(sd, (struct sockaddr*) &sa, sizeof (sa));
    CHK_ERR(err, "connect");

    /* ----------------------------------------------- */
    /* Now we have TCP conncetion. Start SSL negotiation. */

    ssl = SSL_new(ctx);
    CHK_NULL(ssl);
    SSL_set_fd(ssl, sd);
    err = SSL_connect(ssl);
    CHK_SSL(err);

    /* Following two steps are optional and not required for
       data exchange to be successful. */

    /* Get the cipher - opt */

    printf("SSL connection using %s\n", SSL_get_cipher(ssl));

    /* Get server's certificate (note: beware of dynamic allocation) -     opt */


    server_cert = SSL_get_peer_certificate(ssl);
    CHK_NULL(server_cert);
    printf("Server certificate:\n");

    str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("\t subject: %s\n", str);
    OPENSSL_free(str);

    str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("\t issuer: %s\n", str);
    OPENSSL_free(str);

    /* We could do all sorts of certificate verification stuff here     before
       deallocating the certificate. */

    X509_free(server_cert);

    /* --------------------------------------------------- */
    /* DATA EXCHANGE - Send a message and receive a reply. */

    err = SSL_write(ssl, "Hello World!", strlen("Hello World!"));
    CHK_SSL(err);

    err = SSL_read(ssl, buf, sizeof (buf) - 1);
    //    err = recv(sd, buf, sizeof(buf), 0);
    CHK_SSL(err);
    buf[err] = '\0';
    printf("Got %d chars:'%s'\n", err, buf);
    SSL_shutdown(ssl); /* send SSL/TLS close_notify */

    /* Clean up. */

    //    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
}
/* EOF - cli.cpp */

最佳答案

ServerKeyExchange 是为临时 Diffie-Hellman 协议(protocol)发送的消息。您无需为此更改代码,只需启用(仅?)DHE 和 ECDHE 密码套件。您选择的密码套件似乎超出了您提供的代码范围。

在您启用这些密码套件之前,请确保您了解对这些协议(protocol)的攻击,例如僵局,至少只允许安全 key 大小。

关于c++ - C++ Openssl 中的服务器 key 交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34369789/

相关文章:

php - 加密/解密文件

php - 适用于 PHP 的 AWS 开发工具包 - 解密密码

c++ - 使用字符串成员函数格式化 SSN

C++ fork() 和 execv() 问题

c++ - Boost Spirit(经典): Inline parser, 工作,除了跳过评论

node.js - 使用远程服务器的 TLS 身份验证

azure - 将 Mosquitto 连接到新的 Azure MQTT 后端

R 服务器 : install. packages() 证书错误

c++ - 多态性 : Accessing inherited class variable

ios - 在 iOS 上使用 Touch ID 加密数据