diff --git a/src/internal.c b/src/internal.c index 9885b7e..5aaf421 100644 --- a/src/internal.c +++ b/src/internal.c @@ -618,6 +618,7 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, WFREE(ctx->privateKey, heap, dynamicType); ctx->privateKey = der; ctx->privateKeySz = derSz; + ctx->useEcc = 0; } else { WFREE(der, heap, dynamicType); diff --git a/tests/api.c b/tests/api.c index d5db677..ddd0bf0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -21,6 +21,7 @@ #include #include +#include #ifdef WOLFSSH_SCP #include #endif @@ -76,6 +77,161 @@ #define AssertStrLE(x, y) AssertStr(x, y, <=, >) +/* Utility functions */ + +#define BAD 0xFF + +const byte hexDecode[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, + 10, 11, 12, 13, 14, 15, /* upper case A-F */ + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, /* G - ` */ + 10, 11, 12, 13, 14, 15 /* lower case a-f */ +}; /* A starts at 0x41 not 0x3A */ + + +static int Base16_Decode(const byte* in, word32 inLen, + byte* out, word32* outLen) +{ + word32 inIdx = 0; + word32 outIdx = 0; + + if (inLen == 1 && *outLen && in) { + byte b = in[inIdx++] - 0x30; /* 0 starts at 0x30 */ + + /* sanity check */ + if (b >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return -1; + + b = hexDecode[b]; + + if (b == BAD) + return -1; + + out[outIdx++] = b; + + *outLen = outIdx; + return 0; + } + + if (inLen % 2) + return -1; + + if (*outLen < (inLen / 2)) + return -1; + + while (inLen) { + byte b = in[inIdx++] - 0x30; /* 0 starts at 0x30 */ + byte b2 = in[inIdx++] - 0x30; + + /* sanity checks */ + if (b >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return -1; + if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return -1; + + b = hexDecode[b]; + b2 = hexDecode[b2]; + + if (b == BAD || b2 == BAD) + return -1; + + out[outIdx++] = (byte)((b << 4) | b2); + inLen -= 2; + } + + *outLen = outIdx; + return 0; +} + + +static void FreeBins(byte* b1, byte* b2, byte* b3, byte* b4) +{ + if (b1 != NULL) free(b1); + if (b2 != NULL) free(b2); + if (b3 != NULL) free(b3); + if (b4 != NULL) free(b4); +} + + +/* convert hex string to binary, store size, 0 success (free mem on failure) */ +static int ConvertHexToBin(const char* h1, byte** b1, word32* b1Sz, + const char* h2, byte** b2, word32* b2Sz, + const char* h3, byte** b3, word32* b3Sz, + const char* h4, byte** b4, word32* b4Sz) +{ + int ret; + + /* b1 */ + if (h1 && b1 && b1Sz) { + *b1Sz = (word32)strlen(h1) / 2; + *b1 = (byte*)malloc(*b1Sz); + if (*b1 == NULL) + return -1; + ret = Base16_Decode((const byte*)h1, (word32)strlen(h1), + *b1, b1Sz); + if (ret != 0) { + FreeBins(*b1, NULL, NULL, NULL); + return -1; + } + } + + /* b2 */ + if (h2 && b2 && b2Sz) { + *b2Sz = (word32)strlen(h2) / 2; + *b2 = (byte*)malloc(*b2Sz); + if (*b2 == NULL) { + FreeBins(b1 ? *b1 : NULL, NULL, NULL, NULL); + return -1; + } + ret = Base16_Decode((const byte*)h2, (word32)strlen(h2), + *b2, b2Sz); + if (ret != 0) { + FreeBins(b1 ? *b1 : NULL, *b2, NULL, NULL); + return -1; + } + } + + /* b3 */ + if (h3 && b3 && b3Sz) { + *b3Sz = (word32)strlen(h3) / 2; + *b3 = (byte*)malloc(*b3Sz); + if (*b3 == NULL) { + FreeBins(b1 ? *b1 : NULL, b2 ? *b2 : NULL, NULL, NULL); + return -1; + } + ret = Base16_Decode((const byte*)h3, (word32)strlen(h3), + *b3, b3Sz); + if (ret != 0) { + FreeBins(b1 ? *b1 : NULL, b2 ? *b2 : NULL, *b3, NULL); + return -1; + } + } + + /* b4 */ + if (h4 && b4 && b4Sz) { + *b4Sz = (word32)strlen(h4) / 2; + *b4 = (byte*)malloc(*b4Sz); + if (*b4 == NULL) { + FreeBins(b1 ? *b1 : NULL, b2 ? *b2 : NULL, b3 ? *b3 : NULL, NULL); + return -1; + } + ret = Base16_Decode((const byte*)h4, (word32)strlen(h4), + *b4, b4Sz); + if (ret != 0) { + FreeBins(b1 ? *b1 : NULL, b2 ? *b2 : NULL, b3 ? *b3 : NULL, *b4); + return -1; + } + } + + return 0; +} + + enum WS_TestEndpointTypes { TEST_GOOD_ENDPOINT_SERVER = WOLFSSH_ENDPOINT_SERVER, TEST_GOOD_ENDPOINT_CLIENT = WOLFSSH_ENDPOINT_CLIENT, @@ -106,9 +262,11 @@ static void test_server_wolfSSH_new(void) WOLFSSH_CTX* ctx; WOLFSSH* ssh; + AssertNull(ssh = wolfSSH_new(NULL)); + wolfSSH_free(ssh); + AssertNotNull(ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL)); AssertNotNull(ssh = wolfSSH_new(ctx)); - wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); } @@ -119,9 +277,11 @@ static void test_client_wolfSSH_new(void) WOLFSSH_CTX* ctx; WOLFSSH* ssh; + AssertNull(ssh = wolfSSH_new(NULL)); + wolfSSH_free(ssh); + AssertNotNull(ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL)); AssertNotNull(ssh = wolfSSH_new(ctx)); - wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); } @@ -180,6 +340,141 @@ static void test_wolfSSH_SetUsername(void) } +enum WS_TestFormatTypes { + TEST_GOOD_FORMAT_ASN1 = WOLFSSH_FORMAT_ASN1, + TEST_GOOD_FORMAT_PEM = WOLFSSH_FORMAT_PEM, + TEST_GOOD_FORMAT_RAW = WOLFSSH_FORMAT_RAW, + TEST_BAD_FORMAT_NEXT, + TEST_BAD_FORMAT_LAST = 0xFFFF +}; + + +static const char serverKeyEccDer[] = + "307702010104206109990b79d25f285a0f5d15cca15654f92b3987212da77d85" + "7bb87f38c66dd5a00a06082a8648ce3d030107a144034200048113ffa42bb79c" + "45747a834c61f33fad26cf22cda9a3bca561b47ce662d4c2f755439a31fb8011" + "20b5124b24f578d7fd22ef4635f005586b5f63c8da1bc4f569"; + +static const char serverKeyRsaDer[] = + "308204a30201000282010100da5dad2514761559f340fd3cb86230b36dc0f9ec" + "ec8b831e9e429cca416ad38ae15234e00d13627ed40fae5c4d04f18dfac5ad77" + "aa5a05caeff88dabff8a29094c04c2f519cbed1fb1b429d3c36ca923dfa3a0e5" + "08dead8c71f934886ced3bf06fa50fac59ff6b33f170fb8ca4b345228d9d777a" + "e5295f8414d999eaeace2d51f3e358fa5b020fc9b52abcb25ed3c230bb3cb1c3" + "ef58f35094288bc4654af700d997d96b4d8d95a18a6206b450112283b4ea2ae7" + "d0a820474fff46aec513e1388bf854af3a4d2ff81fd78490d8930506c27d90db" + "e39cd0c4655a03ad00ac5aa2cdda3f89583753bf2b467aac89412b5a2ee876e7" + "5ee32985a363eae686607c2d02030100010281ff0f911e06c6aea45705405ccd" + "3757c8a101f1ffdf23fdce1b20ad1f004c29916b1525071ff1ceaff6daa74386" + "d0f6c94195df01bec62624c392d7e5419db5fbb6edf468f19025398248e8cf12" + "899bf572d93e90f9c2e81cf72628ddd5dbee0d97d65dae005b6a19fa59fbf3f2" + "d2caf4e2c1b5b80ecac76847c234c1043e38f4820159f28a6ef76b5b0abc05a9" + "2737b9f9068054e8701ab432936bf526c786f4580543f9728fec42a03bba3562" + "ccecf4b304a2ebae3c87408efe8fdd14bebd83c9c918ca817c06f9e3992eec29" + "c52756ea1e93c6e80c44ca73684a7fae16251d1225142aec416925c35de6aee4" + "59801dfabd9f3336939d88d688c95b277b0b6102818100de01abfa65d2fad26f" + "fe3f576d757f8ce6bdfe08bdc71334620e87b27a2ca9cdca93d83191812dd668" + "96aa25e3b87ea598a8e8153cc0cedef5ab80b1f5baafac9cc1b34334ae22f718" + "418663a2448e1b419d2d756f0d5b10195d14aa801fee023ef8b6f6ec658e3889" + "0d0b50e41149863982db73e53a0f1322abada0789b942102818100fbcd4c5249" + "3f2c8094914a38ec0f4a7d3a8ebc0490152584fbd368bdefa047fece5bbf1d2a" + "9427fc5170ffc9e9babe2ba05025d3e1a15733cc5cc77d09f6dcfb72943dca59" + "5273e06c450ad9da30df2b33d752184101f0df1b01c1d3b79b26f81c8fffc819" + "fd36d013a57242a3305957b4da2a09e5455a396d70220cba53268d02818100b1" + "3cc270f093c43cf6be1311984882e11961bb0a7d800e3bf6c0c4e2df19032351" + "44410829b2e8c650cf5fdd49f503deee86826a5a0b4fdcbe63022691184ea1ce" + "aff18e88e330f4f5ff71ebdf233e145288ca3f03beb4e1a06e284e8a65735d85" + "aa885f8f90f03f006352926cd1c4520d5e04177d7ca186545a9d0e0cdba02102" + "818100eafe1b9e27b1876cb03a2f9493e9695119971facfa7261c38be92eb523" + "aee7c1cb002089adb4fae4257559a22c3915454da5bec7d0a86be371739cd0fa" + "bda25a20026cf02d1020086fc2b76fbc8b239b04148d0f098c302966e0eaed15" + "4afcc14c96aed5263c042d88483d2c2773f5cd3e80e3febc334f128d29bafd39" + "de63f9028181008b1f47a2904b823b892de96be128e5228783d0de1e0d8ccc84" + "433d238d9d6cbcc4c6da44447920b63eefcf8ac438b0e5da45ac5acc7b62baa9" + "731fba275c82f8ad311edef33772cb47d2cdf7f87f0039db8d2aca4ec1cee215" + "89d63a61ae9da230a585ae38ea4674dc023aace95fa3c6734f73819056c3ce77" + "5f5bba6c42f121"; + + +static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) +{ +#ifndef WOLFSSH_NO_SERVER + WOLFSSH_CTX* ctx; + byte* eccKey; + byte* rsaKey; + byte* lastKey; + word32 eccKeySz, rsaKeySz, lastKeySz; + + AssertIntEQ(0, ConvertHexToBin(serverKeyEccDer, &eccKey, &eccKeySz, + serverKeyRsaDer, &rsaKey, &rsaKeySz, + NULL, NULL, NULL, NULL, NULL, NULL)); + + AssertNotNull(ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Fail: all NULL/BAD */ + AssertIntNE(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(NULL, NULL, 0, TEST_BAD_FORMAT_NEXT)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Fail: ctx set, others NULL/bad */ + AssertIntNE(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, NULL, 0, TEST_BAD_FORMAT_NEXT)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Fail: ctx set, key set, others bad */ + AssertIntNE(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, + rsaKey, 0, TEST_BAD_FORMAT_NEXT)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Fail: ctx set, keySz set, others NULL/bad */ + AssertIntNE(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, NULL, 1, TEST_BAD_FORMAT_NEXT)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Fail: ctx set, key set, keySz set, format invalid */ + AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, + rsaKey, rsaKeySz, TEST_GOOD_FORMAT_PEM)); + AssertNull(ctx->privateKey); + AssertIntEQ(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + + /* Pass */ + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, eccKey, eccKeySz, + TEST_GOOD_FORMAT_ASN1)); + AssertNotNull(ctx->privateKey); + AssertIntNE(0, ctx->privateKeySz); + AssertIntEQ(ECC_SECP256R1, ctx->useEcc); + lastKey = ctx->privateKey; + lastKeySz = ctx->privateKeySz; + + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, rsaKey, rsaKeySz, + TEST_GOOD_FORMAT_ASN1)); + AssertNotNull(ctx->privateKey); + AssertIntNE(0, ctx->privateKeySz); + AssertIntEQ(0, ctx->useEcc); + AssertIntEQ(0, (lastKey == ctx->privateKey)); + AssertIntNE(lastKeySz, ctx->privateKeySz); + + wolfSSH_CTX_free(ctx); + FreeBins(eccKey, rsaKey, NULL, NULL); +#endif /* WOLFSSH_NO_SERVER */ +} + + #ifdef WOLFSSH_SCP static int my_ScpRecv(WOLFSSH* ssh, int state, const char* basePath, const char* fileName, int fileMode, word64 mTime, word64 aTime, @@ -336,6 +631,7 @@ int main(void) test_wolfSSH_set_fd(); test_wolfSSH_SetUsername(); test_wolfSSH_ConvertConsole(); + test_wolfSSH_CTX_UsePrivateKey_buffer(); /* SCP tests */ test_wolfSSH_SCP_CB(); diff --git a/tests/include.am b/tests/include.am index 4f1b880..cdef8b9 100644 --- a/tests/include.am +++ b/tests/include.am @@ -9,11 +9,23 @@ noinst_PROGRAMS += tests/unit.test tests/api.test \ tests_unit_test_SOURCES = tests/unit.c tests_unit_test_CPPFLAGS = -DNO_MAIN_DRIVER +if BUILD_SCP +tests_unit_test_CPPFLAGS += -DWOLFSSH_SCP +endif +if BUILD_SFTP +tests_unit_test_CPPFLAGS += -DWOLFSSH_SFTP +endif tests_unit_test_LDADD = src/libwolfssh.la tests_unit_test_DEPENDENCIES = src/libwolfssh.la tests_api_test_SOURCES = tests/api.c tests_api_test_CPPFLAGS = -DNO_MAIN_DRIVER +if BUILD_SCP +tests_api_test_CPPFLAGS += -DWOLFSSH_SCP +endif +if BUILD_SFTP +tests_api_test_CPPFLAGS += -DWOLFSSH_SFTP +endif tests_api_test_LDADD = src/libwolfssh.la tests_api_test_DEPENDENCIES = src/libwolfssh.la @@ -23,8 +35,11 @@ tests_testsuite_test_SOURCES = tests/testsuite.c \ examples/client/client.c \ examples/sftpclient/sftpclient.c tests_testsuite_test_CPPFLAGS = -DNO_MAIN_DRIVER +if BUILD_SCP +tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SCP +endif if BUILD_SFTP -tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SFTP +tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SFTP endif tests_testsuite_test_LDADD = src/libwolfssh.la tests_testsuite_test_DEPENDENCIES = src/libwolfssh.la