PHPバージョン対応openssl呼び出しパラメータ

8512 ワード

背景と問題解決方法
古いプロジェクトは支付宝の一部のコードを再構築して支付宝の新しいsdkを統合する時検査署名がいつも失敗することを発見して、やっとopenであることを発見しますverifyの最後のパラメータ転送の問題.そしてopen_signも同じです.ここではopen_について主に説明します.verifyの解決方法とコード解析.問題の解決方法も最後の暗号化タイプパラメータを修正し、解決方法コードは以下の通りである.
    //       OPENSSL_ALGO_SHA256      
  openssl_verify($data, base64_decode($sign), $res, "sha256WithRSAEncryption");

公式文書の解釈
問題の発生と対応する解決方法についてのみ述べたが,興味があればこの関数を理解し続けることができ,まず公式ドキュメントのこの関数の解釈を見てみよう.
int openssl_verify ( string $data , string $signature , mixed $pub_key_id [, mixed $signature_alg = OPENSSL_ALGO_SHA1 ] )

パラメータコメント
  • dataは、署名を生成するために以前に使用されたデータ文字列である.
  • signature元のバイナリ文字列openssl_を介してSign()または類似の関数生成.
  • pub_key_id
  • resource-opensslを介して鍵get_publickey()関数が返されます.
  • string-PEM形式の鍵.たとえば、「---BEGIN PUBLIC KEY---MIIBCgK...」

  • signature_alg
  • int-以下の署名アルゴリズムの1つSignature Algorithms.
  • string-openssl_get_md_methods()関数は、「sha 1 WithRSAEncryption」や「sha 512」などの使用可能な文字列を返す.


  • 公式ドキュメントに記載されているsignature_algパラメータはintまたはstringタイプであり、intタイプは対応する列挙値を直接呼び出し、stringはopenssl_である.get_md_methods関数が返す使用可能な文字列openssl_を呼び出すget_md_methodsメソッドの印刷パラメータは以下の通りであり、これらの文字列も暗号化方式の要約情報に対応しており、後文ソースコードで見られる可能性のある関数呼び出しについては、その損失を少し理解している.
    Array
    (
        [0] => DSA
        [1] => DSA-SHA
        [2] => DSA-SHA1
        [3] => DSA-SHA1-old
        [4] => DSS1
        [5] => GOST 28147-89 MAC
        [6] => GOST R 34.11-94
        [7] => MD4
        [8] => MD5
        [9] => MDC2
        [10] => RIPEMD160
        [11] => RSA-MD4
        [12] => RSA-MD5
        [13] => RSA-MDC2
        [14] => RSA-RIPEMD160
        [15] => RSA-SHA
        [16] => RSA-SHA1
        [17] => RSA-SHA1-2
        [18] => RSA-SHA224
        [19] => RSA-SHA256
        [20] => RSA-SHA384
        [21] => RSA-SHA512
        [22] => SHA
        [23] => SHA1
        [24] => SHA224
        [25] => SHA256
        [26] => SHA384
        [27] => SHA512
        [28] => dsaEncryption
        [29] => dsaWithSHA
        [30] => dsaWithSHA1
        [31] => dss1
        [32] => ecdsa-with-SHA1
        [33] => gost-mac
        [34] => md4
        [35] => md4WithRSAEncryption
        [36] => md5
        [37] => md5WithRSAEncryption
        [38] => md_gost94
        [39] => mdc2
        [40] => mdc2WithRSA
        [41] => ripemd
        [42] => ripemd160
        [43] => ripemd160WithRSA
        [44] => rmd160
        [45] => sha
        [46] => sha1
        [47] => sha1WithRSAEncryption
        [48] => sha224
        [49] => sha224WithRSAEncryption
        [50] => sha256
        [51] => sha256WithRSAEncryption
        [52] => sha384
        [53] => sha384WithRSAEncryption
        [54] => sha512
        [55] => sha512WithRSAEncryption
        [56] => shaWithRSAEncryption
        [57] => ssl2-md5
        [58] => ssl3-md5
        [59] => ssl3-sha1
        [60] => whirlpool
    )
    

    関数は2つのモードに互換性があることもわかりますが、phpバージョンで互換性に問題があるのはなぜですか?Opensslライブラリのバージョンが一致している場合、次の理由はphp拡張の問題にのみ残るはずです.では、対応するソースコードを見て、問題がどこにあるかを発見しましょう.
    関数ソース
    openssl_verify関数ソース
    openssl_verifyソースコードには、パラメータmethodがstringタイプの場合opensslライブラリのEVP_を呼び出すセグメントがあります.get_digestbynameメソッドは、主に要約情報に基づいてEVP_を返すために、このメソッドの役割をネット上で確認しました.MD構造、EVP_get_digestbynameメソッドはopensslライブラリのソースコードであり、C言語についてあまり知られていないため、熊さんは見ていないが、phpコード呼び出しの背後にある処理ロジックを理解しているだけで、opensslライブラリのコード実装を見ることに興味がある.
    if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
            if (method != NULL) {
                signature_algo = Z_LVAL_P(method);
            }
            mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
        } else if (Z_TYPE_P(method) == IS_STRING) {
            mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
        } else {
            php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
            RETURN_FALSE;
        }
    

    列挙値の問題だったのか?
    最初はphp 5と思っていた.3バージョンはmethodパラメータタイプの制限になります.ソースコードを見るとopenssl_verify関数の実装ロジックは一致しており、methodパラメータタイプが検出されているため、問題はパラメータタイプに現れず、longタイプのパラメータが呼び出されたphp_であることを確認しました.openssl_get_evp_md_from_Algo関数は,やはり問題点を発見した.ソースコードは次のとおりです.
  • php5.3.27
  • static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
        EVP_MD *mdtype;
    
        switch (algo) {
            case OPENSSL_ALGO_SHA1:
                mdtype = (EVP_MD *) EVP_sha1();
                break;
            case OPENSSL_ALGO_MD5:
                mdtype = (EVP_MD *) EVP_md5();
                break;
            case OPENSSL_ALGO_MD4:
                mdtype = (EVP_MD *) EVP_md4();
                break;
    #ifdef HAVE_OPENSSL_MD2_H
            case OPENSSL_ALGO_MD2:
                mdtype = (EVP_MD *) EVP_md2();
                break;
    #endif
            case OPENSSL_ALGO_DSS1:
                mdtype = (EVP_MD *) EVP_dss1();
                break;
            default:
                return NULL;
                break;
        }
        return mdtype;
    }
    
    
  • php7.1.18
  • static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */
        EVP_MD *mdtype;
    
        switch (algo) {
            case OPENSSL_ALGO_SHA1:
                mdtype = (EVP_MD *) EVP_sha1();
                break;
            case OPENSSL_ALGO_MD5:
                mdtype = (EVP_MD *) EVP_md5();
                break;
            case OPENSSL_ALGO_MD4:
                mdtype = (EVP_MD *) EVP_md4();
                break;
    #ifdef HAVE_OPENSSL_MD2_H
            case OPENSSL_ALGO_MD2:
                mdtype = (EVP_MD *) EVP_md2();
                break;
    #endif
    #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
            case OPENSSL_ALGO_DSS1:
                mdtype = (EVP_MD *) EVP_dss1();
                break;
    #endif
            case OPENSSL_ALGO_SHA224:
                mdtype = (EVP_MD *) EVP_sha224();
                break;
            case OPENSSL_ALGO_SHA256:
                mdtype = (EVP_MD *) EVP_sha256();
                break;
            case OPENSSL_ALGO_SHA384:
                mdtype = (EVP_MD *) EVP_sha384();
                break;
            case OPENSSL_ALGO_SHA512:
                mdtype = (EVP_MD *) EVP_sha512();
                break;
            case OPENSSL_ALGO_RMD160:
                mdtype = (EVP_MD *) EVP_ripemd160();
                break;
            default:
                return NULL;
                break;
        }
        return mdtype;
    }
    

    上のソースコードから問題点を明確に発見することができ、phpバージョンのアップグレードに伴い、openssl拡張に対応する呼び出し条件も大幅に増加し、最後に上記の問題を引き起こしたソースコードもswitchにすぎない...Caseにはいくつかの条件が少なく、ここでも問題を発見したときに、まず問題を解決し、興味があればソースコード分析の下で問題が引き起こした原因を調べることができることを望んでいます.