/* Updates the /ByteRange with the provided value */ private void UpdateByteRange(PdfPKCS7 pkcs7, PdfSignature signature) { PdfArray b = signature.GetByteRange(); RandomAccessFileOrArray rf = document.GetReader().GetSafeFile(); Stream rg = null; try { rg = new RASInputStream(new RandomAccessSourceFactory().CreateRanged(rf.CreateSourceView(), b.ToLongArray( ))); byte[] buf = new byte[8192]; int rd; while ((rd = rg.JRead(buf, 0, buf.Length)) > 0) { pkcs7.Update(buf, 0, rd); } } catch (Exception e) { throw new PdfException(e); } finally { try { if (rg != null) { rg.Dispose(); } } catch (System.IO.IOException e) { // this really shouldn't ever happen - the source view we use is based on a Safe view, which is a no-op anyway throw new PdfException(e); } } }
/// <summary>Adds keys to the signature dictionary that define the field permissions.</summary> /// <remarks> /// Adds keys to the signature dictionary that define the field permissions. /// This method is only used for signatures that lock fields. /// </remarks> /// <param name="crypto">the signature dictionary</param> protected internal virtual void AddFieldMDP(PdfSignature crypto, PdfSigFieldLockDictionary fieldLock) { PdfDictionary reference = new PdfDictionary(); PdfDictionary transformParams = new PdfDictionary(); transformParams.PutAll(fieldLock.GetPdfObject()); transformParams.Put(PdfName.Type, PdfName.TransformParams); transformParams.Put(PdfName.V, new PdfName("1.2")); reference.Put(PdfName.TransformMethod, PdfName.FieldMDP); reference.Put(PdfName.Type, PdfName.SigRef); reference.Put(PdfName.TransformParams, transformParams); reference.Put(new PdfName("DigestValue"), new PdfString("aa")); PdfArray loc = new PdfArray(); loc.Add(new PdfNumber(0)); loc.Add(new PdfNumber(0)); reference.Put(new PdfName("DigestLocation"), loc); reference.Put(new PdfName("DigestMethod"), new PdfName("MD5")); reference.Put(PdfName.Data, document.GetTrailer().Get(PdfName.Root)); PdfArray types = crypto.GetPdfObject().GetAsArray(PdfName.Reference); if (types == null) { types = new PdfArray(); } types.Add(reference); crypto.Put(PdfName.Reference, types); }
/// <summary>Adds keys to the signature dictionary that define the certification level and the permissions.</summary> /// <remarks> /// Adds keys to the signature dictionary that define the certification level and the permissions. /// This method is only used for Certifying signatures. /// </remarks> /// <param name="crypto">the signature dictionary</param> protected internal virtual void AddDocMDP(PdfSignature crypto) { PdfDictionary reference = new PdfDictionary(); PdfDictionary transformParams = new PdfDictionary(); transformParams.Put(PdfName.P, new PdfNumber(certificationLevel)); transformParams.Put(PdfName.V, new PdfName("1.2")); transformParams.Put(PdfName.Type, PdfName.TransformParams); reference.Put(PdfName.TransformMethod, PdfName.DocMDP); reference.Put(PdfName.Type, PdfName.SigRef); reference.Put(PdfName.TransformParams, transformParams); if (document.GetPdfVersion().CompareTo(PdfVersion.PDF_1_6) < 0) { reference.Put(new PdfName("DigestValue"), new PdfString("aa")); PdfArray loc = new PdfArray(); loc.Add(new PdfNumber(0)); loc.Add(new PdfNumber(0)); reference.Put(new PdfName("DigestLocation"), loc); reference.Put(new PdfName("DigestMethod"), new PdfName("MD5")); } reference.Put(PdfName.Data, document.GetTrailer().Get(PdfName.Root)); PdfArray types = new PdfArray(); types.Add(reference); crypto.Put(PdfName.Reference, types); }
/// <summary> /// Prepares an /// <see cref="PdfPKCS7"/> /// instance for the given signature. /// This method handles signature parsing and might throw an exception if /// signature is malformed. /// <p> /// The returned /// <see cref="PdfPKCS7"/> /// can be used to fetch additional info about the signature /// and also to perform integrity check of data signed by the given signature field. /// </p> /// Prepared /// <see cref="PdfPKCS7"/> /// instance calculates digest based on signature's /ByteRange entry. /// In order to check that /ByteRange is properly defined and given signature indeed covers the current PDF document /// revision please use /// <see cref="SignatureCoversWholeDocument(System.String)"/> /// method. /// </summary> /// <param name="signatureFieldName">the signature field name</param> /// <param name="securityProvider">the security provider or null for the default provider</param> /// <returns> /// a /// <see cref="PdfPKCS7"/> /// instance which can be used to fetch additional info about the signature /// and also to perform integrity check of data signed by the given signature field. /// </returns> public virtual PdfPKCS7 ReadSignatureData(String signatureFieldName) { PdfSignature signature = GetSignature(signatureFieldName); if (signature == null) { return(null); } try { PdfName sub = signature.GetSubFilter(); PdfString contents = signature.GetContents(); PdfPKCS7 pk = null; if (sub.Equals(PdfName.Adbe_x509_rsa_sha1)) { PdfString cert = signature.GetPdfObject().GetAsString(PdfName.Cert); if (cert == null) { cert = signature.GetPdfObject().GetAsArray(PdfName.Cert).GetAsString(0); } pk = new PdfPKCS7(PdfEncodings.ConvertToBytes(contents.GetValue(), null), cert.GetValueBytes()); } else { pk = new PdfPKCS7(PdfEncodings.ConvertToBytes(contents.GetValue(), null), sub); } UpdateByteRange(pk, signature); PdfString date = signature.GetDate(); if (date != null) { pk.SetSignDate(PdfDate.Decode(date.ToString())); } String signName = signature.GetName(); pk.SetSignName(signName); String reason = signature.GetReason(); if (reason != null) { pk.SetReason(reason); } String location = signature.GetLocation(); if (location != null) { pk.SetLocation(location); } return(pk); } catch (Exception e) { throw new PdfException(e); } }
/// <summary>Signs a document with a PAdES-LTV Timestamp.</summary> /// <remarks> /// Signs a document with a PAdES-LTV Timestamp. The document is closed at the end. /// <br /><br /> /// NOTE: This method closes the underlying pdf document. This means, that current instance /// of PdfSigner cannot be used after this method call. /// </remarks> /// <param name="tsa">the timestamp generator</param> /// <param name="signatureName"> /// the signature name or null to have a name generated /// automatically /// </param> /// <exception cref="System.IO.IOException"/> /// <exception cref="Org.BouncyCastle.Security.GeneralSecurityException"/> public virtual void Timestamp(ITSAClient tsa, String signatureName) { if (closed) { throw new PdfException(PdfException.ThisInstanceOfPdfSignerAlreadyClosed); } int contentEstimated = tsa.GetTokenSizeEstimate(); AddDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL5); SetFieldName(signatureName); PdfSignature dic = new PdfSignature(PdfName.Adobe_PPKLite, PdfName.ETSI_RFC3161); dic.Put(PdfName.Type, PdfName.DocTimeStamp); cryptoDictionary = dic; IDictionary <PdfName, int?> exc = new Dictionary <PdfName, int?>(); exc[PdfName.Contents] = contentEstimated * 2 + 2; PreClose(exc); Stream data = GetRangeStream(); IDigest messageDigest = tsa.GetMessageDigest(); byte[] buf = new byte[4096]; int n; while ((n = data.Read(buf)) > 0) { messageDigest.Update(buf, 0, n); } byte[] tsImprint = messageDigest.Digest(); byte[] tsToken; try { tsToken = tsa.GetTimeStampToken(tsImprint); } catch (Exception e) { throw new GeneralSecurityException(e.Message, e); } if (contentEstimated + 2 < tsToken.Length) { throw new System.IO.IOException("Not enough space"); } byte[] paddedSig = new byte[contentEstimated]; System.Array.Copy(tsToken, 0, paddedSig, 0, tsToken.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); Close(dic2); closed = true; }
/// <exception cref="Org.BouncyCastle.Security.SecurityUtilityException"/> /// <exception cref="System.IO.IOException"/> private PdfName GetSignatureHashKey(String signatureName) { PdfSignature sig = sgnUtil.GetSignature(signatureName); PdfString contents = sig.GetContents(); byte[] bc = PdfEncodings.ConvertToBytes(contents.GetValue(), null); byte[] bt = null; if (PdfName.ETSI_RFC3161.Equals(sig.GetSubFilter())) { Asn1InputStream din = new Asn1InputStream(new MemoryStream(bc)); Asn1Object pkcs = din.ReadObject(); bc = pkcs.GetEncoded(); } bt = HashBytesSha1(bc); return(new PdfName(ConvertToHex(bt))); }
/// <summary>Sign the document using an external container, usually a PKCS7.</summary> /// <remarks> /// Sign the document using an external container, usually a PKCS7. The signature is fully composed /// externally, iText will just put the container inside the document. /// <br /><br /> /// NOTE: This method closes the underlying pdf document. This means, that current instance /// of PdfSigner cannot be used after this method call. /// </remarks> /// <param name="externalSignatureContainer">the interface providing the actual signing</param> /// <param name="estimatedSize">the reserved size for the signature</param> /// <exception cref="Org.BouncyCastle.Security.GeneralSecurityException"/> /// <exception cref="System.IO.IOException"/> public virtual void SignExternalContainer(IExternalSignatureContainer externalSignatureContainer, int estimatedSize ) { if (closed) { throw new PdfException(PdfException.ThisInstanceOfPdfSignerAlreadyClosed); } PdfSignature dic = new PdfSignature(); PdfSignatureAppearance appearance = GetSignatureAppearance(); dic.SetReason(appearance.GetReason()); dic.SetLocation(appearance.GetLocation()); dic.SetSignatureCreator(appearance.GetSignatureCreator()); dic.SetContact(appearance.GetContact()); dic.SetDate(new PdfDate(GetSignDate())); // time-stamp will over-rule this externalSignatureContainer.ModifySigningDictionary(dic.GetPdfObject()); cryptoDictionary = dic; IDictionary <PdfName, int?> exc = new Dictionary <PdfName, int?>(); exc[PdfName.Contents] = estimatedSize * 2 + 2; PreClose(exc); Stream data = GetRangeStream(); byte[] encodedSig = externalSignatureContainer.Sign(data); if (estimatedSize < encodedSig.Length) { throw new System.IO.IOException("Not enough space"); } byte[] paddedSig = new byte[estimatedSize]; System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); Close(dic2); closed = true; }
/// <summary>Signs the document using the detached mode, CMS or CAdES equivalent.</summary> /// <remarks> /// Signs the document using the detached mode, CMS or CAdES equivalent. /// <br /><br /> /// NOTE: This method closes the underlying pdf document. This means, that current instance /// of PdfSigner cannot be used after this method call. /// </remarks> /// <param name="externalSignature">the interface providing the actual signing</param> /// <param name="chain">the certificate chain</param> /// <param name="crlList">the CRL list</param> /// <param name="ocspClient">the OCSP client</param> /// <param name="tsaClient">the Timestamp client</param> /// <param name="externalDigest">an implementation that provides the digest</param> /// <param name="estimatedSize">the reserved size for the signature. It will be estimated if 0</param> /// <param name="sigtype">Either Signature.CMS or Signature.CADES</param> /// <exception cref="System.IO.IOException"/> /// <exception cref="Org.BouncyCastle.Security.GeneralSecurityException"/> public virtual void SignDetached(IExternalSignature externalSignature, X509Certificate[] chain, ICollection <ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize, PdfSigner.CryptoStandard sigtype) { if (closed) { throw new PdfException(PdfException.ThisInstanceOfPdfSignerAlreadyClosed); } ICollection <byte[]> crlBytes = null; int i = 0; while (crlBytes == null && i < chain.Length) { crlBytes = ProcessCrl(chain[i++], crlList); } if (estimatedSize == 0) { estimatedSize = 8192; if (crlBytes != null) { foreach (byte[] element in crlBytes) { estimatedSize += element.Length + 10; } } if (ocspClient != null) { estimatedSize += 4192; } if (tsaClient != null) { estimatedSize += 4192; } } PdfSignatureAppearance appearance = GetSignatureAppearance(); appearance.SetCertificate(chain[0]); if (sigtype == PdfSigner.CryptoStandard.CADES) { AddDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL2); } PdfSignature dic = new PdfSignature(PdfName.Adobe_PPKLite, sigtype == PdfSigner.CryptoStandard.CADES ? PdfName .ETSI_CAdES_DETACHED : PdfName.Adbe_pkcs7_detached); dic.SetReason(appearance.GetReason()); dic.SetLocation(appearance.GetLocation()); dic.SetSignatureCreator(appearance.GetSignatureCreator()); dic.SetContact(appearance.GetContact()); dic.SetDate(new PdfDate(GetSignDate())); // time-stamp will over-rule this cryptoDictionary = dic; IDictionary <PdfName, int?> exc = new Dictionary <PdfName, int?>(); exc[PdfName.Contents] = estimatedSize * 2 + 2; PreClose(exc); String hashAlgorithm = externalSignature.GetHashAlgorithm(); PdfPKCS7 sgn = new PdfPKCS7((ICipherParameters)null, chain, hashAlgorithm, false); Stream data = GetRangeStream(); byte[] hash = DigestAlgorithms.Digest(data, SignUtils.GetMessageDigest(hashAlgorithm)); byte[] ocsp = null; if (chain.Length >= 2 && ocspClient != null) { ocsp = ocspClient.GetEncoded((X509Certificate)chain[0], (X509Certificate)chain[1], null); } byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, ocsp, crlBytes, sigtype); byte[] extSignature = externalSignature.Sign(sh); sgn.SetExternalDigest(extSignature, null, externalSignature.GetEncryptionAlgorithm()); byte[] encodedSig = sgn.GetEncodedPKCS7(hash, tsaClient, ocsp, crlBytes, sigtype); if (estimatedSize < encodedSig.Length) { throw new System.IO.IOException("Not enough space"); } byte[] paddedSig = new byte[estimatedSize]; System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); Close(dic2); closed = true; }