Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:27984 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 19506 invoked by uid 1010); 10 Feb 2007 14:17:11 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 19491 invoked from network); 10 Feb 2007 14:17:11 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 10 Feb 2007 14:17:11 -0000 Authentication-Results: pb1.pair.com smtp.mail=wez@omniti.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=wez@omniti.com; sender-id=pass; domainkeys=good Received-SPF: pass (pb1.pair.com: domain omniti.com designates 66.225.209.50 as permitted sender) DomainKey-Status: good X-DomainKeys: Ecelerity dk_validate implementing draft-delany-domainkeys-base-01 X-PHP-List-Original-Sender: wez@omniti.com X-Host-Fingerprint: 66.225.209.50 mail.omniti.com Linux 2.5 (sometimes 2.4) (4) Received: from [66.225.209.50] ([66.225.209.50:57055] helo=mail.omniti.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id ED/D0-06763-6E3DDC54 for ; Sat, 10 Feb 2007 09:17:10 -0500 X-DomainKeys: Ecelerity dk_sign implementing draft-delany-domainkeys-base-01 DomainKey-Signature: q=dns; a=rsa-sha1; c=nofws; s=test; d=omniti.com; h=Authentication-Results:Received:Mime-Version:Message-Id:Content-Type:To:Subject:From:Date:X-Mailer; b=T8ZzzxkAd7e3UlANOFqNROJd2OwC49j7vVzMbY7WF5zw2wSG4ygDC4y64M0LnSQU rs2xUiy+KgTnFspCzy70myGIfRrWbZ1tH1b/ktdTcFSjeC6rybqD8evxDaiItSoP Authentication-Results: mail.omniti.com smtp.user=wez; auth=pass (LOGIN) Received: from [68.85.222.253] ([68.85.222.253:60895] helo=[192.168.50.4]) by mail.omniti.com (ecelerity 2.1.1.12 r(14453)) with ESMTPSA (cipher=AES128-SHA) id 71/7B-17191-1E3DDC54 for ; Sat, 10 Feb 2007 09:17:08 -0500 Mime-Version: 1.0 (Apple Message framework v752.3) Message-ID: <700A466F-7822-4371-AD6A-36F6880E6368@omniti.com> Content-Type: multipart/mixed; boundary=Apple-Mail-3--463701434 To: internals@lists.php.net Date: Sat, 10 Feb 2007 09:17:06 -0500 X-Mailer: Apple Mail (2.752.3) Subject: OpenID enabling patch for OpenSSL and PHP 5 From: wez@omniti.com (Wez Furlong) --Apple-Mail-3--463701434 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed 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. --Apple-Mail-3--463701434 Content-Transfer-Encoding: 7bit Content-Type: text/plain; x-unix-mode=0644; name=openid-patch.txt Content-Disposition: attachment; filename=openid-patch.txt 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 #include #include +#include +#include #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 --Apple-Mail-3--463701434 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed --Apple-Mail-3--463701434--