1*774Svbart@nginx.com 2*774Svbart@nginx.com /* 3*774Svbart@nginx.com * Copyright (C) Valentin V. Bartenev 4*774Svbart@nginx.com * Copyright (C) NGINX, Inc. 5*774Svbart@nginx.com */ 6*774Svbart@nginx.com 7*774Svbart@nginx.com #include <nxt_main.h> 8*774Svbart@nginx.com #include <nxt_conf.h> 9*774Svbart@nginx.com #include <nxt_cert.h> 10*774Svbart@nginx.com 11*774Svbart@nginx.com #include <dirent.h> 12*774Svbart@nginx.com 13*774Svbart@nginx.com #include <openssl/bio.h> 14*774Svbart@nginx.com #include <openssl/pem.h> 15*774Svbart@nginx.com #include <openssl/evp.h> 16*774Svbart@nginx.com #include <openssl/x509.h> 17*774Svbart@nginx.com #include <openssl/x509v3.h> 18*774Svbart@nginx.com #include <openssl/rsa.h> 19*774Svbart@nginx.com #include <openssl/err.h> 20*774Svbart@nginx.com 21*774Svbart@nginx.com 22*774Svbart@nginx.com struct nxt_cert_s { 23*774Svbart@nginx.com EVP_PKEY *key; 24*774Svbart@nginx.com nxt_uint_t count; 25*774Svbart@nginx.com X509 *chain[]; 26*774Svbart@nginx.com }; 27*774Svbart@nginx.com 28*774Svbart@nginx.com 29*774Svbart@nginx.com typedef struct { 30*774Svbart@nginx.com nxt_str_t name; 31*774Svbart@nginx.com nxt_conf_value_t *value; 32*774Svbart@nginx.com nxt_mp_t *mp; 33*774Svbart@nginx.com } nxt_cert_info_t; 34*774Svbart@nginx.com 35*774Svbart@nginx.com 36*774Svbart@nginx.com typedef struct { 37*774Svbart@nginx.com nxt_str_t name; 38*774Svbart@nginx.com nxt_fd_t fd; 39*774Svbart@nginx.com } nxt_cert_item_t; 40*774Svbart@nginx.com 41*774Svbart@nginx.com 42*774Svbart@nginx.com static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd); 43*774Svbart@nginx.com static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio); 44*774Svbart@nginx.com static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix); 45*774Svbart@nginx.com 46*774Svbart@nginx.com static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert); 47*774Svbart@nginx.com static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, 48*774Svbart@nginx.com nxt_bool_t issuer); 49*774Svbart@nginx.com 50*774Svbart@nginx.com 51*774Svbart@nginx.com static nxt_lvlhsh_t nxt_cert_info; 52*774Svbart@nginx.com 53*774Svbart@nginx.com 54*774Svbart@nginx.com nxt_cert_t * 55*774Svbart@nginx.com nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf) 56*774Svbart@nginx.com { 57*774Svbart@nginx.com BIO *bio; 58*774Svbart@nginx.com nxt_cert_t *cert; 59*774Svbart@nginx.com 60*774Svbart@nginx.com bio = BIO_new_mem_buf(mbuf->pos, nxt_buf_mem_used_size(mbuf)); 61*774Svbart@nginx.com if (nxt_slow_path(bio == NULL)) { 62*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_mem_buf() failed"); 63*774Svbart@nginx.com return NULL; 64*774Svbart@nginx.com } 65*774Svbart@nginx.com 66*774Svbart@nginx.com cert = nxt_cert_bio(task, bio); 67*774Svbart@nginx.com 68*774Svbart@nginx.com BIO_free(bio); 69*774Svbart@nginx.com 70*774Svbart@nginx.com return cert; 71*774Svbart@nginx.com } 72*774Svbart@nginx.com 73*774Svbart@nginx.com 74*774Svbart@nginx.com static nxt_cert_t * 75*774Svbart@nginx.com nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd) 76*774Svbart@nginx.com { 77*774Svbart@nginx.com BIO *bio; 78*774Svbart@nginx.com nxt_cert_t *cert; 79*774Svbart@nginx.com 80*774Svbart@nginx.com bio = BIO_new_fd(fd, 0); 81*774Svbart@nginx.com if (nxt_slow_path(bio == NULL)) { 82*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_fd() failed"); 83*774Svbart@nginx.com return NULL; 84*774Svbart@nginx.com } 85*774Svbart@nginx.com 86*774Svbart@nginx.com cert = nxt_cert_bio(task, bio); 87*774Svbart@nginx.com 88*774Svbart@nginx.com BIO_free(bio); 89*774Svbart@nginx.com 90*774Svbart@nginx.com return cert; 91*774Svbart@nginx.com } 92*774Svbart@nginx.com 93*774Svbart@nginx.com 94*774Svbart@nginx.com static nxt_cert_t * 95*774Svbart@nginx.com nxt_cert_bio(nxt_task_t *task, BIO *bio) 96*774Svbart@nginx.com { 97*774Svbart@nginx.com int ret, suffix, key_id; 98*774Svbart@nginx.com long length, reason; 99*774Svbart@nginx.com char *type, *header; 100*774Svbart@nginx.com X509 *x509; 101*774Svbart@nginx.com EVP_PKEY *key; 102*774Svbart@nginx.com nxt_uint_t nalloc; 103*774Svbart@nginx.com nxt_cert_t *cert, *new_cert; 104*774Svbart@nginx.com u_char *data; 105*774Svbart@nginx.com const u_char *data_copy; 106*774Svbart@nginx.com PKCS8_PRIV_KEY_INFO *p8inf; 107*774Svbart@nginx.com const EVP_PKEY_ASN1_METHOD *ameth; 108*774Svbart@nginx.com 109*774Svbart@nginx.com nalloc = 4; 110*774Svbart@nginx.com 111*774Svbart@nginx.com cert = nxt_zalloc(sizeof(nxt_cert_t) + nalloc * sizeof(X509 *)); 112*774Svbart@nginx.com if (cert == NULL) { 113*774Svbart@nginx.com return NULL; 114*774Svbart@nginx.com } 115*774Svbart@nginx.com 116*774Svbart@nginx.com for ( ;; ) { 117*774Svbart@nginx.com ret = PEM_read_bio(bio, &type, &header, &data, &length); 118*774Svbart@nginx.com 119*774Svbart@nginx.com if (ret == 0) { 120*774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 121*774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 122*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 123*774Svbart@nginx.com "PEM_read_bio() failed"); 124*774Svbart@nginx.com goto fail; 125*774Svbart@nginx.com } 126*774Svbart@nginx.com 127*774Svbart@nginx.com ERR_clear_error(); 128*774Svbart@nginx.com break; 129*774Svbart@nginx.com } 130*774Svbart@nginx.com 131*774Svbart@nginx.com nxt_debug(task, "PEM type: \"%s\"", type); 132*774Svbart@nginx.com 133*774Svbart@nginx.com key = NULL; 134*774Svbart@nginx.com x509 = NULL; 135*774Svbart@nginx.com /* 136*774Svbart@nginx.com EVP_CIPHER_INFO cipher; 137*774Svbart@nginx.com 138*774Svbart@nginx.com if (PEM_get_EVP_CIPHER_INFO(header, &cipher) != 0) { 139*774Svbart@nginx.com nxt_alert(task, "encrypted PEM isn't supported"); 140*774Svbart@nginx.com goto done; 141*774Svbart@nginx.com } 142*774Svbart@nginx.com */ 143*774Svbart@nginx.com if (nxt_strcmp(type, PEM_STRING_PKCS8) == 0) { 144*774Svbart@nginx.com nxt_alert(task, "PEM PKCS8 isn't supported"); 145*774Svbart@nginx.com goto done; 146*774Svbart@nginx.com } 147*774Svbart@nginx.com 148*774Svbart@nginx.com if (nxt_strcmp(type, PEM_STRING_PKCS8INF) == 0) { 149*774Svbart@nginx.com data_copy = data; 150*774Svbart@nginx.com 151*774Svbart@nginx.com p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &data_copy, length); 152*774Svbart@nginx.com 153*774Svbart@nginx.com if (p8inf == NULL) { 154*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 155*774Svbart@nginx.com "d2i_PKCS8_PRIV_KEY_INFO() failed"); 156*774Svbart@nginx.com goto done; 157*774Svbart@nginx.com } 158*774Svbart@nginx.com 159*774Svbart@nginx.com key = EVP_PKCS82PKEY(p8inf); 160*774Svbart@nginx.com 161*774Svbart@nginx.com PKCS8_PRIV_KEY_INFO_free(p8inf); 162*774Svbart@nginx.com goto done; 163*774Svbart@nginx.com } 164*774Svbart@nginx.com 165*774Svbart@nginx.com suffix = nxt_nxt_cert_pem_suffix(type, PEM_STRING_PKCS8INF); 166*774Svbart@nginx.com 167*774Svbart@nginx.com if (suffix != 0) { 168*774Svbart@nginx.com 169*774Svbart@nginx.com ameth = EVP_PKEY_asn1_find_str(NULL, type, suffix); 170*774Svbart@nginx.com if (ameth == NULL) { 171*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 172*774Svbart@nginx.com "EVP_PKEY_asn1_find_str() failed"); 173*774Svbart@nginx.com goto done; 174*774Svbart@nginx.com } 175*774Svbart@nginx.com 176*774Svbart@nginx.com EVP_PKEY_asn1_get0_info(&key_id, NULL, NULL, NULL, NULL, ameth); 177*774Svbart@nginx.com 178*774Svbart@nginx.com data_copy = data; 179*774Svbart@nginx.com 180*774Svbart@nginx.com key = d2i_PrivateKey(key_id, NULL, &data_copy, length); 181*774Svbart@nginx.com goto done; 182*774Svbart@nginx.com } 183*774Svbart@nginx.com 184*774Svbart@nginx.com if (nxt_strcmp(type, PEM_STRING_X509) == 0 185*774Svbart@nginx.com || nxt_strcmp(type, PEM_STRING_X509_OLD) == 0) 186*774Svbart@nginx.com { 187*774Svbart@nginx.com data_copy = data; 188*774Svbart@nginx.com 189*774Svbart@nginx.com x509 = d2i_X509(NULL, &data_copy, length); 190*774Svbart@nginx.com if (x509 == NULL) { 191*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 192*774Svbart@nginx.com "d2i_X509() failed"); 193*774Svbart@nginx.com } 194*774Svbart@nginx.com 195*774Svbart@nginx.com goto done; 196*774Svbart@nginx.com } 197*774Svbart@nginx.com 198*774Svbart@nginx.com if (nxt_strcmp(type, PEM_STRING_X509_TRUSTED) == 0) { 199*774Svbart@nginx.com data_copy = data; 200*774Svbart@nginx.com 201*774Svbart@nginx.com x509 = d2i_X509_AUX(NULL, &data_copy, length); 202*774Svbart@nginx.com if (x509 == NULL) { 203*774Svbart@nginx.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 204*774Svbart@nginx.com "d2i_X509_AUX() failed"); 205*774Svbart@nginx.com } 206*774Svbart@nginx.com 207*774Svbart@nginx.com goto done; 208*774Svbart@nginx.com } 209*774Svbart@nginx.com 210*774Svbart@nginx.com nxt_alert(task, "unsupported PEM type: \"%s\"", type); 211*774Svbart@nginx.com 212*774Svbart@nginx.com done: 213*774Svbart@nginx.com 214*774Svbart@nginx.com OPENSSL_free(data); 215*774Svbart@nginx.com OPENSSL_free(header); 216*774Svbart@nginx.com OPENSSL_free(type); 217*774Svbart@nginx.com 218*774Svbart@nginx.com if (key != NULL) { 219*774Svbart@nginx.com if (cert->key != NULL) { 220*774Svbart@nginx.com EVP_PKEY_free(key); 221*774Svbart@nginx.com nxt_alert(task, "multiple private keys in PEM"); 222*774Svbart@nginx.com goto fail; 223*774Svbart@nginx.com } 224*774Svbart@nginx.com 225*774Svbart@nginx.com cert->key = key; 226*774Svbart@nginx.com continue; 227*774Svbart@nginx.com } 228*774Svbart@nginx.com 229*774Svbart@nginx.com if (x509 != NULL) { 230*774Svbart@nginx.com 231*774Svbart@nginx.com if (cert->count == nalloc) { 232*774Svbart@nginx.com nalloc += 4; 233*774Svbart@nginx.com 234*774Svbart@nginx.com new_cert = nxt_realloc(cert, sizeof(nxt_cert_t) 235*774Svbart@nginx.com + nalloc * sizeof(X509 *)); 236*774Svbart@nginx.com if (new_cert == NULL) { 237*774Svbart@nginx.com X509_free(x509); 238*774Svbart@nginx.com goto fail; 239*774Svbart@nginx.com } 240*774Svbart@nginx.com 241*774Svbart@nginx.com nxt_free(cert); 242*774Svbart@nginx.com cert = new_cert; 243*774Svbart@nginx.com } 244*774Svbart@nginx.com 245*774Svbart@nginx.com cert->chain[cert->count++] = x509; 246*774Svbart@nginx.com continue; 247*774Svbart@nginx.com } 248*774Svbart@nginx.com 249*774Svbart@nginx.com goto fail; 250*774Svbart@nginx.com } 251*774Svbart@nginx.com 252*774Svbart@nginx.com if (cert->key == NULL) { 253*774Svbart@nginx.com nxt_alert(task, "no key found"); 254*774Svbart@nginx.com goto fail; 255*774Svbart@nginx.com } 256*774Svbart@nginx.com 257*774Svbart@nginx.com if (cert->count == 0) { 258*774Svbart@nginx.com nxt_alert(task, "no certificates found"); 259*774Svbart@nginx.com goto fail; 260*774Svbart@nginx.com } 261*774Svbart@nginx.com 262*774Svbart@nginx.com return cert; 263*774Svbart@nginx.com 264*774Svbart@nginx.com fail: 265*774Svbart@nginx.com 266*774Svbart@nginx.com nxt_cert_destroy(cert); 267*774Svbart@nginx.com 268*774Svbart@nginx.com return NULL; 269*774Svbart@nginx.com } 270*774Svbart@nginx.com 271*774Svbart@nginx.com 272*774Svbart@nginx.com static int 273*774Svbart@nginx.com nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix) 274*774Svbart@nginx.com { 275*774Svbart@nginx.com char *p; 276*774Svbart@nginx.com nxt_uint_t pem_len, suffix_len; 277*774Svbart@nginx.com 278*774Svbart@nginx.com pem_len = strlen(pem_str); 279*774Svbart@nginx.com suffix_len = strlen(suffix); 280*774Svbart@nginx.com 281*774Svbart@nginx.com if (suffix_len + 1 >= pem_len) { 282*774Svbart@nginx.com return 0; 283*774Svbart@nginx.com } 284*774Svbart@nginx.com 285*774Svbart@nginx.com p = pem_str + pem_len - suffix_len; 286*774Svbart@nginx.com 287*774Svbart@nginx.com if (nxt_strcmp(p, suffix) != 0) { 288*774Svbart@nginx.com return 0; 289*774Svbart@nginx.com } 290*774Svbart@nginx.com 291*774Svbart@nginx.com p--; 292*774Svbart@nginx.com 293*774Svbart@nginx.com if (*p != ' ') { 294*774Svbart@nginx.com return 0; 295*774Svbart@nginx.com } 296*774Svbart@nginx.com 297*774Svbart@nginx.com return p - pem_str; 298*774Svbart@nginx.com } 299*774Svbart@nginx.com 300*774Svbart@nginx.com 301*774Svbart@nginx.com void 302*774Svbart@nginx.com nxt_cert_destroy(nxt_cert_t *cert) 303*774Svbart@nginx.com { 304*774Svbart@nginx.com nxt_uint_t i; 305*774Svbart@nginx.com 306*774Svbart@nginx.com EVP_PKEY_free(cert->key); 307*774Svbart@nginx.com 308*774Svbart@nginx.com for (i = 0; i != cert->count; i++) { 309*774Svbart@nginx.com X509_free(cert->chain[i]); 310*774Svbart@nginx.com } 311*774Svbart@nginx.com 312*774Svbart@nginx.com nxt_free(cert); 313*774Svbart@nginx.com } 314*774Svbart@nginx.com 315*774Svbart@nginx.com 316*774Svbart@nginx.com 317*774Svbart@nginx.com static nxt_int_t 318*774Svbart@nginx.com nxt_cert_info_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 319*774Svbart@nginx.com { 320*774Svbart@nginx.com nxt_cert_info_t *info; 321*774Svbart@nginx.com 322*774Svbart@nginx.com info = data; 323*774Svbart@nginx.com 324*774Svbart@nginx.com if (nxt_strcasestr_eq(&lhq->key, &info->name)) { 325*774Svbart@nginx.com return NXT_OK; 326*774Svbart@nginx.com } 327*774Svbart@nginx.com 328*774Svbart@nginx.com return NXT_DECLINED; 329*774Svbart@nginx.com } 330*774Svbart@nginx.com 331*774Svbart@nginx.com 332*774Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_cert_info_hash_proto 333*774Svbart@nginx.com nxt_aligned(64) = 334*774Svbart@nginx.com { 335*774Svbart@nginx.com NXT_LVLHSH_DEFAULT, 336*774Svbart@nginx.com nxt_cert_info_hash_test, 337*774Svbart@nginx.com nxt_lvlhsh_alloc, 338*774Svbart@nginx.com nxt_lvlhsh_free, 339*774Svbart@nginx.com }; 340*774Svbart@nginx.com 341*774Svbart@nginx.com 342*774Svbart@nginx.com void 343*774Svbart@nginx.com nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs) 344*774Svbart@nginx.com { 345*774Svbart@nginx.com uint32_t i; 346*774Svbart@nginx.com nxt_cert_t *cert; 347*774Svbart@nginx.com nxt_cert_item_t *items; 348*774Svbart@nginx.com 349*774Svbart@nginx.com for (items = certs->elts, i = 0; i < certs->nelts; i++) { 350*774Svbart@nginx.com cert = nxt_cert_fd(task, items[i].fd); 351*774Svbart@nginx.com 352*774Svbart@nginx.com if (nxt_slow_path(cert == NULL)) { 353*774Svbart@nginx.com continue; 354*774Svbart@nginx.com } 355*774Svbart@nginx.com 356*774Svbart@nginx.com (void) nxt_cert_info_save(&items[i].name, cert); 357*774Svbart@nginx.com 358*774Svbart@nginx.com nxt_cert_destroy(cert); 359*774Svbart@nginx.com } 360*774Svbart@nginx.com } 361*774Svbart@nginx.com 362*774Svbart@nginx.com 363*774Svbart@nginx.com nxt_int_t 364*774Svbart@nginx.com nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert) 365*774Svbart@nginx.com { 366*774Svbart@nginx.com nxt_mp_t *mp; 367*774Svbart@nginx.com nxt_int_t ret; 368*774Svbart@nginx.com nxt_cert_info_t *info; 369*774Svbart@nginx.com nxt_conf_value_t *value; 370*774Svbart@nginx.com nxt_lvlhsh_query_t lhq; 371*774Svbart@nginx.com 372*774Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 373*774Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 374*774Svbart@nginx.com return NXT_ERROR; 375*774Svbart@nginx.com } 376*774Svbart@nginx.com 377*774Svbart@nginx.com info = nxt_mp_get(mp, sizeof(nxt_cert_info_t)); 378*774Svbart@nginx.com if (nxt_slow_path(info == NULL)) { 379*774Svbart@nginx.com goto fail; 380*774Svbart@nginx.com } 381*774Svbart@nginx.com 382*774Svbart@nginx.com name = nxt_str_dup(mp, &info->name, name); 383*774Svbart@nginx.com if (nxt_slow_path(name == NULL)) { 384*774Svbart@nginx.com goto fail; 385*774Svbart@nginx.com } 386*774Svbart@nginx.com 387*774Svbart@nginx.com value = nxt_cert_details(mp, cert); 388*774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 389*774Svbart@nginx.com goto fail; 390*774Svbart@nginx.com } 391*774Svbart@nginx.com 392*774Svbart@nginx.com info->mp = mp; 393*774Svbart@nginx.com info->value = value; 394*774Svbart@nginx.com 395*774Svbart@nginx.com lhq.key_hash = nxt_djb_hash(name->start, name->length); 396*774Svbart@nginx.com lhq.replace = 1; 397*774Svbart@nginx.com lhq.key = *name; 398*774Svbart@nginx.com lhq.value = info; 399*774Svbart@nginx.com lhq.proto = &nxt_cert_info_hash_proto; 400*774Svbart@nginx.com 401*774Svbart@nginx.com ret = nxt_lvlhsh_insert(&nxt_cert_info, &lhq); 402*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 403*774Svbart@nginx.com goto fail; 404*774Svbart@nginx.com } 405*774Svbart@nginx.com 406*774Svbart@nginx.com if (lhq.value != info) { 407*774Svbart@nginx.com info = lhq.value; 408*774Svbart@nginx.com nxt_mp_destroy(info->mp); 409*774Svbart@nginx.com } 410*774Svbart@nginx.com 411*774Svbart@nginx.com return NXT_OK; 412*774Svbart@nginx.com 413*774Svbart@nginx.com fail: 414*774Svbart@nginx.com 415*774Svbart@nginx.com nxt_mp_destroy(mp); 416*774Svbart@nginx.com return NXT_ERROR; 417*774Svbart@nginx.com } 418*774Svbart@nginx.com 419*774Svbart@nginx.com 420*774Svbart@nginx.com nxt_conf_value_t * 421*774Svbart@nginx.com nxt_cert_info_get(nxt_str_t *name) 422*774Svbart@nginx.com { 423*774Svbart@nginx.com nxt_int_t ret; 424*774Svbart@nginx.com nxt_cert_info_t *info; 425*774Svbart@nginx.com nxt_lvlhsh_query_t lhq; 426*774Svbart@nginx.com 427*774Svbart@nginx.com lhq.key_hash = nxt_djb_hash(name->start, name->length); 428*774Svbart@nginx.com lhq.key = *name; 429*774Svbart@nginx.com lhq.proto = &nxt_cert_info_hash_proto; 430*774Svbart@nginx.com 431*774Svbart@nginx.com ret = nxt_lvlhsh_find(&nxt_cert_info, &lhq); 432*774Svbart@nginx.com if (ret != NXT_OK) { 433*774Svbart@nginx.com return NULL; 434*774Svbart@nginx.com } 435*774Svbart@nginx.com 436*774Svbart@nginx.com info = lhq.value; 437*774Svbart@nginx.com 438*774Svbart@nginx.com return info->value; 439*774Svbart@nginx.com } 440*774Svbart@nginx.com 441*774Svbart@nginx.com 442*774Svbart@nginx.com nxt_conf_value_t * 443*774Svbart@nginx.com nxt_cert_info_get_all(nxt_mp_t *mp) 444*774Svbart@nginx.com { 445*774Svbart@nginx.com uint32_t i; 446*774Svbart@nginx.com nxt_cert_info_t *info; 447*774Svbart@nginx.com nxt_conf_value_t *all; 448*774Svbart@nginx.com nxt_lvlhsh_each_t lhe; 449*774Svbart@nginx.com 450*774Svbart@nginx.com nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); 451*774Svbart@nginx.com 452*774Svbart@nginx.com i = 0; 453*774Svbart@nginx.com 454*774Svbart@nginx.com for ( ;; ) { 455*774Svbart@nginx.com info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); 456*774Svbart@nginx.com 457*774Svbart@nginx.com if (info == NULL) { 458*774Svbart@nginx.com break; 459*774Svbart@nginx.com } 460*774Svbart@nginx.com 461*774Svbart@nginx.com i++; 462*774Svbart@nginx.com } 463*774Svbart@nginx.com 464*774Svbart@nginx.com all = nxt_conf_create_object(mp, i); 465*774Svbart@nginx.com if (nxt_slow_path(all == NULL)) { 466*774Svbart@nginx.com return NULL; 467*774Svbart@nginx.com } 468*774Svbart@nginx.com 469*774Svbart@nginx.com nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); 470*774Svbart@nginx.com 471*774Svbart@nginx.com i = 0; 472*774Svbart@nginx.com 473*774Svbart@nginx.com for ( ;; ) { 474*774Svbart@nginx.com info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); 475*774Svbart@nginx.com 476*774Svbart@nginx.com if (info == NULL) { 477*774Svbart@nginx.com break; 478*774Svbart@nginx.com } 479*774Svbart@nginx.com 480*774Svbart@nginx.com nxt_conf_set_member(all, &info->name, info->value, i); 481*774Svbart@nginx.com 482*774Svbart@nginx.com i++; 483*774Svbart@nginx.com } 484*774Svbart@nginx.com 485*774Svbart@nginx.com return all; 486*774Svbart@nginx.com } 487*774Svbart@nginx.com 488*774Svbart@nginx.com 489*774Svbart@nginx.com static nxt_conf_value_t * 490*774Svbart@nginx.com nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert) 491*774Svbart@nginx.com { 492*774Svbart@nginx.com BIO *bio; 493*774Svbart@nginx.com X509 *x509; 494*774Svbart@nginx.com u_char *end; 495*774Svbart@nginx.com EVP_PKEY *key; 496*774Svbart@nginx.com ASN1_TIME *asn1_time; 497*774Svbart@nginx.com nxt_str_t str; 498*774Svbart@nginx.com nxt_int_t ret; 499*774Svbart@nginx.com nxt_uint_t i; 500*774Svbart@nginx.com nxt_conf_value_t *object, *chain, *element, *value; 501*774Svbart@nginx.com u_char buf[256]; 502*774Svbart@nginx.com 503*774Svbart@nginx.com static nxt_str_t key_str = nxt_string("key"); 504*774Svbart@nginx.com static nxt_str_t chain_str = nxt_string("chain"); 505*774Svbart@nginx.com static nxt_str_t since_str = nxt_string("since"); 506*774Svbart@nginx.com static nxt_str_t until_str = nxt_string("until"); 507*774Svbart@nginx.com static nxt_str_t issuer_str = nxt_string("issuer"); 508*774Svbart@nginx.com static nxt_str_t subject_str = nxt_string("subject"); 509*774Svbart@nginx.com static nxt_str_t validity_str = nxt_string("validity"); 510*774Svbart@nginx.com 511*774Svbart@nginx.com object = nxt_conf_create_object(mp, 2); 512*774Svbart@nginx.com if (nxt_slow_path(object == NULL)) { 513*774Svbart@nginx.com return NULL; 514*774Svbart@nginx.com } 515*774Svbart@nginx.com 516*774Svbart@nginx.com if (cert->key != NULL) { 517*774Svbart@nginx.com key = cert->key; 518*774Svbart@nginx.com 519*774Svbart@nginx.com switch (EVP_PKEY_base_id(key)) { 520*774Svbart@nginx.com case EVP_PKEY_RSA: 521*774Svbart@nginx.com end = nxt_sprintf(buf, buf + sizeof(buf), "RSA (%d bits)", 522*774Svbart@nginx.com EVP_PKEY_bits(key)); 523*774Svbart@nginx.com 524*774Svbart@nginx.com str.length = end - buf; 525*774Svbart@nginx.com str.start = buf; 526*774Svbart@nginx.com break; 527*774Svbart@nginx.com 528*774Svbart@nginx.com case EVP_PKEY_DH: 529*774Svbart@nginx.com end = nxt_sprintf(buf, buf + sizeof(buf), "DH (%d bits)", 530*774Svbart@nginx.com EVP_PKEY_bits(key)); 531*774Svbart@nginx.com 532*774Svbart@nginx.com str.length = end - buf; 533*774Svbart@nginx.com str.start = buf; 534*774Svbart@nginx.com break; 535*774Svbart@nginx.com 536*774Svbart@nginx.com case EVP_PKEY_EC: 537*774Svbart@nginx.com nxt_str_set(&str, "ECDH"); 538*774Svbart@nginx.com break; 539*774Svbart@nginx.com 540*774Svbart@nginx.com default: 541*774Svbart@nginx.com nxt_str_set(&str, "unknown"); 542*774Svbart@nginx.com } 543*774Svbart@nginx.com 544*774Svbart@nginx.com ret = nxt_conf_set_member_string_dup(object, mp, &key_str, &str, 0); 545*774Svbart@nginx.com 546*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 547*774Svbart@nginx.com return NULL; 548*774Svbart@nginx.com } 549*774Svbart@nginx.com 550*774Svbart@nginx.com } else { 551*774Svbart@nginx.com nxt_conf_set_member_null(object, &key_str, 0); 552*774Svbart@nginx.com } 553*774Svbart@nginx.com 554*774Svbart@nginx.com chain = nxt_conf_create_array(mp, cert->count); 555*774Svbart@nginx.com if (nxt_slow_path(chain == NULL)) { 556*774Svbart@nginx.com return NULL; 557*774Svbart@nginx.com } 558*774Svbart@nginx.com 559*774Svbart@nginx.com for (i = 0; i < cert->count; i++) { 560*774Svbart@nginx.com element = nxt_conf_create_object(mp, 3); 561*774Svbart@nginx.com if (nxt_slow_path(element == NULL)) { 562*774Svbart@nginx.com return NULL; 563*774Svbart@nginx.com } 564*774Svbart@nginx.com 565*774Svbart@nginx.com x509 = cert->chain[i]; 566*774Svbart@nginx.com 567*774Svbart@nginx.com value = nxt_cert_name_details(mp, x509, 0); 568*774Svbart@nginx.com if (value == NULL) { 569*774Svbart@nginx.com return NULL; 570*774Svbart@nginx.com } 571*774Svbart@nginx.com 572*774Svbart@nginx.com nxt_conf_set_member(element, &subject_str, value, 0); 573*774Svbart@nginx.com 574*774Svbart@nginx.com value = nxt_cert_name_details(mp, x509, 1); 575*774Svbart@nginx.com if (value == NULL) { 576*774Svbart@nginx.com return NULL; 577*774Svbart@nginx.com } 578*774Svbart@nginx.com 579*774Svbart@nginx.com nxt_conf_set_member(element, &issuer_str, value, 1); 580*774Svbart@nginx.com 581*774Svbart@nginx.com value = nxt_conf_create_object(mp, 2); 582*774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 583*774Svbart@nginx.com return NULL; 584*774Svbart@nginx.com } 585*774Svbart@nginx.com 586*774Svbart@nginx.com bio = BIO_new(BIO_s_mem()); 587*774Svbart@nginx.com if (nxt_slow_path(bio == NULL)) { 588*774Svbart@nginx.com return NULL; 589*774Svbart@nginx.com } 590*774Svbart@nginx.com 591*774Svbart@nginx.com asn1_time = X509_get_notBefore(x509); 592*774Svbart@nginx.com 593*774Svbart@nginx.com ret = ASN1_TIME_print(bio, asn1_time); 594*774Svbart@nginx.com 595*774Svbart@nginx.com if (nxt_fast_path(ret == 1)) { 596*774Svbart@nginx.com str.length = BIO_get_mem_data(bio, &str.start); 597*774Svbart@nginx.com ret = nxt_conf_set_member_string_dup(value, mp, &since_str, &str, 598*774Svbart@nginx.com 0); 599*774Svbart@nginx.com } else { 600*774Svbart@nginx.com ret = NXT_ERROR; 601*774Svbart@nginx.com } 602*774Svbart@nginx.com 603*774Svbart@nginx.com BIO_free(bio); 604*774Svbart@nginx.com 605*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 606*774Svbart@nginx.com return NULL; 607*774Svbart@nginx.com } 608*774Svbart@nginx.com 609*774Svbart@nginx.com bio = BIO_new(BIO_s_mem()); 610*774Svbart@nginx.com if (nxt_slow_path(bio == NULL)) { 611*774Svbart@nginx.com return NULL; 612*774Svbart@nginx.com } 613*774Svbart@nginx.com 614*774Svbart@nginx.com asn1_time = X509_get_notAfter(x509); 615*774Svbart@nginx.com 616*774Svbart@nginx.com ret = ASN1_TIME_print(bio, asn1_time); 617*774Svbart@nginx.com 618*774Svbart@nginx.com if (nxt_fast_path(ret == 1)) { 619*774Svbart@nginx.com str.length = BIO_get_mem_data(bio, &str.start); 620*774Svbart@nginx.com ret = nxt_conf_set_member_string_dup(value, mp, &until_str, &str, 621*774Svbart@nginx.com 1); 622*774Svbart@nginx.com } else { 623*774Svbart@nginx.com ret = NXT_ERROR; 624*774Svbart@nginx.com } 625*774Svbart@nginx.com 626*774Svbart@nginx.com BIO_free(bio); 627*774Svbart@nginx.com 628*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 629*774Svbart@nginx.com return NULL; 630*774Svbart@nginx.com } 631*774Svbart@nginx.com 632*774Svbart@nginx.com nxt_conf_set_member(element, &validity_str, value, 2); 633*774Svbart@nginx.com 634*774Svbart@nginx.com nxt_conf_set_element(chain, i, element); 635*774Svbart@nginx.com } 636*774Svbart@nginx.com 637*774Svbart@nginx.com nxt_conf_set_member(object, &chain_str, chain, 1); 638*774Svbart@nginx.com 639*774Svbart@nginx.com return object; 640*774Svbart@nginx.com } 641*774Svbart@nginx.com 642*774Svbart@nginx.com 643*774Svbart@nginx.com typedef struct { 644*774Svbart@nginx.com int nid; 645*774Svbart@nginx.com nxt_str_t name; 646*774Svbart@nginx.com } nxt_cert_nid_t; 647*774Svbart@nginx.com 648*774Svbart@nginx.com 649*774Svbart@nginx.com static nxt_conf_value_t * 650*774Svbart@nginx.com nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) 651*774Svbart@nginx.com { 652*774Svbart@nginx.com int len; 653*774Svbart@nginx.com X509_NAME *x509_name; 654*774Svbart@nginx.com nxt_str_t str; 655*774Svbart@nginx.com nxt_int_t ret; 656*774Svbart@nginx.com nxt_uint_t i, n, count; 657*774Svbart@nginx.com GENERAL_NAME *name; 658*774Svbart@nginx.com nxt_conf_value_t *object, *names; 659*774Svbart@nginx.com STACK_OF(GENERAL_NAME) *alt_names; 660*774Svbart@nginx.com u_char buf[256]; 661*774Svbart@nginx.com 662*774Svbart@nginx.com static nxt_cert_nid_t nids[] = { 663*774Svbart@nginx.com { NID_commonName, nxt_string("common_name") }, 664*774Svbart@nginx.com { NID_countryName, nxt_string("country") }, 665*774Svbart@nginx.com { NID_stateOrProvinceName, nxt_string("state_or_province") }, 666*774Svbart@nginx.com { NID_localityName, nxt_string("locality") }, 667*774Svbart@nginx.com { NID_organizationName, nxt_string("organization") }, 668*774Svbart@nginx.com { NID_organizationalUnitName, nxt_string("department") }, 669*774Svbart@nginx.com }; 670*774Svbart@nginx.com 671*774Svbart@nginx.com static nxt_str_t alt_names_str = nxt_string("alt_names"); 672*774Svbart@nginx.com 673*774Svbart@nginx.com count = 0; 674*774Svbart@nginx.com 675*774Svbart@nginx.com x509_name = issuer ? X509_get_issuer_name(x509) 676*774Svbart@nginx.com : X509_get_subject_name(x509); 677*774Svbart@nginx.com 678*774Svbart@nginx.com for (n = 0; n != nxt_nitems(nids); n++) { 679*774Svbart@nginx.com 680*774Svbart@nginx.com if (X509_NAME_get_index_by_NID(x509_name, nids[n].nid, -1) < 0) { 681*774Svbart@nginx.com continue; 682*774Svbart@nginx.com } 683*774Svbart@nginx.com 684*774Svbart@nginx.com count++; 685*774Svbart@nginx.com } 686*774Svbart@nginx.com 687*774Svbart@nginx.com alt_names = X509_get_ext_d2i(x509, issuer ? NID_issuer_alt_name 688*774Svbart@nginx.com : NID_subject_alt_name, 689*774Svbart@nginx.com NULL, NULL); 690*774Svbart@nginx.com 691*774Svbart@nginx.com if (alt_names != NULL) { 692*774Svbart@nginx.com count++; 693*774Svbart@nginx.com } 694*774Svbart@nginx.com 695*774Svbart@nginx.com object = nxt_conf_create_object(mp, count); 696*774Svbart@nginx.com if (nxt_slow_path(object == NULL)) { 697*774Svbart@nginx.com goto fail; 698*774Svbart@nginx.com } 699*774Svbart@nginx.com 700*774Svbart@nginx.com for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) { 701*774Svbart@nginx.com 702*774Svbart@nginx.com len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid, 703*774Svbart@nginx.com (char *) buf, sizeof(buf)); 704*774Svbart@nginx.com 705*774Svbart@nginx.com if (len < 0) { 706*774Svbart@nginx.com continue; 707*774Svbart@nginx.com } 708*774Svbart@nginx.com 709*774Svbart@nginx.com if (i == 1 && alt_names != NULL) { 710*774Svbart@nginx.com i++; 711*774Svbart@nginx.com } 712*774Svbart@nginx.com 713*774Svbart@nginx.com str.length = len; 714*774Svbart@nginx.com str.start = buf; 715*774Svbart@nginx.com 716*774Svbart@nginx.com ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name, 717*774Svbart@nginx.com &str, i++); 718*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 719*774Svbart@nginx.com goto fail; 720*774Svbart@nginx.com } 721*774Svbart@nginx.com } 722*774Svbart@nginx.com 723*774Svbart@nginx.com if (alt_names != NULL) { 724*774Svbart@nginx.com count = sk_GENERAL_NAME_num(alt_names); 725*774Svbart@nginx.com 726*774Svbart@nginx.com for (n = 0; n != count; n++) { 727*774Svbart@nginx.com name = sk_GENERAL_NAME_value(alt_names, n); 728*774Svbart@nginx.com 729*774Svbart@nginx.com if (name->type != GEN_DNS) { 730*774Svbart@nginx.com continue; 731*774Svbart@nginx.com } 732*774Svbart@nginx.com } 733*774Svbart@nginx.com 734*774Svbart@nginx.com names = nxt_conf_create_array(mp, n); 735*774Svbart@nginx.com if (nxt_slow_path(names == NULL)) { 736*774Svbart@nginx.com goto fail; 737*774Svbart@nginx.com } 738*774Svbart@nginx.com 739*774Svbart@nginx.com for (n = 0, i = 0; n != count; n++) { 740*774Svbart@nginx.com name = sk_GENERAL_NAME_value(alt_names, n); 741*774Svbart@nginx.com 742*774Svbart@nginx.com if (name->type != GEN_DNS) { 743*774Svbart@nginx.com continue; 744*774Svbart@nginx.com } 745*774Svbart@nginx.com 746*774Svbart@nginx.com str.length = ASN1_STRING_length(name->d.dNSName); 747*774Svbart@nginx.com #if OPENSSL_VERSION_NUMBER > 0x10100000L 748*774Svbart@nginx.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 749*774Svbart@nginx.com #else 750*774Svbart@nginx.com str.start = ASN1_STRING_data(name->d.dNSName); 751*774Svbart@nginx.com #endif 752*774Svbart@nginx.com 753*774Svbart@nginx.com ret = nxt_conf_set_element_string_dup(names, mp, i++, &str); 754*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 755*774Svbart@nginx.com goto fail; 756*774Svbart@nginx.com } 757*774Svbart@nginx.com } 758*774Svbart@nginx.com 759*774Svbart@nginx.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 760*774Svbart@nginx.com 761*774Svbart@nginx.com nxt_conf_set_member(object, &alt_names_str, names, 1); 762*774Svbart@nginx.com } 763*774Svbart@nginx.com 764*774Svbart@nginx.com return object; 765*774Svbart@nginx.com 766*774Svbart@nginx.com fail: 767*774Svbart@nginx.com 768*774Svbart@nginx.com if (alt_names != NULL) { 769*774Svbart@nginx.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 770*774Svbart@nginx.com } 771*774Svbart@nginx.com 772*774Svbart@nginx.com return NULL; 773*774Svbart@nginx.com } 774*774Svbart@nginx.com 775*774Svbart@nginx.com 776*774Svbart@nginx.com nxt_int_t 777*774Svbart@nginx.com nxt_cert_info_delete(nxt_str_t *name) 778*774Svbart@nginx.com { 779*774Svbart@nginx.com nxt_int_t ret; 780*774Svbart@nginx.com nxt_cert_info_t *info; 781*774Svbart@nginx.com nxt_lvlhsh_query_t lhq; 782*774Svbart@nginx.com 783*774Svbart@nginx.com lhq.key_hash = nxt_djb_hash(name->start, name->length); 784*774Svbart@nginx.com lhq.key = *name; 785*774Svbart@nginx.com lhq.proto = &nxt_cert_info_hash_proto; 786*774Svbart@nginx.com 787*774Svbart@nginx.com ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq); 788*774Svbart@nginx.com 789*774Svbart@nginx.com if (ret == NXT_OK) { 790*774Svbart@nginx.com info = lhq.value; 791*774Svbart@nginx.com nxt_mp_destroy(info->mp); 792*774Svbart@nginx.com } 793*774Svbart@nginx.com 794*774Svbart@nginx.com return ret; 795*774Svbart@nginx.com } 796*774Svbart@nginx.com 797*774Svbart@nginx.com 798*774Svbart@nginx.com 799*774Svbart@nginx.com nxt_array_t * 800*774Svbart@nginx.com nxt_cert_store_load(nxt_task_t *task) 801*774Svbart@nginx.com { 802*774Svbart@nginx.com DIR *dir; 803*774Svbart@nginx.com size_t size, alloc; 804*774Svbart@nginx.com u_char *buf, *p; 805*774Svbart@nginx.com nxt_mp_t *mp; 806*774Svbart@nginx.com nxt_str_t name; 807*774Svbart@nginx.com nxt_int_t ret; 808*774Svbart@nginx.com nxt_file_t file; 809*774Svbart@nginx.com nxt_array_t *certs; 810*774Svbart@nginx.com nxt_runtime_t *rt; 811*774Svbart@nginx.com struct dirent *de; 812*774Svbart@nginx.com nxt_cert_item_t *item; 813*774Svbart@nginx.com 814*774Svbart@nginx.com rt = task->thread->runtime; 815*774Svbart@nginx.com 816*774Svbart@nginx.com if (nxt_slow_path(rt->certs.start == NULL)) { 817*774Svbart@nginx.com nxt_alert(task, "no certificates storage directory"); 818*774Svbart@nginx.com return NULL; 819*774Svbart@nginx.com } 820*774Svbart@nginx.com 821*774Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 822*774Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 823*774Svbart@nginx.com return NULL; 824*774Svbart@nginx.com } 825*774Svbart@nginx.com 826*774Svbart@nginx.com certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t)); 827*774Svbart@nginx.com if (nxt_slow_path(certs == NULL)) { 828*774Svbart@nginx.com nxt_mp_destroy(mp); 829*774Svbart@nginx.com return NULL; 830*774Svbart@nginx.com } 831*774Svbart@nginx.com 832*774Svbart@nginx.com buf = NULL; 833*774Svbart@nginx.com alloc = 0; 834*774Svbart@nginx.com 835*774Svbart@nginx.com dir = opendir((char *) rt->certs.start); 836*774Svbart@nginx.com if (nxt_slow_path(dir == NULL)) { 837*774Svbart@nginx.com nxt_alert(task, "opendir(\"%s\") failed %E", 838*774Svbart@nginx.com rt->certs.start, nxt_errno); 839*774Svbart@nginx.com goto fail; 840*774Svbart@nginx.com } 841*774Svbart@nginx.com 842*774Svbart@nginx.com for ( ;; ) { 843*774Svbart@nginx.com de = readdir(dir); 844*774Svbart@nginx.com if (de == NULL) { 845*774Svbart@nginx.com break; 846*774Svbart@nginx.com } 847*774Svbart@nginx.com 848*774Svbart@nginx.com if (de->d_type != DT_REG) { 849*774Svbart@nginx.com continue; 850*774Svbart@nginx.com } 851*774Svbart@nginx.com 852*774Svbart@nginx.com item = nxt_array_add(certs); 853*774Svbart@nginx.com if (nxt_slow_path(item == NULL)) { 854*774Svbart@nginx.com goto fail; 855*774Svbart@nginx.com } 856*774Svbart@nginx.com 857*774Svbart@nginx.com item->fd = -1; 858*774Svbart@nginx.com 859*774Svbart@nginx.com name.length = nxt_strlen(de->d_name); 860*774Svbart@nginx.com name.start = (u_char *) de->d_name; 861*774Svbart@nginx.com 862*774Svbart@nginx.com size = rt->certs.length + name.length + 1; 863*774Svbart@nginx.com 864*774Svbart@nginx.com if (size > alloc) { 865*774Svbart@nginx.com size += 32; 866*774Svbart@nginx.com 867*774Svbart@nginx.com p = nxt_realloc(buf, size); 868*774Svbart@nginx.com if (p == NULL) { 869*774Svbart@nginx.com goto fail; 870*774Svbart@nginx.com } 871*774Svbart@nginx.com 872*774Svbart@nginx.com alloc = size; 873*774Svbart@nginx.com buf = p; 874*774Svbart@nginx.com } 875*774Svbart@nginx.com 876*774Svbart@nginx.com p = nxt_cpymem(buf, rt->certs.start, rt->certs.length); 877*774Svbart@nginx.com p = nxt_cpymem(p, name.start, name.length + 1); 878*774Svbart@nginx.com 879*774Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 880*774Svbart@nginx.com 881*774Svbart@nginx.com file.name = buf; 882*774Svbart@nginx.com 883*774Svbart@nginx.com ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 884*774Svbart@nginx.com NXT_FILE_OWNER_ACCESS); 885*774Svbart@nginx.com 886*774Svbart@nginx.com 887*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 888*774Svbart@nginx.com nxt_array_remove_last(certs); 889*774Svbart@nginx.com continue; 890*774Svbart@nginx.com } 891*774Svbart@nginx.com 892*774Svbart@nginx.com item->fd = file.fd; 893*774Svbart@nginx.com 894*774Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) { 895*774Svbart@nginx.com goto fail; 896*774Svbart@nginx.com } 897*774Svbart@nginx.com } 898*774Svbart@nginx.com 899*774Svbart@nginx.com if (buf != NULL) { 900*774Svbart@nginx.com nxt_free(buf); 901*774Svbart@nginx.com } 902*774Svbart@nginx.com 903*774Svbart@nginx.com (void) closedir(dir); 904*774Svbart@nginx.com 905*774Svbart@nginx.com return certs; 906*774Svbart@nginx.com 907*774Svbart@nginx.com fail: 908*774Svbart@nginx.com 909*774Svbart@nginx.com if (buf != NULL) { 910*774Svbart@nginx.com nxt_free(buf); 911*774Svbart@nginx.com } 912*774Svbart@nginx.com 913*774Svbart@nginx.com if (dir != NULL) { 914*774Svbart@nginx.com (void) closedir(dir); 915*774Svbart@nginx.com } 916*774Svbart@nginx.com 917*774Svbart@nginx.com nxt_cert_store_release(certs); 918*774Svbart@nginx.com 919*774Svbart@nginx.com return NULL; 920*774Svbart@nginx.com } 921*774Svbart@nginx.com 922*774Svbart@nginx.com 923*774Svbart@nginx.com void 924*774Svbart@nginx.com nxt_cert_store_release(nxt_array_t *certs) 925*774Svbart@nginx.com { 926*774Svbart@nginx.com uint32_t i; 927*774Svbart@nginx.com nxt_cert_item_t *items; 928*774Svbart@nginx.com 929*774Svbart@nginx.com for (items = certs->elts, i = 0; 930*774Svbart@nginx.com i < certs->nelts; 931*774Svbart@nginx.com i++) 932*774Svbart@nginx.com { 933*774Svbart@nginx.com nxt_fd_close(items[i].fd); 934*774Svbart@nginx.com } 935*774Svbart@nginx.com 936*774Svbart@nginx.com nxt_mp_destroy(certs->mem_pool); 937*774Svbart@nginx.com } 938*774Svbart@nginx.com 939*774Svbart@nginx.com 940*774Svbart@nginx.com #if 0 941*774Svbart@nginx.com 942*774Svbart@nginx.com void 943*774Svbart@nginx.com nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 944*774Svbart@nginx.com { 945*774Svbart@nginx.com DIR *dir; 946*774Svbart@nginx.com size_t size; 947*774Svbart@nginx.com nxt_buf_t *b; 948*774Svbart@nginx.com nxt_int_t ret; 949*774Svbart@nginx.com nxt_port_t *port; 950*774Svbart@nginx.com nxt_runtime_t *rt; 951*774Svbart@nginx.com struct dirent *de; 952*774Svbart@nginx.com 953*774Svbart@nginx.com port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 954*774Svbart@nginx.com msg->port_msg.reply_port); 955*774Svbart@nginx.com 956*774Svbart@nginx.com if (nxt_slow_path(port == NULL)) { 957*774Svbart@nginx.com return; 958*774Svbart@nginx.com } 959*774Svbart@nginx.com 960*774Svbart@nginx.com b = NULL; 961*774Svbart@nginx.com dir = NULL; 962*774Svbart@nginx.com 963*774Svbart@nginx.com rt = task->thread->runtime; 964*774Svbart@nginx.com 965*774Svbart@nginx.com if (nxt_slow_path(rt->certs.start == NULL)) { 966*774Svbart@nginx.com nxt_alert(task, "no certificates storage directory"); 967*774Svbart@nginx.com goto fail; 968*774Svbart@nginx.com } 969*774Svbart@nginx.com 970*774Svbart@nginx.com dir = opendir((char *) rt->certs.start); 971*774Svbart@nginx.com if (nxt_slow_path(dir == NULL)) { 972*774Svbart@nginx.com nxt_alert(task, "opendir(\"%s\") failed %E", 973*774Svbart@nginx.com rt->certs.start, nxt_errno); 974*774Svbart@nginx.com goto fail; 975*774Svbart@nginx.com } 976*774Svbart@nginx.com 977*774Svbart@nginx.com size = 0; 978*774Svbart@nginx.com 979*774Svbart@nginx.com for ( ;; ) { 980*774Svbart@nginx.com de = readdir(dir); 981*774Svbart@nginx.com if (de == NULL) { 982*774Svbart@nginx.com break; 983*774Svbart@nginx.com } 984*774Svbart@nginx.com 985*774Svbart@nginx.com if (de->d_type != DT_REG) { 986*774Svbart@nginx.com continue; 987*774Svbart@nginx.com } 988*774Svbart@nginx.com 989*774Svbart@nginx.com size += nxt_strlen(de->d_name) + 1; 990*774Svbart@nginx.com } 991*774Svbart@nginx.com 992*774Svbart@nginx.com b = nxt_port_mmap_get_buf(task, port, size); 993*774Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 994*774Svbart@nginx.com goto fail; 995*774Svbart@nginx.com } 996*774Svbart@nginx.com 997*774Svbart@nginx.com rewinddir(dir); 998*774Svbart@nginx.com 999*774Svbart@nginx.com for ( ;; ) { 1000*774Svbart@nginx.com de = readdir(dir); 1001*774Svbart@nginx.com if (de == NULL) { 1002*774Svbart@nginx.com break; 1003*774Svbart@nginx.com } 1004*774Svbart@nginx.com 1005*774Svbart@nginx.com if (de->d_type != DT_REG) { 1006*774Svbart@nginx.com continue; 1007*774Svbart@nginx.com } 1008*774Svbart@nginx.com 1009*774Svbart@nginx.com size = nxt_strlen(de->d_name) + 1; 1010*774Svbart@nginx.com 1011*774Svbart@nginx.com if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) { 1012*774Svbart@nginx.com b->mem.free = b->mem.start; 1013*774Svbart@nginx.com break; 1014*774Svbart@nginx.com } 1015*774Svbart@nginx.com 1016*774Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size); 1017*774Svbart@nginx.com } 1018*774Svbart@nginx.com 1019*774Svbart@nginx.com (void) closedir(dir); 1020*774Svbart@nginx.com dir = NULL; 1021*774Svbart@nginx.com 1022*774Svbart@nginx.com if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) { 1023*774Svbart@nginx.com nxt_alert(task, "certificates storage directory " 1024*774Svbart@nginx.com "has changed while reading it"); 1025*774Svbart@nginx.com goto fail; 1026*774Svbart@nginx.com } 1027*774Svbart@nginx.com 1028*774Svbart@nginx.com ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1, 1029*774Svbart@nginx.com msg->port_msg.stream, 0, b); 1030*774Svbart@nginx.com 1031*774Svbart@nginx.com if (nxt_fast_path(ret == NXT_OK)) { 1032*774Svbart@nginx.com return; 1033*774Svbart@nginx.com } 1034*774Svbart@nginx.com 1035*774Svbart@nginx.com fail: 1036*774Svbart@nginx.com 1037*774Svbart@nginx.com if (dir != NULL) { 1038*774Svbart@nginx.com (void) closedir(dir); 1039*774Svbart@nginx.com } 1040*774Svbart@nginx.com 1041*774Svbart@nginx.com if (b != NULL) { 1042*774Svbart@nginx.com b->completion_handler(task, b, b->parent); 1043*774Svbart@nginx.com } 1044*774Svbart@nginx.com 1045*774Svbart@nginx.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, 1046*774Svbart@nginx.com msg->port_msg.stream, 0, NULL); 1047*774Svbart@nginx.com } 1048*774Svbart@nginx.com 1049*774Svbart@nginx.com #endif 1050*774Svbart@nginx.com 1051*774Svbart@nginx.com 1052*774Svbart@nginx.com void 1053*774Svbart@nginx.com nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, 1054*774Svbart@nginx.com nxt_port_rpc_handler_t handler, void *ctx) 1055*774Svbart@nginx.com { 1056*774Svbart@nginx.com uint32_t stream; 1057*774Svbart@nginx.com nxt_int_t ret; 1058*774Svbart@nginx.com nxt_buf_t *b; 1059*774Svbart@nginx.com nxt_port_t *main_port, *recv_port; 1060*774Svbart@nginx.com nxt_runtime_t *rt; 1061*774Svbart@nginx.com 1062*774Svbart@nginx.com b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1063*774Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 1064*774Svbart@nginx.com goto fail; 1065*774Svbart@nginx.com } 1066*774Svbart@nginx.com 1067*774Svbart@nginx.com nxt_buf_cpystr(b, name); 1068*774Svbart@nginx.com *b->mem.free++ = '\0'; 1069*774Svbart@nginx.com 1070*774Svbart@nginx.com rt = task->thread->runtime; 1071*774Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1072*774Svbart@nginx.com recv_port = rt->port_by_type[rt->type]; 1073*774Svbart@nginx.com 1074*774Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler, 1075*774Svbart@nginx.com -1, ctx); 1076*774Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 1077*774Svbart@nginx.com goto fail; 1078*774Svbart@nginx.com } 1079*774Svbart@nginx.com 1080*774Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1, 1081*774Svbart@nginx.com stream, recv_port->id, b); 1082*774Svbart@nginx.com 1083*774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1084*774Svbart@nginx.com nxt_port_rpc_cancel(task, recv_port, stream); 1085*774Svbart@nginx.com goto fail; 1086*774Svbart@nginx.com } 1087*774Svbart@nginx.com 1088*774Svbart@nginx.com return; 1089*774Svbart@nginx.com 1090*774Svbart@nginx.com fail: 1091*774Svbart@nginx.com 1092*774Svbart@nginx.com handler(task, NULL, ctx); 1093*774Svbart@nginx.com } 1094*774Svbart@nginx.com 1095*774Svbart@nginx.com 1096*774Svbart@nginx.com void 1097*774Svbart@nginx.com nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1098*774Svbart@nginx.com { 1099*774Svbart@nginx.com u_char *p; 1100*774Svbart@nginx.com nxt_int_t ret; 1101*774Svbart@nginx.com nxt_str_t name; 1102*774Svbart@nginx.com nxt_file_t file; 1103*774Svbart@nginx.com nxt_port_t *port; 1104*774Svbart@nginx.com nxt_runtime_t *rt; 1105*774Svbart@nginx.com nxt_port_msg_type_t type; 1106*774Svbart@nginx.com 1107*774Svbart@nginx.com port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 1108*774Svbart@nginx.com msg->port_msg.reply_port); 1109*774Svbart@nginx.com 1110*774Svbart@nginx.com if (port == NULL) { 1111*774Svbart@nginx.com return; 1112*774Svbart@nginx.com } 1113*774Svbart@nginx.com 1114*774Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 1115*774Svbart@nginx.com 1116*774Svbart@nginx.com file.fd = -1; 1117*774Svbart@nginx.com type = NXT_PORT_MSG_RPC_ERROR; 1118*774Svbart@nginx.com 1119*774Svbart@nginx.com rt = task->thread->runtime; 1120*774Svbart@nginx.com 1121*774Svbart@nginx.com if (nxt_slow_path(rt->certs.start == NULL)) { 1122*774Svbart@nginx.com nxt_alert(task, "no certificates storage directory"); 1123*774Svbart@nginx.com goto error; 1124*774Svbart@nginx.com } 1125*774Svbart@nginx.com 1126*774Svbart@nginx.com name.start = msg->buf->mem.pos; 1127*774Svbart@nginx.com name.length = nxt_strlen(name.start); 1128*774Svbart@nginx.com 1129*774Svbart@nginx.com file.name = nxt_malloc(rt->certs.length + name.length + 1); 1130*774Svbart@nginx.com 1131*774Svbart@nginx.com if (nxt_slow_path(file.name == NULL)) { 1132*774Svbart@nginx.com goto error; 1133*774Svbart@nginx.com } 1134*774Svbart@nginx.com 1135*774Svbart@nginx.com p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length); 1136*774Svbart@nginx.com p = nxt_cpymem(p, name.start, name.length + 1); 1137*774Svbart@nginx.com 1138*774Svbart@nginx.com ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN, 1139*774Svbart@nginx.com NXT_FILE_OWNER_ACCESS); 1140*774Svbart@nginx.com 1141*774Svbart@nginx.com nxt_free(file.name); 1142*774Svbart@nginx.com 1143*774Svbart@nginx.com if (nxt_fast_path(ret == NXT_OK)) { 1144*774Svbart@nginx.com type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 1145*774Svbart@nginx.com } 1146*774Svbart@nginx.com 1147*774Svbart@nginx.com error: 1148*774Svbart@nginx.com 1149*774Svbart@nginx.com (void) nxt_port_socket_write(task, port, type, file.fd, 1150*774Svbart@nginx.com msg->port_msg.stream, 0, NULL); 1151*774Svbart@nginx.com } 1152*774Svbart@nginx.com 1153*774Svbart@nginx.com 1154*774Svbart@nginx.com void 1155*774Svbart@nginx.com nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp) 1156*774Svbart@nginx.com { 1157*774Svbart@nginx.com nxt_buf_t *b; 1158*774Svbart@nginx.com nxt_port_t *main_port; 1159*774Svbart@nginx.com nxt_runtime_t *rt; 1160*774Svbart@nginx.com 1161*774Svbart@nginx.com b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1162*774Svbart@nginx.com 1163*774Svbart@nginx.com if (nxt_fast_path(b != NULL)) { 1164*774Svbart@nginx.com nxt_buf_cpystr(b, name); 1165*774Svbart@nginx.com *b->mem.free++ = '\0'; 1166*774Svbart@nginx.com 1167*774Svbart@nginx.com rt = task->thread->runtime; 1168*774Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1169*774Svbart@nginx.com 1170*774Svbart@nginx.com (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE, 1171*774Svbart@nginx.com -1, 0, 0, b); 1172*774Svbart@nginx.com } 1173*774Svbart@nginx.com } 1174*774Svbart@nginx.com 1175*774Svbart@nginx.com 1176*774Svbart@nginx.com void 1177*774Svbart@nginx.com nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1178*774Svbart@nginx.com { 1179*774Svbart@nginx.com u_char *p; 1180*774Svbart@nginx.com nxt_str_t name; 1181*774Svbart@nginx.com nxt_runtime_t *rt; 1182*774Svbart@nginx.com nxt_file_name_t *path; 1183*774Svbart@nginx.com 1184*774Svbart@nginx.com rt = task->thread->runtime; 1185*774Svbart@nginx.com 1186*774Svbart@nginx.com if (nxt_slow_path(rt->certs.start == NULL)) { 1187*774Svbart@nginx.com nxt_alert(task, "no certificates storage directory"); 1188*774Svbart@nginx.com return; 1189*774Svbart@nginx.com } 1190*774Svbart@nginx.com 1191*774Svbart@nginx.com name.start = msg->buf->mem.pos; 1192*774Svbart@nginx.com name.length = nxt_strlen(name.start); 1193*774Svbart@nginx.com 1194*774Svbart@nginx.com path = nxt_malloc(rt->certs.length + name.length + 1); 1195*774Svbart@nginx.com 1196*774Svbart@nginx.com if (nxt_fast_path(path != NULL)) { 1197*774Svbart@nginx.com p = nxt_cpymem(path, rt->certs.start, rt->certs.length); 1198*774Svbart@nginx.com p = nxt_cpymem(p, name.start, name.length + 1); 1199*774Svbart@nginx.com 1200*774Svbart@nginx.com (void) nxt_file_delete(path); 1201*774Svbart@nginx.com 1202*774Svbart@nginx.com nxt_free(path); 1203*774Svbart@nginx.com } 1204*774Svbart@nginx.com } 1205