溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

nginx怎么實現(xiàn)keyless

發(fā)布時間:2021-07-28 09:26:57 來源:億速云 閱讀:415 作者:chen 欄目:網(wǎng)絡(luò)管理

本篇內(nèi)容介紹了“nginx怎么實現(xiàn)keyless”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

簡介

當(dāng)企業(yè)把業(yè)務(wù)遷移到云WAF/CDN邊緣節(jié)點上,需向云廠商提供業(yè)務(wù)的私鑰安全性不能得到保證,且若業(yè)務(wù)私鑰證書發(fā)生變化或頻繁修改需要受限于人。風(fēng)險:一旦服務(wù)端的私鑰泄露會導(dǎo)致惡意攻擊者偽造虛假的服務(wù)器和客戶端通信,通信內(nèi)容也存在被劫持和解密的風(fēng)險。keyless源于clouldflare,采用keyless方案私鑰部署在客戶自己的服務(wù)器,無需向把業(yè)務(wù)私鑰部署在云/CDN邊緣節(jié)點上。

nginx怎么實現(xiàn)keyless

nginx怎么實現(xiàn)keyless

clouldflare keyless項目地址:https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/

cloudflare keyless開源項目地址:https://github.com/cloudflare/keyless

相關(guān)基礎(chǔ)知識介紹:

加解密套件知識普及

MAC(Message authentication code):消息認(rèn)證碼

PRF(pseudorandom function):偽隨機函數(shù)

SHA (Secure Hash Algorithm):安全散列算法

  • 對稱密碼:

DES:是以64比特的明文為一個單位來進行加密的,密鑰長度是64比特

三重DES: 就是將DES重復(fù)3次,有3個密鑰

AES(Advanced Encryption Standard):是一種新標(biāo)準(zhǔn)的對稱密碼算法,已取代DES

分組長度128比特,密鑰長度128、192、256三種規(guī)格

  • 分組密碼模式 :

ECB(Electronic CodeBook):將明文分組加密之后的結(jié)果將直接成為密文分組

CBC(Cipher Block Chaining):密文分組鏈接的模式

CFB(Cipher FeedBack):密文反饋模式

OFB(Output-Feedback):輸入反饋模式

CTR(CounTeR):計數(shù)器模式

GCM(Galois Counter Mode):Galois/計數(shù)器模式

  • 填充模式:對當(dāng)明文長度不為分組長度的整數(shù)倍時,需要在最后一個分組中填充一些數(shù)據(jù)使其填滿一個分組長度,攻擊者會利用這個利用這個在最后一個分組填充一些數(shù)據(jù)。

  • 單向散列函數(shù)

輸入的是消息輸出的是散列值,任意長度的消息計算出固定長度的散列值,消息不同散列值也不同

應(yīng)用:MD4、MD5;SHA-2系列(SHA-256,SHA-384,SHA-512,數(shù)字表示計算后的散列值長度)

  • 密鑰交換算法

RSA本質(zhì)上是為了解決密鑰配送的問題,密鑰配送的是配送的是運算對稱密鑰的關(guān)鍵信息,并不是對稱密鑰

RSA:這是一個標(biāo)準(zhǔn)的密鑰交換算法,在ClientKeyExchange階段客戶端生成預(yù)主秘鑰,不支持向前保密,并以服務(wù)器公鑰加密傳送給服務(wù)器

DHE_RSA:臨時Diffie-Hellman(ephemeral Diffie-Hellman, DHE),支持向前保密,缺點是執(zhí)行緩慢,DHE是一種秘鑰協(xié)定算法,進行協(xié)商的團體都對密鑰生成產(chǎn)生作用,并對公共密鑰產(chǎn)生作用

ECDHE_RSA和ECDHE_ECDSA:

臨時橢圓曲線Diffe-Hellman(ephemeral elliptic curve Diffie-Hellman, ECDHE)密鑰交換建立在橢圓曲線加密的基礎(chǔ)之上。執(zhí)行很快而且提供了向前保密,和DHE類似

過濾了一臺設(shè)備上一天的數(shù)據(jù)

加密套件

完整名稱

條數(shù)

比例

ECDHE-RSA-AES128-SHA256

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

590549

89.67%

DHE-RSA-AES256-GCM-SHA384

TLS_DHE_RSA_WITH_AES_256_GCM_SHA384

33802

5.13%

ECDHE-RSA-AES256-GCM-SHA384

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

18150

2.76%

DHE-RSA-AES256-SHA256

TLS_DHE_RSA_WITH_AES_256_CBC_SHA256

12845

1.95%

ECDHE-RSA-AES256-SHA

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

1462

0.22%

ECDHE-RSA-CHACHA20-POLY1305

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

1388

0.21%

AES256-SHA256

TLS_RSA_WITH_AES_256_CBC_SHA256

302

0.05%

ECDHE-RSA-AES128-GCM-SHA256

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

36

0.01%

DHE-RSA-AES256-SHA

TLS_DHE_RSA_WITH_AES_256_CBC_SHA

23

0%

AES256-SHA

TLS_RSA_WITH_AES_256_CBC_SHA

1

0%

TLS握手中使用的密碼技術(shù)

TLS記錄協(xié)議位于TLS協(xié)議的下層,是負(fù)責(zé)使用對稱密碼對消息進行加密通信(對消息壓縮、加密以及數(shù)據(jù)的認(rèn)證)的部分

  • TLS握手協(xié)議中使用的密碼技術(shù)

公鑰密碼:加密預(yù)主秘鑰用的

單向散列函數(shù):構(gòu)成偽隨機數(shù)生成器

數(shù)字簽名:驗證證書用的(單向散列函數(shù)計算公鑰密碼的散列值,加密后得到)

偽隨機書生成器:生成預(yù)主秘鑰

                      生成初始化向量(可以使用對稱密碼,單向散列函數(shù)來構(gòu)建)?

                     根據(jù)主密鑰生成密鑰(密碼參數(shù))?

  • TLS記錄協(xié)議中使用的密碼技術(shù)

對稱密碼(CBC模式):確保片段的機密性

消息認(rèn)證碼:確保片段的完整性并進行認(rèn)證(單向散列函數(shù)和密鑰組合而成,也可以通過對稱密碼生成,應(yīng)用單向散列函數(shù)計算密鑰+消息構(gòu)成的)

認(rèn)證加密(AEAD,Authenticated-Encryption with Associated-Data用于關(guān)聯(lián)數(shù)據(jù)的認(rèn)證加密):確保片段的完整性和機密性并進行認(rèn)證?

HTTPS中所用到的密碼技術(shù)

證書:公鑰、數(shù)字簽名和指紋組合而成,一般講是基于指紋的數(shù)字簽名,一堆的東西就認(rèn)證公鑰,為了保證不可否認(rèn)行、認(rèn)證、完整性

Keyless原理

總體架構(gòu)

nginx怎么實現(xiàn)keyless

密鑰交換算法類

握手協(xié)議

密鑰建立

認(rèn)證

RSA

RSA

RSA

DH

DH

RSA/DSA

client random 是第1個隨機數(shù)R1(公開),對應(yīng)wireshark抓包里“Client Hello”的Random

server random 是第2個隨機數(shù)R2(公開),對應(yīng)wireshark抓包里“Server Hello”的Random

premaster 是第3個隨機數(shù)R3(私密),該隨機數(shù)是由客戶端創(chuàng)建,然后客戶端用服務(wù)端傳來的證書對premaster secret進行加密,生成premaster secret用來實際傳輸,對應(yīng)抓包里的“Client Key Exchange”

服務(wù)端用私鑰對premaster secret解密,得到premaster,這樣只有客戶端和服務(wù)端知道premaster

最終,客戶端和服務(wù)端用公開的隨機數(shù)R1、R2、雙方私密的premaster(R3)組合起來,通過預(yù)定的算法生成一個hash值,作為之后的對話密鑰(session key)

nginx怎么實現(xiàn)keyless

RSA密鑰交換算法主密鑰計算

Client Random和Server Random明文傳輸,中間人可以直接查看,客戶端生成于中Premaster Secret后,如果有證書私鑰就可以直接通過這三個參數(shù)解得主密鑰

nginx怎么實現(xiàn)keyless

標(biāo)準(zhǔn)RSAkeyless握手方案

工作在:Server端的ChangeCipherSpec階段

基于DH的完整握手主密鑰的計算

從密鑰交換流程來說,DH算法和ECDHE一樣,二者的主要區(qū)別見該頁備注里的注意點1~3

client random 是第1個隨機數(shù)R1(公開),對應(yīng)wireshark抓包里“Client Hello”的Random ②a、server random 是第2個隨機數(shù)R2(公開),對應(yīng)wireshark抓包里“Server Hello”的Random

服務(wù)端自己創(chuàng)建一個隨機數(shù)或者 直接從證書中拿公鑰信息(圖例是拿公鑰信息),記為R3 ,結(jié)合上面的兩個公開的隨機數(shù),通過DH算法算出來服務(wù)端DH參數(shù)=(R1 * R2 * R3) ,對應(yīng)wireshark抓包里“Server Key Exchange”的Pubkey。

服務(wù)端用私鑰,對兩個公開隨機數(shù)R1、R2和服務(wù)端的DH參數(shù)進行簽名,對應(yīng)wireshark抓包里“Server Key Exchange”的Signature

客戶端用證書公鑰驗證Signature,驗證服務(wù)端確實擁有私鑰后,客戶端就創(chuàng)建一個隨機數(shù),記為R4,通過DH算法算出來客戶端DH參數(shù)=(R1 * R2 * R4) ,對應(yīng)wireshark抓包里“Client Key Exchange”的Pubkey 。 這樣,客戶端和服務(wù)端用對方發(fā)來的DH參數(shù),結(jié)合各自的私有隨機數(shù)R3或R4,分別計算得到相同的premaster = (R1 * R2 * R3 * R4) ,且只有客戶端和服務(wù)端知道premaster 最終,客戶端和服務(wù)端用公開的隨機數(shù)1、隨機數(shù)2、雙方私密的premaster組合起來,通過預(yù)定的算法生成一個hash值,作為之后的對話密鑰(session key)

nginx怎么實現(xiàn)keyless

Server DH Parameter 是用證書私鑰簽名的,客戶端使用證書公鑰就可以驗證服務(wù)端合法性,相比 RSA 密鑰交換,DH 由傳遞 Premaster Scret 變成了傳遞 DH 算法所需的 Parameter,然后雙方各自算出 Premaster Secret。由于 Premaster Secret 無需交換,中間人就算有私鑰也無法獲得 Premaster Secret 和 Master Secret。

ServerKeyExchange

基于DH的keyless的完整握手

nginx怎么實現(xiàn)keyless

工作在:Server端的ServerKeyExchange階段

開源項目做了什么

nginx怎么實現(xiàn)keyless

keyless server安裝和配置

存儲給定的私鑰。

使用加速卡(EXAR)進行解密,簽名操作。

狀態(tài)信息統(tǒng)計。

開源項目地址:https://github.com/cloudflare/keyless

需要進行二次開發(fā),開源版本很多細(xì)節(jié)處理的不好。

On Centos:

sudo yum install gcc automake libtool
 sudo yum install rpm-build rubybgems ruby-devel # only required for packages
 sudo gem install fpm --no-ri --no-rdoc # only required for packages

安裝 make即可,make test測試

參數(shù)說明 --port keyless server端的監(jiān)聽端口

          --ip keyless server端監(jiān)聽的ip

          --server-cert和--server-key簽發(fā)的證書

         --private-key-directory 用戶證書對應(yīng)的私鑰存放文件夾

          --ca-file生成的根證書

          --pid-file pid文件

         --num-workers 線程數(shù)

        --verbose打印日志

        --daemon守護進程開啟

nginx于keyless server交互?

nginx怎么實現(xiàn)keyless

在SSL_do_handshake解密和簽名處理過程中增加一個keyless狀態(tài)。

PREPARE REQUEST狀態(tài),封裝keyless請求報文,然后將狀態(tài)設(shè)置為SEND REQUEST,SSL_do_handshake函數(shù)返回,nginx將keyless_connection的wev放到epoll里;

SEND REQUEST狀態(tài)發(fā)送keyless請求,成功后將狀態(tài)設(shè)置為RECEIVE RESPONSE,SSL_do_handshake函數(shù)返回,nginx將keyless_connection的rev放到epoll里;

RECEIVE RESPONSE狀態(tài)讀請求,全部讀完將狀態(tài)設(shè)置為FINISH;如果未讀完數(shù)據(jù)SSL_do_handshake函數(shù)返回,nginx將keyless_connection的rev放到epoll里;

FINISH 繼續(xù)由openssl原有的邏輯處理。

如果rev和wev超時,則關(guān)閉ssl_connection。

nginx 處理https握手

ngx_http_init_connection中recv→handler設(shè)置為ngx_http_ssl_handshake,把這個讀時間加入到epoll中,重點看handshake這個函數(shù)

static void

ngx_http_ssl_handshake(ngx_event_t *rev)

{

...

n = recv(c->fd, (char *) buf, size, MSG_PEEK);

//判斷協(xié)議

if (n == 1) {

if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {

// 獲取loc conf和server conf

clcf = ngx_http_get_module_loc_conf(hc->conf_ctx,

ngx_http_core_module);


if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {

ngx_http_close_connection(c);

return;

}


sscf = ngx_http_get_module_srv_conf(hc->conf_ctx,

ngx_http_ssl_module);

// 調(diào)用該函數(shù)生成ssl

if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)

!= NGX_OK)

{

ngx_http_close_connection(c);

return;

}

}

}

...

}

ngx_int_t

ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)

{

...

sc->session_ctx = ssl->ctx;


sc->connection = SSL_new(ssl->ctx);


if (sc->connection == NULL) {

ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");

return NGX_ERROR;

}


if (SSL_set_fd(sc->connection, c->fd) == 0) {

ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");

return NGX_ERROR;

}

...

}

第一次收到client hello之后,完成初始化后調(diào)用ngx_ssl_handshake,其調(diào)用openssl的ssl_do_handshake

ngx_int_t

ngx_ssl_handshake(ngx_connection_t *c)

{

...

n = ngx_ssl_handshake_early_data(c);

n = SSL_do_handshake(c->ssl->connection);

...

}

調(diào)用keyless模塊的init函數(shù)先是獲取coremodule的main conf,然后獲取到servers,遍歷這些servers的上下文中的srv conf配置,然后把sscf→ssl.ctx設(shè)置cert_cb為keyless_cert_handler,這個函數(shù)在api使用證書的時候會調(diào)用。

static ngx_int_t

ngx_http_ssl_keyless_init(ngx_conf_t *cf)

{

...

cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);


cscfp = cmcf->servers.elts;


for (s = 0; s < cmcf->servers.nelts; s++) {


sscf = cscfp[s]->ctx->srv_conf[ngx_http_ssl_module.ctx_index];

kscf = cscfp[s]->ctx->srv_conf[ngx_http_ssl_keyless_module.ctx_index];

if (sscf->enable == 1 && kscf->enable == 1) {

//TODO set prev cert callback handler.

kscf->prev_ssl_cert_cb = ngx_http_lua_ssl_cert_handler;

#endif

SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_ssl_keyless_cert_handler, NULL);


}

...

}

cert handler做了了很多事情,初始化了很多nginx keyless相關(guān)的參數(shù),核心在于這個函數(shù)新建了一條通向keyserver的連接。

static int

ngx_http_ssl_keyless_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data)

{

...

if (ngx_http_ssl_keyless_get_keyserver_pc(klss) != NGX_OK) {

ngx_log_error(NGX_LOG_ERR, c->log, 0, "init keyless sess");

}


klss_state->data = klss;

klss_state->state = KEYLESS_STATE_RSA_INIT;


c->klss = klss;

pc = klss->pc;


rc = ngx_event_connect_peer(klss->pc);

pcc = ((ngx_peer_connection_t *)klss->pc)->connection;


pcc->data = klss;

pcc->write->handler = ngx_http_ssl_keyless_keyserver_handler;

pcc->read->handler = ngx_http_ssl_keyless_keyserver_handler;

...

}

static ngx_int_t

ngx_http_ssl_keyless_get_keyserver_pc(ngx_http_keyless_sess_t *klss)

{

...

pc->get = ngx_http_ssl_keyless_peer_get;

pc->free = ngx_http_ssl_keyless_peer_free;

...

}

do handshake的時候調(diào)用的是openssl的async job的庫,相當(dāng)于新開一個函數(shù)棧

ASYNC JOB

int SSL_do_handshake(SSL *s)

{

...

if (SSL_in_init(s) || SSL_in_before(s)) {

if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {

struct ssl_async_args args;


args.s = s;


ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);

} else {

ret = s->handshake_func(s);

}

}

...

}

int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,

int (*func)(void *), void *args, size_t size)

{

...

/* Start a new job */

if ((ctx->currjob = async_get_pool_job()) == NULL)

return ASYNC_NO_JOBS;

...

}

static ASYNC_JOB *async_get_pool_job(void) {

...

if (job == NULL) {

/* Pool is empty */

if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size))

return NULL;


job = async_job_new();

if (job != NULL) {

if (! async_fibre_makecontext(&job->fibrectx)) {

async_job_free(job);

return NULL;

}

pool->curr_size++;

}

}

...

}

先做初始化get下context,malloc一個stack,這個堆棧創(chuàng)建完成后把函數(shù)放進去,使用makecontext來創(chuàng)建一旦調(diào)用就會運行該函數(shù),async_start_func本身使用當(dāng)前job中的func,函數(shù)也是傳進來的參數(shù)

int async_fibre_makecontext(async_fibre *fibre)

{

fibre->env_init = 0;

if (getcontext(&fibre->fibre) == 0) {           //初始化當(dāng)前ucontext

fibre->fibre.uc_stack.ss_sp = OPENSSL_malloc(STACKSIZE);

if (fibre->fibre.uc_stack.ss_sp != NULL) {

fibre->fibre.uc_stack.ss_size = STACKSIZE;

fibre->fibre.uc_link = NULL;

makecontext(&fibre->fibre, async_start_func, 0);

return 1;

}

} else {

fibre->fibre.uc_stack.ss_sp = NULL;

}

return 0;

}

Pause job最關(guān)鍵的是swapcontext,這個在func中一旦被調(diào)用的話,就可以立即切換棧信息,切回start_job的主函數(shù),根據(jù)job→status=ASYNC_JOB_PAUSING來返回

int ASYNC_pause_job(void)

{

...

if (!async_fibre_swapcontext(&job->fibrectx,

&ctx->dispatcher, 1)) {

ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);

return 0;

}

...

}

切回主函數(shù)之后,因為start job是for死循環(huán),所以會根據(jù)job的狀態(tài)進行返回

int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,

int (*func)(void *), void *args, size_t size)

{

...

for (;;) {

if (ctx->currjob != NULL) {

if (ctx->currjob->status == ASYNC_JOB_PAUSING) {

*job = ctx->currjob;

ctx->currjob->status = ASYNC_JOB_PAUSED;

ctx->currjob = NULL;

return ASYNC_PAUSE;

}

if (ctx->currjob->status == ASYNC_JOB_PAUSED) {

ctx->currjob = *job;

/* Resume previous job */

if (!async_fibre_swapcontext(&ctx->dispatcher,

&ctx->currjob->fibrectx, 1)) {

ASYNCerr(ASYNC_F_ASYNC_START_JOB,

ASYNC_R_FAILED_TO_SWAP_CONTEXT);

goto err;

}

continue;

}

...

}

static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,

int (*func) (void *))

{

...

switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,

sizeof(struct ssl_async_args))) {

case ASYNC_ERR:

s->rwstate = SSL_NOTHING;

SSLerr(SSL_F_SSL_START_ASYNC_JOB, SSL_R_FAILED_TO_INIT_ASYNC);

return -1;

case ASYNC_PAUSE:

s->rwstate = SSL_ASYNC_PAUSED;

return -1;

}

...

}

返回的這個狀態(tài)碼,在nginx里面接到就是SSL_ERROR_WANT_ASYNC

關(guān)鍵就是調(diào)用async_pause_job交還給nginx來做keyless處理,以及將與keyserver的狀態(tài)調(diào)整為presend。

int kls_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)

{

...

waitctx = ASYNC_get_wait_ctx(job);

ASYNC_WAIT_CTX_get_fd(waitctx, (void *)waitctx, &fd, (void *)&klss_state);

if (klss_state->state == KEYLESS_STATE_RSA_INIT) {

klss_state->is_rsa_decrypt = 1;

dec_ctx = &klss_state->dec_ctx;

dec_ctx->from = from;

dec_ctx->to = to;

dec_ctx->flen = flen;

dec_ctx->padding = padding;

klss_state->state = KEYLESS_STATE_RSA_PRE_SEND;

ASYNC_pause_job();

}

...

}

這里處理完交還給nginx,之后nginx 就可以做原本由openssl實現(xiàn)的加解密。

重寫engine重寫兩個關(guān)鍵函數(shù)

static int bind_helper(ENGINE *e)

{

kls_rsa_meth = RSA_meth_new("keyless rsa method", RSA_METHOD_FLAG_NO_CHECK);

RSA_meth_set_sign(kls_rsa_meth, kls_rsa_sign);

RSA_meth_set_priv_dec(kls_rsa_meth, kls_rsa_private_decrypt);



if (!ENGINE_set_id(e, engine_keyless_id) ||

!ENGINE_set_name(e, engine_keyless_name) ||

!ENGINE_set_RSA(e, kls_rsa_meth)) {


return 0;

}


return 1;

}


static ENGINE *ENGINE_keyless(void)

{

ENGINE *e = ENGINE_new();

if (e == NULL)

return NULL;

if (!bind_helper(e)) {

ENGINE_free(e);

return NULL;

}

return e;

}


void engine_load_keyless_int(void)

{

ENGINE *e = ENGINE_keyless();

if (e == NULL) {

return;

}


ENGINE_add(e);

ENGINE_free(e);

ERR_clear_error();


return;

}

重寫的兩個函數(shù)是sign和priv_dec

struct rsa_meth_st {

int (*rsa_priv_dec) (int flen, const unsigned char *from,

unsigned char *to, RSA *rsa, int padding);

int (*rsa_sign) (int type,

const unsigned char *m, unsigned int m_length,

unsigned char *sigret, unsigned int *siglen,

const RSA *rsa);

}


int kls_rsa_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, const RSA *rsa)

{

...

waitctx = ASYNC_get_wait_ctx(job);

ASYNC_WAIT_CTX_get_fd(waitctx, (void *)waitctx, &fd, (void *)&klss_state);


if (klss_state->state == KEYLESS_STATE_RSA_INIT) {

klss_state->is_rsa_sign = 1;

sign_ctx = &klss_state->sign_ctx;

sign_ctx = &klss_state->sign_ctx;

sign_ctx->type = type;

sign_ctx->m = m;

sign_ctx->m_length = m_length;

klss_state->state = KEYLESS_STATE_RSA_PRE_SEND;

ASYNC_pause_job();

}

...

}

調(diào)用pause時最重要邏輯是async_fibre_swapcontext,這個函數(shù)是用于切換的核心,同時進行初始化操作,把函數(shù)放到新開辟棧里運行。

static ossl_inline int async_fibre_swapcontext(async_fibre *o, async_fibre *n, int r)

{

o->env_init = 1;


if (!r || !_setjmp(o->env)) {

if (n->env_init)

_longjmp(n->env, 1);

else

setcontext(&n->fibre);

}


return 1;

}

“nginx怎么實現(xiàn)keyless”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI