多个流程平台

时间:2016-09-06 14:36:32

标签: ssl openssl sessionid

我正在使用openssl(作为客户端和服务器)的linux多进程平台上工作,我将需要使用EXTERNAL CACHE实现会话重用(具有会话ID)。

我成功地连接了#34;一些回调openssl以获得新的通知并获得SSL_SESSION,但仅当我使用相同的SSL_CTX对象时。

我的问题是当SSL_CTX对象永远不是同一个时,我如何重用会话对象。

Openssl似乎不是为此而构建的。 简而言之,我想为SSL会话实现一个外部缓存,它不依赖于SSL_CTX。

还有一件事:你知道也许是一个开源项目吗?我认为mod_ssl就是这样,但不确定(需要检查)。

非常感谢。

*编辑*

我写了一些代码作为示例:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

static SSL_SESSION* sess_session = 0;
static unsigned char* char_session;
static long char_session_length;

static int new_session_cb(struct ssl_st *ssl, SSL_SESSION *sessionX)
{
    printf("!!! NEW SESSION CB !!!\n");

    char_session_length = i2d_SSL_SESSION(sessionX, &char_session);
    printf("Session length: %ld bytes.\n",char_session_length);
    sess_session = sessionX;
    return 0;
}

static void remove_session_cb(struct ssl_ctx_st *ctx, SSL_SESSION *sess)
{
    printf("!!! REMOVE SESSION CB !!!\n");
    return;
}

static SSL_SESSION *get_session_cb(struct ssl_st *ssl, const unsigned char *data, int len, int *copy)
{
    printf("!!! GET SESSION CB !!!\n");

    /* allow the session to be freed automatically by openssl */
    *copy = 0;

    SSL_SESSION* a;
    const unsigned char* ptr = (const unsigned char *)malloc(char_session_length);
    memcpy(ptr,char_session, char_session_length);
    a = d2i_SSL_SESSION(NULL, &ptr, char_session_length);
    free((void*)ptr);
    return a;
}


int main(int argc, char **argv)
{
    SSL                *ssl    = NULL;
    SSL_CTX            *ctx    = NULL;
    int                 servfd = -1;
    int                 clntfd = -1;
    struct sockaddr_in  serv;
    struct sockaddr_in  clnt;
    socklen_t           socksize;
    char                buf[128];
    int                 ret;
    int                 clean_disconnect;

    /* Initialize OpenSSL. */
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();

    /* Setup the socket to listen for incoming connections. */
    memset(&serv, 0, sizeof(serv));
    serv.sin_family      = AF_INET;
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    serv.sin_port        = htons(4433);
    servfd               = socket(AF_INET, SOCK_STREAM, 0);
    if (servfd == -1) {
        printf("Failed to create socket\n");
        return 0;
    }
    if (bind(servfd, (struct sockaddr *)&serv, sizeof(struct sockaddr)) != 0) {
        printf("Failed to bind\n");
        goto cleanup;
    }

    if (listen(servfd, 512) != 0) {
        printf("Failed to listen\n");
        goto cleanup;
    }
    /* Wait for and handle connections as they come in. */
    while (1) {

        printf("Loop..\n");

        /* Generate an SSL server context. */
        ctx = SSL_CTX_new(SSLv23_server_method());
        if (ctx == NULL) {
            printf("Failed to create SSL server context\n");
            goto cleanup;
        }

        /* Set some options and the session id.
         * SSL_OP_NO_SSLv2: SSLv2 is insecure, disable it.
         * SSL_OP_NO_TICKET: We don't want TLS tickets used because this is an SSL server caching example.
         *                   It should be fine to use tickets in addition to server side caching.
         */
        SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET);
        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_AUTO_CLEAR|SSL_SESS_CACHE_NO_INTERNAL);
        SSL_CTX_sess_set_new_cb(ctx, new_session_cb);
        SSL_CTX_sess_set_remove_cb(ctx,remove_session_cb);
        SSL_CTX_sess_set_get_cb(ctx, get_session_cb);

        /* Load certificate. */
        if (SSL_CTX_use_certificate_file(ctx, "/XXXX/certs/www.site1.com.crt", SSL_FILETYPE_PEM) != 1) {
            printf("Failed to load cert.pem\n");
            goto cleanup;
        }
        if (SSL_CTX_use_PrivateKey_file(ctx, "/XXXX/certs/www.site1.com.key.pem.insecure", SSL_FILETYPE_PEM) != 1) {
            printf("Failed to load key.pem\n");
            goto cleanup;
        }
        if (!SSL_CTX_check_private_key(ctx)) {
            printf("Failed to validate cert\n");
            goto cleanup;
        }

        socksize = sizeof(struct sockaddr_in);
        clntfd   = accept(servfd, (struct sockaddr *)&clnt, &socksize);
        if (clntfd == -1) {
            continue;
        }
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, clntfd);
        SSL_accept(ssl);

        clean_disconnect = 1;
        ret = SSL_read(ssl, buf, sizeof(buf));
        if (ret <= 0) {
            switch (SSL_get_error(ssl, ret)) {
                case SSL_ERROR_NONE:
                case SSL_ERROR_ZERO_RETURN:
                    break;
                default:
                    clean_disconnect = 0;
                    break;
            }
        }
        if (clean_disconnect) {
            SSL_shutdown(ssl);
        } else {
            SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
        }

        SSL_free(ssl);
        close(clntfd);
cleanup:
        if (ctx != NULL)
            SSL_CTX_free(ctx);
    }

    if (servfd != -1)
        close(servfd);

    return 0;
}

我遇到了这个崩溃:

Loop..
!!! NEW SESSION CB !!!
Session length: 115 bytes.
Clean Disconnect do shutdown...
Loop..
!!! GET SESSION CB !!!

Program received signal SIGSEGV, Segmentation fault.
malloc_consolidate (av=av@entry=0x7ffff79b1760 <main_arena>) at malloc.c:4151
4151    malloc.c: No such file or directory.
(gdb) bt
#0  malloc_consolidate (av=av@entry=0x7ffff79b1760 <main_arena>) at malloc.c:4151
#1  0x00007ffff7672ce8 in _int_malloc (av=0x7ffff79b1760 <main_arena>, bytes=1056) at malloc.c:3423
#2  0x00007ffff76756c0 in __GI___libc_malloc (bytes=1056) at malloc.c:2891
#3  0x00000000004afa36 in CRYPTO_malloc (num=1056, file=0x5f893a "crypto/kdf/tls1_prf.c", line=40) at crypto/mem.c:92
#4  0x00000000004afa69 in CRYPTO_zalloc (num=1056, file=0x5f893a "crypto/kdf/tls1_prf.c", line=40) at crypto/mem.c:100
#5  0x00000000004adefd in pkey_tls1_prf_init (ctx=0x8badf0) at crypto/kdf/tls1_prf.c:40
#6  0x00000000004a79be in int_ctx_new (pkey=0x0, e=0x0, id=1021) at crypto/evp/pmeth_lib.c:135
#7  0x00000000004a7cca in EVP_PKEY_CTX_new_id (id=1021, e=0x0) at crypto/evp/pmeth_lib.c:220
#8  0x000000000044d6e6 in tls1_PRF (s=0x8bb800, seed1=0x5f0c09, seed1_len=13, seed2=0x8baa10, seed2_len=32, seed3=0x8baa30, seed3_len=32, seed4=0x0, seed4_len=0, 
    seed5=0x0, seed5_len=0, sec=0x8cc0f8 "\324\f", <incomplete sequence \353>, slen=48, out=0x8bad90 "h\031\233\367\377\177", olen=88) at ssl/t1_enc.c:65
#9  0x000000000044d945 in tls1_generate_key_block (s=0x8bb800, km=0x8bad90 "h\031\233\367\377\177", num=88) at ssl/t1_enc.c:94
#10 0x000000000044e6de in tls1_setup_key_block (s=0x8bb800) at ssl/t1_enc.c:417
#11 0x0000000000431a37 in ossl_statem_server_pre_work (s=0x8bb800, wst=WORK_MORE_A) at ssl/statem/statem_srvr.c:477
#12 0x0000000000424d78 in write_state_machine (s=0x8bb800) at ssl/statem/statem.c:725
#13 0x0000000000424658 in state_machine (s=0x8bb800, server=1) at ssl/statem/statem.c:394
#14 0x0000000000424138 in ossl_statem_accept (s=0x8bb800) at ssl/statem/statem.c:175
#15 0x000000000041ca46 in SSL_do_handshake (s=0x8bb800) at ssl/ssl_lib.c:3025
#16 0x00000000004199ba in SSL_accept (s=0x8bb800) at ssl/ssl_lib.c:1457
#17 0x00000000004034ee in main (argc=1, argv=0x7fffffffdf28) at ../src/openssl_server2.c:195
(gdb) 

1 个答案:

答案 0 :(得分:0)

您想使用PEM_write_bio_SSL_SESSIONPEM_read_bio_SSL_SESSIONSSL_get1_sessionSSL_set_session。但这是基本的东西。

以下是详细解释的link。这个对我有用。您也可以加密磁盘上的密码。

取决于在磁盘上保留秘密不是问题。