124 lines
4.0 KiB
C#
124 lines
4.0 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
|
|
namespace Microsoft.AspNetCore.Identity.Service
|
|
{
|
|
internal static class CryptographyHelpers
|
|
{
|
|
private static readonly RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
|
|
|
|
public static string FindAlgorithm(X509Certificate2 certificate)
|
|
{
|
|
var rsapk = certificate.GetRSAPublicKey();
|
|
if (rsapk != null)
|
|
{
|
|
return "RS256";
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException("Algorithm not supported.");
|
|
}
|
|
}
|
|
|
|
public static void ValidateRsaKeyLength(X509Certificate2 certificate)
|
|
{
|
|
var rsa = certificate.GetRSAPublicKey();
|
|
if (rsa == null)
|
|
{
|
|
throw new InvalidOperationException("Algorithm not supported.");
|
|
}
|
|
ValidateRsaKeyLength(rsa);
|
|
}
|
|
|
|
public static void ValidateRsaKeyLength(RSA rsa)
|
|
{
|
|
if (rsa.KeySize < 2048)
|
|
{
|
|
throw new InvalidOperationException("The RSA key must be at least 2048 bits long.");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
public static SHA256 CreateSHA256()
|
|
{
|
|
SHA256 sha256 = null;
|
|
try
|
|
{
|
|
sha256 = SHA256.Create();
|
|
return sha256;
|
|
}
|
|
// SHA256.Create is documented to throw this exception on FIPS compliant machines.
|
|
// See: https://msdn.microsoft.com/enus/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=2147217396
|
|
catch (System.Reflection.TargetInvocationException)
|
|
{
|
|
// Fallback to a FIPS compliant SHA256 algorithm.
|
|
sha256 = new SHA256CryptoServiceProvider();
|
|
}
|
|
|
|
return sha256;
|
|
}
|
|
|
|
public static RSAParameters GetRSAParameters(SigningCredentials credentials)
|
|
{
|
|
RSA algorithm = null;
|
|
if (credentials.Key is X509SecurityKey x509SecurityKey)
|
|
{
|
|
algorithm = x509SecurityKey.PublicKey as RSA;
|
|
}
|
|
|
|
if (credentials.Key is RsaSecurityKey rsaSecurityKey)
|
|
{
|
|
algorithm = rsaSecurityKey.Rsa;
|
|
|
|
if (algorithm == null)
|
|
{
|
|
var rsa = RSA.Create();
|
|
rsa.ImportParameters(rsaSecurityKey.Parameters);
|
|
algorithm = rsa;
|
|
}
|
|
}
|
|
|
|
var parameters = algorithm.ExportParameters(includePrivateParameters: false);
|
|
return parameters;
|
|
}
|
|
|
|
public static string GetAlgorithm(SigningCredentials credentials)
|
|
{
|
|
RSA algorithm = null;
|
|
if (credentials.Key is X509SecurityKey x509SecurityKey && x509SecurityKey.PublicKey is RSA)
|
|
{
|
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
|
}
|
|
|
|
var rsaSecurityKey = credentials.Key as RsaSecurityKey;
|
|
// Check that the key has either an Asymmetric Algorithm assigned or that at least
|
|
// one of the RSA parameters are initialized to consider the key "valid".
|
|
if (rsaSecurityKey != null &&
|
|
(rsaSecurityKey.Rsa != null || rsaSecurityKey.Parameters.Modulus != null))
|
|
{
|
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
|
}
|
|
|
|
if (algorithm != null)
|
|
{
|
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
|
}
|
|
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
internal static string GenerateHighEntropyValue(int byteLength)
|
|
{
|
|
var bytes = new byte[byteLength];
|
|
randomNumberGenerator.GetBytes(bytes);
|
|
return Base64UrlEncoder.Encode(bytes);
|
|
}
|
|
}
|
|
}
|