I have tried Itext to do this, There i use a IExternalSingatureContainer interface class that uses our class to contact the signature service and get the byte[] of a pkcs1 signature, in some cases we can get PKCS7 and if we simply return that byte array from the signature container and then add a document timestamp, the the signature is fine, but in some cases we can only get PKCS1 signature, and the Certs without private key. when we use that to create a pkcs7 class then adobe shows an error “document has been alterd…”.
Our Itext code:
public byte[] Sign(Stream data)
{
String hashAlgorithm = DigestAlgorithms.SHA256;
byte[] hash = DigestAlgorithms.Digest(data, DigestAlgorithms.GetMessageDigest(hashAlgorithm));
string hashStr = Convert.ToBase64String(hash);
// Create and add the 'SignedProperties' element (you need to adapt this to follow the AdES standard)
PdfDictionary vri = new PdfDictionary();
vri.Put(PdfName.Contents, new PdfString("SignedPropertiesPlaceholder"));
sigDic.Put(PdfName.VRI, vri);
// this class singns the hash using a third party PKCS1 singature service where the customer confirms the singature using his mobile phone
SignService signService = new SignService(this.Propperties, this.KtOrPhone, ConfirmString);
string authId = signService.InitSign(hashStr);
signService.GetSignatureResult(authId);
var user = signService.UserInfo;
SignerFullName = user.name;
SignerIdentifier = user.nationalRegisterId;
Propperties.SignerIDNumber = SignerIdentifier;
Propperties.SignerName = SignerFullName;
// if this paramerter si returnd here the ti singature is corrrect but has no tsa, we requer tsa, that is added below.
Signature = System.Convert.FromBase64String(signService.Signature);
//if we return here Singature and the signature is pkcs7 then the singature is fine, but we need to ask for pkcs1 because pkcs7 is not always available.
byte[] certBytes = Convert.FromBase64String(signService.SigningCert);
X509Certificate2 certificate = new X509Certificate2(certBytes);
X509Chain certificateChain = new X509Chain();
certificateChain.ChainPolicy = new X509ChainPolicy
{
RevocationMode = X509RevocationMode.Offline, // or X509RevocationMode.Offline if you have an OCSP responder
RevocationFlag = X509RevocationFlag.EntireChain,
};
bool chainBuilt = certificateChain.Build(certificate);
UsedCerts = new X509Certificate2Collection(certificateChain.ChainElements.Cast<X509ChainElement>().Select(e => e.Certificate).ToArray());
SigningCertSubject = certificate.Subject;
SignerCertExpier = certificate.NotAfter.ToShortDateString();
try
{
string[] arr = SigningCertSubject.Split(',');
string name = arr.FirstOrDefault(x => x.Trim().StartsWith("CN"));
string serial = arr.FirstOrDefault(x => x.Trim().StartsWith("SERIALNUMBER"));
name = name.Contains('=') ? name.Split('=')[1] : name;
serial = serial.Contains('=') ? serial.Split('=')[1] : serial;
}
catch (InvalidOperationException e)
{
throw new Exception("Undirritunin er ólögleg", e);
}
// Create an RSACryptoServiceProvider
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)UsedCerts[0].PublicKey.Key;
RSAParameters rsaParams = UsedCerts[0].GetRSAPublicKey().ExportParameters(false);
rsa.ImportParameters(rsaParams);
if (!rsa.VerifyData(ReadStreamToByteArray(data), Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
{
throw new Exception("Singature data Illegal");
}
if (!rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), Signature))
{
throw new Exception("Singature hash Illegal");
}
X509CertificateParser parser = new X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[UsedCerts.Count];
for (int i = 0; i < UsedCerts.Count; i++)
{
chain[i] = parser.ReadCertificate(UsedCerts[i].GetRawCertData());
}
ITSAClient tsaClient = new TSAClientBouncyCastle(Propperties.TimeServicePropperties.TimeServerURL);
OcspClientBouncyCastle ocspClient = new OcspClientBouncyCastle(null);
Collection<byte[]> ocsp = new Collection<byte[]>();
Collection<byte[]> crl = new Collection<byte[]>();
for (var i = 0; i < chain.Length - 1; i++)
{
byte[] encoded = ocspClient.GetEncoded((Org.BouncyCastle.X509.X509Certificate)chain[i], (Org.BouncyCastle.X509.X509Certificate)chain[i + 1], null);// Propperties.OcspURL
if (encoded != null)
ocsp.Add(encoded);
}
PdfPKCS7 pdfPKCS7 = new PdfPKCS7(null, chain, hashAlgorithm, false);
pdfPKCS7.SetExternalDigest(Signature, null, "RSA");
byte[] sh = pdfPKCS7.GetAuthenticatedAttributeBytes(hash, PdfSigner.CryptoStandard.CMS, ocsp, null);
byte[] result = pdfPKCS7.GetEncodedPKCS7(sh, PdfSigner.CryptoStandard.CADES, tsaClient, ocsp, null);
return result;
}
in line pdfPKCS7.GetEncodedPKCS7 we have tried as first parameter sh and hash with same result.
is this something Aspose can handle to result in a legal pkcs7 signature?