Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize keyless with nginx

2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the relevant knowledge of "how to achieve keyless in nginx". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Brief introduction

When the enterprise migrates the business to the cloud WAF/CDN edge node, the private key security of the business that needs to be provided to the cloud vendor can not be guaranteed, and if the business private key certificate is changed or frequently modified, it needs to be limited by people. Risk: once the private key of the server is disclosed, it will cause a malicious attacker to forge a false communication between the server and the client, and the communication content is also at risk of being hijacked and decrypted. Keyless originates from clouldflare and uses the keyless solution to deploy the private key on the customer's own server. There is no need to deploy the business private key on the cloud / CDN edge node.

Clouldflare keyless project address: https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/

Cloudflare keyless open source project address: https://github.com/cloudflare/keyless

Introduction to related basic knowledge: popularization of encryption and decryption kit

MAC (Message authentication code): message authentication code

PRF (pseudorandom function): pseudorandom function

SHA (Secure Hash Algorithm): secure hashing algorithm

Symmetric password:

DES: it is encrypted in 64-bit plaintext, and the key length is 64 bits.

Triple DES: repeat the DES 3 times, with 3 keys

AES (Advanced Encryption Standard): a new standard symmetric cryptographic algorithm that has replaced DES

The packet length is 128 bits and the key length is 128, 192 and 256

Block cipher mode:

ECB (Electronic CodeBook): the result of plaintext grouping encryption will directly become ciphertext grouping

CBC (Cipher Block Chaining): the mode of ciphertext grouping links

CFB (Cipher FeedBack): ciphertext feedback mode

OFB (Output-Feedback): input feedback mode

CTR (CounTeR): counter mode

GCM (Galois Counter Mode): Galois/ counter mode

Fill mode: when the plaintext length is not an integer multiple of the packet length, the attacker will use this to fill some data in the last packet to fill a packet length.

One-way hash function

The input is the message output is the hash value, the arbitrary length message calculates the fixed length hash value, different message hash value is also different.

Application: MD4, MD5;SHA-2 series (SHA-256,SHA-384,SHA-512, numbers represent the length of calculated hash values)

Key exchange algorithm

In essence, RSA is to solve the problem of key distribution, which distributes the key information of computing symmetric keys, not symmetric keys.

RSA: this is a standard key exchange algorithm. During the ClientKeyExchange phase, the client generates a pre-master key, which does not support forward secrecy, and is encrypted and transmitted to the server with the server public key.

DHE_RSA: temporary Diffie-Hellman (ephemeral Diffie-Hellman, DHE), which supports forward secrecy, but has the disadvantage of slow execution. DHE is a secret key protocol algorithm, and the negotiating groups have an effect on key generation and public key generation.

ECDHE_RSA and ECDHE_ECDSA:

Temporary elliptic curve Diffe-Hellman (ephemeral elliptic curve Diffie-Hellman, ECDHE) key exchange is based on elliptic curve encryption. Execution is fast and provides forward confidentiality, similar to DHE

Filtered a day's data on a device.

Cipher kit

Full name

Number of entries

Proportion

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

three hundred and two

0.05%

ECDHE-RSA-AES128-GCM-SHA256

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

thirty-six

0.01%

DHE-RSA-AES256-SHA

TLS_DHE_RSA_WITH_AES_256_CBC_SHA

twenty-three

0%

AES256-SHA

TLS_RSA_WITH_AES_256_CBC_SHA

one

0%

Cryptographic techniques used in TLS handshakes

The TLS recording protocol, located at the lower layer of the TLS protocol, is responsible for encrypting messages using symmetric passwords (message compression, encryption, and data authentication).

Cryptographic techniques used in TLS handshake Protocol

Public key password: used to encrypt the pre-master key

One-way hash function: constitutes a pseudorandom number generator

Digital signature: used to verify the certificate (the one-way hash function calculates the hash value of the public key password and gets it after encryption)

Pseudo-random book generator: generate pre-master key

Generate initialization vectors (can be built using symmetric passwords, one-way hash functions)?

Generate a key based on the master key (password parameter)?

Cryptographic techniques used in TLS recording protocols

Symmetric cipher (CBC mode): ensures the confidentiality of fragments

Message authentication code: ensures the integrity of the fragment and authenticates it (composed of an one-way hash function and a key, or it can be generated by a symmetric password, and an one-way hash function is used to calculate the key + message)

Authenticated encryption (AEAD,Authenticated-Encryption with Associated-Data for authenticated encryption of associated data): ensure the integrity and confidentiality of fragments and authenticate them?

Cryptographic techniques used in HTTPS

Certificate: a combination of public key, digital signature and fingerprint. Generally speaking, it is a digital signature based on fingerprint. A bunch of things authenticate the public key in order to ensure the undeniable line, authentication and integrity.

Keyless principle

Overall architecture

Key exchange algorithm class

Handshake protocol

Key establishment

Authentication

RSA

RSA

RSA

DH

DH

RSA/DSA

Client random is the first random number R1 (public), corresponding to the Random of "Client Hello" in the wireshark grab packet.

Server random is the second random number R2 (public), corresponding to the Random of "Server Hello" in the wireshark grab package.

Premaster is the third random number R3 (private), which is created by the client, and then the client encrypts the premaster secret with the certificate sent from the server to generate premaster secret for actual transmission, corresponding to the "Client Key Exchange" in the capture packet.

The server decrypts the premaster secret with the private key to get the premaster, so that only the client and the server know the premaster

Finally, the client and the server are combined with the open random numbers R1, R2 and their private premaster (R3) to generate a hash value through a predetermined algorithm, which is used as the later conversation key (session key).

Master key calculation of RSA key Exchange algorithm

Client Random and Server Random plaintext transmission, which can be viewed directly by the middleman. After the client is generated in Premaster Secret, if you have a certificate private key, you can directly obtain the master key through these three parameters.

Standard RSAkeyless handshake scheme

Work in the ChangeCipherSpec phase on the server side

Calculation of Master key of complete handshake based on DH

In terms of the key exchange process, the DH algorithm is the same as ECDHE, and the main difference between them can be found in note 1: 3 on this page.

Client random is the first random number R1 (public), corresponding to Random ② an and server random of "Client Hello" in wireshark grab packet is the second random number R2 (public), and corresponding to the Random of "Server Hello" in wireshark grab packet.

The server creates a random number or takes the public key information directly from the certificate (the legend takes the public key information) and marks it as R3. Combined with the above two public random numbers, the server DH parameter = (R1 * R2 * R3) is calculated by the DH algorithm, which corresponds to the Pubkey of "Server Key Exchange" in the wireshark package.

The server uses the private key to sign the two public random numbers R1, R2 and the DH parameters of the server, corresponding to the Signature of "Server Key Exchange" in the wireshark packet.

The client verifies the Signature with the certificate public key, and after verifying that the server does have the private key, the client creates a random number, marked as R4, and calculates the client DH parameter = (R1 * R2 * R4) through the DH algorithm, corresponding to the Pubkey of "Client Key Exchange" in the wireshark packet. In this way, the client and the server use the DH parameters sent by each other, combined with their respective private random numbers R3 or R4, to calculate the same premaster = (R1 * R2 * R3 * R4), and only the client and the server know the premaster. In the end, the client and the server combine the open random number 1, the random number 2 and the private premaster of both sides to generate a hash value through a predetermined algorithm, which is used as the conversation key (session key).

Server DH Parameter is signed with a certificate private key, and the client can use the certificate public key to verify the server's validity. Compared with RSA key exchange, DH changes from passing Premaster Scret to Parameter needed to transfer DH algorithm, and then both sides calculate the Premaster Secret respectively. Since Premaster Secret does not need to be exchanged, the middleman cannot obtain Premaster Secret and Master Secret even if he has a private key.

ServerKeyExchange

Complete handshake of keyless based on DH

Work in the ServerKeyExchange phase on the server side

What did the open source project do?

Keyless server installation and configuration

Stores the given private key.

Use accelerator card (EXAR) for decryption and signature operation.

Status information statistics.

Open source project address: https://github.com/cloudflare/keyless

Need to carry out secondary development, open source version of a lot of details are not handled well.

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

Just install make, make test test

Parameter description-listening port on port keyless server

-- ip listened to by the ip keyless server

Certificates issued by server-cert and-server-key

-- folder for storing private keys corresponding to private-key-directory user certificates

-- the root certificate generated by ca-file

-- pid-file pid file

-- number of num-workers threads

-- verbose prints the log

-- daemon daemon is enabled

Nginx interacts with keyless server

Add a keyless state during SSL_do_handshake decryption and signature processing.

PREPARE REQUEST status, encapsulating the keyless request message, then setting the status to be returned by the SEND REQUEST,SSL_do_handshake function, and nginx putting the wev of the keyless_connection into the epoll

The SEND REQUEST status sends the keyless request. After success, the status is set to return by the RECEIVE RESPONSE,SSL_do_handshake function, and nginx puts the rev of keyless_connection into the epoll.

RECEIVE RESPONSE status read request. Set the status to FINISH; after all readings. If the SSL_do_handshake function returns, nginx will put the rev of keyless_connection into epoll.

FINISH continues to be handled by openssl's original logic.

If rev and wev time out, close ssl_connection.

Nginx handles https handshake

Recv → handler in ngx_http_init_connection is set to ngx_http_ssl_handshake. Add this read time to epoll, focusing on the function handshake.

Static void

Ngx_http_ssl_handshake (ngx_event_t * rev)

{

...

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

/ / judge the agreement

If (n = = 1) {

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

/ / obtain loc conf and 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)

/ / call this function to generate ssl

If (& 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

}

...

}

After receiving the client hello for the first time, call ngx_ssl_handshake after initialization, which calls the ssl_do_handshake of openssl

Ngx_int_t

Ngx_ssl_handshake (ngx_connection_t * c)

{

...

N = ngx_ssl_handshake_early_data (c)

N = SSL_do_handshake (c-> ssl- > connection)

...

}

Call the init function of the keyless module to first get the main conf of the coremodule, then get the servers, traverse the srv conf configuration in the context of these servers, and then set the sscf → ssl.ctx to cert_cb to keyless_cert_handler. This function is called when api uses the certificate.

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; slots +) {

Sscf = cscfp [s]-> ctx- > srv_ confession [NGX _ http_ssl_module.ctx_index]

Kscf = cscfp [s]-> ctx- > srv_ confession [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 does a lot of things, initializing a lot of nginx keyless-related parameters, and the core is that this function creates a new connection to 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 calls openssl's async job library, which is equivalent to opening a new function stack.

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++

}

}

...

}

First initialize context,malloc a stack under get. After the stack is created, put the function into it. Use makecontext to create the function that will run once called. Async_start_func itself uses the func in the current job, and the function is also passed in parameters.

Int async_fibre_makecontext (async_fibre * fibre)

{

Fibre- > env_init = 0

If (& fibre- > fibre) = = 0) {/ / initialize the current 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

}

The most important thing in Pause job is swapcontext. Once this is called in func, you can immediately switch stack information, switch back to the main function of start_job, and return according to 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

}

...

}

After switching back to the main function, because start job is a for loop, it will be returned according to the state of job

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

}

...

}

The returned status code is received as SSL_ERROR_WANT_ASYNC in nginx.

The key is to call async_pause_job and return it to nginx for keyless processing, and to adjust the state with keyserver to 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 ()

}

...

}

After processing here, it is returned to nginx, and then nginx can do the encryption and decryption originally implemented by openssl.

Rewrite engine rewrite two key functions

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

}

The two rewritten functions are sign and 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 ()

}

...

}

The most important logic when calling pause is async_fibre_swapcontext, which is the core of the switch, initializes the function and runs the function on the newly opened stack.

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

}

This is the end of the content of "how to achieve keyless in nginx". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report