您的位置:首页 > 运维架构 > Nginx

nginx openssl 的集成代码流程

2014-06-11 17:43 2231 查看
本文转载自: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: