Over the weekend I went ahead and created a patch to implement support for SPKAC keys for the old/new KEYGEN element within the HTML5 spec. According to feature requests at bugs.php.net I came accross this existing request: https://bugs.php.net/bug.php?id=38917
I have filed a patch under this feature request but figured I would make sure it doesn't get over looked as I am sure there are a few developers out there (myself included) that would like to see this upstream. A little background. The patch implements the SPKAC support the extisting OpenSSL extension has been missing. I am attatching the patch as well as providing a simple test case of the functions it implements. Any feedback is appreciated. $key = openssl_pkey_new(array('digest_alg' => 'sha1', 'private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048)); if (function_exists('openssl_spki_new')){ $spki = openssl_spki_new($key, 'password'); echo $spki.'\n\r'; } if (function_exists('openssl_spki_verify')){ echo (empty($_POST['keygen'])) ? openssl_spki_verify(preg_replace('/SPKAC=/', '', $spki)).'\n\r' : openssl_spki_verify($_POST['keygen']); } if (function_exists('openssl_spki_export')){ echo (empty($_POST['keygen'])) ? openssl_spki_export(preg_replace('/SPKAC=/', '', $spki)).'\n\r' : openssl_spki_export($_POST['keygen']); } The attatched patch should be pretty seamless and has been tested again PHP-5.3.8 and OpenSSL-1.0.0e. -- Jas
diff -Naur php-5.3.8/ext/openssl/openssl.c php-5.3.8-patched/ext/openssl/openssl.c --- php-5.3.8/ext/openssl/openssl.c 2011-07-25 05:42:53.000000000 -0600 +++ php-5.3.8-patched/ext/openssl/openssl.c 2011-12-06 04:24:32.403578621 -0700 @@ -372,11 +372,30 @@ ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(1, result_is_strong) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 0) + ZEND_ARG_INFO(0, privkey) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, spki_hash) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ openssl_functions[] */ const zend_function_entry openssl_functions[] = { +/* spki functions */ + PHP_FE(openssl_spki_new, arginfo_openssl_spki_new) + PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify) + PHP_FE(openssl_spki_export, arginfo_openssl_spki_export) + /* public/private key functions */ PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free) PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new) @@ -1252,6 +1271,151 @@ } /* }}} */ +/* {{{ proto string openssl_spki_new(mixed priv_key, string password) + Creates new private key (or uses existing) and creates a new spki cert + outputting results to var */ +PHP_FUNCTION(openssl_spki_new) +{ + zval * zout, * zpkey = NULL; + EVP_PKEY * pkey = NULL; + NETSCAPE_SPKI *spki=NULL; + char * password, * spkstr; + long keyresource; + const char *spkac = "SPKAC="; + + RETVAL_FALSE; + + zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|s", &zpkey, &password, &zout); + + pkey = php_openssl_evp_from_zval(&zpkey, 0, password, 1, &keyresource TSRMLS_CC); + + if (pkey == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 1"); + goto cleanup; + } + + if ((spki = NETSCAPE_SPKI_new()) == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get spki interface"); + goto cleanup; + } + + if (password) { + ASN1_STRING_set(spki->spkac->challenge, password, (int)strlen(password)); + } + + if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get public key from spki"); + goto cleanup; + } + + if (!NETSCAPE_SPKI_sign(spki, pkey, EVP_md5())) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot sign public key with spki"); + goto cleanup; + } + + spkstr = NETSCAPE_SPKI_b64_encode(spki); + + char * s = malloc(snprintf(NULL, 0, "%s%s", spkac, spkstr) + 1); + sprintf(s, "%s%s", spkac, spkstr); + + RETVAL_STRINGL(s, strlen(s), 0); + +cleanup: + if (keyresource == -1 && pkey) { + NETSCAPE_SPKI_free(spki); + EVP_PKEY_free(pkey); + } +} +/* }}} */ + +/* {{{ proto bool openssl_spki_verify(string spki) + Verifies spki returns boolean */ +PHP_FUNCTION(openssl_spki_verify) +{ + int spkstr_len, i, x=0; + char *spkstr = NULL; + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "missing argument 1"); + goto cleanup; + } + + if (!spkstr) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "spki not found"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr, -1); + if (!spki) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "error decoding spki"); + goto cleanup; + } + + pkey = NETSCAPE_SPKI_get_pubkey(spki); + if (pkey == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting public key from spki"); + goto cleanup; + } + + i = NETSCAPE_SPKI_verify(spki, pkey); + + if (i > 0) { + x = 1; + } else { + x = 0; + } + goto cleanup; + +cleanup: + EVP_PKEY_free(pkey); + RETVAL_BOOL(x); +} +/* }}} */ + +/* {{{ proto string openssl_spki_export(string spki) + Exports public key from existing spki to var */ +PHP_FUNCTION(openssl_spki_export) +{ + int spkstr_len; + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE); + char *spkstr; + + RETVAL_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "missing argument 1"); + goto cleanup; + } + + if (!spkstr) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "spki not found"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr, strlen(spkstr)); + if (!spki) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "error decoding spki"); + goto cleanup; + } + + pkey = NETSCAPE_SPKI_get_pubkey(spki); + if (!pkey) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting public key from spki"); + goto cleanup; + } + + PEM_write_bio_PUBKEY(out, pkey); + +cleanup: + NETSCAPE_SPKI_free(spki); + EVP_PKEY_free(pkey); +} +/* }}} */ + /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true]) Exports a CERT to file or a var */ PHP_FUNCTION(openssl_x509_export) diff -Naur php-5.3.8/ext/openssl/php_openssl.h php-5.3.8-patched/ext/openssl/php_openssl.h --- php-5.3.8/ext/openssl/php_openssl.h 2010-12-31 19:19:59.000000000 -0700 +++ php-5.3.8-patched/ext/openssl/php_openssl.h 2011-12-06 04:24:56.581276358 -0700 @@ -74,6 +74,10 @@ PHP_FUNCTION(openssl_csr_sign); PHP_FUNCTION(openssl_csr_get_subject); PHP_FUNCTION(openssl_csr_get_public_key); + +PHP_FUNCTION(openssl_spki_new); +PHP_FUNCTION(openssl_spki_verify); +PHP_FUNCTION(openssl_spki_export); #else #define phpext_openssl_ptr NULL
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php