summaryrefslogtreecommitdiff
path: root/ext/openssl/openssl.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2007-08-06 08:43:43 +0000
committerDmitry Stogov <dmitry@php.net>2007-08-06 08:43:43 +0000
commita433f85ce1f4f898abb407575ec15fd6ef804130 (patch)
tree440d9831791f8a006c6e28aa759ff4809aca7a65 /ext/openssl/openssl.c
parentda7792c135a1ddb80e9ad1ecf4b04257993ee7d1 (diff)
downloadphp-git-a433f85ce1f4f898abb407575ec15fd6ef804130.tar.gz
Improved ext/openssl
. Added support for OpenSSL digest functions . Added support for OpenSSL cipher functions . Added access to internal values of DSA, RSA and DH keys
Diffstat (limited to 'ext/openssl/openssl.c')
-rw-r--r--ext/openssl/openssl.c575
1 files changed, 531 insertions, 44 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index c6eee0183a..d583220965 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -33,6 +33,8 @@
#include "ext/standard/file.h"
#include "ext/standard/info.h"
#include "ext/standard/php_fopen_wrappers.h"
+#include "ext/standard/md5.h"
+#include "ext/standard/base64.h"
/* OpenSSL includes */
#include <openssl/evp.h>
@@ -88,6 +90,15 @@ enum php_openssl_cipher_type {
PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
};
+PHP_FUNCTION(openssl_get_md_methods);
+PHP_FUNCTION(openssl_get_cipher_methods);
+
+PHP_FUNCTION(openssl_digest);
+PHP_FUNCTION(openssl_encrypt);
+PHP_FUNCTION(openssl_decrypt);
+
+PHP_FUNCTION(openssl_dh_compute_key);
+
/* {{{ openssl_functions[]
*/
zend_function_entry openssl_functions[] = {
@@ -126,10 +137,13 @@ zend_function_entry openssl_functions[] = {
PHP_FE(openssl_csr_get_subject, NULL)
PHP_FE(openssl_csr_get_public_key, NULL)
- PHP_FE(openssl_sign, second_arg_force_ref)
- PHP_FE(openssl_verify, NULL)
- PHP_FE(openssl_seal, arg2and3_force_ref)
- PHP_FE(openssl_open, second_arg_force_ref)
+ PHP_FE(openssl_digest, NULL)
+ PHP_FE(openssl_encrypt, NULL)
+ PHP_FE(openssl_decrypt, NULL)
+ PHP_FE(openssl_sign, second_arg_force_ref)
+ PHP_FE(openssl_verify, NULL)
+ PHP_FE(openssl_seal, arg2and3_force_ref)
+ PHP_FE(openssl_open, second_arg_force_ref)
/* for S/MIME handling */
PHP_FE(openssl_pkcs7_verify, NULL)
@@ -142,6 +156,11 @@ zend_function_entry openssl_functions[] = {
PHP_FE(openssl_public_encrypt, second_arg_force_ref)
PHP_FE(openssl_public_decrypt, second_arg_force_ref)
+ PHP_FE(openssl_get_md_methods, NULL)
+ PHP_FE(openssl_get_cipher_methods, NULL)
+
+ PHP_FE(openssl_dh_compute_key, NULL)
+
PHP_FE(openssl_error_string, NULL)
{NULL, NULL, NULL}
};
@@ -645,6 +664,34 @@ static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
return mdtype;
}
/* }}} */
+
+static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* {{{ */
+ switch (algo) {
+#ifndef OPENSSL_NO_RC2
+ case PHP_OPENSSL_CIPHER_RC2_40:
+ return EVP_rc2_40_cbc();
+ break;
+ case PHP_OPENSSL_CIPHER_RC2_64:
+ return EVP_rc2_64_cbc();
+ break;
+ case PHP_OPENSSL_CIPHER_RC2_128:
+ return EVP_rc2_cbc();
+ break;
+#endif
+
+#ifndef OPENSSL_NO_DES
+ case PHP_OPENSSL_CIPHER_DES:
+ return EVP_des_cbc();
+ break;
+ case PHP_OPENSSL_CIPHER_3DES:
+ return EVP_des_ede3_cbc();
+ break;
+#endif
+ default:
+ return NULL;
+ break;
+ }
+}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
@@ -2476,6 +2523,25 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
}
break;
#endif
+#if !defined(NO_DH)
+ case OPENSSL_KEYTYPE_DH:
+ {
+ DH *dhpar = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
+ int codes = 0;
+
+ if (dhpar) {
+ DH_set_method(dhpar, DH_get_default_method());
+ if (DH_check(dhpar, &codes) && codes == 0 && DH_generate_key(dhpar)) {
+ if (EVP_PKEY_assign_DH(req->priv_key, dhpar)) {
+ return_val = req->priv_key;
+ }
+ } else {
+ DH_free(dhpar);
+ }
+ }
+ }
+ break;
+#endif
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type");
}
@@ -2540,18 +2606,111 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
}
/* }}} */
+#define OPENSSL_PKEY_GET_BN(_type, _name) do { \
+ if (pkey->pkey._type->_name != NULL) { \
+ int len = BN_num_bytes(pkey->pkey._type->_name); \
+ char *str = emalloc(len + 1); \
+ BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)str); \
+ str[len] = 0; \
+ add_assoc_stringl(_type, #_name, str, len, 0); \
+ } \
+ } while (0)
+
+#define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \
+ zval **bn; \
+ if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \
+ Z_TYPE_PP(bn) == IS_STRING) { \
+ _type->_name = BN_bin2bn( \
+ (unsigned char*)Z_STRVAL_PP(bn), \
+ Z_STRLEN_PP(bn), NULL); \
+ } \
+ } while (0);
+
+
/* {{{ proto resource openssl_pkey_new([array configargs])
Generates a new private key */
PHP_FUNCTION(openssl_pkey_new)
{
struct php_x509_request req;
zval * args = NULL;
+ zval **data;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == FAILURE) {
return;
}
RETVAL_FALSE;
-
+
+ if (args && Z_TYPE_P(args) == IS_ARRAY) {
+ EVP_PKEY *pkey;
+
+ if (zend_hash_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa"), (void**)&data) == SUCCESS &&
+ Z_TYPE_PP(data) == IS_ARRAY) {
+ pkey = EVP_PKEY_new();
+ if (pkey) {
+ RSA *rsa = RSA_new();
+ if (rsa) {
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, n);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, e);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, d);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, p);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, q);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmp1);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmq1);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp);
+ if (EVP_PKEY_assign_RSA(pkey, rsa)) {
+ RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+ }
+ RSA_free(rsa);
+ }
+ EVP_PKEY_free(pkey);
+ }
+ RETURN_FALSE;
+ } else if (zend_hash_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa"), (void**)&data) == SUCCESS &&
+ Z_TYPE_PP(data) == IS_ARRAY) {
+ pkey = EVP_PKEY_new();
+ if (pkey) {
+ DSA *dsa = DSA_new();
+ if (dsa) {
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, p);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, q);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, g);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, priv_key);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, pub_key);
+ if (!dsa->priv_key && !dsa->pub_key) {
+ DSA_generate_key(dsa);
+ }
+ if (EVP_PKEY_assign_DSA(pkey, dsa)) {
+ RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+ }
+ DSA_free(dsa);
+ }
+ EVP_PKEY_free(pkey);
+ }
+ RETURN_FALSE;
+ } else if (zend_hash_find(Z_ARRVAL_P(args), "dh", sizeof("dh"), (void**)&data) == SUCCESS &&
+ Z_TYPE_PP(data) == IS_ARRAY) {
+ pkey = EVP_PKEY_new();
+ if (pkey) {
+ DH *dh = DH_new();
+ if (dh) {
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, p);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, g);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, priv_key);
+ OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, pub_key);
+ if (!dh->priv_key && !dh->pub_key) {
+ DH_generate_key(dh);
+ }
+ if (EVP_PKEY_assign_DH(pkey, dh)) {
+ RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+ }
+ DH_free(dh);
+ }
+ EVP_PKEY_free(pkey);
+ }
+ RETURN_FALSE;
+ }
+ }
+
PHP_SSL_REQ_INIT(&req);
if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
@@ -2769,15 +2928,59 @@ PHP_FUNCTION(openssl_pkey_get_details)
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
ktype = OPENSSL_KEYTYPE_RSA;
+
+ if (pkey->pkey.rsa != NULL) {
+ zval *rsa;
+
+ ALLOC_INIT_ZVAL(rsa);
+ array_init(rsa);
+ OPENSSL_PKEY_GET_BN(rsa, n);
+ OPENSSL_PKEY_GET_BN(rsa, e);
+ OPENSSL_PKEY_GET_BN(rsa, d);
+ OPENSSL_PKEY_GET_BN(rsa, p);
+ OPENSSL_PKEY_GET_BN(rsa, q);
+ OPENSSL_PKEY_GET_BN(rsa, dmp1);
+ OPENSSL_PKEY_GET_BN(rsa, dmq1);
+ OPENSSL_PKEY_GET_BN(rsa, iqmp);
+ add_assoc_zval(return_value, "rsa", rsa);
+ }
+
break;
case EVP_PKEY_DSA:
case EVP_PKEY_DSA2:
case EVP_PKEY_DSA3:
case EVP_PKEY_DSA4:
ktype = OPENSSL_KEYTYPE_DSA;
+
+ if (pkey->pkey.dsa != NULL) {
+ zval *dsa;
+
+ ALLOC_INIT_ZVAL(dsa);
+ array_init(dsa);
+ OPENSSL_PKEY_GET_BN(dsa, p);
+ OPENSSL_PKEY_GET_BN(dsa, q);
+ OPENSSL_PKEY_GET_BN(dsa, g);
+ OPENSSL_PKEY_GET_BN(dsa, priv_key);
+ OPENSSL_PKEY_GET_BN(dsa, pub_key);
+ add_assoc_zval(return_value, "dsa", dsa);
+ }
break;
case EVP_PKEY_DH:
+
ktype = OPENSSL_KEYTYPE_DH;
+
+ if (pkey->pkey.dh != NULL) {
+ zval *dh;
+
+ ALLOC_INIT_ZVAL(dh);
+ array_init(dh);
+ OPENSSL_PKEY_GET_BN(dh, p);
+ OPENSSL_PKEY_GET_BN(dh, g);
+ OPENSSL_PKEY_GET_BN(dh, priv_key);
+ OPENSSL_PKEY_GET_BN(dh, pub_key);
+ add_assoc_zval(return_value, "dh", dh);
+ }
+
break;
#ifdef EVP_PKEY_EC
case EVP_PKEY_EC:
@@ -2994,32 +3197,7 @@ PHP_FUNCTION(openssl_pkcs7_encrypt)
}
/* sanity check the cipher */
- switch (cipherid) {
-#ifndef OPENSSL_NO_RC2
- case PHP_OPENSSL_CIPHER_RC2_40:
- cipher = EVP_rc2_40_cbc();
- break;
- case PHP_OPENSSL_CIPHER_RC2_64:
- cipher = EVP_rc2_64_cbc();
- break;
- case PHP_OPENSSL_CIPHER_RC2_128:
- cipher = EVP_rc2_cbc();
- break;
-#endif
-
-#ifndef OPENSSL_NO_DES
- case PHP_OPENSSL_CIPHER_DES:
- cipher = EVP_des_cbc();
- break;
- case PHP_OPENSSL_CIPHER_3DES:
- cipher = EVP_des_ede3_cbc();
- break;
-#endif
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid cipher type `%ld'", cipherid);
- goto clean_exit;
- }
+ cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
if (cipher == NULL) {
/* shouldn't happen */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher");
@@ -3518,7 +3696,7 @@ PHP_FUNCTION(openssl_error_string)
}
/* }}} */
-/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, int signature_alg])
+/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
Signs data */
PHP_FUNCTION(openssl_sign)
{
@@ -3530,10 +3708,11 @@ PHP_FUNCTION(openssl_sign)
char * data;
int data_len;
EVP_MD_CTX md_ctx;
+ zval *method = NULL;
long signature_algo = OPENSSL_ALGO_SHA1;
- EVP_MD *mdtype;
+ const EVP_MD *mdtype;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &signature, &key, &signature_algo) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
return;
}
pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
@@ -3542,7 +3721,17 @@ PHP_FUNCTION(openssl_sign)
RETURN_FALSE;
}
- mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+ if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
+ if (Z_TYPE_P(method) == IS_LONG) {
+ signature_algo = Z_LVAL_P(method);
+ }
+ mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+ } else if (Z_TYPE_P(method) == IS_STRING) {
+ mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
+ RETURN_FALSE;
+ }
if (!mdtype) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
RETURN_FALSE;
@@ -3568,7 +3757,7 @@ PHP_FUNCTION(openssl_sign)
}
/* }}} */
-/* {{{ proto int openssl_verify(string data, string signature, mixed key [, int signature_algo])
+/* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
Verifys data */
PHP_FUNCTION(openssl_verify)
{
@@ -3576,17 +3765,28 @@ PHP_FUNCTION(openssl_verify)
EVP_PKEY *pkey;
int err;
EVP_MD_CTX md_ctx;
- EVP_MD *mdtype;
+ const EVP_MD *mdtype;
long keyresource = -1;
char * data; int data_len;
char * signature; int signature_len;
+ zval *method = NULL;
long signature_algo = OPENSSL_ALGO_SHA1;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|l", &data, &data_len, &signature, &signature_len, &key, &signature_algo) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
return;
}
- mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+ if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
+ if (Z_TYPE_P(method) == IS_LONG) {
+ signature_algo = Z_LVAL_P(method);
+ }
+ mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+ } else if (Z_TYPE_P(method) == IS_STRING) {
+ mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
+ RETURN_FALSE;
+ }
if (!mdtype) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
RETURN_FALSE;
@@ -3621,9 +3821,12 @@ PHP_FUNCTION(openssl_seal)
int i, len1, len2, *eksl, nkeys;
unsigned char *buf = NULL, **eks;
char * data; int data_len;
+ char *method =NULL;
+ int method_len;
+ const EVP_CIPHER *cipher;
EVP_CIPHER_CTX ctx;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/", &data, &data_len, &sealdata, &ekeys, &pubkeys) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
return;
}
@@ -3634,6 +3837,16 @@ PHP_FUNCTION(openssl_seal)
RETURN_FALSE;
}
+ if (method) {
+ cipher = EVP_get_cipherbyname(method);
+ if (!cipher) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
+ RETURN_FALSE;
+ }
+ } else {
+ cipher = EVP_rc4();
+ }
+
pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
eks = safe_emalloc(nkeys, sizeof(*eks), 0);
@@ -3657,7 +3870,7 @@ PHP_FUNCTION(openssl_seal)
i++;
}
- if (!EVP_EncryptInit(&ctx,EVP_rc4(),NULL,NULL)) {
+ if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
RETVAL_FALSE;
goto clean_exit;
}
@@ -3670,7 +3883,7 @@ PHP_FUNCTION(openssl_seal)
/* allocate one byte extra to make room for \0 */
buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
- if (!EVP_SealInit(&ctx, EVP_rc4(), eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
+ if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
RETVAL_FALSE;
efree(buf);
goto clean_exit;
@@ -3734,8 +3947,11 @@ PHP_FUNCTION(openssl_open)
EVP_CIPHER_CTX ctx;
char * data; int data_len;
char * ekey; int ekey_len;
+ char *method =NULL;
+ int method_len;
+ const EVP_CIPHER *cipher;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) {
return;
}
@@ -3744,9 +3960,20 @@ PHP_FUNCTION(openssl_open)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key");
RETURN_FALSE;
}
+
+ if (method) {
+ cipher = EVP_get_cipherbyname(method);
+ if (!cipher) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
+ RETURN_FALSE;
+ }
+ } else {
+ cipher = EVP_rc4();
+ }
+
buf = emalloc(data_len + 1);
- if (EVP_OpenInit(&ctx, EVP_rc4(), (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
+ if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
efree(buf);
if (keyresource == -1) {
@@ -3996,6 +4223,266 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
}
/* }}} */
+static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
+{
+ add_next_index_string((zval*)arg, (char*)name->name, 1);
+}
+/* }}} */
+
+static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
+{
+ if (name->alias == 0) {
+ add_next_index_string((zval*)arg, (char*)name->name, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array openssl_get_md_methods([bool aliases = false])
+ Return array of available digest methods */
+PHP_FUNCTION(openssl_get_md_methods)
+{
+ zend_bool aliases = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
+ return;
+ }
+ array_init(return_value);
+ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
+ aliases ? openssl_add_method_or_alias: openssl_add_method,
+ return_value);
+}
+/* }}} */
+
+/* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
+ Return array of available cipher methods */
+PHP_FUNCTION(openssl_get_cipher_methods)
+{
+ zend_bool aliases = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
+ return;
+ }
+ array_init(return_value);
+ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
+ aliases ? openssl_add_method_or_alias: openssl_add_method,
+ return_value);
+}
+/* }}} */
+
+/* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
+ Computes digest hash value for given data using given method, returns raw or binhex encoded string */
+PHP_FUNCTION(openssl_digest)
+{
+ zend_bool raw_output = 0;
+ char *data, *method;
+ int data_len, method_len;
+ const EVP_MD *mdtype;
+ EVP_MD_CTX md_ctx;
+ int siglen;
+ unsigned char *sigbuf;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
+ return;
+ }
+ mdtype = EVP_get_digestbyname(method);
+ if (!mdtype) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
+ RETURN_FALSE;
+ }
+
+ siglen = EVP_MD_size(mdtype);
+ sigbuf = emalloc(siglen + 1);
+
+ EVP_DigestInit(&md_ctx, mdtype);
+ EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
+ if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int *)&siglen)) {
+ if (raw_output) {
+ sigbuf[siglen] = '\0';
+ RETVAL_STRINGL((char *)sigbuf, siglen, 0);
+ } else {
+ int digest_str_len = siglen * 2;
+ char *digest_str = emalloc(digest_str_len + 1);
+
+ make_digest_ex(digest_str, sigbuf, siglen);
+ efree(sigbuf);
+ RETVAL_STRINGL(digest_str, digest_str_len, 0);
+ }
+ } else {
+ efree(sigbuf);
+ RETVAL_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false])
+ Encrypts given data with given method and key, returns raw or base64 encoded string */
+PHP_FUNCTION(openssl_encrypt)
+{
+ zend_bool raw_output = 0;
+ char *data, *method, *password;
+ int data_len, method_len, password_len;
+ const EVP_CIPHER *cipher_type;
+ EVP_CIPHER_CTX cipher_ctx;
+ int i, outlen, keylen, ivlen;
+ unsigned char *outbuf, *key, *iv;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_output) == FAILURE) {
+ return;
+ }
+ cipher_type = EVP_get_cipherbyname(method);
+ if (!cipher_type) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
+ RETURN_FALSE;
+ }
+
+ keylen = EVP_CIPHER_key_length(cipher_type);
+ if (keylen > password_len) {
+ key = emalloc(keylen);
+ memset(key, 0, keylen);
+ memcpy(key, password, password_len);
+ } else {
+ key = (unsigned char*)password;
+ }
+
+ ivlen = EVP_CIPHER_iv_length(cipher_type);
+ iv = emalloc(ivlen);
+ memset(iv, 0, ivlen);
+
+ outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+ outbuf = emalloc(outlen + 1);
+
+ EVP_EncryptInit(&cipher_ctx, cipher_type, key, iv);
+ EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
+ outlen = i;
+ if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
+ outlen += i;
+ if (raw_output) {
+ outbuf[outlen] = '\0';
+ RETVAL_STRINGL((char *)outbuf, outlen, 0);
+ } else {
+ int base64_str_len;
+ char *base64_str;
+
+ base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len);
+ efree(outbuf);
+ RETVAL_STRINGL(base64_str, base64_str_len, 0);
+ }
+ } else {
+ efree(outbuf);
+ RETVAL_FALSE;
+ }
+ if (key != (unsigned char*)password) {
+ efree(key);
+ }
+ efree(iv);
+}
+/* }}} */
+
+/* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false])
+ Takes raw or base64 encoded string and dectupt it using given method and key */
+PHP_FUNCTION(openssl_decrypt)
+{
+ zend_bool raw_input = 0;
+ char *data, *method, *password;
+ int data_len, method_len, password_len;
+ const EVP_CIPHER *cipher_type;
+ EVP_CIPHER_CTX cipher_ctx;
+ int i, outlen, keylen, ivlen;
+ unsigned char *outbuf, *key, *iv;
+ int base64_str_len;
+ char *base64_str = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_input) == FAILURE) {
+ return;
+ }
+
+ if (!raw_input) {
+ base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len);
+ data_len = base64_str_len;
+ data = base64_str;
+ }
+
+ cipher_type = EVP_get_cipherbyname(method);
+ if (!cipher_type) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
+ RETURN_FALSE;
+ }
+
+ keylen = EVP_CIPHER_key_length(cipher_type);
+ if (keylen > password_len) {
+ key = emalloc(keylen);
+ memset(key, 0, keylen);
+ memcpy(key, password, password_len);
+ } else {
+ key = (unsigned char*)password;
+ }
+
+ ivlen = EVP_CIPHER_iv_length(cipher_type);
+ iv = emalloc(ivlen);
+ memset(iv, 0, ivlen);
+
+ outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+ outbuf = emalloc(outlen + 1);
+
+ EVP_DecryptInit(&cipher_ctx, cipher_type, key, iv);
+ EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
+ outlen = i;
+ if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
+ outlen += i;
+ outbuf[outlen] = '\0';
+ RETVAL_STRINGL((char *)outbuf, outlen, 0);
+ } else {
+ efree(outbuf);
+ RETVAL_FALSE;
+ }
+ if (key != (unsigned char*)password) {
+ efree(key);
+ }
+ efree(iv);
+ if (base64_str) {
+ efree(base64_str);
+ }
+}
+/* }}} */
+
+
+/* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
+ Computes shared sicret for public value of remote DH key and local DH key */
+PHP_FUNCTION(openssl_dh_compute_key)
+{
+ zval *key;
+ char *pub_str;
+ int pub_len;
+ EVP_PKEY *pkey;
+ BIGNUM *pub;
+ char *data;
+ int len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, &pub_len, &key) == FAILURE) {
+ return;
+ }
+ ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
+ if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
+ RETURN_FALSE;
+ }
+
+ pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
+
+ data = emalloc(DH_size(pkey->pkey.dh) + 1);
+ len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
+
+ if (len >= 0) {
+ data[len] = 0;
+ RETVAL_STRINGL(data, len, 0);
+ } else {
+ efree(data);
+ RETVAL_FALSE;
+ }
+
+ BN_free(pub);
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 8