/// <summary> /// Create a byte array containing a signed S/MIME message. /// </summary> /// <param name="buffer">A byte array to streamline bit shuffling.</param> /// <param name="contentBytes">The contents of the envelope to be encrypted.</param> /// <param name="message">An OpaqueMail.MailMessage that contains the message to send.</param> /// <param name="alreadyEncrypted">Whether a portion of the message has previously been signed, as when triple wrapping.</param> private byte[] SmimeSign(byte[] buffer, byte[] contentBytes, MailMessage message, bool alreadyEncrypted) { if (message.SmimeSigningCertificate == null) { // If the implementation requires S/MIME signing (the default), throw an error if there's no certificate. if ((message.SmimeSettingsMode & SmimeSettingsMode.RequireExactSettings) > 0) throw new SmtpException("Trying to send a signed message, but no signing certificate has been assigned."); else return contentBytes; } // First, create a buffer for tracking the unsigned portion of this message. StringBuilder unsignedMessageBuilder = new StringBuilder(Constants.SMALLSBSIZE); // If triple wrapping, the previous layer was an encrypted envelope and needs to be Base64 encoded. if (alreadyEncrypted) { unsignedMessageBuilder.Append("Content-Type: application/pkcs7-mime; smime-type=enveloped-data;\r\n\tname=\"smime.p7m\"\r\n"); unsignedMessageBuilder.Append("Content-Transfer-Encoding: base64\r\n"); unsignedMessageBuilder.Append("Content-Description: \"S/MIME Cryptographic envelopedCms\"\r\n"); unsignedMessageBuilder.Append("Content-Disposition: attachment; filename=\"smime.p7m\"\r\n\r\n"); unsignedMessageBuilder.Append(Functions.ToBase64String(contentBytes)); } else unsignedMessageBuilder.Append(Encoding.UTF8.GetString(contentBytes)); // Prepare the signing parameters. ContentInfo contentInfo = new ContentInfo(Encoding.UTF8.GetBytes(unsignedMessageBuilder.ToString())); SignedCms signedCms = new SignedCms(contentInfo, true); CmsSigner signer = new CmsSigner(message.SubjectIdentifierType, message.SmimeSigningCertificate); signer.IncludeOption = X509IncludeOption.WholeChain; // Sign the current time. if ((message.SmimeSigningOptionFlags & SmimeSigningOptionFlags.SignTime) > 0) { Pkcs9SigningTime signingTime = new Pkcs9SigningTime(); signer.SignedAttributes.Add(signingTime); } // Encode the signed message. signedCms.ComputeSignature(signer); byte[] signedBytes = signedCms.Encode(); // Embed the signed and original version of the message using MIME. StringBuilder messageBuilder = new StringBuilder(Constants.SMALLSBSIZE); // Build the MIME message by embedding the unsigned and signed portions. messageBuilder.Append("This is a multi-part S/MIME signed message.\r\n\r\n"); messageBuilder.Append("--" + (alreadyEncrypted ? SmimeTripleSignedCmsBoundaryName : SmimeSignedCmsBoundaryName) + "\r\n"); messageBuilder.Append(unsignedMessageBuilder.ToString()); messageBuilder.Append("\r\n--" + (alreadyEncrypted ? SmimeTripleSignedCmsBoundaryName : SmimeSignedCmsBoundaryName) + "\r\n"); messageBuilder.Append("Content-Type: application/x-pkcs7-signature; smime-type=signed-data; name=\"smime.p7s\"\r\n"); messageBuilder.Append("Content-Transfer-Encoding: base64\r\n"); messageBuilder.Append("Content-Description: \"S/MIME Cryptographic signedCms\"\r\n"); messageBuilder.Append("Content-Disposition: attachment; filename=\"smime.p7s\"\r\n\r\n"); messageBuilder.Append(Functions.ToBase64String(signedBytes, 0, signedBytes.Length)); messageBuilder.Append("\r\n--" + (alreadyEncrypted ? SmimeTripleSignedCmsBoundaryName : SmimeSignedCmsBoundaryName) + "--\r\n"); return Encoding.UTF8.GetBytes(messageBuilder.ToString()); }
CmsSigner CreateSigner(X509Certificate2 cert) { CmsSigner signer = new CmsSigner(cert) { IncludeOption = m_certChainInclude, DigestAlgorithm = ToDigestAlgorithmOid(m_digestAlgorithm) }; Pkcs9SigningTime signingTime = new Pkcs9SigningTime(); signer.SignedAttributes.Add(signingTime); return signer; }
public void Constructor_DateTime_Now () { Pkcs9SigningTime st = new Pkcs9SigningTime (DateTime.UtcNow); Assert.AreEqual (signingTimeName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (signingTimeOid, st.Oid.Value, "Oid.Value"); Assert.AreEqual (15, st.RawData.Length, "RawData.Length"); Assert.AreEqual (BitConverter.ToString (st.RawData).ToLower ().Replace ("-", " "), st.Format (true), "Format(true)"); Assert.AreEqual (BitConverter.ToString (st.RawData).ToLower ().Replace ("-", " "), st.Format (false), "Format(false)"); }
public void CopyFrom_Bad () { Pkcs9SigningTime st = new Pkcs9SigningTime (mono10release); Pkcs9DocumentName dn = new Pkcs9DocumentName ("Mono"); st.CopyFrom (dn); Assert.AreEqual (dn.Oid.FriendlyName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (dn.Oid.Value, st.Oid.Value, "Oid.Value"); Assert.AreEqual (BitConverter.ToString (dn.RawData), BitConverter.ToString (st.RawData), "RawData"); // wrong ASN.1 Assert.AreEqual (mono10release, st.SigningTime, "SigningTime"); }
public static void SigningTimeFromRawData() { DateTime dateTime = new DateTime(2015, 4, 1); byte[] rawData = "170d3135303430313030303030305a".HexToByteArray(); Pkcs9SigningTime p = new Pkcs9SigningTime(rawData); Assert.Equal(rawData, p.RawData); DateTime cookedData = p.SigningTime; Assert.Equal(dateTime, cookedData); string oid = p.Oid.Value; Assert.Equal(s_OidSigningTime, oid); }
/// <summary> /// Проверка файла с подписью на валидность подписи /// </summary> /// <returns>Сообщения (или ошибки) о проверки подписи</returns> public ValidationResult Verify() { var result = new ValidationResult(); if (this.Signature == null) { result.AddError("Отсутствует файл с подписью!"); return result; } //Создаем пакет с подписью для проверки самой подписи SignedCms cms = null; if (this.Detached) {//отсоединенная подпись //создаем контейнер с оригинальными данными, подпись которых будет проверяться ContentInfo content = new ContentInfo(this.Original); //формируем пакет с оригинальными данными и параметрами подписи cms = new SignedCms(content, true); } else {// присоединенная подпись //формируем пустой пакет с данными //так как в случае присоединенной подписи //данные содержатся в самом подписанном файле cms = new SignedCms(); } try { //декодируем файл, содержащий подпись //если вылетает ошибка - значит подпись не верна!!! cms.Decode(this.Signature); //возможно, информация о подписаниях отсутствует if (cms.SignerInfos.Count <= 0) { result.AddError("Нет информации о подписях (возможно файл не подписан)"); return result; } result.AddInfo("Электронная Подпись Вернa."); result.AddNewLine(); result.Add("Файл подписан следующим(и) сертификатом(и):"); foreach (SignerInfo si in cms.SignerInfos) { var certificate = new Certificate(si.Certificate); if (_certificate == null) _certificate = certificate; result.AddNewLine(); result.Add(certificate.SerialNumber + " [" + certificate.Thumbprint + "]"); result.Add(certificate.SubjectCommonName); //дергаем время подписания документа текущей подписью for (int i = 0; i < si.SignedAttributes.Count; i++) { if (si.SignedAttributes[i].Oid.Value == "1.2.840.113549.1.9.5") // Oid время подписания { Pkcs9SigningTime pkcs9_time = new Pkcs9SigningTime(si.SignedAttributes[i].Values[0].RawData); result.Add("Дата и Время подписания: " + pkcs9_time.SigningTime.ToString()); break; } } } } catch { result.AddError("Подпись НЕ верна!"); } return result; }
public void CopyFrom_SigningTime_OidRaw () { Pkcs9SigningTime st = new Pkcs9SigningTime (DateTime.UtcNow); Pkcs9AttributeObject a = new Pkcs9AttributeObject (); a.CopyFrom (new AsnEncodedData (st.Oid, st.RawData)); }
public void Constructor_DateTime_1601 () { DateTime dt = new DateTime (1601, 01, 01, 00, 00, 00); Pkcs9SigningTime st = new Pkcs9SigningTime (dt); }
public void Constructor_DateTime_Before2050 () { DateTime dt = new DateTime (2049, 12, 31, 11, 59, 59); // up to 2050 encoding should stay with UTCTIME (0x17), i.e. 2 digits years Pkcs9SigningTime st = new Pkcs9SigningTime (dt); Assert.AreEqual (signingTimeName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (signingTimeOid, st.Oid.Value, "Oid.Value"); Assert.AreEqual (15, st.RawData.Length, "RawData.Length"); Assert.AreEqual ("17-0D-34-39-31-32-33-31-31-31-35-39-35-39-5A", BitConverter.ToString (st.RawData)); Assert.AreEqual (dt, st.SigningTime, "st.SigningTime"); Assert.AreEqual ("17 0d 34 39 31 32 33 31 31 31 35 39 35 39 5a", st.Format (true), "Format(true)"); Assert.AreEqual ("17 0d 34 39 31 32 33 31 31 31 35 39 35 39 5a", st.Format (false), "Format(false)"); }
public void Constructor_DateTime_After1950 () { DateTime dt = new DateTime (1950, 01, 01, 00, 00, 00); // UTCTIME (0x17), i.e. 2 digits years, limited to 1950-2050 Pkcs9SigningTime st = new Pkcs9SigningTime (dt); Assert.AreEqual (signingTimeName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (signingTimeOid, st.Oid.Value, "Oid.Value"); Assert.AreEqual (15, st.RawData.Length, "RawData.Length"); Assert.AreEqual ("17-0D-35-30-30-31-30-31-30-30-30-30-30-30-5A", BitConverter.ToString (st.RawData)); Assert.AreEqual (dt, st.SigningTime, "st.SigningTime"); Assert.AreEqual ("17 0d 35 30 30 31 30 31 30 30 30 30 30 30 5a", st.Format (true), "Format(true)"); Assert.AreEqual ("17 0d 35 30 30 31 30 31 30 30 30 30 30 30 5a", st.Format (false), "Format(false)"); }
public void Constructor_DateTime_Before1950 () { DateTime dt = new DateTime (1949, 12, 31, 11, 59, 59); // UTCTIME (0x17), i.e. 2 digits years, limited to 1950-2050 Pkcs9SigningTime st = new Pkcs9SigningTime (dt); }
/// <summary> /// 연대 서명과 관련된 정보를 반환합니다. /// </summary> /// <param name="filePath">연대 서명이 포함된 파일의 경로입니다.</param> /// <param name="counterCertificate">연대 서명의 인증서입니다.</param> /// <param name="signingTime">UTC+0 기준에서의 서명 시간입니다.</param> public static bool GetCounterSignerInfo(string filePath, ref X509Certificate2 counterCertificate, ref Pkcs9SigningTime signingTime) { try { int encodingType; int contentType; int formatType; IntPtr certStore = IntPtr.Zero; IntPtr cryptMsg = IntPtr.Zero; IntPtr context = IntPtr.Zero; if (!CryptQueryObject( CERT_QUERY_OBJECT_FILE, Marshal.StringToHGlobalUni(filePath), CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, out encodingType, out contentType, out formatType, ref certStore, ref cryptMsg, ref context)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } /* contentType = 10; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED * encodingType = 65537; PKCS_7_ASN_ENCODING | X509_ASN_ENCODING (65536 + 1) */ //Console.WriteLine("Querying file '{0}':", filePath); //Console.WriteLine(" Encoding Type: {0}", encodingType); //Console.WriteLine(" Content Type: {0}", contentType); //Console.WriteLine(" Format Type: {0}", formatType); //Console.WriteLine(" Cert Store: {0}", certStore.ToInt32()); //Console.WriteLine(" Crypt Msg: {0}", cryptMsg.ToInt32()); //Console.WriteLine(" Context: {0}", context.ToInt32()); // Get size of the encoded message. int cbData = 0; if (!CryptMsgGetParam( cryptMsg, CMSG_ENCODED_MESSAGE,//Crypt32.CMSG_SIGNER_INFO_PARAM, 0, IntPtr.Zero, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var vData = new byte[cbData]; // Get the encoded message. if (!CryptMsgGetParam( cryptMsg, CMSG_ENCODED_MESSAGE,//Crypt32.CMSG_SIGNER_INFO_PARAM, 0, vData, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var signedCms = new SignedCms(); signedCms.Decode(vData); foreach (var signerInfo in signedCms.SignerInfos) { foreach (var unsignedAttribute in signerInfo.UnsignedAttributes) { if (unsignedAttribute.Oid.Value != szOID_RSA_counterSign) continue; // 하나 이상의 연대 서명이 존재하는 파일이 만약 있다면 Collection을 반환하도록 다시 짜야함 foreach (var counterSignInfo in signerInfo.CounterSignerInfos) { // 연대 서명 정보 얻는 부분 counterCertificate = counterSignInfo.Certificate; // 연대 서명의 인증서 foreach (var signedAttribute in counterSignInfo.SignedAttributes) { if (signedAttribute.Oid.Value == szOID_RSA_signingTime) { // 연대 서명의 서명시간 signingTime = (Pkcs9SigningTime)signedAttribute.Values[0]; //Console.Out.WriteLine("Signing Time UTC: " + signingTime.SigningTime); } } } } } } catch (Win32Exception ex) { // 해당 파일에 연대 서명 정보가 없는 경우 if (ex.HResult == -2147467259) // ex.HResult == 0x80004005 { return false; } throw; // 겪어본 적 없는 예외 } return true; }
public static void SigningTimeFromCookedData() { DateTime dateTime = new DateTime(2015, 4, 1); Pkcs9SigningTime p = new Pkcs9SigningTime(dateTime); string oid = p.Oid.Value; Assert.Equal(s_OidSigningTime, oid); Pkcs9SigningTime p2 = new Pkcs9SigningTime(p.RawData); DateTime cookedData = p2.SigningTime; Assert.Equal(dateTime, cookedData); }
public void Constructor_DateTime_MinValue () { Pkcs9SigningTime st = new Pkcs9SigningTime (DateTime.MinValue); }
public void Constructor_DateTime_After2050 () { DateTime dt = new DateTime (2050, 01, 01, 00, 00, 00); // in 2050 encoding should switch to GENERALIZEDTIME (0x18), i.e. 4 digits years Pkcs9SigningTime st = new Pkcs9SigningTime (dt); }
public void Constructor_DateTime_1600 () { DateTime dt = new DateTime (1600, 12, 31, 11, 59, 59); Pkcs9SigningTime st = new Pkcs9SigningTime (dt); }
public void Constructor_DateTime () { Pkcs9SigningTime st = new Pkcs9SigningTime (mono10release); Assert.AreEqual (signingTimeName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (signingTimeOid, st.Oid.Value, "Oid.Value"); Assert.AreEqual (15, st.RawData.Length, "RawData.Length"); Assert.AreEqual ("17-0D-30-34-30-36-33-30-30-34-30-30-30-30-5A", BitConverter.ToString (st.RawData), "RawData"); Assert.AreEqual (mono10release, st.SigningTime, "st.SigningTime"); Assert.AreEqual ("17 0d 30 34 30 36 33 30 30 34 30 30 30 30 5a", st.Format (true), "Format(true)"); Assert.AreEqual ("17 0d 30 34 30 36 33 30 30 34 30 30 30 30 5a", st.Format (false), "Format(false)"); }
/// <summary> /// /// </summary> /// <param name="message"></param> /// <param name="signingCertificate"></param> /// <param name="encryptionCertificate"></param> /// <returns></returns> internal static byte[] GetSignature(Byte[] message, X509Certificate2 signingCertificate, X509Certificate2 encryptionCertificate) { SignedCms signedCms = new SignedCms(new ContentInfo(message), true); CmsSigner cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signingCertificate); cmsSigner.IncludeOption = X509IncludeOption.WholeChain; if (encryptionCertificate != null) { cmsSigner.Certificates.Add(encryptionCertificate); } Pkcs9SigningTime signingTime = new Pkcs9SigningTime(); cmsSigner.SignedAttributes.Add(signingTime); signedCms.ComputeSignature(cmsSigner, false); return signedCms.Encode(); }
public void Constructor_Bytes () { byte[] date = new byte [15] { 0x17, 0x0D, 0x30, 0x34, 0x30, 0x36, 0x33, 0x30, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5A }; Pkcs9SigningTime st = new Pkcs9SigningTime (date); Assert.AreEqual (signingTimeName, st.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (signingTimeOid, st.Oid.Value, "Oid.Value"); Assert.AreEqual (15, st.RawData.Length, "RawData.Length"); Assert.AreEqual ("17-0D-30-34-30-36-33-30-30-34-30-30-30-30-5A", BitConverter.ToString (st.RawData), "RawData"); Assert.AreEqual (mono10release, st.SigningTime, "st.SigningTime"); Assert.AreEqual ("17 0d 30 34 30 36 33 30 30 34 30 30 30 30 5a", st.Format (true), "Format(true)"); Assert.AreEqual ("17 0d 30 34 30 36 33 30 30 34 30 30 30 30 5a", st.Format (false), "Format(false)"); }
private bool VerifySignatureTimestamp(XmlElement signatureNode, XmlNamespaceManager nsm, out DateTime verificationTime) { verificationTime = DateTime.Now; XmlElement node = signatureNode.SelectSingleNode("ds:Object/as:Timestamp", nsm) as XmlElement; if (node != null) { string encodedMessage = node.InnerText; if (!string.IsNullOrEmpty(encodedMessage)) { byte[] base64DecodedMessage = null; try { base64DecodedMessage = Convert.FromBase64String(encodedMessage); } catch (FormatException) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_TIME_STAMP; throw new CryptographicException(Win32.TRUST_E_TIME_STAMP); } if (base64DecodedMessage != null) { // Create a new, nondetached SignedCms message. SignedCms signedCms = new SignedCms(); signedCms.Decode(base64DecodedMessage); // Verify the signature without validating the // certificate. signedCms.CheckSignature(true); byte[] signingTime = null; CryptographicAttributeObjectCollection caos = signedCms.SignerInfos[0].SignedAttributes; foreach (CryptographicAttributeObject cao in caos) { if (0 == string.Compare(cao.Oid.Value, Win32.szOID_RSA_signingTime, StringComparison.Ordinal)) { foreach (AsnEncodedData d in cao.Values) { if (0 == string.Compare(d.Oid.Value, Win32.szOID_RSA_signingTime, StringComparison.Ordinal)) { signingTime = d.RawData; Pkcs9SigningTime time = new Pkcs9SigningTime(signingTime); verificationTime = time.SigningTime; return true; } } } } } } } return false; }
public void Constructor_Bytes_Null () { Pkcs9SigningTime st = new Pkcs9SigningTime (null); }
private void Initialize() { _counterCertificateVerifier = new CertificateVerifier(); _counterCertificate = null; SigningTime = null; }
// [Ignore ("MS returns bad results (original time) - Mono needs to override CopyFrom to fix")] // http://lab.msdn.microsoft.com/ProductFeedback/viewfeedback.aspx?feedbackid=66943396-ad73-497f-82ae-090b87ffcb4e public void CopyFrom () { Pkcs9SigningTime st1 = new Pkcs9SigningTime (mono10release); Pkcs9SigningTime st2 = new Pkcs9SigningTime (DateTime.UtcNow); st1.CopyFrom (st2); Assert.AreEqual (st2.Oid.FriendlyName, st1.Oid.FriendlyName, "Oid.FriendlyName"); Assert.AreEqual (st2.Oid.Value, st1.Oid.Value, "Oid.Value"); Assert.AreEqual (BitConverter.ToString (st2.RawData), BitConverter.ToString (st1.RawData), "RawData"); // Note: Some timing resolution is lost by goind to ASN.1 Assert.AreEqual (st2.SigningTime.ToString (), st1.SigningTime.ToString (), "SigningTime"); }
/// <summary> /// Signs the signature request with the specified certificate, embeds all the specified additional certificates /// in the signature, and uses the provided additional certificates (along with the Operating /// System certificate store, if present) to build the full chain for the signing cert and /// embed that in the signature. /// </summary> /// <param name="signingCert">The certificate and private key to sign the document with</param> /// <param name="chainBuildingCertificates">Additional certificates to use when building the chain to embed</param> /// <param name="certificatesToEmbed">Additional certificates to add to the signature</param> public void Sign(X509Certificate2 signingCert, X509Certificate2Collection chainBuildingCertificates, X509Certificate2Collection certificatesToEmbed) { if (_signature != null) { throw new InvalidOperationException("A signature already exists"); } // Create the content info var content = new ContentInfo(Payload.Encode()); // Create the signer var signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, signingCert); var signingTime = new Pkcs9SigningTime(DateTime.UtcNow); signer.SignedAttributes.Add( new CryptographicAttributeObject( signingTime.Oid, new AsnEncodedDataCollection(signingTime))); // We do want the whole chain in the file, but we can't control how // CmsSigner builds the chain and add our additional certificates. // So, we tell it not to worry and we manually build the chain and // add it to the signer. signer.IncludeOption = X509IncludeOption.EndCertOnly; // Embed all the certificates in the CMS var chain = new X509Chain(); if (chainBuildingCertificates != null) { chain.ChainPolicy.ExtraStore.AddRange(chainBuildingCertificates); } chain.Build(signingCert); foreach (var element in chain.ChainElements) { // Don't re-embed the signing certificate! if (!Equals(element.Certificate, signingCert)) { signer.Certificates.Add(element.Certificate); } } if (certificatesToEmbed != null) { signer.Certificates.AddRange(certificatesToEmbed); } // Create the message and sign it // Use a local variable so that if the signature fails to compute, this object // remains in a "good" state. var cms = new SignedCms(content); cms.ComputeSignature(signer); _signature = cms; }
public static void SigningTimeNullary() { Pkcs9SigningTime p = new Pkcs9SigningTime(); // the default constructor initializes with DateTime.Now. Assert.NotNull(p.RawData); string oid = p.Oid.Value; Assert.Equal(s_OidSigningTime, oid); }