如何在PHP中验证PKCS#7签名

时间:2018-05-31 08:53:14

标签: ssl openssl ssl-certificate phpseclib pkcs#7

我有一个数字签名(加密格式PKCS#7)需要验证所以我尝试过使用不同的PHP核心方法(openssl_verify,openssl_pkcs7_verify,甚至尝试过外部库,如phpseclib但是没有用:(

我通过此链接获得了一个签名以及一些额外的参数..

  

http://URL?sign= {' PARAM' {'标识':' XXXXXXX''朗':' EN',' Rc':' 00','电子邮件':' test@yahoo.com''},&#39 ;签名':' DFERVgYJKoZIhvcNAQcCoIIFRzCCBUMCAQExCzAJBgUrDg   MCGgUAMIGCBgkqhkiG9w0BBwGgdQRzeyJEYXRlIjoidG9fY2hhcihzeXNkYXRlJ0RETU1ZWVlZJykgIiwiSWQiOiJ   VMDExODg3NyIsIklkaW9tYSI6IkNBUyIsIk51bUVtcCI6IlUwM23D4DEE3dSi ...'}

PHP代码 - 始终返回0(false)而不是1(true)。

       $JSONDATA               = str_replace("'", '"', @$_GET["sign"]);
       $data                   = json_decode($JSONDATA, true);
       $this->email            = $data['param']["EMAIL"];
       $this->signature        = $data['signature'];
       $this->signature_base64 =  base64_decode($this->signature);
       $this->dataencoded      = json_encode($data['param']);

       //SOLUTION 1 (By using phpseclib)  but didnt work..
       $rsa        = $this->phpseclib->load();
       $keysize    =  2048;
       $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
       $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
       $d = $rsa->createKey($keysize);
       $Kver = $d['publickey'];
       $KSign = $d['privatekey'];

       // Signing
       $rsa->loadKey($KSign);
       $rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
       $rsa->setHash('sha256');

       $signature = $rsa->sign($this->dataencoded);
       $signedHS = base64_encode($signature);

       // Verification
       $rsa->loadKey($Kver);
       $status = $rsa->verify($this->dataencoded, $this->firma_base64); // getting an error on this line Message: Invalid signature
       var_dump($status);  // reutrn false


        //SOLUTION 2 (By using code php methods)

        // obtener la clave pública desde el certifiado y prepararla
       $orignal_parse = parse_url("https://example.com", PHP_URL_HOST);
       $get = stream_context_create(array("ssl" => array("capture_peer_cert" => TRUE)));
       $read = stream_socket_client("ssl://".$orignal_parse.":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
       $cert = stream_context_get_params($read);
       $certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
       openssl_x509_export($cert["options"]["ssl"]["peer_certificate"],$cert_key);
       $pubkeyid = openssl_pkey_get_public($cert_key);

       $dataencoded = json_encode($data['param']);

       echo $ok = openssl_x509_check_private_key($cert_key,$this->firma_base64); // return nothing
       echo $ok1 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256); // returns 0
       echo $ok2 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA512);   // returns 0  
       echo $ok3 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256);  // returns 0
        echo $ok4 = openssl_verify($dataencoded, $this->firma, $pubkeyid, OPENSSL_ALGO_SHA512);   // returns 0     

Java代码 - (此代码有效并返回true)

private boolean verifySignautre(String frm) throws NetinfException, IOException, CMSException,
CertificateException, OperatorCreationException, Exception {
Security.addProvider(new BouncyCastleProvider());

//we extract the containers that make up the signature and the keystore used to sign included in the same signature.
CMSSignedData signedData = new CMSSignedData(Base64.decode(frm.getBytes()));
SignerInformationStore signers = signedData.getSignerInfos();
Store certStore = signedData.getCertificates();
Collection c = signers.getSigners();
Iterator it = c.iterator();

while (it.hasNext()) {
//retrieve the certificate with the recipient's id.
SignerInformation signerInfo = (SignerInformation) it.next();
Collection certCollection = certStore.getMatches(signerInfo.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder signerCertificateHolder = (X509CertificateHolder) certIt.next();

//create the container to validate signature.
ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new
DefaultDigestAlgorithmIdentifierFinder()).build(signerCertificateHolder);

//valid signature and then certificate validity date
try{
X509Certificate signedcert = new
JcaX509CertificateConverter().setProvider("BC").getCertificate(signerCertificateHolder);
signedcert.checkValidity();
signedcert.verify(signedcert.getPublicKey());
return true;
}catch(Exception e){
return false;
}
}

我只需要将这个Java代码转换为PHP。但是,正如您在上面所看到的那样,我尝试了不同的方法,但没有一种方法有效。

请支持我找到解决方案。

非常感谢您的支持

0 个答案:

没有答案