Skip to content

Commit

Permalink
Switch files to file-based namespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewlock committed Jul 10, 2023
1 parent 8553c05 commit 36ffc0d
Show file tree
Hide file tree
Showing 155 changed files with 6,940 additions and 7,093 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,90 @@
using System.Security.Cryptography;
using NetEscapades.AspNetCore.SecurityHeaders.Infrastructure;

namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers
namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers;

/// <summary>
/// Helpers for creating hashing algorithms
/// </summary>
internal class CryptographyAlgorithms
{
/// <summary>
/// Helpers for creating hashing algorithms
/// Create an instance of the required hashing algorithm
/// </summary>
internal class CryptographyAlgorithms
/// <param name="algorithm">The CSP algorithm to create</param>
/// <returns>The hashing algorithm instance</returns>
public static HashAlgorithm Create(CSPHashType algorithm)
{
/// <summary>
/// Create an instance of the required hashing algorithm
/// </summary>
/// <param name="algorithm">The CSP algorithm to create</param>
/// <returns>The hashing algorithm instance</returns>
public static HashAlgorithm Create(CSPHashType algorithm)
switch (algorithm)
{
switch (algorithm)
{
case CSPHashType.SHA256:
return CreateSHA256();
case CSPHashType.SHA384:
return CreateSHA384();
case CSPHashType.SHA512:
return CreateSHA512();
default:
throw new InvalidOperationException($"Unknown CSP Hash Type: {algorithm}");
}
case CSPHashType.SHA256:
return CreateSHA256();
case CSPHashType.SHA384:
return CreateSHA384();
case CSPHashType.SHA512:
return CreateSHA512();
default:
throw new InvalidOperationException($"Unknown CSP Hash Type: {algorithm}");
}
}

/// <summary>
/// Creates an instance of <see cref="SHA256"/> or <see cref="SHA256CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA256"/></returns>
private static SHA256 CreateSHA256()
/// <summary>
/// Creates an instance of <see cref="SHA256"/> or <see cref="SHA256CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA256"/></returns>
private static SHA256 CreateSHA256()
{
try
{
try
{
return SHA256.Create();
}
catch (System.Reflection.TargetInvocationException)
{
// SHA256.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA256 algorithm.
return new SHA256CryptoServiceProvider();
}
return SHA256.Create();
}
catch (System.Reflection.TargetInvocationException)
{
// SHA256.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA256 algorithm.
return new SHA256CryptoServiceProvider();
}
}

/// <summary>
/// Creates an instance of <see cref="SHA384" /> or <see cref="SHA384CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA384"/></returns>
private static SHA384 CreateSHA384()
/// <summary>
/// Creates an instance of <see cref="SHA384" /> or <see cref="SHA384CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA384"/></returns>
private static SHA384 CreateSHA384()
{
try
{
return SHA384.Create();
}
catch (System.Reflection.TargetInvocationException)
{
try
{
return SHA384.Create();
}
catch (System.Reflection.TargetInvocationException)
{
// SHA384.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA384 algorithm.
return new SHA384CryptoServiceProvider();
}
// SHA384.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA384 algorithm.
return new SHA384CryptoServiceProvider();
}
}

/// <summary>
/// Creates an instance of <see cref="SHA512"/> or <see cref="SHA512CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA512"/></returns>
private static SHA512 CreateSHA512()
/// <summary>
/// Creates an instance of <see cref="SHA512"/> or <see cref="SHA512CryptoServiceProvider"/> on
/// FIPS compliant machines.
/// </summary>
/// <returns>An instance of <see cref="SHA512"/></returns>
private static SHA512 CreateSHA512()
{
try
{
return SHA512.Create();
}
catch (System.Reflection.TargetInvocationException)
{
try
{
return SHA512.Create();
}
catch (System.Reflection.TargetInvocationException)
{
// SHA512.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA512 algorithm.
return new SHA512CryptoServiceProvider();
}
// SHA512.Create is documented to throw this exception on FIPS compliant machines.
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
// Fallback to a FIPS compliant SHA512 algorithm.
return new SHA512CryptoServiceProvider();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,62 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using NetEscapades.AspNetCore.SecurityHeaders.Infrastructure;

namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers
namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers;

/// <summary>
/// Generates a Hash of the content of the script
/// </summary>
[HtmlTargetElement("script", Attributes = AttributeName)]
[HtmlTargetElement("style", Attributes = AttributeName)]
public class HashTagHelper : TagHelper
{
private const string AttributeName = "asp-add-content-to-csp";
private const string CspHashTypeAttributeName = "csp-hash-type";

/// <summary>
/// Generates a Hash of the content of the script
/// Add a <code>nonce</code> attribute to the element
/// </summary>
[HtmlTargetElement("script", Attributes = AttributeName)]
[HtmlTargetElement("style", Attributes = AttributeName)]
public class HashTagHelper : TagHelper
{
private const string AttributeName = "asp-add-content-to-csp";
private const string CspHashTypeAttributeName = "csp-hash-type";
[HtmlAttributeName(CspHashTypeAttributeName)]
public CSPHashType CSPHashType { get; set; } = CSPHashType.SHA256;

/// <summary>
/// Add a <code>nonce</code> attribute to the element
/// </summary>
[HtmlAttributeName(CspHashTypeAttributeName)]
public CSPHashType CSPHashType { get; set; } = CSPHashType.SHA256;

/// <summary>
/// Provides access to the <see cref="ViewContext"/>
/// </summary>
[ViewContext]
public ViewContext? ViewContext { get; set; }
/// <summary>
/// Provides access to the <see cref="ViewContext"/>
/// </summary>
[ViewContext]
public ViewContext? ViewContext { get; set; }

/// <inheritdoc />
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
/// <inheritdoc />
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (ViewContext is null)
{
if (ViewContext is null)
{
throw new InvalidOperationException("ViewContext was null");
}
throw new InvalidOperationException("ViewContext was null");
}

using (var sha = CryptographyAlgorithms.Create(CSPHashType))
{
var childContent = await output.GetChildContentAsync();
using (var sha = CryptographyAlgorithms.Create(CSPHashType))
{
var childContent = await output.GetChildContentAsync();

// the hash is calculated based on unix line endings, not windows endings, so account for that
var content = childContent.GetContent().Replace("\r\n", "\n");
var contentBytes = Encoding.UTF8.GetBytes(content);
var hashedBytes = sha.ComputeHash(contentBytes);
var hash = Convert.ToBase64String(hashedBytes);
// the hash is calculated based on unix line endings, not windows endings, so account for that
var content = childContent.GetContent().Replace("\r\n", "\n");
var contentBytes = Encoding.UTF8.GetBytes(content);
var hashedBytes = sha.ComputeHash(contentBytes);
var hash = Convert.ToBase64String(hashedBytes);

output.Attributes.RemoveAll(AttributeName);
output.Attributes.RemoveAll(CspHashTypeAttributeName);
output.Attributes.RemoveAll(AttributeName);
output.Attributes.RemoveAll(CspHashTypeAttributeName);

if (context.TagName == "script")
{
ViewContext.HttpContext.SetScriptCSPHash(CSPHashType, hash);
}
else if (context.TagName == "style")
{
ViewContext.HttpContext.SetStylesCSPHash(CSPHashType, hash);
}
else
{
throw new InvalidOperationException("Unexpected tag name: " + context.TagName);
}
if (context.TagName == "script")
{
ViewContext.HttpContext.SetScriptCSPHash(CSPHashType, hash);
}
else if (context.TagName == "style")
{
ViewContext.HttpContext.SetStylesCSPHash(CSPHashType, hash);
}
else
{
throw new InvalidOperationException("Unexpected tag name: " + context.TagName);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,57 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers
namespace NetEscapades.AspNetCore.SecurityHeaders.TagHelpers;

/// <summary>
/// Tag helper for adding a nonce to script and style tags.
/// </summary>
[HtmlTargetElement("script", Attributes = "asp-add-nonce")]
[HtmlTargetElement("style", Attributes = "asp-add-nonce")]
[HtmlTargetElement("frame", Attributes = "asp-add-nonce")]
[HtmlTargetElement("iframe", Attributes = "asp-add-nonce")]
[HtmlTargetElement("img", Attributes = "asp-add-nonce")]
[HtmlTargetElement("audio", Attributes = "asp-add-nonce")]
[HtmlTargetElement("video", Attributes = "asp-add-nonce")]
[HtmlTargetElement("object", Attributes = "asp-add-nonce")]
[HtmlTargetElement("applet", Attributes = "asp-add-nonce")]
[HtmlTargetElement("embed", Attributes = "asp-add-nonce")]
[HtmlTargetElement("base", Attributes = "asp-add-nonce")]
[HtmlTargetElement("link", Attributes = "asp-add-nonce")]
public class NonceTagHelper : TagHelper
{
/// <summary>
/// Tag helper for adding a nonce to script and style tags.
/// Add a <code>nonce</code> attribute to the element
/// </summary>
[HtmlTargetElement("script", Attributes = "asp-add-nonce")]
[HtmlTargetElement("style", Attributes = "asp-add-nonce")]
[HtmlTargetElement("frame", Attributes = "asp-add-nonce")]
[HtmlTargetElement("iframe", Attributes = "asp-add-nonce")]
[HtmlTargetElement("img", Attributes = "asp-add-nonce")]
[HtmlTargetElement("audio", Attributes = "asp-add-nonce")]
[HtmlTargetElement("video", Attributes = "asp-add-nonce")]
[HtmlTargetElement("object", Attributes = "asp-add-nonce")]
[HtmlTargetElement("applet", Attributes = "asp-add-nonce")]
[HtmlTargetElement("embed", Attributes = "asp-add-nonce")]
[HtmlTargetElement("base", Attributes = "asp-add-nonce")]
[HtmlTargetElement("link", Attributes = "asp-add-nonce")]
public class NonceTagHelper : TagHelper
{
/// <summary>
/// Add a <code>nonce</code> attribute to the element
/// </summary>
[HtmlAttributeName("asp-add-nonce")]
public bool AddNonce { get; set; }
[HtmlAttributeName("asp-add-nonce")]
public bool AddNonce { get; set; }

/// <summary>
/// Provides access to the <see cref="ViewContext"/>
/// </summary>
[ViewContext]
public ViewContext? ViewContext { get; set; }
/// <summary>
/// Provides access to the <see cref="ViewContext"/>
/// </summary>
[ViewContext]
public ViewContext? ViewContext { get; set; }

/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (AddNonce)
{
if (AddNonce)
if (ViewContext is null)
{
if (ViewContext is null)
{
throw new InvalidOperationException("ViewContext was null");
}
throw new InvalidOperationException("ViewContext was null");
}

var nonce = ViewContext.HttpContext.GetNonce();
var nonce = ViewContext.HttpContext.GetNonce();

if (string.IsNullOrEmpty(nonce))
{
var logger = ViewContext.HttpContext.RequestServices.GetRequiredService<ILogger<NonceTagHelper>>();
logger.LogInformation("Nonce attribute not set, nonce value for request not set");
}
else
{
output.Attributes.Add("nonce", nonce);
}
if (string.IsNullOrEmpty(nonce))
{
var logger = ViewContext.HttpContext.RequestServices.GetRequiredService<ILogger<NonceTagHelper>>();
logger.LogInformation("Nonce attribute not set, nonce value for request not set");
}
else
{
output.Attributes.Add("nonce", nonce);
}
}
}
Expand Down
Loading

0 comments on commit 36ffc0d

Please sign in to comment.