Skip to content

Commit cac83f0

Browse files
authored
Merge pull request #204 from dorssel/fix_import
Fix imports with oversized source
2 parents 58d70b7 + 0b59b09 commit cac83f0

File tree

2 files changed

+97
-34
lines changed

2 files changed

+97
-34
lines changed

UnitTests/UnitTests/ImportTests.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
//
33
// SPDX-License-Identifier: MIT
44

5+
using System.Formats.Asn1;
56
using System.Security.Cryptography;
67
using Dorssel.Security.Cryptography;
8+
using static Dorssel.Security.Cryptography.X509Certificates.XmssCertificateExtensions;
79

810
namespace UnitTests;
911

@@ -140,6 +142,17 @@ public void ImportRfcPublicKey_WrongSize()
140142
});
141143
}
142144

145+
[TestMethod]
146+
public void ImportRfcPublicKey_Oversized()
147+
{
148+
using var xmss = new Xmss();
149+
150+
var oversized = new ReadOnlySpan<byte>([..ExampleCertificate.RfcPublicKey.Span, 0]);
151+
152+
xmss.ImportRfcPublicKey(oversized, out var bytesRead);
153+
Assert.AreEqual(ExampleCertificate.RfcPublicKey.Length, bytesRead);
154+
}
155+
143156
[TestMethod]
144157
public void ImportRfcPublicKey_AfterPrivateKey()
145158
{
@@ -189,6 +202,55 @@ public void ImportAsnPublicKey_Invalid()
189202
});
190203
}
191204

205+
[TestMethod]
206+
public void ImportAsnPublicKey_OversizedAsn()
207+
{
208+
byte[] asn;
209+
{
210+
using var tmpXmss = new Xmss();
211+
tmpXmss.ImportFromPem(ExampleCertificate.Pem);
212+
asn = tmpXmss.ExportAsnPublicKey();
213+
}
214+
215+
using var xmss = new Xmss();
216+
217+
Assert.IsFalse(xmss.HasPrivateKey);
218+
Assert.IsFalse(xmss.HasPublicKey);
219+
220+
xmss.ImportAsnPublicKey([..asn, 0], out var bytesRead);
221+
222+
Assert.AreEqual(asn.Length, bytesRead);
223+
Assert.IsFalse(xmss.HasPrivateKey);
224+
Assert.IsTrue(xmss.HasPublicKey);
225+
}
226+
227+
[TestMethod]
228+
public void ImportAsnPublicKey_OversizedKey()
229+
{
230+
byte[] asn;
231+
{
232+
233+
using var tmpXmss = new Xmss();
234+
tmpXmss.ImportFromPem(ExampleCertificate.Pem);
235+
asn = tmpXmss.ExportAsnPublicKey();
236+
}
237+
var correctKey = AsnDecoder.ReadOctetString(asn, AsnEncodingRules.BER, out var bytesConsumed);
238+
239+
var asnWriter = new AsnWriter(AsnEncodingRules.DER);
240+
asnWriter.WriteOctetString([.. correctKey, 42]);
241+
var asnWithOversizedKey = asnWriter.Encode();
242+
243+
using var xmss = new Xmss();
244+
245+
Assert.IsFalse(xmss.HasPrivateKey);
246+
Assert.IsFalse(xmss.HasPublicKey);
247+
248+
Assert.ThrowsExactly<CryptographicException>(() =>
249+
{
250+
xmss.ImportAsnPublicKey(asnWithOversizedKey, out var bytesRead);
251+
});
252+
}
253+
192254
[TestMethod]
193255
public void ImportSubjectPublicKeyInfo()
194256
{
@@ -282,6 +344,26 @@ public void ImportFromPem_XmssAsn()
282344
Assert.IsTrue(xmss.HasPublicKey);
283345
}
284346

347+
[TestMethod]
348+
public void ImportFromPem_XmssAsn_OversizedAsn()
349+
{
350+
using var xmss = ExampleCertificate.Certificate2.GetXmssPublicKey()!;
351+
352+
#pragma warning disable CS0618 // Type or member is obsolete
353+
var asnPem = xmss.ExportAsnPublicKeyPem();
354+
#pragma warning restore CS0618 // Type or member is obsolete
355+
356+
var fields = PemEncoding.Find(asnPem);
357+
var correctData = Convert.FromBase64String(asnPem[fields.Base64Data]);
358+
359+
var infoPemWithExtraneousData = PemEncoding.WriteString(asnPem[fields.Label], [.. correctData, 42]);
360+
361+
Assert.ThrowsExactly<CryptographicException>(() =>
362+
{
363+
xmss.ImportFromPem(infoPemWithExtraneousData);
364+
});
365+
}
366+
285367
[TestMethod]
286368
public void ImportFromPem_SubjectPublicKeyInfo()
287369
{

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)