/* * tries to sign a MimeEntity */ public static MimeEntity SignEntity(MimeEntity entity, MailboxAddress signer) { using (WindowsSecureMimeContext ctx = new WindowsSecureMimeContext(sys.StoreLocation.CurrentUser)) { return(MultipartSigned.Create(ctx, signer, DigestAlgorithm.Sha1, entity)); } }
public void TestPgpMimeSigning() { var self = new MailboxAddress("MimeKit UnitTests", "*****@*****.**"); var cleartext = new TextPart("plain"); cleartext.Text = "This is some cleartext that we'll end up signing..."; using (var ctx = new DummyOpenPgpContext()) { var multipart = MultipartSigned.Create(ctx, self, DigestAlgorithm.Sha1, cleartext); Assert.AreEqual(2, multipart.Count, "The multipart/signed has an unexpected number of children."); var protocol = multipart.ContentType.Parameters["protocol"]; Assert.AreEqual(ctx.SignatureProtocol, protocol, "The multipart/signed protocol does not match."); Assert.IsInstanceOfType(typeof(TextPart), multipart[0], "The first child is not a text part."); Assert.IsInstanceOfType(typeof(ApplicationPgpSignature), multipart[1], "The second child is not a detached signature."); var signatures = multipart.Verify(ctx); Assert.AreEqual(1, signatures.Count, "Verify returned an unexpected number of signatures."); foreach (var signature in signatures) { try { bool valid = signature.Verify(); Assert.IsTrue(valid, "Bad signature from {0}", signature.SignerCertificate.Email); } catch (DigitalSignatureVerifyException ex) { Assert.Fail("Failed to verify signature: {0}", ex); } } } }
/* * Only signs the given MimeEntity */ private MultipartSigned SignEntity( Node entityNode, MimeEntity entity) { // Retrieving signature node to use for signing operation var signatureNode = entityNode ["signature"]; // Getting signature email as provided by caller var signatureAddress = GetSignatureMailboxAddress(signatureNode); // Figuring out signature Digest Algorithm to use for signature, defaulting to Sha256 var algo = signatureNode.GetChildValue("digest-algorithm", _context, DigestAlgorithm.Sha256); // Creating our Gnu Privacy Guard context using (var ctx = new GnuPrivacyContext()) { // Setting password to retrieve signing certificate from GnuPG context ctx.Password = signatureAddress.Item1; // Signing content of email and returning to caller return(MultipartSigned.Create( ctx, signatureAddress.Item2, algo, entity)); } }
public void Sign(MimeMessage message, PgpSecretKey key) { // digitally sign our message body using our custom GnuPG cryptography context using (var ctx = new MyGnuPGContext()) { message.Body = MultipartSigned.Create(ctx, key, DigestAlgorithm.Sha1, message.Body); } }
public static bool SendSignedMessage(MimeMessage message) { bool IsMailSigned = false; // digitally sign our message body using our custom S/MIME cryptography context try { using (var ctx = new SecureMimeContext()) { var signer = new CmsSigner(P12Stream(), "<PWD>") { DigestAlgorithm = DigestAlgorithm.Sha1 }; message.Body = MultipartSigned.Create(ctx, signer, message.Body); } SendEmailByMailServer(message); IsMailSigned = true; } catch (Exception e) { Console.WriteLine(e.InnerException.ToString()); IsMailSigned = false; } return(IsMailSigned); }
/* * Only signs the given MimeEntity. */ MultipartSigned SignEntity(Node entityNode, MimeEntity entity) { // Retrieving signature node to use for signing operation. var signatureNode = entityNode ["sign"]; // Getting signature email as provided by caller. var signatureAddress = GetSignatureMailboxAddress(signatureNode); /* * Figuring out signature Digest Algorithm to use for signature, defaulting to SHA256. * SHA256 should be safe, since there are no known collision weaknesses in it. * Therefor we default to SHA256, unlesss caller explicitly tells us he wants to use another algorithm. */ var algo = signatureNode.GetChildValue("digest-algorithm", _context, DigestAlgorithm.Sha256); /* * Creating our PGP context, passing in password specified by caller. */ using (var ctx = _context.RaiseEvent( ".p5.crypto.pgp-keys.context.create", new Node("", false, new Node [] { new Node("password", signatureAddress.Item1), new Node("fingerprint", signatureNode ["fingerprint"]?.GetExChildValue <string> ("fingerprint", _context, null) ?? _context.RaiseEvent("p5.auth.pgp.get-fingerprint").Get <string> (_context)) })) .Get <OpenPgpContext> (_context)) { // Signing content of email and returning to caller. return(MultipartSigned.Create( ctx, signatureAddress.Item2, algo, entity)); } }
protected void WriteMdn(HttpResponse response, MimeMessage mdn, int status) { response.StatusCode = status; foreach (var header in mdn.Headers) { response.Headers.Add(header.Field, header.Value); } var contentType = ((MultipartSigned)mdn.Body).Headers[HeaderId.ContentType]; response.Headers.Add("Content-Type", this.NormalizeHeaderValue(contentType)); // Write MDN to response without header names. // Force 7bit encoding in MIME Response MultipartSigned mSigned = mdn.Body as MultipartSigned; Debug.Assert(mSigned != null, nameof(mSigned) + " != null"); MultipartReport mReport = mSigned[0] as MultipartReport; Debug.Assert(mReport != null, nameof(mReport) + " != null"); TextPart textReport = mReport[0] as TextPart; Debug.Assert(textReport != null, nameof(textReport) + " != null"); textReport.ContentTransferEncoding = ContentEncoding.SevenBit; var notReport = mReport[1] as MessageDispositionNotification; Debug.Assert(notReport != null, nameof(notReport) + " != null"); notReport.ContentTransferEncoding = ContentEncoding.SevenBit; mdn.Headers.Add(HeaderId.Date, As2DateUtil.Rfc822.GetFormat(DateTime.Now)); mdn.WriteTo(response.Body); }
public void MultipartSign(MimeMessage message, X509Certificate2 certificate) { // digitally sign our message body using our custom S/MIME cryptography context using (var ctx = new MySecureMimeContext()) { var signer = new CmsSigner(certificate) { DigestAlgorithm = DigestAlgorithm.Sha1 }; message.Body = MultipartSigned.Create(ctx, signer, message.Body); } }
public void MultipartSign(MimeMessage message) { // digitally sign our message body using our custom S/MIME cryptography context using (var ctx = new MySecureMimeContext()) { // Note: this assumes that the Sender address has an S/MIME signing certificate // and private key with an X.509 Subject Email identifier that matches the // sender's email address. var sender = message.From.Mailboxes.FirstOrDefault(); message.Body = MultipartSigned.Create(ctx, sender, DigestAlgorithm.Sha1, message.Body); } }
public void TestMultipartSignedSignUsingKeys() { var body = new TextPart("plain") { Text = "This is some cleartext that we'll end up signing..." }; var self = new SecureMailboxAddress("MimeKit UnitTests", "*****@*****.**", "44CD48EEC90D8849961F36BA50DCD107AB0821A2"); PgpSecretKey signer; using (var ctx = new DummyOpenPgpContext()) { signer = ctx.GetSigningKey(self); foreach (DigestAlgorithm digest in Enum.GetValues(typeof(DigestAlgorithm))) { if (digest == DigestAlgorithm.None || digest == DigestAlgorithm.DoubleSha || digest == DigestAlgorithm.Tiger192 || digest == DigestAlgorithm.Haval5160 || digest == DigestAlgorithm.MD4) { continue; } var multipart = MultipartSigned.Create(signer, digest, body); Assert.AreEqual(2, multipart.Count, "The multipart/signed has an unexpected number of children."); var protocol = multipart.ContentType.Parameters["protocol"]; Assert.AreEqual("application/pgp-signature", protocol, "The multipart/signed protocol does not match."); var micalg = multipart.ContentType.Parameters["micalg"]; var algorithm = ctx.GetDigestAlgorithm(micalg); Assert.AreEqual(digest, algorithm, "The multipart/signed micalg does not match."); Assert.IsInstanceOf <TextPart> (multipart[0], "The first child is not a text part."); Assert.IsInstanceOf <ApplicationPgpSignature> (multipart[1], "The second child is not a detached signature."); var signatures = multipart.Verify(); Assert.AreEqual(1, signatures.Count, "Verify returned an unexpected number of signatures."); foreach (var signature in signatures) { try { bool valid = signature.Verify(); Assert.IsTrue(valid, "Bad signature from {0}", signature.SignerCertificate.Email); } catch (DigitalSignatureVerifyException ex) { Assert.Fail("Failed to verify signature: {0}", ex); } } } } }
/* * Processes a signed Multipart. */ private void ProcessSignedMultipart(MultipartSigned signedMultipart, Node entityNode) { // Creating cryptographic context. using (var ctx = new GnuPrivacyContext()) { // Adding signatures. ProcessSignatures(entityNode, signedMultipart.Verify(ctx)); // Looping through all entities in Multipart, processing recursively. foreach (var idxEntity in signedMultipart) { ProcessEntity(idxEntity, entityNode); } } }
/// <summary> /// Creates an S/MIME message using the supplied MimeBodyPart. The signature is generated using the private key /// as supplied in the constructor. Our certificate, which is required to verify the signature is enclosed. /// </summary> /// <param name="mimeBodyPart"></param> /// <param name="digestMethod"></param> /// <returns></returns> public MimeMessage CreateSignedMimeMessage(MimeMessage mimeBodyPart, SMimeDigestMethod digestMethod) { MimeMessage message = new MimeMessage(); using (var ctx = this.secContentFactory()) { // Algorithm lookup DigestAlgorithm algorithm; if (digestMethod.Equals(SMimeDigestMethod.Sha1)) { algorithm = DigestAlgorithm.Sha1; } else if (digestMethod.Equals(SMimeDigestMethod.Sha512)) { algorithm = DigestAlgorithm.Sha512; } else { throw new NotSupportedException($"Algorithm {digestMethod.GetAlgorithm()} not supported"); } // Signer identification var cmsSigner = new CmsSigner(this.ourCertificate, this.privateKey) { DigestAlgorithm = algorithm }; // Create and sign message message.Body = MultipartSigned.Create(ctx, cmsSigner, mimeBodyPart.Body); // Force signed content to be transferred in binary format MimePart xml = (MimePart)message.BodyParts.First(); xml.ContentTransferEncoding = ContentEncoding.Binary; } // Remove unused headers foreach (var header in message.Headers.Select(x => x.Id).ToList()) { if (header != HeaderId.MessageId && header != HeaderId.MimeVersion && header != HeaderId.ContentType) { message.Headers.Remove(header); } } return(message); }
public void TestSecureMimeSigning() { var self = new MailboxAddress("MimeKit UnitTests", "*****@*****.**"); var cleartext = new TextPart("plain"); cleartext.Text = "This is some cleartext that we'll end up signing..."; using (var ctx = CreateContext()) { var multipart = MultipartSigned.Create(ctx, self, DigestAlgorithm.Sha1, cleartext); Assert.AreEqual(2, multipart.Count, "The multipart/signed has an unexpected number of children."); var protocol = multipart.ContentType.Parameters["protocol"]; Assert.AreEqual(ctx.SignatureProtocol, protocol, "The multipart/signed protocol does not match."); Assert.IsInstanceOfType(typeof(TextPart), multipart[0], "The first child is not a text part."); Assert.IsInstanceOfType(typeof(ApplicationPkcs7Signature), multipart[1], "The second child is not a detached signature."); var signatures = multipart.Verify(ctx); Assert.AreEqual(1, signatures.Count, "Verify returned an unexpected number of signatures."); foreach (var signature in signatures) { try { bool valid = signature.Verify(); Assert.IsTrue(valid, "Bad signature from {0}", signature.SignerCertificate.Email); } catch (DigitalSignatureVerifyException ex) { Assert.Fail("Failed to verify signature: {0}", ex); } var algorithms = ((SecureMimeDigitalSignature)signature).EncryptionAlgorithms; Assert.AreEqual(EncryptionAlgorithm.Camellia256, algorithms[0], "Expected Camellia-256 capability"); Assert.AreEqual(EncryptionAlgorithm.Aes256, algorithms[1], "Expected AES-256 capability"); Assert.AreEqual(EncryptionAlgorithm.Camellia192, algorithms[2], "Expected Camellia-192 capability"); Assert.AreEqual(EncryptionAlgorithm.Aes192, algorithms[3], "Expected AES-192 capability"); Assert.AreEqual(EncryptionAlgorithm.Camellia128, algorithms[4], "Expected Camellia-128 capability"); Assert.AreEqual(EncryptionAlgorithm.Aes128, algorithms[5], "Expected AES-128 capability"); Assert.AreEqual(EncryptionAlgorithm.Idea, algorithms[6], "Expected IDEA capability"); Assert.AreEqual(EncryptionAlgorithm.Cast5, algorithms[7], "Expected Cast5 capability"); Assert.AreEqual(EncryptionAlgorithm.TripleDes, algorithms[8], "Expected Triple-DES capability"); //Assert.AreEqual (EncryptionAlgorithm.RC2128, algorithms[9], "Expected RC2-128 capability"); //Assert.AreEqual (EncryptionAlgorithm.RC264, algorithms[10], "Expected RC2-64 capability"); //Assert.AreEqual (EncryptionAlgorithm.Des, algorithms[11], "Expected DES capability"); //Assert.AreEqual (EncryptionAlgorithm.RC240, algorithms[12], "Expected RC2-40 capability"); } } }
/* * Processes a signed multipart. */ void ProcessSignedMultipart(MultipartSigned signedMultipart, Node entityNode) { // Creating cryptographic context. using (var ctx = _context.RaiseEvent( ".p5.crypto.pgp-keys.context.create", new Node("", false)).Get <OpenPgpContext> (_context)) { // Adding signatures. ProcessSignatures(entityNode, signedMultipart.Verify(ctx)); // Looping through all entities in Multipart, processing recursively. foreach (var idxEntity in signedMultipart) { // Processing currently iterated MIME part. ProcessEntity(idxEntity, entityNode); } } }
public void Sign(MimeMessage message) { // digitally sign our message body using our custom GnuPG cryptography context using (var ctx = new MyGnuPGContext()) { // Note: this assumes that the Sender address has an S/MIME signing certificate // and private key with an X.509 Subject Email identifier that matches the // sender's email address. // // If this is not the case, you can use a SecureMailboxAddress instead of a // normal MailboxAddress which would allow you to specify the fingerprint // of the sender's private PGP key. You could also choose to use one of the // Create() overloads that take a PgpSecretKey, instead. var sender = message.From.Mailboxes.FirstOrDefault(); message.Body = MultipartSigned.Create(ctx, sender, DigestAlgorithm.Sha1, message.Body); } }
/* * returns true if email address can sign email */ public static bool CanSign(string email) { try { MailboxAddress signer = new MailboxAddress("", email); TextPart entity = new TextPart("text"); using (WindowsSecureMimeContext ctx = new WindowsSecureMimeContext(sys.StoreLocation.CurrentUser)) { MultipartSigned.Create(ctx, signer, DigestAlgorithm.Sha1, entity); return(true); } } catch { return(false); } }
/* * Cryptographically signs an entity. */ static MultipartSigned Sign( MimeEntity entity, string armoredPrivateKey, string keyPassword) { var algo = DigestAlgorithm.Sha256; using (var ctx = new CreatePgpMimeContext { Password = keyPassword }) { return(MultipartSigned.Create( ctx, PgpHelpers.GetSecretKeyFromAsciiArmored(armoredPrivateKey), algo, entity)); } }
public bool VerifySignature(MultipartSigned multipartSigned, out DigitalSignatureCollection signatures) { var signed = multipartSigned; signatures = null; var valid = true; if (signed != null) { using (var ctx = this.secureContextFactory()) { signatures = signed.Verify(ctx); foreach (var signature in signatures) { valid = signature.Verify(); if (!valid) { break; } } } } return(valid); }
public MimeMessage CreateSignedMimeMessage(MimeEntity mimeBodyPart, SMimeDigestMethod digestMethod) { if (mimeBodyPart is MimePart) { ((MimePart)mimeBodyPart).ContentTransferEncoding = ContentEncoding.Binary; } MultipartSigned multipart; using (var ctx = this.secContentFactory()) { // Algorithm lookup DigestAlgorithm algorithm; if (digestMethod.Equals(SMimeDigestMethod.Sha1)) { algorithm = DigestAlgorithm.Sha1; } else if (digestMethod.Equals(SMimeDigestMethod.Sha512)) { algorithm = DigestAlgorithm.Sha512; } else { throw new NotSupportedException($"Algorithm {digestMethod.GetAlgorithm()} not supported"); } var micalg = ctx.GetDigestAlgorithmName(algorithm); var signed = new MultipartSigned(); // set the protocol and micalg Content-Type parameters signed.ContentType.Parameters["protocol"] = ctx.SignatureProtocol; signed.ContentType.Parameters["micalg"] = micalg; // add the modified/parsed entity as our first part signed.Add(mimeBodyPart); var cmsSigner = new CmsSigner(this.ourCertificate, this.privateKey) { DigestAlgorithm = algorithm }; ApplicationPkcs7Signature signature; using (var memory = new MemoryBlockStream()) { // var prepared = Prepare(entity, memory); mimeBodyPart.WriteTo(memory); memory.Position = 0; // sign the cleartext content signature = ctx.Sign(cmsSigner, memory); } // add the detached signature as the second part signed.Add(signature); // Create and sign message multipart = signed; } var message = new MimeMessage(); message.Body = multipart; return(message); }
/* * extracts body parts from message and put into node */ private static void ExtractBody( IEnumerable <MimeEntity> entities, Node node, bool skipSignature, MimeMessage msg, string basePath, string attachmentDirectory, string linkedAttachmentDirectory) { foreach (MimeEntity idxBody in entities) { if (idxBody is TextPart) { TextPart tp = idxBody as TextPart; if (idxBody.ContentType.MediaType == "text") { if (idxBody.ContentType.MediaSubtype == "plain") { node["body"]["plain"].Value = tp.Text; } else if (idxBody.ContentType.MediaSubtype == "html") { node["body"]["html"].Value = CleanHtml(tp.Text); } } } else if (idxBody is ApplicationPkcs7Mime) { ApplicationPkcs7Mime pkcs7 = idxBody as ApplicationPkcs7Mime; if (pkcs7.SecureMimeType == SecureMimeType.EnvelopedData) { try { MimeEntity entity = pkcs7.Decrypt(); ExtractBody(new MimeEntity[] { entity }, node, false, msg, basePath, attachmentDirectory, linkedAttachmentDirectory); node["encrypted"].Value = true; } catch (Exception err) { // couldn't decrypt node["body"]["plain"].Value = "couldn't decrypt message, exceptions was; '" + err.Message + "'"; node["encrypted"].Value = true; } } } else if (!skipSignature && idxBody is MultipartSigned) { MultipartSigned signed = idxBody as MultipartSigned; bool valid = false; foreach (IDigitalSignature signature in signed.Verify()) { valid = signature.Verify(); if (!valid) { break; } } node["signed"].Value = valid; ExtractBody(new MimeEntity[] { signed }, node, true, msg, basePath, attachmentDirectory, linkedAttachmentDirectory); } else if (idxBody is Multipart) { Multipart mp = idxBody as Multipart; ExtractBody(mp, node, false, msg, basePath, attachmentDirectory, linkedAttachmentDirectory); } else if (idxBody is MimePart) { // this is an attachment ExtractAttachments(idxBody as MimePart, msg, node, basePath, attachmentDirectory, linkedAttachmentDirectory); } } }
protected internal override void VisitMultipartSigned(MultipartSigned signed) { MultipartSigned++; base.VisitMultipartSigned(signed); }
/// <summary> /// Visit the multipart/signed MIME entity. /// </summary> /// <remarks> /// Visits the multipart/signed MIME entity. /// </remarks> /// <param name="signed">The multipart/signed MIME entity.</param> protected internal virtual void VisitMultipartSigned(MultipartSigned signed) { VisitMultipart(signed); }
protected ITransmissionResponse HandleResponse(HttpResponse httpResponse) { Trace span = this.root.Child(); // tracer.newChild(root.context()).name("response").start(); span.Record(Annotations.ServiceName("response")); span.Record(Annotations.ClientSend()); try { HttpResponse response = httpResponse; span.Record(Annotations.Tag("code", response.StatusCode.ToString())); // span.tag("code", String.valueOf(response.getStatusLine().getStatusCode())); if (response.StatusCode != HttpStatusCode.OK) { Logger.ErrorFormat( "AS2 HTTP POST expected HTTP OK, but got : {0} from {1}", response.StatusCode, this.transmissionRequest.GetEndpoint().Address); // Throws exception this.HandleFailedRequest(response); } // handle normal HTTP OK response Logger.DebugFormat( "AS2 transmission to {0} returned HTTP OK, verify MDN response", this.transmissionRequest.GetEndpoint().Address); string contentTypeHeader = response.Headers["Content-Type"]; if (string.IsNullOrWhiteSpace(contentTypeHeader)) { throw new HyperwayTransmissionException( "No Content-Type header in response, probably a server error."); } // Read MIME Message MimeMessage mimeMessage; using (var m = new MemoryStream()) { // Add headers to MIME Message foreach (var headerName in response.Headers.AllKeys) { var headerText = $"{headerName}: {response.Headers[headerName]}"; var headerData = Encoding.ASCII.GetBytes(headerText); m.Write(headerData, 0, headerData.Length); m.Write(new byte[] { 13, 10 }, 0, 2); } m.Write(new byte[] { 13, 10 }, 0, 2); var messageData = response.Entity.Content; m.Write(messageData, 0, messageData.Length); m.Seek(0, SeekOrigin.Begin); mimeMessage = MimeMessage.Load(m); mimeMessage.Headers[HeaderId.ContentType] = response.Headers["Content-Type"]; } SMimeReader sMimeReader = new SMimeReader(mimeMessage); // Timestamp of reception of MDN Timestamp t3 = this.timestampProvider.Generate(sMimeReader.GetSignature(), Direction.OUT); MultipartSigned signedMessage = mimeMessage.Body as MultipartSigned; using (this.secureMimeContext()) { Debug.Assert(signedMessage != null, nameof(signedMessage) + " != null"); var signatures = signedMessage.Verify(); var signature = signatures.First(); var mimeCertificate = signature.SignerCertificate as SecureMimeDigitalCertificate; // Verify if the certificate used by the receiving Access Point in // the response message does not match its certificate published by the SMP Debug.Assert(mimeCertificate != null, nameof(mimeCertificate) + " != null"); X509Certificate certificate = mimeCertificate.Certificate; if (!this.transmissionRequest.GetEndpoint().Certificate.Equals(certificate)) { throw new HyperwayTransmissionException( String.Format( "Certificate in MDN ('{0}') does not match certificate from SMP ('{1}').", certificate.SubjectDN, // .getSubjectX500Principal().getName(), this.transmissionRequest.GetEndpoint().Certificate.SubjectDN)); // .getSubjectX500Principal().getName())); } Logger.Debug("MDN signature was verified for : " + certificate.SubjectDN); } // Verifies the actual MDN MdnMimeMessageInspector mdnMimeMessageInspector = new MdnMimeMessageInspector(mimeMessage); String msg = mdnMimeMessageInspector.GetPlainTextPartAsText(); if (!mdnMimeMessageInspector.IsOkOrWarning(new Mic(this.outboundMic))) { Logger.ErrorFormat("AS2 transmission failed with some error message '{0}'.", msg); throw new HyperwayTransmissionException(String.Format("AS2 transmission failed : {0}", msg)); } // Read structured content MimeEntity mimeBodyPart = mdnMimeMessageInspector.GetMessageDispositionNotificationPart(); var internetHeaders = mimeBodyPart.Headers; // InternetHeaders internetHeaders = new InternetHeaders((InputStream)mimeBodyPart.getContent()); // Fetch timestamp if set DateTime date = t3.GetDate(); if (internetHeaders.Any(x => x.Field == MdnHeader.Date)) { var dateText = internetHeaders.First(x => x.Field == MdnHeader.Date).Value; date = As2DateUtil.Rfc822.Parse(dateText); } // Return TransmissionResponse return(new As2TransmissionResponse( this.transmissionIdentifier, this.transmissionRequest, this.outboundMic, MimeMessageHelper.ToBytes(mimeMessage), t3, date)); } catch (TimestampException e) { throw new HyperwayTransmissionException(e.Message, e); } catch (Exception e) { throw new HyperwayTransmissionException("Unable to parse received content.", e); } finally { span.Record(Annotations.ClientRecv()); } }