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.
- https://www.e-guven.com/media/2582/eguvenkoks2.crt
- https://www.e-guven.com/media/2584/turkcellmobilimzaaltkoks2.crt
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?
- Compute a digest from PDF content of the ByteRange.
- Create a Cms container, externally. (somehow)
- Add signer info, and put content digest into the container.
- Compute a digest from CMS authenticated attributes.
- Sign final digest via MSSP, and retrieve XMLDSig.
- Add signature fields to existing Cms container.
- 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.