Extract certificate from a PKCS7 signature in php

5.2k views Asked by At

I need to extract the user certificate from a pkcs7 signature file. I can do it via the command line using the following:

openssl pkcs7 -in somesign.pks7 -inform PEM -print_certs

This will give me the entire certificate chain and I can process the resulting file to extract what I want.

Is there any way to do that with the openssl_pkcs7_ commands? I saw that openssl_pkcs7_verify has the $outfilename where the certs would be stored but I don't have the signed message, but it seems the $filename should have both the signature and the message, which is not my case (signature is in a separate file).

3

There are 3 answers

0
EpNa On

Try this

$pem_cert = [];
openssl_pkcs7_read(
    "-----BEGIN CERTIFICATE-----\n"
       . chunk_split(base64_encode(file_get_contents('somesign.pks7')), 64, "\n")
       . "-----END CERTIFICATE-----\n",
   $pem_cert
);
// PEM format cert
var_dump($pem_cert);

0
Junaid Jamil On

I have already using it via exec() function.

exec('../../apache/bin/openssl.exe pkcs7 -in D:/mypkcs7.p7b -inform DER -print_certs').

But I think, the best choise is to use the structure of SMIME files. You can obtain the structure by analysing the source code of OpenSSL. Finding it maybe tough,but once you find it,you can use it anywhere. OpenSSL GitHub source code is available here

2
Joe On

I'm not aware of a PHP library with straightforward API for this.

I've implemented several libraries however that could help with the task. asn1, crypto-util and x509 are available via composer.

Here's a barebones proof of concept that extracts all certificates from a PKCS7 PEM file:

<?php

use ASN1\Element;
use ASN1\Type\Constructed\Sequence;
use CryptoUtil\PEM\PEM;
use X509\Certificate\Certificate;

require __DIR__ . "/vendor/autoload.php";

$pem = PEM::fromFile("path-to-your.p7b");
// ContentInfo: https://tools.ietf.org/html/rfc2315#section-7
$content_info = Sequence::fromDER($pem->data());
// SignedData: https://tools.ietf.org/html/rfc2315#section-9.1
$signed_data = $content_info->getTagged(0)->asExplicit()->asSequence();
// ExtendedCertificatesAndCertificates: https://tools.ietf.org/html/rfc2315#section-6.6
$ecac = $signed_data->getTagged(0)->asImplicit(Element::TYPE_SET)->asSet();
// ExtendedCertificateOrCertificate: https://tools.ietf.org/html/rfc2315#section-6.5
foreach ($ecac->elements() as $ecoc) {
    $cert = Certificate::fromASN1($ecoc->asSequence());
    echo $cert->toPEM() . "\n";
}

ASN.1 handling is very error-prone. I've omitted all sanity checks from the above example, but the underlying library will throw exceptions on errors.

I hope this gives some pointers in case someone needs to parse PKCS #7 structures without relying on external programs.