From: Jeremy Barton Date: Wed, 9 Oct 2019 05:56:00 +0000 (-0700) Subject: Add support for reading/writing key files for explicit parameter ECC X-Git-Tag: submit/tizen/20210909.063632~11031^2~329 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=59e6458a2ea1f71bdfde7f290d341bf33231f4e0;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add support for reading/writing key files for explicit parameter ECC Add support for reading/writing key files for explicit parameter ECC * Prime curves * ECPrivateKey * Pkcs8 * EncryptedPkcs8 * SubjectPublicKeyInfo * Characteristic-2 curves * ECPrivateKey * Pkcs8 * EncryptedPkcs8 * SubjectPublicKeyInfo Commit migrated from https://github.com/dotnet/corefx/commit/a7ee8cdccce7d2607d58f9b93ce319209a238f7a --- diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml index 779f0fc..ee3b485 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml @@ -27,5 +27,5 @@ - - \ No newline at end of file + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs index 25eed00..255b065 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs @@ -41,7 +41,12 @@ namespace System.Security.Cryptography.Asn1 writer.WriteInteger(Cofactor.Value.Span); } - writer.WriteObjectIdentifier(Hash); + + if (Hash != null) + { + writer.WriteObjectIdentifier(Hash); + } + writer.PopSequence(tag); } @@ -100,7 +105,12 @@ namespace System.Security.Cryptography.Asn1 decoded.Cofactor = sequenceReader.ReadIntegerBytes(); } - decoded.Hash = sequenceReader.ReadObjectIdentifier(); + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.ObjectIdentifier)) + { + decoded.Hash = sequenceReader.ReadObjectIdentifier(); + } + sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs index dd68722..12c4b14 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs @@ -3,9 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Buffers; +using System.Collections; using System.Diagnostics; -using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography.Asn1; @@ -13,6 +12,10 @@ namespace System.Security.Cryptography { internal static class EccKeyFormatHelper { + // This is the same limit that OpenSSL 1.0.2-1.1.1 has, + // there's no real point reading anything bigger than this (for now). + private const int MaxFieldBitSize = 661; + private static readonly string[] s_validOids = { Oids.EcPublicKey, @@ -229,8 +232,13 @@ namespace System.Security.Cryptography } } - private static ECCurve GetCurve(in ECDomainParameters domainParameters) + private static ECCurve GetCurve(ECDomainParameters domainParameters) { + if (domainParameters.Specified.HasValue) + { + return GetSpecifiedECCurve(domainParameters.Specified.Value); + } + if (domainParameters.Named == null) { throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly); @@ -254,15 +262,171 @@ namespace System.Security.Cryptography return ECCurve.CreateFromOid(curveOid); } - internal static AsnWriter WriteSubjectPublicKeyInfo(in ECParameters ecParameters) + private static ECCurve GetSpecifiedECCurve(SpecifiedECDomain specifiedParameters) { - ecParameters.Validate(); + // sec1-v2 C.3: + // + // Versions 1, 2, and 3 are defined. + // 1 is just data, 2 and 3 mean that a seed is required (with different reasons for why, + // but they're human-reasons, not technical ones). + if (specifiedParameters.Version < 1 || specifiedParameters.Version > 3) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } - if (!ecParameters.Curve.IsNamed) + if (specifiedParameters.Version > 1 && !specifiedParameters.Curve.Seed.HasValue) { - throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly); + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + byte[] primeOrPoly; + bool prime; + + switch (specifiedParameters.FieldID.FieldType) + { + case Oids.EcPrimeField: + prime = true; + AsnReader primeReader = new AsnReader(specifiedParameters.FieldID.Parameters, AsnEncodingRules.BER); + ReadOnlySpan primeValue = primeReader.ReadIntegerBytes().Span; + + if (primeValue[0] == 0) + { + primeValue = primeValue.Slice(1); + } + + if (primeValue.Length > (MaxFieldBitSize / 8)) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + primeOrPoly = primeValue.ToArray(); + break; + case Oids.EcChar2Field: + prime = false; + AsnReader char2Reader = new AsnReader(specifiedParameters.FieldID.Parameters, AsnEncodingRules.BER); + AsnReader innerReader = char2Reader.ReadSequence(); + char2Reader.ThrowIfNotEmpty(); + + // Characteristic-two ::= SEQUENCE + // { + // m INTEGER, -- Field size + // basis CHARACTERISTIC-TWO.&id({BasisTypes}), + // parameters CHARACTERISTIC-TWO.&Type({BasisTypes}{@basis}) + // } + + if (!innerReader.TryReadInt32(out int m) || m > MaxFieldBitSize || m < 0) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + int k1; + int k2 = -1; + int k3 = -1; + + switch (innerReader.ReadObjectIdentifierAsString()) + { + case Oids.EcChar2TrinomialBasis: + // Trinomial ::= INTEGER + if (!innerReader.TryReadInt32(out k1) || k1 >= m || k1 < 1) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + break; + case Oids.EcChar2PentanomialBasis: + // Pentanomial ::= SEQUENCE + // { + // k1 INTEGER, -- k1 > 0 + // k2 INTEGER, -- k2 > k1 + // k3 INTEGER -- k3 > k2 + // } + AsnReader pentanomialReader = innerReader.ReadSequence(); + + if (!pentanomialReader.TryReadInt32(out k1) || + !pentanomialReader.TryReadInt32(out k2) || + !pentanomialReader.TryReadInt32(out k3) || + k1 < 1 || + k2 <= k1 || + k3 <= k2 || + k3 >= m) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + pentanomialReader.ThrowIfNotEmpty(); + + break; + default: + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + innerReader.ThrowIfNotEmpty(); + + BitArray poly = new BitArray(m + 1); + poly.Set(m, true); + poly.Set(k1, true); + poly.Set(0, true); + + if (k2 > 0) + { + poly.Set(k2, true); + poly.Set(k3, true); + } + + primeOrPoly = new byte[(m + 7) / 8]; + poly.CopyTo(primeOrPoly, 0); + Array.Reverse(primeOrPoly); + break; + default: + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } + ECCurve curve; + + if (prime) + { + curve = new ECCurve + { + CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass, + Prime = primeOrPoly, + }; + } + else + { + curve = new ECCurve + { + CurveType = ECCurve.ECCurveType.Characteristic2, + Polynomial = primeOrPoly, + }; + } + + curve.A = specifiedParameters.Curve.A.ToUnsignedIntegerBytes(primeOrPoly.Length); + curve.B = specifiedParameters.Curve.B.ToUnsignedIntegerBytes(primeOrPoly.Length); + curve.Order = specifiedParameters.Order.ToUnsignedIntegerBytes(primeOrPoly.Length); + + ReadOnlySpan baseSpan = specifiedParameters.Base.Span; + + // We only understand the uncompressed point encoding, but that's almost always what's used. + if (baseSpan[0] != 0x04 || baseSpan.Length != 2 * primeOrPoly.Length + 1) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + curve.G.X = baseSpan.Slice(1, primeOrPoly.Length).ToArray(); + curve.G.Y = baseSpan.Slice(1 + primeOrPoly.Length).ToArray(); + + if (specifiedParameters.Cofactor.HasValue) + { + curve.Cofactor = specifiedParameters.Cofactor.Value.ToUnsignedIntegerBytes(); + } + + return curve; + } + + internal static AsnWriter WriteSubjectPublicKeyInfo(ECParameters ecParameters) + { + ecParameters.Validate(); + // Since the public key format for EC keys is not ASN.1, // write the SPKI structure manually. @@ -298,7 +462,7 @@ namespace System.Security.Cryptography writer.PopSequence(); } - internal static AsnWriter WritePkcs8PrivateKey(in ECParameters ecParameters) + internal static AsnWriter WritePkcs8PrivateKey(ECParameters ecParameters) { ecParameters.Validate(); @@ -307,11 +471,6 @@ namespace System.Security.Cryptography throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } - if (!ecParameters.Curve.IsNamed) - { - throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly); - } - // Don't need the domain parameters because they're contained in the algId. using (AsnWriter ecPrivateKey = WriteEcPrivateKey(ecParameters, includeDomainParameters: false)) using (AsnWriter algorithmIdentifier = WriteAlgorithmIdentifier(ecParameters)) @@ -320,7 +479,7 @@ namespace System.Security.Cryptography } } - private static void WriteEcParameters(in ECParameters ecParameters, AsnWriter writer) + private static void WriteEcParameters(ECParameters ecParameters, AsnWriter writer) { if (ecParameters.Curve.IsNamed) { @@ -334,10 +493,237 @@ namespace System.Security.Cryptography writer.WriteObjectIdentifier(oid.Value); } + else if (ecParameters.Curve.IsExplicit) + { + Debug.Assert(ecParameters.Curve.IsPrime || ecParameters.Curve.IsCharacteristic2); + WriteSpecifiedECDomain(ecParameters, writer); + } else { - throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly); + throw new CryptographicException( + SR.Format(SR.Cryptography_CurveNotSupported, ecParameters.Curve.CurveType.ToString())); + } + } + + private static void WriteSpecifiedECDomain(ECParameters ecParameters, AsnWriter writer) + { + int m; + int k1; + int k2; + int k3; + m = k1 = k2 = k3 = -1; + + if (ecParameters.Curve.IsCharacteristic2) + { + DetermineChar2Parameters(ecParameters, ref m, ref k1, ref k2, ref k3); } + + // SpecifiedECDomain + writer.PushSequence(); + { + // version + // We don't know if the seed (if present) is verifiably random (2). + // We also don't know if the base point is verifiably random (3). + // So just be version 1. + writer.WriteInteger(1); + + // fieldId + writer.PushSequence(); + { + if (ecParameters.Curve.IsPrime) + { + writer.WriteObjectIdentifier(Oids.EcPrimeField); + writer.WriteIntegerUnsigned(ecParameters.Curve.Prime); + } + else + { + Debug.Assert(ecParameters.Curve.IsCharacteristic2); + + // id + writer.WriteObjectIdentifier(Oids.EcChar2Field); + + // Parameters (Characteristic-two) + writer.PushSequence(); + { + // m + writer.WriteInteger(m); + + if (k3 > 0) + { + writer.WriteObjectIdentifier(Oids.EcChar2PentanomialBasis); + + writer.PushSequence(); + { + writer.WriteInteger(k1); + writer.WriteInteger(k2); + writer.WriteInteger(k3); + + writer.PopSequence(); + } + } + else + { + Debug.Assert(k2 < 0); + Debug.Assert(k1 > 0); + + writer.WriteObjectIdentifier(Oids.EcChar2TrinomialBasis); + writer.WriteInteger(k1); + } + + writer.PopSequence(); + } + } + + writer.PopSequence(); + } + + // curve + WriteCurve(ecParameters.Curve, writer); + + // base + WriteUncompressedBasePoint(ecParameters, writer); + + // order + writer.WriteIntegerUnsigned(ecParameters.Curve.Order); + + // cofactor + if (ecParameters.Curve.Cofactor != null) + { + writer.WriteIntegerUnsigned(ecParameters.Curve.Cofactor); + } + + // hash is omitted. + + writer.PopSequence(); + } + } + + private static void DetermineChar2Parameters( + in ECParameters ecParameters, + ref int m, + ref int k1, + ref int k2, + ref int k3) + { + byte[] polynomial = ecParameters.Curve.Polynomial; + int lastIndex = polynomial.Length - 1; + + // The most significant byte needs a set bit, and the least significant bit must be set. + if (polynomial[0] == 0 || (polynomial[lastIndex] & 1) != 1) + { + throw new CryptographicException(SR.Cryptography_InvalidECCharacteristic2Curve); + } + + for (int localBitIndex = 7; localBitIndex >= 0; localBitIndex--) + { + int test = 1 << localBitIndex; + + if ((polynomial[0] & test) == test) + { + m = checked(8 * lastIndex + localBitIndex); + } + } + + // Find the other set bits. Since we've already found m and 0, there is either + // one remaining (trinomial) or 3 (pentanomial). + for (int inverseIndex = 0; inverseIndex < polynomial.Length; inverseIndex++) + { + int forwardIndex = lastIndex - inverseIndex; + byte val = polynomial[forwardIndex]; + + for (int localBitIndex = 0; localBitIndex < 8; localBitIndex++) + { + int test = 1 << localBitIndex; + + if ((val & test) == test) + { + int bitIndex = 8 * inverseIndex + localBitIndex; + + if (bitIndex == 0) + { + // The bottom bit is always set, it's not considered a parameter. + } + else if (bitIndex == m) + { + break; + } + else if (k1 < 0) + { + k1 = bitIndex; + } + else if (k2 < 0) + { + k2 = bitIndex; + } + else if (k3 < 0) + { + k3 = bitIndex; + } + else + { + // More than pentanomial. + throw new CryptographicException(SR.Cryptography_InvalidECCharacteristic2Curve); + } + } + } + } + + if (k3 > 0) + { + // Pentanomial + } + else if (k2 > 0) + { + // There is no quatranomial + throw new CryptographicException(SR.Cryptography_InvalidECCharacteristic2Curve); + } + else if (k1 > 0) + { + // Trinomial + } + else + { + // No smaller bases exist + throw new CryptographicException(SR.Cryptography_InvalidECCharacteristic2Curve); + } + } + + private static void WriteCurve(in ECCurve curve, AsnWriter writer) + { + writer.PushSequence(); + WriteFieldElement(curve.A, writer); + WriteFieldElement(curve.B, writer); + + if (curve.Seed != null) + { + writer.WriteBitString(curve.Seed); + } + + writer.PopSequence(); + } + + private static void WriteFieldElement(byte[] fieldElement, AsnWriter writer) + { + int start = 0; + + while (start < fieldElement.Length - 1 && fieldElement[start] == 0) + { + start++; + } + + writer.WriteOctetString(fieldElement.AsSpan(start)); + } + + private static void WriteUncompressedBasePoint(in ECParameters ecParameters, AsnWriter writer) + { + int basePointLength = ecParameters.Curve.G.X.Length * 2 + 1; + byte[] tmp = CryptoPool.Rent(basePointLength); + tmp[0] = 0x04; + ecParameters.Curve.G.X.CopyTo(tmp.AsSpan(1)); + ecParameters.Curve.G.Y.CopyTo(tmp.AsSpan(1 + ecParameters.Curve.G.X.Length)); + writer.WriteOctetString(tmp.AsSpan(0, basePointLength)); + // Non-sensitive data. + CryptoPool.Return(tmp, clearSize: 0); } private static void WriteUncompressedPublicKey(in ECParameters ecParameters, AsnWriter writer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs index 23ad0dc..b5aab14 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs @@ -10,6 +10,45 @@ namespace System.Security.Cryptography { internal static class KeyBlobHelpers { + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory, int length) + { + if (memory.Length == length) + { + return memory.ToArray(); + } + + ReadOnlySpan span = memory.Span; + + if (memory.Length == length + 1) + { + if (span[0] == 0) + { + return span.Slice(1).ToArray(); + } + } + + if (span.Length > length) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + byte[] target = new byte[length]; + span.CopyTo(target.AsSpan(length - span.Length)); + return target; + } + + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory) + { + ReadOnlySpan span = memory.Span; + + if (span.Length > 1 && span[0] == 0) + { + return span.Slice(1).ToArray(); + } + + return span.ToArray(); + } + internal static byte[] ExportKeyParameter(this BigInteger value, int length) { byte[] target = new byte[length]; diff --git a/src/libraries/Common/src/System/Security/Cryptography/Oids.cs b/src/libraries/Common/src/System/Security/Cryptography/Oids.cs index 1385dee..6717704 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Oids.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Oids.cs @@ -75,6 +75,10 @@ namespace System.Security.Cryptography // ECDSA CMS uses the combined signature+digest OID // https://tools.ietf.org/html/rfc5753#section-2.1.1 + internal const string EcPrimeField = "1.2.840.10045.1.1"; + internal const string EcChar2Field = "1.2.840.10045.1.2"; + internal const string EcChar2TrinomialBasis = "1.2.840.10045.1.2.3.2"; + internal const string EcChar2PentanomialBasis = "1.2.840.10045.1.2.3.3"; internal const string EcPublicKey = "1.2.840.10045.2.1"; internal const string ECDsaWithSha1 = "1.2.840.10045.4.1"; internal const string ECDsaWithSha256 = "1.2.840.10045.4.3.2"; diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs index 0203752..a6c7157 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Security.Cryptography.Pkcs; using System.Text; using Test.Cryptography; using Xunit; @@ -19,8 +18,13 @@ namespace System.Security.Cryptography.Tests protected abstract ECParameters ExportParameters(T key, bool includePrivate); public static bool SupportsBrainpool { get; } = IsCurveSupported(ECCurve.NamedCurves.brainpoolP160r1.Oid); - + public static bool SupportsSect163k1 { get; } = IsCurveSupported(EccTestData.Sect163k1Key1.Curve.Oid); public static bool SupportsSect283k1 { get; } = IsCurveSupported(EccTestData.Sect283k1Key1.Curve.Oid); + public static bool SupportsC2pnb163v1 { get; } = IsCurveSupported(EccTestData.C2pnb163v1Key1.Curve.Oid); + + // This would need to be virtualized if there was ever a platform that + // allowed explicit in ECDH or ECDSA but not the other. + public static bool SupportsExplicitCurves { get; } = EcDiffieHellman.Tests.ECDiffieHellmanFactory.ExplicitCurvesSupported; private static bool IsCurveSupported(Oid oid) { @@ -225,18 +229,10 @@ NfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ=="; } [Fact] - public void ReadNistP256Explicit() + public void ReadWriteNistP256ExplicitECPrivateKey() { - byte[] explicitSPKI = Convert.FromBase64String(@" -MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA -AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA//// -///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd -NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5 -RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA -//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIEB7OR0ZKbq1wz2mm4r09iG -kaMmLSLLpPdjXq/yZoCo2KErph1ZkjX2fZy01Y8Xg9PKQ+ePClq6piQHmTbAw6k="); - - byte[] explicitECPrivateKey = Convert.FromBase64String(@" + ReadWriteBase64ECPrivateKey( + @" MIIBaAIBAQQgcKEsLbFoRe1W/2jPwhpHKz8E19aFG/Y0ny19WzRSs4qggfowgfcC AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr @@ -244,9 +240,16 @@ vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 YyVRAgEBoUQDQgAEgQHs5HRkpurXDPaabivT2IaRoyYtIsuk92Ner/JmgKjYoSum -HVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ=="); +HVmSNfZ9nLTVjxeD08pD548KWrqmJAeZNsDDqQ==", + EccTestData.GetNistP256ReferenceKeyExplicit(), + SupportsExplicitCurves); + } - byte[] explicitPkcs8 = Convert.FromBase64String(@" + [Fact] + public void ReadWriteNistP256ExplicitPkcs8() + { + ReadWriteBase64Pkcs8( + @" MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA ///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV @@ -254,34 +257,48 @@ AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg 9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgcKEsLbFoRe1W /2jPwhpHKz8E19aFG/Y0ny19WzRSs4qhRANCAASBAezkdGSm6tcM9ppuK9PYhpGj -Ji0iy6T3Y16v8maAqNihK6YdWZI19n2ctNWPF4PTykPnjwpauqYkB5k2wMOp"); - - using (T key = CreateKey()) - { - Assert.ThrowsAny( - () => key.ImportSubjectPublicKeyInfo(explicitSPKI, out _)); - - Assert.ThrowsAny( - () => ImportECPrivateKey(key, explicitECPrivateKey, out _)); - - // Win10 supports explicit curve PKCS8 on the CNG types. - if (!PlatformDetection.IsWindows10Version1607OrGreater) - { - Assert.ThrowsAny( - () => key.ImportPkcs8PrivateKey(explicitPkcs8, out _)); +Ji0iy6T3Y16v8maAqNihK6YdWZI19n2ctNWPF4PTykPnjwpauqYkB5k2wMOp", + EccTestData.GetNistP256ReferenceKeyExplicit(), + SupportsExplicitCurves); + } - Pkcs8PrivateKeyInfo builder = Pkcs8PrivateKeyInfo.Decode(explicitPkcs8, out _, skipCopy: true); - byte[] explicitEncryptedPkcs8 = builder.Encrypt( - "asdf", - new PbeParameters( - PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, - HashAlgorithmName.SHA1, - 2048)); + [Fact] + public void ReadWriteNistP256ExplicitEncryptedPkcs8() + { + ReadWriteBase64EncryptedPkcs8( + @" +MIIBoTAbBgkqhkiG9w0BBQMwDgQIQqYZ3N87K0ICAggABIIBgOHAWa6wz144p0uT +qZsQAbQcIpAFBQRC382dxiOHCV11OyZg264SmxS9iY1OEwIr/peACLu+Fk7zPKhv +Ox1hYz/OeLoKKdtBMqrp65JmH73jG8qeAMuYNj83AIERY7Cckuc2fEC2GTEJcNWs +olE+0p4H6yIvXI48NEQazj5w9zfOGvLmP6Kw6nX+SV3fzM9jHskU226LnDdokGVg +an6/hV1r+2+n2MujhfNzQd/5vW5zx7PN/1aMVMz3wUv9t8scDppeMR5CNCMkxlRA +cQ2lfx2vqFuY70EckgumDqm7AtKK2bLlA6XGTb8HuqKHA0l1zrul9AOBC1g33isD +5CJu1CCT34adV4E4G44uiRQUtf+K8m5Oeo8FI/gGBxdQyOh1k8TNsM+p32gTU8HH +89M5R+s1ayQI7jVPGHXm8Ch7lxvqo6FZAu6+vh23vTwVShUTpGYd0XguE6XKJjGx +eWDIWFuFRj58uAQ65/viFausHWt1BdywcwcyVRb2eLI5MR7DWA==", + "explicit", + new PbeParameters( + PbeEncryptionAlgorithm.Aes128Cbc, + HashAlgorithmName.SHA256, + 1234), + EccTestData.GetNistP256ReferenceKeyExplicit(), + SupportsExplicitCurves); + } - Assert.ThrowsAny( - () => key.ImportEncryptedPkcs8PrivateKey("asdf", explicitEncryptedPkcs8, out _)); - } - } + [Fact] + public void ReadWriteNistP256ExplicitSubjectPublicKeyInfo() + { + ReadWriteBase64SubjectPublicKeyInfo( + @" +MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA +AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA//// +///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd +NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5 +RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA +//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIEB7OR0ZKbq1wz2mm4r09iG +kaMmLSLLpPdjXq/yZoCo2KErph1ZkjX2fZy01Y8Xg9PKQ+ePClq6piQHmTbAw6k=", + EccTestData.GetNistP256ReferenceKeyExplicit(), + SupportsExplicitCurves); } [Fact] @@ -336,6 +353,118 @@ ctLI7vH2zDIF0AV+ud5sqeMQUJY=", } [Fact] + public void ReadWriteSect163k1Key1ECPrivateKey() + { + ReadWriteBase64ECPrivateKey( + @" +MFMCAQEEFQPBmVrfrowFGNwT3+YwS7AQF+akEqAHBgUrgQQAAaEuAywABAYXnjcZ +zIElQ1/mRYnV/KbcGIdVHQeI/rti/8kkjYs5iv4+C1w8ArP+Nw==", + EccTestData.Sect163k1Key1, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1Pkcs8() + { + ReadWriteBase64Pkcs8( + @" +MGMCAQAwEAYHKoZIzj0CAQYFK4EEAAEETDBKAgEBBBUDwZla366MBRjcE9/mMEuw +EBfmpBKhLgMsAAQGF543GcyBJUNf5kWJ1fym3BiHVR0HiP67Yv/JJI2LOYr+Pgtc +PAKz/jc=", + EccTestData.Sect163k1Key1, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1EncryptedPkcs8() + { + ReadWriteBase64EncryptedPkcs8( + @" +MIGHMBsGCSqGSIb3DQEFAzAOBAjLBuCZyPt15QICCAAEaPa9V9VJoB8G+RIgZaYv +z4xl+rpvkDrDI0Xnh8oj1CLQldy2N77pdk3pOg9TwJo+r+eKfIJgBVezW2O615ww +f+ESRyxDnBgKz6H2RKeenyrwVhxF98SyJzAdP637vR3QmDNAWWAgoUhg", + "Koblitz", + new PbeParameters( + PbeEncryptionAlgorithm.Aes256Cbc, + HashAlgorithmName.SHA256, + 7), + EccTestData.Sect163k1Key1, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1SubjectPublicKeyInfo() + { + ReadWriteBase64SubjectPublicKeyInfo( + @" +MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEBheeNxnMgSVDX+ZFidX8ptwYh1UdB4j+ +u2L/ySSNizmK/j4LXDwCs/43", + EccTestData.Sect163k1Key1, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1ExplicitECPrivateKey() + { + ReadWriteBase64ECPrivateKey( + @" +MIHHAgEBBBUDwZla366MBRjcE9/mMEuwEBfmpBKgezB5AgEBMCUGByqGSM49AQIw +GgICAKMGCSqGSM49AQIDAzAJAgEDAgEGAgEHMAYEAQEEAQEEKwQC/hPAU3u8Eayq +B9eT3k5tXlyU7ugCiQcPsF04/1gyHy6ABTbVOMzao9kCFQQAAAAAAAAAAAACAQii +4MwNmfil7wIBAqEuAywABAYXnjcZzIElQ1/mRYnV/KbcGIdVHQeI/rti/8kkjYs5 +iv4+C1w8ArP+Nw==", + EccTestData.Sect163k1Key1Explicit, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1ExplicitPkcs8() + { + ReadWriteBase64Pkcs8( + @" +MIHYAgEAMIGEBgcqhkjOPQIBMHkCAQEwJQYHKoZIzj0BAjAaAgIAowYJKoZIzj0B +AgMDMAkCAQMCAQYCAQcwBgQBAQQBAQQrBAL+E8BTe7wRrKoH15PeTm1eXJTu6AKJ +Bw+wXTj/WDIfLoAFNtU4zNqj2QIVBAAAAAAAAAAAAAIBCKLgzA2Z+KXvAgECBEww +SgIBAQQVA8GZWt+ujAUY3BPf5jBLsBAX5qQSoS4DLAAEBheeNxnMgSVDX+ZFidX8 +ptwYh1UdB4j+u2L/ySSNizmK/j4LXDwCs/43", + EccTestData.Sect163k1Key1Explicit, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1ExplicitEncryptedPkcs8() + { + ReadWriteBase64EncryptedPkcs8( + @" +MIIBADAbBgkqhkiG9w0BBQMwDgQICAkWq2tKYZUCAggABIHgjBfngwE9DbCEaznz ++55MjSGbQH0NMgIRCJtQLbrI7888+KmTL6hWYPH6CQzTsi1unWrMAH2JKa7dkIe9 +FWNXW7bmhcokVDh/OTXOV9QPZ3O4m19a9XOl0wNlbi47XQ3KUkcbzyFNYlDMSzFw +HRfW8+aIkyYAvYCoA4buRfigBe0xy1VKyE5aUkX0EFjx4gqC3Q5mjDMFOxlKNjVV +clSZg6tg9J7bTQsDAN0uYpBc1r8DiSQbKMxg+q13yBciXJzfmkQRtNVXQPsseiUm +z2NFvWcpK0Fh9fCVGuXV9sjJ5qE=", + "Koblitz", + new PbeParameters( + PbeEncryptionAlgorithm.Aes128Cbc, + HashAlgorithmName.SHA256, + 12), + EccTestData.Sect163k1Key1Explicit, + SupportsSect163k1); + } + + [Fact] + public void ReadWriteSect163k1Key1ExplicitSubjectPublicKeyInfo() + { + ReadWriteBase64SubjectPublicKeyInfo( + @" +MIG1MIGEBgcqhkjOPQIBMHkCAQEwJQYHKoZIzj0BAjAaAgIAowYJKoZIzj0BAgMD +MAkCAQMCAQYCAQcwBgQBAQQBAQQrBAL+E8BTe7wRrKoH15PeTm1eXJTu6AKJBw+w +XTj/WDIfLoAFNtU4zNqj2QIVBAAAAAAAAAAAAAIBCKLgzA2Z+KXvAgECAywABAYX +njcZzIElQ1/mRYnV/KbcGIdVHQeI/rti/8kkjYs5iv4+C1w8ArP+Nw==", + EccTestData.Sect163k1Key1Explicit, + SupportsSect163k1); + } + + [Fact] public void ReadWriteSect283k1Key1ECPrivateKey() { ReadWriteBase64ECPrivateKey( @@ -390,6 +519,124 @@ V9r2k5CdhAcW7qeqBH25mVw1YDxeay+M3/DrcdN640MboISeurE6TJADx5afVc2Q", } [Fact] + public void ReadWriteC2pnb163v1ECPrivateKey() + { + ReadWriteBase64ECPrivateKey( + @" +MFYCAQEEFQD00koUBxIvRFlnvh2TwAk6ZTZ5hqAKBggqhkjOPQMAAaEuAywABAIR +Jy8cVYJCaIjpG9aSV3SUIyJIqgQnCDD3oQCa1nCojekr1ZJIzIE7RQ==", + EccTestData.C2pnb163v1Key1, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1Pkcs8() + { + ReadWriteBase64Pkcs8( + @" +MGYCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAAEETDBKAgEBBBUA9NJKFAcSL0RZZ74d +k8AJOmU2eYahLgMsAAQCEScvHFWCQmiI6RvWkld0lCMiSKoEJwgw96EAmtZwqI3p +K9WSSMyBO0U=", + EccTestData.C2pnb163v1Key1, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1EncryptedPkcs8() + { + ReadWriteBase64EncryptedPkcs8( + @" +MIGPMBsGCSqGSIb3DQEFAzAOBAjdV9IDq+L+5gICCAAEcI1e6RA8kMcYB+PvOcCU +Jj65nXTIrMPmZ0DmFMF9WBg0J+yzxgDhBVynpT2uJntY4FuDlvdpcLRK1EGLZYKf +qYc5zJMYkRZ178bE3DtfrP3UxD34YvbRl2aeu334+wJOm7ApXv81ugt4OoCiPhdg +wiA=", + "secret", + new PbeParameters( + PbeEncryptionAlgorithm.Aes192Cbc, + HashAlgorithmName.SHA512, + 1024), + EccTestData.C2pnb163v1Key1, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1SubjectPublicKeyInfo() + { + ReadWriteBase64SubjectPublicKeyInfo( + @" +MEMwEwYHKoZIzj0CAQYIKoZIzj0DAAEDLAAEAhEnLxxVgkJoiOkb1pJXdJQjIkiq +BCcIMPehAJrWcKiN6SvVkkjMgTtF", + EccTestData.C2pnb163v1Key1, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1ExplicitECPrivateKey() + { + ReadWriteBase64ECPrivateKey( + @" +MIIBBwIBAQQVAPTSShQHEi9EWWe+HZPACTplNnmGoIG6MIG3AgEBMCUGByqGSM49 +AQIwGgICAKMGCSqGSM49AQIDAzAJAgEBAgECAgEIMEQEFQclRrVDUjSkIuB4lnX0 +MsiUNd5SQgQUyVF9BtUkDTz/OMdLILbNTW+d1NkDFQDSwPsVdghg3vHu9NaW5naH +VhUXVAQrBAevaZiVRhA9eTKfzD10iA8zu+gDywHsIyEbWWat6h0/h/fqWEiu8LfK +nwIVBAAAAAAAAAAAAAHmD8iCHMdNrq/BAgECoS4DLAAEAhEnLxxVgkJoiOkb1pJX +dJQjIkiqBCcIMPehAJrWcKiN6SvVkkjMgTtF", + EccTestData.C2pnb163v1Key1Explicit, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1ExplicitPkcs8() + { + ReadWriteBase64Pkcs8( + @" +MIIBFwIBADCBwwYHKoZIzj0CATCBtwIBATAlBgcqhkjOPQECMBoCAgCjBgkqhkjO +PQECAwMwCQIBAQIBAgIBCDBEBBUHJUa1Q1I0pCLgeJZ19DLIlDXeUkIEFMlRfQbV +JA08/zjHSyC2zU1vndTZAxUA0sD7FXYIYN7x7vTWluZ2h1YVF1QEKwQHr2mYlUYQ +PXkyn8w9dIgPM7voA8sB7CMhG1lmreodP4f36lhIrvC3yp8CFQQAAAAAAAAAAAAB +5g/IghzHTa6vwQIBAgRMMEoCAQEEFQD00koUBxIvRFlnvh2TwAk6ZTZ5hqEuAywA +BAIRJy8cVYJCaIjpG9aSV3SUIyJIqgQnCDD3oQCa1nCojekr1ZJIzIE7RQ==", + EccTestData.C2pnb163v1Key1Explicit, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1ExplicitEncryptedPkcs8() + { + ReadWriteBase64EncryptedPkcs8( + @" +MIIBQTAbBgkqhkiG9w0BBQMwDgQI9+ZZnHaqxb0CAggABIIBIM+n6x/Q1hs5OW0F +oOKZmQ0mKNRKb23SMqwo0bJlxseIOVdYzOV2LH1hSWeJb7FMxo6OJXb2CpYSPqv1 +v3lhdLC5t/ViqAOhG70KF+Dy/vZr8rWXRFqy+OdqwxOes/lBsG+Ws9+uEk8+Gm2G +xMHXJNKliSUePlT3wC7z8bCkEvLF7hkGjEAgcABry5Ohq3W2by6Dnd8YWJNgeiW/ +Vu5rT1ThAus7w2TJjWrrEqBbIlQ9nm6/MMj9nYnVVfpPAOk/qX9Or7TmK+Sei88Q +staXBhfJk9ec8laiPpNbhHJSZ2Ph3Snb6SA7MYi5nIMP4RPxOM2eUet4/ueV1O3U +wxcZ+wOsnebIwy4ftKL+klh5EXv/9S5sCjC8g8J2cA6GmcZbiQ==", + "secret", + new PbeParameters( + PbeEncryptionAlgorithm.Aes192Cbc, + HashAlgorithmName.SHA512, + 1024), + EccTestData.C2pnb163v1Key1Explicit, + SupportsC2pnb163v1); + } + + [Fact] + public void ReadWriteC2pnb163v1ExplicitSubjectPublicKeyInfo() + { + ReadWriteBase64SubjectPublicKeyInfo( + @" +MIH0MIHDBgcqhkjOPQIBMIG3AgEBMCUGByqGSM49AQIwGgICAKMGCSqGSM49AQID +AzAJAgEBAgECAgEIMEQEFQclRrVDUjSkIuB4lnX0MsiUNd5SQgQUyVF9BtUkDTz/ +OMdLILbNTW+d1NkDFQDSwPsVdghg3vHu9NaW5naHVhUXVAQrBAevaZiVRhA9eTKf +zD10iA8zu+gDywHsIyEbWWat6h0/h/fqWEiu8LfKnwIVBAAAAAAAAAAAAAHmD8iC +HMdNrq/BAgECAywABAIRJy8cVYJCaIjpG9aSV3SUIyJIqgQnCDD3oQCa1nCojekr +1ZJIzIE7RQ==", + EccTestData.C2pnb163v1Key1Explicit, + SupportsC2pnb163v1); + } + + [Fact] public void NoFuzzySubjectPublicKeyInfo() { using (T key = CreateKey()) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs index e723817..2d6b79e 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs @@ -225,8 +225,18 @@ namespace System.Security.Cryptography.Tests Assert.Equal(c1.G.Y, c2.G.Y); Assert.Equal(c1.Cofactor, c2.Cofactor); Assert.Equal(c1.Order, c2.Order); - Assert.Equal(c1.Seed, c2.Seed); - Assert.Equal(c1.Hash, c2.Hash); + + // Optional parameters. Null is an OK interpretation. + // Different is not. + if (c1.Seed != null && c2.Seed != null) + { + Assert.Equal(c1.Seed, c2.Seed); + } + + if (c1.Hash != null && c2.Hash != null) + { + Assert.Equal(c1.Hash, c2.Hash); + } if (c1.IsPrime) { diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs index f266970..8d3afe1 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs @@ -215,6 +215,24 @@ namespace System.Security.Cryptography.Tests }; } + internal static ECParameters GetNistP256ReferenceKeyExplicit() + { + // From Suite B Implementers's Guide to FIPS 186-3 (ECDSA) + // Section D.1.1 + return new ECParameters + { + Curve = GetNistP256ExplicitCurve(), + + Q = + { + X = "8101ECE47464A6EAD70CF69A6E2BD3D88691A3262D22CBA4F7635EAFF26680A8".HexToByteArray(), + Y = "D8A12BA61D599235F67D9CB4D58F1783D3CA43E78F0A5ABAA624079936C0C3A9".HexToByteArray(), + }, + + D = "70A12C2DB16845ED56FF68CFC21A472B3F04D7D6851BF6349F2D7D5B3452B38A".HexToByteArray(), + }; + } + internal static readonly ECParameters BrainpoolP160r1Key1 = new ECParameters { @@ -227,6 +245,43 @@ namespace System.Security.Cryptography.Tests D = "C5D944547DE115DB2588DC6FDEBA3B473E9C4D96".HexToByteArray(), }; + internal static readonly ECParameters Sect163k1Key1 = + new ECParameters + { + Curve = ECCurve.CreateFromValue("1.3.132.0.1"), + Q = + { + X = "06179E3719CC8125435FE64589D5FCA6DC1887551D".HexToByteArray(), + Y = "0788FEBB62FFC9248D8B398AFE3E0B5C3C02B3FE37".HexToByteArray(), + }, + D = "03C1995ADFAE8C0518DC13DFE6304BB01017E6A412".HexToByteArray(), + }; + + internal static readonly ECParameters Sect163k1Key1Explicit = + new ECParameters + { + Curve = + { + CurveType = ECCurve.ECCurveType.Characteristic2, + Polynomial = "0800000000000000000000000000000000000000C9".HexToByteArray(), + A = "000000000000000000000000000000000000000001".HexToByteArray(), + B = "000000000000000000000000000000000000000001".HexToByteArray(), + G = + { + X = "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8".HexToByteArray(), + Y = "0289070FB05D38FF58321F2E800536D538CCDAA3D9".HexToByteArray(), + }, + Order = "04000000000000000000020108A2E0CC0D99F8A5EF".HexToByteArray(), + Cofactor = new byte[] { 2 }, + }, + Q = + { + X = "06179E3719CC8125435FE64589D5FCA6DC1887551D".HexToByteArray(), + Y = "0788FEBB62FFC9248D8B398AFE3E0B5C3C02B3FE37".HexToByteArray(), + }, + D = "03C1995ADFAE8C0518DC13DFE6304BB01017E6A412".HexToByteArray(), + }; + internal static readonly ECParameters Sect283k1Key1 = new ECParameters { @@ -238,5 +293,42 @@ namespace System.Security.Cryptography.Tests }, D = "00B4F1AE1E7FDCD4B0E82053C08A908852B26231E6C01670FCC6C3EA2C5D3FED40EDF037".HexToByteArray(), }; + + internal static readonly ECParameters C2pnb163v1Key1 = + new ECParameters + { + Curve = ECCurve.CreateFromValue("1.2.840.10045.3.0.1"), + Q = + { + X = "0211272F1C5582426888E91BD692577494232248AA".HexToByteArray(), + Y = "04270830F7A1009AD670A88DE92BD59248CC813B45".HexToByteArray(), + }, + D = "00F4D24A1407122F445967BE1D93C0093A65367986".HexToByteArray(), + }; + + internal static readonly ECParameters C2pnb163v1Key1Explicit = + new ECParameters + { + Curve = + { + CurveType = ECCurve.ECCurveType.Characteristic2, + Polynomial = "080000000000000000000000000000000000000107".HexToByteArray(), + A = "072546B5435234A422E0789675F432C89435DE5242".HexToByteArray(), + B = "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9".HexToByteArray(), + G = + { + X = "07AF69989546103D79329FCC3D74880F33BBE803CB".HexToByteArray(), + Y = "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F".HexToByteArray(), + }, + Order = "0400000000000000000001E60FC8821CC74DAEAFC1".HexToByteArray(), + Cofactor = new byte[] { 2 }, + }, + Q = + { + X = "0211272F1C5582426888E91BD692577494232248AA".HexToByteArray(), + Y = "04270830F7A1009AD670A88DE92BD59248CC813B45".HexToByteArray(), + }, + D = "00F4D24A1407122F445967BE1D93C0093A65367986".HexToByteArray(), + }; } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx index 389d6f3..bdf2a6a 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx @@ -162,6 +162,9 @@ The hash algorithm name cannot be null or empty. + + The specified Characteristic2 curve parameters are not valid. Polynomial, A, B, G.X, G.Y, and Order are required. A, B, G.X, G.Y must be the same length, and the same length as Q.X, Q.Y and D if those are specified. Seed, Cofactor and Hash are optional. Other parameters are not allowed. + The chain context handle is invalid.