I'd like to tuck the attached patch into the PHP 5 branch.
It provides the following functions, and does not modify the behavior of any of the others:

openssl_bignum_from_bin
openssl_bignum_from_hex
openssl_bignum_from_dec
openssl_bignum_to_string

openssl_dh_generate_key
openssl_dh_compute_key
openssl_dh_get_params
openssl_dh_generate_parameters

openssl_dsa_verify

These functions allow one to implement OpenID and TypeKey authentication schemes without resorting to writing crypto code in user-space PHP--aside from the speed advantage, you have the benefit of using the tried and trusted OpenSSL for your DH kex.

--Wez.
Index: openssl.c
===================================================================
RCS file: /repository/php-src/ext/openssl/openssl.c,v
retrieving revision 1.98.2.5.2.27
diff -u -p -r1.98.2.5.2.27 openssl.c
--- openssl.c   20 Jan 2007 22:08:29 -0000      1.98.2.5.2.27
+++ openssl.c   10 Feb 2007 04:02:04 -0000
@@ -42,6 +42,8 @@
 #include <openssl/conf.h>
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
 
 #define DEFAULT_KEY_LENGTH     512
 #define MIN_KEY_LENGTH         384
@@ -135,6 +137,17 @@ zend_function_entry openssl_functions[] 
        PHP_FE(openssl_public_decrypt,          second_arg_force_ref)
 
        PHP_FE(openssl_error_string, NULL)
+
+       PHP_FE(openssl_bignum_from_bin, NULL)
+       PHP_FE(openssl_bignum_from_hex, NULL)
+       PHP_FE(openssl_bignum_from_dec, NULL)
+       PHP_FE(openssl_bignum_to_string, NULL)
+       PHP_FE(openssl_dh_generate_key, NULL)
+       PHP_FE(openssl_dh_compute_key, NULL)
+       PHP_FE(openssl_dh_get_params, NULL)
+       PHP_FE(openssl_dh_generate_parameters, NULL)
+       PHP_FE(openssl_dsa_verify, NULL)
+
        {NULL, NULL, NULL}
 };
 /* }}} */
@@ -166,6 +179,14 @@ static int le_key;
 static int le_x509;
 static int le_csr;
 static int ssl_stream_data_index;
+static int le_num;
+static int le_dh;
+
+typedef struct {
+       BIGNUM *bn;
+       long ref;
+       long me;
+} php_bignum;
 
 int php_openssl_get_x509_list_id(void) /* {{{ */
 {
@@ -194,6 +215,46 @@ static void php_csr_free(zend_rsrc_list_
        X509_REQ * csr = (X509_REQ*)rsrc->ptr;
        X509_REQ_free(csr);
 }
+
+static void php_bignum_free(php_bignum *bn, int clear)
+{
+       if (bn->me != -1) {
+               zend_list_delete(bn->me);
+       } else {
+               if (bn->ref != -1) {
+                       zend_list_delete(bn->ref);
+               } else if (bn->bn != BN_value_one()) {
+                       if (clear)
+                               BN_clear_free(bn->bn);
+                       else
+                               BN_free(bn->bn);
+               }
+               efree(bn);
+       }
+}
+
+static long bignum_resource(php_bignum *bn)
+{
+       if (bn->me == -1) {
+               bn->me = zend_list_insert(bn, le_num);
+       }
+       return bn->me;
+}
+
+static void php_bignum_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+       php_bignum *bn = (php_bignum*)rsrc->ptr;
+       bn->me = -1;
+       php_bignum_free(bn, 1);
+}
+
+static void php_dh_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+       DH *dh = (DH*)rsrc->ptr;
+       DH_free(dh);
+}
+
+
 /* }}} */
 
 /* {{{ openssl safe_mode & open_basedir checks */
@@ -637,6 +698,8 @@ PHP_MINIT_FUNCTION(openssl)
        le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, 
"OpenSSL key", module_number);
        le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, 
"OpenSSL X.509", module_number);
        le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL 
X.509 CSR", module_number);
+       le_num = zend_register_list_destructors_ex(php_bignum_dtor, NULL, 
"OpenSSL BIGNUM", module_number);
+       le_dh = zend_register_list_destructors_ex(php_dh_free, NULL, "OpenSSL 
DH", module_number);
 
        SSL_library_init();
        OpenSSL_add_all_ciphers();
@@ -3361,6 +3424,400 @@ PHP_FUNCTION(openssl_open)
 }
 /* }}} */
 
+static php_bignum *openssl_bignum_from_zval(zval **val TSRMLS_DC)
+{
+       BIGNUM *bn = NULL;
+       php_bignum *bnw;
+       char *c;
+
+       if (Z_TYPE_PP(val) == IS_RESOURCE) {
+               /* is it a big number resource ? */
+               void * what;
+               int type;
+
+               what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL BIGNUM", 
&type, 1, le_num);
+               if (!what) {
+                       return NULL;
+               }
+               if (type == le_num) {
+                       zend_list_addref(Z_LVAL_PP(val));
+                       return (php_bignum*)what;
+               }
+               return NULL;
+       }
+
+       if (Z_TYPE_PP(val) != IS_STRING) {
+               return NULL;
+       }
+
+       /* force it to be a string */
+       convert_to_string_ex(val);
+
+       if (Z_STRLEN_PP(val) > 2) {
+               if (!strncmp(Z_STRVAL_PP(val), "0x", 2)) {
+                       /* hex */
+                       BN_hex2bn(&bn, Z_STRVAL_PP(val)+2);
+               }
+       }
+       if (bn == NULL) {
+               /* decimal */
+               BN_dec2bn(&bn, Z_STRVAL_PP(val));
+       }
+
+       if (bn) {
+               bnw = emalloc(sizeof(*bnw));
+               bnw->ref = -1;
+               bnw->me = -1;
+               bnw->bn = bn;
+       } else {
+               bnw = NULL;
+       }
+       return bnw;
+}
+
+/* {{{ proto resource openssl_bignum_from_bin(string binary)
+       Returns a bignum resource from the raw binary bytes supplied. */
+PHP_FUNCTION(openssl_bignum_from_bin)
+{
+       char *bin;
+       int blen;
+       BIGNUM *bn = NULL;
+       php_bignum *bnw;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+                       &bin, &blen)) {
+               return;
+       }
+
+       bn = BN_bin2bn((unsigned char*)bin, blen, NULL);
+
+       if (!bn) {
+               RETURN_FALSE;
+       }
+
+       bnw = emalloc(sizeof(*bnw));
+       bnw->me = -1;
+       bnw->ref = -1;
+       bnw->bn = bn;
+       
+       RETURN_RESOURCE(bignum_resource(bnw));
+}
+/* }}} */
+
+/* {{{ proto resource openssl_bignum_from_hex(string hex)
+       Returns a bignum resource from the hex string supplied */
+PHP_FUNCTION(openssl_bignum_from_hex)
+{
+       char *bin;
+       int blen;
+       BIGNUM *bn = NULL;
+       php_bignum *bnw;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+                       &bin, &blen)) {
+               return;
+       }
+
+       if (!BN_hex2bn(&bn, bin)) {
+               RETURN_FALSE;
+       }
+
+       bnw = emalloc(sizeof(*bnw));
+       bnw->ref = -1;
+       bnw->me = -1;
+       bnw->bn = bn;
+               
+       RETURN_RESOURCE(bignum_resource(bnw));
+}
+/* }}} */
+
+/* {{{ proto string openssl_bignum_to_string(mixed num [, int base])
+       Converts a big number to a string representation.  base is the number 
base; 0 for binary (default), 10 for decimal, 16 for hex */
+PHP_FUNCTION(openssl_bignum_to_string)
+{
+       zval **num;
+       php_bignum *bn;
+       long format = 0;
+       char *str;
+       int len;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l",
+                       &num, &format)) {
+               return;
+       }
+
+       bn = openssl_bignum_from_zval(num TSRMLS_CC);
+       if (!bn) RETURN_FALSE;
+
+       switch (format) {
+               case 0:
+                       len = BN_num_bytes(bn->bn);
+                       str = emalloc(len + 1);
+                       BN_bn2bin(bn->bn, (unsigned char*)str);
+                       RETVAL_STRINGL(str, len, 0);
+                       break;
+               case 10:
+                       str = BN_bn2dec(bn->bn);
+                       RETVAL_STRING(str, 1);
+                       OPENSSL_free(str);
+                       break;
+               case 16:
+                       str = BN_bn2hex(bn->bn);
+                       RETVAL_STRING(str, 1);
+                       OPENSSL_free(str);
+                       break;
+               default:
+                       RETVAL_FALSE;
+       }
+
+       php_bignum_free(bn, 0);
+}
+/* }}} */
+
+/* {{{ proto resource openssl_bignum_from_dec(string dec)
+       Returns a bignum resource from the decimal string supplied */
+PHP_FUNCTION(openssl_bignum_from_dec)
+{
+       char *bin;
+       int blen;
+       BIGNUM *bn = NULL;
+       php_bignum *bnw;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+                       &bin, &blen)) {
+               return;
+       }
+
+       if (!BN_dec2bn(&bn, bin)) {
+               RETURN_FALSE;
+       }
+
+       bnw = emalloc(sizeof(*bnw));
+       bnw->ref = -1;
+       bnw->bn = bn;
+       bnw->me = -1;
+       
+       RETURN_RESOURCE(bignum_resource(bnw));
+}
+/* }}} */
+
+
+/* {{{ proto resource openssl_dh_generate_key(mixed p, mixed g [, mixed priv])
+   Given shared parameters p and g, generates private and public keys */
+PHP_FUNCTION(openssl_dh_generate_key)
+{
+       zval **p, **g, **priv = NULL;
+       DH *dh;
+       php_bignum *P, *G, *PRIV = NULL;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|Z",
+                       &p, &g, &priv) == FAILURE) {
+               return;
+       }
+
+       P = openssl_bignum_from_zval(p TSRMLS_CC);
+       G = openssl_bignum_from_zval(g TSRMLS_CC);
+       if (priv) {
+               PRIV = openssl_bignum_from_zval(priv TSRMLS_CC);
+       }
+
+       dh = DH_new();
+       dh->p = P->bn;
+       dh->g = G->bn;
+       if (PRIV) {
+               dh->priv_key = PRIV->bn;
+       }
+
+       if (DH_generate_key(dh)) {
+               /* we're good */
+               ZVAL_RESOURCE(return_value, zend_list_insert(dh, le_dh));
+               return;
+       }
+       
+       if (P) php_bignum_free(P, 0);
+       if (G) php_bignum_free(G, 0);
+       if (PRIV) php_bignum_free(PRIV, 1);
+       DH_free(dh);
+}
+/* }}} */
+
+/* {{{ proto string openssl_dh_compute_key(resource dh, mixed peer_pub)
+   Computes the shared secret from the private DH value and the other party's 
public value, returning it as a raw binary string */
+PHP_FUNCTION(openssl_dh_compute_key)
+{
+       zval **pub, *dhval;
+       long pres;
+       DH *dh;
+       php_bignum *PUB;
+       char *data;
+       int len;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ",
+                       &dhval, &pub) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE(dh, DH *, &dhval, -1, "OpenSSL DH", le_dh);
+
+       PUB = openssl_bignum_from_zval(pub TSRMLS_CC);
+
+       data = emalloc(DH_size(dh) + 1);
+       len = DH_compute_key((unsigned char*)data, PUB->bn, dh);
+
+       if (len >= 0) {
+               RETVAL_STRINGL(data, len, 0);
+       } else {
+               RETVAL_FALSE;
+       }
+
+       if (PUB) php_bignum_free(PUB, 0);
+}
+/* }}} */
+
+/* {{{ proto array openssl_dh_get_params(resource dh)
+       Returns the various pieces of the DH as an array of big numbers */
+PHP_FUNCTION(openssl_dh_get_params)
+{
+       DH *dh;
+       zval *dhval;
+       zval *tmp;
+       php_bignum *bnw;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+                       &dhval) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE(dh, DH *, &dhval, -1, "OpenSSL DH", le_dh);
+
+       array_init(return_value);
+
+       if (dh->p) {
+               MAKE_STD_ZVAL(tmp);
+               bnw = emalloc(sizeof(*bnw));
+               bnw->ref = Z_LVAL_P(dhval);
+               zend_list_addref(bnw->ref);
+               bnw->me = -1;
+               bnw->bn = dh->p;
+               ZVAL_RESOURCE(tmp, bignum_resource(bnw));
+               add_assoc_zval(return_value, "p", tmp);
+       }
+       if (dh->g) {
+               MAKE_STD_ZVAL(tmp);
+               bnw = emalloc(sizeof(*bnw));
+               bnw->ref = Z_LVAL_P(dhval);
+               zend_list_addref(bnw->ref);
+               bnw->me = -1;
+               bnw->bn = dh->g;
+               ZVAL_RESOURCE(tmp, bignum_resource(bnw));
+               add_assoc_zval(return_value, "g", tmp);
+       }
+       if (dh->pub_key) {
+               MAKE_STD_ZVAL(tmp);
+               bnw = emalloc(sizeof(*bnw));
+               bnw->ref = Z_LVAL_P(dhval);
+               zend_list_addref(bnw->ref);
+               bnw->me = -1;
+               bnw->bn = dh->pub_key;
+               ZVAL_RESOURCE(tmp, bignum_resource(bnw));
+               add_assoc_zval(return_value, "pub_key", tmp);
+       }
+       if (dh->priv_key) {
+               MAKE_STD_ZVAL(tmp);
+               bnw = emalloc(sizeof(*bnw));
+               bnw->ref = Z_LVAL_P(dhval);
+               zend_list_addref(bnw->ref);
+               bnw->me = -1;
+               bnw->bn = dh->priv_key;
+               ZVAL_RESOURCE(tmp, bignum_resource(bnw));
+               add_assoc_zval(return_value, "priv_key", tmp);
+       }
+}
+/* }}} */
+
+/* {{{ proto resource openssl_dh_generate_parameters(int prime_len [, int 
generator])
+       Generates parameters g and p for a given length of prime. Generator is 
either 2 or 5. */
+PHP_FUNCTION(openssl_dh_generate_parameters)
+{
+       long prime_len, generator = 2;
+       DH *dh;
+       int codes;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l",
+                       &prime_len, &generator)) {
+               return;
+       }
+
+       if (generator != 2 && generator != 5) {
+               RETURN_FALSE;
+       }
+
+       dh = DH_generate_parameters(prime_len, generator, NULL, NULL);
+
+       if (dh) {
+               codes = 0;
+               if (DH_check(dh, &codes) && codes == 0) {
+                       RETURN_RESOURCE(zend_list_insert(dh, le_dh));
+               }
+               DH_free(dh);
+       }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_dsa_verify(string dgst, mixed r, mixed s, mixed p, 
mixed q, mixed g, mixed pub)
+       Verifies that sig is a valid signature of dgst, given the signing 
parameters. */
+PHP_FUNCTION(openssl_dsa_verify)
+{
+       char *dgst;
+       int dlen;
+       zval **p, **q, **g, **r, **s, **pub;
+       DSA *dsa;
+       php_bignum *P, *Q, *G, *R, *S, *PUB;
+       DSA_SIG sig;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZZZZZZ",
+                       &dgst, &dlen,
+                       &r, &s, &p, &q, &g, &pub) == FAILURE) {
+               return;
+       }
+
+       P = openssl_bignum_from_zval(p TSRMLS_CC);
+       Q = openssl_bignum_from_zval(q TSRMLS_CC);
+       G = openssl_bignum_from_zval(g TSRMLS_CC);
+       R = openssl_bignum_from_zval(r TSRMLS_CC);
+       S = openssl_bignum_from_zval(s TSRMLS_CC);
+       PUB = openssl_bignum_from_zval(pub TSRMLS_CC);
+
+       dsa = DSA_new();
+       dsa->p = P->bn;
+       dsa->q = Q->bn;
+       dsa->g = G->bn;
+       dsa->pub_key = PUB->bn;
+       sig.r = R->bn;
+       sig.s = S->bn;
+
+       switch (DSA_do_verify((unsigned char*)dgst, dlen, &sig, dsa)) {
+               case -1:
+               case 0:
+                       RETVAL_FALSE;
+                       break;
+               case 1:
+                       RETVAL_TRUE;
+       }
+       dsa->p = NULL;
+       dsa->q = NULL;
+       dsa->g = NULL;
+       dsa->pub_key = NULL;
+       DSA_free(dsa);
+       php_bignum_free(P, 0);
+       php_bignum_free(Q, 0);
+       php_bignum_free(G, 0);
+       php_bignum_free(R, 0);
+       php_bignum_free(S, 0);
+       php_bignum_free(PUB, 0);
+}
+/* }}} */
+
 /* SSL verification functions */
 
 #define GET_VER_OPT(name)               (stream->context && SUCCESS == 
php_stream_context_get_option(stream->context, "ssl", name, &val))
Index: php_openssl.h
===================================================================
RCS file: /repository/php-src/ext/openssl/php_openssl.h,v
retrieving revision 1.16.2.1.2.3
diff -u -p -r1.16.2.1.2.3 php_openssl.h
--- php_openssl.h       1 Jan 2007 09:36:04 -0000       1.16.2.1.2.3
+++ php_openssl.h       10 Feb 2007 04:02:05 -0000
@@ -69,6 +69,18 @@ PHP_FUNCTION(openssl_csr_export_to_file)
 PHP_FUNCTION(openssl_csr_sign);
 PHP_FUNCTION(openssl_csr_get_subject);
 PHP_FUNCTION(openssl_csr_get_public_key);
+
+PHP_FUNCTION(openssl_bignum_from_bin);
+PHP_FUNCTION(openssl_bignum_from_hex);
+PHP_FUNCTION(openssl_bignum_from_dec);
+PHP_FUNCTION(openssl_bignum_to_string);
+
+PHP_FUNCTION(openssl_dh_generate_key);
+PHP_FUNCTION(openssl_dh_compute_key);
+PHP_FUNCTION(openssl_dh_get_params);
+PHP_FUNCTION(openssl_dh_generate_parameters);
+
+PHP_FUNCTION(openssl_dsa_verify);
 #else
 
 #define phpext_openssl_ptr NULL







-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to