多进程平台会话的外部缓存



我正在使用openssl(作为客户端和服务器)的linux多进程平台上工作,我需要使用外部缓存实现会话重用(带有会话id)。

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

我的问题是如何重用会话对象时,SSL_CTX对象从来不是相同的。

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

还有一件事:你知道可能有一个开源项目做到了吗?我认为mod_ssl是这样工作的,但不确定(需要检查)。

非常感谢。

* EDIT *

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

#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 socketn");
        return 0;
    }
    if (bind(servfd, (struct sockaddr *)&serv, sizeof(struct sockaddr)) != 0) {
        printf("Failed to bindn");
        goto cleanup;
    }
    if (listen(servfd, 512) != 0) {
        printf("Failed to listenn");
        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 contextn");
            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.pemn");
            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.pemn");
            goto cleanup;
        }
        if (!SSL_CTX_check_private_key(ctx)) {
            printf("Failed to validate certn");
            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 "324f", <incomplete sequence 353>, slen=48, out=0x8bad90 "h31233367377177", olen=88) at ssl/t1_enc.c:65
#9  0x000000000044d945 in tls1_generate_key_block (s=0x8bb800, km=0x8bad90 "h31233367377177", 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) 

您要使用PEM_write_bio_SSL_SESSION, PEM_read_bio_SSL_SESSION, SSL_get1_sessionSSL_set_session。但这是基本的东西。

这里是详细解释的链接。这对我很有效。您也可以加密磁盘上的秘密。

最新更新