diff --git a/Makefile.am b/Makefile.am index 497357b3..cd0a6127 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/tpm2_param_enc.c b/src/tpm2_param_enc.c index 6c60a7a4..eb1b3735 100644 --- a/src/tpm2_param_enc.c +++ b/src/tpm2_param_enc.c @@ -173,7 +173,7 @@ int TPM2_KDFa( copyLen = keySz - pos; } - memcpy(keyStream, hash, copyLen); + XMEMCPY(keyStream, hash, copyLen); keyStream += copyLen; } ret = keySz; diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 12cf6bef..9c2ee651 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -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) { diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 261dd5e1..6d857c33 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -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 diff --git a/wrapper/CSharp/.runsettings b/wrapper/CSharp/.runsettings new file mode 100644 index 00000000..fd2dd642 --- /dev/null +++ b/wrapper/CSharp/.runsettings @@ -0,0 +1,15 @@ + + + + + + + %PATH%;..\..\..\..\..\out\build\x64-Debug\bin + + + \ No newline at end of file diff --git a/wrapper/CSharp/README.md b/wrapper/CSharp/README.md new file mode 100644 index 00000000..cbecd80c --- /dev/null +++ b/wrapper/CSharp/README.md @@ -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. + diff --git a/wrapper/CSharp/include.am b/wrapper/CSharp/include.am new file mode 100644 index 00000000..3a9c6022 --- /dev/null +++ b/wrapper/CSharp/include.am @@ -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 diff --git a/wrapper/CSharp/wolfTPM-csharp.csproj b/wrapper/CSharp/wolfTPM-csharp.csproj new file mode 100644 index 00000000..df87d8d1 --- /dev/null +++ b/wrapper/CSharp/wolfTPM-csharp.csproj @@ -0,0 +1,15 @@ + + + + Library + netcoreapp3.1 + wolfTPM_csharp + + + + + + + + + diff --git a/wrapper/CSharp/wolfTPM-tests.cs b/wrapper/CSharp/wolfTPM-tests.cs new file mode 100644 index 00000000..7f6748e5 --- /dev/null +++ b/wrapper/CSharp/wolfTPM-tests.cs @@ -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); + + } + + } +} diff --git a/wrapper/CSharp/wolfTPM.cs b/wrapper/CSharp/wolfTPM.cs new file mode 100644 index 00000000..24b9ea7e --- /dev/null +++ b/wrapper/CSharp/wolfTPM.cs @@ -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); + } + + + } +} diff --git a/wrapper/include.am b/wrapper/include.am new file mode 100644 index 00000000..991a32ac --- /dev/null +++ b/wrapper/include.am @@ -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 diff --git a/wrapper/wolfTPM-csharp.sln b/wrapper/wolfTPM-csharp.sln new file mode 100644 index 00000000..9ee0779d --- /dev/null +++ b/wrapper/wolfTPM-csharp.sln @@ -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