src/event/ngx_event_openssl_cache.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_event.h>


  7. #define NGX_SSL_CACHE_PATH    0
  8. #define NGX_SSL_CACHE_DATA    1
  9. #define NGX_SSL_CACHE_ENGINE  2


  10. typedef struct {
  11.     unsigned                    type:2;
  12.     unsigned                    len:30;
  13.     u_char                     *data;
  14. } ngx_ssl_cache_key_t;


  15. typedef void *(*ngx_ssl_cache_create_pt)(ngx_ssl_cache_key_t *id, char **err,
  16.     void *data);
  17. typedef void (*ngx_ssl_cache_free_pt)(void *data);
  18. typedef void *(*ngx_ssl_cache_ref_pt)(char **err, void *data);


  19. typedef struct {
  20.     ngx_ssl_cache_create_pt     create;
  21.     ngx_ssl_cache_free_pt       free;
  22.     ngx_ssl_cache_ref_pt        ref;
  23. } ngx_ssl_cache_type_t;


  24. typedef struct {
  25.     ngx_rbtree_node_t           node;
  26.     ngx_ssl_cache_key_t         id;
  27.     ngx_ssl_cache_type_t       *type;
  28.     void                       *value;
  29. } ngx_ssl_cache_node_t;


  30. typedef struct {
  31.     ngx_rbtree_t                rbtree;
  32.     ngx_rbtree_node_t           sentinel;
  33. } ngx_ssl_cache_t;


  34. static ngx_int_t ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index,
  35.     ngx_str_t *path, ngx_ssl_cache_key_t *id);
  36. static ngx_ssl_cache_node_t *ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache,
  37.     ngx_ssl_cache_type_t *type, ngx_ssl_cache_key_t *id, uint32_t hash);

  38. static void *ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err,
  39.     void *data);
  40. static void ngx_ssl_cache_cert_free(void *data);
  41. static void *ngx_ssl_cache_cert_ref(char **err, void *data);

  42. static void *ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err,
  43.     void *data);
  44. static int ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
  45.     void *userdata);
  46. static void ngx_ssl_cache_pkey_free(void *data);
  47. static void *ngx_ssl_cache_pkey_ref(char **err, void *data);

  48. static void *ngx_ssl_cache_crl_create(ngx_ssl_cache_key_t *id, char **err,
  49.     void *data);
  50. static void ngx_ssl_cache_crl_free(void *data);
  51. static void *ngx_ssl_cache_crl_ref(char **err, void *data);

  52. static void *ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err,
  53.     void *data);

  54. static BIO *ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err);

  55. static void *ngx_openssl_cache_create_conf(ngx_cycle_t *cycle);
  56. static void ngx_ssl_cache_cleanup(void *data);
  57. static void ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
  58.     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);


  59. static ngx_core_module_t  ngx_openssl_cache_module_ctx = {
  60.     ngx_string("openssl_cache"),
  61.     ngx_openssl_cache_create_conf,
  62.     NULL
  63. };


  64. ngx_module_t  ngx_openssl_cache_module = {
  65.     NGX_MODULE_V1,
  66.     &ngx_openssl_cache_module_ctx,         /* module context */
  67.     NULL,                                  /* module directives */
  68.     NGX_CORE_MODULE,                       /* module type */
  69.     NULL,                                  /* init master */
  70.     NULL,                                  /* init module */
  71.     NULL,                                  /* init process */
  72.     NULL,                                  /* init thread */
  73.     NULL,                                  /* exit thread */
  74.     NULL,                                  /* exit process */
  75.     NULL,                                  /* exit master */
  76.     NGX_MODULE_V1_PADDING
  77. };


  78. static ngx_ssl_cache_type_t  ngx_ssl_cache_types[] = {

  79.     /* NGX_SSL_CACHE_CERT */
  80.     { ngx_ssl_cache_cert_create,
  81.       ngx_ssl_cache_cert_free,
  82.       ngx_ssl_cache_cert_ref },

  83.     /* NGX_SSL_CACHE_PKEY */
  84.     { ngx_ssl_cache_pkey_create,
  85.       ngx_ssl_cache_pkey_free,
  86.       ngx_ssl_cache_pkey_ref },

  87.     /* NGX_SSL_CACHE_CRL */
  88.     { ngx_ssl_cache_crl_create,
  89.       ngx_ssl_cache_crl_free,
  90.       ngx_ssl_cache_crl_ref },

  91.     /* NGX_SSL_CACHE_CA */
  92.     { ngx_ssl_cache_ca_create,
  93.       ngx_ssl_cache_cert_free,
  94.       ngx_ssl_cache_cert_ref }
  95. };


  96. void *
  97. ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
  98.     ngx_str_t *path, void *data)
  99. {
  100.     uint32_t               hash;
  101.     ngx_ssl_cache_t       *cache;
  102.     ngx_ssl_cache_key_t    id;
  103.     ngx_ssl_cache_type_t  *type;
  104.     ngx_ssl_cache_node_t  *cn;

  105.     *err = NULL;

  106.     if (ngx_ssl_cache_init_key(cf->pool, index, path, &id) != NGX_OK) {
  107.         return NULL;
  108.     }

  109.     cache = (ngx_ssl_cache_t *) ngx_get_conf(cf->cycle->conf_ctx,
  110.                                              ngx_openssl_cache_module);

  111.     type = &ngx_ssl_cache_types[index];
  112.     hash = ngx_murmur_hash2(id.data, id.len);

  113.     cn = ngx_ssl_cache_lookup(cache, type, &id, hash);
  114.     if (cn != NULL) {
  115.         return type->ref(err, cn->value);
  116.     }

  117.     cn = ngx_palloc(cf->pool, sizeof(ngx_ssl_cache_node_t) + id.len + 1);
  118.     if (cn == NULL) {
  119.         return NULL;
  120.     }

  121.     cn->node.key = hash;
  122.     cn->id.data = (u_char *)(cn + 1);
  123.     cn->id.len = id.len;
  124.     cn->id.type = id.type;
  125.     cn->type = type;

  126.     ngx_cpystrn(cn->id.data, id.data, id.len + 1);

  127.     cn->value = type->create(&id, err, data);
  128.     if (cn->value == NULL) {
  129.         return NULL;
  130.     }

  131.     ngx_rbtree_insert(&cache->rbtree, &cn->node);

  132.     return type->ref(err, cn->value);
  133. }


  134. void *
  135. ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, char **err,
  136.     ngx_str_t *path, void *data)
  137. {
  138.     ngx_ssl_cache_key_t  id;

  139.     *err = NULL;

  140.     if (ngx_ssl_cache_init_key(pool, index, path, &id) != NGX_OK) {
  141.         return NULL;
  142.     }

  143.     return ngx_ssl_cache_types[index].create(&id, err, data);
  144. }


  145. static ngx_int_t
  146. ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index, ngx_str_t *path,
  147.     ngx_ssl_cache_key_t *id)
  148. {
  149.     if (index <= NGX_SSL_CACHE_PKEY
  150.         && ngx_strncmp(path->data, "data:", sizeof("data:") - 1) == 0)
  151.     {
  152.         id->type = NGX_SSL_CACHE_DATA;

  153.     } else if (index == NGX_SSL_CACHE_PKEY
  154.         && ngx_strncmp(path->data, "engine:", sizeof("engine:") - 1) == 0)
  155.     {
  156.         id->type = NGX_SSL_CACHE_ENGINE;

  157.     } else {
  158.         if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, path)
  159.             != NGX_OK)
  160.         {
  161.             return NGX_ERROR;
  162.         }

  163.         id->type = NGX_SSL_CACHE_PATH;
  164.     }

  165.     id->len = path->len;
  166.     id->data = path->data;

  167.     return NGX_OK;
  168. }


  169. static ngx_ssl_cache_node_t *
  170. ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache, ngx_ssl_cache_type_t *type,
  171.     ngx_ssl_cache_key_t *id, uint32_t hash)
  172. {
  173.     ngx_int_t              rc;
  174.     ngx_rbtree_node_t     *node, *sentinel;
  175.     ngx_ssl_cache_node_t  *cn;

  176.     node = cache->rbtree.root;
  177.     sentinel = cache->rbtree.sentinel;

  178.     while (node != sentinel) {

  179.         if (hash < node->key) {
  180.             node = node->left;
  181.             continue;
  182.         }

  183.         if (hash > node->key) {
  184.             node = node->right;
  185.             continue;
  186.         }

  187.         /* hash == node->key */

  188.         cn = (ngx_ssl_cache_node_t *) node;

  189.         if (type < cn->type) {
  190.             node = node->left;
  191.             continue;
  192.         }

  193.         if (type > cn->type) {
  194.             node = node->right;
  195.             continue;
  196.         }

  197.         /* type == cn->type */

  198.         rc = ngx_memn2cmp(id->data, cn->id.data, id->len, cn->id.len);

  199.         if (rc == 0) {
  200.             return cn;
  201.         }

  202.         node = (rc < 0) ? node->left : node->right;
  203.     }

  204.     return NULL;
  205. }


  206. static void *
  207. ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err, void *data)
  208. {
  209.     BIO             *bio;
  210.     X509            *x509;
  211.     u_long           n;
  212.     STACK_OF(X509)  *chain;

  213.     chain = sk_X509_new_null();
  214.     if (chain == NULL) {
  215.         *err = "sk_X509_new_null() failed";
  216.         return NULL;
  217.     }

  218.     bio = ngx_ssl_cache_create_bio(id, err);
  219.     if (bio == NULL) {
  220.         sk_X509_pop_free(chain, X509_free);
  221.         return NULL;
  222.     }

  223.     /* certificate itself */

  224.     x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
  225.     if (x509 == NULL) {
  226.         *err = "PEM_read_bio_X509_AUX() failed";
  227.         BIO_free(bio);
  228.         sk_X509_pop_free(chain, X509_free);
  229.         return NULL;
  230.     }

  231.     if (sk_X509_push(chain, x509) == 0) {
  232.         *err = "sk_X509_push() failed";
  233.         BIO_free(bio);
  234.         X509_free(x509);
  235.         sk_X509_pop_free(chain, X509_free);
  236.         return NULL;
  237.     }

  238.     /* rest of the chain */

  239.     for ( ;; ) {

  240.         x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
  241.         if (x509 == NULL) {
  242.             n = ERR_peek_last_error();

  243.             if (ERR_GET_LIB(n) == ERR_LIB_PEM
  244.                 && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
  245.             {
  246.                 /* end of file */
  247.                 ERR_clear_error();
  248.                 break;
  249.             }

  250.             /* some real error */

  251.             *err = "PEM_read_bio_X509() failed";
  252.             BIO_free(bio);
  253.             sk_X509_pop_free(chain, X509_free);
  254.             return NULL;
  255.         }

  256.         if (sk_X509_push(chain, x509) == 0) {
  257.             *err = "sk_X509_push() failed";
  258.             BIO_free(bio);
  259.             X509_free(x509);
  260.             sk_X509_pop_free(chain, X509_free);
  261.             return NULL;
  262.         }
  263.     }

  264.     BIO_free(bio);

  265.     return chain;
  266. }


  267. static void
  268. ngx_ssl_cache_cert_free(void *data)
  269. {
  270.     sk_X509_pop_free(data, X509_free);
  271. }


  272. static void *
  273. ngx_ssl_cache_cert_ref(char **err, void *data)
  274. {
  275.     int              n, i;
  276.     X509            *x509;
  277.     STACK_OF(X509)  *chain;

  278.     chain = sk_X509_dup(data);
  279.     if (chain == NULL) {
  280.         *err = "sk_X509_dup() failed";
  281.         return NULL;
  282.     }

  283.     n = sk_X509_num(chain);

  284.     for (i = 0; i < n; i++) {
  285.         x509 = sk_X509_value(chain, i);

  286. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
  287.         X509_up_ref(x509);
  288. #else
  289.         CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
  290. #endif
  291.     }

  292.     return chain;
  293. }


  294. static void *
  295. ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data)
  296. {
  297.     ngx_array_t  *passwords = data;

  298.     BIO              *bio;
  299.     EVP_PKEY         *pkey;
  300.     ngx_str_t        *pwd;
  301.     ngx_uint_t        tries;
  302.     pem_password_cb  *cb;

  303.     if (id->type == NGX_SSL_CACHE_ENGINE) {

  304. #ifndef OPENSSL_NO_ENGINE

  305.         u_char  *p, *last;
  306.         ENGINE  *engine;

  307.         p = id->data + sizeof("engine:") - 1;
  308.         last = (u_char *) ngx_strchr(p, ':');

  309.         if (last == NULL) {
  310.             *err = "invalid syntax";
  311.             return NULL;
  312.         }

  313.         *last = '\0';

  314.         engine = ENGINE_by_id((char *) p);

  315.         *last++ = ':';

  316.         if (engine == NULL) {
  317.             *err = "ENGINE_by_id() failed";
  318.             return NULL;
  319.         }

  320.         pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);

  321.         if (pkey == NULL) {
  322.             *err = "ENGINE_load_private_key() failed";
  323.             ENGINE_free(engine);
  324.             return NULL;
  325.         }

  326.         ENGINE_free(engine);

  327.         return pkey;

  328. #else

  329.         *err = "loading \"engine:...\" certificate keys is not supported";
  330.         return NULL;

  331. #endif
  332.     }

  333.     bio = ngx_ssl_cache_create_bio(id, err);
  334.     if (bio == NULL) {
  335.         return NULL;
  336.     }

  337.     if (passwords) {
  338.         tries = passwords->nelts;
  339.         pwd = passwords->elts;
  340.         cb = ngx_ssl_cache_pkey_password_callback;

  341.     } else {
  342.         tries = 1;
  343.         pwd = NULL;
  344.         cb = NULL;
  345.     }

  346.     for ( ;; ) {

  347.         pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
  348.         if (pkey != NULL) {
  349.             break;
  350.         }

  351.         if (tries-- > 1) {
  352.             ERR_clear_error();
  353.             (void) BIO_reset(bio);
  354.             pwd++;
  355.             continue;
  356.         }

  357.         *err = "PEM_read_bio_PrivateKey() failed";
  358.         BIO_free(bio);
  359.         return NULL;
  360.     }

  361.     BIO_free(bio);

  362.     return pkey;
  363. }


  364. static int
  365. ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
  366.     void *userdata)
  367. {
  368.     ngx_str_t  *pwd = userdata;

  369.     if (rwflag) {
  370.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  371.                       "ngx_ssl_cache_pkey_password_callback() is called "
  372.                       "for encryption");
  373.         return 0;
  374.     }

  375.     if (pwd == NULL) {
  376.         return 0;
  377.     }

  378.     if (pwd->len > (size_t) size) {
  379.         ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
  380.                       "password is truncated to %d bytes", size);
  381.     } else {
  382.         size = pwd->len;
  383.     }

  384.     ngx_memcpy(buf, pwd->data, size);

  385.     return size;
  386. }


  387. static void
  388. ngx_ssl_cache_pkey_free(void *data)
  389. {
  390.     EVP_PKEY_free(data);
  391. }


  392. static void *
  393. ngx_ssl_cache_pkey_ref(char **err, void *data)
  394. {
  395.     EVP_PKEY  *pkey = data;

  396. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
  397.     EVP_PKEY_up_ref(pkey);
  398. #else
  399.     CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
  400. #endif

  401.     return data;
  402. }


  403. static void *
  404. ngx_ssl_cache_crl_create(ngx_ssl_cache_key_t *id, char **err, void *data)
  405. {
  406.     BIO                 *bio;
  407.     u_long               n;
  408.     X509_CRL            *x509;
  409.     STACK_OF(X509_CRL)  *chain;

  410.     chain = sk_X509_CRL_new_null();
  411.     if (chain == NULL) {
  412.         *err = "sk_X509_CRL_new_null() failed";
  413.         return NULL;
  414.     }

  415.     bio = ngx_ssl_cache_create_bio(id, err);
  416.     if (bio == NULL) {
  417.         sk_X509_CRL_pop_free(chain, X509_CRL_free);
  418.         return NULL;
  419.     }

  420.     for ( ;; ) {

  421.         x509 = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
  422.         if (x509 == NULL) {
  423.             n = ERR_peek_last_error();

  424.             if (ERR_GET_LIB(n) == ERR_LIB_PEM
  425.                 && ERR_GET_REASON(n) == PEM_R_NO_START_LINE
  426.                 && sk_X509_CRL_num(chain) > 0)
  427.             {
  428.                 /* end of file */
  429.                 ERR_clear_error();
  430.                 break;
  431.             }

  432.             /* some real error */

  433.             *err = "PEM_read_bio_X509_CRL() failed";
  434.             BIO_free(bio);
  435.             sk_X509_CRL_pop_free(chain, X509_CRL_free);
  436.             return NULL;
  437.         }

  438.         if (sk_X509_CRL_push(chain, x509) == 0) {
  439.             *err = "sk_X509_CRL_push() failed";
  440.             BIO_free(bio);
  441.             X509_CRL_free(x509);
  442.             sk_X509_CRL_pop_free(chain, X509_CRL_free);
  443.             return NULL;
  444.         }
  445.     }

  446.     BIO_free(bio);

  447.     return chain;
  448. }


  449. static void
  450. ngx_ssl_cache_crl_free(void *data)
  451. {
  452.     sk_X509_CRL_pop_free(data, X509_CRL_free);
  453. }


  454. static void *
  455. ngx_ssl_cache_crl_ref(char **err, void *data)
  456. {
  457.     int                  n, i;
  458.     X509_CRL            *x509;
  459.     STACK_OF(X509_CRL)  *chain;

  460.     chain = sk_X509_CRL_dup(data);
  461.     if (chain == NULL) {
  462.         *err = "sk_X509_CRL_dup() failed";
  463.         return NULL;
  464.     }

  465.     n = sk_X509_CRL_num(chain);

  466.     for (i = 0; i < n; i++) {
  467.         x509 = sk_X509_CRL_value(chain, i);

  468. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
  469.         X509_CRL_up_ref(x509);
  470. #else
  471.         CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509_CRL);
  472. #endif
  473.     }

  474.     return chain;
  475. }


  476. static void *
  477. ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err, void *data)
  478. {
  479.     BIO             *bio;
  480.     X509            *x509;
  481.     u_long           n;
  482.     STACK_OF(X509)  *chain;

  483.     chain = sk_X509_new_null();
  484.     if (chain == NULL) {
  485.         *err = "sk_X509_new_null() failed";
  486.         return NULL;
  487.     }

  488.     bio = ngx_ssl_cache_create_bio(id, err);
  489.     if (bio == NULL) {
  490.         sk_X509_pop_free(chain, X509_free);
  491.         return NULL;
  492.     }

  493.     for ( ;; ) {

  494.         x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
  495.         if (x509 == NULL) {
  496.             n = ERR_peek_last_error();

  497.             if (ERR_GET_LIB(n) == ERR_LIB_PEM
  498.                 && ERR_GET_REASON(n) == PEM_R_NO_START_LINE
  499.                 && sk_X509_num(chain) > 0)
  500.             {
  501.                 /* end of file */
  502.                 ERR_clear_error();
  503.                 break;
  504.             }

  505.             /* some real error */

  506.             *err = "PEM_read_bio_X509_AUX() failed";
  507.             BIO_free(bio);
  508.             sk_X509_pop_free(chain, X509_free);
  509.             return NULL;
  510.         }

  511.         if (sk_X509_push(chain, x509) == 0) {
  512.             *err = "sk_X509_push() failed";
  513.             BIO_free(bio);
  514.             X509_free(x509);
  515.             sk_X509_pop_free(chain, X509_free);
  516.             return NULL;
  517.         }
  518.     }

  519.     BIO_free(bio);

  520.     return chain;
  521. }


  522. static BIO *
  523. ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err)
  524. {
  525.     BIO  *bio;

  526.     if (id->type == NGX_SSL_CACHE_DATA) {

  527.         bio = BIO_new_mem_buf(id->data + sizeof("data:") - 1,
  528.                               id->len - (sizeof("data:") - 1));
  529.         if (bio == NULL) {
  530.             *err = "BIO_new_mem_buf() failed";
  531.         }

  532.         return bio;
  533.     }

  534.     bio = BIO_new_file((char *) id->data, "r");
  535.     if (bio == NULL) {
  536.         *err = "BIO_new_file() failed";
  537.     }

  538.     return bio;
  539. }


  540. static void *
  541. ngx_openssl_cache_create_conf(ngx_cycle_t *cycle)
  542. {
  543.     ngx_ssl_cache_t     *cache;
  544.     ngx_pool_cleanup_t  *cln;

  545.     cache = ngx_pcalloc(cycle->pool, sizeof(ngx_ssl_cache_t));
  546.     if (cache == NULL) {
  547.         return NULL;
  548.     }

  549.     cln = ngx_pool_cleanup_add(cycle->pool, 0);
  550.     if (cln == NULL) {
  551.         return NULL;
  552.     }

  553.     cln->handler = ngx_ssl_cache_cleanup;
  554.     cln->data = cache;

  555.     ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
  556.                     ngx_ssl_cache_node_insert);

  557.     return cache;
  558. }


  559. static void
  560. ngx_ssl_cache_cleanup(void *data)
  561. {
  562.     ngx_ssl_cache_t  *cache = data;

  563.     ngx_rbtree_t          *tree;
  564.     ngx_rbtree_node_t     *node;
  565.     ngx_ssl_cache_node_t  *cn;

  566.     tree = &cache->rbtree;

  567.     if (tree->root == tree->sentinel) {
  568.         return;
  569.     }

  570.     for (node = ngx_rbtree_min(tree->root, tree->sentinel);
  571.          node;
  572.          node = ngx_rbtree_next(tree, node))
  573.     {
  574.         cn = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
  575.         cn->type->free(cn->value);
  576.     }
  577. }


  578. static void
  579. ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
  580.     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
  581. {
  582.     ngx_rbtree_node_t     **p;
  583.     ngx_ssl_cache_node_t   *n, *t;

  584.     for ( ;; ) {

  585.         n = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
  586.         t = ngx_rbtree_data(temp, ngx_ssl_cache_node_t, node);

  587.         if (node->key != temp->key) {

  588.             p = (node->key < temp->key) ? &temp->left : &temp->right;

  589.         } else if (n->type != t->type) {

  590.             p = (n->type < t->type) ? &temp->left : &temp->right;

  591.         } else {

  592.             p = (ngx_memn2cmp(n->id.data, t->id.data, n->id.len, t->id.len)
  593.                  < 0) ? &temp->left : &temp->right;
  594.         }

  595.         if (*p == sentinel) {
  596.             break;
  597.         }

  598.         temp = *p;
  599.     }

  600.     *p = node;
  601.     node->parent = temp;
  602.     node->left = sentinel;
  603.     node->right = sentinel;
  604.     ngx_rbt_red(node);
  605. }