In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.