using System;
using System.Diagnostics;
using System.IO;
+using System.Numerics;
using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
namespace Internal.Cryptography
{
// Output is the DER encoded value of CONSTRUCTEDSEQUENCE(INTEGER(r), INTEGER(s)).
int halfLength = input.Length / 2;
- byte[][] rEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input.Slice(0, halfLength));
- byte[][] sEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input.Slice(halfLength, halfLength));
-
- return DerEncoder.ConstructSequence(rEncoded, sEncoded);
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ writer.PushSequence();
+ writer.WriteKeyParameterInteger(input.Slice(0, halfLength));
+ writer.WriteKeyParameterInteger(input.Slice(halfLength, halfLength));
+ writer.PopSequence();
+ return writer.Encode();
+ }
}
/// <summary>
{
int size = BitsToBytes(fieldSizeBits);
- try
- {
- DerSequenceReader reader = new DerSequenceReader(input, inputOffset, inputCount);
- byte[] rDer = reader.ReadIntegerBytes();
- byte[] sDer = reader.ReadIntegerBytes();
- byte[] response = new byte[2 * size];
+ AsnReader reader = new AsnReader(input.AsMemory(inputOffset, inputCount), AsnEncodingRules.DER);
+ AsnReader sequenceReader = reader.ReadSequence();
+ reader.ThrowIfNotEmpty();
+ ReadOnlySpan<byte> rDer = sequenceReader.GetIntegerBytes().Span;
+ ReadOnlySpan<byte> sDer = sequenceReader.GetIntegerBytes().Span;
+ sequenceReader.ThrowIfNotEmpty();
- CopySignatureField(rDer, response, 0, size);
- CopySignatureField(sDer, response, size, size);
+ byte[] response = new byte[2 * size];
+ CopySignatureField(rDer, response.AsSpan(0, size));
+ CopySignatureField(sDer, response.AsSpan(size, size));
- return response;
- }
- catch (InvalidOperationException e)
- {
- throw new CryptographicException(SR.Arg_CryptographyException, e);
- }
+ return response;
}
public static int BitsToBytes(int bitLength)
return byteLength;
}
- private static void CopySignatureField(byte[] signatureField, byte[] response, int offset, int fieldLength)
+ private static void CopySignatureField(ReadOnlySpan<byte> signatureField, Span<byte> response)
{
- if (signatureField.Length > fieldLength)
+ if (signatureField.Length > response.Length)
{
// The only way this should be true is if the value required a zero-byte-pad.
- Debug.Assert(signatureField.Length == fieldLength + 1, "signatureField.Length == fieldLength + 1");
+ Debug.Assert(signatureField.Length == response.Length + 1, "signatureField.Length == fieldLength + 1");
Debug.Assert(signatureField[0] == 0, "signatureField[0] == 0");
Debug.Assert(signatureField[1] > 0x7F, "signatureField[1] > 0x7F");
-
- Buffer.BlockCopy(signatureField, 1, response, offset, fieldLength);
- }
- else if (signatureField.Length == fieldLength)
- {
- Buffer.BlockCopy(signatureField, 0, response, offset, fieldLength);
+ signatureField = signatureField.Slice(1);
}
- else
- {
- // If the field is too short then it needs to be prepended
- // with zeroes in the response. Since the array was already
- // zeroed out, just figure out where we need to start copying.
- int writeOffset = fieldLength - signatureField.Length;
- Buffer.BlockCopy(signatureField, 0, response, offset + writeOffset, signatureField.Length);
- }
+ // If the field is too short then it needs to be prepended
+ // with zeroes in the response. Since the array was already
+ // zeroed out, just figure out where we need to start copying.
+ int writeOffset = response.Length - signatureField.Length;
+ signatureField.CopyTo(response.Slice(writeOffset));
}
}
}
out SafeCFDataHandle cfDataOut,
out int pOSStatus);
- internal static DerSequenceReader SecKeyExport(
+ internal static byte[] SecKeyExport(
SafeSecKeyRefHandle key,
- bool exportPrivate)
+ bool exportPrivate,
+ string password)
{
- // Apple requires all private keys to be exported encrypted, but since we're trying to export
- // as parsed structures we will need to decrypt it for the user.
- const string ExportPassword = "DotnetExportPassphrase";
-
SafeCreateHandle exportPassword = exportPrivate
- ? CoreFoundation.CFStringCreateWithCString(ExportPassword)
+ ? CoreFoundation.CFStringCreateWithCString(password)
: s_nullExportString;
int ret;
exportedData = CoreFoundation.CFGetData(cfData);
}
- DerSequenceReader reader = new DerSequenceReader(exportedData);
-
- if (!exportPrivate)
- {
- return reader;
- }
-
- byte tag = reader.PeekTag();
-
- // PKCS#8 defines two structures, PrivateKeyInfo, which starts with an integer,
- // and EncryptedPrivateKey, which starts with an encryption algorithm (DER sequence).
- if (tag == (byte)DerSequenceReader.DerTag.Integer)
- {
- return reader;
- }
-
- const byte ConstructedSequence =
- DerSequenceReader.ConstructedFlag | (byte)DerSequenceReader.DerTag.Sequence;
-
- if (tag == ConstructedSequence)
- {
- return ReadEncryptedPkcs8Blob(ExportPassword, reader);
- }
-
- Debug.Fail($"Data was neither PrivateKey or EncryptedPrivateKey: {tag:X2}");
- throw new CryptographicException();
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "3DES identified from payload by OID")]
- private static DerSequenceReader ReadEncryptedPkcs8Blob(string passphrase, DerSequenceReader reader)
- {
- // EncryptedPrivateKeyInfo::= SEQUENCE {
- // encryptionAlgorithm EncryptionAlgorithmIdentifier,
- // encryptedData EncryptedData }
- //
- // EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- //
- // EncryptedData ::= OCTET STRING
- DerSequenceReader algorithmIdentifier = reader.ReadSequence();
- string algorithmOid = algorithmIdentifier.ReadOidAsString();
-
- // PBES2 (Password-Based Encryption Scheme 2)
- if (algorithmOid != OidPbes2)
- {
- Debug.Fail($"Expected PBES2 ({OidPbes2}), got {algorithmOid}");
- throw new CryptographicException();
- }
-
- // PBES2-params ::= SEQUENCE {
- // keyDerivationFunc AlgorithmIdentifier { { PBES2 - KDFs} },
- // encryptionScheme AlgorithmIdentifier { { PBES2 - Encs} }
- // }
-
- DerSequenceReader pbes2Params = algorithmIdentifier.ReadSequence();
- algorithmIdentifier = pbes2Params.ReadSequence();
-
- string kdfOid = algorithmIdentifier.ReadOidAsString();
-
- // PBKDF2 (Password-Based Key Derivation Function 2)
- if (kdfOid != OidPbkdf2)
- {
- Debug.Fail($"Expected PBKDF2 ({OidPbkdf2}), got {kdfOid}");
- throw new CryptographicException();
- }
-
- // PBKDF2-params ::= SEQUENCE {
- // salt CHOICE {
- // specified OCTET STRING,
- // otherSource AlgorithmIdentifier { { PBKDF2 - SaltSources} }
- // },
- // iterationCount INTEGER (1..MAX),
- // keyLength INTEGER(1..MAX) OPTIONAL,
- // prf AlgorithmIdentifier { { PBKDF2 - PRFs} } DEFAULT algid - hmacWithSHA1
- // }
- DerSequenceReader pbkdf2Params = algorithmIdentifier.ReadSequence();
-
- byte[] salt = pbkdf2Params.ReadOctetString();
- int iterCount = pbkdf2Params.ReadInteger();
- int keySize = -1;
-
- if (pbkdf2Params.HasData && pbkdf2Params.PeekTag() == (byte)DerSequenceReader.DerTag.Integer)
- {
- keySize = pbkdf2Params.ReadInteger();
- }
-
- if (pbkdf2Params.HasData)
- {
- string prfOid = pbkdf2Params.ReadOidAsString();
-
- // SHA-1 is the only hash algorithm our PBKDF2 supports.
- if (prfOid != OidSha1)
- {
- Debug.Fail($"Expected SHA1 ({OidSha1}), got {prfOid}");
- throw new CryptographicException();
- }
- }
-
- DerSequenceReader encryptionScheme = pbes2Params.ReadSequence();
- string cipherOid = encryptionScheme.ReadOidAsString();
-
- // DES-EDE3-CBC (TripleDES in CBC mode)
- if (cipherOid != OidTripleDesCbc)
- {
- Debug.Fail($"Expected DES-EDE3-CBC ({OidTripleDesCbc}), got {cipherOid}");
- throw new CryptographicException();
- }
-
- byte[] decrypted;
-
- using (TripleDES des3 = TripleDES.Create())
- {
- if (keySize == -1)
- {
- foreach (KeySizes keySizes in des3.LegalKeySizes)
- {
- keySize = Math.Max(keySize, keySizes.MaxSize);
- }
- }
-
- byte[] iv = encryptionScheme.ReadOctetString();
-
- using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(passphrase, salt, iterCount))
- using (ICryptoTransform decryptor = des3.CreateDecryptor(pbkdf2.GetBytes(keySize / 8), iv))
- {
- byte[] encrypted = reader.ReadOctetString();
- decrypted = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length);
- }
- }
-
- DerSequenceReader pkcs8Reader = new DerSequenceReader(decrypted);
- return pkcs8Reader;
+ return exportedData;
}
}
}
namespace System.Security.Cryptography.Asn1
{
- [StructLayout(LayoutKind.Sequential)]
- // https://tools.ietf.org/html/rfc3280#section-4.1.1.2
- //
- // AlgorithmIdentifier ::= SEQUENCE {
- // algorithm OBJECT IDENTIFIER,
- // parameters ANY DEFINED BY algorithm OPTIONAL }
- internal partial struct AlgorithmIdentifierAsn
- {
+ internal partial struct AlgorithmIdentifierAsn
+ {
internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
- [ObjectIdentifier(PopulateFriendlyName = true)]
- public Oid Algorithm;
-
- [AnyValue, OptionalValue]
- public ReadOnlyMemory<byte>? Parameters;
-
internal bool Equals(ref AlgorithmIdentifierAsn other)
{
- if (Algorithm.Value != other.Algorithm.Value)
+ if (Algorithm != other.Algorithm)
{
return false;
}
return span[1] == 0;
}
-
- internal void Encode(AsnWriter writer)
- {
- AsnSerializer.Serialize(this, writer);
- }
-
- internal static void Decode(AsnReader reader, out AlgorithmIdentifierAsn decoded)
- {
- if (reader == null)
- throw new ArgumentNullException(nameof(reader));
-
- ReadOnlyMemory<byte> value = reader.GetEncodedValue();
- decoded = AsnSerializer.Deserialize<AlgorithmIdentifierAsn>(value, reader.RuleSet);
- }
-
- internal static AlgorithmIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
- {
- AsnReader reader = new AsnReader(encoded, ruleSet);
-
- Decode(reader, out AlgorithmIdentifierAsn decoded);
- reader.ThrowIfNotEmpty();
- return decoded;
- }
}
}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="AlgorithmIdentifierAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc3280#section-4.1.1.2
+
+ AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL
+ }
+ -->
+ <asn:ObjectIdentifier name="Algorithm" />
+ <asn:AnyValue name="Parameters" optional="true" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct AlgorithmIdentifierAsn
+ {
+ internal Oid Algorithm;
+ internal ReadOnlyMemory<byte>? Parameters;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteObjectIdentifier(Algorithm);
+
+ if (Parameters.HasValue)
+ {
+ writer.WriteEncodedValue(Parameters.Value);
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static AlgorithmIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static AlgorithmIdentifierAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out AlgorithmIdentifierAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out AlgorithmIdentifierAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AlgorithmIdentifierAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ decoded.Algorithm = sequenceReader.ReadObjectIdentifier();
+
+ if (sequenceReader.HasData)
+ {
+ decoded.Parameters = sequenceReader.GetEncodedValue();
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc5652#section-5.3
- //
- // Attribute ::= SEQUENCE {
- // attrType OBJECT IDENTIFIER,
- // attrValues SET OF AttributeValue }
- //
- // AttributeValue ::= ANY
- [StructLayout(LayoutKind.Sequential)]
- internal struct AttributeAsn
- {
- public Oid AttrType;
-
- [AnyValue]
- public ReadOnlyMemory<byte> AttrValues;
-
- internal void Encode(AsnWriter writer)
- {
- AsnSerializer.Serialize(this, writer);
- }
-
- internal static void Decode(AsnReader reader, out AttributeAsn decoded)
- {
- if (reader == null)
- throw new ArgumentNullException(nameof(reader));
-
- ReadOnlyMemory<byte> value = reader.GetEncodedValue();
- decoded = AsnSerializer.Deserialize<AttributeAsn>(value, reader.RuleSet);
- }
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="AttributeAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc5652#section-5.3
+
+ Attribute ::= SEQUENCE {
+ attrType OBJECT IDENTIFIER,
+ attrValues SET OF AttributeValue
+ }
+
+ AttributeValue ::= ANY
+ -->
+ <asn:ObjectIdentifier name="AttrType" />
+ <asn:AnyValue name="AttrValues" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct AttributeAsn
+ {
+ internal Oid AttrType;
+ internal ReadOnlyMemory<byte> AttrValues;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteObjectIdentifier(AttrType);
+ writer.WriteEncodedValue(AttrValues);
+ writer.PopSequence(tag);
+ }
+
+ internal static AttributeAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static AttributeAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out AttributeAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out AttributeAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AttributeAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ decoded.AttrType = sequenceReader.ReadObjectIdentifier();
+ decoded.AttrValues = sequenceReader.GetEncodedValue();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="CurveAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://www.secg.org/sec1-v2.pdf, C.2
+
+ Curve ::= SEQUENCE {
+ a FieldElement,
+ b FieldElement,
+ seed BIT STRING OPTIONAL
+ - Shall be present if used in SpecifiedECDomain
+ - with version equal to ecdpVer2 or ecdpVer3
+ }
+
+ FieldElement ::= OCTET STRING
+ -->
+ <asn:OctetString name="A" />
+ <asn:OctetString name="B" />
+ <asn:BitString name="Seed" optional="true" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct CurveAsn
+ {
+ internal ReadOnlyMemory<byte> A;
+ internal ReadOnlyMemory<byte> B;
+ internal ReadOnlyMemory<byte>? Seed;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteOctetString(A.Span);
+ writer.WriteOctetString(B.Span);
+
+ if (Seed.HasValue)
+ {
+ writer.WriteBitString(Seed.Value.Span);
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static CurveAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static CurveAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out CurveAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out CurveAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpA))
+ {
+ decoded.A = tmpA;
+ }
+ else
+ {
+ decoded.A = sequenceReader.ReadOctetString();
+ }
+
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpB))
+ {
+ decoded.B = tmpB;
+ }
+ else
+ {
+ decoded.B = sequenceReader.ReadOctetString();
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.PrimitiveBitString))
+ {
+
+ if (sequenceReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSeed))
+ {
+ decoded.Seed = tmpSeed;
+ }
+ else
+ {
+ decoded.Seed = sequenceReader.ReadBitString(out _);
+ }
+
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="DssParms"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc3279#section-2.3.2
+
+ Dss-Parms ::= SEQUENCE {
+ p INTEGER,
+ q INTEGER,
+ g INTEGER
+ }
+ -->
+ <asn:Integer name="P" />
+ <asn:Integer name="Q" />
+ <asn:Integer name="G" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct DssParms
+ {
+ internal System.Numerics.BigInteger P;
+ internal System.Numerics.BigInteger Q;
+ internal System.Numerics.BigInteger G;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(P);
+ writer.WriteInteger(Q);
+ writer.WriteInteger(G);
+ writer.PopSequence(tag);
+ }
+
+ internal static DssParms Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static DssParms Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out DssParms decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out DssParms decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DssParms decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ decoded.P = sequenceReader.GetInteger();
+ decoded.Q = sequenceReader.GetInteger();
+ decoded.G = sequenceReader.GetInteger();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Choice
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="ECDomainParameters"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://www.secg.org/sec1-v2.pdf, C.2
+
+ ECDomainParameters{ECDOMAIN:IOSet} ::= CHOICE {
+ specified SpecifiedECDomain,
+ named ECDOMAIN.&id({IOSet}),
+ implicitCA NULL
+ }
+ -->
+ <asn:AsnType name="Specified" typeName="System.Security.Cryptography.Asn1.SpecifiedECDomain" />
+ <asn:ObjectIdentifier name="Named" />
+</asn:Choice>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct ECDomainParameters
+ {
+ internal System.Security.Cryptography.Asn1.SpecifiedECDomain? Specified;
+ internal Oid Named;
+
+#if DEBUG
+ static ECDomainParameters()
+ {
+ var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
+ Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
+ {
+ if (usedTags.TryGetValue(tag, out string existing))
+ {
+ throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
+ }
+
+ usedTags.Add(tag, fieldName);
+ };
+
+ ensureUniqueTag(Asn1Tag.Sequence, "Specified");
+ ensureUniqueTag(Asn1Tag.ObjectIdentifier, "Named");
+ }
+#endif
+
+ internal void Encode(AsnWriter writer)
+ {
+ bool wroteValue = false;
+
+ if (Specified.HasValue)
+ {
+ if (wroteValue)
+ throw new CryptographicException();
+
+ Specified.Value.Encode(writer);
+ wroteValue = true;
+ }
+
+ if (Named != null)
+ {
+ if (wroteValue)
+ throw new CryptographicException();
+
+ writer.WriteObjectIdentifier(Named);
+ wroteValue = true;
+ }
+
+ if (!wroteValue)
+ {
+ throw new CryptographicException();
+ }
+ }
+
+ internal static ECDomainParameters Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, out ECDomainParameters decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out ECDomainParameters decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ Asn1Tag tag = reader.PeekTag();
+
+ if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
+ {
+ System.Security.Cryptography.Asn1.SpecifiedECDomain tmpSpecified;
+ System.Security.Cryptography.Asn1.SpecifiedECDomain.Decode(reader, out tmpSpecified);
+ decoded.Specified = tmpSpecified;
+
+ }
+ else if (tag.HasSameClassAndValue(Asn1Tag.ObjectIdentifier))
+ {
+ decoded.Named = reader.ReadObjectIdentifier();
+ }
+ else
+ {
+ throw new CryptographicException();
+ }
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="ECPrivateKey"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://www.secg.org/sec1-v2.pdf, C.4
+
+ ECPrivateKey ::= SEQUENCE {
+ version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ privateKey OCTET STRING,
+ parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+ }
+ -->
+ <asn:Integer name="Version" backingType="byte" />
+ <asn:OctetString name="PrivateKey" />
+ <asn:AsnType name="Parameters" typeName="System.Security.Cryptography.Asn1.ECDomainParameters" explicitTag="0" optional="true" />
+ <asn:BitString name="PublicKey" explicitTag="1" optional="true" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct ECPrivateKey
+ {
+ internal byte Version;
+ internal ReadOnlyMemory<byte> PrivateKey;
+ internal System.Security.Cryptography.Asn1.ECDomainParameters? Parameters;
+ internal ReadOnlyMemory<byte>? PublicKey;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(Version);
+ writer.WriteOctetString(PrivateKey.Span);
+
+ if (Parameters.HasValue)
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ Parameters.Value.Encode(writer);
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ }
+
+
+ if (PublicKey.HasValue)
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+ writer.WriteBitString(PublicKey.Value.Span);
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static ECPrivateKey Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out ECPrivateKey decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out ECPrivateKey decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivateKey decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+ AsnReader explicitReader;
+
+
+ if (!sequenceReader.TryReadUInt8(out decoded.Version))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+ {
+ decoded.PrivateKey = tmpPrivateKey;
+ }
+ else
+ {
+ decoded.PrivateKey = sequenceReader.ReadOctetString();
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ System.Security.Cryptography.Asn1.ECDomainParameters tmpParameters;
+ System.Security.Cryptography.Asn1.ECDomainParameters.Decode(explicitReader, out tmpParameters);
+ decoded.Parameters = tmpParameters;
+
+ explicitReader.ThrowIfNotEmpty();
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+
+ if (explicitReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpPublicKey))
+ {
+ decoded.PublicKey = tmpPublicKey;
+ }
+ else
+ {
+ decoded.PublicKey = explicitReader.ReadBitString(out _);
+ }
+
+ explicitReader.ThrowIfNotEmpty();
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc5208#section-6
- //
- // EncryptedPrivateKeyInfo ::= SEQUENCE {
- // encryptionAlgorithm EncryptionAlgorithmIdentifier,
- // encryptedData EncryptedData }
- //
- // EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- // EncryptedData ::= OCTET STRING
- [StructLayout(LayoutKind.Sequential)]
- internal struct EncryptedPrivateKeyInfoAsn
- {
- public AlgorithmIdentifierAsn EncryptionAlgorithm;
-
- [OctetString]
- public ReadOnlyMemory<byte> EncryptedData;
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="EncryptedPrivateKeyInfoAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc5208#section-6
+
+ EncryptedPrivateKeyInfo ::= SEQUENCE {
+ encryptionAlgorithm EncryptionAlgorithmIdentifier,
+ encryptedData EncryptedData
+ }
+
+ EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ EncryptedData ::= OCTET STRING
+ -->
+ <asn:AsnType name="EncryptionAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+ <asn:OctetString name="EncryptedData" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct EncryptedPrivateKeyInfoAsn
+ {
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionAlgorithm;
+ internal ReadOnlyMemory<byte> EncryptedData;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ EncryptionAlgorithm.Encode(writer);
+ writer.WriteOctetString(EncryptedData.Span);
+ writer.PopSequence(tag);
+ }
+
+ internal static EncryptedPrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static EncryptedPrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out EncryptedPrivateKeyInfoAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out EncryptedPrivateKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedPrivateKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionAlgorithm);
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpEncryptedData))
+ {
+ decoded.EncryptedData = tmpEncryptedData;
+ }
+ else
+ {
+ decoded.EncryptedData = sequenceReader.ReadOctetString();
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="FieldID"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://www.secg.org/sec1-v2.pdf, C.1
+
+ FieldID { FIELD-ID:IOSet } ::= SEQUENCE { - Finite field
+ fieldType FIELD-ID.&id({IOSet}),
+ parameters FIELD-ID.&Type({IOSet}{@fieldType})
+ }
+ -->
+ <asn:ObjectIdentifier name="FieldType" backingType="string" />
+ <asn:AnyValue name="Parameters" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct FieldID
+ {
+ internal string FieldType;
+ internal ReadOnlyMemory<byte> Parameters;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteObjectIdentifier(FieldType);
+ writer.WriteEncodedValue(Parameters);
+ writer.PopSequence(tag);
+ }
+
+ internal static FieldID Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static FieldID Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out FieldID decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out FieldID decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out FieldID decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ decoded.FieldType = sequenceReader.ReadObjectIdentifierAsString();
+ decoded.Parameters = sequenceReader.GetEncodedValue();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc2898#appendix-A.3
- //
- // PBEParameter ::= SEQUENCE {
- // salt OCTET STRING (SIZE(8)),
- // iterationCount INTEGER }
- //
- // The version from PKCS#12 (pkcs-12PbeParams, https://tools.ietf.org/html/rfc7292#appendix-C)
- // is the same, without limiting the size of the salt value.
- [StructLayout(LayoutKind.Sequential)]
- internal struct PBEParameter
- {
- [OctetString]
- public ReadOnlyMemory<byte> Salt;
-
- // The spec calls out that while there's technically no limit to IterationCount,
- // that specific platforms may have their own limits.
- //
- // This defines ours to uint.MaxValue (and, conveniently, not a negative number)
- public uint IterationCount;
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="PBEParameter"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc2898#appendix-A.3
+
+ PBEParameter ::= SEQUENCE {
+ salt OCTET STRING (SIZE(8)),
+ iterationCount INTEGER
+ }
+
+ The version from PKCS#12 (pkcs-12PbeParams, https://tools.ietf.org/html/rfc7292#appendix-C)
+ is the same, without limiting the size of the salt value.
+ -->
+ <asn:OctetString name="Salt" />
+ <!--
+ The spec calls out that while there's technically no limit to IterationCount,
+ that specific platforms may have their own limits. This defines ours to int.MaxValue.
+ -->
+ <asn:Integer name="IterationCount" backingType="int" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct PBEParameter
+ {
+ internal ReadOnlyMemory<byte> Salt;
+ internal int IterationCount;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteOctetString(Salt.Span);
+ writer.WriteInteger(IterationCount);
+ writer.PopSequence(tag);
+ }
+
+ internal static PBEParameter Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static PBEParameter Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out PBEParameter decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out PBEParameter decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBEParameter decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSalt))
+ {
+ decoded.Salt = tmpSalt;
+ }
+ else
+ {
+ decoded.Salt = sequenceReader.ReadOctetString();
+ }
+
+
+ if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc2898#appendix-A.4
- //
- // PBES2-params ::= SEQUENCE {
- // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
- // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
- //
- [StructLayout(LayoutKind.Sequential)]
- internal struct PBES2Params
- {
- public AlgorithmIdentifierAsn KeyDerivationFunc;
- public AlgorithmIdentifierAsn EncryptionScheme;
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="PBES2Params"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc2898#appendix-A.4
+
+ PBES2-params ::= SEQUENCE {
+ keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
+ }
+ -->
+ <asn:AsnType name="KeyDerivationFunc" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+ <asn:AsnType name="EncryptionScheme" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct PBES2Params
+ {
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyDerivationFunc;
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionScheme;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ KeyDerivationFunc.Encode(writer);
+ EncryptionScheme.Encode(writer);
+ writer.PopSequence(tag);
+ }
+
+ internal static PBES2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static PBES2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out PBES2Params decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out PBES2Params decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBES2Params decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.KeyDerivationFunc);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionScheme);
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc2898#appendix-A.2
- //
- // PBKDF2-params ::= SEQUENCE {
- // salt CHOICE {
- // specified OCTET STRING,
- // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
- // },
- // iterationCount INTEGER (1..MAX),
- // keyLength INTEGER (1..MAX) OPTIONAL,
- // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
- // }
- [StructLayout(LayoutKind.Sequential)]
- internal struct Pbkdf2Params
- {
- public Pbkdf2SaltChoice Salt;
-
- // The spec calls out that while there's technically no limit to IterationCount,
- // that specific platforms may have their own limits.
- //
- // This defines ours to uint.MaxValue (and, conveniently, not a negative number)
- public uint IterationCount;
-
- // The biggest value that makes sense currently is 256/8 => 32.
- [OptionalValue]
- public byte? KeyLength;
-
- [DefaultValue(
- 0x30, 0x0C,
- 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07,
- 0x05, 0x00)]
- public AlgorithmIdentifierAsn Prf;
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="Pbkdf2Params"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc2898#appendix-A.2
+
+ PBKDF2-params ::= SEQUENCE {
+ salt CHOICE {
+ specified OCTET STRING,
+ otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ },
+ iterationCount INTEGER (1..MAX),
+ keyLength INTEGER (1..MAX) OPTIONAL,
+ prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+ }
+ -->
+ <asn:AsnType name="Salt" typeName="System.Security.Cryptography.Asn1.Pbkdf2SaltChoice" />
+ <!--
+ The spec calls out that while there's technically no limit to IterationCount,
+ that specific platforms may have their own limits. This defines ours to int.MaxValue.
+ -->
+ <asn:Integer name="IterationCount" backingType="int" />
+ <!-- The biggest value that makes sense currently is 256/8 => 32. -->
+ <asn:Integer name="KeyLength" backingType="byte" optional="true" />
+ <asn:AsnType name="Prf" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" defaultDerInit="0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct Pbkdf2Params
+ {
+ private static byte[] s_defaultPrf = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 };
+
+ internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt;
+ internal int IterationCount;
+ internal byte? KeyLength;
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf;
+
+#if DEBUG
+ static Pbkdf2Params()
+ {
+ Pbkdf2Params decoded = default;
+ AsnReader reader;
+
+ reader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.Prf);
+ reader.ThrowIfNotEmpty();
+ }
+#endif
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ Salt.Encode(writer);
+ writer.WriteInteger(IterationCount);
+
+ if (KeyLength.HasValue)
+ {
+ writer.WriteInteger(KeyLength.Value);
+ }
+
+
+ // DEFAULT value handler for Prf.
+ {
+ using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+ {
+ Prf.Encode(tmp);
+ ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+ if (!encoded.SequenceEqual(s_defaultPrf))
+ {
+ writer.WriteEncodedValue(encoded.ToArray());
+ }
+ }
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static Pbkdf2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out Pbkdf2Params decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out Pbkdf2Params decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Pbkdf2Params decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+ AsnReader defaultReader;
+
+ System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(sequenceReader, out decoded.Salt);
+
+ if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
+ {
+
+ if (sequenceReader.TryReadUInt8(out byte tmpKeyLength))
+ {
+ decoded.KeyLength = tmpKeyLength;
+ }
+ else
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
+ {
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Prf);
+ }
+ else
+ {
+ defaultReader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.Prf);
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc2898#appendix-A.2
- //
- // PBKDF2-params ::= SEQUENCE {
- // salt CHOICE {
- // specified OCTET STRING,
- // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
- // },
- // iterationCount INTEGER (1..MAX),
- // keyLength INTEGER (1..MAX) OPTIONAL,
- // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
- // algid-hmacWithSHA1
- // }
- [Choice]
- [StructLayout(LayoutKind.Sequential)]
- internal struct Pbkdf2SaltChoice
- {
- [OctetString]
- public ReadOnlyMemory<byte>? Specified;
-
- public AlgorithmIdentifierAsn? OtherSource;
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Choice
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="Pbkdf2SaltChoice"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc2898#appendix-A.2
+
+ PBKDF2-params ::= SEQUENCE {
+ salt CHOICE {
+ specified OCTET STRING,
+ otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ },
+ iterationCount INTEGER (1..MAX),
+ keyLength INTEGER (1..MAX) OPTIONAL,
+ prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+ }
+ -->
+ <asn:OctetString name="Specified" />
+ <asn:AsnType name="OtherSource" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+</asn:Choice>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct Pbkdf2SaltChoice
+ {
+ internal ReadOnlyMemory<byte>? Specified;
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn? OtherSource;
+
+#if DEBUG
+ static Pbkdf2SaltChoice()
+ {
+ var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
+ Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
+ {
+ if (usedTags.TryGetValue(tag, out string existing))
+ {
+ throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
+ }
+
+ usedTags.Add(tag, fieldName);
+ };
+
+ ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "Specified");
+ ensureUniqueTag(Asn1Tag.Sequence, "OtherSource");
+ }
+#endif
+
+ internal void Encode(AsnWriter writer)
+ {
+ bool wroteValue = false;
+
+ if (Specified.HasValue)
+ {
+ if (wroteValue)
+ throw new CryptographicException();
+
+ writer.WriteOctetString(Specified.Value.Span);
+ wroteValue = true;
+ }
+
+ if (OtherSource.HasValue)
+ {
+ if (wroteValue)
+ throw new CryptographicException();
+
+ OtherSource.Value.Encode(writer);
+ wroteValue = true;
+ }
+
+ if (!wroteValue)
+ {
+ throw new CryptographicException();
+ }
+ }
+
+ internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, out Pbkdf2SaltChoice decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out Pbkdf2SaltChoice decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ Asn1Tag tag = reader.PeekTag();
+
+ if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString))
+ {
+
+ if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSpecified))
+ {
+ decoded.Specified = tmpSpecified;
+ }
+ else
+ {
+ decoded.Specified = reader.ReadOctetString();
+ }
+
+ }
+ else if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
+ {
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn tmpOtherSource;
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out tmpOtherSource);
+ decoded.OtherSource = tmpOtherSource;
+
+ }
+ else
+ {
+ throw new CryptographicException();
+ }
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc5208#section-5
- //
- // PrivateKeyInfo ::= SEQUENCE {
- // version Version,
- // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- // privateKey PrivateKey,
- // attributes [0] IMPLICIT Attributes OPTIONAL }
- //
- // Version ::= INTEGER
- // PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
- // PrivateKey ::= OCTET STRING
- // Attributes ::= SET OF Attribute
- [StructLayout(LayoutKind.Sequential)]
- internal struct PrivateKeyInfoAsn
- {
- public byte Version;
-
- public AlgorithmIdentifierAsn PrivateKeyAlgorithm;
-
- [OctetString]
- public ReadOnlyMemory<byte> PrivateKey;
-
- [ExpectedTag(0)]
- [OptionalValue]
- public AttributeAsn[] Attributes;
-
- internal void Encode(AsnWriter writer)
- {
- AsnSerializer.Serialize(this, writer);
- }
-
- internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
- {
- if (reader == null)
- throw new ArgumentNullException(nameof(reader));
-
- ReadOnlyMemory<byte> value = reader.GetEncodedValue();
- decoded = AsnSerializer.Deserialize<PrivateKeyInfoAsn>(value, reader.RuleSet);
- }
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="PrivateKeyInfoAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc5208#section-5
+
+ PrivateKeyInfo ::= SEQUENCE {
+ version Version,
+ privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ privateKey PrivateKey,
+ attributes [0] IMPLICIT Attributes OPTIONAL
+ }
+
+ Version ::= INTEGER
+ PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ PrivateKey ::= OCTET STRING
+ Attributes ::= SET OF Attribute
+ -->
+ <asn:Integer name="Version" backingType="byte" />
+ <asn:AsnType name="PrivateKeyAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+ <asn:OctetString name="PrivateKey" />
+ <asn:SetOf name="Attributes" implicitTag="0" optional="true">
+ <asn:AsnType typeName="System.Security.Cryptography.Asn1.AttributeAsn" />
+ </asn:SetOf>
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct PrivateKeyInfoAsn
+ {
+ internal byte Version;
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PrivateKeyAlgorithm;
+ internal ReadOnlyMemory<byte> PrivateKey;
+ internal System.Security.Cryptography.Asn1.AttributeAsn[] Attributes;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(Version);
+ PrivateKeyAlgorithm.Encode(writer);
+ writer.WriteOctetString(PrivateKey.Span);
+
+ if (Attributes != null)
+ {
+
+ writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+ for (int i = 0; i < Attributes.Length; i++)
+ {
+ Attributes[i].Encode(writer);
+ }
+ writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static PrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static PrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out PrivateKeyInfoAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PrivateKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+ AsnReader collectionReader;
+
+
+ if (!sequenceReader.TryReadUInt8(out decoded.Version))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.PrivateKeyAlgorithm);
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+ {
+ decoded.PrivateKey = tmpPrivateKey;
+ }
+ else
+ {
+ decoded.PrivateKey = sequenceReader.ReadOctetString();
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+ {
+
+ // Decode SEQUENCE OF for Attributes
+ {
+ collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
+ var tmpList = new List<System.Security.Cryptography.Asn1.AttributeAsn>();
+ System.Security.Cryptography.Asn1.AttributeAsn tmpItem;
+
+ while (collectionReader.HasData)
+ {
+ System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem);
+ tmpList.Add(tmpItem);
+ }
+
+ decoded.Attributes = tmpList.ToArray();
+ }
+
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc8017#appendix-A.2.3
- //
- // RSASSA-PSS-params ::= SEQUENCE {
- // hashAlgorithm[0] HashAlgorithm DEFAULT sha1,
- // maskGenAlgorithm[1] MaskGenAlgorithm DEFAULT mgf1SHA1,
- // saltLength[2] INTEGER DEFAULT 20,
- // trailerField[3] TrailerField DEFAULT trailerFieldBC }
- //
- [StructLayout(LayoutKind.Sequential)]
- internal struct PssParamsAsn
- {
- // SEQUENCE(id-sha1, NULL)
- [DefaultValue(0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00)]
- [ExpectedTag(0, ExplicitTag = true)]
- public AlgorithmIdentifierAsn HashAlgorithm;
-
- // SEQUENCE(id-mgf1, SEQUENCE(id-sha1, NULL))
- [DefaultValue(
- 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06,
- 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00)]
- [ExpectedTag(1, ExplicitTag = true)]
- public AlgorithmIdentifierAsn MaskGenAlgorithm;
-
- [DefaultValue(0x02, 0x01, 0x14)]
- [ExpectedTag(2, ExplicitTag = true)]
- public uint SaltLength;
-
- [DefaultValue(0x02, 0x01, 0x01)]
- [ExpectedTag(3, ExplicitTag = true)]
- public uint TrailerField;
-
- internal void Encode(AsnWriter writer)
- {
- AsnSerializer.Serialize(this, writer);
- }
-
- internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
- {
- if (reader == null)
- throw new ArgumentNullException(nameof(reader));
-
- ReadOnlyMemory<byte> value = reader.GetEncodedValue();
- decoded = AsnSerializer.Deserialize<PssParamsAsn>(value, reader.RuleSet);
- }
-
- internal static PssParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
- {
- AsnReader reader = new AsnReader(encoded, ruleSet);
-
- Decode(reader, out PssParamsAsn decoded);
- reader.ThrowIfNotEmpty();
- return decoded;
- }
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="PssParamsAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc8017#appendix-A.2.3
+
+ RSASSA-PSS-params ::= SEQUENCE {
+ hashAlgorithm[0] HashAlgorithm DEFAULT sha1,
+ maskGenAlgorithm[1] MaskGenAlgorithm DEFAULT mgf1SHA1,
+ saltLength[2] INTEGER DEFAULT 20,
+ trailerField[3] TrailerField DEFAULT trailerFieldBC
+ }
+ -->
+ <asn:AsnType name="HashAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" explicitTag="0" defaultDerInit="0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00" />
+ <asn:AsnType name="MaskGenAlgorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" explicitTag="1" defaultDerInit="0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00" />
+ <asn:Integer name="SaltLength" explicitTag="2" backingType="int" defaultDerInit="0x02, 0x01, 0x14" />
+ <asn:Integer name="TrailerField" explicitTag="3" backingType="int" defaultDerInit="0x02, 0x01, 0x01" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct PssParamsAsn
+ {
+ private static byte[] s_defaultHashAlgorithm = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
+
+ private static byte[] s_defaultMaskGenAlgorithm = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
+
+ private static byte[] s_defaultSaltLength = { 0x02, 0x01, 0x14 };
+
+ private static byte[] s_defaultTrailerField = { 0x02, 0x01, 0x01 };
+
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm;
+ internal int SaltLength;
+ internal int TrailerField;
+
+#if DEBUG
+ static PssParamsAsn()
+ {
+ PssParamsAsn decoded = default;
+ AsnReader reader;
+
+ reader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashAlgorithm);
+ reader.ThrowIfNotEmpty();
+
+ reader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenAlgorithm);
+ reader.ThrowIfNotEmpty();
+
+ reader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+
+ if (!reader.TryReadInt32(out decoded.SaltLength))
+ {
+ reader.ThrowIfNotEmpty();
+ }
+
+ reader.ThrowIfNotEmpty();
+
+ reader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+
+ if (!reader.TryReadInt32(out decoded.TrailerField))
+ {
+ reader.ThrowIfNotEmpty();
+ }
+
+ reader.ThrowIfNotEmpty();
+ }
+#endif
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+
+ // DEFAULT value handler for HashAlgorithm.
+ {
+ using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+ {
+ HashAlgorithm.Encode(tmp);
+ ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+ if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ writer.WriteEncodedValue(encoded.ToArray());
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ }
+ }
+ }
+
+
+ // DEFAULT value handler for MaskGenAlgorithm.
+ {
+ using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+ {
+ MaskGenAlgorithm.Encode(tmp);
+ ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+ if (!encoded.SequenceEqual(s_defaultMaskGenAlgorithm))
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+ writer.WriteEncodedValue(encoded.ToArray());
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+ }
+ }
+ }
+
+
+ // DEFAULT value handler for SaltLength.
+ {
+ using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+ {
+ tmp.WriteInteger(SaltLength);
+ ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+ if (!encoded.SequenceEqual(s_defaultSaltLength))
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+ writer.WriteEncodedValue(encoded.ToArray());
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+ }
+ }
+ }
+
+
+ // DEFAULT value handler for TrailerField.
+ {
+ using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+ {
+ tmp.WriteInteger(TrailerField);
+ ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+ if (!encoded.SequenceEqual(s_defaultTrailerField))
+ {
+ writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+ writer.WriteEncodedValue(encoded.ToArray());
+ writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+ }
+ }
+ }
+
+ writer.PopSequence(tag);
+ }
+
+ internal static PssParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static PssParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out PssParamsAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParamsAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+ AsnReader explicitReader;
+ AsnReader defaultReader;
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.HashAlgorithm);
+ explicitReader.ThrowIfNotEmpty();
+ }
+ else
+ {
+ defaultReader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashAlgorithm);
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.MaskGenAlgorithm);
+ explicitReader.ThrowIfNotEmpty();
+ }
+ else
+ {
+ defaultReader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.MaskGenAlgorithm);
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+
+ if (!explicitReader.TryReadInt32(out decoded.SaltLength))
+ {
+ explicitReader.ThrowIfNotEmpty();
+ }
+
+ explicitReader.ThrowIfNotEmpty();
+ }
+ else
+ {
+ defaultReader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+
+ if (!defaultReader.TryReadInt32(out decoded.SaltLength))
+ {
+ defaultReader.ThrowIfNotEmpty();
+ }
+
+ }
+
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
+ {
+ explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
+
+ if (!explicitReader.TryReadInt32(out decoded.TrailerField))
+ {
+ explicitReader.ThrowIfNotEmpty();
+ }
+
+ explicitReader.ThrowIfNotEmpty();
+ }
+ else
+ {
+ defaultReader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+
+ if (!defaultReader.TryReadInt32(out decoded.TrailerField))
+ {
+ defaultReader.ThrowIfNotEmpty();
+ }
+
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="RSAPrivateKeyAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc3447#appendix-C
+
+ RSAPrivateKey ::= SEQUENCE {
+ version Version,
+ modulus INTEGER, - n
+ publicExponent INTEGER, - e
+ privateExponent INTEGER, - d
+ prime1 INTEGER, - p
+ prime2 INTEGER, - q
+ exponent1 INTEGER, - d mod (p-1)
+ exponent2 INTEGER, - d mod (q-1)
+ coefficient INTEGER, - (inverse of q) mod p
+ otherPrimeInfos OtherPrimeInfos OPTIONAL
+ }
+
+ Version ::= INTEGER { two-prime(0), multi(1) }
+ (CONSTRAINED BY {
+ - version must be multi if otherPrimeInfos present -
+ })
+
+ Since we don't support otherPrimeInfos (Version=1) just don't map it in.
+ -->
+ <asn:Integer name="Version" backingType="byte" />
+ <asn:Integer name="Modulus" />
+ <asn:Integer name="PublicExponent" />
+ <asn:Integer name="PrivateExponent" />
+ <asn:Integer name="Prime1" />
+ <asn:Integer name="Prime2" />
+ <asn:Integer name="Exponent1" />
+ <asn:Integer name="Exponent2" />
+ <asn:Integer name="Coefficient" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct RSAPrivateKeyAsn
+ {
+ internal byte Version;
+ internal System.Numerics.BigInteger Modulus;
+ internal System.Numerics.BigInteger PublicExponent;
+ internal System.Numerics.BigInteger PrivateExponent;
+ internal System.Numerics.BigInteger Prime1;
+ internal System.Numerics.BigInteger Prime2;
+ internal System.Numerics.BigInteger Exponent1;
+ internal System.Numerics.BigInteger Exponent2;
+ internal System.Numerics.BigInteger Coefficient;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(Version);
+ writer.WriteInteger(Modulus);
+ writer.WriteInteger(PublicExponent);
+ writer.WriteInteger(PrivateExponent);
+ writer.WriteInteger(Prime1);
+ writer.WriteInteger(Prime2);
+ writer.WriteInteger(Exponent1);
+ writer.WriteInteger(Exponent2);
+ writer.WriteInteger(Coefficient);
+ writer.PopSequence(tag);
+ }
+
+ internal static RSAPrivateKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out RSAPrivateKeyAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out RSAPrivateKeyAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPrivateKeyAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+
+ if (!sequenceReader.TryReadUInt8(out decoded.Version))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+ decoded.Modulus = sequenceReader.GetInteger();
+ decoded.PublicExponent = sequenceReader.GetInteger();
+ decoded.PrivateExponent = sequenceReader.GetInteger();
+ decoded.Prime1 = sequenceReader.GetInteger();
+ decoded.Prime2 = sequenceReader.GetInteger();
+ decoded.Exponent1 = sequenceReader.GetInteger();
+ decoded.Exponent2 = sequenceReader.GetInteger();
+ decoded.Coefficient = sequenceReader.GetInteger();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="RSAPublicKeyAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc3447#appendix-C
+
+ RSAPublicKey ::= SEQUENCE {
+ modulus INTEGER, - n
+ publicExponent INTEGER - e
+ }
+ -->
+ <asn:Integer name="Modulus" />
+ <asn:Integer name="PublicExponent" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct RSAPublicKeyAsn
+ {
+ internal System.Numerics.BigInteger Modulus;
+ internal System.Numerics.BigInteger PublicExponent;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(Modulus);
+ writer.WriteInteger(PublicExponent);
+ writer.PopSequence(tag);
+ }
+
+ internal static RSAPublicKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out RSAPublicKeyAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out RSAPublicKeyAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPublicKeyAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ decoded.Modulus = sequenceReader.GetInteger();
+ decoded.PublicExponent = sequenceReader.GetInteger();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="SpecifiedECDomain"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://www.secg.org/sec1-v2.pdf, C.2
+
+ SpecifiedECDomain ::= SEQUENCE {
+ version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
+ fieldID FieldID {{FieldTypes}},
+ curve Curve,
+ base ECPoint,
+ order INTEGER,
+ cofactor INTEGER OPTIONAL,
+ hash HashAlgorithm OPTIONAL,
+ ...
+ }
+
+ HashAlgorithm ::= AlgorithmIdentifier {{ HashFunctions }}
+ ECPoint ::= OCTET STRING
+ -->
+ <asn:Integer name="Version" backingType="byte" />
+ <asn:AsnType name="FieldID" typeName="System.Security.Cryptography.Asn1.FieldID" />
+ <asn:AsnType name="Curve" typeName="System.Security.Cryptography.Asn1.CurveAsn" />
+ <asn:OctetString name="Base" />
+ <asn:Integer name="Order" backingType="ReadOnlyMemory" />
+ <asn:Integer name="Cofactor" backingType="ReadOnlyMemory" optional="true" />
+ <asn:ObjectIdentifier name="Hash" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct SpecifiedECDomain
+ {
+ internal byte Version;
+ internal System.Security.Cryptography.Asn1.FieldID FieldID;
+ internal System.Security.Cryptography.Asn1.CurveAsn Curve;
+ internal ReadOnlyMemory<byte> Base;
+ internal ReadOnlyMemory<byte> Order;
+ internal ReadOnlyMemory<byte>? Cofactor;
+ internal Oid Hash;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ writer.WriteInteger(Version);
+ FieldID.Encode(writer);
+ Curve.Encode(writer);
+ writer.WriteOctetString(Base.Span);
+ writer.WriteInteger(Order.Span);
+
+ if (Cofactor.HasValue)
+ {
+ writer.WriteInteger(Cofactor.Value.Span);
+ }
+
+ writer.WriteObjectIdentifier(Hash);
+ writer.PopSequence(tag);
+ }
+
+ internal static SpecifiedECDomain Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static SpecifiedECDomain Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out SpecifiedECDomain decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out SpecifiedECDomain decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SpecifiedECDomain decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+
+ if (!sequenceReader.TryReadUInt8(out decoded.Version))
+ {
+ sequenceReader.ThrowIfNotEmpty();
+ }
+
+ System.Security.Cryptography.Asn1.FieldID.Decode(sequenceReader, out decoded.FieldID);
+ System.Security.Cryptography.Asn1.CurveAsn.Decode(sequenceReader, out decoded.Curve);
+
+ if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpBase))
+ {
+ decoded.Base = tmpBase;
+ }
+ else
+ {
+ decoded.Base = sequenceReader.ReadOctetString();
+ }
+
+ decoded.Order = sequenceReader.GetIntegerBytes();
+
+ if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
+ {
+ decoded.Cofactor = sequenceReader.GetIntegerBytes();
+ }
+
+ decoded.Hash = sequenceReader.ReadObjectIdentifier();
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc3280#section-4.1
- //
- // SubjectPublicKeyInfo ::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- [StructLayout(LayoutKind.Sequential)]
- internal partial struct SubjectPublicKeyInfoAsn
- {
- internal AlgorithmIdentifierAsn Algorithm;
-
- [BitString]
- internal ReadOnlyMemory<byte> SubjectPublicKey;
-
- internal void Encode(AsnWriter writer)
- {
- AsnSerializer.Serialize(this, writer);
- }
-
- internal static void Decode(AsnReader reader, out SubjectPublicKeyInfoAsn decoded)
- {
- if (reader == null)
- throw new ArgumentNullException(nameof(reader));
-
- ReadOnlyMemory<byte> value = reader.GetEncodedValue();
- decoded = AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(value, reader.RuleSet);
- }
- }
-}
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+ xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+ name="SubjectPublicKeyInfoAsn"
+ namespace="System.Security.Cryptography.Asn1">
+
+ <!--
+ https://tools.ietf.org/html/rfc3280#section-4.1
+
+ SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ subjectPublicKey BIT STRING
+ }
+ -->
+ <asn:AsnType name="Algorithm" typeName="System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn" />
+ <asn:BitString name="SubjectPublicKey" />
+</asn:Sequence>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct SubjectPublicKeyInfoAsn
+ {
+ internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Algorithm;
+ internal ReadOnlyMemory<byte> SubjectPublicKey;
+
+ internal void Encode(AsnWriter writer)
+ {
+ Encode(writer, Asn1Tag.Sequence);
+ }
+
+ internal void Encode(AsnWriter writer, Asn1Tag tag)
+ {
+ writer.PushSequence(tag);
+
+ Algorithm.Encode(writer);
+ writer.WriteBitString(SubjectPublicKey.Span);
+ writer.PopSequence(tag);
+ }
+
+ internal static SubjectPublicKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+ }
+
+ internal static SubjectPublicKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+ {
+ AsnReader reader = new AsnReader(encoded, ruleSet);
+
+ Decode(reader, expectedTag, out SubjectPublicKeyInfoAsn decoded);
+ reader.ThrowIfNotEmpty();
+ return decoded;
+ }
+
+ internal static void Decode(AsnReader reader, out SubjectPublicKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ Decode(reader, Asn1Tag.Sequence, out decoded);
+ }
+
+ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SubjectPublicKeyInfoAsn decoded)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+
+ decoded = default;
+ AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+
+ System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Algorithm);
+
+ if (sequenceReader.TryGetPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSubjectPublicKey))
+ {
+ decoded.SubjectPublicKey = tmpSubjectPublicKey;
+ }
+ else
+ {
+ decoded.SubjectPublicKey = sequenceReader.ReadBitString(out _);
+ }
+
+
+ sequenceReader.ThrowIfNotEmpty();
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+ internal static class DSAKeyFormatHelper
+ {
+ private static readonly string[] s_validOids =
+ {
+ Oids.Dsa,
+ };
+
+ internal static void ReadDsaPrivateKey(
+ ReadOnlyMemory<byte> xBytes,
+ in AlgorithmIdentifierAsn algId,
+ out DSAParameters ret)
+ {
+ if (!algId.Parameters.HasValue)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER);
+
+ ret = new DSAParameters
+ {
+ P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
+ Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
+ };
+
+ ret.G = parms.G.ExportKeyParameter(ret.P.Length);
+
+ AsnReader reader = new AsnReader(xBytes, AsnEncodingRules.DER);
+ // Force a positive interpretation because Windows sometimes writes negative numbers.
+ BigInteger x = new BigInteger(reader.GetIntegerBytes().Span, isUnsigned: true, isBigEndian: true);
+ ret.X = x.ExportKeyParameter(ret.Q.Length);
+ reader.ThrowIfNotEmpty();
+
+ // The public key is not contained within the format, calculate it.
+ BigInteger y = BigInteger.ModPow(parms.G, x, parms.P);
+ ret.Y = y.ExportKeyParameter(ret.P.Length);
+ }
+
+ internal static void ReadDsaPublicKey(
+ ReadOnlyMemory<byte> yBytes,
+ in AlgorithmIdentifierAsn algId,
+ out DSAParameters ret)
+ {
+ AsnReader reader = new AsnReader(yBytes, AsnEncodingRules.DER);
+ BigInteger y = reader.GetInteger();
+ reader.ThrowIfNotEmpty();
+
+ if (!algId.Parameters.HasValue)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER);
+
+ ret = new DSAParameters
+ {
+ P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
+ Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
+ };
+
+ ret.G = parms.G.ExportKeyParameter(ret.P.Length);
+ ret.Y = y.ExportKeyParameter(ret.P.Length);
+ }
+
+ internal static void ReadSubjectPublicKeyInfo(
+ ReadOnlySpan<byte> source,
+ out int bytesRead,
+ out DSAParameters key)
+ {
+ KeyFormatHelper.ReadSubjectPublicKeyInfo<DSAParameters>(
+ s_validOids,
+ source,
+ ReadDsaPublicKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadPkcs8(
+ ReadOnlySpan<byte> source,
+ out int bytesRead,
+ out DSAParameters key)
+ {
+ KeyFormatHelper.ReadPkcs8<DSAParameters>(
+ s_validOids,
+ source,
+ ReadDsaPrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<char> password,
+ out int bytesRead,
+ out DSAParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters>(
+ s_validOids,
+ source,
+ password,
+ ReadDsaPrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<byte> passwordBytes,
+ out int bytesRead,
+ out DSAParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters>(
+ s_validOids,
+ source,
+ passwordBytes,
+ ReadDsaPrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static AsnWriter WriteSubjectPublicKeyInfo(in DSAParameters dsaParameters)
+ {
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ writer.PushSequence();
+ WriteAlgorithmId(writer, dsaParameters);
+ WriteKeyComponent(writer, dsaParameters.Y, bitString: true);
+ writer.PopSequence();
+
+ return writer;
+ }
+
+ internal static AsnWriter WritePkcs8(in DSAParameters dsaParameters)
+ {
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ writer.PushSequence();
+ writer.WriteInteger(0);
+ WriteAlgorithmId(writer, dsaParameters);
+ WriteKeyComponent(writer, dsaParameters.X, bitString: false);
+ writer.PopSequence();
+
+ return writer;
+ }
+
+ private static void WriteAlgorithmId(AsnWriter writer, in DSAParameters dsaParameters)
+ {
+ writer.PushSequence();
+ writer.WriteObjectIdentifier(Oids.Dsa);
+
+ // Dss-Parms ::= SEQUENCE {
+ // p INTEGER,
+ // q INTEGER,
+ // g INTEGER }
+ writer.PushSequence();
+ writer.WriteKeyParameterInteger(dsaParameters.P);
+ writer.WriteKeyParameterInteger(dsaParameters.Q);
+ writer.WriteKeyParameterInteger(dsaParameters.G);
+ writer.PopSequence();
+ writer.PopSequence();
+ }
+
+ private static void WriteKeyComponent(AsnWriter writer, byte[] component, bool bitString)
+ {
+ using (AsnWriter inner = new AsnWriter(AsnEncodingRules.DER))
+ {
+ inner.WriteKeyParameterInteger(component);
+
+ if (bitString)
+ {
+ writer.WriteBitString(inner.EncodeAsSpan());
+ }
+ else
+ {
+ writer.WriteOctetString(inner.EncodeAsSpan());
+ }
+ }
+ }
+ }
+}
using System.Diagnostics;
using System.IO;
+using System.Numerics;
using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
using Internal.Cryptography;
namespace System.Security.Cryptography
public override DSAParameters ExportParameters(bool includePrivateParameters)
{
+ // Apple requires all private keys to be exported encrypted, but since we're trying to export
+ // as parsed structures we will need to decrypt it for the user.
+ const string ExportPassword = "DotnetExportPassphrase";
SecKeyPair keys = GetKeys();
if (keys.PublicKey == null ||
throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
}
- DSAParameters parameters = new DSAParameters();
+ byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+ includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+ exportPrivate: includePrivateParameters,
+ password: ExportPassword);
- DerSequenceReader publicKeyReader =
- Interop.AppleCrypto.SecKeyExport(keys.PublicKey, exportPrivate: false);
-
- publicKeyReader.ReadSubjectPublicKeyInfo(ref parameters);
-
- if (includePrivateParameters)
+ try
{
- DerSequenceReader privateKeyReader =
- Interop.AppleCrypto.SecKeyExport(keys.PrivateKey, exportPrivate: true);
-
- privateKeyReader.ReadPkcs8Blob(ref parameters);
+ if (!includePrivateParameters)
+ {
+ DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
+ keyBlob,
+ out int localRead,
+ out DSAParameters key);
+ Debug.Assert(localRead == keyBlob.Length);
+ return key;
+ }
+ else
+ {
+ DSAKeyFormatHelper.ReadEncryptedPkcs8(
+ keyBlob,
+ ExportPassword,
+ out int localRead,
+ out DSAParameters key);
+ Debug.Assert(localRead == keyBlob.Length);
+ return key;
+ }
}
-
- KeyBlobHelpers.TrimPaddingByte(ref parameters.P);
- KeyBlobHelpers.TrimPaddingByte(ref parameters.Q);
-
- KeyBlobHelpers.PadOrTrim(ref parameters.G, parameters.P.Length);
- KeyBlobHelpers.PadOrTrim(ref parameters.Y, parameters.P.Length);
-
- if (includePrivateParameters)
+ finally
{
- KeyBlobHelpers.PadOrTrim(ref parameters.X, parameters.Q.Length);
+ CryptographicOperations.ZeroMemory(keyBlob);
}
-
- return parameters;
}
public override void ImportParameters(DSAParameters parameters)
private static SafeSecKeyRefHandle ImportKey(DSAParameters parameters)
{
bool hasPrivateKey = parameters.X != null;
- byte[] blob = hasPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
+ byte[] blob;
+
+ if (hasPrivateKey)
+ {
+ Debug.Assert(parameters.X != null);
+
+ // DSAPrivateKey ::= SEQUENCE(
+ // version INTEGER,
+ // p INTEGER,
+ // q INTEGER,
+ // g INTEGER,
+ // y INTEGER,
+ // x INTEGER,
+ // )
+
+ using (AsnWriter privateKeyWriter = new AsnWriter(AsnEncodingRules.DER))
+ {
+ privateKeyWriter.PushSequence();
+ privateKeyWriter.WriteInteger(0);
+ privateKeyWriter.WriteKeyParameterInteger(parameters.P);
+ privateKeyWriter.WriteKeyParameterInteger(parameters.Q);
+ privateKeyWriter.WriteKeyParameterInteger(parameters.G);
+ privateKeyWriter.WriteKeyParameterInteger(parameters.Y);
+ privateKeyWriter.WriteKeyParameterInteger(parameters.X);
+ privateKeyWriter.PopSequence();
+ blob = privateKeyWriter.Encode();
+ }
+ }
+ else
+ {
+ using (AsnWriter writer = DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
+ {
+ blob = writer.Encode();
+ }
+ }
return Interop.AppleCrypto.ImportEphemeralKey(blob, hasPrivateKey);
}
#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
}
#endif
-
- internal static class DsaKeyBlobHelpers
- {
- private static readonly Oid s_idDsa = new Oid("1.2.840.10040.4.1");
-
- internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref DSAParameters parameters)
- {
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- DerSequenceReader algorithm = keyInfo.ReadSequence();
- string algorithmOid = algorithm.ReadOidAsString();
-
- // EC Public Key
- if (algorithmOid != s_idDsa.Value)
- {
- throw new CryptographicException();
- }
-
- // Dss-Parms ::= SEQUENCE {
- // p INTEGER,
- // q INTEGER,
- // g INTEGER
- // }
-
- DerSequenceReader algParameters = algorithm.ReadSequence();
- byte[] publicKeyBlob = keyInfo.ReadBitString();
- // We don't care about the rest of the blob here, but it's expected to not exist.
-
- ReadSubjectPublicKeyInfo(algParameters, publicKeyBlob, ref parameters);
- }
-
- internal static void ReadSubjectPublicKeyInfo(
- this DerSequenceReader algParameters,
- byte[] publicKeyBlob,
- ref DSAParameters parameters)
- {
- parameters.P = algParameters.ReadIntegerBytes();
- parameters.Q = algParameters.ReadIntegerBytes();
- parameters.G = algParameters.ReadIntegerBytes();
-
- DerSequenceReader privateKeyReader = DerSequenceReader.CreateForPayload(publicKeyBlob);
- parameters.Y = privateKeyReader.ReadIntegerBytes();
-
- KeyBlobHelpers.TrimPaddingByte(ref parameters.P);
- KeyBlobHelpers.TrimPaddingByte(ref parameters.Q);
-
- KeyBlobHelpers.PadOrTrim(ref parameters.G, parameters.P.Length);
- KeyBlobHelpers.PadOrTrim(ref parameters.Y, parameters.P.Length);
- }
-
- internal static byte[] ToSubjectPublicKeyInfo(this DSAParameters parameters)
- {
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
-
- // Dss-Parms ::= SEQUENCE {
- // p INTEGER,
- // q INTEGER,
- // g INTEGER
- // }
-
- return DerEncoder.ConstructSequence(
- DerEncoder.ConstructSegmentedSequence(
- DerEncoder.SegmentedEncodeOid(s_idDsa),
- DerEncoder.ConstructSegmentedSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.G)
- )
- ),
- DerEncoder.SegmentedEncodeBitString(
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Y))
- );
- }
-
- internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref DSAParameters parameters)
- {
- // Since the PKCS#8 blob for DSS/DSA does not include the public key (Y) this
- // structure is only read after filling the public half.
- Debug.Assert(parameters.P != null);
- Debug.Assert(parameters.Q != null);
- Debug.Assert(parameters.G != null);
- Debug.Assert(parameters.Y != null);
-
- // OneAsymmetricKey ::= SEQUENCE {
- // version Version,
- // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- // privateKey PrivateKey,
- // attributes [0] Attributes OPTIONAL,
- // ...,
- // [[2: publicKey [1] PublicKey OPTIONAL ]],
- // ...
- // }
- //
- // PrivateKeyInfo ::= OneAsymmetricKey
- //
- // PrivateKey ::= OCTET STRING
-
- int version = reader.ReadInteger();
-
- // We understand both version 0 and 1 formats,
- // which are now known as v1 and v2, respectively.
- if (version > 1)
- {
- throw new CryptographicException();
- }
-
- {
- // Ensure we're reading DSA, extract the parameters
- DerSequenceReader algorithm = reader.ReadSequence();
-
- string algorithmOid = algorithm.ReadOidAsString();
-
- if (algorithmOid != s_idDsa.Value)
- {
- throw new CryptographicException();
- }
-
- // The Dss-Params SEQUENCE is present here, but not needed since
- // we got it from the public key already.
- }
-
- byte[] privateKeyBlob = reader.ReadOctetString();
- DerSequenceReader privateKeyReader = DerSequenceReader.CreateForPayload(privateKeyBlob);
- parameters.X = privateKeyReader.ReadIntegerBytes();
- }
-
- internal static byte[] ToPrivateKeyBlob(this DSAParameters parameters)
- {
- Debug.Assert(parameters.X != null);
-
- // DSAPrivateKey ::= SEQUENCE(
- // version INTEGER,
- // p INTEGER,
- // q INTEGER,
- // g INTEGER,
- // y INTEGER,
- // x INTEGER,
- // )
-
- return DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(new byte[] { 0 }),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.G),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Y),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.X));
- }
- }
}
throw new ObjectDisposedException(typeof(ECDiffieHellmanSecurityTransformsPublicKey).Name);
}
- return _ecc.ExportParameters(includePrivateParameters: false, keySizeInBIts: -1);
+ return _ecc.ExportParameters(includePrivateParameters: false, keySizeInBits: -1);
}
internal SafeSecKeyRefHandle KeyHandle
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+ internal static class EccKeyFormatHelper
+ {
+ private static readonly string[] s_validOids =
+ {
+ Oids.EcPublicKey,
+ };
+
+ internal static void ReadSubjectPublicKeyInfo(
+ ReadOnlySpan<byte> source,
+ out int bytesRead,
+ out ECParameters key)
+ {
+ KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
+ s_validOids,
+ source,
+ FromECPublicKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<char> password,
+ out int bytesRead,
+ out ECParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
+ s_validOids,
+ source,
+ password,
+ FromECPrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<byte> passwordBytes,
+ out int bytesRead,
+ out ECParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
+ s_validOids,
+ source,
+ passwordBytes,
+ FromECPrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan<byte> key, out int bytesRead)
+ {
+ fixed (byte* ptr = &MemoryMarshal.GetReference(key))
+ {
+ using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, key.Length))
+ {
+ AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+ AlgorithmIdentifierAsn algId = default;
+ ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+ FromECPrivateKey(firstValue, algId, out ECParameters ret);
+ bytesRead = firstValue.Length;
+ return ret;
+ }
+ }
+ }
+
+ internal static void FromECPrivateKey(
+ ReadOnlyMemory<byte> keyData,
+ in AlgorithmIdentifierAsn algId,
+ out ECParameters ret)
+ {
+ ECPrivateKey key = ECPrivateKey.Decode(keyData, AsnEncodingRules.BER);
+
+ ValidateParameters(key.Parameters, algId);
+
+ if (key.Version != 1)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ // Implementation limitation
+ if (key.PublicKey == null)
+ {
+ throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+ }
+
+ ReadOnlySpan<byte> publicKeyBytes = key.PublicKey.Value.Span;
+
+ if (publicKeyBytes.Length == 0)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ // Implementation limitation
+ // 04 (Uncompressed ECPoint) is almost always used.
+ if (publicKeyBytes[0] != 0x04)
+ {
+ throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+ }
+
+ // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
+ if (publicKeyBytes.Length != 2 * key.PrivateKey.Length + 1)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ ECDomainParameters domainParameters;
+
+ if (key.Parameters != null)
+ {
+ domainParameters = key.Parameters.Value;
+ }
+ else
+ {
+ domainParameters = ECDomainParameters.Decode(algId.Parameters.Value, AsnEncodingRules.DER);
+ }
+
+ ret = new ECParameters
+ {
+ Curve = GetCurve(domainParameters),
+ Q =
+ {
+ X = publicKeyBytes.Slice(1, key.PrivateKey.Length).ToArray(),
+ Y = publicKeyBytes.Slice(1 + key.PrivateKey.Length).ToArray(),
+ },
+ D = key.PrivateKey.ToArray(),
+ };
+
+ ret.Validate();
+ }
+
+ internal static void FromECPublicKey(
+ ReadOnlyMemory<byte> key,
+ in AlgorithmIdentifierAsn algId,
+ out ECParameters ret)
+ {
+ if (algId.Parameters == null)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ ReadOnlySpan<byte> publicKeyBytes = key.Span;
+
+ if (publicKeyBytes.Length == 0)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ // Implementation limitation.
+ // 04 (Uncompressed ECPoint) is almost always used.
+ if (publicKeyBytes[0] != 0x04)
+ {
+ throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
+ }
+
+ // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
+ if ((publicKeyBytes.Length & 0x01) != 1)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ int fieldWidth = publicKeyBytes.Length / 2;
+
+ ECDomainParameters domainParameters = ECDomainParameters.Decode(
+ algId.Parameters.Value,
+ AsnEncodingRules.DER);
+
+ ret = new ECParameters
+ {
+ Curve = GetCurve(domainParameters),
+ Q =
+ {
+ X = publicKeyBytes.Slice(1, fieldWidth).ToArray(),
+ Y = publicKeyBytes.Slice(1 + fieldWidth).ToArray(),
+ },
+ };
+
+ ret.Validate();
+ }
+
+ private static void ValidateParameters(ECDomainParameters? keyParameters, in AlgorithmIdentifierAsn algId)
+ {
+ // At least one is required
+ if (keyParameters == null && algId.Parameters == null)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ // If they are both specified they must match.
+ if (keyParameters != null && algId.Parameters != null)
+ {
+ ReadOnlySpan<byte> algIdParameters = algId.Parameters.Value.Span;
+ byte[] verify = ArrayPool<byte>.Shared.Rent(algIdParameters.Length);
+
+ try
+ {
+ // X.509 SubjectPublicKeyInfo specifies DER encoding.
+ // RFC 5915 specifies DER encoding for EC Private Keys.
+ // So we can compare as DER.
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ keyParameters.Value.Encode(writer);
+ if (!writer.TryEncode(verify, out int written) ||
+ written != algIdParameters.Length ||
+ !algIdParameters.SequenceEqual(verify.AsSpan(0, written)))
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+ }
+ }
+ finally
+ {
+ // verify contains public information and does not need to be cleared.
+ ArrayPool<byte>.Shared.Return(verify);
+ }
+ }
+ }
+
+ private static ECCurve GetCurve(in ECDomainParameters domainParameters)
+ {
+ if (domainParameters.Named == null)
+ {
+ throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ Oid curveOid = domainParameters.Named;
+
+ switch (curveOid.Value)
+ {
+ case Oids.secp256r1:
+ curveOid = new Oid(Oids.secp256r1, nameof(ECCurve.NamedCurves.nistP256));
+ break;
+ case Oids.secp384r1:
+ curveOid = new Oid(Oids.secp384r1, nameof(ECCurve.NamedCurves.nistP384));
+ break;
+ case Oids.secp521r1:
+ curveOid = new Oid(Oids.secp521r1, nameof(ECCurve.NamedCurves.nistP521));
+ break;
+ }
+
+ return ECCurve.CreateFromOid(curveOid);
+ }
+
+ internal static AsnWriter WriteSubjectPublicKeyInfo(in ECParameters ecParameters)
+ {
+ ecParameters.Validate();
+
+ if (!ecParameters.Curve.IsNamed)
+ {
+ throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ // Since the public key format for EC keys is not ASN.1,
+ // write the SPKI structure manually.
+
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ // SubjectPublicKeyInfo
+ writer.PushSequence();
+
+ // algorithm
+ WriteAlgorithmIdentifier(ecParameters, writer);
+
+ // subjectPublicKey
+ WriteUncompressedPublicKey(ecParameters, writer);
+
+ writer.PopSequence();
+ return writer;
+ }
+
+ private static AsnWriter WriteAlgorithmIdentifier(in ECParameters ecParameters)
+ {
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+ WriteAlgorithmIdentifier(ecParameters, writer);
+ return writer;
+ }
+
+ private static void WriteAlgorithmIdentifier(in ECParameters ecParameters, AsnWriter writer)
+ {
+ writer.PushSequence();
+
+ writer.WriteObjectIdentifier(Oids.EcPublicKey);
+ WriteEcParameters(ecParameters, writer);
+
+ writer.PopSequence();
+ }
+
+ internal static AsnWriter WritePkcs8PrivateKey(in ECParameters ecParameters)
+ {
+ ecParameters.Validate();
+
+ if (ecParameters.D == null)
+ {
+ 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))
+ {
+ return KeyFormatHelper.WritePkcs8(algorithmIdentifier, ecPrivateKey);
+ }
+ }
+
+ private static void WriteEcParameters(in ECParameters ecParameters, AsnWriter writer)
+ {
+ if (ecParameters.Curve.IsNamed)
+ {
+ Oid oid = ecParameters.Curve.Oid;
+
+ // On Windows the FriendlyName is populated in places where the Value mightn't be.
+ if (string.IsNullOrEmpty(oid.Value))
+ {
+ oid = Oid.FromFriendlyName(oid.FriendlyName, OidGroup.All);
+ }
+
+ writer.WriteObjectIdentifier(oid.Value);
+ }
+ else
+ {
+ throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+ }
+
+ private static void WriteUncompressedPublicKey(in ECParameters ecParameters, AsnWriter writer)
+ {
+ int publicKeyLength = ecParameters.Q.X.Length * 2 + 1;
+ Span<byte> publicKeyBytes = stackalloc byte[0];
+ byte[] publicKeyRented = null;
+
+ if (publicKeyLength < 256)
+ {
+ publicKeyBytes = stackalloc byte[publicKeyLength];
+ }
+ else
+ {
+ publicKeyRented = ArrayPool<byte>.Shared.Rent(publicKeyLength);
+ publicKeyBytes = publicKeyRented.AsSpan(0, publicKeyLength);
+ }
+
+ try
+ {
+ publicKeyBytes[0] = 0x04;
+ ecParameters.Q.X.AsSpan().CopyTo(publicKeyBytes.Slice(1));
+ ecParameters.Q.Y.AsSpan().CopyTo(publicKeyBytes.Slice(1 + ecParameters.Q.X.Length));
+
+ writer.WriteBitString(publicKeyBytes);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(publicKeyBytes);
+
+ if (publicKeyRented != null)
+ {
+ ArrayPool<byte>.Shared.Return(publicKeyRented);
+ }
+ }
+ }
+
+ internal static AsnWriter WriteECPrivateKey(in ECParameters ecParameters)
+ {
+ return WriteEcPrivateKey(ecParameters, includeDomainParameters: true);
+ }
+
+ private static AsnWriter WriteEcPrivateKey(in ECParameters ecParameters, bool includeDomainParameters)
+ {
+ bool returning = false;
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ try
+ {
+ // ECPrivateKey
+ writer.PushSequence();
+
+ // version 1
+ writer.WriteInteger(1);
+
+ // privateKey
+ writer.WriteOctetString(ecParameters.D);
+
+ // domainParameters
+ if (includeDomainParameters)
+ {
+ Asn1Tag explicit0 = new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true);
+ writer.PushSequence(explicit0);
+
+ WriteEcParameters(ecParameters, writer);
+
+ writer.PopSequence(explicit0);
+ }
+
+ // publicKey
+ {
+ Asn1Tag explicit1 = new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true);
+ writer.PushSequence(explicit1);
+
+ WriteUncompressedPublicKey(ecParameters, writer);
+
+ writer.PopSequence(explicit1);
+ }
+
+ writer.PopSequence();
+ returning = true;
+ return writer;
+ }
+ finally
+ {
+ if (!returning)
+ {
+ writer.Dispose();
+ }
+ }
+ }
+ }
+}
using System.Diagnostics;
using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
using Internal.Cryptography;
namespace System.Security.Cryptography
current?.Dispose();
}
- internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBIts)
+ internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits)
{
- SecKeyPair keys = GetOrGenerateKeys(keySizeInBIts);
+ // Apple requires all private keys to be exported encrypted, but since we're trying to export
+ // as parsed structures we will need to decrypt it for the user.
+ const string ExportPassword = "DotnetExportPassphrase";
+ SecKeyPair keys = GetOrGenerateKeys(keySizeInBits);
- SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
-
- if (keyHandle == null)
- {
+ if (keys.PublicKey == null ||
+ (includePrivateParameters && keys.PrivateKey == null))
+ {
throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
}
- DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
- ECParameters parameters = new ECParameters();
+ byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+ includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+ exportPrivate: includePrivateParameters,
+ password: ExportPassword);
- if (includePrivateParameters)
- {
- keyReader.ReadPkcs8Blob(ref parameters);
- }
- else
+ try
{
- keyReader.ReadSubjectPublicKeyInfo(ref parameters);
+ if (!includePrivateParameters)
+ {
+ EccKeyFormatHelper.ReadSubjectPublicKeyInfo(
+ keyBlob,
+ out int localRead,
+ out ECParameters key);
+ return key;
+ }
+ else
+ {
+ EccKeyFormatHelper.ReadEncryptedPkcs8(
+ keyBlob,
+ ExportPassword,
+ out int localRead,
+ out ECParameters key);
+ return key;
+ }
}
-
- int size = AsymmetricAlgorithmHelpers.BitsToBytes(keySizeInBIts);
-
- KeyBlobHelpers.PadOrTrim(ref parameters.Q.X, size);
- KeyBlobHelpers.PadOrTrim(ref parameters.Q.Y, size);
-
- if (includePrivateParameters)
+ finally
{
- KeyBlobHelpers.PadOrTrim(ref parameters.D, size);
+ CryptographicOperations.ZeroMemory(keyBlob);
}
-
- return parameters;
}
public int ImportParameters(ECParameters parameters)
private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
{
bool isPrivateKey = parameters.D != null;
- byte[] blob = isPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
-
- return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
- }
- }
-
- internal static class EcKeyBlobHelpers
- {
- private static readonly byte[] s_version1 = { 1 };
- private static readonly byte[][] s_encodedVersion1 = DerEncoder.SegmentedEncodeUnsignedInteger(s_version1);
-
- private static readonly Oid s_idEcPublicKey = new Oid("1.2.840.10045.2.1", null);
- private static readonly byte[][] s_encodedIdEcPublicKey = DerEncoder.SegmentedEncodeOid(s_idEcPublicKey);
-
- internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref ECParameters parameters)
- {
- // OneAsymmetricKey ::= SEQUENCE {
- // version Version,
- // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- // privateKey PrivateKey,
- // attributes [0] Attributes OPTIONAL,
- // ...,
- // [[2: publicKey [1] PublicKey OPTIONAL ]],
- // ...
- // }
- //
- // PrivateKeyInfo ::= OneAsymmetricKey
- //
- // PrivateKey ::= OCTET STRING
-
- int version = reader.ReadInteger();
-
- // We understand both version 0 and 1 formats,
- // which are now known as v1 and v2, respectively.
- if (version > 1)
- {
- throw new CryptographicException();
- }
+ byte[] blob;
+ if (isPrivateKey)
{
- // Ensure we're reading EC Public Key (well, Private, but the OID says Public)
- DerSequenceReader algorithm = reader.ReadSequence();
-
- string algorithmOid = algorithm.ReadOidAsString();
-
- if (algorithmOid != s_idEcPublicKey.Value)
+ using (AsnWriter privateKey = EccKeyFormatHelper.WriteECPrivateKey(parameters))
{
- throw new CryptographicException();
+ blob = privateKey.Encode();
}
}
-
- byte[] privateKeyBlob = reader.ReadOctetString();
-
- try
+ else
{
- // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
- // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- // privateKey OCTET STRING,
- // parameters [0] Parameters{{IOSet}} OPTIONAL,
- // publicKey [1] BIT STRING OPTIONAL
- // }
- DerSequenceReader keyReader = new DerSequenceReader(privateKeyBlob);
- version = keyReader.ReadInteger();
-
- // We understand the version 1 format
- if (version > 1)
+ using (AsnWriter publicKey = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
{
- throw new CryptographicException();
+ blob = publicKey.Encode();
}
-
- parameters.D = keyReader.ReadOctetString();
-
- // Check for context specific 0
- const byte ConstructedContextSpecific =
- DerSequenceReader.ContextSpecificTagFlag | DerSequenceReader.ConstructedFlag;
-
- const byte ConstructedContextSpecific0 = (ConstructedContextSpecific | 0);
- const byte ConstructedContextSpecific1 = (ConstructedContextSpecific | 1);
-
- if (keyReader.PeekTag() != ConstructedContextSpecific0)
- {
- throw new CryptographicException();
- }
-
- // Parameters ::= CHOICE {
- // ecParameters ECParameters,
- // namedCurve CURVES.&id({ CurveNames}),
- // implicitlyCA NULL
- // }
- DerSequenceReader parametersReader = keyReader.ReadSequence();
-
- if (parametersReader.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- parameters.Curve = ECCurve.CreateFromValue(parametersReader.ReadOidAsString());
-
- // Check for context specific 1
- if (keyReader.PeekTag() != ConstructedContextSpecific1)
- {
- throw new CryptographicException();
- }
-
- keyReader = keyReader.ReadSequence();
- byte[] encodedPoint = keyReader.ReadBitString();
- ReadEncodedPoint(encodedPoint, ref parameters);
-
- // We don't care about the rest of the blob here, but it's expected to not exist.
}
- finally
- {
- Array.Clear(privateKeyBlob, 0, privateKeyBlob.Length);
- }
- }
-
- internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref ECParameters parameters)
- {
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- DerSequenceReader algorithm = keyInfo.ReadSequence();
- string algorithmOid = algorithm.ReadOidAsString();
-
- // EC Public Key
- if (algorithmOid != s_idEcPublicKey.Value)
- {
- throw new CryptographicException();
- }
-
- if (algorithm.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- parameters.Curve = ECCurve.CreateFromValue(algorithm.ReadOidAsString());
-
- byte[] encodedPoint = keyInfo.ReadBitString();
- ReadEncodedPoint(encodedPoint, ref parameters);
-
- // We don't care about the rest of the blob here, but it's expected to not exist.
- }
-
- internal static byte[] ToSubjectPublicKeyInfo(this ECParameters parameters)
- {
- parameters.Validate();
-
- if (!parameters.Curve.IsNamed)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- byte[] pointBlob = GetPointBlob(ref parameters);
-
- return DerEncoder.ConstructSequence(
- DerEncoder.ConstructSegmentedSequence(
- s_encodedIdEcPublicKey,
- DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
- DerEncoder.SegmentedEncodeBitString(pointBlob));
- }
- private static byte[] GetPointBlob(ref ECParameters parameters)
- {
- byte[] pointBlob = new byte[parameters.Q.X.Length + parameters.Q.Y.Length + 1];
-
- // Uncompressed point
- pointBlob[0] = 0x04;
- Buffer.BlockCopy(parameters.Q.X, 0, pointBlob, 1, parameters.Q.X.Length);
- Buffer.BlockCopy(parameters.Q.Y, 0, pointBlob, 1 + parameters.Q.X.Length, parameters.Q.Y.Length);
- return pointBlob;
- }
-
- internal static byte[] ToPrivateKeyBlob(this ECParameters parameters)
- {
- parameters.Validate();
-
- if (!parameters.Curve.IsNamed)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- byte[] pointBlob = GetPointBlob(ref parameters);
-
- // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
- // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- // privateKey OCTET STRING,
- // parameters [0] Parameters{{IOSet}} OPTIONAL,
- // publicKey [1] BIT STRING OPTIONAL
- // }
- return DerEncoder.ConstructSequence(
- s_encodedVersion1,
- DerEncoder.SegmentedEncodeOctetString(parameters.D),
- DerEncoder.ConstructSegmentedContextSpecificValue(
- 0,
- DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
- DerEncoder.ConstructSegmentedContextSpecificValue(
- 1,
- DerEncoder.SegmentedEncodeBitString(pointBlob)));
- }
-
- private static void ReadEncodedPoint(byte[] encodedPoint, ref ECParameters parameters)
- {
- if (encodedPoint == null || encodedPoint.Length < 1)
- {
- throw new CryptographicException();
- }
-
- byte encoding = encodedPoint[0];
-
- switch (encoding)
- {
- // Uncompressed encoding (04 xbytes ybytes)
- case 0x04:
- // Hybrid encoding, ~yp == 0 (06 xbytes ybytes)
- case 0x06:
- // Hybrid encoding, ~yp == 1 (07 xbytes ybytes)
- case 0x07:
- break;
- default:
- Debug.Fail($"Don't know how to read point encoding {encoding}");
- throw new CryptographicException();
- }
-
- // For formats 04, 06, and 07 the X and Y points are equal length, and they should
- // already be left-padded with zeros in cases where they're short.
- int pointEncodingSize = (encodedPoint.Length - 1) / 2;
- byte[] encodedX = new byte[pointEncodingSize];
- byte[] encodedY = new byte[pointEncodingSize];
- Buffer.BlockCopy(encodedPoint, 1, encodedX, 0, pointEncodingSize);
- Buffer.BlockCopy(encodedPoint, 1 + pointEncodingSize, encodedY, 0, pointEncodingSize);
- parameters.Q.X = encodedX;
- parameters.Q.Y = encodedY;
+ return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
}
}
}
// 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.Diagnostics;
+using System.Numerics;
+using System.Security.Cryptography.Asn1;
+
namespace System.Security.Cryptography
{
internal static class KeyBlobHelpers
{
- internal static byte[] TrimPaddingByte(byte[] data)
+ internal static byte[] ExportKeyParameter(this BigInteger value, int length)
{
- byte[] dataLocal = data;
- TrimPaddingByte(ref dataLocal);
- return dataLocal;
- }
+ byte[] target = new byte[length];
- internal static void TrimPaddingByte(ref byte[] data)
- {
- if (data[0] != 0)
- return;
+ if (value.TryWriteBytes(target, out int bytesWritten, isUnsigned: true, isBigEndian: true))
+ {
+ if (bytesWritten < length)
+ {
+ Buffer.BlockCopy(target, 0, target, length - bytesWritten, bytesWritten);
+ target.AsSpan(0, length - bytesWritten).Clear();
+ }
- byte[] newData = new byte[data.Length - 1];
- Buffer.BlockCopy(data, 1, newData, 0, newData.Length);
- data = newData;
- }
+ return target;
+ }
- internal static byte[] PadOrTrim(byte[] data, int length)
- {
- byte[] dataLocal = data;
- PadOrTrim(ref dataLocal, length);
- return dataLocal;
+ throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
}
- internal static void PadOrTrim(ref byte[] data, int length)
+ internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan<byte> integer)
{
- if (data.Length == length)
- return;
+ Debug.Assert(!integer.IsEmpty);
- // Need to skip the sign-padding byte.
- if (data.Length == length + 1 && data[0] == 0)
+ if (integer[0] == 0)
{
- TrimPaddingByte(ref data);
- return;
- }
+ int newStart = 1;
+
+ while (newStart < integer.Length)
+ {
+ if (integer[newStart] >= 0x80)
+ {
+ newStart--;
+ break;
+ }
+
+ if (integer[newStart] != 0)
+ {
+ break;
+ }
- int offset = length - data.Length;
+ newStart++;
+ }
+
+ if (newStart == integer.Length)
+ {
+ newStart--;
+ }
+
+ integer = integer.Slice(newStart);
+ }
- byte[] newData = new byte[length];
- Buffer.BlockCopy(data, 0, newData, offset, data.Length);
- data = newData;
+ writer.WriteIntegerUnsigned(integer);
}
}
}
{
internal static class KeyFormatHelper
{
- internal delegate void KeyReader<TRet, TParsed>(in TParsed key, in AlgorithmIdentifierAsn algId, out TRet ret);
+ internal delegate void KeyReader<TRet>(ReadOnlyMemory<byte> key, in AlgorithmIdentifierAsn algId, out TRet ret);
- internal static unsafe void ReadSubjectPublicKeyInfo<TRet, TParsed>(
+ internal static unsafe void ReadSubjectPublicKeyInfo<TRet>(
string[] validOids,
ReadOnlySpan<byte> source,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
out int bytesRead)
{
// X.509 SubjectPublicKeyInfo is described as DER.
- SubjectPublicKeyInfoAsn spki =
- AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(source, AsnEncodingRules.DER, out int read);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+ int read = reader.PeekEncodedValue().Length;
+ SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
{
return spki.SubjectPublicKey;
}
- private static void ReadSubjectPublicKeyInfo<TRet, TParsed>(
+ private static void ReadSubjectPublicKeyInfo<TRet>(
string[] validOids,
ReadOnlyMemory<byte> source,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
// X.509 SubjectPublicKeyInfo is described as DER.
- SubjectPublicKeyInfoAsn spki =
- AsnSerializer.Deserialize<SubjectPublicKeyInfoAsn>(source, AsnEncodingRules.DER, out int read);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+ int read = reader.PeekEncodedValue().Length;
+ SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
{
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
}
- TParsed parsed;
-
- if (typeof(TParsed) == typeof(ReadOnlyMemory<byte>))
- {
- ReadOnlyMemory<byte> tmp = spki.SubjectPublicKey;
- parsed = (TParsed)(object)tmp;
- }
- else
- {
- // Fails if there are unconsumed bytes.
- parsed = AsnSerializer.Deserialize<TParsed>(
- spki.SubjectPublicKey,
- AsnEncodingRules.DER);
- }
-
- keyReader(parsed, spki.Algorithm, out ret);
+ keyReader(spki.SubjectPublicKey, spki.Algorithm, out ret);
bytesRead = read;
}
- internal static unsafe void ReadPkcs8<TRet, TParsed>(
+ internal static unsafe void ReadPkcs8<TRet>(
string[] validOids,
ReadOnlySpan<byte> source,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
ReadOnlyMemory<byte> source,
out int bytesRead)
{
- PrivateKeyInfoAsn privateKeyInfo =
- AsnSerializer.Deserialize<PrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+ int read = reader.PeekEncodedValue().Length;
+ PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
{
return privateKeyInfo.PrivateKey;
}
- private static void ReadPkcs8<TRet, TParsed>(
+ private static void ReadPkcs8<TRet>(
string[] validOids,
ReadOnlyMemory<byte> source,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
- PrivateKeyInfoAsn privateKeyInfo =
- AsnSerializer.Deserialize<PrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+ int read = reader.PeekEncodedValue().Length;
+ PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
{
}
// Fails if there are unconsumed bytes.
- TParsed parsed = AsnSerializer.Deserialize<TParsed>(
- privateKeyInfo.PrivateKey,
- AsnEncodingRules.BER);
-
- keyReader(parsed, privateKeyInfo.PrivateKeyAlgorithm, out ret);
+ keyReader(privateKeyInfo.PrivateKey, privateKeyInfo.PrivateKeyAlgorithm, out ret);
bytesRead = read;
}
- internal static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
+ internal static unsafe void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlySpan<byte> source,
ReadOnlySpan<char> password,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
}
}
- internal static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
+ internal static unsafe void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlySpan<byte> source,
ReadOnlySpan<byte> passwordBytes,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
}
}
- private static void ReadEncryptedPkcs8<TRet, TParsed>(
+ private static void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlyMemory<byte> source,
ReadOnlySpan<char> password,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
ReadEncryptedPkcs8(
validOids,
- source.Span,
+ source,
password,
ReadOnlySpan<byte>.Empty,
keyReader,
out ret);
}
- private static void ReadEncryptedPkcs8<TRet, TParsed>(
+ private static void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlyMemory<byte> source,
ReadOnlySpan<byte> passwordBytes,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
out ret);
}
- private static unsafe void ReadEncryptedPkcs8<TRet, TParsed>(
- string[] validOids,
- ReadOnlySpan<byte> source,
- ReadOnlySpan<char> password,
- ReadOnlySpan<byte> passwordBytes,
- KeyReader<TRet, TParsed> keyReader,
- out int bytesRead,
- out TRet ret)
- {
- fixed (byte* ptr = &MemoryMarshal.GetReference(source))
- {
- using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
- {
- ReadEncryptedPkcs8(
- validOids,
- manager.Memory,
- password,
- passwordBytes,
- keyReader,
- out bytesRead,
- out ret);
- }
- }
- }
-
- private static void ReadEncryptedPkcs8<TRet, TParsed>(
+ private static void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlyMemory<byte> source,
ReadOnlySpan<char> password,
ReadOnlySpan<byte> passwordBytes,
- KeyReader<TRet, TParsed> keyReader,
+ KeyReader<TRet> keyReader,
out int bytesRead,
out TRet ret)
{
- EncryptedPrivateKeyInfoAsn epki =
- AsnSerializer.Deserialize<EncryptedPrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out int read);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+ int read = reader.PeekEncodedValue().Length;
+ EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
// No supported encryption algorithms produce more bytes of decryption output than there
// were of decryption input.
ReadOnlyMemory<byte> source,
out int bytesRead)
{
- EncryptedPrivateKeyInfoAsn epki =
- AsnSerializer.Deserialize<EncryptedPrivateKeyInfoAsn>(source, AsnEncodingRules.BER, out bytesRead);
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+ int localRead = reader.PeekEncodedValue().Length;
+ EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
// No supported encryption algorithms produce more bytes of decryption output than there
// were of decryption input.
epki.EncryptedData.Span,
decrypted);
+ bytesRead = localRead;
+
return new ArraySegment<byte>(decrypted, 0, decryptedBytes);
}
catch (CryptographicException e)
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
- PBES2Params pbes2Params =
- AsnSerializer.Deserialize<PBES2Params>(algorithmParameters.Value, AsnEncodingRules.BER);
+ PBES2Params pbes2Params = PBES2Params.Decode(algorithmParameters.Value, AsnEncodingRules.BER);
if (pbes2Params.KeyDerivationFunc.Algorithm.Value != Oids.Pbkdf2)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
- Pbkdf2Params pbkdf2Params =
- AsnSerializer.Deserialize<Pbkdf2Params>(parameters.Value, AsnEncodingRules.BER);
+ Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode(parameters.Value, AsnEncodingRules.BER);
// No OtherSource is defined in RFC 2898 or RFC 8018, so whatever
// algorithm was requested isn't one we know.
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
- PBEParameter pbeParameters =
- AsnSerializer.Deserialize<PBEParameter>(algorithmParameters.Value, AsnEncodingRules.BER);
+ PBEParameter pbeParameters = PBEParameter.Decode(algorithmParameters.Value, AsnEncodingRules.BER);
if (pbeParameters.Salt.Length != 8)
{
throw new CryptographicException();
}
- PBEParameter pbeParameters = AsnSerializer.Deserialize<PBEParameter>(
+ PBEParameter pbeParameters = PBEParameter.Decode(
algorithmIdentifier.Parameters.Value,
AsnEncodingRules.BER);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Buffers;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography
+{
+ internal static class RSAKeyFormatHelper
+ {
+ private static readonly string[] s_validOids =
+ {
+ Oids.Rsa,
+ };
+
+ internal static void FromPkcs1PrivateKey(
+ ReadOnlyMemory<byte> keyData,
+ in AlgorithmIdentifierAsn algId,
+ out RSAParameters ret)
+ {
+ RSAPrivateKeyAsn key = RSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER);
+
+ if (!algId.HasNullEquivalentParameters())
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ const int MaxSupportedVersion = 0;
+
+ if (key.Version > MaxSupportedVersion)
+ {
+ throw new CryptographicException(
+ SR.Format(
+ SR.Cryptography_RSAPrivateKey_VersionTooNew,
+ key.Version,
+ MaxSupportedVersion));
+ }
+
+ // The modulus size determines the encoded output size of the CRT parameters.
+ byte[] n = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true);
+ int halfModulusLength = (n.Length + 1) / 2;
+
+ ret = new RSAParameters
+ {
+ Modulus = n,
+ Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
+ D = key.PrivateExponent.ExportKeyParameter(n.Length),
+ P = key.Prime1.ExportKeyParameter(halfModulusLength),
+ Q = key.Prime2.ExportKeyParameter(halfModulusLength),
+ DP = key.Exponent1.ExportKeyParameter(halfModulusLength),
+ DQ = key.Exponent2.ExportKeyParameter(halfModulusLength),
+ InverseQ = key.Coefficient.ExportKeyParameter(halfModulusLength),
+ };
+ }
+
+ internal static void ReadRsaPublicKey(
+ ReadOnlyMemory<byte> keyData,
+ in AlgorithmIdentifierAsn algId,
+ out RSAParameters ret)
+ {
+ RSAPublicKeyAsn key = RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER);
+
+ ret = new RSAParameters
+ {
+ Modulus = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true),
+ Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
+ };
+ }
+
+ internal static void ReadSubjectPublicKeyInfo(
+ ReadOnlySpan<byte> source,
+ out int bytesRead,
+ out RSAParameters key)
+ {
+ KeyFormatHelper.ReadSubjectPublicKeyInfo<RSAParameters>(
+ s_validOids,
+ source,
+ ReadRsaPublicKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static ReadOnlyMemory<byte> ReadSubjectPublicKeyInfo(
+ ReadOnlyMemory<byte> source,
+ out int bytesRead)
+ {
+ return KeyFormatHelper.ReadSubjectPublicKeyInfo(
+ s_validOids,
+ source,
+ out bytesRead);
+ }
+
+ public static void ReadPkcs8(
+ ReadOnlySpan<byte> source,
+ out int bytesRead,
+ out RSAParameters key)
+ {
+ KeyFormatHelper.ReadPkcs8<RSAParameters>(
+ s_validOids,
+ source,
+ FromPkcs1PrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static ReadOnlyMemory<byte> ReadPkcs8(
+ ReadOnlyMemory<byte> source,
+ out int bytesRead)
+ {
+ return KeyFormatHelper.ReadPkcs8(
+ s_validOids,
+ source,
+ out bytesRead);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<char> password,
+ out int bytesRead,
+ out RSAParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>(
+ s_validOids,
+ source,
+ password,
+ FromPkcs1PrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static void ReadEncryptedPkcs8(
+ ReadOnlySpan<byte> source,
+ ReadOnlySpan<byte> passwordBytes,
+ out int bytesRead,
+ out RSAParameters key)
+ {
+ KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters>(
+ s_validOids,
+ source,
+ passwordBytes,
+ FromPkcs1PrivateKey,
+ out bytesRead,
+ out key);
+ }
+
+ internal static AsnWriter WriteSubjectPublicKeyInfo(in ReadOnlySpan<byte> pkcs1PublicKey)
+ {
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ try
+ {
+ writer.PushSequence();
+ WriteAlgorithmIdentifier(writer);
+ writer.WriteBitString(pkcs1PublicKey);
+ writer.PopSequence();
+ }
+ catch
+ {
+ writer.Dispose();
+ throw;
+ }
+
+ return writer;
+ }
+
+ internal static AsnWriter WriteSubjectPublicKeyInfo(in RSAParameters rsaParameters)
+ {
+ using (AsnWriter pkcs1PublicKey = WritePkcs1PublicKey(rsaParameters))
+ {
+ return WriteSubjectPublicKeyInfo(pkcs1PublicKey.EncodeAsSpan());
+ }
+ }
+
+ internal static AsnWriter WritePkcs8PrivateKey(in ReadOnlySpan<byte> pkcs1PrivateKey)
+ {
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
+
+ try
+ {
+ writer.PushSequence();
+ // Version 0 format (no attributes)
+ writer.WriteInteger(0);
+ WriteAlgorithmIdentifier(writer);
+ writer.WriteOctetString(pkcs1PrivateKey);
+ writer.PopSequence();
+ return writer;
+ }
+ catch
+ {
+ writer.Dispose();
+ throw;
+ }
+ }
+
+ internal static AsnWriter WritePkcs8PrivateKey(in RSAParameters rsaParameters)
+ {
+ using (AsnWriter pkcs1PrivateKey = WritePkcs1PrivateKey(rsaParameters))
+ {
+ return WritePkcs8PrivateKey(pkcs1PrivateKey.EncodeAsSpan());
+ }
+ }
+
+ private static void WriteAlgorithmIdentifier(AsnWriter writer)
+ {
+ writer.PushSequence();
+
+ // https://tools.ietf.org/html/rfc3447#appendix-C
+ //
+ // --
+ // -- When rsaEncryption is used in an AlgorithmIdentifier the
+ // -- parameters MUST be present and MUST be NULL.
+ // --
+ writer.WriteObjectIdentifier(Oids.Rsa);
+ writer.WriteNull();
+
+ writer.PopSequence();
+ }
+
+ internal static AsnWriter WritePkcs1PublicKey(in RSAParameters rsaParameters)
+ {
+ if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
+ {
+ throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+ }
+
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+ writer.PushSequence();
+ writer.WriteKeyParameterInteger(rsaParameters.Modulus);
+ writer.WriteKeyParameterInteger(rsaParameters.Exponent);
+ writer.PopSequence();
+
+ return writer;
+ }
+
+ internal static AsnWriter WritePkcs1PrivateKey(in RSAParameters rsaParameters)
+ {
+ if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
+ {
+ throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+ }
+
+ if (rsaParameters.D == null ||
+ rsaParameters.P == null ||
+ rsaParameters.Q == null ||
+ rsaParameters.DP == null ||
+ rsaParameters.DQ == null ||
+ rsaParameters.InverseQ == null)
+ {
+ throw new CryptographicException(SR.Cryptography_NotValidPrivateKey);
+ }
+
+ AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
+
+ writer.PushSequence();
+
+ // Format version 0
+ writer.WriteInteger(0);
+ writer.WriteKeyParameterInteger(rsaParameters.Modulus);
+ writer.WriteKeyParameterInteger(rsaParameters.Exponent);
+ writer.WriteKeyParameterInteger(rsaParameters.D);
+ writer.WriteKeyParameterInteger(rsaParameters.P);
+ writer.WriteKeyParameterInteger(rsaParameters.Q);
+ writer.WriteKeyParameterInteger(rsaParameters.DP);
+ writer.WriteKeyParameterInteger(rsaParameters.DQ);
+ writer.WriteKeyParameterInteger(rsaParameters.InverseQ);
+
+ writer.PopSequence();
+ return writer;
+ }
+ }
+}
using System.Buffers;
using System.Diagnostics;
using System.IO;
+using System.Numerics;
using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
using Internal.Cryptography;
namespace System.Security.Cryptography
public override RSAParameters ExportParameters(bool includePrivateParameters)
{
+ // Apple requires all private keys to be exported encrypted, but since we're trying to export
+ // as parsed structures we will need to decrypt it for the user.
+ const string ExportPassword = "DotnetExportPassphrase";
SecKeyPair keys = GetKeys();
- SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
-
- if (keyHandle == null)
- {
+ if (keys.PublicKey == null ||
+ (includePrivateParameters && keys.PrivateKey == null))
+ {
throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
}
- DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
- RSAParameters parameters = new RSAParameters();
+ byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
+ includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
+ exportPrivate: includePrivateParameters,
+ password: ExportPassword);
- if (includePrivateParameters)
- {
- keyReader.ReadPkcs8Blob(ref parameters);
- }
- else
+ try
{
- // When exporting a key handle opened from a certificate, it seems to
- // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob.
- // So, check for that.
- if (keyReader.PeekTag() == (byte)DerSequenceReader.DerTag.Integer)
+ if (!includePrivateParameters)
{
- keyReader.ReadPkcs1PublicBlob(ref parameters);
+ // When exporting a key handle opened from a certificate, it seems to
+ // export as a PKCS#1 blob instead of an X509 SubjectPublicKeyInfo blob.
+ // So, check for that.
+ // NOTE: It doesn't affect macOS Mojave when SecCertificateCopyKey API
+ // is used.
+ RSAParameters key;
+
+ AsnReader reader = new AsnReader(keyBlob, AsnEncodingRules.BER);
+ AsnReader sequenceReader = reader.ReadSequence();
+
+ if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer))
+ {
+ AlgorithmIdentifierAsn ignored = default;
+ RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key);
+ }
+ else
+ {
+ RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
+ keyBlob,
+ out int localRead,
+ out key);
+ Debug.Assert(localRead == keyBlob.Length);
+ }
+ return key;
}
else
{
- keyReader.ReadSubjectPublicKeyInfo(ref parameters);
+ RSAKeyFormatHelper.ReadEncryptedPkcs8(
+ keyBlob,
+ ExportPassword,
+ out int localRead,
+ out RSAParameters key);
+ return key;
}
}
-
- return parameters;
+ finally
+ {
+ CryptographicOperations.ZeroMemory(keyBlob);
+ }
}
public override void ImportParameters(RSAParameters parameters)
private static SafeSecKeyRefHandle ImportKey(RSAParameters parameters)
{
bool isPrivateKey = parameters.D != null;
- byte[] pkcs1Blob = isPrivateKey ? parameters.ToPkcs1Blob() : parameters.ToSubjectPublicKeyInfo();
-
- return Interop.AppleCrypto.ImportEphemeralKey(pkcs1Blob, isPrivateKey);
- }
- }
-
- private static Exception HashAlgorithmNameNullOrEmpty() =>
- new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, "hashAlgorithm");
- }
-
- internal static class RsaKeyBlobHelpers
- {
- private const string RsaOid = "1.2.840.113549.1.1.1";
-
- // The PKCS#1 version blob for an RSA key based on 2 primes.
- private static readonly byte[] s_versionNumberBytes = { 0 };
+ byte[] pkcs1Blob;
- // The AlgorithmIdentifier structure for RSA contains an explicit NULL, for legacy/compat reasons.
- private static readonly byte[][] s_encodedRsaAlgorithmIdentifier =
- DerEncoder.ConstructSegmentedSequence(
- DerEncoder.SegmentedEncodeOid(new Oid(RsaOid)),
- // DER:NULL (0x05 0x00)
- new byte[][]
- {
- new byte[] { (byte)DerSequenceReader.DerTag.Null },
- new byte[] { 0 },
- Array.Empty<byte>(),
- });
-
- internal static byte[] ToPkcs1Blob(this RSAParameters parameters)
- {
- if (parameters.Exponent == null || parameters.Modulus == null)
- throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
-
- if (parameters.D == null)
- {
- if (parameters.P != null ||
- parameters.DP != null ||
- parameters.Q != null ||
- parameters.DQ != null ||
- parameters.InverseQ != null)
+ if (isPrivateKey)
{
- throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
+ using (AsnWriter pkcs1PrivateKey = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters))
+ {
+ pkcs1Blob = pkcs1PrivateKey.Encode();
+ }
}
-
- return DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent));
- }
-
- if (parameters.P == null ||
- parameters.DP == null ||
- parameters.Q == null ||
- parameters.DQ == null ||
- parameters.InverseQ == null)
- {
- throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
- }
-
- return DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(s_versionNumberBytes),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.D),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.P),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Q),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.DP),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.DQ),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.InverseQ));
- }
-
- internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref RSAParameters parameters)
- {
- // OneAsymmetricKey ::= SEQUENCE {
- // version Version,
- // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- // privateKey PrivateKey,
- // attributes [0] Attributes OPTIONAL,
- // ...,
- // [[2: publicKey [1] PublicKey OPTIONAL ]],
- // ...
- // }
- //
- // PrivateKeyInfo ::= OneAsymmetricKey
- //
- // PrivateKey ::= OCTET STRING
-
- int version = reader.ReadInteger();
-
- // We understand both version 0 and 1 formats,
- // which are now known as v1 and v2, respectively.
- if (version > 1)
- {
- throw new CryptographicException();
- }
-
- {
- // Ensure we're reading RSA
- DerSequenceReader algorithm = reader.ReadSequence();
-
- string algorithmOid = algorithm.ReadOidAsString();
-
- if (algorithmOid != RsaOid)
+ else
{
- throw new CryptographicException();
+ using (AsnWriter pkcs1PublicKey = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
+ {
+ pkcs1Blob = pkcs1PublicKey.Encode();
+ }
}
- }
-
- byte[] privateKeyBytes = reader.ReadOctetString();
- // Because this was an RSA private key, the key format is PKCS#1.
- ReadPkcs1PrivateBlob(privateKeyBytes, ref parameters);
-
- // We don't care about the rest of the blob here, but it's expected to not exist.
- }
-
- internal static byte[] ToSubjectPublicKeyInfo(this RSAParameters parameters)
- {
- Debug.Assert(parameters.D == null);
-
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- return DerEncoder.ConstructSequence(
- s_encodedRsaAlgorithmIdentifier,
- DerEncoder.SegmentedEncodeBitString(
- parameters.ToPkcs1Blob()));
- }
-
- internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref RSAParameters parameters)
- {
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- DerSequenceReader algorithm = keyInfo.ReadSequence();
- string algorithmOid = algorithm.ReadOidAsString();
- if (algorithmOid != RsaOid)
- {
- throw new CryptographicException();
+ return Interop.AppleCrypto.ImportEphemeralKey(pkcs1Blob, isPrivateKey);
}
-
- byte[] subjectPublicKeyBytes = keyInfo.ReadBitString();
-
- DerSequenceReader subjectPublicKey = new DerSequenceReader(subjectPublicKeyBytes);
- subjectPublicKey.ReadPkcs1PublicBlob(ref parameters);
- }
-
- internal static void ReadPkcs1PublicBlob(this DerSequenceReader subjectPublicKey, ref RSAParameters parameters)
- {
- parameters.Modulus = KeyBlobHelpers.TrimPaddingByte(subjectPublicKey.ReadIntegerBytes());
- parameters.Exponent = KeyBlobHelpers.TrimPaddingByte(subjectPublicKey.ReadIntegerBytes());
-
- if (subjectPublicKey.HasData)
- throw new CryptographicException();
}
- private static void ReadPkcs1PrivateBlob(byte[] privateKeyBytes, ref RSAParameters parameters)
- {
- // RSAPrivateKey::= SEQUENCE {
- // version Version,
- // modulus INTEGER, --n
- // publicExponent INTEGER, --e
- // privateExponent INTEGER, --d
- // prime1 INTEGER, --p
- // prime2 INTEGER, --q
- // exponent1 INTEGER, --d mod(p - 1)
- // exponent2 INTEGER, --d mod(q - 1)
- // coefficient INTEGER, --(inverse of q) mod p
- // otherPrimeInfos OtherPrimeInfos OPTIONAL
- // }
- DerSequenceReader privateKey = new DerSequenceReader(privateKeyBytes);
- int version = privateKey.ReadInteger();
-
- if (version != 0)
- {
- throw new CryptographicException();
- }
-
- parameters.Modulus = KeyBlobHelpers.TrimPaddingByte(privateKey.ReadIntegerBytes());
- parameters.Exponent = KeyBlobHelpers.TrimPaddingByte(privateKey.ReadIntegerBytes());
-
- int modulusLen = parameters.Modulus.Length;
- // Add one so that odd byte-length values (RSA 1032) get padded correctly.
- int halfModulus = (modulusLen + 1) / 2;
-
- parameters.D = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), modulusLen);
- parameters.P = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
- parameters.Q = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
- parameters.DP = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
- parameters.DQ = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
- parameters.InverseQ = KeyBlobHelpers.PadOrTrim(privateKey.ReadIntegerBytes(), halfModulus);
-
- if (privateKey.HasData)
- {
- throw new CryptographicException();
- }
- }
+ private static Exception HashAlgorithmNameNullOrEmpty() =>
+ new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, "hashAlgorithm");
}
}
dest[2] = (byte)((value & 0xFF00) >> 8);
dest[3] = (byte)(value & 0xFF);
}
-
- internal static byte[] ExportKeyParameter(this BigInteger value, int length)
- {
- byte[] target = new byte[length];
-
- if (value.TryWriteBytes(target, out int bytesWritten, isUnsigned: true, isBigEndian: true))
- {
- if (bytesWritten < length)
- {
- Buffer.BlockCopy(target, 0, target, length - bytesWritten, bytesWritten);
- target.AsSpan(0, length - bytesWritten).Clear();
- }
-
- return target;
- }
-
- throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
- }
-
- internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan<byte> integer)
- {
- Debug.Assert(!integer.IsEmpty);
-
- if (integer[0] == 0)
- {
- int newStart = 1;
-
- while (newStart < integer.Length)
- {
- if (integer[newStart] >= 0x80)
- {
- newStart--;
- break;
- }
-
- if (integer[newStart] != 0)
- {
- break;
- }
-
- newStart++;
- }
-
- if (newStart == integer.Length)
- {
- newStart--;
- }
-
- integer = integer.Slice(newStart);
- }
-
- writer.WriteIntegerUnsigned(integer);
- }
}
}
<data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
<value>Unused bit count must be between 0 and 7, inclusive.</value>
</data>
- <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
- <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
- <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
- <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
- <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
- <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
- </data>
- <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
- <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_PopulateFriendlyNameOnString" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has [ObjectIdentifier].PopulateFriendlyName set to true, which is not applicable to a string. Change the field to '{2}' or set PopulateFriendlyName to false.</value>
- </data>
- <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
- <value>Unable to set field {0} on type {1}.</value>
- </data>
- <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
- </data>
- <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
- <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
- </data>
- <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
- </data>
- <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
- <value>Could not determine how to serialize or deserialize type '{0}'.</value>
- </data>
<data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
<value>Encode cannot be called while a Sequence or SetOf is still open.</value>
</data>
<NoWarn>CS3016;CA5351;$(NoWarn)</NoWarn>
<Configurations>netcoreapp-OSX-Debug;netcoreapp-OSX-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
</PropertyGroup>
+ <Import Project="$(CommonPath)\System\Security\Cryptography\Asn1\AsnXml.targets"/>
<ItemGroup>
<Compile Include="Internal\Cryptography\AesImplementation.cs" />
<Compile Include="Internal\Cryptography\DesImplementation.cs" />
<Compile Include="System\Security\Cryptography\AsymmetricKeyExchangeFormatter.cs" />
<Compile Include="System\Security\Cryptography\AsymmetricSignatureDeformatter.cs" />
<Compile Include="System\Security\Cryptography\AsymmetricSignatureFormatter.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\CurveAsn.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\DSSParms.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\DsaPrivateKeyAsn.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\ECDomainParameters.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\ECPrivateKey.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\FieldID.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\RSAPublicKeyAsn.cs" />
- <Compile Include="System\Security\Cryptography\Asn1\SpecifiedECDomain.cs" />
<Compile Include="System\Security\Cryptography\CryptoConfig.cs" />
<Compile Include="System\Security\Cryptography\DeriveBytes.cs" />
<Compile Include="System\Security\Cryptography\DES.cs" />
<Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
<Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
- <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
<Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\AsnWriter.cs">
<Link>Common\System\Security\Cryptography\AsnWriter.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\DSAKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\DSAKeyFormatHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\EccKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\EccKeyFormatHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+ <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\KeyFormatHelper.cs">
<Link>Common\System\Security\Cryptography\KeyFormatHelper.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\Pkcs12Kdf.cs">
<Link>Common\System\Security\Cryptography\Pkcs12Kdf.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RSAKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\RSAKeyFormatHelper.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
<Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\DssParms.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\FieldID.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
- <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSASecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\RSASecurityTransforms.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
- <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
- <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanDerivation.cs">
<Link>Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs</Link>
</Compile>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Reference Include="System.Runtime.Numerics" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="@(AsnXml)" />
+ </ItemGroup>
</Project>
\ No newline at end of file
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://www.secg.org/sec1-v2.pdf, C.2
- //
- // Curve ::= SEQUENCE {
- // a FieldElement,
- // b FieldElement,
- // seed BIT STRING OPTIONAL
- // -- Shall be present if used in SpecifiedECDomain
- // -- with version equal to ecdpVer2 or ecdpVer3
- // }
- //
- // FieldElement ::= OCTET STRING
- [StructLayout(LayoutKind.Sequential)]
- internal struct CurveAsn
- {
- [OctetString]
- public ReadOnlyMemory<byte> A;
-
- [OctetString]
- public ReadOnlyMemory<byte> B;
-
- [BitString, OptionalValue]
- public ReadOnlyMemory<byte>? Seed;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc3279#section-2.3.2
- //
- // Dss-Parms ::= SEQUENCE {
- // p INTEGER,
- // q INTEGER,
- // g INTEGER }
- [StructLayout(LayoutKind.Sequential)]
- internal struct DssParms
- {
- public BigInteger P;
- public BigInteger Q;
- public BigInteger G;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // The private key field is just an integer, but we need the raw bytes.
- [Choice]
- [StructLayout(LayoutKind.Sequential)]
- internal struct DsaPrivateKeyAsn
- {
- [Integer]
- public ReadOnlyMemory<byte>? X;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://www.secg.org/sec1-v2.pdf, C.2
- //
- // ECDomainParameters{ECDOMAIN:IOSet} ::= CHOICE {
- // specified SpecifiedECDomain,
- // named ECDOMAIN.&id({IOSet}),
- // implicitCA NULL
- // }
- [Choice]
- [StructLayout(LayoutKind.Sequential)]
- internal struct ECDomainParameters
- {
- public SpecifiedECDomain? Specified;
-
- [ObjectIdentifier(PopulateFriendlyName = true)]
- public Oid Named;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://www.secg.org/sec1-v2.pdf, C.4
- //
- // ECPrivateKey ::= SEQUENCE {
- // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- // privateKey OCTET STRING,
- // parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
- // publicKey [1] BIT STRING OPTIONAL
- // }
- [StructLayout(LayoutKind.Sequential)]
- internal struct ECPrivateKey
- {
- public byte Version;
-
- [OctetString]
- public ReadOnlyMemory<byte> PrivateKey;
-
- [OptionalValue]
- [ExpectedTag(0, ExplicitTag = true)]
- public ECDomainParameters? Parameters;
-
- [BitString, OptionalValue]
- [ExpectedTag(1, ExplicitTag = true)]
- public ReadOnlyMemory<byte>? PublicKey;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://www.secg.org/sec1-v2.pdf, C.1
- //
- // FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
- // fieldType FIELD-ID.&id({IOSet}),
- // parameters FIELD-ID.&Type({IOSet}{@fieldType})
- // }
- [StructLayout(LayoutKind.Sequential)]
- internal struct FieldID
- {
- [ObjectIdentifier]
- public string FieldType;
-
- [AnyValue]
- public ReadOnlyMemory<byte> Parameters;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc3447#appendix-C
- //
- // RSAPrivateKey ::= SEQUENCE {
- // version Version,
- // modulus INTEGER, -- n
- // publicExponent INTEGER, -- e
- // privateExponent INTEGER, -- d
- // prime1 INTEGER, -- p
- // prime2 INTEGER, -- q
- // exponent1 INTEGER, -- d mod (p-1)
- // exponent2 INTEGER, -- d mod (q-1)
- // coefficient INTEGER, -- (inverse of q) mod p
- // otherPrimeInfos OtherPrimeInfos OPTIONAL
- // }
- //
- // Version ::= INTEGER { two-prime(0), multi(1) }
- // (CONSTRAINED BY {
- // -- version must be multi if otherPrimeInfos present --
- // })
- //
- // Since we don't support otherPrimeInfos (Version=1) just don't map it in.
- [StructLayout(LayoutKind.Sequential)]
- internal struct RSAPrivateKeyAsn
- {
- internal byte Version;
- internal BigInteger Modulus;
- internal BigInteger PublicExponent;
- internal BigInteger PrivateExponent;
- internal BigInteger Prime1;
- internal BigInteger Prime2;
- internal BigInteger Exponent1;
- internal BigInteger Exponent2;
- internal BigInteger Coefficient;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Numerics;
-using System.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://tools.ietf.org/html/rfc3447#appendix-C
- //
- // RSAPublicKey ::= SEQUENCE {
- // modulus INTEGER, -- n
- // publicExponent INTEGER -- e
- // }
- [StructLayout(LayoutKind.Sequential)]
- internal struct RSAPublicKey
- {
- internal BigInteger Modulus;
- internal BigInteger PublicExponent;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// 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.Runtime.InteropServices;
-
-namespace System.Security.Cryptography.Asn1
-{
- // https://www.secg.org/sec1-v2.pdf, C.2
- //
- // SpecifiedECDomain ::= SEQUENCE {
- // version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
- // fieldID FieldID {{FieldTypes}},
- // curve Curve,
- // base ECPoint,
- // order INTEGER,
- // cofactor INTEGER OPTIONAL,
- // hash HashAlgorithm OPTIONAL,
- // ...
- // }
- //
- // HashAlgorithm ::= AlgorithmIdentifier {{ HashFunctions }}
- // ECPoint ::= OCTET STRING
- [StructLayout(LayoutKind.Sequential)]
- internal struct SpecifiedECDomain
- {
- public byte Version;
-
- public FieldID FieldID;
-
- public CurveAsn Curve;
-
- [OctetString]
- public ReadOnlyMemory<byte> Base;
-
- [Integer]
- public ReadOnlyMemory<byte> Order;
-
- [Integer, OptionalValue]
- public ReadOnlyMemory<byte>? Cofactor;
-
- [OptionalValue]
- [ObjectIdentifier(PopulateFriendlyName = true)]
- public Oid Hash;
- }
-}
{
public abstract partial class DSA : AsymmetricAlgorithm
{
- private static readonly string[] s_validOids =
- {
- Oids.Dsa,
- };
-
public abstract DSAParameters ExportParameters(bool includePrivateParameters);
public abstract void ImportParameters(DSAParameters parameters);
{
try
{
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
- writer.PushSequence();
- writer.WriteInteger(0);
- WriteAlgorithmId(writer, dsaParameters);
- WriteKeyComponent(writer, dsaParameters.X, bitString: false);
- writer.PopSequence();
-
- return writer;
+ return DSAKeyFormatHelper.WritePkcs8(dsaParameters);
}
finally
{
private AsnWriter WriteSubjectPublicKeyInfo()
{
DSAParameters dsaParameters = ExportParameters(false);
-
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
- writer.PushSequence();
- WriteAlgorithmId(writer, dsaParameters);
- WriteKeyComponent(writer, dsaParameters.Y, bitString: true);
- writer.PopSequence();
-
- return writer;
- }
-
- private void WriteAlgorithmId(AsnWriter writer, in DSAParameters dsaParameters)
- {
- writer.PushSequence();
- writer.WriteObjectIdentifier(Oids.Dsa);
-
- // Dss-Parms ::= SEQUENCE {
- // p INTEGER,
- // q INTEGER,
- // g INTEGER }
- writer.PushSequence();
- writer.WriteKeyParameterInteger(dsaParameters.P);
- writer.WriteKeyParameterInteger(dsaParameters.Q);
- writer.WriteKeyParameterInteger(dsaParameters.G);
- writer.PopSequence();
- writer.PopSequence();
- }
-
- private void WriteKeyComponent(AsnWriter writer, byte[] component, bool bitString)
- {
- using (AsnWriter inner = new AsnWriter(AsnEncodingRules.DER))
- {
- inner.WriteKeyParameterInteger(component);
-
- if (bitString)
- {
- writer.WriteBitString(inner.EncodeAsSpan());
- }
- else
- {
- writer.WriteOctetString(inner.EncodeAsSpan());
- }
- }
+ return DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(dsaParameters);
}
public override unsafe void ImportEncryptedPkcs8PrivateKey(
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters, DsaPrivateKeyAsn>(
- s_validOids,
+ DSAKeyFormatHelper.ReadEncryptedPkcs8(
source,
passwordBytes,
- ReadDsaPrivateKey,
out int localRead,
out DSAParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<DSAParameters, DsaPrivateKeyAsn>(
- s_validOids,
+ DSAKeyFormatHelper.ReadEncryptedPkcs8(
source,
password,
- ReadDsaPrivateKey,
out int localRead,
out DSAParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadPkcs8<DSAParameters, DsaPrivateKeyAsn>(
- s_validOids,
+ DSAKeyFormatHelper.ReadPkcs8(
source,
- ReadDsaPrivateKey,
out int localRead,
out DSAParameters key);
bytesRead = localRead;
}
- private void ReadDsaPrivateKey(
- in DsaPrivateKeyAsn key,
- in AlgorithmIdentifierAsn algId,
- out DSAParameters ret)
- {
- if (!algId.Parameters.HasValue)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- DssParms parms =
- AsnSerializer.Deserialize<DssParms>(algId.Parameters.Value, AsnEncodingRules.BER);
-
- ret = new DSAParameters
- {
- P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
- Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
- };
-
- ret.G = parms.G.ExportKeyParameter(ret.P.Length);
-
- // Force a positive interpretation because Windows sometimes writes negative numbers.
- BigInteger x = new BigInteger(key.X.Value.Span, isUnsigned: true, isBigEndian: true);
- ret.X = x.ExportKeyParameter(ret.Q.Length);
-
- // The public key is not contained within the format, calculate it.
- BigInteger y = BigInteger.ModPow(parms.G, x, parms.P);
- ret.Y = y.ExportKeyParameter(ret.P.Length);
- }
-
- private void ReadDsaPublicKey(
- in BigInteger y,
- in AlgorithmIdentifierAsn algId,
- out DSAParameters ret)
- {
- if (!algId.Parameters.HasValue)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- DssParms parms =
- AsnSerializer.Deserialize<DssParms>(algId.Parameters.Value, AsnEncodingRules.BER);
-
- ret = new DSAParameters
- {
- P = parms.P.ToByteArray(isUnsigned: true, isBigEndian: true),
- Q = parms.Q.ToByteArray(isUnsigned: true, isBigEndian: true),
- };
-
- ret.G = parms.G.ExportKeyParameter(ret.P.Length);
- ret.Y = y.ExportKeyParameter(ret.P.Length);
- }
-
public override void ImportSubjectPublicKeyInfo(
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadSubjectPublicKeyInfo<DSAParameters, BigInteger>(
- s_validOids,
+ DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
source,
- ReadDsaPublicKey,
out int localRead,
out DSAParameters key);
{
try
{
- using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
passwordBytes,
pkcs8PrivateKey,
{
try
{
- using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
password,
pkcs8PrivateKey,
{
try
{
- using (AsnWriter writer = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
{
ECParameters ecParameters = ExportParameters(false);
- using (AsnWriter writer = ecParameters.WriteSubjectPublicKeyInfo())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
s_validOids,
source,
passwordBytes,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
s_validOids,
source,
password,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadPkcs8<ECParameters>(
s_validOids,
source,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters key);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters, ReadOnlyMemory<byte>>(
+ KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
s_validOids,
source,
- ECParameters.FromECPublicKey,
+ EccKeyFormatHelper.FromECPublicKey,
out int localRead,
out ECParameters key);
public virtual unsafe void ImportECPrivateKey(ReadOnlySpan<byte> source, out int bytesRead)
{
- ECParameters ecParameters = ECParameters.FromECPrivateKey(source, out int localRead);
+ ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead);
fixed (byte* privPin = ecParameters.D)
{
{
try
{
- using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
{
return writer.Encode();
}
{
try
{
- using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
{
try
{
- using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
passwordBytes,
pkcs8PrivateKey,
{
try
{
- using (AsnWriter pkcs8PrivateKey = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
using (AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
password,
pkcs8PrivateKey,
{
try
{
- using (AsnWriter writer = ecParameters.WritePkcs8PrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
{
ECParameters ecParameters = ExportParameters(false);
- using (AsnWriter writer = ecParameters.WriteSubjectPublicKeyInfo())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
s_validOids,
source,
passwordBytes,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadEncryptedPkcs8<ECParameters>(
s_validOids,
source,
password,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadPkcs8<ECParameters, ECPrivateKey>(
+ KeyFormatHelper.ReadPkcs8<ECParameters>(
s_validOids,
source,
- ECParameters.FromECPrivateKey,
+ EccKeyFormatHelper.FromECPrivateKey,
out int localRead,
out ECParameters key);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters, ReadOnlyMemory<byte>>(
+ KeyFormatHelper.ReadSubjectPublicKeyInfo<ECParameters>(
s_validOids,
source,
- ECParameters.FromECPublicKey,
+ EccKeyFormatHelper.FromECPublicKey,
out int localRead,
out ECParameters key);
public virtual unsafe void ImportECPrivateKey(ReadOnlySpan<byte> source, out int bytesRead)
{
- ECParameters ecParameters = ECParameters.FromECPrivateKey(source, out int localRead);
+ ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead);
fixed (byte* privPin = ecParameters.D)
{
{
try
{
- using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
{
return writer.Encode();
}
{
try
{
- using (AsnWriter writer = ecParameters.WriteECPrivateKey())
+ using (AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters))
{
return writer.TryEncode(destination, out bytesWritten);
}
Curve.Validate();
}
-
- internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan<byte> key, out int bytesRead)
- {
- fixed (byte* ptr = &MemoryMarshal.GetReference(key))
- {
- using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, key.Length))
- {
- ECPrivateKey parsedKey =
- AsnSerializer.Deserialize<ECPrivateKey>(manager.Memory, AsnEncodingRules.BER, out bytesRead);
-
- ECParameters ret;
- AlgorithmIdentifierAsn algId = default;
- FromECPrivateKey(parsedKey, algId, out ret);
- return ret;
- }
- }
- }
-
- internal static void FromECPrivateKey(
- in ECPrivateKey key,
- in AlgorithmIdentifierAsn algId,
- out ECParameters ret)
- {
- ValidateParameters(key.Parameters, algId);
-
- if (key.Version != 1)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- // Implementation limitation
- if (key.PublicKey == null)
- {
- throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
- }
-
- ReadOnlySpan<byte> publicKeyBytes = key.PublicKey.Value.Span;
-
- if (publicKeyBytes.Length == 0)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- // Implementation limitation
- // 04 (Uncompressed ECPoint) is almost always used.
- if (publicKeyBytes[0] != 0x04)
- {
- throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
- }
-
- // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
- if (publicKeyBytes.Length != 2 * key.PrivateKey.Length + 1)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- ECDomainParameters domainParameters;
-
- if (key.Parameters != null)
- {
- domainParameters = key.Parameters.Value;
- }
- else
- {
- domainParameters = AsnSerializer.Deserialize<ECDomainParameters>(
- algId.Parameters.Value,
- AsnEncodingRules.DER);
- }
-
- ret = new ECParameters
- {
- Curve = GetCurve(domainParameters),
- Q =
- {
- X = publicKeyBytes.Slice(1, key.PrivateKey.Length).ToArray(),
- Y = publicKeyBytes.Slice(1 + key.PrivateKey.Length).ToArray(),
- },
- D = key.PrivateKey.ToArray(),
- };
-
- ret.Validate();
- }
-
- internal static void FromECPublicKey(
- in ReadOnlyMemory<byte> key,
- in AlgorithmIdentifierAsn algId,
- out ECParameters ret)
- {
- if (algId.Parameters == null)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- ReadOnlySpan<byte> publicKeyBytes = key.Span;
-
- if (publicKeyBytes.Length == 0)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- // Implementation limitation.
- // 04 (Uncompressed ECPoint) is almost always used.
- if (publicKeyBytes[0] != 0x04)
- {
- throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
- }
-
- // https://www.secg.org/sec1-v2.pdf, 2.3.4, #3 (M has length 2 * CEIL(log2(q)/8) + 1)
- if ((publicKeyBytes.Length & 0x01) != 1)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- int fieldWidth = publicKeyBytes.Length / 2;
-
- ECDomainParameters domainParameters = AsnSerializer.Deserialize<ECDomainParameters>(
- algId.Parameters.Value,
- AsnEncodingRules.DER);
-
- ret = new ECParameters
- {
- Curve = GetCurve(domainParameters),
- Q =
- {
- X = publicKeyBytes.Slice(1, fieldWidth).ToArray(),
- Y = publicKeyBytes.Slice(1 + fieldWidth).ToArray(),
- },
- };
-
- ret.Validate();
- }
-
- private static void ValidateParameters(ECDomainParameters? keyParameters, in AlgorithmIdentifierAsn algId)
- {
- // At least one is required
- if (keyParameters == null && algId.Parameters == null)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- // If they are both specified they must match.
- if (keyParameters != null && algId.Parameters != null)
- {
- ReadOnlySpan<byte> algIdParameters = algId.Parameters.Value.Span;
- byte[] verify = ArrayPool<byte>.Shared.Rent(algIdParameters.Length);
-
- try
- {
- // X.509 SubjectPublicKeyInfo specifies DER encoding.
- // RFC 5915 specifies DER encoding for EC Private Keys.
- // So we can compare as DER.
- using (AsnWriter writer = AsnSerializer.Serialize(keyParameters.Value, AsnEncodingRules.DER))
- {
- if (!writer.TryEncode(verify, out int written) ||
- written != algIdParameters.Length ||
- !algIdParameters.SequenceEqual(verify.AsSpan(0, written)))
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
- }
- }
- finally
- {
- // verify contains public information and does not need to be cleared.
- ArrayPool<byte>.Shared.Return(verify);
- }
- }
- }
-
- private static ECCurve GetCurve(in ECDomainParameters domainParameters)
- {
- if (domainParameters.Named == null)
- {
- throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- Oid curveOid = domainParameters.Named;
-
- switch (curveOid.Value)
- {
- case Oids.secp256r1:
- curveOid = new Oid(Oids.secp256r1, nameof(ECCurve.NamedCurves.nistP256));
- break;
- case Oids.secp384r1:
- curveOid = new Oid(Oids.secp384r1, nameof(ECCurve.NamedCurves.nistP384));
- break;
- case Oids.secp521r1:
- curveOid = new Oid(Oids.secp521r1, nameof(ECCurve.NamedCurves.nistP521));
- break;
- }
-
- return ECCurve.CreateFromOid(curveOid);
- }
-
- internal AsnWriter WriteSubjectPublicKeyInfo()
- {
- Validate();
-
- if (!Curve.IsNamed)
- {
- throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- // Since the public key format for EC keys is not ASN.1,
- // write the SPKI structure manually.
-
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
- // SubjectPublicKeyInfo
- writer.PushSequence();
-
- // algorithm
- WriteAlgorithmIdentifier(writer);
-
- // subjectPublicKey
- WriteUncompressedPublicKey(writer);
-
- writer.PopSequence();
- return writer;
- }
-
- private AsnWriter WriteAlgorithmIdentifier()
- {
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
- WriteAlgorithmIdentifier(writer);
- return writer;
- }
-
- private void WriteAlgorithmIdentifier(AsnWriter writer)
- {
- writer.PushSequence();
-
- writer.WriteObjectIdentifier(Oids.EcPublicKey);
- WriteEcParameters(writer);
-
- writer.PopSequence();
- }
-
- internal AsnWriter WritePkcs8PrivateKey()
- {
- Validate();
-
- if (D == null)
- {
- throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
- }
-
- if (!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(includeDomainParameters: false))
- using (AsnWriter algorithmIdentifier = WriteAlgorithmIdentifier())
- {
- return KeyFormatHelper.WritePkcs8(algorithmIdentifier, ecPrivateKey);
- }
- }
-
- private void WriteEcParameters(AsnWriter writer)
- {
- if (Curve.IsNamed)
- {
- Oid oid = Curve.Oid;
-
- // On Windows the FriendlyName is populated in places where the Value mightn't be.
- if (string.IsNullOrEmpty(oid.Value))
- {
- oid = Oid.FromFriendlyName(oid.FriendlyName, OidGroup.All);
- }
-
- writer.WriteObjectIdentifier(oid.Value);
- }
- else
- {
- throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
- }
-
- private void WriteUncompressedPublicKey(AsnWriter writer)
- {
- int publicKeyLength = Q.X.Length * 2 + 1;
- Span<byte> publicKeyBytes = stackalloc byte[0];
- byte[] publicKeyRented = null;
-
- if (publicKeyLength < 256)
- {
- publicKeyBytes = stackalloc byte[publicKeyLength];
- }
- else
- {
- publicKeyRented = ArrayPool<byte>.Shared.Rent(publicKeyLength);
- publicKeyBytes = publicKeyRented.AsSpan(0, publicKeyLength);
- }
-
- try
- {
- publicKeyBytes[0] = 0x04;
- Q.X.AsSpan().CopyTo(publicKeyBytes.Slice(1));
- Q.Y.AsSpan().CopyTo(publicKeyBytes.Slice(1 + Q.X.Length));
-
- writer.WriteBitString(publicKeyBytes);
- }
- finally
- {
- CryptographicOperations.ZeroMemory(publicKeyBytes);
-
- if (publicKeyRented != null)
- {
- ArrayPool<byte>.Shared.Return(publicKeyRented);
- }
- }
- }
-
- internal AsnWriter WriteECPrivateKey()
- {
- return WriteEcPrivateKey(includeDomainParameters: true);
- }
-
- private AsnWriter WriteEcPrivateKey(bool includeDomainParameters)
- {
- bool returning = false;
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
- try
- {
- // ECPrivateKey
- writer.PushSequence();
-
- // version 1
- writer.WriteInteger(1);
-
- // privateKey
- writer.WriteOctetString(D);
-
- // domainParameters
- if (includeDomainParameters)
- {
- Asn1Tag explicit0 = new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true);
- writer.PushSequence(explicit0);
-
- WriteEcParameters(writer);
-
- writer.PopSequence(explicit0);
- }
-
- // publicKey
- {
- Asn1Tag explicit1 = new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true);
- writer.PushSequence(explicit1);
-
- WriteUncompressedPublicKey(writer);
-
- writer.PopSequence(explicit1);
- }
-
- writer.PopSequence();
- returning = true;
- return writer;
- }
- finally
- {
- if (!returning)
- {
- writer.Dispose();
- }
- }
- }
}
}
{
public abstract partial class RSA : AsymmetricAlgorithm
{
- private static readonly string[] s_validOids =
- {
- Oids.Rsa,
- };
-
public static new RSA Create(string algName)
{
return (RSA)CryptoConfig.CreateFromName(algName);
continue;
}
- using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ using (AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(rented.AsSpan(0, pkcs1Size)))
{
- writer.PushSequence();
- WriteAlgorithmIdentifier(writer);
- writer.WriteBitString(rented.AsSpan(0, pkcs1Size));
- writer.PopSequence();
-
return writer.TryEncode(destination, out bytesWritten);
}
}
continue;
}
- AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
-
- try
- {
- writer.PushSequence();
- // Version 0 format (no attributes)
- writer.WriteInteger(0);
- WriteAlgorithmIdentifier(writer);
- writer.WriteOctetString(rented.AsSpan(0, pkcs1Size));
- writer.PopSequence();
-
- return writer;
- }
- catch
- {
- writer.Dispose();
- throw;
- }
+ return RSAKeyFormatHelper.WritePkcs8PrivateKey(rented.AsSpan(0, pkcs1Size));
}
finally
{
return writer.TryEncode(destination, out bytesWritten);
}
}
-
- private static void WriteAlgorithmIdentifier(AsnWriter writer)
- {
- writer.PushSequence();
-
- // https://tools.ietf.org/html/rfc3447#appendix-C
- //
- // --
- // -- When rsaEncryption is used in an AlgorithmIdentifier the
- // -- parameters MUST be present and MUST be NULL.
- // --
- writer.WriteObjectIdentifier(Oids.Rsa);
- writer.WriteNull();
-
- writer.PopSequence();
- }
private AsnWriter WritePkcs1PublicKey()
{
RSAParameters rsaParameters = ExportParameters(false);
-
- if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
- {
- throw new InvalidOperationException(SR.Cryptography_InvalidRsaParameters);
- }
-
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
- writer.PushSequence();
- writer.WriteKeyParameterInteger(rsaParameters.Modulus);
- writer.WriteKeyParameterInteger(rsaParameters.Exponent);
- writer.PopSequence();
-
- return writer;
+ return RSAKeyFormatHelper.WritePkcs1PublicKey(rsaParameters);
}
private unsafe AsnWriter WritePkcs1PrivateKey()
{
try
{
- if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
- {
- throw new InvalidOperationException(SR.Cryptography_InvalidRsaParameters);
- }
-
- if (rsaParameters.D == null ||
- rsaParameters.P == null ||
- rsaParameters.Q == null ||
- rsaParameters.DP == null ||
- rsaParameters.DQ == null ||
- rsaParameters.InverseQ == null)
- {
- throw new InvalidOperationException(SR.Cryptography_NotValidPrivateKey);
- }
-
- AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
-
- writer.PushSequence();
-
- // Format version 0
- writer.WriteInteger(0);
- writer.WriteKeyParameterInteger(rsaParameters.Modulus);
- writer.WriteKeyParameterInteger(rsaParameters.Exponent);
- writer.WriteKeyParameterInteger(rsaParameters.D);
- writer.WriteKeyParameterInteger(rsaParameters.P);
- writer.WriteKeyParameterInteger(rsaParameters.Q);
- writer.WriteKeyParameterInteger(rsaParameters.DP);
- writer.WriteKeyParameterInteger(rsaParameters.DQ);
- writer.WriteKeyParameterInteger(rsaParameters.InverseQ);
-
- writer.PopSequence();
- return writer;
+ return RSAKeyFormatHelper.WritePkcs1PrivateKey(rsaParameters);
}
finally
{
{
using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
{
- ReadOnlyMemory<byte> pkcs1 = KeyFormatHelper.ReadSubjectPublicKeyInfo(
- s_validOids,
+ ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
manager.Memory,
out int localRead);
{
using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
{
- RSAPublicKey key = AsnSerializer.Deserialize<RSAPublicKey>(
- manager.Memory,
- AsnEncodingRules.BER,
- out int localRead);
+ AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+ ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+ int localRead = firstValue.Length;
- RSAParameters rsaParameters = new RSAParameters
- {
- Modulus = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true),
- Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
- };
+ AlgorithmIdentifierAsn ignored = default;
+ RSAKeyFormatHelper.ReadRsaPublicKey(firstValue, ignored, out RSAParameters rsaParameters);
ImportParameters(rsaParameters);
+
bytesRead = localRead;
}
}
{
using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
{
- RSAPrivateKeyAsn key =
- AsnSerializer.Deserialize<RSAPrivateKeyAsn>(
- manager.Memory,
- AsnEncodingRules.BER,
- out int localRead);
+ AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
+ ReadOnlyMemory<byte> firstValue = reader.PeekEncodedValue();
+ int localRead = firstValue.Length;
AlgorithmIdentifierAsn ignored = default;
- FromPkcs1PrivateKey(key, ignored, out RSAParameters rsaParameters);
+ RSAKeyFormatHelper.FromPkcs1PrivateKey(firstValue, ignored, out RSAParameters rsaParameters);
fixed (byte* dPin = rsaParameters.D)
fixed (byte* pPin = rsaParameters.P)
{
using (MemoryManager<byte> manager = new PointerMemoryManager<byte>(ptr, source.Length))
{
- ReadOnlyMemory<byte> pkcs1 = KeyFormatHelper.ReadPkcs8(
- s_validOids,
+ ReadOnlyMemory<byte> pkcs1 = RSAKeyFormatHelper.ReadPkcs8(
manager.Memory,
out int localRead);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters, RSAPrivateKeyAsn>(
- s_validOids,
+ RSAKeyFormatHelper.ReadEncryptedPkcs8(
source,
passwordBytes,
- FromPkcs1PrivateKey,
out int localRead,
out RSAParameters ret);
ReadOnlySpan<byte> source,
out int bytesRead)
{
- KeyFormatHelper.ReadEncryptedPkcs8<RSAParameters, RSAPrivateKeyAsn>(
- s_validOids,
+ RSAKeyFormatHelper.ReadEncryptedPkcs8(
source,
password,
- FromPkcs1PrivateKey,
out int localRead,
out RSAParameters ret);
bytesRead = localRead;
}
- private static void FromPkcs1PrivateKey(
- in RSAPrivateKeyAsn key,
- in AlgorithmIdentifierAsn algId,
- out RSAParameters ret)
- {
- if (!algId.HasNullEquivalentParameters())
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- const int MaxSupportedVersion = 0;
-
- if (key.Version > MaxSupportedVersion)
- {
- throw new CryptographicException(
- SR.Format(
- SR.Cryptography_RSAPrivateKey_VersionTooNew,
- key.Version,
- MaxSupportedVersion));
- }
-
- // The modulus size determines the encoded output size of the CRT parameters.
- byte[] n = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true);
- int halfModulusLength = (n.Length + 1) / 2;
-
- ret = new RSAParameters
- {
- Modulus = n,
- Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true),
- D = key.PrivateExponent.ExportKeyParameter(n.Length),
- P = key.Prime1.ExportKeyParameter(halfModulusLength),
- Q = key.Prime2.ExportKeyParameter(halfModulusLength),
- DP = key.Exponent1.ExportKeyParameter(halfModulusLength),
- DQ = key.Exponent2.ExportKeyParameter(halfModulusLength),
- InverseQ = key.Coefficient.ExportKeyParameter(halfModulusLength),
- };
- }
-
private static void ClearPrivateParameters(in RSAParameters rsaParameters)
{
CryptographicOperations.ZeroMemory(rsaParameters.D);
<data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
<value>Unused bit count must be between 0 and 7, inclusive.</value>
</data>
- <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
- <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
- <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
- <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
- <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
- <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
- <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
- </data>
- <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
- </data>
- <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
- <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
- </data>
- <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
- <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
- </data>
- <data name="Cryptography_AsnSerializer_PopulateFriendlyNameOnString" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has [ObjectIdentifier].PopulateFriendlyName set to true, which is not applicable to a string. Change the field to '{2}' or set PopulateFriendlyName to false.</value>
- </data>
- <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
- <value>Unable to set field {0} on type {1}.</value>
- </data>
- <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
- </data>
- <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
- <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
- </data>
- <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
- <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
- </data>
- <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
- <value>Could not determine how to serialize or deserialize type '{0}'.</value>
- </data>
<data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
<value>Encode cannot be called while a Sequence or SetOf is still open.</value>
</data>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.4'">4.1.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard'">4.3.0.0</AssemblyVersion>
</PropertyGroup>
+ <Import Project="$(CommonPath)\System\Security\Cryptography\Asn1\AsnXml.targets"/>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(TargetsWindows)' == 'true'">
<Compile Include="System\Security\Cryptography\AesCng.cs" />
<Compile Include="System\Security\Cryptography\CngAlgorithm.cs" />
<Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
<Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
- <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
<Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
<Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
</Compile>
</ItemGroup>
+ <ItemGroup>
+ <None Include="@(AsnXml)" />
+ </ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
<Reference Include="System.Core" />
[Integer]
public ReadOnlyMemory<byte> Second;
}
+
+ // https://tools.ietf.org/html/rfc3280#section-4.1.1.2
+ //
+ // AlgorithmIdentifier ::= SEQUENCE {
+ // algorithm OBJECT IDENTIFIER,
+ // parameters ANY DEFINED BY algorithm OPTIONAL }
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct AlgorithmIdentifierAsn
+ {
+ internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
+
+ [ObjectIdentifier(PopulateFriendlyName = true)]
+ public Oid Algorithm;
+
+ [AnyValue, OptionalValue]
+ public ReadOnlyMemory<byte>? Parameters;
+ }
+
+ // https://tools.ietf.org/html/rfc3280#section-4.1
+ //
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ [StructLayout(LayoutKind.Sequential)]
+ internal partial struct SubjectPublicKeyInfoAsn
+ {
+ internal AlgorithmIdentifierAsn Algorithm;
+
+ [BitString]
+ internal ReadOnlyMemory<byte> SubjectPublicKey;
+ }
}
<Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
<Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
- </Compile>
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
<Link>CommonTest\System\Security\Cryptography\ByteUtils.cs</Link>
</Compile>
<data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
<value>The provided hash value is not the expected size for the specified hash algorithm.</value>
</data>
+ <data name="Cryptography_WriteEncodedValue_OneValueAtATime" xml:space="preserve">
+ <value>The input to WriteEncodedValue must represent a single encoded value with no trailing data.</value>
+ </data>
+ <data name="Cryptography_Asn_EnumeratedValueRequiresNonFlagsEnum" xml:space="preserve">
+ <value>ASN.1 Enumerated values only apply to enum types without the [Flags] attribute.</value>
+ </data>
+ <data name="Cryptography_Asn_NamedBitListRequiresFlagsEnum" xml:space="preserve">
+ <value>Named bit list operations require an enum with the [Flags] attribute.</value>
+ </data>
+ <data name="Cryptography_Asn_NamedBitListValueTooBig" xml:space="preserve">
+ <value>The encoded named bit list value is larger than the value size of the '{0}' enum.</value>
+ </data>
+ <data name="Cryptography_Asn_UniversalValueIsFixed" xml:space="preserve">
+ <value>Tags with TagClass Universal must have the appropriate TagValue value for the data type being read or written.</value>
+ </data>
+ <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
+ <value>Unused bit count must be between 0 and 7, inclusive.</value>
+ </data>
+ <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
+ <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
+ </data>
+ <data name="Cryptography_AsnWriter_PopWrongTag" xml:space="preserve">
+ <value>Cannot pop the requested tag as it is not currently in progress.</value>
+ </data>
+ <data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
+ <value>Key is not a valid public or private key.</value>
+ </data>
<data name="PlatformNotSupported_CryptographyOpenSSL" xml:space="preserve">
<value>OpenSSL is not supported on this platform.</value>
</data>
<AssemblyName>System.Security.Cryptography.OpenSsl</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard'">4.1.0.0</AssemblyVersion>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<Configurations>netcoreapp-Debug;netcoreapp-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netstandard-Debug;netstandard-Release</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetsUnix)' != 'true'">
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
- <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
+ <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
- <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
+ <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnWriter.cs">
+ <Link>Common\System\Security\Cryptography\AsnWriter.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\DSAOpenSsl.cs</Link>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.ImportExport.cs">
<Link>Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+ <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\RSAOpenSsl.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\Oids.cs">
<Link>Common\System\Security\Cryptography\Oids.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml">
<Link>Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml</Link>
<Link>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs">
- <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
<Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
<Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
{
Assert.NotSame(expected.Oid, actual.Oid);
Assert.Equal(expected.Oid.Value, actual.Oid.Value);
- Assert.Equal(expected.Oid.FriendlyName, actual.Oid.FriendlyName);
// We need to decode bytes because DER and BER may encode the same information slightly differently
Rfc3161TimestampTokenInfo expectedToken;
using System;
using System.Diagnostics;
+using System.Numerics;
using System.Security.Cryptography;
using System.Security.Cryptography.Apple;
+using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal
private static AsymmetricAlgorithm DecodeRsaPublicKey(byte[] encodedKeyValue)
{
- DerSequenceReader reader = new DerSequenceReader(encodedKeyValue);
- RSAParameters rsaParameters = new RSAParameters();
- reader.ReadPkcs1PublicBlob(ref rsaParameters);
+ AlgorithmIdentifierAsn ignored = default;
+ RSAKeyFormatHelper.ReadRsaPublicKey(
+ encodedKeyValue,
+ ignored,
+ out RSAParameters rsaParameters);
RSA rsa = RSA.Create();
try
private static AsymmetricAlgorithm DecodeDsaPublicKey(byte[] encodedKeyValue, byte[] encodedParameters)
{
- DSAParameters dsaParameters = new DSAParameters();
- DerSequenceReader parameterReader = new DerSequenceReader(encodedParameters);
-
- parameterReader.ReadSubjectPublicKeyInfo(encodedKeyValue, ref dsaParameters);
+ DSAKeyFormatHelper.ReadDsaPublicKey(
+ encodedKeyValue,
+ new AlgorithmIdentifierAsn { Parameters = encodedParameters },
+ out DSAParameters dsaParameters);
DSA dsa = DSA.Create();
try
<data name="Cryptography_AsnWriter_PopWrongTag" xml:space="preserve">
<value>Cannot pop the requested tag as it is not currently in progress.</value>
</data>
+ <data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
+ <value>Key is not a valid public or private key.</value>
+ </data>
+ <data name="Cryptography_Pkcs8_EncryptedReadFailed" xml:space="preserve">
+ <value>The EncryptedPrivateKeyInfo structure was decoded but was not successfully interpreted, the password may be incorrect.</value>
+ </data>
+ <data name="Cryptography_UnknownAlgorithmIdentifier" xml:space="preserve">
+ <value>The algorithm identified by '{0}' is unknown, not valid for the requested usage, or was not handled.</value>
+ </data>
+ <data name="Argument_InvalidValue" xml:space="preserve">
+ <value>Value was invalid.</value>
+ </data>
+ <data name="Cryptography_AlgKdfRequiresChars" xml:space="preserve">
+ <value>The KDF for algorithm '{0}' requires a char-based password input.</value>
+ </data>
+ <data name="Cryptography_RSAPrivateKey_VersionTooNew" xml:space="preserve">
+ <value>The provided RSAPrivateKey value has version '{0}', but version '{1}' is the maximum supported.</value>
+ </data>
+ <data name="Cryptography_NotValidPrivateKey" xml:space="preserve">
+ <value>Key is not a valid private key.</value>
+ </data>
</root>
<Compile Include="$(CommonPath)\System\Security\Cryptography\Oids.cs">
<Link>Common\System\Security\Cryptography\Oids.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
+ <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\KeySizeHelpers.cs">
<Link>Common\System\Security\Cryptography\KeySizeHelpers.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.manual.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml">
<Link>Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml</Link>
<Link>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\OtherNameAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PssParamsAsn.xml</DependentUpon>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs">
- <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.cs</Link>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
<Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
+ <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Internal\Cryptography\Helpers.cs">
<Link>Internal\Cryptography\Helpers.cs</Link>
</Compile>
</Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsOSX)' == 'true' AND '$(IsPartialFacadeAssembly)' != 'true'">
- <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
- <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs">
<Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Memory\PointerMemoryManager.cs">
+ <Link>Common\System\Memory\PointerMemoryManager.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\DSAKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\DSAKeyFormatHelper.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSASecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\DSASecurityTransforms.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\EccKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\EccKeyFormatHelper.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\EccSecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\EccSecurityTransforms.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
- <Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\KeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\KeyFormatHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\PasswordBasedEncryption.cs">
+ <Link>Common\System\Security\Cryptography\PasswordBasedEncryption.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Pkcs12Kdf.cs">
+ <Link>Common\System\Security\Cryptography\Pkcs12Kdf.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RSAKeyFormatHelper.cs">
+ <Link>Common\System\Security\Cryptography\RSAKeyFormatHelper.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
<Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
<Compile Include="$(CommonPath)\System\Security\Cryptography\SecKeyPair.cs">
<Link>Common\System\Security\Cryptography\SecKeyPair.cs</Link>
</Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\AttributeAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\CurveAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\CurveAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\CurveAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\DssParms.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\DssParms.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\DssParms.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\ECDomainParameters.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\ECPrivateKey.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\FieldID.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\FieldID.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\FieldID.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBEParameter.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\PBES2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\PBES2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\PBES2Params.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2Params.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Pbkdf2SaltChoice.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml</DependentUpon>
+ </Compile>
+ <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml">
+ <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</Link>
+ </AsnXml>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs">
+ <Link>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml.cs</Link>
+ <DependentUpon>Common\System\Security\Cryptography\Asn1\SpecifiedECDomain.xml</DependentUpon>
+ </Compile>
<Compile Include="Internal\Cryptography\Pal.OSX\AppleCertificatePal.cs" />
<Compile Include="Internal\Cryptography\Pal.OSX\CertificatePal.cs" />
<Compile Include="Internal\Cryptography\Pal.OSX\CertificateData.cs" />
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Numerics;
+using System.Security.Cryptography.Asn1;
using Internal.Cryptography;
namespace System.Security.Cryptography.X509Certificates
SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
}
- return DerEncoder.ConstructSequence(DerEncoder.SegmentedEncodeOid(oid));
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ writer.PushSequence();
+ writer.WriteObjectIdentifier(oid);
+ writer.PopSequence();
+ return writer.Encode();
+ }
}
public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
{
byte[] ieeeFormat = _key.SignData(data, hashAlgorithm);
-
- Debug.Assert(ieeeFormat.Length % 2 == 0);
- int segmentLength = ieeeFormat.Length / 2;
-
- return DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(new ReadOnlySpan<byte>(ieeeFormat, 0, segmentLength)),
- DerEncoder.SegmentedEncodeUnsignedInteger(new ReadOnlySpan<byte>(ieeeFormat, segmentLength, segmentLength)));
+ return AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(ieeeFormat);
}
protected override PublicKey BuildPublicKey()
}
string curveOid = ecParameters.Curve.Oid.Value;
+ byte[] curveOidEncoded;
if (string.IsNullOrEmpty(curveOid))
{
}
}
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ writer.WriteObjectIdentifier(curveOid);
+ curveOidEncoded = writer.Encode();
+ }
+
Debug.Assert(ecParameters.Q.X.Length == ecParameters.Q.Y.Length);
byte[] uncompressedPoint = new byte[1 + ecParameters.Q.X.Length + ecParameters.Q.Y.Length];
return new PublicKey(
ecPublicKey,
- new AsnEncodedData(ecPublicKey, DerEncoder.EncodeOid(curveOid)),
+ new AsnEncodedData(ecPublicKey, curveOidEncoded),
new AsnEncodedData(ecPublicKey, uncompressedPoint));
}
}
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Security.Cryptography.Asn1;
using Internal.Cryptography;
namespace System.Security.Cryptography.X509Certificates
internal static PublicKey BuildPublicKey(RSA rsa)
{
- RSAParameters parameters = rsa.ExportParameters(false);
-
- byte[] rsaPublicKey = DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus),
- DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent));
-
Oid oid = new Oid(Oids.Rsa);
// The OID is being passed to everything here because that's what
// This is due to one version of the ASN.1 not including OPTIONAL, and that was
// the version that got predominately implemented for RSA. Now it's convention.
new AsnEncodedData(oid, new byte[] { 0x05, 0x00 }),
- new AsnEncodedData(oid, rsaPublicKey));
+ new AsnEncodedData(oid, rsa.ExportRSAPublicKey()));
}
public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
}
- return DerEncoder.ConstructSequence(
- DerEncoder.SegmentedEncodeOid(oid),
- DerEncoder.SegmentedEncodeNull());
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ writer.PushSequence();
+ writer.WriteObjectIdentifier(oid);
+ writer.WriteNull();
+ writer.PopSequence();
+ return writer.Encode();
+ }
}
}
}
throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
}
- uint cbSalt;
+ int cbSalt;
string digestOid;
if (hashAlgorithm == HashAlgorithmName.SHA256)