]> granicus.if.org Git - php/commitdiff
Adds initial support to generate and work with ECC public key pair
authorDominic Luechinger <dol@cyon.ch>
Wed, 15 Jun 2016 20:31:42 +0000 (22:31 +0200)
committerJakub Zelenka <bukka@php.net>
Sun, 26 Jun 2016 15:15:25 +0000 (16:15 +0100)
New features:
- openssl_get_curve_names => list ECC curve names
- generate a ECC public key pair
- generate an CSR with an ECC key
- export x,y,d params of ECC public/private key

Thanks to @bukka for the review and feedback

ext/openssl/openssl.c
ext/openssl/tests/029.phpt [new file with mode: 0644]
ext/openssl/tests/ecc.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_pkey_export_basic.phpt
ext/openssl/tests/openssl_pkey_get_details_basic.phpt

index 32c27c326f9d889e3c6a5bfb729de78004e97679..1261433cae4efbfc53b900add2caccdb414bbe28 100644 (file)
@@ -118,6 +118,9 @@ enum php_openssl_cipher_type {
 
 PHP_FUNCTION(openssl_get_md_methods);
 PHP_FUNCTION(openssl_get_cipher_methods);
+#ifdef HAVE_EVP_PKEY_EC
+PHP_FUNCTION(openssl_get_curve_names);
+#endif
 
 PHP_FUNCTION(openssl_digest);
 PHP_FUNCTION(openssl_encrypt);
@@ -379,6 +382,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
        ZEND_ARG_INFO(0, aliases)
 ZEND_END_ARG_INFO()
 
+#ifdef HAVE_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)
@@ -515,6 +523,9 @@ const zend_function_entry openssl_functions[] = {
 
        PHP_FE(openssl_get_md_methods,          arginfo_openssl_get_md_methods)
        PHP_FE(openssl_get_cipher_methods,      arginfo_openssl_get_cipher_methods)
+#ifdef HAVE_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)
 
@@ -672,6 +683,10 @@ struct php_x509_request { /* {{{ */
 
        int priv_key_encrypt;
 
+#ifdef HAVE_EVP_PKEY_EC
+       int curve_name;
+#endif
+
        EVP_PKEY * priv_key;
 
        const EVP_CIPHER * priv_key_encrypt_cipher;
@@ -1035,6 +1050,18 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
        }
 
        PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
+#ifdef HAVE_EVP_PKEY_EC
+       /* set the ec group curve name */
+       req->curve_name = NID_undef;
+       if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "curve_name", sizeof("curve_name")-1)) != NULL
+               && Z_TYPE_P(item) == IS_STRING) {
+               req->curve_name = OBJ_sn2nid(Z_STRVAL_P(item));
+               if (req->curve_name == NID_undef) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(item));
+                       return FAILURE;
+               }
+       }
+#endif
 
        /* set the string mask */
        str = CONF_get_string(req->req_config, req->section_name, "string_mask");
@@ -3730,6 +3757,26 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
                                        }
                                }
                                break;
+#endif
+#ifdef HAVE_EVP_PKEY_EC
+                       case OPENSSL_KEYTYPE_EC:
+                               {
+                                       if (req->curve_name == NID_undef) {
+                                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing configuration value: 'curve_name' not set");
+                                               return NULL;
+                                       }
+                                       EC_KEY *eckey = EC_KEY_new_by_curve_name(req->curve_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, E_WARNING, "Unsupported private key type");
@@ -3805,24 +3852,30 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey)
 }
 /* }}} */
 
-#define OPENSSL_PKEY_GET_BN(_type, _name) do {                                                 \
-               if (pkey->pkey._type->_name != NULL) {                                                  \
-                       int len = BN_num_bytes(pkey->pkey._type->_name);                        \
-                       zend_string *str = zend_string_alloc(len, 0);                           \
-                       BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)ZSTR_VAL(str));      \
-                       ZSTR_VAL(str)[len] = 0;                                                                         \
-                       add_assoc_str(&_type, #_name, str);                                                     \
-               }                                                                                                                               \
-       } while (0)
-
-#define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do {                                            \
-               zval *bn;                                                                                                               \
+#define OPENSSL_GET_BN(_array, _bn, _name) do {                                                \
+               if (_bn != NULL) {                                                      \
+                       int len = BN_num_bytes(_bn);                                    \
+                       zend_string *str = zend_string_alloc(len, 0);                   \
+                       BN_bn2bin(_bn, (unsigned char*)ZSTR_VAL(str));                  \
+                       ZSTR_VAL(str)[len] = 0;                                         \
+                       add_assoc_str(&_array, #_name, str);                            \
+               }                                                                       \
+       } while (0);
+
+#define OPENSSL_PKEY_GET_BN(_type, _name) do {                                         \
+               if (pkey->pkey._type->_name != NULL) {                                  \
+                       OPENSSL_GET_BN(_type, pkey->pkey._type->_name, _name);          \
+               }                                                                       \
+       } while (0);
+
+#define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do {                                    \
+               zval *bn;                                                               \
                if ((bn = zend_hash_str_find(_ht, #_name, sizeof(#_name)-1)) != NULL && \
-                               Z_TYPE_P(bn) == IS_STRING) {                                                    \
-                       _type->_name = BN_bin2bn(                                                                       \
-                               (unsigned char*)Z_STRVAL_P(bn),                                                 \
-                               (int)Z_STRLEN_P(bn), NULL);                                                                     \
-           }                                                               \
+                               Z_TYPE_P(bn) == IS_STRING) {                            \
+                       _type->_name = BN_bin2bn(                                       \
+                               (unsigned char*)Z_STRVAL_P(bn),                         \
+                               (int)Z_STRLEN_P(bn), NULL);                             \
+               }                                                                               \
        } while (0);
 
 /* {{{ php_openssl_pkey_init_dsa */
@@ -3968,6 +4021,97 @@ PHP_FUNCTION(openssl_pkey_new)
                                php_openssl_store_errors();
                        }
                        RETURN_FALSE;
+#ifdef HAVE_EVP_PKEY_EC
+               } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ec", sizeof("ec") - 1)) != NULL &&
+                       Z_TYPE_P(data) == IS_ARRAY) {
+                       pkey = EVP_PKEY_new();
+                       EC_KEY *eckey = NULL;
+                       EC_GROUP *group = NULL;
+                       EC_POINT *pnt = NULL;
+                       const BIGNUM *d;
+                       if (pkey) {
+                               eckey = EC_KEY_new();
+                               if (eckey) {
+                                       EC_GROUP *group = NULL;
+                                       zval *bn;
+                                       zval *x;
+                                       zval *y;
+
+                                       if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1)) != NULL
+                                               && Z_TYPE_P(bn) == IS_STRING) {
+                                               int nid = OBJ_sn2nid(Z_STRVAL_P(bn));
+                                               if (nid != NID_undef) {
+                                                       group = EC_GROUP_new_by_curve_name(nid);
+                                                       EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+                                                       EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+                                                       EC_KEY_set_group(eckey, group);
+                                               }
+                                       }
+
+                                       if (group == NULL) {
+                                               php_error_docref(NULL, E_WARNING, "Unknown curve_name");
+                                               goto clean_exit;
+                                       }
+
+                                       // The public key 'pnt' can be calculated from 'd' or is defined by 'x' and 'y'
+                                       if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "d", sizeof("d") - 1)) != NULL
+                                               && Z_TYPE_P(bn) == IS_STRING) {
+                                               d = BN_bin2bn((unsigned char*) Z_STRVAL_P(bn), Z_STRLEN_P(bn), NULL);
+                                               if (!EC_KEY_set_private_key(eckey, d)) {
+                                                       goto clean_exit;
+                                               }
+                                               // Calculate the public key by multiplying the Point Q with the public key
+                                               // P = d * Q
+                                               pnt = EC_POINT_new(group);
+                                               if (!EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) {
+                                                       goto clean_exit;
+                                               }
+                                       } else if ((x = zend_hash_str_find(Z_ARRVAL_P(data), "x", sizeof("x") - 1)) != NULL
+                                               && Z_TYPE_P(x) == IS_STRING
+                                               && (y = zend_hash_str_find(Z_ARRVAL_P(data), "y", sizeof("y") - 1)) != NULL
+                                               && Z_TYPE_P(y) == IS_STRING) {
+                                               pnt = EC_POINT_new(group);
+                                               if (pnt == NULL) {
+                                                       goto clean_exit;
+                                               }
+                                               if (!EC_POINT_set_affine_coordinates_GFp(group, pnt, BN_bin2bn((unsigned char*) Z_STRVAL_P(x), Z_STRLEN_P(x), NULL),
+                                                       BN_bin2bn((unsigned char*) Z_STRVAL_P(y), Z_STRLEN_P(y), NULL), NULL)) {
+                                                       goto clean_exit;
+                                               }
+                                       }
+
+                                       EC_GROUP_free(group);
+
+                                       if (pnt != NULL) {
+                                               if (!EC_KEY_set_public_key(eckey, pnt)) {
+                                                       goto clean_exit;
+                                               }
+                                               EC_POINT_free(pnt);
+                                       }
+
+                                       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_RES(zend_register_resource(pkey, le_key));
+                                       }
+                               }
+                       }
+clean_exit:
+                       if (pnt != NULL) {
+                               EC_POINT_free(pnt);
+                       }
+                       if (group != NULL) {
+                               EC_GROUP_free(group);
+                       }
+                       if (eckey != NULL) {
+                               EC_KEY_free(eckey);
+                       }
+                       if (pkey != NULL) {
+                               EVP_PKEY_free(pkey);
+                       }
+                       RETURN_FALSE;
+#endif
                }
        }
 
@@ -4308,8 +4452,12 @@ PHP_FUNCTION(openssl_pkey_get_details)
                                ASN1_OBJECT *obj;
                                // openssl recommends a buffer length of 80
                                char oir_buf[80];
+                               const EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey);
+                               BIGNUM *x = BN_new();
+                               BIGNUM *y = BN_new();
+                               const BIGNUM *d;
 
-                               ec_group = EC_KEY_get0_group(EVP_PKEY_get1_EC_KEY(pkey));
+                               ec_group = EC_KEY_get0_group(ec_key);
 
                                // Curve nid (numerical identifier) used for ASN1 mapping
                                nid = EC_GROUP_get_curve_name(ec_group);
@@ -4327,11 +4475,25 @@ PHP_FUNCTION(openssl_pkey_get_details)
                                obj = OBJ_nid2obj(nid);
                                if (obj != NULL) {
                                        int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
-                                       add_assoc_stringl(&ec, "curve_oid", (char*)oir_buf, oir_len);
+                                       add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len);
                                        ASN1_OBJECT_free(obj);
                                }
 
+                               const EC_POINT *pub = EC_KEY_get0_public_key(ec_key);
+
+                               if (EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x, y, NULL)) {
+                                       OPENSSL_GET_BN(ec, x, x);
+                                       OPENSSL_GET_BN(ec, y, y);
+                               }
+
+                               if ((d = EC_KEY_get0_private_key(pkey->pkey.ec)) != NULL) {
+                                       OPENSSL_GET_BN(ec, d, d);
+                               }
+
                                add_assoc_zval(return_value, "ec", &ec);
+
+                               BN_free(x);
+                               BN_free(y);
                        }
                        break;
 #endif
@@ -5540,6 +5702,33 @@ PHP_FUNCTION(openssl_get_cipher_methods)
 }
 /* }}} */
 
+/* {{{ proto array openssl_get_curve_names()
+   Return array of available elliptic curves */
+#ifdef HAVE_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(sizeof(EC_builtin_curve) * len);
+       if (!EC_get_builtin_curves(curves, len)) {
+               RETURN_FALSE;
+       }
+
+       for (i = 0; i < len; i++) {
+               sname = OBJ_nid2sn(curves[i].nid);
+               if (sname != NULL) {
+                       add_next_index_string(return_value, sname);
+               }
+       }
+       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)
diff --git a/ext/openssl/tests/029.phpt b/ext/openssl/tests/029.phpt
new file mode 100644 (file)
index 0000000..cf43e0e
--- /dev/null
@@ -0,0 +1,254 @@
+--TEST--
+openssl_pkey_new() with EC key
+--SKIPIF--
+<?php
+if (!extension_loaded("openssl")) die("skip");
+if (!defined("OPENSSL_KEYTYPE_EC")) die("skip no EC available");
+?>
+--FILE--
+<?php
+$key = openssl_pkey_get_private("file://" . dirname(__FILE__) . "/private_ec.key");
+
+$details = openssl_pkey_get_details($key);
+print_r($details);
+
+echo "Use details an create the same key pair\n";
+$key2 = openssl_pkey_new($details);
+$details2 = openssl_pkey_get_details($key2);
+print_r($details2);
+var_dump(array_diff($details["ec"], $details2["ec"]));
+
+echo "Missing 'd' parameter (private key part) => no private key informations\n";
+$detailsCopy3 = $details;
+unset($detailsCopy3["ec"]["d"]);
+$key3 = openssl_pkey_new($detailsCopy3);
+$details3 = openssl_pkey_get_details($key3);
+print_r($details3);
+var_dump(array_diff($details["ec"], $details3["ec"]));
+$privateKey3 = openssl_pkey_get_private($key3);
+var_dump($privateKey3);
+$publicKey3 = openssl_pkey_get_public($key3);
+var_dump($publicKey3);
+var_dump($details["key"] === $details3["key"]);
+
+echo "Missing 'x' parameter will not change the details. The public key is calculated from the private key 'd'\n";
+$detailsCopy4 = $details;
+unset($detailsCopy4["ec"]["x"]);
+$key4 = openssl_pkey_new($detailsCopy4);
+$details4 = openssl_pkey_get_details($key4);
+print_r($details4);
+var_dump(array_diff($details["ec"], $details4["ec"]));
+
+echo "Missing 'y' parameter will not change the details. The public key is calculated from the private key 'd'\n";
+$detailsCopy5 = $details;
+unset($detailsCopy5["ec"]["y"]);
+$key5 = openssl_pkey_new($detailsCopy5);
+$details5 = openssl_pkey_get_details($key5);
+print_r($details5);
+var_dump(array_diff($details["ec"], $details5["ec"]));
+
+echo "Missing 'd' and 'x' parameters will generate a new public key pair\n";
+$detailsCopy6 = $details;
+unset($detailsCopy6["ec"]["d"]);
+unset($detailsCopy6["ec"]["x"]);
+$key6 = openssl_pkey_new($detailsCopy6);
+$details6 = openssl_pkey_get_details($key6);
+print_r($details6);
+var_dump(array_diff($details["ec"], $details6["ec"]));
+
+echo "Missing 'd' and 'y' parameters will generate a new public key pair\n";
+$detailsCopy7 = $details;
+unset($detailsCopy7["ec"]["d"]);
+unset($detailsCopy7["ec"]["y"]);
+$key7 = openssl_pkey_new($detailsCopy7);
+$details7 = openssl_pkey_get_details($key7);
+print_r($details7);
+var_dump(array_diff($details["ec"], $details7["ec"]));
+
+// Tests vectors from http://point-at-infinity.org/ecc/nisttv
+echo "Create a private key from scratch 1\n";
+$detailsFromScratch8 = array(
+       "ec" => array(
+               "curve_name" => "prime256v1",
+               "d" => "\1",
+       ),
+);
+$key8 = openssl_pkey_new($detailsFromScratch8);
+$details8 = openssl_pkey_get_details($key8);
+var_dump(strtoupper(bin2hex($details8["ec"]["x"])) === "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
+var_dump(strtoupper(bin2hex($details8["ec"]["y"])) === "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
+
+echo "Create a private key from scratch 2\n";
+$detailsFromScratch9 = array(
+       "ec" => array(
+               "curve_name" => "prime192v1",
+               "d" => hex2bin("7FFFFFFFFE0000007FFFFE003FFFFFE0007FFF1FFFFE0800"),
+       ),
+);
+$key9 = openssl_pkey_new($detailsFromScratch9);
+$details9 = openssl_pkey_get_details($key9);
+var_dump(strtoupper(bin2hex($details9["ec"]["x"])) === "45DAF0A306121BDB3B82E734CB44FDF65C9930F0E4FD2068");
+var_dump(strtoupper(bin2hex($details9["ec"]["y"])) === "F039FACE58EB7DE34E3374ADB28DF81F019C4548BAA75B64");
+?>
+--EXPECTF--
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+Use details an create the same key pair
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+array(0) {
+}
+Missing 'd' parameter (private key part) => no private key informations
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+        )
+
+    [type] => 3
+)
+array(1) {
+  ["d"]=>
+  string(32) "%a"
+}
+
+Warning: openssl_pkey_get_private(): supplied key param is a public key in %s on line %d
+bool(false)
+resource(%d) of type (OpenSSL key)
+bool(true)
+Missing 'x' parameter will not change the details. The public key is calculated from the private key 'd'
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+array(0) {
+}
+Missing 'y' parameter will not change the details. The public key is calculated from the private key 'd'
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+array(0) {
+}
+Missing 'd' and 'x' parameters will generate a new public key pair
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+array(3) {
+  ["x"]=>
+  string(32) "%a"
+  ["y"]=>
+  string(32) "%a"
+  ["d"]=>
+  string(32) "%a"
+}
+Missing 'd' and 'y' parameters will generate a new public key pair
+Array
+(
+    [bits] => 256
+    [key] => -----BEGIN PUBLIC KEY-----%a
+-----END PUBLIC KEY-----
+
+    [ec] => Array
+        (
+            [curve_name] => prime256v1
+            [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
+        )
+
+    [type] => 3
+)
+array(3) {
+  ["x"]=>
+  string(32) "%a"
+  ["y"]=>
+  string(32) "%a"
+  ["d"]=>
+  string(32) "%a"
+}
+Create a private key from scratch 1
+bool(true)
+bool(true)
+Create a private key from scratch 2
+bool(true)
+bool(true)
diff --git a/ext/openssl/tests/ecc.phpt b/ext/openssl/tests/ecc.phpt
new file mode 100644 (file)
index 0000000..5df0130
--- /dev/null
@@ -0,0 +1,110 @@
+--TEST--
+openssl_*() with OPENSSL_KEYTYPE_EC
+--SKIPIF--
+<?php if (!extension_loaded("openssl") && !defined("OPENSSL_KEYTYPE_EC")) print "skip"; ?>
+--FILE--
+<?php
+$args = array(
+       "curve_name" => "secp384r1",
+       "private_key_type" => OPENSSL_KEYTYPE_EC,
+);
+echo "Testing openssl_pkey_new\n";
+$key1 = openssl_pkey_new($args);
+var_dump($key1);
+
+$argsFailed = array(
+       "curve_name" => "invalid_cuve_name",
+       "private_key_type" => OPENSSL_KEYTYPE_EC,
+);
+
+$keyFailed = openssl_pkey_new($argsFailed);
+var_dump($keyFailed);
+
+$d1 = openssl_pkey_get_details($key1);
+var_dump($d1["bits"]);
+var_dump(strlen($d1["key"]));
+var_dump($d1["ec"]["curve_name"]);
+var_dump($d1["type"] == OPENSSL_KEYTYPE_EC);
+
+$key2 = openssl_pkey_new($d1);
+var_dump($key2);
+
+$d2 = openssl_pkey_get_details($key2);
+// Compare array
+var_dump($d1 === $d2);
+
+$dn = array(
+       "countryName" => "BR",
+       "stateOrProvinceName" => "Rio Grande do Sul",
+       "localityName" => "Porto Alegre",
+       "commonName" => "Henrique do N. Angelo",
+       "emailAddress" => "hnangelo@php.net"
+);
+
+// openssl_csr_new creates a new public key pair if the key argument is null
+echo "Testing openssl_csr_new with key generation\n";
+$keyGenerate = null;
+var_dump($keyGenerate);
+$csr = openssl_csr_new($dn, $keyGenerate, $args);
+
+var_dump($keyGenerate);
+
+$args["digest_alg"] = "sha1";
+echo "Testing openssl_csr_new with existing ecc key\n";
+$csr = openssl_csr_new($dn, $key1, $args);
+var_dump($csr);
+
+$pubkey1 = openssl_pkey_get_details(openssl_csr_get_public_key($csr));
+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);
+
+echo "Testing openssl_x509_check_private_key\n";
+var_dump(openssl_x509_check_private_key($x509, $key1));
+
+$key3 = openssl_pkey_new($args);
+var_dump(openssl_x509_check_private_key($x509, $key3));
+
+echo "Testing openssl_get_curve_names\n";
+$curve_names = openssl_get_curve_names();
+
+var_dump(is_array($curve_names));
+
+foreach ($curve_names as $curve_name) {
+       if ("secp384r1" === $curve_name) {
+               echo "Found secp384r1 in curve names\n";
+       }
+}
+?>
+--EXPECTF--
+Testing openssl_pkey_new
+resource(%d) of type (OpenSSL key)
+
+Warning: openssl_pkey_new(): Unknown elliptic curve (short) name invalid_cuve_name in %s on line %d
+bool(false)
+int(384)
+int(215)
+string(9) "secp384r1"
+bool(true)
+resource(%d) of type (OpenSSL key)
+bool(true)
+Testing openssl_csr_new with key generation
+NULL
+resource(%d) of type (OpenSSL key)
+Testing openssl_csr_new with existing ecc key
+resource(%d) of type (OpenSSL X.509 CSR)
+bool(false)
+array(1) {
+  ["d"]=>
+  string(48) "%a"
+}
+resource(%d) of type (OpenSSL X.509)
+Testing openssl_x509_check_private_key
+bool(true)
+bool(false)
+Testing openssl_get_curve_names
+bool(true)
+Found secp384r1 in curve names
index d229d6b13529bd4c9308452bf035a68f8e285997..530158d7d94f0106f865c7d32227b2c4a2a743ab 100644 (file)
@@ -2,8 +2,10 @@
 openssl_pkey_export() with EC key
 --SKIPIF--
 <?php
-if (!extension_loaded("openssl")) die("skip");
-if (!defined('OPENSSL_KEYTYPE_EC')) die("skip no EC available");
+if (!extension_loaded("openssl"))
+    die("skip");
+if (!defined('OPENSSL_KEYTYPE_EC'))
+    die("skip no EC available");
 ?>
 --FILE--
 <?php
@@ -28,9 +30,9 @@ var_dump(OPENSSL_KEYTYPE_EC === $details['type']);
 // Read public key
 $pKey = openssl_pkey_get_public('file://' . dirname(__FILE__) . '/public_ec.key');
 var_dump($pKey);
-// The details are the same for a public or private key
-var_dump($details === openssl_pkey_get_details($pKey));
-
+// The details are the same for a public or private key, expect the private key parameter 'd
+$detailsPKey = openssl_pkey_get_details($pKey);
+var_dump(array_diff_assoc($details['ec'], $detailsPKey['ec']));
 
 // Export to file
 $tempname = tempnam(sys_get_temp_dir(), 'openssl_ec');
@@ -40,7 +42,6 @@ var_dump(OPENSSL_KEYTYPE_EC === $details['type']);
 
 // Clean the temporary file
 @unlink($tempname);
-
 ?>
 --EXPECTF--
 resource(%d) of type (OpenSSL key)
@@ -49,6 +50,9 @@ bool(true)
 bool(true)
 bool(true)
 resource(%d) of type (OpenSSL key)
-bool(true)
+array(1) {
+  ["d"]=>
+  string(32) "%a"
+}
 bool(true)
 bool(true)
index 8e0cef46c07cf7ce2f5208a7b642ae5e9762b005..3c239af2a2b5b10d1c3c2199c83df1b901484e2b 100644 (file)
@@ -3,11 +3,11 @@ openssl_pkey_get_details() with EC key
 --SKIPIF--
 <?php
 if (!extension_loaded("openssl")) die("skip");
-if (!defined('OPENSSL_KEYTYPE_EC')) die("skip no EC available");
+if (!defined("OPENSSL_KEYTYPE_EC")) die("skip no EC available");
 ?>
 --FILE--
 <?php
-$key = openssl_pkey_get_private('file://' . dirname(__FILE__) . '/private_ec.key');
+$key = openssl_pkey_get_private("file://" . dirname(__FILE__) . "/private_ec.key");
 
 print_r(openssl_pkey_get_details($key));
 ?>
@@ -22,6 +22,9 @@ Array
         (
             [curve_name] => prime256v1
             [curve_oid] => 1.2.840.10045.3.1.7
+            [x] => %a
+            [y] => %a
+            [d] => %a
         )
 
     [type] => 3