📄 openssl.c
字号:
/* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true]) Exports a CSR to file or a var */PHP_FUNCTION(openssl_csr_export){ X509_REQ * csr; zval * zcsr = NULL, *zout=NULL; zend_bool notext = 1; BIO * bio_out; long csr_resource; char * bio_mem_ptr; long bio_mem_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zcsr, &zout, ¬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; } /* export to a var */ bio_out = BIO_new(BIO_s_mem()); if (!notext) X509_REQ_print(bio_out, csr); PEM_write_bio_X509_REQ(bio_out, csr); bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr); ZVAL_STRINGL(zout, bio_mem_ptr, bio_mem_len, 1); RETVAL_TRUE; if (csr_resource == -1 && csr) X509_REQ_free(csr); BIO_free(bio_out);}/* }}} *//* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]]) Signs a cert with another CERT */PHP_FUNCTION(openssl_csr_sign){ zval * zcert = NULL, *zcsr, *zpkey, *args = NULL; long num_days; long serial = 0L; X509 * cert = NULL, *new_cert = NULL; X509_REQ * csr; EVP_PKEY * key = NULL, *priv_key = NULL; long csr_resource, certresource, keyresource; int i; struct php_x509_request req; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz!zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE) return; RETVAL_FALSE; PHP_SSL_REQ_INIT(&req); 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 (zcert) { cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC); if (cert == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 2"); goto cleanup; } } priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC); if (priv_key == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; } if (cert && !X509_check_private_key(cert, priv_key)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert"); goto cleanup; } if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) goto cleanup; /* Check that the request matches the signature */ key = X509_REQ_get_pubkey(csr); if (key == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "error unpacking public key"); goto cleanup; } i = X509_REQ_verify(csr, key); if (i < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature verification problems"); goto cleanup; } else if (i==0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature did not match the certificate request"); goto cleanup; } /* Now we can get on with it */ new_cert = X509_new(); if (new_cert == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "No memory"); goto cleanup; } /* Version 3 cert */ if (!X509_set_version(new_cert, 2)) goto cleanup; ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial); X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr)); if (cert == NULL) cert = new_cert; if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) goto cleanup; X509_gmtime_adj(X509_get_notBefore(new_cert), 0); X509_gmtime_adj(X509_get_notAfter(new_cert), (long)60*60*24*num_days); i = X509_set_pubkey(new_cert, key); if (!i) goto cleanup; if (req.request_extensions_section) { X509V3_CTX ctx; X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0); X509V3_set_conf_lhash(&ctx, req.req_config); if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.request_extensions_section, new_cert)) goto cleanup; } /* Now sign it */ if (!X509_sign(new_cert, priv_key, req.digest)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it"); goto cleanup; } /* Succeeded; lets return the cert */ RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509)); new_cert = NULL; cleanup: if (cert == new_cert) cert = NULL; PHP_SSL_REQ_DISPOSE(&req); if (keyresource == -1 && priv_key) EVP_PKEY_free(priv_key); if (key) EVP_PKEY_free(key); if (csr_resource == -1 && csr) X509_REQ_free(csr); if (certresource == -1 && cert) X509_free(cert); if (new_cert) X509_free(new_cert);}/* }}} *//* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs, array extraattribs]) Generates a privkey and CSR */PHP_FUNCTION(openssl_csr_new){ struct php_x509_request req; zval * args = NULL, * dn, *attribs = NULL; zval * out_pkey; X509_REQ * csr = NULL; int we_made_the_key = 1; long key_resource; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) return; RETVAL_FALSE; PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { /* Generate or use a private key */ if (Z_TYPE_P(out_pkey) != IS_NULL) { req.priv_key = php_openssl_evp_from_zval(&out_pkey, 0, NULL, 0, &key_resource TSRMLS_CC); if (req.priv_key != NULL) we_made_the_key = 0; } if (req.priv_key == NULL) php_openssl_generate_private_key(&req TSRMLS_CC); if (req.priv_key == NULL) php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to generate a private key"); else { csr = X509_REQ_new(); if (csr) { if (php_openssl_make_REQ(&req, csr, dn, attribs TSRMLS_CC) == SUCCESS) { X509V3_CTX ext_ctx; X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0); X509V3_set_conf_lhash(&ext_ctx, req.req_config); /* Add extensions */ if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config, &ext_ctx, req.request_extensions_section, csr)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading extension section %s", req.request_extensions_section); } else { RETVAL_TRUE; if (X509_REQ_sign(csr, req.priv_key, req.digest)) { RETVAL_RESOURCE(zend_list_insert(csr, le_csr)); csr = NULL; } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request"); } if (we_made_the_key) { /* and a resource for the private key */ ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key)); req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ } else if (key_resource != -1) req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ } } else { if (!we_made_the_key) { /* if we have not made the key we are not supposed to zap it by calling dispose! */ req.priv_key = NULL; } } } } } if (csr) X509_REQ_free(csr); PHP_SSL_REQ_DISPOSE(&req);}/* }}} *//* }}} *//* {{{ EVP Public/Private key functions *//* {{{ php_openssl_evp_from_zval Given a zval, coerce it into a EVP_PKEY object. It can be: 1. private key resource from openssl_get_privatekey() 2. X509 resource -> public key will be extracted from it 3. if it starts with file:// interpreted as path to key file 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey() 5. an array(0 => [items 2..4], 1 => passphrase) 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key NOTE: If you are requesting a private key but have not specified a passphrase, you should use an empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in the Apache error log!*/static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC){ EVP_PKEY * key = NULL; X509 * cert = NULL; int free_cert = 0; long cert_res = -1; char * filename = NULL; if (resourceval) *resourceval = -1; if (Z_TYPE_PP(val) == IS_ARRAY) { zval ** zphrase; /* get passphrase */ if (zend_hash_index_find(HASH_OF(*val), 1, (void **)&zphrase) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); return NULL; } convert_to_string_ex(zphrase); passphrase = Z_STRVAL_PP(zphrase); /* now set val to be the key param and continue */ if (zend_hash_index_find(HASH_OF(*val), 0, (void **)&val) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); return NULL; } } if (Z_TYPE_PP(val) == IS_RESOURCE) { void * what; int type; what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key); if (!what) return NULL; if (resourceval) *resourceval = Z_LVAL_PP(val); if (type == le_x509) { /* extract key from cert, depending on public_key param */ cert = (X509*)what; free_cert = 0; } else if (type == le_key) { int is_priv; is_priv = php_openssl_is_private_key((EVP_PKEY*)what TSRMLS_CC); /* check whether it is actually a private key if requested */ if (!public_key && !is_priv) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param is a public key"); return NULL; } if (public_key && is_priv) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Don't know how to get public key from this private key (the documentation lied)"); return NULL; } else { /* got the key - return it */ return (EVP_PKEY*)what; } } /* other types could be used here - eg: file pointers and read in the data from them */ return NULL; } else { /* force it to be a string and check if it refers to a file */ 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; /* it's an X509 file/cert of some kind, and we need to extract the data from that */ if (public_key) { cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC); free_cert = (cert_res == -1); /* actual extraction done later */ if (!cert) { /* not a X509 certificate, try to retrieve public key */ BIO* in; if (filename) in = BIO_new_file(filename, "r"); else in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); if (in == NULL) return NULL; key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL); BIO_free(in); } } else { /* we want the private key */ BIO *in; 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)); } if (in == NULL) { return NULL; } key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase); BIO_free(in); } } if (public_key && cert && key == NULL) { /* extract public key from X509 cert */ key = (EVP_PKEY *) X509_get_pubkey(cert); } if (free_cert && cert) X509_free(cert); if (key && makeresource && resourceval) { *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key); } return key;}/* }}} *//* {{{ php_openssl_generate_private_key */static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC){ char * randfile = NULL; int egdsocket, seeded; EVP_PKEY * return_val = NULL; if (req->priv_key_bits < MIN_KEY_LENGTH) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d", MIN_KEY_LENGTH, req->priv_key_bits); return NULL; } randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE"); php_openssl_load_rand_file(randfile, &egdsocket, &seeded); if ((req->priv_key = EVP_PKEY_new()) != NULL) { switch(req->priv_key_type) { case OPENSSL_KEYTYPE_RSA: if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) return_val = req->priv_key; break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type"); } } php_openssl_write_rand_file(randfile, egdsocket, seeded TSRMLS_CC); if (return_val == NULL) { EVP_PKEY_free(req->priv_key); req->priv_key = NULL; return NULL; } return return_val;}/* }}} *//* {{{ php_openssl_is_private_key Check whether the supplied key is a private key by checking if the secret prime factors are set */static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC){ assert(pkey != NULL); switch (pkey->type) {#ifndef NO_RSA case EVP_PKEY_RSA: case EVP_PKEY_RSA2: assert(pkey->pkey.rsa != NULL); if (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q) return 0; break;#endif#ifndef NO_DSA case EVP_PKEY_DSA: case EVP_PKEY_DSA1: case EVP_PKEY_DSA2: case EVP_PKEY_DSA3: case EVP_PKEY_DSA4: assert(pkey->pkey.dsa != NULL); if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key) return 0; break;#endif#ifndef NO_DH case EVP_PKEY_DH: assert(pkey->pkey.dh != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -