📄 openssl.c
字号:
}/* }}} *//* {{{ load_all_certs_from_file */static STACK_OF(X509) * load_all_certs_from_file(char *certfile){ STACK_OF(X509_INFO) *sk=NULL; STACK_OF(X509) *stack=NULL, *ret=NULL; BIO *in=NULL; X509_INFO *xi; TSRMLS_FETCH(); if(!(stack = sk_X509_new_null())) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure"); goto end; } if (php_openssl_safe_mode_chk(certfile TSRMLS_CC)) { goto end; } if(!(in=BIO_new_file(certfile, "r"))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile); goto end; } /* This loads from a file, a stack of x509/crl/pkey sets */ if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile); goto end; } /* scan over it and pull out the certs */ while (sk_X509_INFO_num(sk)) { xi=sk_X509_INFO_shift(sk); if (xi->x509 != NULL) { sk_X509_push(stack,xi->x509); xi->x509=NULL; } X509_INFO_free(xi); } if(!sk_X509_num(stack)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile); sk_X509_free(stack); goto end; } ret=stack;end: BIO_free(in); sk_X509_INFO_free(sk); return ret;}/* }}} *//* {{{ check_cert */static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose){ int ret=0; X509_STORE_CTX *csc; TSRMLS_FETCH(); csc = X509_STORE_CTX_new(); if (csc == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure"); return 0; } X509_STORE_CTX_init(csc, ctx, x, untrustedchain); if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose); ret = X509_verify_cert(csc); X509_STORE_CTX_free(csc); return ret;}/* }}} *//* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile]) Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */PHP_FUNCTION(openssl_x509_checkpurpose){ zval * zcert, * zcainfo = NULL; X509_STORE * cainfo = NULL; X509 * cert = NULL; long certresource = -1; STACK_OF(X509) * untrustedchain = NULL; long purpose; char * untrusted = NULL; int untrusted_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) return; RETVAL_LONG(-1); if (untrusted) { untrustedchain = load_all_certs_from_file(untrusted); if (untrustedchain == NULL) goto clean_exit; } cainfo = setup_verify(zcainfo TSRMLS_CC); if (cainfo == NULL) goto clean_exit; cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC); if (cert == NULL) goto clean_exit; RETVAL_LONG(check_cert(cainfo, cert, untrustedchain, purpose));clean_exit: if (certresource == 1 && cert) X509_free(cert); if (cainfo) X509_STORE_free(cainfo); if (untrustedchain) sk_X509_pop_free(untrustedchain, X509_free);}/* }}} *//* {{{ setup_verify * calist is an array containing file and directory names. create a * certificate store and add those certs to it for use in verification.*/static X509_STORE * setup_verify(zval * calist TSRMLS_DC){ X509_STORE *store; X509_LOOKUP * dir_lookup, * file_lookup; HashPosition pos; int ndirs = 0, nfiles = 0; store = X509_STORE_new(); if (store == NULL) return NULL; if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) { zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos); for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) { zval ** item; struct stat sb; if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) break; convert_to_string_ex(item); if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item)); continue; } if ((sb.st_mode & S_IFREG) == S_IFREG) { file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item)); else nfiles++; file_lookup = NULL; } else { dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item)); else ndirs++; dir_lookup = NULL; } } } if (nfiles == 0) { file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (file_lookup) X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT); } if (ndirs == 0) { dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if (dir_lookup) X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT); } return store;}/* }}} *//* {{{ proto resource openssl_x509_read(mixed cert) Reads X.509 certificates */PHP_FUNCTION(openssl_x509_read){ zval *cert; X509 *x509; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &cert) == FAILURE) return; Z_TYPE_P(return_value) = IS_RESOURCE; x509 = php_openssl_x509_from_zval(&cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC); if (x509 == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!"); RETURN_FALSE; }}/* }}} *//* {{{ proto void openssl_x509_free(resource x509) Frees X.509 certificates */PHP_FUNCTION(openssl_x509_free){ zval *x509; X509 *cert; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) return; ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509); zend_list_delete(Z_LVAL_P(x509));}/* }}} *//* }}} *//* {{{ x509 CSR functions *//* {{{ php_openssl_make_REQ */static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs TSRMLS_DC){ STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL; char * str, *dn_sect, *attr_sect; dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name"); if (dn_sect == NULL) return FAILURE; dn_sk = CONF_get_section(req->req_config, dn_sect); if (dn_sk == NULL) return FAILURE; attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes"); if (attr_sect == NULL) attr_sk = NULL; else { attr_sk = CONF_get_section(req->req_config, attr_sect); if (attr_sk == NULL) return FAILURE; } /* setup the version number: version 1 */ if (X509_REQ_set_version(csr, 0L)) { int i, nid; char * type; CONF_VALUE * v; X509_NAME * subj; HashPosition hpos; zval ** item; subj = X509_REQ_get_subject_name(csr); /* apply values from the dn hash */ zend_hash_internal_pointer_reset_ex(HASH_OF(dn), &hpos); while(zend_hash_get_current_data_ex(HASH_OF(dn), (void**)&item, &hpos) == SUCCESS) { char * strindex; int strindexlen; long intindex; zend_hash_get_current_key_ex(HASH_OF(dn), &strindex, &strindexlen, &intindex, 0, &hpos); convert_to_string_ex(item); if (strindex) { int nid; nid = OBJ_txt2nid(strindex); if (nid != NID_undef) { if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item)); return FAILURE; } } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex); } } zend_hash_move_forward_ex(HASH_OF(dn), &hpos); } /* Finally apply defaults from config file */ for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { int len; char buffer[200]; v = sk_CONF_VALUE_value(dn_sk, i); type = v->name; len = strlen(type); if (len < sizeof("_default")) continue; len -= sizeof("_default") - 1; if (strcmp("_default", type + len) != 0) { continue; } memcpy(buffer, type, len); buffer[len] = '\0'; type = buffer; /* Skip past any leading X. X: X, etc to allow for multiple * instances */ for (str = type; *str; str++) { if (*str == ':' || *str == ',' || *str == '.') { str++; if (*str) type = str; break; } } /* if it is already set, skip this */ nid = OBJ_txt2nid(type); if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) continue; zend_printf("%s not already set; using default of %s\n", type, v->value); if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_ASC, (unsigned char*)v->value, -1, -1, 0)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value); return FAILURE; } if (!X509_NAME_entry_count(subj)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "no objects specified in config file"); return FAILURE; } } if (attribs) { zend_hash_internal_pointer_reset_ex(HASH_OF(attribs), &hpos); while(zend_hash_get_current_data_ex(HASH_OF(attribs), (void**)&item, &hpos) == SUCCESS) { char * strindex; int strindexlen; long intindex; zend_hash_get_current_key_ex(HASH_OF(attribs), &strindex, &strindexlen, &intindex, 0, &hpos); convert_to_string_ex(item); if (strindex) { int nid; nid = OBJ_txt2nid(strindex); if (nid != NID_undef) { if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item)); return FAILURE; } } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex); } } zend_hash_move_forward_ex(HASH_OF(attribs), &hpos); } for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { v = sk_CONF_VALUE_value(attr_sk, i); /* if it is already set, skip this */ nid = OBJ_txt2nid(v->name); if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) continue; if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_ASC, (unsigned char*)v->value, -1)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "add1_attr_by_txt %s -> %s (failed)", v->name, v->value); return FAILURE; } } } } X509_REQ_set_pubkey(csr, req->priv_key); return SUCCESS;}/* }}} *//* {{{ php_openssl_csr_from_zval */static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC){ X509_REQ * csr = NULL; char * filename = NULL; BIO * in; if (resourceval) *resourceval = -1; if (Z_TYPE_PP(val) == IS_RESOURCE) { void * what; int type; what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509 CSR", &type, 1, le_csr); if (what) { if (resourceval) *resourceval = Z_LVAL_PP(val); return (X509_REQ*)what; } return NULL; } convert_to_string_ex(val); if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", 7) == 0) filename = Z_STRVAL_PP(val) + 7; if (filename) { if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { return NULL; } in = BIO_new_file(filename, "r"); } else in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL); BIO_free(in); return csr;}/* }}} *//* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true]) Exports a CSR to file */PHP_FUNCTION(openssl_csr_export_to_file){ X509_REQ * csr; zval * zcsr = NULL; zend_bool notext = 1; char * filename = NULL; int filename_len; BIO * bio_out; long csr_resource; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) return; RETVAL_FALSE; csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC); if (csr == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); return; } if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { return; } bio_out = BIO_new_file(filename, "w"); if (bio_out) { if (!notext) X509_REQ_print(bio_out, csr); PEM_write_bio_X509_REQ(bio_out, csr); RETVAL_TRUE; } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename); } if (csr_resource == -1 && csr) X509_REQ_free(csr); BIO_free(bio_out);}/* }}} */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -