Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ExportSubjectPublicKeyInfo on ECDHPublicKey #41887

Merged
merged 3 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public abstract partial class ECKeyFileTests<T> where T : AsymmetricAlgorithm
protected abstract void ImportParameters(T key, ECParameters ecParameters);
protected abstract ECParameters ExportParameters(T key, bool includePrivate);
protected abstract void Exercise(T key);
protected virtual Func<T, byte[]> PublicKeyWriteArrayFunc { get; } = null;
protected virtual WriteKeyToSpanFunc PublicKeyWriteSpanFunc { get; } = null;

public static bool SupportsBrainpool { get; } = IsCurveSupported(ECCurve.NamedCurves.brainpoolP160r1.Oid);
public static bool SupportsSect163k1 { get; } = IsCurveSupported(EccTestData.Sect163k1Key1.Curve.Oid);
Expand Down Expand Up @@ -1153,7 +1155,9 @@ private void ReadWriteBase64SubjectPublicKeyInfo(
key.ImportSubjectPublicKeyInfo(source, out read),
key => key.ExportSubjectPublicKeyInfo(),
(T key, Span<byte> destination, out int written) =>
key.TryExportSubjectPublicKeyInfo(destination, out written));
key.TryExportSubjectPublicKeyInfo(destination, out written),
writePublicArrayFunc: PublicKeyWriteArrayFunc,
writePublicSpanFunc: PublicKeyWriteSpanFunc);
}
else
{
Expand All @@ -1175,7 +1179,9 @@ private void ReadWriteKey(
ReadKeyAction readAction,
Func<T, byte[]> writeArrayFunc,
WriteKeyToSpanFunc writeSpanFunc,
bool isEncrypted = false)
bool isEncrypted = false,
Func<T, byte[]> writePublicArrayFunc = null,
WriteKeyToSpanFunc writePublicSpanFunc = null)
{
bool isPrivateKey = expected.D != null;

Expand All @@ -1192,6 +1198,16 @@ private void ReadWriteKey(

arrayExport = writeArrayFunc(key);

if (writePublicArrayFunc is not null)
{
byte[] publicArrayExport = writePublicArrayFunc(key);
Assert.Equal(arrayExport, publicArrayExport);

Assert.True(writePublicSpanFunc(key, publicArrayExport, out int publicExportWritten));
Assert.Equal(publicExportWritten, publicArrayExport.Length);
Assert.Equal(arrayExport, publicArrayExport);
}

ECParameters ecParameters = ExportParameters(key, isPrivateKey);
EccTestBase.AssertEqual(expected, ecParameters);
}
Expand Down Expand Up @@ -1286,7 +1302,7 @@ private void ReadWriteKey(
}
}

private delegate void ReadKeyAction(T key, ReadOnlySpan<byte> source, out int bytesRead);
private delegate bool WriteKeyToSpanFunc(T key, Span<byte> destination, out int bytesWritten);
protected delegate void ReadKeyAction(T key, ReadOnlySpan<byte> source, out int bytesRead);
protected delegate bool WriteKeyToSpanFunc(T key, Span<byte> destination, out int bytesWritten);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,12 @@ protected override ECParameters ExportParameters(ECDiffieHellman key, bool inclu
}

protected override void Exercise(ECDiffieHellman key) => key.Exercise();

protected override Func<ECDiffieHellman, byte[]> PublicKeyWriteArrayFunc { get; } =
key => key.PublicKey.ExportSubjectPublicKeyInfo();

protected override WriteKeyToSpanFunc PublicKeyWriteSpanFunc { get; } =
(ECDiffieHellman key, Span<byte> destination, out int bytesWritten) =>
key.PublicKey.TryExportSubjectPublicKeyInfo(destination, out bytesWritten);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ public static void PublicKeyIsFactory()
}
}

[Fact]
public static void PublicKey_TryExportSubjectPublicKeyInfo_TooSmall()
{
using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
{
Span<byte> destination = stackalloc byte[1];
Assert.False(publicKey.TryExportSubjectPublicKeyInfo(destination, out int written));
Assert.Equal(0, written);
}
}

[Theory]
[InlineData(false)]
[InlineData(true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,10 @@ public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
public virtual System.Security.Cryptography.ECParameters ExportExplicitParameters() { throw null; }
public virtual System.Security.Cryptography.ECParameters ExportParameters() { throw null; }
public virtual byte[] ExportSubjectPublicKeyInfo() { throw null; }
public virtual byte[] ToByteArray() { throw null; }
public virtual string ToXmlString() { throw null; }
public virtual bool TryExportSubjectPublicKeyInfo(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public abstract partial class ECDsa : System.Security.Cryptography.AsymmetricAlgorithm
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Formats.Asn1;

namespace System.Security.Cryptography
{
/// <summary>
Expand All @@ -27,5 +29,47 @@ public virtual ECParameters ExportExplicitParameters()
{
throw new NotSupportedException(SR.NotSupported_SubclassOverride);
}

/// <summary>
/// Attempts to export the current key in the X.509 SubjectPublicKeyInfo format.
/// </summary>
/// <param name="destination">The byte span to receive the X.509 SubjectPublicKeyInfo data.</param>
/// <param name="bytesWritten">
/// When this method returns, contains a value that indicates the number of bytes written to <paramref name="destination" />.
/// This parameter is treated as uninitialized.
/// </param>
/// <returns>
/// <see langword="true"/> if <paramref name="destination"/> is big enough to receive the output;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="NotSupportedException">
/// The member <see cref="ExportParameters" /> has not been overridden in a derived class.
/// </exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <exception cref="CryptographicException">The key is invalid and could not be exported.</exception>
public virtual bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten)
{
ECParameters ecParameters = ExportParameters();
AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters);
return writer.TryEncode(destination, out bytesWritten);
}

/// <summary>
/// Exports the current key in the X.509 SubjectPublicKeyInfo format.
/// </summary>
/// <returns>
/// A byte array containing the X.509 SubjectPublicKeyInfo representation of this key.
/// </returns>
/// <exception cref="NotSupportedException">
/// The member <see cref="ExportParameters" /> has not been overridden in a derived class.
/// </exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
/// <exception cref="CryptographicException">The key is invalid and could not be exported.</exception>
public virtual byte[] ExportSubjectPublicKeyInfo()
{
ECParameters ecParameters = ExportParameters();
AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters);
return writer.Encode();
}
}
}