nginx openssl 的集成代码流程

本文转载自:http://blog.chinaunix.net/uid-26335251-id-3508765.html

说明:
一、这里个人测试完全和nginx处理流程和返回的数据完全一致
二、这里做了只是做了简要抽取,如果作为服务器,能实现这些步骤整体ssl处理应该没有任何问题。
三、这里包含三个文件:NGXSSL.c 为主文件,source.h为头文件,source.c为部分代码文件。

source.h

/*
 * source.h
 *
 * Created on: 2013-3-3
 * Author: root
 */

#ifndef SOURCE_H_
#define SOURCE_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/epoll.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/evp.h>

//错误码的定义
#define NGX_OK 0
#define NGX_ERROR -1
#define NGX_AGAIN -2
#define NGX_BUSY -3
#define NGX_DONE -4
#define NGX_DECLINED -5
#define NGX_ABORT -6
#if (NGX_HAVE_ACCEPT4)
    static ngx_uint_t use_accept4 = 1;
#endif
typedef int ngx_socket_t;

int ngx_ssl_connection_index;
int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index;

#define NGX_SSL_SSLv2 0x0002
#define NGX_SSL_SSLv3 0x0004
#define NGX_SSL_TLSv1 0x0008
#define NGX_SSL_TLSv1_1 0x0010
#define NGX_SSL_TLSv1_2 0x0020

#define ngx_ssl_get_connection(ssl_conn) 
    SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index)

#define ngx_ssl_conn_t SSL

#define ngx_close_socket close
#define ngx_socket socket

//错误吗的定义
#define NGX_OK 0
#define NGX_ERROR -1
#define NGX_AGAIN -2
#define NGX_BUSY -3
#define NGX_DONE -4
#define NGX_DECLINED -5
#define NGX_ABORT -6

typedef intptr_t ngx_int_t; //long int 定义
typedef uintptr_t ngx_uint_t; //unsigned long int定义
typedef intptr_t ngx_flag_t;

typedef struct {
    SSL_CTX *ctx;
} ngx_ssl_t;

RSA * ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length);
int ngx_nonblocking(ngx_socket_t s);
void ngx_http_ssl_handshake(int fd,ngx_ssl_conn_t *connection);
ngx_int_t ngx_ssl_handshake(ngx_ssl_conn_t *connection);
ngx_int_t ngx_ssl_shutdown(ngx_ssl_conn_t *connection);
void ngx_ssl_clear_error();

#endif /* SOURCE_H_ */


source.c

/*
 * source.c
 *
 * Created on: 2013-3-3
 * Author: root
 */

#include "source.h"

//设置一个临时的RSA,在出口算法中,有规定需要这么做的
RSA * ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length) {
    static RSA *key;

    if (key_length == 512) {
        if (key == NULL) {
            key = RSA_generate_key(512, RSA_F4, NULL, NULL);
        }
    }

    return key;
}

//
int ngx_nonblocking(ngx_socket_t s) {
    int nb;

    nb = 1;

    return ioctl(s, FIONBIO, &nb);
}

void ngx_http_ssl_handshake(int fd,ngx_ssl_conn_t *connection) {
    u_char buf[1];
    ssize_t n;
    ngx_int_t rc;

    //如果在recv的时候,flag字段设置了MSG_PEEK,则读取数据包的时候,不会把该数据包从缓存队列中删除;下次读取时还是这个数据包
    n = recv(fd, (char *) buf, 1, MSG_PEEK);

    if (n == 1) {
        if (buf[0] & 0x80 /* SSLv2 */|| buf[0] == 0x16 /* SSLv3/TLSv1 */) { //对不同加密协议进行判断
            rc = ngx_ssl_handshake(connection); //处理握手和单向认证
            if (rc == NGX_AGAIN) {
                return;
            }
            return;
        }else
        {
            //http 平台的请求,如果是http平台的请求,就走一般流程返回错我信息
            return;
        }
    }
    return;
}

ngx_int_t ngx_ssl_handshake(ngx_ssl_conn_t *connection) {
    int n, sslerr;
    n = SSL_do_handshake(connection); //这里会试着握手,由于上次recv之后,会有数据正在写入,返回-1
    if (n == 1) {
        /* initial handshake done, disable renegotiation (CVE-2009-3555) */
        if (connection->s3) {
            connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
        }
        return NGX_OK;
    }
    sslerr = SSL_get_error(connection, n);

    //这里应该再重新接收一次和NGINX一样,等待下一次循环(epoll)再进行,同时设置读写句柄,以便下次读取的时候直接进行握手
     if (sslerr == SSL_ERROR_WANT_READ) {
         n = SSL_do_handshake(connection);
             if (n == 1) {
                 /* initial handshake done, disable renegotiation (CVE-2009-3555) */
                 if (connection->s3) {
                     connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
                 }
                 return NGX_OK;//握手成功,就可以读取了
             }
     }

    return NGX_AGAIN;
}

//ret->quiet_shutdown=1;默认的是ret->quiet_shutdown=0;他相当于SSL_set_shutdown函数将参数设置为SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN
// 当设置为1时,假如关闭后,不通知对方,这样不适合TLS标准
ngx_int_t ngx_ssl_shutdown(ngx_ssl_conn_t *connection) {

    //这里是对认证正确的处理方式简要地关闭处理
    int n, sslerr, mode;
//    ngx_err_t err;

//    if (c->timedout) { //超时,可能是读取或写入超时导致
    if(0){
        mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
        SSL_set_quiet_shutdown(connection, 1); //设置为1时,假如关闭后,不通知对方

    } else {
        mode = SSL_get_shutdown(connection);

//        if (c->ssl->no_wait_shutdown) {
            mode |= SSL_RECEIVED_SHUTDOWN;
//        }

//        if (c->ssl->no_send_shutdown) {
            mode |= SSL_SENT_SHUTDOWN;
//        }

//        if (c->ssl->no_wait_shutdown && c->ssl->no_send_shutdown) {
            SSL_set_quiet_shutdown(connection, 1);
//        }
    }

    SSL_set_shutdown(connection, mode);

    ngx_ssl_clear_error();

    n = SSL_shutdown(connection);//关闭SSL套接字


    sslerr = 0;

//    /* SSL_shutdown() never returns -1, on error it returns 0 */
//    if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
        SSL_free(connection); //释放SSL套接字
//        c->ssl = NULL;

        return NGX_OK; //到这里结束了
//    }
//
// return NGX_OK;
}

void ngx_ssl_clear_error() { //对错误信息的清理工作
    while (ERR_peek_error()) {
    }

    ERR_clear_error();
}


//
//ngx_int_t ngx_ssl_init(void) {
//    OPENSSL_config(NULL);
//
//    SSL_library_init();
//    SSL_load_error_strings();
//
//    OpenSSL_add_all_algorithms();
//
//    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
//
//    if (ngx_ssl_connection_index == -1) {
//        printf("SSL_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }
//
//    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
//            NULL);
//    if (ngx_ssl_server_conf_index == -1) {
//        printf("SSL_CTX_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }
//
//    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
//            NULL);
//    if (ngx_ssl_session_cache_index == -1) {
//        printf("SSL_CTX_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }
//
//    return NGX_OK;
//}
//
static void *
ngx_openssl_create_conf(ngx_cycle_t *cycle)
{
 ngx_openssl_conf_t *oscf;

 oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
 if (oscf == NULL) {
 return NULL;
 }

 /*
 * set by ngx_pcalloc():
 *
 * oscf->engine = 0;
 */

 return oscf;
}

static void *
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
{
 ngx_http_ssl_srv_conf_t *sscf;

 sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
 if (sscf == NULL) {
 return NULL;
 }

 /*
 * set by ngx_pcalloc():
 *
 * sscf->protocols = 0;
 * sscf->certificate = { 0, NULL };
 * sscf->certificate_key = { 0, NULL };
 * sscf->dhparam = { 0, NULL };
 * sscf->ecdh_curve = { 0, NULL };
 * sscf->client_certificate = { 0, NULL };
 * sscf->crl = { 0, NULL };
 * sscf->ciphers = { 0, NULL };
 * sscf->shm_zone = NULL;
 */

 sscf->enable = NGX_CONF_UNSET;
 sscf->prefer_server_ciphers = NGX_CONF_UNSET;
 sscf->verify = NGX_CONF_UNSET_UINT;
 sscf->verify_depth = NGX_CONF_UNSET_UINT;
 sscf->builtin_session_cache = NGX_CONF_UNSET;
 sscf->session_timeout = NGX_CONF_UNSET;

 return sscf;
}

static ngx_int_t
ngx_http_ssl_add_variables(ngx_conf_t *cf)
{
 ngx_http_variable_t *var, *v;

 for (v = ngx_http_ssl_vars; v->name.len; v++) {
 var = ngx_http_add_variable(cf, &v->name, v->flags);
 if (var == NULL) {
 return NGX_ERROR;
 }

 var->get_handler = v->get_handler;
 var->data = v->data;
 }

 return NGX_OK;
}

static void *
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
{
 ngx_http_ssl_srv_conf_t *sscf;

 sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
 if (sscf == NULL) {
 return NULL;
 }

 /*
 * set by ngx_pcalloc():
 *
 * sscf->protocols = 0;
 * sscf->certificate = { 0, NULL };
 * sscf->certificate_key = { 0, NULL };
 * sscf->dhparam = { 0, NULL };
 * sscf->ecdh_curve = { 0, NULL };
 * sscf->client_certificate = { 0, NULL };
 * sscf->crl = { 0, NULL };
 * sscf->ciphers = { 0, NULL };
 * sscf->shm_zone = NULL;
 */

 sscf->enable = NGX_CONF_UNSET;
 sscf->prefer_server_ciphers = NGX_CONF_UNSET;
 sscf->verify = NGX_CONF_UNSET_UINT;
 sscf->verify_depth = NGX_CONF_UNSET_UINT;
 sscf->builtin_session_cache = NGX_CONF_UNSET;
 sscf->session_timeout = NGX_CONF_UNSET;

 return sscf;
}


//ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) {
//    ssl->ctx = SSL_CTX_new(SSLv23_method());
//
//    if (ssl->ctx == NULL) {
//        printf("SSL_CTX_new() failed");
//        return NGX_ERROR;
//    }
//
//    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
//        printf("SSL_CTX_set_ex_data() failed");
//        return NGX_ERROR;
//    }
//
//    /* client side options */
//
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
//
//    /* server side options */
//
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
//
//    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
//
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
//
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
//
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
//
//    if (!(protocols & NGX_SSL_SSLv2)) {
//        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
//    }
//    if (!(protocols & NGX_SSL_SSLv3)) {
//        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
//    }
//    if (!(protocols & NGX_SSL_TLSv1)) {
//        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
//    }
//
//#ifdef SSL_OP_NO_COMPRESSION
//    SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
//#endif
//
//#ifdef SSL_MODE_RELEASE_BUFFERS
//    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
//#endif
//
//    SSL_CTX_set_read_ahead(ssl->ctx, 1);
//
//    SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
//
//    return NGX_OK;
//}
//
//void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) {
//    //    void *c;
//    //
//    // if (where & SSL_CB_HANDSHAKE_START) {
//    // c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
//    //
//    // if (c) {
//    // printf("SSL renegotiation");
//    // }
//    // }
//
//    printf("SSL renegotiation");
//}
//
//int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) {
//    const char *servername;
//
//    servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
//
//    if (servername == NULL) {
//        return SSL_TLSEXT_ERR_NOACK;
//    }
//
//    c = ngx_ssl_get_connection(ssl_conn);
//
//    printf("SSL server name: "%s"", servername);
//
//    return SSL_TLSEXT_ERR_OK;
//}
//
//ngx_int_t ngx_ssl_certificate(ngx_ssl_t *ssl, const char *cert, const char *key) {
//    if (SSL_CTX_use_certificate_chain_file(ssl->ctx, (char *) cert) == 0) {
//        printf("SSL_CTX_use_certificate_chain_file("%s") failed", cert);
//        return NGX_ERROR;
//    }
//
//    if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key, SSL_FILETYPE_PEM)
//            == 0) {
//        printf("SSL_CTX_use_PrivateKey_file("%s") failed", key);
//        return NGX_ERROR;
//    }
//
//    return NGX_OK;
//}
//

//
//ngx_ssl_conn_t * ngx_ssl_create_connection(ngx_ssl_t *ssl, int socketid) {
//    c = malloc(1024);
//    ngx_ssl_conn_t *connection;
//
//    connection = SSL_new(ssl->ctx);
//
//    if (connection == NULL) {
//        return NULL;
//    }
//
//    if (SSL_set_fd(connection, socketid) == 0) {
//        return NULL;
//    }
//    SSL_set_accept_state(connection);
//    if (SSL_set_ex_data(connection, ngx_ssl_connection_index, c) == 0) {
//        return NULL;
//    }
//
//    return connection;
//}
//
//
//ngx_int_t ngx_ssl_dhparam(ngx_ssl_t *ssl, const char *file) {
//    DH *dh;
//    BIO *bio;
//
//    /*
//     * -----BEGIN DH PARAMETERS-----
//     * MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc
//     * y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl
//     * 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC
//     * -----END DH PARAMETERS-----
//     */
//
//    static unsigned char dh1024_p[] = { 0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46,
//            0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5, 0x80, 0xE9, 0xCF, 0xDB, 0xD9,
//            0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B, 0x08, 0xEE, 0xD4, 0xEB,
//            0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76, 0xE7, 0x10, 0x80,
//            0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5, 0xBE, 0xEC,
//            0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04, 0x9B,
//            0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04,
//            0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5,
//            0xDF, 0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC,
//            0x9A, 0x50, 0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A,
//            0x63, 0xAB, 0x1E, 0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D,
//            0x14, 0x67, 0x57, 0xDA, 0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B,
//            0x9B };
//
//    static unsigned char dh1024_g[] = { 0x02 };
//
//    if (!file) {
//
//        dh = DH_new();
//        if (dh == NULL) {
//            return NGX_ERROR;
//        }
//
//        dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
//        dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
//
//        if (dh->p == NULL || dh->g == NULL) {
//            DH_free(dh);
//            return NGX_ERROR;
//        }
//
//        SSL_CTX_set_tmp_dh(ssl->ctx, dh);
//
//        DH_free(dh);
//
//        return NGX_OK;
//    }
//
//    bio = BIO_new_file((char *) file, "r");
//    if (bio == NULL) {
//        return NGX_ERROR;
//    }
//
//    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
//    if (dh == NULL) {
//        BIO_free(bio);
//        return NGX_ERROR;
//    }
//
//    SSL_CTX_set_tmp_dh(ssl->ctx, dh);
//
//    DH_free(dh);
//    BIO_free(bio);
//
//    return NGX_OK;
//}
//
//ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, const char *sess_ctx,
//        ssize_t builtin_session_cache, time_t timeout) {
//    SSL_CTX_set_session_id_context(ssl->ctx, (const unsigned char *) sess_ctx,strlen(sess_ctx));
//
//    SSL_CTX_set_session_cache_mode(ssl->ctx,
//            SSL_SESS_CACHE_SERVER
//            |SSL_SESS_CACHE_NO_AUTO_CLEAR
//            |SSL_SESS_CACHE_NO_INTERNAL_STORE);
//
//    SSL_CTX_sess_set_cache_size(ssl->ctx, 1);
//
//    return NGX_OK;
//
//}

//打开监听到接口,只绑定了一个
ngx_socket_t ngx_open_listening_sockets() {
    int reuseaddr;
    ngx_socket_t s;
    reuseaddr = 1; //重用地址
    struct sockaddr_in addr;

    s = ngx_socket(AF_INET, SOCK_STREAM, 0); //创建套接口
    if (s == -1) {
        return NGX_ERROR;
    }

    /* 填写sockaddr_in结构*/
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(443);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr,
            sizeof(int)) == -1) {
        if (ngx_close_socket(s) == -1) { //出错就把它关闭
        }
        return NGX_ERROR;
    }

    if (ngx_nonblocking(s) == -1) { //堵塞失败调用
        if (ngx_close_socket(s) == -1) { //关闭套接字
        }
        return NGX_ERROR;
    }

    if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) == -1) { //绑定
        return NGX_ERROR;
    }

    if (listen(s, 5) == -1) { //监听套接口
        if (ngx_close_socket(s) == -1) {
        }
        return NGX_ERROR;
    }

    return s;
}


NGXSSL.c

/*
 ============================================================================
 Name : NGXSSL.c
 Author : xiangrongcheng
 Version :
 Copyright : Your copyright notice
 Description :  Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include "source.h"

int epfd;

int main(void) {

//    void *data = NULL;

    //认证和密钥目录
    const char * certificate = "/usr/local/nginx/conf/api.bz.crt";
    const char * certificate_key = "/usr/local/nginx/conf/api.bz_nopass.key";

    //这里模拟nginx初始化
    //    ngx_ssl_init(); //初始化ssl
    OPENSSL_config(NULL); //加载openssl的配置信息,不知道对否
    SSL_library_init(); //加载ssl库函数
    SSL_load_error_strings(); //格式化错误日志信息
    OpenSSL_add_all_algorithms(); //load所有的SSL算法

//    //这里没有必要,是做为缓存,会话和连接池处理的
//    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
//    if (ngx_ssl_connection_index == -1) {
//        printf("SSL_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }
//
//    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);
//    if (ngx_ssl_server_conf_index == -1) {
//        printf("SSL_CTX_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }
//
//    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);
//    if (ngx_ssl_session_cache_index == -1) {
//        printf("SSL_CTX_get_ex_new_index() failed");
//        return NGX_ERROR;
//    }

    //创建ssl
    ngx_ssl_t ssl;
    ngx_uint_t protocols = 61;
//    ngx_ssl_create(ssl, protocols, data);
    ssl.ctx = SSL_CTX_new(SSLv23_method()); //通过SSL所用方法新建SSL_CTX上下文信息
    if (ssl.ctx == NULL) {
        printf("SSL_CTX_new() failed");
        return NGX_ERROR;
    }

//    //设置上下文信息的数据,保存扩展数据(应该不是很需要)
//    if (SSL_CTX_set_ex_data(ssl.ctx, ngx_ssl_server_conf_index, data) == 0) {
//        printf("SSL_CTX_set_ex_data() failed");
//        return NGX_ERROR;
//    }

    //客户端服务器选项的设定,具体查看具体参数吧,可以看一下英文
    /* client side options */
    SSL_CTX_set_options(ssl.ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);

    /* server side options */
    SSL_CTX_set_options(ssl.ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);

    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
    SSL_CTX_set_options(ssl.ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_TLS_D5_BUG);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
    SSL_CTX_set_options(ssl.ctx, SSL_OP_SINGLE_DH_USE);

    if (!(protocols & NGX_SSL_SSLv2)) {
        SSL_CTX_set_options(ssl.ctx, SSL_OP_NO_SSLv2);
    }
    if (!(protocols & NGX_SSL_SSLv3)) {
        SSL_CTX_set_options(ssl.ctx, SSL_OP_NO_SSLv3);
    }
    if (!(protocols & NGX_SSL_TLSv1)) {
        SSL_CTX_set_options(ssl.ctx, SSL_OP_NO_TLSv1);
    }

#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ssl.ctx, SSL_OP_NO_COMPRESSION);
#endif

#ifdef SSL_MODE_RELEASE_BUFFERS
    SSL_CTX_set_mode(ssl.ctx, SSL_MODE_RELEASE_BUFFERS);
#endif

    //这里一定需要,设置读取头一个字节,作为判断协议,如果不设定那么将使得n = SSL_read(connection, buffer, 512);少读前一个字节,因为读取第一个字节作为判断字节
    SSL_CTX_set_read_ahead(ssl.ctx, 1);

    //下面也不是必要的
//    SSL_CTX_set_info_callback(ssl.ctx, ngx_ssl_info_callback);
//    SSL_CTX_set_tlsext_servername_callback(ssl.ctx,ngx_http_ssl_servername);

//    ngx_ssl_certificate(ssl, certificate, certificate_key);

//     SSL_CTX_load_verify_locations用于加载受信任的CA证书,CAfile如果不为NULL,则他指向的文件包含PEM编码格式的一个或多个证书,可以用e.g.来简要介绍证书内容
//      CApath如果不为NULL,则它指向一个包含PEM格式的CA证书的目录,目录中每个文件包含一份CA证书,文件名是证书中CA名的HASH值
//      可以用c-rehash来建立该目录,如cd /some/where/certs(包含了很多可信任的CA证书) c_rehash .。返回一成功,0 失败。SSL_CTX_set_default_verify_paths找寻默认的验证路径,在这里肯定找不到的。
//      这里主要set cert_store
//      char *CAfile=NULL,*CApath=NULL;
//      SSL_CTX_load_verify_locations(ctx,CAfile,CApath);
//      当需要客户端验证的时候,服务器把CAfile里面的可信任CA证书发往客户端。
//      if(CAfile !=NULL )SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
//      设置最大的验证用户证书的上级数。
//      SSL_CTX_set_verify_depth(ctx,10);

    //设置加载服务器的证书和私钥
    if (SSL_CTX_use_certificate_chain_file(ssl.ctx, (char *) certificate) == 0) {
        printf("SSL_CTX_use_certificate_chain_file("%s") failed", certificate);
    }
    if (SSL_CTX_use_PrivateKey_file(ssl.ctx, (char *) certificate_key, SSL_FILETYPE_PEM)== 0) { //类型测试好像无所谓,应该是SSL_FILETYPE_ASN1?
        printf("SSL_CTX_use_PrivateKey_file("%s") failed", certificate_key);
    }

    SSL_CTX_set_cipher_list(ssl.ctx, "HIGH:!aNULL:!MD5"); //设置密码链表,具体看密码    ciphers(1)指令吧
    SSL_CTX_set_tmp_rsa_callback(ssl.ctx, ngx_ssl_rsa512_key_callback); //设置键改变时调用,握手时的处理

    //如果是双向认证还得做下面这几件事情
//     SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);
// SSL_CTX_set_verify_depth(ssl->ctx, depth);
//     SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL);
//     SSL_load_client_CA_file((char *) cert->data);
//     ERR_clear_error();
//     SSL_CTX_set_client_CA_list(ssl->ctx, list);
//     SSL_CTX_get_cert_store(ssl->ctx);
// X509_STORE_add_lookup(store, X509_LOOKUP_file();
// X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM);
// X509_STORE_set_flags(store,X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);

    //ngx_ssl_dhparam(ssl, "");
//    当使用RSA算法鉴别的时候,会有一个临时的DH密钥磋商发生。这样会话数据将用这个临时的密钥加密,而证书中的密钥中做为签名。
//    所以这样增强了安全性,临时密钥是在会话结束消失的,所以就是获取了全部信息也无法把通信内容给解密出来。

//    实现 openssl 提供的默认的 DH_METHOD,实现了根据密钥参数生成 DH 公私钥,以及根据 DH 公钥(一方)以及 DH 私钥(另一方)来生成一个共享密钥,用于密钥交换。
    //DH密钥磋商设置
    DH *dh;
    static unsigned char dh1024_p[] = { 0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46,
            0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5, 0x80, 0xE9, 0xCF, 0xDB, 0xD9,
            0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B, 0x08, 0xEE, 0xD4, 0xEB,
            0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76, 0xE7, 0x10, 0x80,
            0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5, 0xBE, 0xEC,
            0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04, 0x9B,
            0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04,
            0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5,
            0xDF, 0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC,
            0x9A, 0x50, 0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A,
            0x63, 0xAB, 0x1E, 0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D,
            0x14, 0x67, 0x57, 0xDA, 0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B,
            0x9B };

    static unsigned char dh1024_g[] = { 0x02 };
    dh = DH_new();
    if (dh == NULL) {
    }

    dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
    dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);

    if (dh->p == NULL || dh->g == NULL) {
        DH_free(dh);
    }
    SSL_CTX_set_tmp_dh(ssl.ctx, dh);
    DH_free(dh);

//    ngx_ssl_session_cache(ssl, "HTTP", 0, 0);
    //下面只是会话的设置
    SSL_CTX_set_session_id_context(ssl.ctx, (const unsigned char *) "HTTP",strlen("HTTP"));
    SSL_CTX_set_session_cache_mode(ssl.ctx,
            SSL_SESS_CACHE_SERVER
            |SSL_SESS_CACHE_NO_AUTO_CLEAR
            |SSL_SESS_CACHE_NO_INTERNAL_STORE);

//    设置cache的大小,默认的为1024*20=20000,这个也就是可以存多少个session_id,一般都不需要更改的。假如为0的话将是无限
    SSL_CTX_sess_set_cache_size(ssl.ctx, 1);

    //下面是网络模块
    socklen_t sin_len = sizeof(struct sockaddr_in);
    int fd, opt = 1;
    struct epoll_event ev;
    struct sockaddr_in sin, cin;

    epfd = epoll_create(1024);
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
        fprintf(stderr, "socket failed/n");
        return -1;
    }
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &opt, sizeof(opt));

    memset(&sin, 0, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons((short) (443));
    sin.sin_addr.s_addr = INADDR_ANY;
    if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
        fprintf(stderr, "bind failed/n");
        return -1;
    }
    if (listen(fd, 32) != 0) {
        fprintf(stderr, "listen failed/n");
        return -1;
    }

    int i, cfd, n, nfds;

    struct epoll_event events[1024];
    char buffer[512];

    ev.data.fd = fd;
    ev.events = EPOLLIN | EPOLLET; //设置要处理的事件类型
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

    while (1) {
        nfds = epoll_wait(epfd, events, 1024, -1);
        printf("nfds ........... %d/n", nfds);
        for (i = 0; i < nfds; i++) {
            if (events[i].data.fd == fd) {
                cfd = accept(fd, (struct sockaddr *) &cin, &sin_len);
                ngx_nonblocking(cfd); //把客户端的socket设置为非阻塞方式
                ev.data.fd = cfd;
                ev.events = EPOLLIN | EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
            } else {
                if (events[i].events & EPOLLIN) {
                    cfd = events[i].data.fd;

                    //这里模拟nginx接收
//                    ngx_ssl_create_connection(ssl, cfd);
                    ngx_ssl_conn_t *connection = SSL_new(ssl.ctx); //根据上下文,建立ssl套接口或链接
                    if (connection == NULL) {
                    }

                    if (SSL_set_fd(connection, cfd) == 0) { //设置处理的id进入上下文里面
                    }
                    SSL_set_accept_state(connection); //设置接收状态

//                    if (SSL_set_ex_data(connection, ngx_ssl_connection_index, c) == 0) {
//                    }

                    //进行握手处理
                    ngx_http_ssl_handshake(cfd,connection);

                    //正确处理
                    for (;;) {
                        n = SSL_read(connection, buffer, 512); //会读取好几次把之前读取的第一个字节也读取回来
                        if (n > 0) {
                        } else {
                            break;
                        }
                        continue;
                    }

                    //这里是,对请求的相关处理,省略掉了

                    //ngx_http_process_request_headers(rev);

                    //给客户端发送数据
                    const char *data = "HTTP/1.1 200 OKrnServer: nginx/1.0.12rnDate: Sun, 03 Mar 2013 12:38:48 GMTrnContent- ...";
                    n = SSL_write(connection, data, sizeof(data));

                    //关闭请求链接;如果验证通过是不会走这里的(而等到超时的时候才处理);对于验证不通过或http请求则直接调用关闭链接。
                    ngx_ssl_shutdown(connection);
                    SSL_CTX_free(ssl.ctx);//释放SSL环境
                    close(fd);

                    //                    ret = recv(cfd, buffer, sizeof(buffer), 0);
                    //                    printf("read ret..........= %d/n", ret);
                    //
                    //                    ev.data.fd = cfd;
                    //                    ev.events = EPOLLOUT | EPOLLET;
                    //                    epoll_ctl(epfd, EPOLL_CTL_MOD, cfd, &ev);
                } else if (events[i].events & EPOLLOUT) {
                    cfd = events[i].data.fd;

                    ev.data.fd = cfd;
                    epoll_ctl(epfd, EPOLL_CTL_DEL, cfd, &ev);
                    close(cfd);

                }
            }
        }
    }

    if (fd > 0)
        close(fd);
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值