Adding a C# wrapper

Tested with swtpm (linux and mono) and on Windows (Visual studio
project and TBS)

Co-authored-by: Anthony Hu <anthony@wolfssl.com>
pull/203/head
Elms 2022-04-29 11:29:03 -07:00 committed by elms
parent efc85dfbfb
commit 3ebc1fc936
12 changed files with 1245 additions and 3 deletions

View File

@ -39,6 +39,7 @@ include IDE/include.am
include certs/include.am
include tests/include.am
include docs/include.am
include wrapper/include.am
EXTRA_DIST+= README.md
EXTRA_DIST+= ChangeLog.md

View File

@ -173,7 +173,7 @@ int TPM2_KDFa(
copyLen = keySz - pos;
}
memcpy(keyStream, hash, copyLen);
XMEMCPY(keyStream, hash, copyLen);
keyStream += copyLen;
}
ret = keySz;

View File

@ -172,6 +172,272 @@ int wolfTPM2_Init(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
return rc;
}
#ifndef WOLFTPM2_NO_HEAP
WOLFTPM2_DEV *wolfTPM2_New(void)
{
WOLFTPM2_DEV *dev = NULL;
dev = (WOLFTPM2_DEV *) XMALLOC(sizeof(WOLFTPM2_DEV), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (dev == NULL) {
return NULL;
}
if (wolfTPM2_Init(dev, NULL, NULL) != TPM_RC_SUCCESS) {
return NULL;
}
return dev;
}
int wolfTPM2_Free(WOLFTPM2_DEV *dev)
{
if (dev != NULL) {
wolfTPM2_Cleanup(dev);
XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM2_KEYBLOB* wolfTPM2_GetNewKeyBlob(void)
{
WOLFTPM2_KEYBLOB* blob = NULL;
blob = (WOLFTPM2_KEYBLOB *) XMALLOC(sizeof(WOLFTPM2_KEYBLOB), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (blob == NULL) {
return NULL;
}
XMEMSET(blob, 0, sizeof(WOLFTPM2_KEYBLOB));
return blob;
}
int wolfTPM2_CleanupKeyBlob(WOLFTPM2_KEYBLOB* blob)
{
if (blob != NULL) {
XFREE(blob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM_API TPMT_PUBLIC* wolfTPM2_GetNewPublicTemplate(void)
{
TPMT_PUBLIC* template = NULL;
template = (TPMT_PUBLIC *) XMALLOC(sizeof(TPMT_PUBLIC), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (template == NULL) {
return NULL;
}
XMEMSET(template, 0, sizeof(TPMT_PUBLIC));
return template;
}
WOLFTPM_API int wolfTPM2_CleanupPublicTemplate(TPMT_PUBLIC* template)
{
if (template != NULL) {
XFREE(template, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM_API WOLFTPM2_KEY* wolfTPM2_GetNewKey(void)
{
WOLFTPM2_KEY* key = NULL;
key = (WOLFTPM2_KEY *) XMALLOC(sizeof(WOLFTPM2_KEY), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (key == NULL) {
return NULL;
}
XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
return key;
}
WOLFTPM_API int wolfTPM2_CleanupKey(WOLFTPM2_KEY* key)
{
if (key != NULL) {
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM2_SESSION* wolfTPM2_GetNewSession(void)
{
WOLFTPM2_SESSION* session = NULL;
session = (WOLFTPM2_SESSION *) XMALLOC(sizeof(WOLFTPM2_SESSION), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (session == NULL) {
return NULL;
}
XMEMSET(session, 0, sizeof(WOLFTPM2_SESSION));
return session;
}
int wolfTPM2_CleanupSession(WOLFTPM2_SESSION* session)
{
if (session != NULL) {
XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
#endif /* WOLFTPM2_NO_HEAP */
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKey(WOLFTPM2_KEY* key)
{
if (key == NULL) {
return NULL;
}
return &(key->handle);
}
int wolfTPM2_GetKeyBlobAsBuffer(byte *buffer, word32 bufferSz,
WOLFTPM2_KEYBLOB* key)
{
int rc = 0;
int sz = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
if ((buffer == NULL) || (bufferSz <= 0) || (key == NULL)) {
return BAD_FUNC_ARG;
}
/* publicArea is encoded format. Eliminates empty fields, saves space. */
rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer),
&pubAreaSize, &key->pub);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size))) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Sanity check for publicArea size failed\n");
#endif
return BUFFER_E;
}
if (bufferSz < sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size +
sizeof(UINT16) + key->priv.size) {
return BUFFER_E;
}
/* Write size marker for the public part */
XMEMCPY(buffer + sz, &key->pub.size, sizeof(key->pub.size));
sz += sizeof(key->pub.size);
/* Write the public part with bytes aligned */
XMEMCPY(buffer + sz, pubAreaBuffer, sizeof(UINT16) + key->pub.size);
sz += sizeof(UINT16) + key->pub.size;
/* Write the private part, size marker is included */
XMEMCPY(buffer + sz, &key->priv, sizeof(UINT16) + key->priv.size);
sz += sizeof(UINT16) + key->priv.size;
#ifdef WOLFTPM_DEBUG_VERBOSE
TPM2_PrintBin(buffer, sz);
printf("Getting %d bytes\n", (int)sz);
#endif
return sz;
}
int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key, byte *buffer,
word32 bufferSz)
{
int rc = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
byte *runner = buffer;
size_t done_reading = 0;
if ((key == NULL) || (buffer == NULL) || (bufferSz <= 0)) {
return BAD_FUNC_ARG;
}
XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB));
#ifdef WOLFTPM_DEBUG_VERBOSE
TPM2_PrintBin(buffer, bufferSz);
printf("Setting %d bytes\n", (int)bufferSz);
#endif
if (bufferSz < done_reading + sizeof(key->pub.size)) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(&key->pub.size, runner, sizeof(key->pub.size));
runner += sizeof(key->pub.size);
done_reading += sizeof(key->pub.size);
if (bufferSz < done_reading + sizeof(UINT16) + key->pub.size) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(pubAreaBuffer, runner, sizeof(UINT16) + key->pub.size);
runner += sizeof(UINT16) + key->pub.size;
done_reading += sizeof(UINT16) + key->pub.size;
/* Decode the byte stream into a publicArea structure ready for use */
rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (bufferSz < done_reading + sizeof(key->priv.size)) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(&key->priv.size, runner, sizeof(key->priv.size));
runner += sizeof(key->priv.size);
done_reading += sizeof(key->priv.size);
if (bufferSz < done_reading + key->priv.size) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(key->priv.buffer, runner, key->priv.size);
runner += key->priv.size;
done_reading += key->priv.size;
return TPM_RC_SUCCESS;
}
int wolfTPM2_SetKeyAuthPassword(WOLFTPM2_KEY *key, const byte* auth,
int authSz)
{
if ((key == NULL) || (authSz < 0)) {
return BAD_FUNC_ARG;
}
if ((auth != NULL) && (authSz == 0)) {
return BAD_FUNC_ARG;
}
/* specify auth password for storage key */
key->handle.auth.size = authSz;
XMEMCPY(key->handle.auth.buffer, auth, authSz);
return TPM_RC_SUCCESS;
}
/* Access already started TPM module */
int wolfTPM2_OpenExisting(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
{

View File

@ -569,8 +569,8 @@ WOLFTPM_API int wolfTPM2_ChangeAuthKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
\sa wolfTPM2_CreatePrimaryKey
*/
WOLFTPM_API int wolfTPM2_CreateKey(WOLFTPM2_DEV* dev,
WOLFTPM2_KEYBLOB* keyBlob, WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz);
WOLFTPM2_KEYBLOB* keyBlob, WOLFTPM2_HANDLE* parent,
TPMT_PUBLIC* publicTemplate, const byte* auth, int authSz);
/*!
\ingroup wolfTPM2_Wrappers
@ -2348,6 +2348,28 @@ WOLFTPM_API int wolfTPM2_ClearCryptoDevCb(WOLFTPM2_DEV* dev, int devId);
#endif /* WOLF_CRYPTO_CB */
#ifndef WOLFTPM2_NO_HEAP
WOLFTPM_API WOLFTPM2_DEV *wolfTPM2_New(void);
WOLFTPM_API int wolfTPM2_Free(WOLFTPM2_DEV *dev);
WOLFTPM_API WOLFTPM2_KEYBLOB* wolfTPM2_GetNewKeyBlob(void);
WOLFTPM_API int wolfTPM2_CleanupKeyBlob(WOLFTPM2_KEYBLOB* blob);
WOLFTPM_API TPMT_PUBLIC* wolfTPM2_GetNewPublicTemplate(void);
WOLFTPM_API int wolfTPM2_CleanupPublicTemplate(TPMT_PUBLIC* template);
WOLFTPM_API WOLFTPM2_KEY* wolfTPM2_GetNewKey(void);
WOLFTPM_API int wolfTPM2_CleanupKey(WOLFTPM2_KEY* key);
WOLFTPM_API WOLFTPM2_SESSION* wolfTPM2_GetNewSession(void);
WOLFTPM_API int wolfTPM2_CleanupSession(WOLFTPM2_SESSION* session);
#endif
WOLFTPM_API int wolfTPM2_OpenExistingDev(WOLFTPM2_DEV* dev);
WOLFTPM_API WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKey(WOLFTPM2_KEY* key);
WOLFTPM_API int wolfTPM2_SetKeyAuthPassword(WOLFTPM2_KEY *key, const byte* auth,
int authSz);
WOLFTPM_API int wolfTPM2_GetKeyBlobAsBuffer(byte *buffer, word32 bufferSz,
WOLFTPM2_KEYBLOB* key);
WOLFTPM_API int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key,
byte *buffer, word32 bufferSz);
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<RunConfiguration>
<EnvironmentVariables>
<!-- update to path to local vcpkg install
<PATH>%PATH%;c:\vcpkg\installed\x64-windows\bin</PATH>
-->
<!--
if wolfTPM cmake solution is built using visual studio,
we need to back out several(5) directories `wrapper\CSharp\bin\Debug\netcoreapp3.1`
-->
<PATH>%PATH%;..\..\..\..\..\out\build\x64-Debug\bin</PATH>
</EnvironmentVariables>
</RunConfiguration>
</RunSettings>

View File

@ -0,0 +1,75 @@
# wolfTPM (TPM 2.0) CSharp Wrappers
This directory contains the CSharp wrapper for the TPM 2.0 API wrapper API.
Once you have created the simulator, you can should build wolfssl as described
in the README.md in the root of this repo. Then you can build wolfTPM:
## Windows
A Visual Studio solution is provided. This will allow you to build the
wrappers. In order to run the tests you will need to update the
`.runsettings` to add the location of the `wolftpm.dll`. There is a
placeholder to leverage a vcpkg build, but cmake can also be used to
build wolfTPM with Visual Studios.
## Linux
The wrapper has been tested with the swtpm TCP protocol for use with
the simulator. Please follow instructions in the `docs/SWTPM.md` file
for building and running the simulator.
```
./autogen.sh
./configure --enable-swtpm
make all
make check
```
Prerequisites for linux
```
apt install mono-tools-devel nunit
```
You can then build and run the test wolfTPM:
```
cd wrapper/CSharp
mcs wolfTPM.cs wolfTPM-tests.cs -r:/usr/lib/cli/nunit.framework-2.6.3/nunit.framework.dll -t:library
# run selftest case
LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll -run=tpm_csharp_test.WolfTPMTest.TrySelfTest
#run all tests
LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll
```
You should see something similar to the following output:
```
NUnit-Console version 2.6.4.0
Copyright (C) 2002-2012 Charlie Poole.
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.
Runtime Environment -
OS Version: Unix 5.13.0.40
CLR Version: 4.0.30319.42000 ( Mono 4.0 ( 6.8.0.105 (Debian 6.8.0.105+dfsg-2 Wed Feb 26 23:23:50 UTC 2020) ) )
ProcessModel: Default DomainUsage: Single
Execution Runtime: mono-4.0
Selected test(s): tpm_csharp_test.WolfTPMTest.TryFillBufferWithRandom
.wolfSSL Entering wolfCrypt_Init
wolfSSL Entering wolfCrypt_Cleanup
buf: { 44, 95, 206, 69, 252, 157, 173, 149, 26, 160, 21, 5, 35, 19, 255, 29, 251, 228, 206, 36, 77, 79, 160, 42, 25, 172, 82, 172, 152, 143, 179, 147, 52, 211, 238, 63, 34, 227, 243, 155, 17, 77, 135, 233, 103, 39, 211, 180, 55, 54, 36, 180, 87, 168, 28, 143, 104, 175, 176, 156, 154, 8, 114, 143, 123, 99, 110, 247, 46, 193, 93, 54, 208, 128, 162, 190, 225, 255, 109, 44, 8, 153, 21, 162, 139, 70, 7, 73, 13, 145, 157, 111, 20, 151, 101, 44, 45, 154, 159, 139, 153, 48, 117, 69, 179, 186, 48, 225, 20, 145, 120, 78, 58, 228, 4, 146, 241, 195, 121, 94, 44, 92, 246, 198, 71, 122, 176, 133, 21, 27, 41, 17, 7, 96, 122, 155, 105, 57, 150, 45, 63, 165, 136, 195, 173, 160, 137, 136, 207, 19, 60, 140, 2, 203, 246, 248, 179, 170, 203, 153, 154, 229, 104, 200, 141, 94, 139, 25, 103, 235, 116, 97, 186, 29, 32, 133, 205, 122, 230, 51, 88, 195, 69, 158, 199, 255, 212, 117, 3, 110, 201, 179, 138, 242, 172, 160, 121, 46, 117, 41, 185, 11, 22, 99, 4, 214, 37, 179, 246, 71, 146, 168, 116, 28, 146, 221, 53, 21, 5, 18, 84, 57, 137, 171, 237, 233, 215, 91, 88, 4, 205, 207, 218, 74, 46, 105, 106, 55, 254, 211, 186, 151, 136, 81, 128, 33, 77, 218, 203, 19, 164, 76, 177, 2, 185, 212, } (256 bytes)
Tests run: 1, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0.0747956 seconds
Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0
```
If you run this multiple time, you will see the content of the buffer changing
for each execution.

View File

@ -0,0 +1,11 @@
# vim:ft=automake
# All paths should be given relative to the root
wrapper_CSharpdir = $(wrapperdir)/CSharp
dist_wrapper_CSharp_DATA= \
wrapper/CSharp/README.md \
wrapper/CSharp/wolfTPM.cs \
wrapper/CSharp/wolfTPM-tests.cs \
wrapper/CSharp/.runsettings \
wrapper/CSharp/wolfTPM-csharp.csproj

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>wolfTPM_csharp</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,326 @@
using NUnit.Framework;
using System;
using System.IO;
using System.Text;
using wolfTPM;
namespace tpm_csharp_test
{
[TestFixture]
public class WolfTPMTest
{
/* Globals used for setup and teardown */
private Device device = new Device();
private Key parent_key;
private static byte[] priv_buffer = {
0xd5, 0x38, 0x1b, 0xc3, 0x8f, 0xc5, 0x93, 0x0c,
0x47, 0x0b, 0x6f, 0x35, 0x92, 0xc5, 0xb0, 0x8d,
0x46, 0xc8, 0x92, 0x18, 0x8f, 0xf5, 0x80, 0x0a,
0xf7, 0xef, 0xa1, 0xfe, 0x80, 0xb9, 0xb5, 0x2a,
0xba, 0xca, 0x18, 0xb0, 0x5d, 0xa5, 0x07, 0xd0,
0x93, 0x8d, 0xd8, 0x9c, 0x04, 0x1c, 0xd4, 0x62,
0x8e, 0xa6, 0x26, 0x81, 0x01, 0xff, 0xce, 0x8a,
0x2a, 0x63, 0x34, 0x35, 0x40, 0xaa, 0x6d, 0x80,
0xde, 0x89, 0x23, 0x6a, 0x57, 0x4d, 0x9e, 0x6e,
0xad, 0x93, 0x4e, 0x56, 0x90, 0x0b, 0x6d, 0x9d,
0x73, 0x8b, 0x0c, 0xae, 0x27, 0x3d, 0xde, 0x4e,
0xf0, 0xaa, 0xc5, 0x6c, 0x78, 0x67, 0x6c, 0x94,
0x52, 0x9c, 0x37, 0x67, 0x6c, 0x2d, 0xef, 0xbb,
0xaf, 0xdf, 0xa6, 0x90, 0x3c, 0xc4, 0x47, 0xcf,
0x8d, 0x96, 0x9e, 0x98, 0xa9, 0xb4, 0x9f, 0xc5,
0xa6, 0x50, 0xdc, 0xb3, 0xf0, 0xfb, 0x74, 0x17
};
private static byte[] pub_buffer = {
0xc3, 0x03, 0xd1, 0x2b, 0xfe, 0x39, 0xa4, 0x32,
0x45, 0x3b, 0x53, 0xc8, 0x84, 0x2b, 0x2a, 0x7c,
0x74, 0x9a, 0xbd, 0xaa, 0x2a, 0x52, 0x07, 0x47,
0xd6, 0xa6, 0x36, 0xb2, 0x07, 0x32, 0x8e, 0xd0,
0xba, 0x69, 0x7b, 0xc6, 0xc3, 0x44, 0x9e, 0xd4,
0x81, 0x48, 0xfd, 0x2d, 0x68, 0xa2, 0x8b, 0x67,
0xbb, 0xa1, 0x75, 0xc8, 0x36, 0x2c, 0x4a, 0xd2,
0x1b, 0xf7, 0x8b, 0xba, 0xcf, 0x0d, 0xf9, 0xef,
0xec, 0xf1, 0x81, 0x1e, 0x7b, 0x9b, 0x03, 0x47,
0x9a, 0xbf, 0x65, 0xcc, 0x7f, 0x65, 0x24, 0x69,
0xa6, 0xe8, 0x14, 0x89, 0x5b, 0xe4, 0x34, 0xf7,
0xc5, 0xb0, 0x14, 0x93, 0xf5, 0x67, 0x7b, 0x3a,
0x7a, 0x78, 0xe1, 0x01, 0x56, 0x56, 0x91, 0xa6,
0x13, 0x42, 0x8d, 0xd2, 0x3c, 0x40, 0x9c, 0x4c,
0xef, 0xd1, 0x86, 0xdf, 0x37, 0x51, 0x1b, 0x0c,
0xa1, 0x3b, 0xf5, 0xf1, 0xa3, 0x4a, 0x35, 0xe4,
0xe1, 0xce, 0x96, 0xdf, 0x1b, 0x7e, 0xbf, 0x4e,
0x97, 0xd0, 0x10, 0xe8, 0xa8, 0x08, 0x30, 0x81,
0xaf, 0x20, 0x0b, 0x43, 0x14, 0xc5, 0x74, 0x67,
0xb4, 0x32, 0x82, 0x6f, 0x8d, 0x86, 0xc2, 0x88,
0x40, 0x99, 0x36, 0x83, 0xba, 0x1e, 0x40, 0x72,
0x22, 0x17, 0xd7, 0x52, 0x65, 0x24, 0x73, 0xb0,
0xce, 0xef, 0x19, 0xcd, 0xae, 0xff, 0x78, 0x6c,
0x7b, 0xc0, 0x12, 0x03, 0xd4, 0x4e, 0x72, 0x0d,
0x50, 0x6d, 0x3b, 0xa3, 0x3b, 0xa3, 0x99, 0x5e,
0x9d, 0xc8, 0xd9, 0x0c, 0x85, 0xb3, 0xd9, 0x8a,
0xd9, 0x54, 0x26, 0xdb, 0x6d, 0xfa, 0xac, 0xbb,
0xff, 0x25, 0x4c, 0xc4, 0xd1, 0x79, 0xf4, 0x71,
0xd3, 0x86, 0x40, 0x18, 0x13, 0xb0, 0x63, 0xb5,
0x72, 0x4e, 0x30, 0xc4, 0x97, 0x84, 0x86, 0x2d,
0x56, 0x2f, 0xd7, 0x15, 0xf7, 0x7f, 0xc0, 0xae,
0xf5, 0xfc, 0x5b, 0xe5, 0xfb, 0xa1, 0xba, 0xd3
};
private byte[] generatedAES;
private byte[] generatedRSA;
private static void PrintByteArray(byte[] bytes)
{
var sb = new StringBuilder("buf: { ");
foreach (var b in bytes)
{
sb.Append(b + ", ");
}
sb.Append("} (");
sb.Append(bytes.Length);
sb.Append(" bytes)");
Console.WriteLine(sb.ToString());
}
void getSRK(Key srkKey, string auth)
{
int ret = device.CreateSRK(srkKey,
(int)TPM2_Alg.RSA,
auth);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
[SetUp]
public void TestInit()
{
parent_key = new Key();
getSRK(parent_key, "ThisIsMyStorageKeyAuth");
}
[TearDown]
public void TestCleanup()
{
int ret = (int)Status.TPM_RC_SUCCESS;
ret = device.UnloadHandle(parent_key);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
[Test]
public void TrySelfTest()
{
uint ret = (uint)device.SelfTest();
Assert.That(ret, Is.EqualTo((uint)Status.TPM_RC_SUCCESS) | Is.EqualTo(0x80280400));
}
[Test]
public void TryFillBufferWithRandom()
{
const int bufSz = 256;
byte[] buf = new byte[bufSz];
int ret = device.GetRandom(buf);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
PrintByteArray(buf);
Assert.That(buf, Has.Some.GreaterThan(0));
}
[Test]
public void TryGenerateAndLoadRSA()
{
GenerateRSA();
LoadGeneratedRSA();
}
[Test]
public void TryGenerateAndLoadAES()
{
GenerateAES();
LoadGeneratedAES();
}
void GenerateRSA()
{
GenerateKey("RSA");
}
void GenerateAES()
{
GenerateKey("AES");
}
void GenerateKey(string algorithm)
{
int ret = (int)Status.TPM_RC_SUCCESS;
KeyBlob blob = new KeyBlob();
Template template = new Template();
byte[] blob_buffer = new byte[Device.MAX_KEYBLOB_BYTES];
if (algorithm == "RSA")
{
ret = template.GetKeyTemplate_RSA((ulong)(
TPM2_Object.sensitiveDataOrigin |
TPM2_Object.userWithAuth |
TPM2_Object.decrypt |
TPM2_Object.sign |
TPM2_Object.noDA));
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
else if (algorithm == "AES")
{
ret = template.GetKeyTemplate_Symmetric(256, TPM2_Alg.CTR, true, true);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
else
{
Console.WriteLine("Unexpected algorithm name!!!");
Assert.Fail();
}
ret = device.CreateKey(blob, parent_key, template,
"ThisIsMyStorageKeyAuth");
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.LoadKey(blob, parent_key);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = blob.GetKeyBlobAsBuffer(blob_buffer);
if (ret > 0)
{
Array.Resize(ref blob_buffer, ret);
if (algorithm == "RSA")
{
generatedRSA = blob_buffer;
}
else if (algorithm == "AES")
{
generatedAES = blob_buffer;
}
else
{
Console.WriteLine("Unexpected algorithm name!!!");
return;
}
ret = (int)Status.TPM_RC_SUCCESS;
}
else
{
Console.WriteLine("wolfTPM2_GetKeyBlobAsBuffer() failed.");
ret = -1;
}
ret = device.UnloadHandle(blob);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
void LoadGeneratedRSA()
{
LoadGeneratedKey("RSA");
}
void LoadGeneratedAES()
{
LoadGeneratedKey("AES");
}
void LoadGeneratedKey(string algorithm)
{
int ret = (int)Status.TPM_RC_SUCCESS;
KeyBlob blob = new KeyBlob();
byte[] blob_buffer;
if (algorithm == "RSA")
{
blob_buffer = generatedRSA;
}
else if (algorithm == "AES")
{
blob_buffer = generatedAES;
}
else
{
Console.WriteLine("Unexpected algorithm name!!!");
return;
}
ret = blob.SetKeyBlobFromBuffer(blob_buffer);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.LoadKey(blob, parent_key);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.UnloadHandle(blob);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
[Test]
public void TryLoadRSAPublicKey()
{
int ret = (int)Status.TPM_RC_SUCCESS;
Key pub_key;
int exp = 0x10001;
PrintByteArray(pub_buffer);
pub_key = new Key();
ret = device.LoadRsaPublicKey(pub_key, pub_buffer, exp);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.UnloadHandle(pub_key);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
[Test]
public void TryLoadRSAPrivateKey()
{
int ret = (int)Status.TPM_RC_SUCCESS;
Key priv_key;
int exp = 0x10001;
PrintByteArray(pub_buffer);
PrintByteArray(priv_buffer);
priv_key = new Key();
ret = device.LoadRsaPrivateKey(parent_key, priv_key,
pub_buffer, exp,
priv_buffer);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.UnloadHandle(priv_key);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
[Test]
public void TryImportRSAPrivateKey()
{
int ret = (int)Status.TPM_RC_SUCCESS;
KeyBlob blob;
int exp = 0x10001;
PrintByteArray(pub_buffer);
PrintByteArray(priv_buffer);
blob = new KeyBlob();
ret = device.ImportRsaPrivateKey(parent_key, blob,
pub_buffer,
exp, priv_buffer,
(uint)TPM2_Alg.NULL, (uint)TPM2_Alg.NULL);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
ret = device.UnloadHandle(blob);
Assert.AreEqual((int)Status.TPM_RC_SUCCESS, ret);
}
}
}

View File

@ -0,0 +1,479 @@
using System;
using System.Runtime.InteropServices;
namespace wolfTPM
{
public enum Status : int
{
TPM_RC_SUCCESS = 0,
}
public enum TPM2_Object : ulong
{
fixedTPM = 0x00000002,
stClear = 0x00000004,
fixedParent = 0x00000010,
sensitiveDataOrigin = 0x00000020,
userWithAuth = 0x00000040,
adminWithPolicy = 0x00000080,
derivedDataOrigin = 0x00000200,
noDA = 0x00000400,
encryptedDuplication = 0x00000800,
restricted = 0x00010000,
decrypt = 0x00020000,
sign = 0x00040000,
}
public enum TPM2_Alg : uint
{
ERROR = 0x0000,
RSA = 0x0001,
SHA = 0x0004,
SHA1 = SHA,
HMAC = 0x0005,
AES = 0x0006,
MGF1 = 0x0007,
KEYEDHASH = 0x0008,
XOR = 0x000A,
SHA256 = 0x000B,
SHA384 = 0x000C,
SHA512 = 0x000D,
NULL = 0x0010,
SM3_256 = 0x0012,
SM4 = 0x0013,
RSASSA = 0x0014,
RSAES = 0x0015,
RSAPSS = 0x0016,
OAEP = 0x0017,
ECDSA = 0x0018,
ECDH = 0x0019,
ECDAA = 0x001A,
SM2 = 0x001B,
ECSCHNORR = 0x001C,
ECMQV = 0x001D,
KDF1_SP800_56A = 0x0020,
KDF2 = 0x0021,
KDF1_SP800_108 = 0x0022,
ECC = 0x0023,
SYMCIPHER = 0x0025,
CAMELLIA = 0x0026,
CTR = 0x0040,
OFB = 0x0041,
CBC = 0x0042,
CFB = 0x0043,
ECB = 0x0044,
}
public enum SE : byte
{
HMAC = 0x00,
POLICY = 0x01,
TRIAL = 0x03,
}
public class KeyBlob
{
const string DLLNAME = "wolftpm";
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetNewKeyBlob")]
private static extern IntPtr wolfTPM2_GetNewKeyBlob();
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CleanupKeyBlob")]
private static extern int wolfTPM2_CleanupKeyBlob(IntPtr blob);
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetKeyBlobAsBuffer")]
private static extern int wolfTPM2_GetKeyBlobAsBuffer(byte[] buffer,
int bufferSz, IntPtr key);
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_SetKeyBlobFromBuffer")]
private static extern int wolfTPM2_SetKeyBlobFromBuffer(IntPtr key,
byte[] buffer, int bufferSz);
internal IntPtr keyblob;
public KeyBlob()
{
keyblob = wolfTPM2_GetNewKeyBlob();
}
~KeyBlob()
{
if (keyblob != IntPtr.Zero)
{
// TODO: check return value?
wolfTPM2_CleanupKeyBlob(keyblob);
}
}
public int GetKeyBlobAsBuffer(byte[] buffer)
{
return wolfTPM2_GetKeyBlobAsBuffer(buffer, buffer.Length, keyblob);
}
public int SetKeyBlobFromBuffer(byte[] buffer)
{
return wolfTPM2_SetKeyBlobFromBuffer(keyblob, buffer, buffer.Length);
}
}
public class Key
{
const string DLLNAME = "wolftpm";
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetNewKey")]
private static extern IntPtr wolfTPM2_GetNewKey();
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CleanupKey")]
private static extern int wolfTPM2_CleanupKey(IntPtr key);
/* ================================================================== */
/* Native Getters and Setters */
/* ================================================================== */
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_SetKeyAuthPassword")]
private static extern int wolfTPM2_SetKeyAuthPassword(
IntPtr key,
string auth,
int authSz);
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetHandleRefFromKey")]
private static extern IntPtr wolfTPM2_GetHandleRefFromKey(IntPtr key);
internal IntPtr key;
public Key()
{
key = wolfTPM2_GetNewKey();
}
~Key()
{
if (key != IntPtr.Zero)
{
// TODO: check return value
wolfTPM2_CleanupKey(key);
}
}
public IntPtr GetHandleRefFromKey()
{
return wolfTPM2_GetHandleRefFromKey(key);
}
public int SetKeyAuthPassword(string auth)
{
return wolfTPM2_SetKeyAuthPassword(key,
auth,
auth.Length);
}
}
public class Template
{
const string DLLNAME = "wolftpm";
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetNewPublicTemplate")]
private static extern IntPtr wolfTPM2_GetNewPublicTemplate();
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CleanupPublicTemplate")]
private static extern int wolfTPM2_CleanupPublicTemplate(IntPtr template);
internal IntPtr template;
public Template()
{
template = wolfTPM2_GetNewPublicTemplate();
}
~Template()
{
wolfTPM2_CleanupPublicTemplate(template);
}
/* non-device functions: template and auth */
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetKeyTemplate_RSA")]
private static extern int wolfTPM2_GetKeyTemplate_RSA(IntPtr publicTemplate,
ulong objectAttributes);
public int GetKeyTemplate_RSA(ulong objectAttributes)
{
return wolfTPM2_GetKeyTemplate_RSA(template,
objectAttributes);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetKeyTemplate_Symmetric")]
private static extern int wolfTPM2_GetKeyTemplate_Symmetric(
IntPtr publicTemplate, int keyBits, uint algMode, int isSign,
int isDecrypt);
public int GetKeyTemplate_Symmetric(int keyBits,
TPM2_Alg algMode,
bool isSign,
bool isDecrypt)
{
return wolfTPM2_GetKeyTemplate_Symmetric(template,
keyBits,
(uint)algMode,
isSign ? 1 : 0,
isDecrypt ? 1 : 0);
}
}
public class Session
{
const string DLLNAME = "wolftpm";
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetNewSession")]
private static extern IntPtr wolfTPM2_GetNewSession();
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CleanupSession")]
private static extern int wolfTPM2_CleanupSession(IntPtr session);
internal IntPtr session;
public Session()
{
session = wolfTPM2_GetNewSession();
}
~Session()
{
if (session != IntPtr.Zero)
{
// TODO: check return value
wolfTPM2_CleanupSession(session);
}
}
}
public class Device
{
/* ================================================================== */
/* Constants */
/* ================================================================== */
const string DLLNAME = "wolftpm";
public const int MAX_KEYBLOB_BYTES = 1024;
private IntPtr device = IntPtr.Zero;
public Device()
{
device = wolfTPM2_New();
}
~Device()
{
if (device != IntPtr.Zero)
{
wolfTPM2_Free(device);
}
}
/* Note that this one is not an empty; it actually calls wolfTPM2_Init()
* as a convenience for the user. */
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_New")]
private static extern IntPtr wolfTPM2_New();
/* WOLFTPM_API int wolfTPM2_SimpleCleanup(WOLFTPM2_DEV *dev); */
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_Free")]
private static extern int wolfTPM2_Free(IntPtr dev);
/* ================================================================== */
/* Native Wrappers */
/* ================================================================== */
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_SelfTest")]
private static extern int wolfTPM2_SelfTest(IntPtr dev);
public int SelfTest()
{
return wolfTPM2_SelfTest(device);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_GetRandom")]
private static extern int wolfTPM2_GetRandom(IntPtr dev,
byte[] buf,
int len);
public int GetRandom(byte[] buf)
{
return wolfTPM2_GetRandom(device, buf, buf.Length);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CreateSRK")]
private static extern int wolfTPM2_CreateSRK(IntPtr dev,
IntPtr srkKey,
int alg,
string auth,
int authSz);
public int CreateSRK(Key srkKey,
int alg,
string auth)
{
return wolfTPM2_CreateSRK(device,
srkKey.key,
alg,
auth,
auth.Length);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_StartSession")]
private static extern int wolfTPM2_StartSession(IntPtr dev, IntPtr session,
IntPtr tmpKey, IntPtr bind, byte sesType, int encDecAlg);
public int StartSession(IntPtr session,
Key tmpKey,
IntPtr bind,
byte sesType,
int encDecAlg)
{
return wolfTPM2_StartSession(device,
session,
tmpKey.key,
bind,
sesType,
encDecAlg);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_ReadPublicKey")]
private static extern int wolfTPM2_ReadPublicKey(IntPtr dev,
IntPtr key,
ulong handle);
public int ReadPublicKey(Key key,
ulong handle)
{
return wolfTPM2_ReadPublicKey(device,
key.key,
handle);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_CreateKey")]
private static extern int wolfTPM2_CreateKey(
IntPtr dev,
IntPtr keyBlob,
IntPtr parent,
IntPtr publicTemplate,
string auth,
int authSz);
public int CreateKey(KeyBlob keyBlob,
Key parent,
Template publicTemplate,
string auth)
{
return wolfTPM2_CreateKey(device,
keyBlob.keyblob,
parent.GetHandleRefFromKey(),
publicTemplate.template,
auth,
auth.Length);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_LoadKey")]
private static extern int wolfTPM2_LoadKey(
IntPtr dev,
IntPtr keyBlob,
IntPtr parent);
public int LoadKey(KeyBlob keyBlob,
Key parent)
{
return wolfTPM2_LoadKey(device, keyBlob.keyblob, parent.GetHandleRefFromKey());
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_ImportRsaPrivateKey")]
private static extern int wolfTPM2_ImportRsaPrivateKey(
IntPtr dev,
IntPtr parentKey,
IntPtr keyBlob,
byte[] rsaPub,
int rsaPubSz,
int exponent,
byte[] rsaPriv,
int rsaPrivSz,
uint scheme,
uint hashAlg);
public int ImportRsaPrivateKey(
Key parentKey,
KeyBlob keyBlob,
byte[] rsaPub,
int exponent,
byte[] rsaPriv,
uint scheme,
uint hashAlg)
{
return wolfTPM2_ImportRsaPrivateKey(device,
parentKey.key,
keyBlob.keyblob,
rsaPub,
rsaPub.Length,
exponent,
rsaPriv,
rsaPriv.Length,
scheme,
hashAlg);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_LoadRsaPublicKey")]
private static extern int wolfTPM2_LoadRsaPublicKey(
IntPtr dev,
IntPtr key,
byte[] rsaPub,
int rsaPubSz,
int exponent);
public int LoadRsaPublicKey(Key key,
byte[] rsaPub,
int exponent)
{
return wolfTPM2_LoadRsaPublicKey(device,
key.key,
rsaPub,
rsaPub.Length,
exponent);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_LoadRsaPrivateKey")]
private static extern int wolfTPM2_LoadRsaPrivateKey(
IntPtr dev,
IntPtr parentKey,
IntPtr key,
byte[] rsaPub,
int rsaPubSz,
int exponent,
byte[] rsaPriv,
int rsaPrivSz);
public int LoadRsaPrivateKey(
Key parentKey,
Key key,
byte[] rsaPub,
int exponent,
byte[] rsaPriv)
{
return wolfTPM2_LoadRsaPrivateKey(
device,
parentKey.key,
key.key,
rsaPub,
rsaPub.Length,
exponent,
rsaPriv,
rsaPriv.Length);
}
[DllImport(DLLNAME, EntryPoint = "wolfTPM2_UnloadHandle")]
private static extern int wolfTPM2_UnloadHandle(IntPtr dev, IntPtr handle);
public int UnloadHandle(Key key)
{
return wolfTPM2_UnloadHandle(device, key.key);
}
public int UnloadHandle(KeyBlob keyblob)
{
return wolfTPM2_UnloadHandle(device, keyblob.keyblob);
}
}
}

View File

@ -0,0 +1,7 @@
# vim:ft=automake
# All paths should be given relative to the root
include wrapper/CSharp/include.am
wrapperdir = $(docdir)/wrapper
dist_wrapper_DATA= wrapper/wolfTPM-csharp.sln

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "wolfTPM-csharp", "CSharp\wolfTPM-csharp.csproj", "{B94757A8-B2A3-4289-887D-A0B23C34F418}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B94757A8-B2A3-4289-887D-A0B23C34F418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B94757A8-B2A3-4289-887D-A0B23C34F418}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B94757A8-B2A3-4289-887D-A0B23C34F418}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B94757A8-B2A3-4289-887D-A0B23C34F418}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C5F3DA80-4658-45F2-9224-EF22CAD6108B}
EndGlobalSection
EndGlobal