/// <summary> /// Gets the version of the DKIM-Signature header with the signature appended, along with /// the CRLF. /// </summary> /// <param name="unsignedDkimHeader">The unsigned DKIM header, to use as a template.</param> /// <param name="canonicalizedHeaders">The headers to be included as part of the signature.</param> /// <returns>The signed DKIM-Signature header.</returns> private string GetSignedDkimHeader( string unsignedDkimHeader, IEnumerable<string> canonicalizedHeaders, DomainElement domain ) { byte[] signatureBytes; string signatureText; StringBuilder signedDkimHeader; using (var stream = new MemoryStream()) { using (var writer = new StreamWriter(stream)) { foreach (var canonicalizedHeader in canonicalizedHeaders) { writer.Write(canonicalizedHeader); } writer.Write(unsignedDkimHeader); writer.Flush(); stream.Seek(0, SeekOrigin.Begin); // Why not pass this.hashAlgorithm here, since we already have it? If we're supporting // Exchange 2007, then we're stuck on CLR 2.0. The SHA-256 functionality was added in // .NET 3.5 SP1, but it was done in such a way that the switch statement used internally // by the Crypto .NET classes won't recognize the new SHA256CryptoServiceProvider type. // So, we have to use the string method instead. More details available at // http://blogs.msdn.com/b/shawnfa/archive/2008/08/25/using-rsacryptoserviceprovider-for-rsa-sha256-signatures.aspx signatureBytes = domain.CryptoProvider.SignData(stream, this.hashAlgorithmCryptoCode); } } signatureText = Convert.ToBase64String(signatureBytes); signedDkimHeader = new StringBuilder(unsignedDkimHeader.Substring(0, unsignedDkimHeader.Length - 1)); signedDkimHeader.Append(signatureText); signedDkimHeader.Append(";\r\n"); return signedDkimHeader.ToString(); }
/// <summary> /// Builds an unsigned DKIM-Signature header. Note that the returned /// header will NOT have a CRLF at the end. /// </summary> /// <param name="bodyHash">The hash of the body.</param> /// <returns>The unsigned DKIM-Signature header.</returns> private string GetUnsignedDkimHeader(string bodyHash, DomainElement domain) { return string.Format( CultureInfo.InvariantCulture, "DKIM-Signature: v=1; a={0}; s={1}; d={2}; c=simple/simple; q=dns/txt; h={3}; bh={4}; b=;", this.hashAlgorithmDkimCode, domain.Selector, domain.Domain, string.Join(" : ", this.eligibleHeaders.OrderBy(x => x, StringComparer.Ordinal).ToArray()), bodyHash); }
/// <summary> /// Initializes various settings based on configuration. /// </summary> private void Initialize() { // Load the signing algorithm. try { this.algorithm = (DkimAlgorithmKind)Enum.Parse( typeof(DkimAlgorithmKind), Properties.Settings.Default.Algorithm, true); } catch (Exception ex) { throw new ConfigurationErrorsException( Resources.DkimSigningRoutingAgentFactory_BadAlgorithmConfig, ex); } // Load the list of headers to sign in each message. var unparsedHeaders = Properties.Settings.Default.HeadersToSign; if (unparsedHeaders != null) { this.headersToSign = unparsedHeaders .Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); } try { XmlDocument xmlDoc = new XmlDocument(); //* create an xml document object. xmlDoc.Load(this.GetType().Assembly.Location + ".config"); //* load the XML document from the specified file. XmlNodeList domainInfoList = xmlDoc.GetElementsByTagName("domainInfo"); if (domainInfoList == null || domainInfoList.Count != 1) { Logger.LogError("There is an error in your configuration file. domainInfo couldn't be initialized properly."); return; } XmlNode domainInfo = domainInfoList.Item(0); domainSettings = new List<DomainElement>(); foreach (XmlNode n in domainInfo.ChildNodes) { DomainElement e = new DomainElement(); e.Domain = n.Attributes["Domain"].Value; e.Selector = n.Attributes["Selector"].Value; e.PrivateKeyFile = n.Attributes["PrivateKeyFile"].Value; if (e.initElement(Path.GetDirectoryName(this.GetType().Assembly.Location))) domainSettings.Add(e); } if (domainSettings.Count == 0) { Logger.LogWarning("No domain configuration found. DKIM will do nothing."); } } catch (Exception e) { Logger.LogError("Couldn't load config: " + e.ToString()); } Logger.LogInformation("Exchange DKIM started. Algorithm: " + algorithm.ToString() + " Number of domains: " + domainSettings.Count); }