You've already forked linux-packaging-mono
Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
This commit is contained in:
parent
ee1447783b
commit
94b2861243
@ -5,12 +5,14 @@
|
||||
namespace System.IdentityModel.Claims
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IdentityModel.Policy;
|
||||
using System.Net.Mail;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Principal;
|
||||
using Globalization;
|
||||
|
||||
public class X509CertificateClaimSet : ClaimSet, IIdentityInfo, IDisposable
|
||||
{
|
||||
@ -172,24 +174,7 @@ namespace System.IdentityModel.Claims
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
claims.Add(Claim.CreateX500DistinguishedNameClaim(this.certificate.SubjectName));
|
||||
|
||||
// App context switch for disabling support for multiple dns entries in a SAN certificate
|
||||
if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate)
|
||||
{
|
||||
// old behavior, default for <= 4.6
|
||||
value = this.certificate.GetNameInfo(X509NameType.DnsName, false);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
claims.Add(Claim.CreateDnsClaim(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
// new behavior as this is the default long term behavior
|
||||
// Since a SAN can have multiple DNS entries
|
||||
string[] entries = GetDnsFromExtensions(this.certificate);
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
claims.Add(Claim.CreateDnsClaim(entries[i]));
|
||||
}
|
||||
}
|
||||
claims.AddRange(GetDnsClaims(this.certificate));
|
||||
|
||||
value = this.certificate.GetNameInfo(X509NameType.SimpleName, false);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
@ -258,25 +243,8 @@ namespace System.IdentityModel.Claims
|
||||
{
|
||||
if (right == null || Rights.PossessProperty.Equals(right))
|
||||
{
|
||||
// App context switch for disabling support for multiple dns entries in a SAN certificate
|
||||
if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate)
|
||||
{
|
||||
// old behavior, default for <= 4.6
|
||||
string value = this.certificate.GetNameInfo(X509NameType.DnsName, false);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
yield return Claim.CreateDnsClaim(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new behavior since this is the default long term behavior
|
||||
string[] entries = GetDnsFromExtensions(certificate);
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
yield return Claim.CreateDnsClaim(entries[i]);
|
||||
}
|
||||
}
|
||||
foreach (var claim in GetDnsClaims(certificate))
|
||||
yield return claim;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -299,31 +267,44 @@ namespace System.IdentityModel.Claims
|
||||
}
|
||||
}
|
||||
|
||||
// Fixing Bug 795660: SAN having multiple DNS entries
|
||||
private static string[] GetDnsFromExtensions(X509Certificate2 cert)
|
||||
private static List<Claim> GetDnsClaims(X509Certificate2 cert)
|
||||
{
|
||||
foreach (X509Extension ext in cert.Extensions)
|
||||
{
|
||||
// Extension is SAN or SAN2
|
||||
if (ext.Oid.Value == "2.5.29.7" || ext.Oid.Value == "2.5.29.17")
|
||||
{
|
||||
string asnString = ext.Format(true);
|
||||
if (string.IsNullOrEmpty(asnString))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
List<Claim> dnsClaimEntries = new List<Claim>();
|
||||
|
||||
string[] rawDnsEntries = asnString.Split(new string[1] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string[] dnsEntries = new string[rawDnsEntries.Length];
|
||||
for (int i = 0; i < rawDnsEntries.Length; ++i)
|
||||
// old behavior, default for <= 4.6
|
||||
string value = cert.GetNameInfo(X509NameType.DnsName, false);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
dnsClaimEntries.Add(Claim.CreateDnsClaim(value));
|
||||
|
||||
// App context switch for disabling support for multiple dns entries in a SAN certificate
|
||||
// If we can't dynamically parse the alt subject names, we will not add any dns claims ONLY for the alt subject names.
|
||||
// In this way, if the X509NameType.DnsName was enough to succeed for the out-bound-message. We would have a success.
|
||||
if (!LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate && X509SubjectAlternativeNameConstants.SuccessfullyInitialized)
|
||||
{
|
||||
foreach (X509Extension ext in cert.Extensions)
|
||||
{
|
||||
// Extension is SAN or SAN2
|
||||
if (ext.Oid.Value == X509SubjectAlternativeNameConstants.SanOid || ext.Oid.Value == X509SubjectAlternativeNameConstants.San2Oid)
|
||||
{
|
||||
int equalSignIndex = rawDnsEntries[i].IndexOf('=');
|
||||
dnsEntries[i] = rawDnsEntries[i].Substring(equalSignIndex + 1).Trim();
|
||||
string asnString = ext.Format(false);
|
||||
if (string.IsNullOrWhiteSpace(asnString))
|
||||
break;
|
||||
|
||||
// SubjectAlternativeNames might contain something other than a dNSName,
|
||||
// so we have to parse through and only use the dNSNames
|
||||
// <identifier><delimiter><value><separator(s)>
|
||||
string[] rawDnsEntries = asnString.Split(X509SubjectAlternativeNameConstants.SeparatorArray, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < rawDnsEntries.Length; i++)
|
||||
{
|
||||
string[] keyval = rawDnsEntries[i].Split(X509SubjectAlternativeNameConstants.Delimiter);
|
||||
if (string.Equals(keyval[0], X509SubjectAlternativeNameConstants.Identifier))
|
||||
dnsClaimEntries.Add(Claim.CreateDnsClaim(keyval[1]));
|
||||
}
|
||||
}
|
||||
return dnsEntries;
|
||||
}
|
||||
}
|
||||
return new string[0];
|
||||
|
||||
return dnsClaimEntries;
|
||||
}
|
||||
|
||||
public override IEnumerator<Claim> GetEnumerator()
|
||||
@ -367,6 +348,107 @@ namespace System.IdentityModel.Claims
|
||||
get { return this.identity; }
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have a strongly typed extension to parse Subject Alt Names, so we have to do a workaround
|
||||
// to figure out what the identifier, delimiter, and separator is by using a well-known extension
|
||||
private static class X509SubjectAlternativeNameConstants
|
||||
{
|
||||
public const string SanOid = "2.5.29.7";
|
||||
public const string San2Oid = "2.5.29.17";
|
||||
|
||||
public static string Identifier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static char Delimiter
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static string Separator
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static string[] SeparatorArray
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static bool SuccessfullyInitialized
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
// static initializer will run before properties are accessed
|
||||
static X509SubjectAlternativeNameConstants()
|
||||
{
|
||||
// Extracted a well-known X509Extension
|
||||
byte[] x509ExtensionBytes = new byte[] {
|
||||
48, 36, 130, 21, 110, 111, 116, 45, 114, 101, 97, 108, 45, 115, 117, 98, 106, 101, 99,
|
||||
116, 45, 110, 97, 109, 101, 130, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109
|
||||
};
|
||||
const string subjectName = "not-real-subject-name";
|
||||
string x509ExtensionFormattedString = string.Empty;
|
||||
try
|
||||
{
|
||||
X509Extension x509Extension = new X509Extension(SanOid, x509ExtensionBytes, true);
|
||||
x509ExtensionFormattedString = x509Extension.Format(false);
|
||||
|
||||
// Each OS has a different dNSName identifier and delimiter
|
||||
// On Windows, dNSName == "DNS Name" (localizable), on Linux, dNSName == "DNS"
|
||||
// e.g.,
|
||||
// Windows: x509ExtensionFormattedString is: "DNS Name=not-real-subject-name, DNS Name=example.com"
|
||||
// Linux: x509ExtensionFormattedString is: "DNS:not-real-subject-name, DNS:example.com"
|
||||
// Parse: <identifier><delimiter><value><separator(s)>
|
||||
|
||||
int delimiterIndex = x509ExtensionFormattedString.IndexOf(subjectName) - 1;
|
||||
Delimiter = x509ExtensionFormattedString[delimiterIndex];
|
||||
|
||||
// Make an assumption that all characters from the the start of string to the delimiter
|
||||
// are part of the identifier
|
||||
Identifier = x509ExtensionFormattedString.Substring(0, delimiterIndex);
|
||||
|
||||
int separatorFirstChar = delimiterIndex + subjectName.Length + 1;
|
||||
int separatorLength = 1;
|
||||
for (int i = separatorFirstChar + 1; i < x509ExtensionFormattedString.Length; i++)
|
||||
{
|
||||
// We advance until the first character of the identifier to determine what the
|
||||
// separator is. This assumes that the identifier assumption above is correct
|
||||
if (x509ExtensionFormattedString[i] == Identifier[0])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
separatorLength++;
|
||||
}
|
||||
|
||||
Separator = x509ExtensionFormattedString.Substring(separatorFirstChar, separatorLength);
|
||||
SeparatorArray = new string[1] { Separator };
|
||||
SuccessfullyInitialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SuccessfullyInitialized = false;
|
||||
DiagnosticUtility.TraceHandledException(
|
||||
new FormatException(string.Format(CultureInfo.InvariantCulture,
|
||||
"There was an error parsing the SubjectAlternativeNames: '{0}'. See inner exception for more details.{1}Detected values were: Identifier: '{2}'; Delimiter:'{3}'; Separator:'{4}'",
|
||||
x509ExtensionFormattedString,
|
||||
Environment.NewLine,
|
||||
Identifier,
|
||||
Delimiter,
|
||||
Separator),
|
||||
ex),
|
||||
TraceEventType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class X509Identity : GenericIdentity, IDisposable
|
||||
|
@ -15,9 +15,11 @@ namespace System.IdentityModel
|
||||
{
|
||||
private const string EnableCachedEmptyDefaultAuthorizationContextString = "Switch.System.IdentityModel.EnableCachedEmptyDefaultAuthorizationContext";
|
||||
private const string DisableMultipleDNSEntriesInSANCertificateString = "Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate";
|
||||
private const string DisableUpdatingRsaProviderTypeString = "Switch.System.IdentityModel.DisableUpdatingRsaProviderType";
|
||||
|
||||
private static int enableCachedEmptyDefaultAuthorizationContext;
|
||||
private static int disableMultipleDNSEntriesInSANCertificate;
|
||||
private static int disableUpdatingRsaProviderType;
|
||||
|
||||
public static bool EnableCachedEmptyDefaultAuthorizationContext
|
||||
{
|
||||
@ -37,16 +39,29 @@ namespace System.IdentityModel
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DisableUpdatingRsaProviderType
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
return LocalAppContext.GetCachedSwitchValue(DisableUpdatingRsaProviderTypeString, ref disableUpdatingRsaProviderType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDefaultsLessOrEqual_452()
|
||||
{
|
||||
#pragma warning disable BCL0012
|
||||
// Define the switches that should be true for 4.5.2 or less, false for 4.6+.
|
||||
LocalAppContext.DefineSwitchDefault(EnableCachedEmptyDefaultAuthorizationContextString, true);
|
||||
#pragma warning restore BCL0012
|
||||
}
|
||||
|
||||
public static void SetDefaultsLessOrEqual_46()
|
||||
{
|
||||
#pragma warning disable BCL0012
|
||||
// Define the switches that should be true for 4.6 or less, false for 4.6.1+.
|
||||
LocalAppContext.DefineSwitchDefault(DisableMultipleDNSEntriesInSANCertificateString, true);
|
||||
#pragma warning restore BCL0012
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -309,22 +309,26 @@ namespace System.IdentityModel.Tokens
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm"));
|
||||
}
|
||||
// We support one of the two algoritms, but not both.
|
||||
|
||||
// We support:
|
||||
// XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
|
||||
// XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
|
||||
// RsaSha256Signature = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
||||
AsymmetricAlgorithm privateKey = LevelUpRsa(this.PrivateKey, algorithm);
|
||||
|
||||
object algorithmObject = CryptoHelper.GetAlgorithmFromConfig(algorithm);
|
||||
if (algorithmObject != null)
|
||||
{
|
||||
SignatureDescription description = algorithmObject as SignatureDescription;
|
||||
if (description != null)
|
||||
return description.CreateFormatter(this.PrivateKey);
|
||||
return description.CreateFormatter(privateKey);
|
||||
|
||||
try
|
||||
{
|
||||
AsymmetricSignatureFormatter asymmetricSignatureFormatter = algorithmObject as AsymmetricSignatureFormatter;
|
||||
if (asymmetricSignatureFormatter != null)
|
||||
{
|
||||
asymmetricSignatureFormatter.SetKey(this.PrivateKey);
|
||||
asymmetricSignatureFormatter.SetKey(privateKey);
|
||||
return asymmetricSignatureFormatter;
|
||||
}
|
||||
}
|
||||
@ -356,19 +360,10 @@ namespace System.IdentityModel.Tokens
|
||||
|
||||
case SecurityAlgorithms.RsaSha256Signature:
|
||||
// Ensure that we have an RSA algorithm object.
|
||||
RSACryptoServiceProvider rsa_prov_full = (this.PrivateKey as RSACryptoServiceProvider);
|
||||
if (rsa_prov_full == null)
|
||||
RSA rsaSha256 = (privateKey as RSA);
|
||||
if (rsaSha256 == null)
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.PrivateKeyNotRSA)));
|
||||
CspParameters csp = new CspParameters();
|
||||
csp.ProviderType = 24;
|
||||
csp.KeyContainerName = rsa_prov_full.CspKeyContainerInfo.KeyContainerName;
|
||||
csp.KeyNumber = (int)rsa_prov_full.CspKeyContainerInfo.KeyNumber;
|
||||
if (rsa_prov_full.CspKeyContainerInfo.MachineKeyStore)
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
|
||||
csp.Flags |= CspProviderFlags.UseExistingKey;
|
||||
|
||||
return new RSAPKCS1SignatureFormatter(new RSACryptoServiceProvider(csp));
|
||||
return new RSAPKCS1SignatureFormatter(rsaSha256);
|
||||
|
||||
default:
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedCryptoAlgorithm, algorithm)));
|
||||
@ -376,6 +371,45 @@ namespace System.IdentityModel.Tokens
|
||||
|
||||
}
|
||||
|
||||
private static AsymmetricAlgorithm LevelUpRsa(AsymmetricAlgorithm asymmetricAlgorithm, string algorithm)
|
||||
{
|
||||
// If user turned off leveling up at app level, return
|
||||
if (LocalAppContextSwitches.DisableUpdatingRsaProviderType)
|
||||
return asymmetricAlgorithm;
|
||||
|
||||
if (asymmetricAlgorithm == null)
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("asymmetricAlgorithm"));
|
||||
|
||||
if (string.IsNullOrEmpty(algorithm))
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm"));
|
||||
|
||||
// only level up if alg is sha256
|
||||
if (!string.Equals(algorithm, SecurityAlgorithms.RsaSha256Signature))
|
||||
return asymmetricAlgorithm;
|
||||
|
||||
RSACryptoServiceProvider rsaCsp = asymmetricAlgorithm as RSACryptoServiceProvider;
|
||||
if (rsaCsp == null)
|
||||
return asymmetricAlgorithm;
|
||||
|
||||
// ProviderType == 1(PROV_RSA_FULL) and providerType == 12(PROV_RSA_SCHANNEL) are provider types that only support SHA1. Change them to PROV_RSA_AES=24 that supports SHA2 also.
|
||||
// Only levels up if the associated key is not a hardware key.
|
||||
// Another provider type related to rsa, PROV_RSA_SIG == 2 that only supports Sha1 is no longer supported
|
||||
if ((rsaCsp.CspKeyContainerInfo.ProviderType == 1 || rsaCsp.CspKeyContainerInfo.ProviderType == 12) && !rsaCsp.CspKeyContainerInfo.HardwareDevice)
|
||||
{
|
||||
CspParameters csp = new CspParameters();
|
||||
csp.ProviderType = 24;
|
||||
csp.KeyContainerName = rsaCsp.CspKeyContainerInfo.KeyContainerName;
|
||||
csp.KeyNumber = (int)rsaCsp.CspKeyContainerInfo.KeyNumber;
|
||||
if (rsaCsp.CspKeyContainerInfo.MachineKeyStore)
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
|
||||
csp.Flags |= CspProviderFlags.UseExistingKey;
|
||||
return new RSACryptoServiceProvider(csp);
|
||||
}
|
||||
|
||||
return rsaCsp;
|
||||
}
|
||||
|
||||
public override bool HasPrivateKey()
|
||||
{
|
||||
return (this.PrivateKey != null);
|
||||
|
Reference in New Issue
Block a user