// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// [....]
//
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Xml;
namespace System.Security.Cryptography.Xml {
///
/// Trace support for debugging issues signing and verifying XML signatures.
///
internal static class SignedXmlDebugLog {
//
// In order to enable XML digital signature debug loggging, applications should setup their config
// file to be similar to the following:
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
private const string NullString = "(null)";
private static TraceSource s_traceSource = new TraceSource("System.Security.Cryptography.Xml.SignedXml");
private static bool? s_verboseLogging;
private static bool? s_informationLogging;
///
/// Types of events that are logged to the debug log
///
internal enum SignedXmlDebugEvent {
///
/// Canonicalization of input XML has begun
///
BeginCanonicalization,
///
/// Verificaiton of the signature format itself is beginning
///
BeginCheckSignatureFormat,
///
/// Verification of a signed info is beginning
///
BeginCheckSignedInfo,
///
/// Signing is beginning
///
BeginSignatureComputation,
///
/// Signature verification is beginning
///
BeginSignatureVerification,
///
/// Input data has been transformed to its canonicalized form
///
CanonicalizedData,
///
/// The result of signature format validation
///
FormatValidationResult,
///
/// Namespaces are being propigated into the signature
///
NamespacePropagation,
///
/// Output from a Reference
///
ReferenceData,
///
/// The result of a signature verification
///
SignatureVerificationResult,
///
/// Calculating the final signature
///
Signing,
///
/// A reference is being hashed
///
SigningReference,
///
/// A signature has failed to verify
///
VerificationFailure,
///
/// Verify that a reference has the correct hash value
///
VerifyReference,
///
/// Verification is processing the SignedInfo section of the signature
///
VerifySignedInfo,
///
/// Verification status on the x.509 certificate in use
///
X509Verification
}
///
/// Check to see if logging should be done in this process
///
private static bool InformationLoggingEnabled {
get {
if (!s_informationLogging.HasValue) {
s_informationLogging = s_traceSource.Switch.ShouldTrace(TraceEventType.Information);
}
return s_informationLogging.Value;
}
}
///
/// Check to see if verbose log messages should be generated
///
private static bool VerboseLoggingEnabled {
get {
if (!s_verboseLogging.HasValue) {
s_verboseLogging = s_traceSource.Switch.ShouldTrace(TraceEventType.Verbose);
}
return s_verboseLogging.Value;
}
}
///
/// Convert the byte array into a hex string
///
private static string FormatBytes(byte[] bytes) {
if (bytes == null)
return NullString;
StringBuilder builder = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes) {
builder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return builder.ToString();
}
///
/// Map a key to a string describing the key
///
private static string GetKeyName(object key) {
Debug.Assert(key != null, "key != null");
ICspAsymmetricAlgorithm cspKey = key as ICspAsymmetricAlgorithm;
X509Certificate certificate = key as X509Certificate;
X509Certificate2 certificate2 = key as X509Certificate2;
//
// Use the following sources for key names, if available:
//
// * CAPI key -> key container name
// * X509Certificate2 -> subject simple name
// * X509Certificate -> subject name
// * All others -> hash code
//
string keyName = null;
if (cspKey != null && cspKey.CspKeyContainerInfo.KeyContainerName != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
cspKey.CspKeyContainerInfo.KeyContainerName);
}
else if (certificate2 != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
certificate2.GetNameInfo(X509NameType.SimpleName, false));
}
else if (certificate != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
certificate.Subject);
}
else {
keyName = key.GetHashCode().ToString("x8", CultureInfo.InvariantCulture);
}
return String.Format(CultureInfo.InvariantCulture, "{0}#{1}", key.GetType().Name, keyName);
}
///
/// Map an object to a string describing the object
///
private static string GetObjectId(object o) {
Debug.Assert(o != null, "o != null");
return String.Format(CultureInfo.InvariantCulture,
"{0}#{1}", o.GetType().Name,
o.GetHashCode().ToString("x8", CultureInfo.InvariantCulture));
}
///
/// Map an OID to the friendliest name possible
///
private static string GetOidName(Oid oid) {
Debug.Assert(oid != null, "oid != null");
string friendlyName = oid.FriendlyName;
if (String.IsNullOrEmpty(friendlyName))
friendlyName = oid.Value;
return friendlyName;
}
///
/// Log that canonicalization has begun on input data
///
/// SignedXml object doing the signing or verification
/// transform canonicalizing the input
internal static void LogBeginCanonicalization(SignedXml signedXml, Transform canonicalizationTransform) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(canonicalizationTransform != null, "canonicalizationTransform != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_BeginCanonicalization"),
canonicalizationTransform.Algorithm,
canonicalizationTransform.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginCanonicalization,
logMessage);
}
if (VerboseLoggingEnabled) {
string canonicalizationSettings = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CanonicalizationSettings"),
canonicalizationTransform.Resolver.GetType(),
canonicalizationTransform.BaseURI);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginCanonicalization,
canonicalizationSettings);
}
}
///
/// Log that we're going to be validating the signature format itself
///
/// SignedXml object doing the verification
/// Callback delegate which is being used for format verification
internal static void LogBeginCheckSignatureFormat(SignedXml signedXml, Func formatValidator) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(formatValidator != null, "formatValidator != null");
if (InformationLoggingEnabled) {
MethodInfo validationMethod = formatValidator.Method;
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CheckSignatureFormat"),
validationMethod.Module.Assembly.FullName,
validationMethod.DeclaringType.FullName,
validationMethod.Name);
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.BeginCheckSignatureFormat, logMessage);
}
}
///
/// Log that checking SignedInfo is beginning
///
/// SignedXml object doing the verification
/// SignedInfo object being verified
internal static void LogBeginCheckSignedInfo(SignedXml signedXml, SignedInfo signedInfo) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signedInfo != null, " signedInfo != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CheckSignedInfo"),
signedInfo.Id != null ? signedInfo.Id : NullString);
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.BeginCheckSignedInfo, logMessage);
}
}
///
/// Log that signature computation is beginning
///
/// SignedXml object doing the signing
/// Context of the signature
internal static void LogBeginSignatureComputation(SignedXml signedXml, XmlElement context) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginSignatureComputation,
SecurityResources.GetResourceString("Log_BeginSignatureComputation"));
}
if (VerboseLoggingEnabled) {
string contextData = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_XmlContext"),
context != null ? context.OuterXml : NullString);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginSignatureComputation,
contextData);
}
}
///
/// Log that signature verification is beginning
///
/// SignedXml object doing the verification
/// Context of the verification
internal static void LogBeginSignatureVerification(SignedXml signedXml, XmlElement context) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginSignatureVerification,
SecurityResources.GetResourceString("Log_BeginSignatureVerification"));
}
if (VerboseLoggingEnabled) {
string contextData = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_XmlContext"),
context != null ? context.OuterXml : NullString);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginSignatureVerification,
contextData);
}
}
///
/// Log the canonicalized data
///
/// SignedXml object doing the signing or verification
/// transform canonicalizing the input
internal static void LogCanonicalizedOutput(SignedXml signedXml, Transform canonicalizationTransform) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(canonicalizationTransform != null, "canonicalizationTransform != null");
if (VerboseLoggingEnabled) {
using (StreamReader reader = new StreamReader(canonicalizationTransform.GetOutput(typeof(Stream)) as Stream)) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CanonicalizedOutput"),
reader.ReadToEnd());
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.CanonicalizedData,
logMessage);
}
}
}
///
/// Log that the signature format callback has rejected the signature
///
/// SignedXml object doing the signature verification
/// result of the signature format verification
internal static void LogFormatValidationResult(SignedXml signedXml, bool result) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
string logMessage = result ? SecurityResources.GetResourceString("Log_FormatValidationSuccessful") :
SecurityResources.GetResourceString("Log_FormatValidationNotSuccessful");
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.FormatValidationResult, logMessage);
}
}
///
/// Log namespaces which are being propigated into the singature
///
/// SignedXml doing the signing or verification
/// namespaces being propigated
internal static void LogNamespacePropagation(SignedXml signedXml, XmlNodeList namespaces) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
if (namespaces != null) {
foreach (XmlAttribute propagatedNamespace in namespaces) {
string propagationMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_PropagatingNamespace"),
propagatedNamespace.Name,
propagatedNamespace.Value);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.NamespacePropagation,
propagationMessage);
}
}
else {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.NamespacePropagation,
SecurityResources.GetResourceString("Log_NoNamespacesPropagated"));
}
}
}
///
/// Log the output of a reference
///
/// The reference being processed
/// Stream containing the output of the reference
/// Stream containing the output of the reference
internal static Stream LogReferenceData(Reference reference, Stream data) {
if (VerboseLoggingEnabled) {
//
// Since the input data stream could be from the network or another source that does not
// support rewinding, we will read the stream into a temporary MemoryStream that can be used
// to stringify the output and also return to the reference so that it can produce the hash
// value.
//
MemoryStream ms = new MemoryStream();
// First read the input stream into our temporary stream
byte[] buffer = new byte[4096];
int readBytes = 0;
do {
readBytes = data.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
} while (readBytes == buffer.Length);
// Log out information about it
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_TransformedReferenceContents"),
Encoding.UTF8.GetString(ms.ToArray()));
WriteLine(reference,
TraceEventType.Verbose,
SignedXmlDebugEvent.ReferenceData,
logMessage);
// Rewind to the beginning, so that the entire input stream is hashed
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
else {
return data;
}
}
///
/// Log the computation of a signature value when signing with an asymmetric algorithm
///
/// SignedXml object calculating the signature
/// key used for signing
/// signature description being used to create the signature
/// hash algorithm used to digest the output
/// signature formatter used to do the signing
internal static void LogSigning(SignedXml signedXml,
object key,
SignatureDescription signatureDescription,
HashAlgorithm hash,
AsymmetricSignatureFormatter asymmetricSignatureFormatter) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signatureDescription != null, "signatureDescription != null");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(asymmetricSignatureFormatter != null, "asymmetricSignatureFormatter != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningAsymmetric"),
GetKeyName(key),
signatureDescription.GetType().Name,
hash.GetType().Name,
asymmetricSignatureFormatter.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.Signing,
logMessage);
}
}
///
/// Log the computation of a signature value when signing with a keyed hash algorithm
///
/// SignedXml object calculating the signature
/// key the signature is created with
/// hash algorithm used to digest the output
/// signature formatter used to do the signing
internal static void LogSigning(SignedXml signedXml, KeyedHashAlgorithm key) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(key != null, "key != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningHmac"),
key.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.Signing,
logMessage);
}
}
///
/// Log the calculation of a hash value of a reference
///
/// SignedXml object driving the signature
/// Reference being hashed
internal static void LogSigningReference(SignedXml signedXml, Reference reference) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
if (VerboseLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningReference"),
GetObjectId(reference),
reference.Uri,
reference.Id,
reference.Type,
reference.DigestMethod,
CryptoConfig.CreateFromName(reference.DigestMethod).GetType().Name);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.SigningReference,
logMessage);
}
}
///
/// Log the specific point where a signature is determined to not be verifiable
///
/// SignedXml object doing the verification
/// location that the signature was determined to be invalid
internal static void LogVerificationFailure(SignedXml signedXml, string failureLocation) {
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationFailed"),
failureLocation);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerificationFailure,
logMessage);
}
}
///
/// Log the success or failure of a signature verification operation
///
/// SignedXml object doing the verification
/// public key used to verify the signature
/// true if the signature verified, false otherwise
internal static void LogVerificationResult(SignedXml signedXml, object key, bool verified) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(key != null, "key != null");
if (InformationLoggingEnabled) {
string resource = verified ? SecurityResources.GetResourceString("Log_VerificationWithKeySuccessful") :
SecurityResources.GetResourceString("Log_VerificationWithKeyNotSuccessful");
string logMessage = String.Format(CultureInfo.InvariantCulture,
resource,
GetKeyName(key));
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.SignatureVerificationResult,
logMessage);
}
}
///
/// Log the check for appropriate X509 key usage
///
/// SignedXml doing the signature verification
/// certificate having its key usages checked
/// key usages being examined
internal static void LogVerifyKeyUsage(SignedXml signedXml, X509Certificate certificate, X509KeyUsageExtension keyUsages) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(certificate != null, "certificate != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_KeyUsages"),
keyUsages.KeyUsages,
GetOidName(keyUsages.Oid),
GetKeyName(certificate));
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.X509Verification,
logMessage);
}
}
///
/// Log that we are verifying a reference
///
/// SignedXMl object doing the verification
/// reference being verified
internal static void LogVerifyReference(SignedXml signedXml, Reference reference) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifyReference"),
GetObjectId(reference),
reference.Uri,
reference.Id,
reference.Type);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.VerifyReference,
logMessage);
}
}
///
/// Log the hash comparison when verifying a reference
///
/// SignedXml object verifying the signature
/// reference being verified
/// actual hash value of the reference
/// hash value the signature expected the reference to have
internal static void LogVerifyReferenceHash(SignedXml signedXml,
Reference reference,
byte[] actualHash,
byte[] expectedHash) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
Debug.Assert(actualHash != null, "actualHash != null");
Debug.Assert(expectedHash != null, "expectedHash != null");
if (VerboseLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ReferenceHash"),
GetObjectId(reference),
reference.DigestMethod,
CryptoConfig.CreateFromName(reference.DigestMethod).GetType().Name,
FormatBytes(actualHash),
FormatBytes(expectedHash));
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.VerifyReference,
logMessage);
}
}
///
/// Log the verification parameters when verifying the SignedInfo section of a signature using an
/// asymmetric key
///
/// SignedXml object doing the verification
/// key being used to verify the signed info
/// type of signature description class used
/// type of hash algorithm used
/// type of signature deformatter used
/// hash value of the signed info
/// raw signature value
internal static void LogVerifySignedInfo(SignedXml signedXml,
AsymmetricAlgorithm key,
SignatureDescription signatureDescription,
HashAlgorithm hashAlgorithm,
AsymmetricSignatureDeformatter asymmetricSignatureDeformatter,
byte[] actualHashValue,
byte[] signatureValue) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signatureDescription != null, "signatureDescription != null");
Debug.Assert(hashAlgorithm != null, "hashAlgorithm != null");
Debug.Assert(asymmetricSignatureDeformatter != null, "asymmetricSignatureDeformatter != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifySignedInfoAsymmetric"),
GetKeyName(key),
signatureDescription.GetType().Name,
hashAlgorithm.GetType().Name,
asymmetricSignatureDeformatter.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerifySignedInfo,
logMessage);
}
if (VerboseLoggingEnabled) {
string hashLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ActualHashValue"),
FormatBytes(actualHashValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, hashLog);
string signatureLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RawSignatureValue"),
FormatBytes(signatureValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, signatureLog);
}
}
///
/// Log the verification parameters when verifying the SignedInfo section of a signature using a
/// keyed hash algorithm
///
/// SignedXml object doing the verification
/// hash algoirthm doing the verification
/// hash value of the signed info
/// raw signature value
internal static void LogVerifySignedInfo(SignedXml signedXml,
KeyedHashAlgorithm mac,
byte[] actualHashValue,
byte[] signatureValue) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(mac != null, "mac != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifySignedInfoHmac"),
mac.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerifySignedInfo,
logMessage);
}
if (VerboseLoggingEnabled) {
string hashLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ActualHashValue"),
FormatBytes(actualHashValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, hashLog);
string signatureLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RawSignatureValue"),
FormatBytes(signatureValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, signatureLog);
}
}
///
/// Log that an X509 chain is being built for a certificate
///
/// SignedXml object building the chain
/// chain built for the certificate
/// certificate having the chain built for it
internal static void LogVerifyX509Chain(SignedXml signedXml, X509Chain chain, X509Certificate certificate) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(certificate != null, "certificate != null");
Debug.Assert(chain != null, "chain != null");
if (InformationLoggingEnabled) {
string buildMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_BuildX509Chain"),
GetKeyName(certificate));
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.X509Verification,
buildMessage);
}
if (VerboseLoggingEnabled) {
// Dump out the flags and other miscelanious information used for building
string revocationMode = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RevocationMode"),
chain.ChainPolicy.RevocationFlag);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationMode);
string revocationFlag = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RevocationFlag"),
chain.ChainPolicy.RevocationFlag);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationFlag);
string verificationFlags = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationFlag"),
chain.ChainPolicy.VerificationFlags);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationFlags);
string verificationTime = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationTime"),
chain.ChainPolicy.VerificationTime);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationTime);
string urlTimeout = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_UrlTimeout"),
chain.ChainPolicy.UrlRetrievalTimeout);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, urlTimeout);
}
// If there were any errors in the chain, make sure to dump those out
if (InformationLoggingEnabled) {
foreach (X509ChainStatus status in chain.ChainStatus) {
if (status.Status != X509ChainStatusFlags.NoError) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_X509ChainError"),
status.Status,
status.StatusInformation);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.X509Verification,
logMessage);
}
}
}
// Finally, dump out the chain itself
if (VerboseLoggingEnabled) {
StringBuilder chainElements = new StringBuilder();
chainElements.Append(SecurityResources.GetResourceString("Log_CertificateChain"));
foreach (X509ChainElement element in chain.ChainElements) {
chainElements.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetKeyName(element.Certificate));
}
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.X509Verification,
chainElements.ToString());
}
}
///
/// Write data to the log
///
/// object doing the trace
/// severity of the debug event
/// data being written
/// type of event being traced
private static void WriteLine(object source, TraceEventType eventType, SignedXmlDebugEvent eventId, string data) {
Debug.Assert(source != null, "source != null");
Debug.Assert(!String.IsNullOrEmpty(data), "!String.IsNullOrEmpty(data)");
Debug.Assert(InformationLoggingEnabled, "InformationLoggingEnabled");
s_traceSource.TraceEvent(eventType,
(int)eventId,
"[{0}, {1}] {2}",
GetObjectId(source),
eventId,
data);
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// [....]
//
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Xml;
namespace System.Security.Cryptography.Xml {
///
/// Trace support for debugging issues signing and verifying XML signatures.
///
internal static class SignedXmlDebugLog {
//
// In order to enable XML digital signature debug loggging, applications should setup their config
// file to be similar to the following:
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
private const string NullString = "(null)";
private static TraceSource s_traceSource = new TraceSource("System.Security.Cryptography.Xml.SignedXml");
private static bool? s_verboseLogging;
private static bool? s_informationLogging;
///
/// Types of events that are logged to the debug log
///
internal enum SignedXmlDebugEvent {
///
/// Canonicalization of input XML has begun
///
BeginCanonicalization,
///
/// Verificaiton of the signature format itself is beginning
///
BeginCheckSignatureFormat,
///
/// Verification of a signed info is beginning
///
BeginCheckSignedInfo,
///
/// Signing is beginning
///
BeginSignatureComputation,
///
/// Signature verification is beginning
///
BeginSignatureVerification,
///
/// Input data has been transformed to its canonicalized form
///
CanonicalizedData,
///
/// The result of signature format validation
///
FormatValidationResult,
///
/// Namespaces are being propigated into the signature
///
NamespacePropagation,
///
/// Output from a Reference
///
ReferenceData,
///
/// The result of a signature verification
///
SignatureVerificationResult,
///
/// Calculating the final signature
///
Signing,
///
/// A reference is being hashed
///
SigningReference,
///
/// A signature has failed to verify
///
VerificationFailure,
///
/// Verify that a reference has the correct hash value
///
VerifyReference,
///
/// Verification is processing the SignedInfo section of the signature
///
VerifySignedInfo,
///
/// Verification status on the x.509 certificate in use
///
X509Verification
}
///
/// Check to see if logging should be done in this process
///
private static bool InformationLoggingEnabled {
get {
if (!s_informationLogging.HasValue) {
s_informationLogging = s_traceSource.Switch.ShouldTrace(TraceEventType.Information);
}
return s_informationLogging.Value;
}
}
///
/// Check to see if verbose log messages should be generated
///
private static bool VerboseLoggingEnabled {
get {
if (!s_verboseLogging.HasValue) {
s_verboseLogging = s_traceSource.Switch.ShouldTrace(TraceEventType.Verbose);
}
return s_verboseLogging.Value;
}
}
///
/// Convert the byte array into a hex string
///
private static string FormatBytes(byte[] bytes) {
if (bytes == null)
return NullString;
StringBuilder builder = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes) {
builder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return builder.ToString();
}
///
/// Map a key to a string describing the key
///
private static string GetKeyName(object key) {
Debug.Assert(key != null, "key != null");
ICspAsymmetricAlgorithm cspKey = key as ICspAsymmetricAlgorithm;
X509Certificate certificate = key as X509Certificate;
X509Certificate2 certificate2 = key as X509Certificate2;
//
// Use the following sources for key names, if available:
//
// * CAPI key -> key container name
// * X509Certificate2 -> subject simple name
// * X509Certificate -> subject name
// * All others -> hash code
//
string keyName = null;
if (cspKey != null && cspKey.CspKeyContainerInfo.KeyContainerName != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
cspKey.CspKeyContainerInfo.KeyContainerName);
}
else if (certificate2 != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
certificate2.GetNameInfo(X509NameType.SimpleName, false));
}
else if (certificate != null) {
keyName = String.Format(CultureInfo.InvariantCulture,
"\"{0}\"",
certificate.Subject);
}
else {
keyName = key.GetHashCode().ToString("x8", CultureInfo.InvariantCulture);
}
return String.Format(CultureInfo.InvariantCulture, "{0}#{1}", key.GetType().Name, keyName);
}
///
/// Map an object to a string describing the object
///
private static string GetObjectId(object o) {
Debug.Assert(o != null, "o != null");
return String.Format(CultureInfo.InvariantCulture,
"{0}#{1}", o.GetType().Name,
o.GetHashCode().ToString("x8", CultureInfo.InvariantCulture));
}
///
/// Map an OID to the friendliest name possible
///
private static string GetOidName(Oid oid) {
Debug.Assert(oid != null, "oid != null");
string friendlyName = oid.FriendlyName;
if (String.IsNullOrEmpty(friendlyName))
friendlyName = oid.Value;
return friendlyName;
}
///
/// Log that canonicalization has begun on input data
///
/// SignedXml object doing the signing or verification
/// transform canonicalizing the input
internal static void LogBeginCanonicalization(SignedXml signedXml, Transform canonicalizationTransform) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(canonicalizationTransform != null, "canonicalizationTransform != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_BeginCanonicalization"),
canonicalizationTransform.Algorithm,
canonicalizationTransform.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginCanonicalization,
logMessage);
}
if (VerboseLoggingEnabled) {
string canonicalizationSettings = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CanonicalizationSettings"),
canonicalizationTransform.Resolver.GetType(),
canonicalizationTransform.BaseURI);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginCanonicalization,
canonicalizationSettings);
}
}
///
/// Log that we're going to be validating the signature format itself
///
/// SignedXml object doing the verification
/// Callback delegate which is being used for format verification
internal static void LogBeginCheckSignatureFormat(SignedXml signedXml, Func formatValidator) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(formatValidator != null, "formatValidator != null");
if (InformationLoggingEnabled) {
MethodInfo validationMethod = formatValidator.Method;
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CheckSignatureFormat"),
validationMethod.Module.Assembly.FullName,
validationMethod.DeclaringType.FullName,
validationMethod.Name);
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.BeginCheckSignatureFormat, logMessage);
}
}
///
/// Log that checking SignedInfo is beginning
///
/// SignedXml object doing the verification
/// SignedInfo object being verified
internal static void LogBeginCheckSignedInfo(SignedXml signedXml, SignedInfo signedInfo) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signedInfo != null, " signedInfo != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CheckSignedInfo"),
signedInfo.Id != null ? signedInfo.Id : NullString);
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.BeginCheckSignedInfo, logMessage);
}
}
///
/// Log that signature computation is beginning
///
/// SignedXml object doing the signing
/// Context of the signature
internal static void LogBeginSignatureComputation(SignedXml signedXml, XmlElement context) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginSignatureComputation,
SecurityResources.GetResourceString("Log_BeginSignatureComputation"));
}
if (VerboseLoggingEnabled) {
string contextData = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_XmlContext"),
context != null ? context.OuterXml : NullString);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginSignatureComputation,
contextData);
}
}
///
/// Log that signature verification is beginning
///
/// SignedXml object doing the verification
/// Context of the verification
internal static void LogBeginSignatureVerification(SignedXml signedXml, XmlElement context) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.BeginSignatureVerification,
SecurityResources.GetResourceString("Log_BeginSignatureVerification"));
}
if (VerboseLoggingEnabled) {
string contextData = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_XmlContext"),
context != null ? context.OuterXml : NullString);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.BeginSignatureVerification,
contextData);
}
}
///
/// Log the canonicalized data
///
/// SignedXml object doing the signing or verification
/// transform canonicalizing the input
internal static void LogCanonicalizedOutput(SignedXml signedXml, Transform canonicalizationTransform) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(canonicalizationTransform != null, "canonicalizationTransform != null");
if (VerboseLoggingEnabled) {
using (StreamReader reader = new StreamReader(canonicalizationTransform.GetOutput(typeof(Stream)) as Stream)) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_CanonicalizedOutput"),
reader.ReadToEnd());
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.CanonicalizedData,
logMessage);
}
}
}
///
/// Log that the signature format callback has rejected the signature
///
/// SignedXml object doing the signature verification
/// result of the signature format verification
internal static void LogFormatValidationResult(SignedXml signedXml, bool result) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
string logMessage = result ? SecurityResources.GetResourceString("Log_FormatValidationSuccessful") :
SecurityResources.GetResourceString("Log_FormatValidationNotSuccessful");
WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.FormatValidationResult, logMessage);
}
}
///
/// Log namespaces which are being propigated into the singature
///
/// SignedXml doing the signing or verification
/// namespaces being propigated
internal static void LogNamespacePropagation(SignedXml signedXml, XmlNodeList namespaces) {
Debug.Assert(signedXml != null, "signedXml != null");
if (InformationLoggingEnabled) {
if (namespaces != null) {
foreach (XmlAttribute propagatedNamespace in namespaces) {
string propagationMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_PropagatingNamespace"),
propagatedNamespace.Name,
propagatedNamespace.Value);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.NamespacePropagation,
propagationMessage);
}
}
else {
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.NamespacePropagation,
SecurityResources.GetResourceString("Log_NoNamespacesPropagated"));
}
}
}
///
/// Log the output of a reference
///
/// The reference being processed
/// Stream containing the output of the reference
/// Stream containing the output of the reference
internal static Stream LogReferenceData(Reference reference, Stream data) {
if (VerboseLoggingEnabled) {
//
// Since the input data stream could be from the network or another source that does not
// support rewinding, we will read the stream into a temporary MemoryStream that can be used
// to stringify the output and also return to the reference so that it can produce the hash
// value.
//
MemoryStream ms = new MemoryStream();
// First read the input stream into our temporary stream
byte[] buffer = new byte[4096];
int readBytes = 0;
do {
readBytes = data.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
} while (readBytes == buffer.Length);
// Log out information about it
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_TransformedReferenceContents"),
Encoding.UTF8.GetString(ms.ToArray()));
WriteLine(reference,
TraceEventType.Verbose,
SignedXmlDebugEvent.ReferenceData,
logMessage);
// Rewind to the beginning, so that the entire input stream is hashed
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
else {
return data;
}
}
///
/// Log the computation of a signature value when signing with an asymmetric algorithm
///
/// SignedXml object calculating the signature
/// key used for signing
/// signature description being used to create the signature
/// hash algorithm used to digest the output
/// signature formatter used to do the signing
internal static void LogSigning(SignedXml signedXml,
object key,
SignatureDescription signatureDescription,
HashAlgorithm hash,
AsymmetricSignatureFormatter asymmetricSignatureFormatter) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signatureDescription != null, "signatureDescription != null");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(asymmetricSignatureFormatter != null, "asymmetricSignatureFormatter != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningAsymmetric"),
GetKeyName(key),
signatureDescription.GetType().Name,
hash.GetType().Name,
asymmetricSignatureFormatter.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.Signing,
logMessage);
}
}
///
/// Log the computation of a signature value when signing with a keyed hash algorithm
///
/// SignedXml object calculating the signature
/// key the signature is created with
/// hash algorithm used to digest the output
/// signature formatter used to do the signing
internal static void LogSigning(SignedXml signedXml, KeyedHashAlgorithm key) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(key != null, "key != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningHmac"),
key.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.Signing,
logMessage);
}
}
///
/// Log the calculation of a hash value of a reference
///
/// SignedXml object driving the signature
/// Reference being hashed
internal static void LogSigningReference(SignedXml signedXml, Reference reference) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
if (VerboseLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_SigningReference"),
GetObjectId(reference),
reference.Uri,
reference.Id,
reference.Type,
reference.DigestMethod,
CryptoConfig.CreateFromName(reference.DigestMethod).GetType().Name);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.SigningReference,
logMessage);
}
}
///
/// Log the specific point where a signature is determined to not be verifiable
///
/// SignedXml object doing the verification
/// location that the signature was determined to be invalid
internal static void LogVerificationFailure(SignedXml signedXml, string failureLocation) {
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationFailed"),
failureLocation);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerificationFailure,
logMessage);
}
}
///
/// Log the success or failure of a signature verification operation
///
/// SignedXml object doing the verification
/// public key used to verify the signature
/// true if the signature verified, false otherwise
internal static void LogVerificationResult(SignedXml signedXml, object key, bool verified) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(key != null, "key != null");
if (InformationLoggingEnabled) {
string resource = verified ? SecurityResources.GetResourceString("Log_VerificationWithKeySuccessful") :
SecurityResources.GetResourceString("Log_VerificationWithKeyNotSuccessful");
string logMessage = String.Format(CultureInfo.InvariantCulture,
resource,
GetKeyName(key));
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.SignatureVerificationResult,
logMessage);
}
}
///
/// Log the check for appropriate X509 key usage
///
/// SignedXml doing the signature verification
/// certificate having its key usages checked
/// key usages being examined
internal static void LogVerifyKeyUsage(SignedXml signedXml, X509Certificate certificate, X509KeyUsageExtension keyUsages) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(certificate != null, "certificate != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_KeyUsages"),
keyUsages.KeyUsages,
GetOidName(keyUsages.Oid),
GetKeyName(certificate));
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.X509Verification,
logMessage);
}
}
///
/// Log that we are verifying a reference
///
/// SignedXMl object doing the verification
/// reference being verified
internal static void LogVerifyReference(SignedXml signedXml, Reference reference) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifyReference"),
GetObjectId(reference),
reference.Uri,
reference.Id,
reference.Type);
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.VerifyReference,
logMessage);
}
}
///
/// Log the hash comparison when verifying a reference
///
/// SignedXml object verifying the signature
/// reference being verified
/// actual hash value of the reference
/// hash value the signature expected the reference to have
internal static void LogVerifyReferenceHash(SignedXml signedXml,
Reference reference,
byte[] actualHash,
byte[] expectedHash) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(reference != null, "reference != null");
Debug.Assert(actualHash != null, "actualHash != null");
Debug.Assert(expectedHash != null, "expectedHash != null");
if (VerboseLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ReferenceHash"),
GetObjectId(reference),
reference.DigestMethod,
CryptoConfig.CreateFromName(reference.DigestMethod).GetType().Name,
FormatBytes(actualHash),
FormatBytes(expectedHash));
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.VerifyReference,
logMessage);
}
}
///
/// Log the verification parameters when verifying the SignedInfo section of a signature using an
/// asymmetric key
///
/// SignedXml object doing the verification
/// key being used to verify the signed info
/// type of signature description class used
/// type of hash algorithm used
/// type of signature deformatter used
/// hash value of the signed info
/// raw signature value
internal static void LogVerifySignedInfo(SignedXml signedXml,
AsymmetricAlgorithm key,
SignatureDescription signatureDescription,
HashAlgorithm hashAlgorithm,
AsymmetricSignatureDeformatter asymmetricSignatureDeformatter,
byte[] actualHashValue,
byte[] signatureValue) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(signatureDescription != null, "signatureDescription != null");
Debug.Assert(hashAlgorithm != null, "hashAlgorithm != null");
Debug.Assert(asymmetricSignatureDeformatter != null, "asymmetricSignatureDeformatter != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifySignedInfoAsymmetric"),
GetKeyName(key),
signatureDescription.GetType().Name,
hashAlgorithm.GetType().Name,
asymmetricSignatureDeformatter.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerifySignedInfo,
logMessage);
}
if (VerboseLoggingEnabled) {
string hashLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ActualHashValue"),
FormatBytes(actualHashValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, hashLog);
string signatureLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RawSignatureValue"),
FormatBytes(signatureValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, signatureLog);
}
}
///
/// Log the verification parameters when verifying the SignedInfo section of a signature using a
/// keyed hash algorithm
///
/// SignedXml object doing the verification
/// hash algoirthm doing the verification
/// hash value of the signed info
/// raw signature value
internal static void LogVerifySignedInfo(SignedXml signedXml,
KeyedHashAlgorithm mac,
byte[] actualHashValue,
byte[] signatureValue) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(mac != null, "mac != null");
if (InformationLoggingEnabled) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerifySignedInfoHmac"),
mac.GetType().Name);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.VerifySignedInfo,
logMessage);
}
if (VerboseLoggingEnabled) {
string hashLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_ActualHashValue"),
FormatBytes(actualHashValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, hashLog);
string signatureLog = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RawSignatureValue"),
FormatBytes(signatureValue));
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifySignedInfo, signatureLog);
}
}
///
/// Log that an X509 chain is being built for a certificate
///
/// SignedXml object building the chain
/// chain built for the certificate
/// certificate having the chain built for it
internal static void LogVerifyX509Chain(SignedXml signedXml, X509Chain chain, X509Certificate certificate) {
Debug.Assert(signedXml != null, "signedXml != null");
Debug.Assert(certificate != null, "certificate != null");
Debug.Assert(chain != null, "chain != null");
if (InformationLoggingEnabled) {
string buildMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_BuildX509Chain"),
GetKeyName(certificate));
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.X509Verification,
buildMessage);
}
if (VerboseLoggingEnabled) {
// Dump out the flags and other miscelanious information used for building
string revocationMode = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RevocationMode"),
chain.ChainPolicy.RevocationFlag);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationMode);
string revocationFlag = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_RevocationFlag"),
chain.ChainPolicy.RevocationFlag);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationFlag);
string verificationFlags = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationFlag"),
chain.ChainPolicy.VerificationFlags);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationFlags);
string verificationTime = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_VerificationTime"),
chain.ChainPolicy.VerificationTime);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationTime);
string urlTimeout = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_UrlTimeout"),
chain.ChainPolicy.UrlRetrievalTimeout);
WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, urlTimeout);
}
// If there were any errors in the chain, make sure to dump those out
if (InformationLoggingEnabled) {
foreach (X509ChainStatus status in chain.ChainStatus) {
if (status.Status != X509ChainStatusFlags.NoError) {
string logMessage = String.Format(CultureInfo.InvariantCulture,
SecurityResources.GetResourceString("Log_X509ChainError"),
status.Status,
status.StatusInformation);
WriteLine(signedXml,
TraceEventType.Information,
SignedXmlDebugEvent.X509Verification,
logMessage);
}
}
}
// Finally, dump out the chain itself
if (VerboseLoggingEnabled) {
StringBuilder chainElements = new StringBuilder();
chainElements.Append(SecurityResources.GetResourceString("Log_CertificateChain"));
foreach (X509ChainElement element in chain.ChainElements) {
chainElements.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetKeyName(element.Certificate));
}
WriteLine(signedXml,
TraceEventType.Verbose,
SignedXmlDebugEvent.X509Verification,
chainElements.ToString());
}
}
///
/// Write data to the log
///
/// object doing the trace
/// severity of the debug event
/// data being written
/// type of event being traced
private static void WriteLine(object source, TraceEventType eventType, SignedXmlDebugEvent eventId, string data) {
Debug.Assert(source != null, "source != null");
Debug.Assert(!String.IsNullOrEmpty(data), "!String.IsNullOrEmpty(data)");
Debug.Assert(InformationLoggingEnabled, "InformationLoggingEnabled");
s_traceSource.TraceEvent(eventType,
(int)eventId,
"[{0}, {1}] {2}",
GetObjectId(source),
eventId,
data);
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.