Asked  7 Months ago    Answers:  5   Viewed   321 times

I need to sign a XML document using a PKCS12 certificate (.p12 file) in PHP, the standard must be XADES-BES. Is this possible?

 Answers

59

It is most likely possible but equally likely has never been done with PHP code yet.

  • XML validation with XMLDSIG using XadES-BES algorithm

Existing PHP XML Digital Signature libraries for example are:

  • xmlseclibs
  • FraGoTe/xmldsig
  • Maks3w/xmldsig

It's probably a good bet to built on top of xmlseclibs.

Wednesday, March 31, 2021
 
Freddie
answered 7 Months ago
97

You mean $str = implode(' ', array('a', 'b', 'c', 'd', 'e', 'f'));?

Wednesday, March 31, 2021
 
Classified
answered 7 Months ago
74

I've found the solution, there was a bug on the expiration date where I was doing:

$expiration = (new DateTime())->modify('+3h')->getTimestamp();

So I've changed h to hours so that it works now, like:

$expiration = (new DateTime())->modify('+3hours')->getTimestamp();

But that didn't quite solved it, the actual missing part is that the Google_Signer_P12::sign() requires it to be encoded on base64, which is specified on the google docs:

Google Cloud Storage expects the Base64 encoded signature in its APIs.

However I (wrongly) though that Google_Signer_P12::sign() already would do that, so after I understood that it was required I've changed the sign method to:

function googleSignString($certificatePath, $stringToSign)
{
  return base64_encode((new Google_Signer_P12(
    file_get_contents($certificatePath),
    'notasecret'
  ))->sign($stringToSign));
}

And it is working now!!!

I've also updated the gist for anyone that wants to use it :)

Wednesday, March 31, 2021
 
davidb
answered 7 Months ago
26

(This answer summarizes the evolution of working code in the course of comments and edits to the question.)

Which option does PDF support

The PDF format (the commonly supported ISO 32000-1:2008) specified embedded signatures using either naked PKCS#1 signatures or full PKCS#7/CMS signature containers, cf. section 12.8.3 "Signature Interoperability", in particular

  • section 12.8.3.2 "PKCS#1 Signatures" and
  • section 12.8.3.3 "PKCS#7 Signatures as used in ISO 32000".

Newer standards, like the ETSI PAdES standards and the new ISO 32000-2:2017, forbid or deprecate the former option. For a new solution that shall not be outdated already on the day it is published, therefore, one should go for the latter choice.

Knowing the certificate beforehand

I am trying to sing a pdf using a remote web service which returns a XML signature that consists of PKCS#1 signature with end users certificate.

If that were all the functionality of the web service, there'd be a problem: Both when embedding a naked PKCS#1 signature and when constructing a PKCS#7 signature container, one needs to know the end entity certificate before calling the service to create a signature for a hash because that certificate or a reference to it must be embedded in the signed PDF data or the signed CMS attributes.

(Strictly speaking very basic CMS signature container do not require this but all signature profiles to take seriously do.)

Fortunately it turned out (edit 1) that one

can access to another service "This service enables Application Providers to request end user’s certificate serial number and certificate hash which can be used in constructing the data to be signed."

The code

The OP found iText/Java code for implementing the functionality to sign a PDF with an embedded PKCS#7/CMS signature container based on a signing service as described above (edit 2).

However, the resulting hash value to be signed is 77 bytes. The web service excepts 32 bytes SHA256 hashed data.

As it turned out, though, those 77 bytes were not the hash of the signed attributes:

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, byte[] x509Signature)
{
    [...]
    byte[] signatureHash = signature.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
    [...]
    return signatureHash;
}

They were the signed attributes bytes. Thus, these bytes merely needed to be hashed to produce the hash to send to the signing service for creating a signature.

Tuesday, August 31, 2021
 
Sergey Kalinichenko
answered 2 Months ago
24

Personally I would consider treating @throws similar to Java's checked exceptions

The way this works in Java is that basically exceptions that inherit from RuntimeException can be thrown and don't have to be handled. Any other types of exceptions must have a try-catch block to handle them. This handling code must be in the caller.

Basically in PHP kinda like this:

When a method has a @throws annotation, you have to add code to handle its exceptions.

Any exceptions that don't get mentioned are optional for handling in the calling code.


Now, I don't 100% follow this principle myself. The whole handling exceptions thing is sort of up to the programmer's preference, but this is just some thoughts on how I think it could be handled in a reasonable fashion.

Saturday, September 11, 2021
 
Kenny
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :