/// <summary> /// Attaches a timestamp to signed CMS object. /// </summary> /// <param name="timestamp">TSP response returned from Time-Stamping Authority.</param> /// <param name="signerInfoIndex">Signature index to attach the timestamp.</param> /// <exception cref="NotSupportedException"> /// Time-Stamp Response contains invalid content type. /// </exception> /// <exception cref="ArgumentException"> /// Data returned from Time-Stamping Authority does not contain valid response. /// </exception> /// <exception cref="ArgumentNullException"> /// <strong>response</strong> parameter is null. /// </exception> /// <exception cref="IndexOutOfRangeException"> /// <strong>signerInfoIndex</strong> value exceeds the number of attached signatures. /// </exception> /// <remarks>Call <see cref="Encode"/> method to get timestamped object.</remarks> public void AddTimestamp(TspResponse timestamp, Int32 signerInfoIndex) { if (timestamp == null) { throw new ArgumentNullException(nameof(timestamp)); } if (timestamp.Status.ResponseStatus != TspResponseStatus.Granted || timestamp.Status.ErrorCode != TspFailureStatus.None) { throw new ArgumentException("The time-stamp response is not successful."); } X509Attribute attribute; DefaultSignedPkcs7 tspCms = timestamp.GetSignedCms(); switch (timestamp.ResponseType.Value) { case PKCS_7_DATA: // add timestamp signing certs to original CMS foreach (X509Certificate2 tspCert in tspCms.Certificates) { if (!Certificates.Contains(tspCert)) { Certificates.Add(tspCert); } } // for Authenticode timestamp, we add SignerInfo from timestamp CMS var asn = new Asn1Reader(tspCms.SignerInfos.Encode()); attribute = new X509Attribute(new Oid(COUNTER_SIGN), asn.GetPayload()); break; case TST_TOKEN_INFO: attribute = new X509Attribute(new Oid(RFC_COUNTER_SIGN), tspCms.RawData); break; default: throw new NotSupportedException("Time-Stamp response contains invalid content type."); } var signerInfoBuilder = new PkcsSignerInfoBuilder(SignerInfos[signerInfoIndex]); X509Attribute attr = signerInfoBuilder.UnauthenticatedAttributes[COUNTER_SIGN]; if (attr != null) { signerInfoBuilder.UnauthenticatedAttributes.Remove(attr); } attr = signerInfoBuilder.UnauthenticatedAttributes[RFC_COUNTER_SIGN]; if (attr != null) { signerInfoBuilder.UnauthenticatedAttributes.Remove(attr); } signerInfoBuilder.AddUnauthenticatedAttribute(attribute); SignerInfos[signerInfoIndex] = signerInfoBuilder.Encode(); }
/// <summary> /// Signs current PKCS#7 message and adds a new signer information to <see cref="SignerInfos"/> collection. /// Certificates specified in <strong>chain</strong> parameter are added to <see cref="Certificates"/> collection. /// </summary> /// <param name="signer">signing object that contains public certificate, private key and signing configuration.</param> /// <param name="chain"> /// Signing certificate chain to add to CMS. This parameter is optional. If not specified, only leaf (signing) certificate /// is added to <see cref="Certificates"/> collection and signed message. /// </param> /// <exception cref="InvalidOperationException"> /// No data to sign was passed in the constructor. /// </exception> /// <returns> /// An instance of <see cref="DefaultSignedPkcs7"/> class that represents signed CMS message. /// </returns> /// <remarks> /// You can call this method multiple times to attach multiple signatures to signed CMS message. /// </remarks> public DefaultSignedPkcs7 Sign(MessageSigner signer, X509Certificate2Collection chain = null) { if (_content == null || _content.Length == 0) { throw new InvalidOperationException("There is no data to sign."); } var builder = new PkcsSignerInfoBuilder { ContentType = ContentType }; SignerInfos.Add(builder.Sign(signer, _content)); var certs = new List <X509Certificate2>(new[] { signer.SignerCertificate }); if (chain != null) { certs.AddRange(chain.Cast <X509Certificate2>()); } addCerts(certs); return(new DefaultSignedPkcs7(wrapEnvelope())); }