Skip to content

Commit

Permalink
Add signing API
Browse files Browse the repository at this point in the history
  • Loading branch information
dorssel committed Nov 29, 2024
1 parent 88fa244 commit f42d761
Show file tree
Hide file tree
Showing 16 changed files with 431 additions and 231 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
bin/
obj/
runtimes/
TestResults/

*.user
1 change: 1 addition & 0 deletions Examples/PrintVersion/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static void Main()
using var stateManager = new XmssFileStateManager(@"C:\test");
using var xmss = new Xmss(stateManager);
xmss.LoadPrivateKey();
_ = xmss.Sign([1, 2, 3]);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,22 @@ sealed unsafe class SafeKeyContextHandleTests
}

[TestMethod]
public void TakeOwnership_Valid()
public void AsRef_Valid()
{
var keyContextPointer = CreateKeyContextPointer();
using var keyContext = SafeKeyContextHandle.TakeOwnership(ref keyContextPointer);
using var keyContext = new SafeKeyContextHandle();
keyContext.AsPointerRef() = CreateKeyContextPointer();

Assert.IsFalse(keyContext.IsInvalid);
_ = keyContext.AsRef().ToString();
}

[TestMethod]
public void TakeOwnership_Null()
public void AsRef_Null()
{
XmssKeyContext* keyContextPointer = null;
using var keyContext = SafeKeyContextHandle.TakeOwnership(ref keyContextPointer);
using var keyContext = new SafeKeyContextHandle();

Assert.IsTrue(keyContext.IsInvalid);
_ = Assert.ThrowsException<NullReferenceException>(() =>
{
_ = keyContext.AsRef().ToString();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2024 Frans van Dorsselaer
//
// SPDX-License-Identifier: MIT

using System.Runtime.InteropServices;
using Dorssel.Security.Cryptography;
using Dorssel.Security.Cryptography.Internal;
using Dorssel.Security.Cryptography.InteropServices;

namespace Internal.UnitTests.InteropServices;

[TestClass]
sealed unsafe class SafeKeyGenerationContextHandleTests
{
static unsafe XmssKeyGenerationContext* CreateKeyGenerationContextPointer(ref XmssKeyContext* keyContext)
{
XmssSigningContext* signingContext = null;
var result = UnsafeNativeMethods.xmss_context_initialize(ref signingContext, XmssParameterSetOID.XMSS_PARAM_SHA2_10_256,
&UnmanagedFunctions.Realloc, &UnmanagedFunctions.Free, &UnmanagedFunctions.Zeroize);
Assert.AreEqual(XmssError.XMSS_OKAY, result);

XmssPrivateKeyStatelessBlob* privateKeyStatelessBlob = null;
XmssPrivateKeyStatefulBlob* privateKeyStatefulBlob = null;
var secureRandomData = stackalloc byte[96];
XmssBuffer secure_random = new() { data_size = 96, data = secureRandomData };
var randomData = stackalloc byte[32];
XmssBuffer random = new() { data_size = 32, data = randomData };
result = UnsafeNativeMethods.xmss_generate_private_key(ref keyContext, ref privateKeyStatelessBlob, ref privateKeyStatefulBlob,
in secure_random, XmssIndexObfuscationSetting.XMSS_INDEX_OBFUSCATION_OFF, in random, in *signingContext);
Assert.AreEqual(XmssError.XMSS_OKAY, result);

XmssKeyGenerationContext* keyGenerationContext = null;
XmssInternalCache* cache = null;
XmssInternalCache* generationCache = null;
result = UnsafeNativeMethods.xmss_generate_public_key(ref keyGenerationContext, ref cache, ref generationCache,
*keyContext, XmssCacheType.XMSS_CACHE_TOP, 0, 1);
Assert.AreEqual(XmssError.XMSS_OKAY, result);

// free everything else
UnsafeNativeMethods.xmss_free_signing_context(signingContext);
signingContext = null;
NativeMemory.Free(privateKeyStatelessBlob);
privateKeyStatelessBlob = null;
NativeMemory.Free(privateKeyStatefulBlob);
privateKeyStatefulBlob = null;

return keyGenerationContext;
}

[TestMethod]
public void AsRef_Valid()
{
// We need to keep the XmssKeyContext alive while handling the XmssKeyGenerationContext.
using var keyContext = new SafeKeyContextHandle();

using var keyGenerationContext = new SafeKeyGenerationContextHandle();
keyGenerationContext.AsPointerRef() = CreateKeyGenerationContextPointer(ref keyContext.AsPointerRef());

_ = keyGenerationContext.AsRef().ToString();
}

[TestMethod]
public void AsRef_Null()
{
using var keyGenerationContext = new SafeKeyGenerationContextHandle();

_ = Assert.ThrowsException<NullReferenceException>(() =>
{
_ = keyGenerationContext.AsRef().ToString();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ namespace Internal.UnitTests.InteropServices;
sealed unsafe class SafeNativeMemoryHandleTests
{
[TestMethod]
public void TakeOwnership_Valid()
public void AsRef_Valid()
{
var nativeMemoryPointer = (int*)NativeMemory.Alloc(sizeof(int));
using var nativeMemory = SafeNativeMemoryHandle.TakeOwnership(ref nativeMemoryPointer);
using var nativeMemory = new SafeNativeMemoryHandle<int>();
nativeMemory.AsPointerRef() = (int*)NativeMemory.Alloc(sizeof(int));

Assert.IsFalse(nativeMemory.IsInvalid);
nativeMemory.AsRef() = 42;
}

[TestMethod]
public void TakeOwnership_Null()
public void AsRef_Null()
{
int* nativeMemoryPointer = null;
using var nativeMemory = SafeNativeMemoryHandle.TakeOwnership(ref nativeMemoryPointer);
using var nativeMemory = new SafeNativeMemoryHandle<int>();

Assert.IsTrue(nativeMemory.IsInvalid);
_ = Assert.ThrowsException<NullReferenceException>(() =>
{
nativeMemory.AsRef() = 42;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,19 @@ sealed unsafe class SafeSigningContextHandleTests
return signingContext;
}

[TestMethod]
public void TakeOwnership_Valid()
{
var signingContextPointer = CreateSigningContextPointer();
using var sigingContext = SafeSigningContextHandle.TakeOwnership(ref signingContextPointer);

Assert.IsFalse(sigingContext.IsInvalid);
}

[TestMethod]
public void TakeOwnership_Null()
{
XmssSigningContext* signingContextPointer = null;
using var sigingContext = SafeSigningContextHandle.TakeOwnership(ref signingContextPointer);

Assert.IsTrue(sigingContext.IsInvalid);
}

[TestMethod]
public void AsRef_Valid()
{
var signingContextPointer = CreateSigningContextPointer();
using var sigingContext = SafeSigningContextHandle.TakeOwnership(ref signingContextPointer);
using var sigingContext = new SafeSigningContextHandle();
sigingContext.AsPointerRef() = CreateSigningContextPointer();

_ = sigingContext.AsRef().ToString();
}

[TestMethod]
public void AsRef_Null()
{
XmssSigningContext* signingContextPointer = null;
using var sigingContext = SafeSigningContextHandle.TakeOwnership(ref signingContextPointer);
using var sigingContext = new SafeSigningContextHandle();

_ = Assert.ThrowsException<NullReferenceException>(() =>
{
Expand Down
12 changes: 10 additions & 2 deletions Xmss/IXmss.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,17 @@ public interface IXmss

public Version NativeLibraryVersion { get; }

public bool Verify(Stream data, byte[] signature);

public void GeneratePrivateKey(XmssParameterSet parameterSet, bool enableIndexObfuscation);

public void LoadPrivateKey();

public byte[] Sign(ReadOnlySpan<byte> data);

public int Sign(ReadOnlySpan<byte> data, Span<byte> destination);

public bool TrySign(ReadOnlySpan<byte> data, Span<byte> destination, out int bytesWritten);

public bool Verify(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature);

public bool Verify(Stream data, ReadOnlySpan<byte> signature);
}
18 changes: 0 additions & 18 deletions Xmss/InteropServices/Generic/SafeNativeMemoryHandle.cs

This file was deleted.

27 changes: 3 additions & 24 deletions Xmss/InteropServices/SafeKeyContextHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,14 @@
//
// SPDX-License-Identifier: MIT

using System.Runtime.InteropServices;
using Dorssel.Security.Cryptography.Internal;

namespace Dorssel.Security.Cryptography.InteropServices;

sealed class SafeKeyContextHandle
: SafeHandle
sealed class SafeKeyContextHandle : SafeXmssHandle<XmssKeyContext>
{
public unsafe SafeKeyContextHandle(XmssKeyContext* keyContext, bool ownsHandle)
: base(0, ownsHandle)
protected override unsafe void Free(XmssKeyContext* pointer)
{
SetHandle((nint)keyContext);
}

public static unsafe SafeKeyContextHandle TakeOwnership(ref XmssKeyContext* ptr)
{
var result = new SafeKeyContextHandle(ptr, true);
ptr = null;
return result;
}

public override bool IsInvalid => handle == 0;

protected override bool ReleaseHandle()
{
unsafe
{
UnsafeNativeMethods.xmss_free_key_context((XmssKeyContext*)handle);
}
return true;
UnsafeNativeMethods.xmss_free_key_context(pointer);
}
}
15 changes: 15 additions & 0 deletions Xmss/InteropServices/SafeKeyGenerationContextHandle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2024 Frans van Dorsselaer
//
// SPDX-License-Identifier: MIT

using Dorssel.Security.Cryptography.Internal;

namespace Dorssel.Security.Cryptography.InteropServices;

sealed class SafeKeyGenerationContextHandle : SafeXmssHandle<XmssKeyGenerationContext>
{
protected override unsafe void Free(XmssKeyGenerationContext* pointer)
{
UnsafeNativeMethods.xmss_free_key_generation_context(pointer);
}
}
27 changes: 3 additions & 24 deletions Xmss/InteropServices/SafeNativeMemoryHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,13 @@
// SPDX-License-Identifier: MIT

using System.Runtime.InteropServices;
using Dorssel.Security.Cryptography.InteropServices.Generic;

namespace Dorssel.Security.Cryptography.InteropServices;

class SafeNativeMemoryHandle
: SafeHandle
sealed unsafe class SafeNativeMemoryHandle<T>() : SafeXmssHandle<T>() where T : unmanaged
{
public unsafe SafeNativeMemoryHandle(void* ptr, bool ownsHandle)
: base(0, ownsHandle)
protected override unsafe void Free(T* pointer)
{
SetHandle((nint)ptr);
}

public static unsafe SafeNativeMemoryHandle<T> TakeOwnership<T>(ref T* ptr) where T : unmanaged
{
var result = new SafeNativeMemoryHandle<T>(ptr, true);
ptr = null;
return result;
}

public override bool IsInvalid => handle == 0;

protected override bool ReleaseHandle()
{
unsafe
{
NativeMemory.Free((void*)handle);
}
return true;
NativeMemory.Free(pointer);
}
}
Loading

0 comments on commit f42d761

Please sign in to comment.