I am using Mimekit to do rsa pss cms sign, to simulate this openssl command
openssl cms -sign -in keys.zip -binary -nodetach -signer selfsigned.crt -inkey keypair.pem -out keys.zip.signed -keyopt rsa_padding_mode:pss
public byte[] Sign(byte[] data, byte[] signCert, byte[] privateKey, CmsKeyOpt cmsKeyOpt)
{
MimeMessage message = new MimeMessage
{
Body = new MimePart()
{
Content = new MimeContent(new MemoryStream(data)),
ContentTransferEncoding = ContentEncoding.Binary,
},
};
// Load private key from byte array
StreamReader stream = new StreamReader(new MemoryStream(privateKey), Encoding.Default);
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(stream).ReadObject();
// load certifacte from byte array
X509CertificateParser parser = new X509CertificateParser();
X509Certificate certificate = parser.ReadCertificate(signCert);
// Create RSA PSS CMS signer
CmsSigner signer = new CmsSigner(certificate, keyPair.Private)
{
RsaSignaturePadding = RsaSignaturePadding.Pss,
DigestAlgorithm = DigestAlgorithm.Sha256,
};
// Create BouncyCastle Secure MimeContext
BouncyCastleSecureMimeContext ctx = new TemporarySecureMimeContext();
ctx.EncapsulatedSign(signer, new MemoryStream(data));
// Get signed message body and override it
message.Body = MultipartSigned.Create(ctx, signer, message.Body);
byte[] singedData;
using (var memory = new MemoryStream())
{
message.WriteTo(memory);
singedData = memory.ToArray();
}
return singedData;
}
And everything works fine, my question how I can achieve verify by Mimekit/BouncyCastle, to simulate this openssl command
openssl cms -verify -in keys.zip.signed.dec -CAfile selfsigned.crt -out keys_dec_unsigned.zip
I tried this but I got exception System.NotSupportedException: 'SQLite is not available on pkcs7.Verify(out original) line
public byte[] Verify(byte[] data, byte[] signCert, byte[] privateKey)
{
bool valid = false;
// Load private key from byte array
StreamReader stream = new StreamReader(new MemoryStream(privateKey), Encoding.Default);
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(stream).ReadObject();
// load certifacte from byte array
X509CertificateParser parser = new X509CertificateParser();
X509Certificate certificate = parser.ReadCertificate(signCert);
MimeMessage message = MimeMessage.Load(new MemoryStream(data));
// Create BouncyCastle Secure MimeContext
MimeEntity original;
ApplicationPkcs7Mime pkcs7 = message.Body as ApplicationPkcs7Mime;
if (pkcs7 != null && pkcs7.SecureMimeType == SecureMimeType.SignedData)
{
foreach (var signature in pkcs7.Verify(out original))
{
try
{
valid = signature.Verify();
}
catch (DigitalSignatureVerifyException)
{
// There was an error verifying the signature.
}
}
}
byte[] res = { 0 };
return res;
}
Is there any guide I can follow to verify and return the data to it's origin forum, or an example?
By default, MimeKit tries to instantiate a S/MIME verify context based on its SQLite backend for certificate storage.
If you don't have SQLite installed and/or don't have your certificates stored in the SQLite database that MimeKit will maintain for you, then you need to either register a different backend for certificate storage/retrieval or instantiate your own S/MIME context (like you did for signing).
MimeKit comes with 2 options:
TemporarySecureMimeContext which stores certificates in memory and is what you used to sign the message in your code snippet above.
WindowsSecureMimeContext which uses the Windows OS X.509 certificate store.
Once you decide on which of those to use, you will need to import your certificate(s) into the context (which will import them into the appropriate backend storage location).
Then, after that, you can do this:
using (BouncyCastleSecureMimeContext ctx = new TemporarySecureMimeContext()) {
ctx.Import (...);
foreach (var signature in pkcs7.Verify(ctx, out original)) {
// ...
}
}
Update:
This devolved into misuse of the openssl cms sign command and an inability to verify the signature using MimeKit because MimeKit expects the encapsulated signed data to be in MIME format as it is supposed to be according to the S/MIME specifications.
Here's the deal:
The openssl cms sign command can be used to sign arbitrary data and the corresponding openssl cms verify command can be used to verify such signed output. HOWEVER, it is only valid S/MIME if the original content signed by the openssl cms sign command is/was in MIME format.
MimeKit expects valid S/MIME because it is... surprise, surprise... a MIME library.
As you might have noticed, the Verify() method has an output parameter (out MimeEntity originalEntity). This means that the Verify() method extracts the encapsulated content from within the signed data and parses it into a MIME entity and returns it to you, the caller, in the form of said output parameter.
If the encapsulated content is not in MIME format, then, obviously, the parser will fail to parse it.
Additional background with how CMS signatures work:
When you sign content using the CMS signing routine (e.g. openssl cms sign ...), it produces something that looks a bit like this:
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"
Content-Transfer-Encoding: base64
MIIQgAYJKoZIhvcNAQcCoIIQcTCCEG0CAQExDTALBglghkgBZQMEAgEwggkPBgkq...
The base64 content in the above MIME part includes both the original content and the CMS signature data (i.e. a list of signatures).
Therefor, MimeKit's Verify() method needs to separate the signatures from the original content after base64 decoding it. MimeKit then returns to you, the caller, the original content (which it expects to be in MIME format) and the list of signatures that you can then independently verify the authenticity of.
When I kept repeating myself that it mattered what format the file.bin file was in when you signed the content, I was not saying that openssl or MimeKit needed to parse file.bin when verifying the signature, I was saying that file.bin has exactly the same content as what would be extracted from the base64 blob in the S/MIME output produced by openssl cms sign ... and therefore, it needs to be in MIME format.
Related
I'm using syncfusion pdf to for digitally signing pdf files. On their website, they have an example for external signing a PDF. I slightly changed the example so the certificate can be selected from the windows certificate store. The selected certificate requires a PIN, so that a dialog pop up. The function Signature_ComputeHast is plain C# code. How can I enter the PIN programmatically in the code below?
Original example: https://help.syncfusion.com/file-formats/pdf/working-with-digitalsignature#externally-sing-a-pdf-document
private static X509Certificate2 SelectCertificate()
{
// Selecte certificate from store
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection selectedCertificate = (X509Certificate2Collection)collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false);// (X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, true);
selectedCertificate = X509Certificate2UI.SelectFromCollection(
store.Certificates,
"Certficates",
"Select a certificate for signing the document",
X509SelectionFlag.SingleSelection);
return selectedCertificate[0];
}
void Signature_ComputeHash(object sender, PdfSignatureEventArgs arguments)
{
//Get the document bytes
byte[] documentBytes = arguments.Data;
SignedCms signedCms = new SignedCms(new ContentInfo(documentBytes), detached: true);
//Compute the signature using the specified digital ID file and the password
X509Certificate2 certificate = SelectCertificate();
var cmsSigner = new CmsSigner(certificate);
//Set the digest algorithm SHA256
cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
signedCms.ComputeSignature(cmsSigner);
//Embed the encoded digital signature to the PDF document
arguments.SignedData = signedCms.Encode();
}
You will need to use the RSACryptoServiceProvider or RSACng cng (in .NET core) classes which support Hardware Security Modules to a greater level of granularity on Windows. You can create a new instance of the appropriate class with parameters to include the password as follows:
if(certificate.PrivateKey is RSACryptoServiceProvider rsa) {
if(rsa.CspKeyContainerInfo.HardwareDevice) {
CspParameters cspParams = new CspParameters(1, rsa.CspKeyContainerInfo.ProviderName,
rsa.CspKeyContainerInfo.UniqueKeyContainerName) {
KeyPassword = certPassword,
Flags = CspProviderFlags.NoPrompt
};
byte[] signedCMSBytes = new RSACryptoServiceProvider(cspParams).SignData(documentBytesDigest);
}
}
As far as I am aware you will need to create the hashed digest of documentBytes digest and put that in the in PKCS#7 along with the desired authenticated attributes yourself prior to signing. After that you will need to add any unauthenticated attributes to the CMS. Personally I do all that using Bouncy Castle. But we have to use the MS SSC to interact with the OS for access to the HSM. There is potentially a way to do it all with the SSC classes. Incidentally certPassword is a SecureString.
I was trying to get keypair for pkcs-7 signature an X509Certificate2 object from this code.
RSACryptoServiceProvider key = (RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaparam = key.ExportParameters(true);
AsymmetricCipherKeyPair keypair = DotNetUtilities.GetRsaKeyPair(rsaparam);
This works fine if X509Certificate2 object is created using .pfx file like this
X509Certificate2 cert = new X509Certificate2(".pfx file path", "password");
it works fine.
but when the certificate is listed from certificate store like this
X509Certificate2 cert;
X509Store UserCertificateStore = new X509Store("My");
UserCertificateStore.Open(OpenFlags.ReadOnly);
var certificates = UserCertificateStore.Certificates;
foreach (var certificate in certificates)
{
if (certificate.Thumbprint==thumbprint)
{
cert=certificate;
break;
}
}
it throws an exception with the message - Key not valid for use in specified state.
after #Crypt32 answer tried using RSA method sign hash
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
using (SHA256Managed sHA256 = new SHA256Managed())
{
byte[] hash = sHA256.ComputeHash(data);
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
}
but the signature was not in PKCS#7 format
This is because BouncyCastle attempts to get raw key material (literally, export) from .NET object while actual key is not marked as exportable. In Windows systems, keys are stored in cryptographic service providers which control all key operations. When you need to perform a specific cryptographic operation, you are asking CSP to do a job and it does without having to expose key material to you. If the key was imported/generated in CSP as exportable, you can ask CSP to export key material. If this flag was not set, CSP won't give you the key.
I don't know how BouncyCastle works, but if it expects raw key material, then you need exportable private key in your certificate.
To answer the underlying question, "How do I make a PKCS#7 SignedData message signed with RSA+SHA-2-256?"
https://github.com/Microsoft/dotnet/blob/master/releases/net471/dotnet471-changes.md#bcl says that SHA-2-256 not only works in 4.7.1, but it's the default now:
Updated SignedXML and SignedCMS to use SHA256 as a default over SHA1. SHA1 may still be used by selected as a default by enabling a context switch. [397307, System.Security.dll, Bug]
On older frameworks it's possible via:
ContentInfo content = new ContentInfo(data);
SignedCms cms = new SignedCms(content);
CmsSigner signer = new CmsSigner(cert);
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
cms.ComputeSignature(signer);
return cms.Encode();
Where "2.16.840.1.101.3.4.2.1" is OID-ese for SHA-2-256.
I am building login workflow using Google for user. Once user is authenticated, I call GetAuthResponse to get idToken.
https://developers.google.com/identity/sign-in/web/backend-auth
Now, I need to verify certificate against Google certificate. I am using JwtSecurityToken(C#) for the same.
I am referencing for verification - http://blogs.msdn.com/b/alejacma/archive/2008/06/25/how-to-sign-and-verify-the-signature-with-net-and-a-certificate-c.aspx
Issue is - I always gets false from VerifyHash. As, VerifyHash returns just false without any reason, I am not able to find way to verify whether idToken is
valid or not. My code is given below
String strID = ""; // idToken received from Google AuthResponse
JwtSecurityToken token = new JwtSecurityToken(strID);
byte[] text = GetHash(token.RawData);
SHA256Cng sha1 = new SHA256Cng();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
byte[] signature = Encoding.Unicode.GetBytes(token.RawSignature);
// Modulus and exponent value from https://www.googleapis.com/oauth2/v2/certs - second set of keys
String modulus = "uHzGq7cMlx21nydbz9VsW1PItetb9mqvnpLp_8E3Knyk-mjv9DlaPhKGHYlJfHYGzKa2190C5vfsLLb1MIeGfdAv7ftpFsanIWawl8Zo0g-l0m7T2yG_7XerqcVK91lFifeJtgxKI86cPdZkgRy6DaYxMuAwAlhvpi3_UhPvsIwi7M6mxE8nUNpUWodh_YjJNu3wOxKDwbBZuRV2itjY6Z7RjFgJt1CsKF-QjqSVvWjAl0LaCaeMS_8yae0ln5YNeS8rAb6xkmcOuYeyhYsiBzwLRvgpXzEVLjLr631Z99oUHTpP9vWJDpGhfkrClkbmdtZ-ZCwX-eFW6ndd54BJEQ==";
String exponent = "AQAB";
modulus = modulus.Replace('-', '+').Replace('_', '/'); // Else it gives Base64 error
StringBuilder sb = new StringBuilder();
sb.Append("<RSAKeyValue>");
sb.Append("<Modulus>");
sb.Append(modulus);
sb.Append("</Modulus>");
sb.Append("<Exponent>");
sb.Append(exponent);
sb.Append("</Exponent>");
sb.Append("</RSAKeyValue>");
RSACryptoServiceProvider RSAVerifier = new RSACryptoServiceProvider();
RSAVerifier.FromXmlString(sb.ToString());
// Verify the signature with the hash
return RSAVerifier.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), signature);
You might want to try as done in the Google+ Token Verification project - this fork includes a few minor updates that are still in review.
An alternative approach is to just verify the tokens using Google's token verification endpoints:
curl https://www.googleapis.com/oauth2/v2/tokeninfo?id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjkyNGE0NjA2NDgxM2I5YTA5ZmFjZGJiNzYwZGI5OTMwMWU0ZjBkZjAifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwNTcwOTc3MjI2ODMwNTc3MjMwIiwiYXpwIjoiMzY0MzgxNDQxMzEwLXRuOGw2ZnY2OWdnOGY3a3VjanJhYTFyZWpmaXRxbGpuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXRfaGFzaCI6IlAzLU1HZTdocWZhUkZ5Si1qcWRidHciLCJhdWQiOiIzNjQzODE0NDEzMTAtdG44bDZmdjY5Z2c4ZjdrdWNqcmFhMXJlamZpdHFsam4uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJjX2hhc2giOiJjd3hsdXBUSkc4N2FnbU1pb0tSYUV3IiwiaWF0IjoxNDM0NDcyODc2LCJleHAiOjE0MzQ0NzY0NzZ9.Gz_WljZOV9NphDdClakLstutEKk65PNpEof7mxM2j-AOfVwh-SS0L5uxIaknFOk4-nDGmip42vrPYgNvbQWKZY63XuCs94YQgVVmTNCTJnao1IavtrhYvpDqGuGKdEB3Wemg5sS81pEthdvHwyxfwLPYukIhT8-u4ESfbFacsRtR77QRIOk-iLJAVYWTROJ05Gpa-EkTunEBVmZyYetbMfSoYkbwFKxYOlHLY-ENz_XfHTGhYhb-GyGrrw0r4FyHb81IWJ6Jf-7w6y3RiUJik7kYRkvnFouXUFSm8GBwxsioi9AAkavUWUk27s15Kcv-_hkPXzVrW5SvR1zoTI_IMw
I used Bouncy Castle to generate a private key, as well as a PKCS10 CSR, which I then send to a remote server to be signed. I get back a standard base64 encoded signed SSL certificate in response as a string. The question is, how do I import the signed certificate from a string, and then save both the private key and signed certificate as a PKCS12 (.PFX) file?
Additionally, how do I bundle in a CA certificate to be included within the PFX file?
// Generate the private/public keypair
RsaKeyPairGenerator kpgen = new RsaKeyPairGenerator ();
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator ();
kpgen.Init (new KeyGenerationParameters (new SecureRandom (randomGenerator), 2048));
AsymmetricCipherKeyPair keyPair = kpgen.GenerateKeyPair ();
// Generate the CSR
X509Name subjectName = new X509Name ("CN=domain.com/name=Name");
Pkcs10CertificationRequest kpGen = new Pkcs10CertificationRequest ("SHA256withRSA", subjectName, keyPair.Public, null, keyPair.Private);
string certCsr = Convert.ToBase64String (kpGen.GetDerEncoded ());
// ** certCsr is now sent to be signed **
// ** let's assume that we get "certSigned" in response, and also have the CA **
string certSigned = "[standard signed certificate goes here]";
string certCA = "[standard CA certificate goes here]";
// Now how do I import certSigned and certCA
// Finally how do I export everything as a PFX file?
Bouncy Castle is a very powerful library, however the lack of documentation makes it quite difficult to work with. After searching for much too long through all of the classes and methods I finally found what I was looking for. The following code will take the previously generated private key, bundle it together with the signed certificate and the CA, and then save it as a .PFX file:
// Import the signed certificate
X509Certificate signedX509Cert = new X509CertificateParser ().ReadCertificate (Encoding.UTF8.GetBytes (certSigned));
X509CertificateEntry certEntry = new X509CertificateEntry (signedX509Cert);
// Import the CA certificate
X509Certificate signedX509CaCert = new X509CertificateParser ().ReadCertificate (Encoding.UTF8.GetBytes (certCA ));
X509CertificateEntry certCaEntry = new X509CertificateEntry (signedX509CaCert);
// Prepare the pkcs12 certificate store
Pkcs12Store store = new Pkcs12StoreBuilder ().Build ();
// Bundle together the private key, signed certificate and CA
store.SetKeyEntry (signedX509Cert.SubjectDN.ToString () + "_key", new AsymmetricKeyEntry (keyPair.Private), new X509CertificateEntry[] {
certEntry,
certCaEntry
});
// Finally save the bundle as a PFX file
using (var filestream = new FileStream (#"CertBundle.pfx", FileMode.Create, FileAccess.ReadWrite)) {
store.Save (filestream, "password".ToCharArray (), new SecureRandom ());
}
Feedback and improvements are welcome!
Hi I'm building REST service and planning to erase language restriction for developing both client and server from this project, the REST server currently written using PHP.
For security I'm validating their hash code, and also their client app signature. Currently the hash is successful but for the signature it always failed.
Every client will have their own private key and on the server we will have their public key to verify the signature, each request to server will send a signature.
If the client is a web server there will be only one private key for all user. If the client is a native app ( C# ) then each installed client app will have their unique private key.
PHP client to PHP REST server -> calculate hash ok, verify client signature ok
C# client (winapp) to PHP REST Server -> calculate hash ok, verify client signature failed
In the future I want to try with JAVA and vice versa.
I use easy way to create a self sign certificate
openssl genrsa -des3 -out netclient.key 2048
openssl req -new -x509 -key netclient.key -out netclient.crt
openssl pkcs12 -export -inkey netclient.key -in netclient.crt -out netclient.p12
Here is my code to sign data using C#
public static string (string Base64EncryptedData ) {
X509Certificate2 my;
my = new X509Certificate2("cert/netclient.p12", "abcdefg", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
RSACryptoServiceProvider csp = null;
csp = (RSACryptoServiceProvider)my.PrivateKey;
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(Base64EncryptedData);
byte[] hash = sha1.ComputeHash(data);
return Convert.ToBase64String(csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")));
}
It return a signature (base64) which I send to PHP REST server using GET method.
On PHP Server I recount the hash and verify but it never return 1. Currently I copy manually all the key to the server.
set_include_path(get_include_path() . PATH_SEPARATOR ."lib");
include("Crypt/RSA.php");
$p12cert = array();
$fp=fopen("cert/netclient.p12","r");
$priv_key=fread($fp,8192);
fclose($fp);
openssl_pkcs12_read($priv_key, $p12cert, "abcdefg");
//try using the phpseclib library from http://phpseclib.sourceforge.net
//req() will get all the $_POST, $_GET data req("signature") = $_GET["signature"];
//$hash_request is an base64_encode string same exact value as the one in C#
$rsa = new Crypt_RSA();
$rsa->setHash("sha1");
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$rsa->loadKey($p12cert["cert"]);
$verified_phpseclib = $rsa->verify($hash_request, base64_decode(req("signature"))) ? "verified" : "diff";
//try using php built in openssl
$verified_builtin = openssl_verify($hash_request, base64_decode(req('signature')), $p12cert["cert");
Non of the result return "verified" or "1"
Could it be because when C# sign the data, the format of the data is byte[] ?
Or is there other reason ?
I'm running all the code in linux
php - using apache2
c# - using monodevelop
Here is my pk12 array after reading using openssl_pkcs12_read you can download it here
Array
(
[cert] => -----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJANjuyBraeAN0MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTMwMzE5MDA0ODI0WhcNMTMwNDE4MDA0ODI0WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAojE1Md/DET9mvKpoNJvb+mbGdTfSYuXQurGxb5pU0ba+gVeARbc8fjaK
D/2EKhUP/7240a31e5qI/2UlgiHO+ghQKDPo+5W5CetDVR1oMbWVA1fp7/gv8DEV
AvNV9nVkYzxnoVPs+W0MhMlWPrhCNSqQ28BbbL0EzXwXESnMw0I2VAhGWDNG0zSl
U03l5zh8jzzRKKK+gw4gIKo0u4lEUqB52MaXPzdwQkOEXRUdT+l1vK3DGfQycMrm
gZEN6IXDvpSFcQfHJlICK06+JNgDM0tYbif2mMfDEPKeFIjGC8S2ZDTZlR92LCk1
/WUGhdDFobbLAOx40M/etOcaEN1bgQIDAQABo1AwTjAdBgNVHQ4EFgQUTr0r49JA
DUKKiIQkRVlog4T952AwHwYDVR0jBBgwFoAUTr0r49JADUKKiIQkRVlog4T952Aw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAO2IwjeIEVy8aLCOTjCkt
fTyLYuoiex+Xa/Dy2Xdl51Q44uAjCeSVsm1mXko+cZSypngGDu8W97sifzeR+pmW
7r6r+Rj+5pZcQiLQOCUQrXVpqHeiCS8QpOhpxGF+TOLy1O9zcqQwEiohKmzJB++d
1NM8//OBx1/Nyu7eLTKrTqfBdhuXfee963HVF9uBxwV8oa3UTQfhKu2vwJ64pcbU
5OVQw4rfhfSYhB1uu+zMQhCZ3hsroj2rC6Kfb8t3BNzngQwiqDBprmJznmJY38pW
kw0NIx+GrO1NUu+Ydl/7MXChujQajqSkG65Z9iJ8G7eegrY988INPVIfitIopWF+
jg==
-----END CERTIFICATE-----
[pkey] => -----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCiMTUx38MRP2a8
qmg0m9v6ZsZ1N9Ji5dC6sbFvmlTRtr6BV4BFtzx+NooP/YQqFQ//vbjRrfV7moj/
ZSWCIc76CFAoM+j7lbkJ60NVHWgxtZUDV+nv+C/wMRUC81X2dWRjPGehU+z5bQyE
yVY+uEI1KpDbwFtsvQTNfBcRKczDQjZUCEZYM0bTNKVTTeXnOHyPPNEoor6DDiAg
qjS7iURSoHnYxpc/N3BCQ4RdFR1P6XW8rcMZ9DJwyuaBkQ3ohcO+lIVxB8cmUgIr
Tr4k2AMzS1huJ/aYx8MQ8p4UiMYLxLZkNNmVH3YsKTX9ZQaF0MWhtssA7HjQz960
5xoQ3VuBAgMBAAECggEAB/TgBi1S9XKlyJWXfRU0SmlmTPPLF1zsy2vSJ4ZrqMoN
OG0hdsoRZqOoTDaEmEfmPAaDnY2qIEEpfVXp7CNacvubaw143Xav2CO5buB9bwrY
X4ydhk8nkuHlhPqI+gkyPogFEW37jxTha1YxK+yAGvmWl6EtGv1+0dHHk+j4CZAO
9DH1gZRBOXyeAJAhYuBMxxKfZhBNgGHzLtf9SGoOd2v9ya/h4CuqYh/CoxHGM/w1
uE6M2CKxSuZtqdtiJnoYcmAnDLACDmVHQNbFMEyC3ALrixgTj1p9aYPi8P/9BVKv
+T6cCmRQIl4VY4Ir0PCbai6BQaP6TIbAo0lt9cefUQKBgQDV2KKuc/TsZgrl+ijV
vW1kf46X1Squ8AqPgJnXYM5M4kG+17AecV25sm1oHmzN0ChwvWYotfhLMSqdH+1l
5zMYMwjTle9BkQXELyAvKiKND5I42DtTE04YnHi7HDlaJmOCa3WTTPjJiyIZC+9S
Lpc3gDwP8VSBcq2V2t/SMw9+nQKBgQDCKfIUJWW0WHkESmc8rJDBUWueUVfEWh/d
9ZG/gIapSXnJcTp/fRDZsaqS0pI7c8bvdPJPkQKO0M7Sy2E/OjyKOT5X4+4FguCd
XlwaUhVRycMxGjb1Q4pTlPCnQkoBVKQ5oW4IVQW/ILtT6wuJQPmqkwiXN6CSHzmF
w1RW+pUpNQKBgDXEeHLgmO5vYcIdOfMz47NnFxU59bdyh1U5gnTS1Ewkf19an9+n
pWcxY6zQKY8+DUz7cho+VqWhQROsmWYL0Z7+BfQdOMEFk6uWJcN2FqXdCmjchV4H
9pTdksWI/SqbiF2cYz2cFtml7/bYN140dLTxuyhPB25cxSRumeQiDn1JAoGBAJDf
w2UM0mpSaVmuOoGnMQtNuUMT5qz3ojd3eByvxcqirGCGP+PIab5FNsT+oWYC6Tja
xcJgrMvrOadHYXRP+8QXGlFyHLO4B+jj800gWhAAv8fvi3pNvvTGeRoT+Cwt/6uQ
rA1Dg1otDhl7k8wB00hXFV3ff8wHyF/qcw/DQXDRAoGBAJGvJSl9yIr5v3ooZ6BV
FtDcDTPFGxQCyqvfi5RzKW65Wqu1ZL7jSiOPcY4+418Zifnfyfr/9IZjl9EKPjhC
/fNqptnuA7DKPDKkQIeQSwtHF9HGVoqG0JGOmYCeCZxQK6eZhiuU8VohAAbzsdu8
PgxyS/PRbCsXP4p+OjR1i+3C
-----END PRIVATE KEY-----
)
Try this:
<?php
set_include_path(get_include_path() . PATH_SEPARATOR ."lib");
include('File/X509.php');
$p12cert = array();
$fp=fopen("cert/netclient.p12","r");
$priv_key=fread($fp,8192);
fclose($fp);
openssl_pkcs12_read($priv_key, $p12cert, "abcdefg");
$x509 = new File_X509();
$x509->loadX509($p12cert["cert"]);
$pubkey = $x509->getPublicKey();
$pubkey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$verified_phpseclib = $pubkey->verify($hash_request, base64_decode(req("signature"))) ? "verified" : "diff";