Necati Yared Ozal
Necati Yared Ozal

Reputation: 48

How to use PdfPkcs7 without a full X509 certificate?

We are attempting to sign PDF externally by a mobile signature service. There are many questions about this topic in Stackoverflow, especially from Turkey. See: Sign Pdf Using ITextSharp and XML Signature. Quite same here.

We request profile info from MSSP. We can not retrieve signer's full public certificate, or a chain because of the laws on the protection of personal data.

Response of profile query service:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Body>
        <ns1:MSS_ProfileQueryResponse xmlns:ns1="http://turkcelltech.com/mobilesignature/validation/soap">
            <MSS_ProfileResp xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" xmlns:ns4="http://www.w3.org/2003/05/soap-envelope" xmlns:ns5="http://uri.etsi.org/TS102204/v1.1.2#" MajorVersion="1" MinorVersion="1">
                <ns5:AP_Info AP_ID="http://localhost" AP_TransID="_1264751036088" AP_PWD="secret" Instant="2013-06-12T04:54:43.260Z"/>
                <ns5:MSSP_Info Instant="2020-07-22T18:43:33.723+03:00">
                    <ns5:MSSP_ID/>
                </ns5:MSSP_Info>
                <ns5:SignatureProfile>
                    <ns5:mssURI>http://uri.turkcellteknoloji.com.tr/MobileSignature/profile2</ns5:mssURI>
                    <ns5:CertIssuerDN>C=TR,O=Elektronik Bilgi Guvenligi A.S.,CN=Turkcell Mobil NES Hizmet Saglayicisi S2</ns5:CertIssuerDN>
                    <ns5:CertSerialNumber>313460597714010174158784514408553193353</ns5:CertSerialNumber>
                    <ns5:CertHash>
                        <ns5:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                        <ns5:DigestValue>MVI4FeeToX6TDPLh3h9zEw19ulzTomxPB/zDvnyWzKA=</ns5:DigestValue>
                    </ns5:CertHash>
                    <ns5:msspUrl>http://localhost</ns5:msspUrl>
                    <ns5:certIssuerDN-DER>MGoxCzAJBgNVBAYTAlRSMSgwJgYDVQQKDB9FbGVrdHJvbmlrIEJpbGdpIEd1dmVubGlnaSBBLlMuMTEwLwYDVQQDDChUdXJrY2VsbCBNb2JpbCBORVMgSGl6bWV0IFNhZ2xheWljaXNpIFMy</ns5:certIssuerDN-DER>
                </ns5:SignatureProfile>
                <ns5:Status>
                    <ns5:StatusCode Value="100"/>
                    <ns5:StatusMessage>REQUEST_OK</ns5:StatusMessage>
                </ns5:Status>
            </MSS_ProfileResp>
        </ns1:MSS_ProfileQueryResponse>
    </soap:Body>
</soap:Envelope>

We still able to create a SigningCertificateV2 instance with this information.

var certAlgorithmIdentifier = new AlgorithmIdentifier(certHashDigestAlgorithm);
var certHash = Convert.FromBase64String(certHashDigestValue);

var issuer = new GeneralNames(new GeneralName(new X509Name(certIssuerDN)));
var serial = new DerInteger(new BigInteger(certSerialNumber));
var issuerSerial = new IssuerSerial(issuer, serial);

var certIDv2 = new EssCertIDv2(certAlgorithmIdentifier, certHash, issuerSerial);

return new SigningCertificateV2(certIDv2);

ASN.1 result is:

SEQUENCE (1 elem)
  SEQUENCE (1 elem)
    SEQUENCE (3 elem)
      SEQUENCE (1 elem)
        OBJECT IDENTIFIER 1.2.840.113549.1.1.11 sha256WithRSAEncryption (PKCS #1)
      OCTET STRING (32 byte) 31523815E793A17E930CF2E1DE1F73130D7DBA5CD3A26C4F07FCC3BE7C96CCA0
      SEQUENCE (2 elem)
        SEQUENCE (1 elem)
          [4] (1 elem)
            SEQUENCE (3 elem)
              SET (1 elem)
                SEQUENCE (2 elem)
                  OBJECT IDENTIFIER 2.5.4.6 countryName (X.520 DN component)
                  PrintableString TR
              SET (1 elem)
                SEQUENCE (2 elem)
                  OBJECT IDENTIFIER 2.5.4.10 organizationName (X.520 DN component)
                  UTF8String Elektronik Bilgi Guvenligi A.S.
              SET (1 elem)
                SEQUENCE (2 elem)
                  OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
                  UTF8String Turkcell Mobil NES Hizmet Saglayicisi S2
        INTEGER (128 bit) 313460597714010174158784514408553193353

And also we can retrieve, root and intermediate certificates from CA's keychain.

So, how can we combine them to use with PdfSigner and PdfPKCS7 to sign PDF? Should we create CMSSignedData externally, and how? Is this roadmap correct?

  1. Compute a digest from PDF content of the ByteRange.
  2. Create a Cms container, externally. (somehow)
  3. Add signer info, and put content digest into the container.
  4. Compute a digest from CMS authenticated attributes.
  5. Sign final digest via MSSP, and retrieve XMLDSig.
  6. Add signature fields to existing Cms container.
  7. Fill /Contents, in PDF signature dictionary, with DER encoded CmsSignedData.

I know there are many questions about the same topic. But none of them is clear enough to explain the process about processing signing certificates.

Edit:

Just to clarify, we are going to retrieve X509 certificates after signature request when we send a SHA-256 digest (base64 encoded).

XML signature, returning from signature service:

<?xml version="1.0" encoding="UTF-8" ?>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
        <CanonicalizationMethod Algorithm=""/>
        <SignatureMethod Algorithm=""/>
        <Reference>
            <DigestMethod Algorithm=""/>
            <DigestValue/>
        </Reference>
    </SignedInfo>
    <SignatureValue>
        ...
    </SignatureValue>
    <KeyInfo>
        <KeyValue>
            <RSAKeyValue>
                <Modulus>
                    ...
                </Modulus>
                <Exponent>
                    ...
                </Exponent>
            </RSAKeyValue>
        </KeyValue>
        <X509Data>
            <X509Certificate>
                ...
            </X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>

But as I mentioned before, we can not retrieve signer's full public certificate before signature request. Only certificate hash, serial number and issuer DN. This information is enough to set ESS signing-certificate-v2 attribute before signing request.

https://www.rfc-editor.org/rfc/rfc5126#section-5.7.3

This is why, we should be able to create CmsSignedData locally, and add pdf content digest, signer info (signing-certificate-v2 retrieved from profile query) and get final digest, from this CmsSignedData instance, to sign with MSSP signature service. After, we can fill other unsigned attributes, certificates in this CmsSignedData instance when we retrieve XML signature from the service.

Upvotes: 1

Views: 811

Answers (1)

mkl
mkl

Reputation: 96039

In response to the first version of the question which left the impression that the full signer certificate was not available at all, not even in the signing service answer:

You cannot create a pdf signature without embedding the signer's X509 certificate.

At least not in an interoperable manner.

According to the pdf specification:

12.8.3.2 PKCS #1 signatures

[...] For signing PDF files using PKCS #1, the only value of SubFilter that should be used is adbe.x509.rsa_sha1. [...] The certificate chain of the signer shall be stored in the Cert entry.

and

12.8.3.3 CMS (PKCS #7) signatures

[...] SubFilter shall take one of the following values:

  • adbe.pkcs7.detached [...]
  • adbe.pkcs7.sha1 [...]

At minimum the CMS object shall include the signer’s X.509 signing certificate. This certificate shall be used to verify the signature value in Contents.

(ISO 32000-2, section 12.8.3 Signature interoperability)

If you are looking into PAdES signatures, according to the PAdES specification:

6.3 PAdES baseline signatures

[...]

Additional requirements:

a) The generator shall include the signing certificate in the SignedData.certificates field.

(ETSI EN 319 142-1 V1.1.1)

Thus, without X509 certificate of the signer you cannot create an interoperable pdf signature.

Upvotes: 1

Related Questions