php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #61204
Patch php-openssl-ec.patch revision 2012-02-28 16:58 UTC by manuel at mausz dot at

Patch php-openssl-ec.patch for OpenSSL related Bug #61204

Patch version 2012-02-28 16:58 UTC

Return to Bug #61204 | Download this patch
Patch Revisions:

Developer: manuel@mausz.at

Index: ext/openssl/tests/026.phpt
===================================================================
--- ext/openssl/tests/026.phpt	(revision 0)
+++ ext/openssl/tests/026.phpt	(revision 0)
@@ -0,0 +1,84 @@
+--TEST--
+openssl_*() with OPENSSL_KEYTYPE_EC
+--SKIPIF--
+<?php if (!extension_loaded("openssl") && !defined("OPENSSL_KEYTYPE_EC")) print "skip"; ?>
+--FILE--
+<?php
+
+$args = array(
+  "ec_group_name" => "secp384r1",
+  "private_key_type" => OPENSSL_KEYTYPE_EC,
+);
+
+$key1 = openssl_pkey_new($args);
+var_dump($key1);
+
+$d1 = openssl_pkey_get_details($key1);
+var_dump($d1["bits"]);
+var_dump(strlen($d1["key"]));
+var_dump($d1["ec"]["group_name"]);
+var_dump(strlen($d1["ec"]["priv_key"]));
+var_dump(strlen($d1["ec"]["pub_key"]));
+var_dump($d1["type"] == OPENSSL_KEYTYPE_EC);
+
+$key2 = openssl_pkey_new($d1);
+var_dump($key2);
+
+$d2 = openssl_pkey_get_details($key2);
+var_dump(array_diff_assoc($d2, $d1));
+var_dump(array_diff_assoc($d2["ec"], $d1["ec"]));
+
+
+$dn = array(
+  "countryName" => "BR",
+  "stateOrProvinceName" => "Rio Grande do Sul",
+  "localityName" => "Porto Alegre",
+  "commonName" => "Henrique do N. Angelo",
+  "emailAddress" => "hnangelo@php.net"
+);
+$csr = openssl_csr_new($dn, $key1, $args);
+
+$args["digest_alg"] = "sha1";
+$csr = openssl_csr_new($dn, $key1, $args);
+var_dump($csr);
+
+$pubkey1 = openssl_pkey_get_details(openssl_csr_get_public_key($csr));
+var_dump(array_diff_assoc($d1, $pubkey1));
+var_dump(isset($pubkey1["ec"]["priv_key"]));
+unset($d1["ec"]["priv_key"]);
+var_dump(array_diff($d1["ec"], $pubkey1["ec"]));
+
+$x509 = openssl_csr_sign($csr, null, $key1, 365, $args);
+var_dump($x509);
+
+
+var_dump(openssl_x509_check_private_key($x509, $key1));
+
+$key3 = openssl_pkey_new($args);
+var_dump(openssl_x509_check_private_key($x509, $key3));
+
+?>
+--EXPECTF--
+resource(%d) of type (OpenSSL key)
+int(384)
+int(215)
+string(9) "secp384r1"
+int(48)
+int(97)
+bool(true)
+resource(%d) of type (OpenSSL key)
+array(0) {
+}
+array(0) {
+}
+
+Warning: openssl_csr_new(): Error signing request in %s on line %d
+resource(%d) of type (OpenSSL X.509 CSR)
+array(0) {
+}
+bool(false)
+array(0) {
+}
+resource(%d) of type (OpenSSL X.509)
+bool(true)
+bool(false)
Index: ext/openssl/openssl.c
===================================================================
--- ext/openssl/openssl.c	(revision 323630)
+++ ext/openssl/openssl.c	(working copy)
@@ -98,6 +98,9 @@
 
 PHP_FUNCTION(openssl_get_md_methods);
 PHP_FUNCTION(openssl_get_cipher_methods);
+#ifdef EVP_PKEY_EC
+PHP_FUNCTION(openssl_get_curve_names);
+#endif
 
 PHP_FUNCTION(openssl_digest);
 PHP_FUNCTION(openssl_encrypt);
@@ -340,6 +343,11 @@
     ZEND_ARG_INFO(0, aliases)
 ZEND_END_ARG_INFO()
 
+#ifdef EVP_PKEY_EC
+ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_curve_names, 0, 0, 0)
+ZEND_END_ARG_INFO()
+#endif
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
     ZEND_ARG_INFO(0, data)
     ZEND_ARG_INFO(0, method)
@@ -437,6 +445,9 @@
 
 	PHP_FE(openssl_get_md_methods,		arginfo_openssl_get_md_methods)
 	PHP_FE(openssl_get_cipher_methods,	arginfo_openssl_get_cipher_methods)
+#ifdef EVP_PKEY_EC
+	PHP_FE(openssl_get_curve_names,		arginfo_openssl_get_curve_names)
+#endif
 
 	PHP_FE(openssl_dh_compute_key,      arginfo_openssl_dh_compute_key)
 
@@ -535,6 +546,10 @@
 
 	int priv_key_encrypt;
 
+#ifdef EVP_PKEY_EC
+	int ec_group_name;
+#endif
+
 	EVP_PKEY * priv_key;
 
     const EVP_CIPHER * priv_key_encrypt_cipher;
@@ -858,6 +873,18 @@
 	}
 
 	PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
+
+#ifdef EVP_PKEY_EC
+	/* set the ec group curve name */
+	req->ec_group_name = 0;
+	if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "ec_group_name", sizeof("ec_group_name"), (void**)&item) == SUCCESS) {
+		req->ec_group_name = OBJ_sn2nid(Z_STRVAL_PP(item));
+		if (req->ec_group_name == NID_undef) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown elliptic curve group (short) name %s", Z_STRVAL_PP(item));
+			return FAILURE;
+		}
+	}
+#endif
 	
 	return SUCCESS;
 }
@@ -2843,6 +2870,26 @@
 				}
 				break;
 #endif
+#ifdef EVP_PKEY_EC
+			case OPENSSL_KEYTYPE_EC:
+				{
+					if (req->ec_group_name == NID_undef) {
+						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing configuration value: 'ec_group_name' not set");
+						return NULL;
+					}
+					EC_KEY *eckey = EC_KEY_new_by_curve_name(req->ec_group_name);
+					if (eckey) {
+						EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+						if (EC_KEY_generate_key(eckey) &&
+						        EVP_PKEY_assign_EC_KEY(req->priv_key, eckey)) {
+							return_val = req->priv_key;
+						} else {
+							EC_KEY_free(eckey);
+						}
+					}
+				}
+				break;
+#endif
 			default:
 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type");
 		}
@@ -2898,6 +2945,14 @@
 			}
 			break;
 #endif
+#ifdef EVP_PKEY_EC
+		case EVP_PKEY_EC:
+			assert(pkey->pkey.ec != NULL);
+			if (EC_KEY_get0_private_key(pkey->pkey.ec) == NULL) {
+				return 0;
+			}
+			break;
+#endif
 		default:
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
 			break;
@@ -3015,6 +3070,56 @@
 			}
 			RETURN_FALSE;
 		}
+#ifdef EVP_PKEY_EC
+		else if (zend_hash_find(Z_ARRVAL_P(args), "ec", sizeof("ec"), (void**)&data) == SUCCESS &&
+		           Z_TYPE_PP(data) == IS_ARRAY) {
+		    pkey = EVP_PKEY_new();
+		    if (pkey) {
+				EC_KEY *eckey = EC_KEY_new();
+				if (eckey) {
+					EC_GROUP *group = NULL;
+					zval **bn;
+
+					if (zend_hash_find(Z_ARRVAL_PP(data), "group_name", sizeof("group_name"), (void**)&bn) == SUCCESS &&
+							Z_TYPE_PP(bn) == IS_STRING) {
+						int name = OBJ_sn2nid(Z_STRVAL_PP(bn));
+						if (name != NID_undef) {
+							group = EC_GROUP_new_by_curve_name(name);
+							EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+							EC_KEY_set_group(eckey, group);
+						}
+					}
+
+					if (zend_hash_find(Z_ARRVAL_PP(data), "priv_key", sizeof("priv_key"), (void**)&bn) == SUCCESS &&
+							Z_TYPE_PP(bn) == IS_STRING) {
+						EC_KEY_set_private_key(eckey, BN_bin2bn((unsigned char*)Z_STRVAL_PP(bn), Z_STRLEN_PP(bn), NULL));
+					}
+
+					if (zend_hash_find(Z_ARRVAL_PP(data), "pub_key", sizeof("pub_key"), (void**)&bn) == SUCCESS &&
+							Z_TYPE_PP(bn) == IS_STRING && group != NULL) {
+						EC_POINT *pub_key = EC_POINT_new(group);
+						EC_POINT_oct2point(group, pub_key, (unsigned char*)Z_STRVAL_PP(bn), Z_STRLEN_PP(bn), NULL);
+						EC_KEY_set_public_key(eckey, pub_key);
+					}
+
+					/* we don't need that any longer. key holds it's own copy */
+					if (group != NULL) {
+						EC_GROUP_free(group);
+					}
+
+					if (!EC_KEY_check_key(eckey)) {
+						EC_KEY_generate_key(eckey);
+					}
+					if (EC_KEY_check_key(eckey) && EVP_PKEY_assign_EC_KEY(pkey, eckey)) {
+						RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+					}
+					EC_KEY_free(eckey);
+				}
+				EVP_PKEY_free(pkey);
+			}
+			RETURN_FALSE;
+		}
+#endif
 	} 
 
 	PHP_SSL_REQ_INIT(&req);
@@ -3299,6 +3404,38 @@
 #ifdef EVP_PKEY_EC 
 		case EVP_PKEY_EC:
 			ktype = OPENSSL_KEYTYPE_EC;
+			if (pkey->pkey.ec != NULL) {
+				zval *ec;
+
+				ALLOC_INIT_ZVAL(ec);
+				array_init(ec);
+
+				const EC_GROUP *group = EC_KEY_get0_group(pkey->pkey.ec);
+				int name = (group != NULL) ? EC_GROUP_get_curve_name(group) : 0;
+				if (name) {
+					add_assoc_string(ec, "group_name", estrdup(OBJ_nid2sn(name)), 0);
+				}
+
+				const BIGNUM *key = EC_KEY_get0_private_key(pkey->pkey.ec);
+				if (key != NULL) {
+					int len = BN_num_bytes(key);
+					char *str = emalloc(len + 1);
+					BN_bn2bin(key, (unsigned char*)str);
+					str[len] = 0;
+					add_assoc_stringl(ec, "priv_key", str, len, 0);
+				}
+
+				const EC_POINT *pub_key = EC_KEY_get0_public_key(pkey->pkey.ec);
+				if (group != NULL && pub_key != NULL) {
+					int len = EC_POINT_point2oct(group, pub_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
+					char *str = emalloc(len + 1);
+					EC_POINT_point2oct(group, pub_key, POINT_CONVERSION_UNCOMPRESSED, str, len, NULL);
+					str[len] = 0;
+					add_assoc_stringl(ec, "pub_key", str, len, 0);
+				}
+
+				add_assoc_zval(return_value, "ec", ec);
+			}
 			break;
 #endif
 		default:
@@ -4609,6 +4746,34 @@
 }
 /* }}} */
 
+/* {{{ proto array openssl_get_curve_names([bool aliases = false])
+   Return array of available elliptic curves */
+#ifdef EVP_PKEY_EC
+PHP_FUNCTION(openssl_get_curve_names)
+{
+	EC_builtin_curve *curves = NULL;
+	const char *sname;
+	int i;
+
+	array_init(return_value);
+	size_t len = EC_get_builtin_curves(NULL, 0);
+	curves = emalloc((int)(sizeof(EC_builtin_curve) * len));
+	if (!EC_get_builtin_curves(curves, len)) {
+		return;
+	}
+
+	for(i = 0; i < len; i++)
+	{
+		sname = OBJ_nid2sn(curves[i].nid);
+		if (sname == NULL)
+			continue;
+		add_next_index_string(return_value, sname, 1);
+	}
+	efree(curves);
+}
+#endif
+/* }}} */
+
 /* {{{ 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)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 01:01:28 2024 UTC