Skip to content

Commit 444d4f2

Browse files
committed
Fix imports with oversized source
- also improve marshalling
1 parent 58d70b7 commit 444d4f2

File tree

2 files changed

+71
-34
lines changed

2 files changed

+71
-34
lines changed

UnitTests/UnitTests/ImportTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ public void ImportRfcPublicKey_WrongSize()
140140
});
141141
}
142142

143+
[TestMethod]
144+
public void ImportRfcPublicKey_Oversized()
145+
{
146+
using var xmss = new Xmss();
147+
148+
var oversized = new ReadOnlySpan<byte>([..ExampleCertificate.RfcPublicKey.Span, 0]);
149+
150+
xmss.ImportRfcPublicKey(oversized, out var bytesRead);
151+
Assert.AreEqual(ExampleCertificate.RfcPublicKey.Length, bytesRead);
152+
}
153+
143154
[TestMethod]
144155
public void ImportRfcPublicKey_AfterPrivateKey()
145156
{
@@ -189,6 +200,51 @@ public void ImportAsnPublicKey_Invalid()
189200
});
190201
}
191202

203+
[TestMethod]
204+
public void ImportAsnPublicKey_OversizedAsn()
205+
{
206+
byte[] asn;
207+
{
208+
using var tmpXmss = new Xmss();
209+
tmpXmss.ImportFromPem(ExampleCertificate.Pem);
210+
asn = tmpXmss.ExportAsnPublicKey();
211+
}
212+
213+
using var xmss = new Xmss();
214+
215+
Assert.IsFalse(xmss.HasPrivateKey);
216+
Assert.IsFalse(xmss.HasPublicKey);
217+
218+
xmss.ImportAsnPublicKey([..asn, 0], out var bytesRead);
219+
220+
Assert.AreEqual(asn.Length, bytesRead);
221+
Assert.IsFalse(xmss.HasPrivateKey);
222+
Assert.IsTrue(xmss.HasPublicKey);
223+
}
224+
225+
[TestMethod]
226+
public void ImportAsnPublicKey_OversizedKey()
227+
{
228+
byte[] asn;
229+
{
230+
231+
using var tmpXmss = new Xmss();
232+
tmpXmss.ImportFromPem(ExampleCertificate.Pem);
233+
asn = [..tmpXmss.ExportAsnPublicKey(), 0];
234+
}
235+
236+
using var xmss = new Xmss();
237+
238+
Assert.IsFalse(xmss.HasPrivateKey);
239+
Assert.IsFalse(xmss.HasPublicKey);
240+
241+
xmss.ImportAsnPublicKey(asn, out var bytesRead);
242+
243+
Assert.AreEqual(asn.Length, bytesRead);
244+
Assert.IsFalse(xmss.HasPrivateKey);
245+
Assert.IsTrue(xmss.HasPublicKey);
246+
}
247+
192248
[TestMethod]
193249
public void ImportSubjectPublicKeyInfo()
194250
{

Xmss/Xmss.cs

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ public bool Verify(Stream data, ReadOnlySpan<byte> signature)
812812
var buffer = possiblyOversizedBuffer.AsSpan(0, 15 * 1088);
813813
fixed (byte* signaturePtr = signature)
814814
fixed (byte* bufferPtr = buffer)
815-
fixed (XmssPublicKey* publicKeyPtr = &PublicKey)
815+
fixed (XmssPublicKey* publicKeyPin = &PublicKey)
816816
{
817817
var result = UnsafeNativeMethods.xmss_verification_init(out var context, PublicKey, *(XmssSignature*)signaturePtr, (nuint)signature.Length);
818818
if (result == XmssError.XMSS_ERR_INVALID_SIGNATURE)
@@ -860,7 +860,7 @@ public bool Verify(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature)
860860
{
861861
fixed (byte* signaturePtr = signature)
862862
fixed (byte* dataPtr = data)
863-
fixed (XmssPublicKey* publicKeyPtr = &PublicKey)
863+
fixed (XmssPublicKey* publicKeyPin = &PublicKey)
864864
{
865865
var result = UnsafeNativeMethods.xmss_verification_init(out var context, PublicKey, *(XmssSignature*)signaturePtr, (nuint)signature.Length);
866866
if (result == XmssError.XMSS_ERR_INVALID_SIGNATURE)
@@ -957,14 +957,7 @@ public bool TryExportRfcPublicKey(Span<byte> destination, out int bytesWritten)
957957
bytesWritten = 0;
958958
return false;
959959
}
960-
unsafe
961-
{
962-
fixed (XmssPublicKey* publicKeyPtr = &PublicKey)
963-
fixed (byte* destinationPtr = destination)
964-
{
965-
Buffer.MemoryCopy(publicKeyPtr, destinationPtr, destination.Length, Defines.XMSS_PUBLIC_KEY_SIZE);
966-
}
967-
}
960+
MemoryMarshal.Write(destination, PublicKey);
968961
bytesWritten = Defines.XMSS_PUBLIC_KEY_SIZE;
969962
return true;
970963
}
@@ -981,15 +974,7 @@ public bool TryExportAsnPublicKey(Span<byte> destination, out int bytesWritten)
981974
ThrowIfNoPublicKey();
982975

983976
var asnWriter = new AsnWriter(AsnEncodingRules.DER);
984-
{
985-
unsafe
986-
{
987-
fixed (XmssPublicKey* publicKeyPtr = &PublicKey)
988-
{
989-
asnWriter.WriteOctetString(new(publicKeyPtr, sizeof(XmssPublicKey)));
990-
}
991-
}
992-
}
977+
asnWriter.WriteOctetString(MemoryMarshal.Cast<XmssPublicKey, byte>(new(ref PublicKey)));
993978
return asnWriter.TryEncode(destination, out bytesWritten);
994979
}
995980

@@ -1027,13 +1012,7 @@ public override bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out i
10271012
asnWriter.WriteObjectIdentifier(IdAlgXmssHashsig.Value!);
10281013
// PARAMS ARE absent
10291014
}
1030-
unsafe
1031-
{
1032-
fixed (XmssPublicKey* publicKeyPtr = &PublicKey)
1033-
{
1034-
asnWriter.WriteBitString(new(publicKeyPtr, sizeof(XmssPublicKey)));
1035-
}
1036-
}
1015+
asnWriter.WriteBitString(MemoryMarshal.Cast<XmssPublicKey, byte>(new(ref PublicKey)));
10371016
}
10381017
return asnWriter.TryEncode(destination, out bytesWritten);
10391018
}
@@ -1061,17 +1040,15 @@ static void DecodeXmssPublicKey(ReadOnlySpan<byte> source, out XmssPublicKey pub
10611040
{
10621041
throw new CryptographicException($"Unsupported parameter set ({parameterSetOID}).");
10631042
}
1064-
if (source.Length != Defines.XMSS_PUBLIC_KEY_SIZE)
1043+
if (source.Length < Defines.XMSS_PUBLIC_KEY_SIZE)
10651044
{
1066-
throw new CryptographicException("Key value wrong size.");
1045+
throw new CryptographicException("Key value too short.");
10671046
}
1068-
unsafe
1047+
if (exact && (source.Length != Defines.XMSS_PUBLIC_KEY_SIZE))
10691048
{
1070-
fixed (XmssPublicKey* xmssPublicKeyPtr = &publicKey)
1071-
{
1072-
source[..sizeof(XmssPublicKey)].CopyTo(new Span<byte>(xmssPublicKeyPtr, Defines.XMSS_PUBLIC_KEY_SIZE));
1073-
}
1049+
throw new CryptographicException("Key value wrong size.");
10741050
}
1051+
XmssException.ThrowFaultDetectedIf(!MemoryMarshal.TryRead(source, out publicKey));
10751052
bytesRead = Defines.XMSS_PUBLIC_KEY_SIZE;
10761053
parameterSet = (XmssParameterSet)parameterSetOID;
10771054
}
@@ -1085,13 +1062,17 @@ static void DecodeAsnPublicKey(ReadOnlySpan<byte> source, out XmssPublicKey publ
10851062
try
10861063
{
10871064
xmssPublicKeyData = AsnDecoder.ReadOctetString(source, AsnEncodingRules.BER, out bytesConsumed);
1065+
if (exact && (source.Length != bytesConsumed))
1066+
{
1067+
throw new CryptographicException("ASN.1 wrong size.");
1068+
}
10881069
}
10891070
catch (AsnContentException ex)
10901071
{
10911072
throw new CryptographicException("Invalid ASN.1 format.", ex);
10921073
}
10931074

1094-
DecodeXmssPublicKey(xmssPublicKeyData, out publicKey, out parameterSet, out _, exact);
1075+
DecodeXmssPublicKey(xmssPublicKeyData, out publicKey, out parameterSet, out _, true);
10951076
bytesRead = bytesConsumed;
10961077
}
10971078

0 commit comments

Comments
 (0)