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

nginx openssl 的集成代码流程

2016-06-02 12:10 806 查看
说明:

一、这里个人测试完全和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;

}

openssl nginx 处理流程总结:

一、初始化工作

1、通过SSL所用方法新建SSL_CTX上下文信息

2、客户端服务器选项的ssl上下文设定

3、设置读取第一个字节读取设定

4、设置服务器的CA证书和私钥

5、DH密钥磋商设定,加强数据安全性

6、如果是双向认证还得做一些事情

7、设置密码链表

8、设置键改变时调用,握手时的处理

9、网络模块的建立

二、当请求到来时

1、通过ssl的上下文建立ssl链接

2、设置链接状态和描述符

3、进行握手处理

4、读取一个字节,进行协议判断,如果协议不正确做退出等操作

5、协议正确,会进行握手操作(SSL_do_handshake),握手里面做了三件事:加密算法保持一致,确认所使用的算法中的加密密钥,对客户端进行认证。

6、握手成功后SSL_read 在“记录层”进行数据读取

7、数据处理

8、对客户端进行写入操作,也在“记录层”进行处理。

9、最后进行数据的关闭等操作

SSL_read 和 SSL_write 都是根据记录层,进行数据加密/解密传输所得的正确数据

当然实现还可有使用 SSL自带的接收和链接函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: