Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Handle additional curve case sensitivity scenarios.
  • Loading branch information
vcsjones committed Nov 4, 2022
commit 8f997ad767cfd3d84158843b9c28d950fc274f27
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ private static bool IsMagicValueOfKeyPublic(KeyBlobMagicNumber magic)
/// that don't have the named curve functionality.
/// </summary>
private static KeyBlobMagicNumber EcdsaCurveNameToMagicNumber(string? name, bool includePrivateParameters) =>
EcdsaCurveNameToAlgorithm(name) switch
CngKey.EcdsaCurveNameToAlgorithm(name).Algorithm switch
{
AlgorithmName.ECDsaP256 => includePrivateParameters ?
KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC :
Expand All @@ -409,7 +409,7 @@ private static KeyBlobMagicNumber EcdsaCurveNameToMagicNumber(string? name, bool
/// that don't have the named curve functionality.
/// </summary>
private static KeyBlobMagicNumber EcdhCurveNameToMagicNumber(string? name, bool includePrivateParameters) =>
EcdhCurveNameToAlgorithm(name) switch
CngKey.EcdhCurveNameToAlgorithm(name).Algorithm switch
{
AlgorithmName.ECDHP256 => includePrivateParameters ?
KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P256_MAGIC :
Expand Down Expand Up @@ -513,58 +513,5 @@ ref MemoryMarshal.GetReference(keyBlob),

return keyHandle;
}

/// <summary>
/// Map a curve name to algorithm. This enables curves that worked pre-Win10
/// to work with newer APIs for import and export.
/// </summary>
internal static string EcdsaCurveNameToAlgorithm(string? algorithm)
{
switch (algorithm)
{
case "nistP256":
case "ECDSA_P256":
return AlgorithmName.ECDsaP256;

case "nistP384":
case "ECDSA_P384":
return AlgorithmName.ECDsaP384;

case "nistP521":
case "ECDSA_P521":
return AlgorithmName.ECDsaP521;
}

// All other curves are new in Win10 so use generic algorithm
return AlgorithmName.ECDsa;
}

/// <summary>
/// Map a curve name to algorithm. This enables curves that worked pre-Win10
/// to work with newer APIs for import and export.
/// </summary>
internal static string EcdhCurveNameToAlgorithm(string? algorithm)
{
switch (algorithm)
{
case "nistP256":
case "ECDH_P256":
case "ECDSA_P256":
return AlgorithmName.ECDHP256;

case "nistP384":
case "ECDH_P384":
case "ECDSA_P384":
return AlgorithmName.ECDHP384;

case "nistP521":
case "ECDH_P521":
case "ECDSA_P521":
return AlgorithmName.ECDHP521;
}

// All other curves are new in Win10 so use generic algorithm
return AlgorithmName.ECDH;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -420,22 +420,21 @@ public static void ImportFromPrivateOnlyKey()
[InlineData("NISTP256", "1.2.840.10045.3.1.7")]
[InlineData("NISTP384", "1.3.132.0.34")]
[InlineData("NISTP521", "1.3.132.0.35")]
[InlineData("ecdh_P256", "1.2.840.10045.3.1.7")]
[InlineData("ecdh_P384", "1.3.132.0.34")]
[InlineData("ecdh_P521", "1.3.132.0.35")]
public static void OidPresentOnCurveMiscased(string curveName, string expectedOid)
{
ECCurve curve = ECCurve.CreateFromFriendlyName(curveName);

using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
{
ECCurve curve = ECCurve.CreateFromFriendlyName(curveName);
ecdh.GenerateKey(curve);
ECParameters exportedParameters = ecdh.ExportParameters(false);
Assert.Equal(expectedOid, exportedParameters.Curve.Oid.Value);

if (PlatformDetection.IsWindows10OrLater)
{
ecdh.GenerateKey(curve);
ECParameters exportedParameters = ecdh.ExportParameters(false);
Assert.Equal(expectedOid, exportedParameters.Curve.Oid.Value);
}
else
{
Assert.Throws<PlatformNotSupportedException>(() => ecdh.GenerateKey(curve));
}
exportedParameters.Curve = curve;
ecdh.ImportParameters(exportedParameters);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,22 +357,21 @@ public static void ImportFromPrivateOnlyKey()
[InlineData("NISTP256", "1.2.840.10045.3.1.7")]
[InlineData("NISTP384", "1.3.132.0.34")]
[InlineData("NISTP521", "1.3.132.0.35")]
public static void OidPresentOnCurveMiscased(string curveName, string expectedOid)
[InlineData("ecdsa_P256", "1.2.840.10045.3.1.7")]
[InlineData("ecdsa_P384", "1.3.132.0.34")]
[InlineData("ecdsa_P521", "1.3.132.0.35")]
public static void GenerateKey_OidPresentOnCurveMiscased(string curveName, string expectedOid)
{
ECCurve curve = ECCurve.CreateFromFriendlyName(curveName);

using (ECDsa ecdsa = ECDsaFactory.Create())
{
ECCurve curve = ECCurve.CreateFromFriendlyName(curveName);
ecdsa.GenerateKey(curve);
ECParameters exportedParameters = ecdsa.ExportParameters(false);
Assert.Equal(expectedOid, exportedParameters.Curve.Oid.Value);

if (PlatformDetection.IsWindows10OrLater)
{
ecdsa.GenerateKey(curve);
ECParameters exportedParameters = ecdsa.ExportParameters(false);
Assert.Equal(expectedOid, exportedParameters.Curve.Oid.Value);
}
else
{
Assert.Throws<PlatformNotSupportedException>(() => ecdsa.GenerateKey(curve));
}
exportedParameters.Curve = curve;
ecdsa.ImportParameters(exportedParameters);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,53 +82,52 @@ internal static CngProperty GetPropertyFromNamedCurve(ECCurve curve)
/// Map a curve name to algorithm. This enables curves that worked pre-Win10
/// to work with newer APIs for import and export.
/// </summary>
internal static CngAlgorithm EcdsaCurveNameToAlgorithm(string name)
internal static CngAlgorithm EcdsaCurveNameToAlgorithm(ReadOnlySpan<char> name)
{
switch (name)
{
case "nistP256":
case "ECDSA_P256":
return CngAlgorithm.ECDsaP256;

case "nistP384":
case "ECDSA_P384":
return CngAlgorithm.ECDsaP384;
const int MaxCurveNameLength = 16;
Span<char> nameLower = stackalloc char[MaxCurveNameLength];
int written = name.ToLowerInvariant(nameLower);

case "nistP521":
case "ECDSA_P521":
return CngAlgorithm.ECDsaP521;
// Either it is empty or too big for the buffer, and the buffer is large enough to hold all mapped
// curve names, so return the generic algorithm.
if (written < 1)
{
return CngAlgorithm.ECDsa;
}

// All other curves are new in Win10 so use generic algorithm
return CngAlgorithm.ECDsa;
return nameLower.Slice(0, written) switch
{
"nistp256" or "ecdsa_p256" => CngAlgorithm.ECDsaP256,
"nistp384" or "ecdsa_p384" => CngAlgorithm.ECDsaP384,
"nistp521" or "ecdsa_p521" => CngAlgorithm.ECDsaP521,
_ => CngAlgorithm.ECDsa, // All other curves are new in Win10 so use generic algorithm
};
}

/// <summary>
/// Map a curve name to algorithm. This enables curves that worked pre-Win10
/// to work with newer APIs for import and export.
/// </summary>
internal static CngAlgorithm EcdhCurveNameToAlgorithm(string name)
internal static CngAlgorithm EcdhCurveNameToAlgorithm(ReadOnlySpan<char> name)
{
switch (name)
const int MaxCurveNameLength = 16;
Span<char> nameLower = stackalloc char[MaxCurveNameLength];
int written = name.ToLowerInvariant(nameLower);

// Either it is empty or too big for the buffer, and the buffer is large enough to hold all mapped
// curve names, so return the generic algorithm.
if (written < 1)
{
case "nistP256":
case "ECDH_P256":
case "ECDSA_P256":
return CngAlgorithm.ECDiffieHellmanP256;

case "nistP384":
case "ECDH_P384":
case "ECDSA_P384":
return CngAlgorithm.ECDiffieHellmanP384;

case "nistP521":
case "ECDH_P521":
case "ECDSA_P521":
return CngAlgorithm.ECDiffieHellmanP521;
return CngAlgorithm.ECDiffieHellman;
}

// All other curves are new in Win10 so use generic algorithm
return CngAlgorithm.ECDiffieHellman;
return nameLower.Slice(0, written) switch
{
"nistp256" or "ecdsa_p256" or "ecdh_p256" => CngAlgorithm.ECDiffieHellmanP256,
"nistp384" or "ecdsa_p384" or "ecdh_p384" => CngAlgorithm.ECDiffieHellmanP384,
"nistp521" or "ecdsa_p521" or "ecdh_p521" => CngAlgorithm.ECDiffieHellmanP521,
_ => CngAlgorithm.ECDiffieHellman, // All other curves are new in Win10 so use generic algorithm
};
}

internal static CngKey Create(ECCurve curve, Func<string?, CngAlgorithm> algorithmResolver)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1094,10 +1094,13 @@ public static void CreateSigningRequestWithDuplicateAttributes(bool reversed)
Assert.Equal(ExpectedPem, output);
}

[ConditionalTheory(nameof(PlatformDetection), nameof(PlatformDetection.IsWindows10OrLater))]
[Theory]
[InlineData("NISTP256", "SHA256")]
[InlineData("NISTP384", "SHA384")]
[InlineData("NISTP521", "SHA512")]
[InlineData("EcDsA_p256", "SHA256")]
[InlineData("EcDsA_p384", "SHA384")]
[InlineData("EcDsA_p521", "SHA512")]
public static void CreateSelfSigned_CurveNameIsCaseInsensitive(string curveName, string hashName)
{
ECCurve ecCurve = ECCurve.CreateFromFriendlyName(curveName);
Expand Down