背景:

    linux已通过源码安装openssl(假设安装目录为:/usr/local/openssl),目前php安装时所指定的openssl未能支持国密算法,若希望php也能实现国密算法,则编译安装php时,需指定gmssl(而非openssl)。

安装GmSSL:

    1、下载源代码(GmSSL-master.zip),解压缩至当前工作目录

# unzip GmSSL-master.zip

    2、编译与安装

# ./config --prefix=/usr/local/gmssl --openssldir=/usr/local/gmssl/ssl
# make
# make test
# make install

    若在安装过程中出现:pod2man: command not found 错误信息,请使用whereis pod2man命令查看是否安装了pod2man,否则执行yum-yinstall perl-podlators进行安装(建议重装,即先执行yum remove perl-podlators)。   

3、安装之后可以执行gmssl命令行工具检查是否成功

# /usr/local/gmssl/bin/gmssl version
GmSSL 2.0 - OpenSSL 1.1.0d

执行gmssl命令后,出现:/usr/local/gmssl/bin/gmssl: relocation error: /usr/local/gmssl/bin/gmssl: symbol PBEPARAM_it, version OPENSSL_1_1_0d not defined in file libcrypto.so.1.1 with link time reference 错误!
暂时解决方法如下:
(1)查看gmssl依赖库路径:ldd /usr/local/gmssl/bin/gmssl
libssl.so.1.1 => /usr/local/openssl/lib/libssl.so.1.1 (0x00007fc91a5d0000)
libcrypto.so.1.1 => /usr/local/openssl/lib/libcrypto.so.1.1 (0x00007fc91a0ed000)

(2)把make后的两个依赖库拷贝到相应路径(覆盖原依赖文件,即安装openssl时所生成的libssl.so.1.1 及libcrypto.so.1.1 文件,注意:这种方法会影响到用openssl的应用,以下操作请三思而后行!)
cd /usr/local/src/GmSSL-master
cp libcrypto.so.1.1 /usr/local/openssl/lib/
cp libssl.so.1.1 /usr/local/openssl/lib/

GmSSL与PHP绑定:

    GmSSL的PHP扩展代码位于源代码中的的php/ext/openssl目录,PHP扩展需要和PHP源代码目录树一起编译,过程如下:

    1、下载并编译安装GmSSL(上一步已完成);

    2、下载最新的PHP源代码并解压;

    3、用GmSSL的php/ext/openssl目录替代PHP源代码中的ext/openssl目录;

    4、编译和安装PHPcentos7 php7.3安装

!!!请注意!!!

PHP的默认配置不编译OpenSSL扩展,需要显式指--with-openssl才会编译OpenSSL扩展,而且,我们此处需要显示指定gmssl,因此,在安装php过程中,执行configure操作时,需这样指定:./configure --with-openssl=/usr/local/gmssl --with-libdir=lib。

在执行./configure命令时,若提示:"configure: error: Cannot find OpenSSL's libraries",请执行:"ln -s /usr/local/openssl/lib/libssl.so /usr/lib",即使用openssl的libssl而非gmssl的libssl(为的是安装gmssl时,将对openssl的影响程度降到最低)。

在编译php过程中(执行make 或 make ZEND_EXTRA_LIBS='-liconv'命令),若出现:"make: *** [ext/openssl/xp_ssl.lo] Error 1"错误信息,可尝试安装php7.1(亲测php7.1.11安装成功)而非php7.3。

php安装成功后,可以通过ldd检查可执行程序是否链接了预期的库:ldd /usr/local/php73/bin/php。

    5、修改PHP配置文件php.ini启用openssl扩展,即取消php.iniextension=openssl前面的注释。

可以通过PHP的phpinfo()函数确认openssl扩展已经启用,通过ldd命令检查PHP的二进制程序调用了GmSSL的动态库而不是系统默认的OpenSSL动态库。

国密算法测试:

<?php
    printf("Versoin : %s\n", OPENSSL_VERSION_TEXT);
    $digests = openssl_get_md_methods(false);
    echo "Digests : ";
    foreach ($digests as $digest) {
	echo $digest.",";
    }
    echo "\n";

    $ciphers = openssl_get_cipher_methods(false);
    echo "Ciphers : ";
    foreach ($ciphers as $cipher) {
	echo $cipher.",";
    }
    echo "\n";

    $curves = openssl_get_curve_names();
    echo "Curves : ";
    foreach ($curves as $curve) {
	echo $curve.",";
    }
    echo "\n";
    echo "\n";

    $msg = "abc";
    printf("sm3(\"%s\") = %s\n", $msg, openssl_digest($msg, "sm3"));
    $key = openssl_random_pseudo_bytes(16);
    $ivlen = openssl_cipher_iv_length("sms4");
    $iv = openssl_random_pseudo_bytes($ivlen);
    $plaintext = "message to be encrypted";
    $ciphertext = openssl_encrypt($plaintext, "sms4", $key, $options=0, $iv);
    $original_plaintext = openssl_decrypt($ciphertext, "sms4", $key, $options=0, $iv);
    printf("sms4enc(\"%s\") = %s\n", $plaintext, bin2hex($ciphertext));
    printf("sms4dec(%s) = \"%s\"\n", bin2hex($ciphertext), $original_plaintext);
    #$pubkey = openssl_pkey_get_public("file://localhost-signcer.pem");
    #$prikey = openssl_pkey_get_private("file://localhost-signkey.pem");
    $prikey = openssl_pkey_new(array("private_key_type" => OPENSSL_KEYTYPE_EC, "curve_name" => "sm2p256v1"));
    openssl_pkey_export($prikey, $prikeypem);
    echo $prikeypem;
    $pubkeypem = openssl_pkey_get_details($prikey)["key"];
    echo $pubkeypem;
    $pubkey = openssl_pkey_get_public($pubkeypem);
    $point = openssl_pkey_get_details($pubkey)["ec"];
    printf("SM2 Public Key: (%s, %s)\n", bin2hex($point["x"]), bin2hex($point["y"]));
    $ec = openssl_pkey_get_details($prikey)["ec"];
    printf("SM2 Private Key: %s\n", bin2hex($ec["d"]));
    openssl_sign($msg, $signature, $prikey, "sm3");
    $ok = openssl_verify($msg, $signature, $pubkey, OPENSSL_ALGO_SM3);
    printf("sm2sign(\"%s\") = %s\n", $msg, bin2hex($signature));
    printf("sm2verify(\"%s\", %s) = %s\n", $msg, bin2hex($signature), $ok ? "OK" : "Failure");
    openssl_seal($plaintext, $sealed, $ekeys, array($pubkey), "sms4", $iv);
    openssl_open($sealed, $opened, $ekeys[0], $prikey, "sms4", $iv);
    printf("sm2seal(\"%s\") = %s\n", $plaintext, bin2hex($sealed));
    printf("sm2open(%s) = \"%s\"\n", bin2hex($sealed), $opened);

?>

如上述代码正常执行,则说明php已支持gmssl。

参考文献:The GmSSL Project

Logo

更多推荐