From d755132ccf77176fabb28e52377f831ea5a020fd Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 1 Apr 2019 12:17:27 -0700 Subject: [PATCH 1/3] Public key authentication 1. Refactor of the RSA public key and password user auth code. 2. In the userauth code remove some usused variable names or use some orphaned variables. 3. Fix the sizes used for calculating the buffer size for ECC public keys. 4. Add in the length of the ECDSA signature wrapping the set r,s. 5. Return the public key rejected error code from DoUserAuthRequestPublicKey when the callback returns invalid public key. --- examples/client/client.c | 50 +-- examples/sftpclient/sftpclient.c | 213 +++++++++++-- src/internal.c | 532 +++++++++++++++++++++++++++++-- src/ssh.c | 2 +- wolfssh/internal.h | 2 +- wolfssh/ssh.h | 20 +- 6 files changed, 728 insertions(+), 91 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index ad8a262..b4e9e05 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -154,33 +154,37 @@ static int wsUserAuth(byte authType, word32 passwordSz = 0; int ret = WOLFSSH_USERAUTH_SUCCESS; - (void)authType; - if (defaultPassword != NULL) { - passwordSz = (word32)strlen(defaultPassword); - memcpy(userPassword, defaultPassword, passwordSz); - } - else { - printf("Password: "); - SetEcho(0); - if (fgets((char*)userPassword, sizeof(userPassword), stdin) == NULL) { - printf("Getting password failed.\n"); - ret = WOLFSSH_USERAUTH_FAILURE; + if (authType == WOLFSSH_USERAUTH_PASSWORD) { + if (defaultPassword != NULL) { + passwordSz = (word32)strlen(defaultPassword); + memcpy(userPassword, defaultPassword, passwordSz); } else { - char* c = strpbrk((char*)userPassword, "\r\n");; - if (c != NULL) - *c = '\0'; + printf("Password: "); + SetEcho(0); + if (fgets((char*)userPassword, sizeof(userPassword), stdin) == NULL) { + printf("Getting password failed.\n"); + ret = WOLFSSH_USERAUTH_FAILURE; + } + else { + char* c = strpbrk((char*)userPassword, "\r\n");; + if (c != NULL) + *c = '\0'; + } + passwordSz = (word32)strlen((const char*)userPassword); + SetEcho(1); + #ifdef USE_WINDOWS_API + printf("\r\n"); + #endif } - passwordSz = (word32)strlen((const char*)userPassword); - SetEcho(1); -#ifdef USE_WINDOWS_API - printf("\r\n"); -#endif - } - if (ret == WOLFSSH_USERAUTH_SUCCESS) { - authData->sf.password.password = userPassword; - authData->sf.password.passwordSz = passwordSz; + if (ret == WOLFSSH_USERAUTH_SUCCESS) { + authData->sf.password.password = userPassword; + authData->sf.password.passwordSz = passwordSz; + } + } + else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { + fprintf(stderr, "username = %p\n", authData->username); } return ret; diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 98a7cdd..640c3cc 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "examples/sftpclient/sftpclient.h" #ifndef USE_WINDOWS_API #include @@ -285,42 +286,202 @@ static void ShowUsage(void) byte userPassword[256]; +byte userPublicKeyType[32]; +byte userPublicKey[512]; +word32 userPublicKeySz; + +const char hanselPublicRsa[] = + "AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho" + "MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G" + "p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj" + "nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW" + "NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE" + "nIf7dO0B8EblgWt+ud+JI8wrAhfE4x"; + +const byte hanselPrivateRsa[] = { + 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xbd, 0x3f, 0x76, 0x45, 0xa3, 0x03, 0xac, 0x38, 0xd5, 0xc7, 0x0f, 0x93, + 0x30, 0x5a, 0x20, 0x9c, 0x89, 0x7c, 0xad, 0x05, 0x16, 0x46, 0x86, 0x83, + 0x0d, 0x8a, 0x2b, 0x16, 0x4a, 0x05, 0x2c, 0xe4, 0x77, 0x47, 0x70, 0x00, + 0xae, 0x1d, 0x83, 0xe2, 0xd9, 0x6e, 0x99, 0xd4, 0xf0, 0x45, 0x98, 0x15, + 0x93, 0xf6, 0x87, 0x4e, 0xac, 0x64, 0x63, 0xa1, 0x95, 0xc9, 0x7c, 0x30, + 0xe8, 0x3e, 0x2f, 0xa3, 0xf1, 0x24, 0x9f, 0x0c, 0x6b, 0x1c, 0xfe, 0x1b, + 0x02, 0x99, 0xcd, 0xc6, 0xa7, 0x6c, 0x84, 0x85, 0x46, 0x54, 0x12, 0x40, + 0xe1, 0xb4, 0xe5, 0xf2, 0xaa, 0x39, 0xec, 0xd6, 0x27, 0x24, 0x0b, 0xd1, + 0xa1, 0xe2, 0xef, 0x34, 0x69, 0x25, 0x6d, 0xc0, 0x74, 0x67, 0x25, 0x98, + 0x7d, 0xc4, 0xf8, 0x52, 0xab, 0x9b, 0x4b, 0x3a, 0x12, 0x1d, 0xe1, 0xe3, + 0xfa, 0xd6, 0xcf, 0x9a, 0xe6, 0x9c, 0x23, 0x4e, 0x39, 0xc4, 0x84, 0x16, + 0x88, 0x3d, 0x42, 0x4e, 0xd8, 0x2f, 0xcc, 0xd2, 0x91, 0x67, 0x9d, 0xb6, + 0x71, 0x2a, 0x02, 0x65, 0x5f, 0xbb, 0x75, 0x0e, 0x8c, 0xbb, 0x87, 0x97, + 0x97, 0xc6, 0xf8, 0xb2, 0x98, 0xe2, 0x2f, 0x68, 0x26, 0x4a, 0x53, 0xec, + 0x79, 0x3a, 0x8a, 0x5f, 0xcc, 0xcf, 0xf0, 0x16, 0x47, 0xb2, 0xd0, 0x43, + 0xd6, 0x36, 0x6c, 0xc8, 0xe7, 0x2f, 0xfe, 0xa7, 0x35, 0x39, 0x69, 0xfb, + 0x1d, 0x78, 0x45, 0x9d, 0x89, 0x00, 0xc8, 0x41, 0xcf, 0x34, 0x1f, 0xa3, + 0xf3, 0xf1, 0xfb, 0x28, 0x14, 0xfb, 0xd8, 0x48, 0x6f, 0xac, 0xe3, 0xfc, + 0x33, 0xd1, 0xdb, 0xae, 0xef, 0x27, 0x9e, 0x57, 0x56, 0x29, 0xa2, 0x1a, + 0x3a, 0xe5, 0x9a, 0xfe, 0xa4, 0x49, 0xc8, 0x7f, 0xb7, 0x4e, 0xd0, 0x1f, + 0x04, 0x6e, 0x58, 0x16, 0xb7, 0xeb, 0x9d, 0xf8, 0x92, 0x3c, 0xc2, 0xb0, + 0x21, 0x7c, 0x4e, 0x31, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, + 0x01, 0x00, 0x8d, 0xa4, 0x61, 0x06, 0x2f, 0xc3, 0x40, 0xf4, 0x6c, 0xf4, + 0x87, 0x30, 0xb8, 0x00, 0xcc, 0xe5, 0xbc, 0x75, 0x87, 0x1e, 0x06, 0x95, + 0x14, 0x7a, 0x23, 0xf9, 0x24, 0xd4, 0x92, 0xe4, 0x1a, 0xbc, 0x88, 0x95, + 0xfc, 0x3b, 0x56, 0x16, 0x1b, 0x2e, 0xff, 0x64, 0x2b, 0x58, 0xd7, 0xd8, + 0x8e, 0xc2, 0x9f, 0xb2, 0xe5, 0x84, 0xb9, 0xbc, 0x8d, 0x61, 0x54, 0x35, + 0xb0, 0x70, 0xfe, 0x72, 0x04, 0xc0, 0x24, 0x6d, 0x2f, 0x69, 0x61, 0x06, + 0x1b, 0x1d, 0xe6, 0x2d, 0x6d, 0x79, 0x60, 0xb7, 0xf4, 0xdb, 0xb7, 0x4e, + 0x97, 0x36, 0xde, 0x77, 0xc1, 0x9f, 0x85, 0x4e, 0xc3, 0x77, 0x69, 0x66, + 0x2e, 0x3e, 0x61, 0x76, 0xf3, 0x67, 0xfb, 0xc6, 0x9a, 0xc5, 0x6f, 0x99, + 0xff, 0xe6, 0x89, 0x43, 0x92, 0x44, 0x75, 0xd2, 0x4e, 0x54, 0x91, 0x58, + 0xb2, 0x48, 0x2a, 0xe6, 0xfa, 0x0d, 0x4a, 0xca, 0xd4, 0x14, 0x9e, 0xf6, + 0x27, 0x67, 0xb7, 0x25, 0x7a, 0x43, 0xbb, 0x2b, 0x67, 0xd1, 0xfe, 0xd1, + 0x68, 0x23, 0x06, 0x30, 0x7c, 0xbf, 0x60, 0x49, 0xde, 0xcc, 0x7e, 0x26, + 0x5a, 0x3b, 0xfe, 0xa6, 0xa6, 0xe7, 0xa8, 0xdd, 0xac, 0xb9, 0xaf, 0x82, + 0x9a, 0x3a, 0x41, 0x7e, 0x61, 0x21, 0x37, 0xa3, 0x08, 0xe4, 0xc4, 0xbc, + 0x11, 0xf5, 0x3b, 0x8e, 0x4d, 0x51, 0xf3, 0xbd, 0xda, 0xba, 0xb2, 0xc5, + 0xee, 0xfb, 0xcf, 0xdf, 0x83, 0xa1, 0x82, 0x01, 0xe1, 0x51, 0x9d, 0x07, + 0x5a, 0x5d, 0xd8, 0xc7, 0x5b, 0x3f, 0x97, 0x13, 0x6a, 0x4d, 0x1e, 0x8d, + 0x39, 0xac, 0x40, 0x95, 0x82, 0x6c, 0xa2, 0xa1, 0xcc, 0x8a, 0x9b, 0x21, + 0x32, 0x3a, 0x58, 0xcc, 0xe7, 0x2d, 0x1a, 0x79, 0xa4, 0x31, 0x50, 0xb1, + 0x4b, 0x76, 0x23, 0x1b, 0xb3, 0x40, 0x3d, 0x3d, 0x72, 0x72, 0x32, 0xec, + 0x5f, 0x38, 0xb5, 0x8d, 0xb2, 0x8d, 0x02, 0x81, 0x81, 0x00, 0xed, 0x5a, + 0x7e, 0x8e, 0xa1, 0x62, 0x7d, 0x26, 0x5c, 0x78, 0xc4, 0x87, 0x71, 0xc9, + 0x41, 0x57, 0x77, 0x94, 0x93, 0x93, 0x26, 0x78, 0xc8, 0xa3, 0x15, 0xbd, + 0x59, 0xcb, 0x1b, 0xb4, 0xb2, 0x6b, 0x0f, 0xe7, 0x80, 0xf2, 0xfa, 0xfc, + 0x8e, 0x32, 0xa9, 0x1b, 0x1e, 0x7f, 0xe1, 0x26, 0xef, 0x00, 0x25, 0xd8, + 0xdd, 0xc9, 0x1a, 0x23, 0x00, 0x26, 0x3b, 0x46, 0x23, 0xc0, 0x50, 0xe7, + 0xce, 0x62, 0xb2, 0x36, 0xb2, 0x98, 0x09, 0x16, 0x34, 0x18, 0x9e, 0x46, + 0xbc, 0xaf, 0x2c, 0x28, 0x94, 0x2f, 0xe0, 0x5d, 0xc9, 0xb2, 0xc8, 0xfb, + 0x5d, 0x13, 0xd5, 0x36, 0xaa, 0x15, 0x0f, 0x89, 0xa5, 0x16, 0x59, 0x5d, + 0x22, 0x74, 0xa4, 0x47, 0x5d, 0xfa, 0xfb, 0x0c, 0x5e, 0x80, 0xbf, 0x0f, + 0xc2, 0x9c, 0x95, 0x0f, 0xe7, 0xaa, 0x7f, 0x16, 0x1b, 0xd4, 0xdb, 0x38, + 0x7d, 0x58, 0x2e, 0x57, 0x78, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcc, 0x1d, + 0x7f, 0x74, 0x36, 0x6d, 0xb4, 0x92, 0x25, 0x62, 0xc5, 0x50, 0xb0, 0x5c, + 0xa1, 0xda, 0xf3, 0xb2, 0xfd, 0x1e, 0x98, 0x0d, 0x8b, 0x05, 0x69, 0x60, + 0x8e, 0x5e, 0xd2, 0x89, 0x90, 0x4a, 0x0d, 0x46, 0x7e, 0xe2, 0x54, 0x69, + 0xae, 0x16, 0xe6, 0xcb, 0xd5, 0xbd, 0x7b, 0x30, 0x2b, 0x7b, 0x5c, 0xee, + 0x93, 0x12, 0xcf, 0x63, 0x89, 0x9c, 0x3d, 0xc8, 0x2d, 0xe4, 0x7a, 0x61, + 0x09, 0x5e, 0x80, 0xfb, 0x3c, 0x03, 0xb3, 0x73, 0xd6, 0x98, 0xd0, 0x84, + 0x0c, 0x59, 0x9f, 0x4e, 0x80, 0xf3, 0x46, 0xed, 0x03, 0x9d, 0xd5, 0xdc, + 0x8b, 0xe7, 0xb1, 0xe8, 0xaa, 0x57, 0xdc, 0xd1, 0x41, 0x55, 0x07, 0xc7, + 0xdf, 0x67, 0x3c, 0x72, 0x78, 0xb0, 0x60, 0x8f, 0x85, 0xa1, 0x90, 0x99, + 0x0c, 0xa5, 0x67, 0xab, 0xf0, 0xb6, 0x74, 0x90, 0x03, 0x55, 0x7b, 0x5e, + 0xcc, 0xc5, 0xbf, 0xde, 0xa7, 0x9f, 0x02, 0x81, 0x80, 0x40, 0x81, 0x6e, + 0x91, 0xae, 0xd4, 0x88, 0x74, 0xab, 0x7e, 0xfa, 0xd2, 0x60, 0x9f, 0x34, + 0x8d, 0xe3, 0xe6, 0xd2, 0x30, 0x94, 0xad, 0x10, 0xc2, 0x19, 0xbf, 0x6b, + 0x2e, 0xe2, 0xe9, 0xb9, 0xef, 0x94, 0xd3, 0xf2, 0xdc, 0x96, 0x4f, 0x9b, + 0x09, 0xb3, 0xa1, 0xb6, 0x29, 0x44, 0xf4, 0x82, 0xd1, 0xc4, 0x77, 0x6a, + 0xd7, 0x23, 0xae, 0x4d, 0x75, 0x16, 0x78, 0xda, 0x70, 0x82, 0xcc, 0x6c, + 0xef, 0xaf, 0xc5, 0x63, 0xc6, 0x23, 0xfa, 0x0f, 0xd0, 0x7c, 0xfb, 0x76, + 0x7e, 0x18, 0xff, 0x32, 0x3e, 0xcc, 0xb8, 0x50, 0x7f, 0xb1, 0x55, 0x77, + 0x17, 0x53, 0xc3, 0xd6, 0x77, 0x80, 0xd0, 0x84, 0xb8, 0x4d, 0x33, 0x1d, + 0x91, 0x1b, 0xb0, 0x75, 0x9f, 0x27, 0x29, 0x56, 0x69, 0xa1, 0x03, 0x54, + 0x7d, 0x9f, 0x99, 0x41, 0xf9, 0xb9, 0x2e, 0x36, 0x04, 0x24, 0x4b, 0xf6, + 0xec, 0xc7, 0x33, 0x68, 0x6b, 0x02, 0x81, 0x80, 0x60, 0x35, 0xcb, 0x3c, + 0xd0, 0xe6, 0xf7, 0x05, 0x28, 0x20, 0x1d, 0x57, 0x82, 0x39, 0xb7, 0x85, + 0x07, 0xf7, 0xa7, 0x3d, 0xc3, 0x78, 0x26, 0xbe, 0x3f, 0x44, 0x66, 0xf7, + 0x25, 0x0f, 0xf8, 0x76, 0x1f, 0x39, 0xca, 0x57, 0x0e, 0x68, 0xdd, 0xc9, + 0x27, 0xb2, 0x8e, 0xa6, 0x08, 0xa9, 0xd4, 0xe5, 0x0a, 0x11, 0xde, 0x3b, + 0x30, 0x8b, 0xff, 0x72, 0x28, 0xe0, 0xf1, 0x58, 0xcf, 0xa2, 0x6b, 0x93, + 0x23, 0x02, 0xc8, 0xf0, 0x09, 0xa7, 0x21, 0x50, 0xd8, 0x80, 0x55, 0x7d, + 0xed, 0x0c, 0x48, 0xd5, 0xe2, 0xe9, 0x97, 0x19, 0xcf, 0x93, 0x6c, 0x52, + 0xa2, 0xd6, 0x43, 0x6c, 0xb4, 0xc5, 0xe1, 0xa0, 0x9d, 0xd1, 0x45, 0x69, + 0x58, 0xe1, 0xb0, 0x27, 0x9a, 0xec, 0x2b, 0x95, 0xd3, 0x1d, 0x81, 0x0b, + 0x7a, 0x09, 0x5e, 0xa5, 0xf1, 0xdd, 0x6b, 0xe4, 0xe0, 0x08, 0xf8, 0x46, + 0x81, 0xc1, 0x06, 0x8b, 0x02, 0x81, 0x80, 0x00, 0xf6, 0xf2, 0xeb, 0x25, + 0xba, 0x78, 0x04, 0xad, 0x0e, 0x0d, 0x2e, 0xa7, 0x69, 0xd6, 0x57, 0xe6, + 0x36, 0x32, 0x50, 0xd2, 0xf2, 0xeb, 0xad, 0x31, 0x46, 0x65, 0xc0, 0x07, + 0x97, 0x83, 0x6c, 0x66, 0x27, 0x3e, 0x94, 0x2c, 0x05, 0x01, 0x5f, 0x5c, + 0xe0, 0x31, 0x30, 0xec, 0x61, 0xd2, 0x74, 0x35, 0xb7, 0x9f, 0x38, 0xe7, + 0x8e, 0x67, 0xb1, 0x50, 0x08, 0x68, 0xce, 0xcf, 0xd8, 0xee, 0x88, 0xfd, + 0x5d, 0xc4, 0xcd, 0xe2, 0x86, 0x3d, 0x4a, 0x0e, 0x04, 0x7f, 0xee, 0x8a, + 0xe8, 0x9b, 0x16, 0xa1, 0xfc, 0x09, 0x82, 0xe2, 0x62, 0x03, 0x3c, 0xe8, + 0x25, 0x7f, 0x3c, 0x9a, 0xaa, 0x83, 0xf8, 0xd8, 0x93, 0xd1, 0x54, 0xf9, + 0xce, 0xb4, 0xfa, 0x35, 0x36, 0xcc, 0x18, 0x54, 0xaa, 0xf2, 0x90, 0xb7, + 0x7c, 0x97, 0x0b, 0x27, 0x2f, 0xae, 0xfc, 0xc3, 0x93, 0xaf, 0x1a, 0x75, + 0xec, 0x18, 0xdb +}; + +unsigned int hanselPrivateRsaSz = 1191; + + +const char hanselPublicEcc[] = + "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNkI5JTP6D0lF42tbx" + "X19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25qUzgDtH7oyaQROUnNvk="; + +const byte hanselPrivateEcc[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x03, 0x6e, 0x17, 0xd3, 0xb9, + 0xb8, 0xab, 0xc8, 0xf9, 0x1f, 0xf1, 0x2d, 0x44, 0x4c, 0x3b, 0x12, 0xb1, + 0xa4, 0x77, 0xd8, 0xed, 0x0e, 0x6a, 0xbe, 0x60, 0xc2, 0xf6, 0x8b, 0xe7, + 0xd3, 0x87, 0x83, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xd9, 0x08, 0xe4, + 0x94, 0xcf, 0xe8, 0x3d, 0x25, 0x17, 0x8d, 0xad, 0x6f, 0x15, 0xf5, 0xf5, + 0xc1, 0x3c, 0xee, 0x1c, 0xed, 0x51, 0x2e, 0x85, 0x48, 0x3a, 0x06, 0xbc, + 0xf7, 0xe2, 0x53, 0x40, 0xa0, 0x78, 0xd4, 0x9b, 0x23, 0xe6, 0x85, 0x74, + 0xa2, 0x33, 0x4c, 0xfe, 0x42, 0x40, 0x42, 0x52, 0xbe, 0x6d, 0xb9, 0xa9, + 0x4c, 0xe0, 0x0e, 0xd1, 0xfb, 0xa3, 0x26, 0x90, 0x44, 0xe5, 0x27, 0x36, + 0xf9 +}; + +unsigned int hanselPrivateEccSz = 121; + static int wsUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) { - const char* defaultPassword = (const char*)ctx; - word32 passwordSz; - int ret = WOLFSSH_USERAUTH_SUCCESS; + int ret = WOLFSSH_USERAUTH_INVALID_AUTHTYPE; - (void)authType; - if (defaultPassword != NULL) { - passwordSz = (word32)strlen(defaultPassword); - memcpy(userPassword, defaultPassword, passwordSz); - } - else { - printf("Password: "); - SetEcho(0); - if (WFGETS((char*)userPassword, sizeof(userPassword), stdin) == NULL) { - printf("Getting password failed.\n"); - ret = WOLFSSH_USERAUTH_FAILURE; + if (authType == WOLFSSH_USERAUTH_PASSWORD) { + const char* defaultPassword = (const char*)ctx; + word32 passwordSz; + + ret = WOLFSSH_USERAUTH_SUCCESS; + if (defaultPassword != NULL) { + passwordSz = (word32)strlen(defaultPassword); + memcpy(userPassword, defaultPassword, passwordSz); } else { - char* c = strpbrk((char*)userPassword, "\r\n");; - if (c != NULL) - *c = '\0'; + printf("Password: "); + SetEcho(0); + if (WFGETS((char*)userPassword, sizeof(userPassword), stdin) == NULL) { + printf("Getting password failed.\n"); + ret = WOLFSSH_USERAUTH_FAILURE; + } + else { + char* c = strpbrk((char*)userPassword, "\r\n"); + if (c != NULL) + *c = '\0'; + } + passwordSz = (word32)strlen((const char*)userPassword); + SetEcho(1); + #ifdef USE_WINDOWS_API + printf("\r\n"); + #endif } - passwordSz = (word32)strlen((const char*)userPassword); - SetEcho(1); -#ifdef USE_WINDOWS_API - printf("\r\n"); -#endif - } - if (ret == WOLFSSH_USERAUTH_SUCCESS) { - authData->sf.password.password = userPassword; - authData->sf.password.passwordSz = passwordSz; + if (ret == WOLFSSH_USERAUTH_SUCCESS) { + authData->sf.password.password = userPassword; + authData->sf.password.passwordSz = passwordSz; + } + } + else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { + WS_UserAuthData_PublicKey* pk = &authData->sf.publicKey; + + userPublicKeySz = (word32)sizeof(userPublicKey); + + Base64_Decode((byte*)hanselPublicRsa, + (word32)WSTRLEN(hanselPublicRsa), + (byte*)userPublicKey, &userPublicKeySz); + + strncpy((char*)userPublicKeyType, "ssh-rsa", + sizeof(userPublicKeyType)); + pk->publicKeyType = userPublicKeyType; + pk->publicKeyTypeSz = (word32)WSTRLEN((char*)userPublicKeyType); + pk->publicKey = userPublicKey; + pk->publicKeySz = userPublicKeySz; + pk->privateKey = hanselPrivateRsa; + pk->privateKeySz = hanselPrivateRsaSz; + ret = WOLFSSH_USERAUTH_SUCCESS; } return ret; diff --git a/src/internal.c b/src/internal.c index 66920f2..2158b1b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1546,7 +1546,7 @@ static int GetBoolean(byte* v, byte* buf, word32 len, word32* idx) } -static int GetUint32(word32* v, byte* buf, word32 len, word32* idx) +static int GetUint32(word32* v, const byte* buf, word32 len, word32* idx) { int result = WS_BUFFER_E; @@ -3227,11 +3227,11 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, enum wc_HashType enmhashId = (enum wc_HashType)hashId; byte checkDigest[MAX_ENCODED_SIG_SZ]; int checkDigestSz; - byte* publicKeyType; + const byte* publicKeyType; word32 publicKeyTypeSz = 0; - byte* n; + const byte* n; word32 nSz = 0; - byte* e = NULL; + const byte* e = NULL; word32 eSz = 0; word32 i = 0; int ret = WS_SUCCESS; @@ -3345,12 +3345,12 @@ static int DoUserAuthRequestEcc(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, byte hashId, byte* digest, word32 digestSz) { ecc_key key; - byte* publicKeyType; + const byte* publicKeyType; word32 publicKeyTypeSz = 0; - byte* curveName; + const byte* curveName; word32 curveNameSz = 0; mp_int r, s; - byte* q = NULL; + const byte* q = NULL; word32 sz, qSz; word32 i = 0; int ret = WS_SUCCESS; @@ -3534,6 +3534,10 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, WLOG(WS_LOG_DEBUG, "DUARPK: callback result = %d", ret); if (ret == WOLFSSH_USERAUTH_SUCCESS) ret = WS_SUCCESS; + else if (ret == WOLFSSH_USERAUTH_INVALID_PUBLICKEY) { + WLOG(WS_LOG_DEBUG, "DUARPK: client key rejected"); + ret = WS_PUBKEY_REJECTED_E; + } else { ret = SendUserAuthFailure(ssh, 0); authFailure = 1; @@ -3699,7 +3703,7 @@ static int DoUserAuthFailure(WOLFSSH* ssh, byte authList[3]; /* Should only ever be password, publickey, hostname */ word32 authListSz = 3; byte partialSuccess; - byte authId = ID_USERAUTH_PASSWORD; + byte authId = ID_USERAUTH_PUBLICKEY; int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering DoUserAuthFailure()"); @@ -3714,7 +3718,7 @@ static int DoUserAuthFailure(WOLFSSH* ssh, ret = GetBoolean(&partialSuccess, buf, len, idx); if (ret == WS_SUCCESS) - ret = SendUserAuthRequest(ssh, authId); + ret = SendUserAuthRequest(ssh, authId, 0); WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthFailure(), ret = %d", ret); return ret; @@ -6697,11 +6701,441 @@ int SendServiceAccept(WOLFSSH* ssh, byte serviceId) } -static const char cannedAuths[] = "publickey,password"; +typedef struct WS_KeySignature { + byte keySigId; + word32 sigSz; + const char *name; + word32 nameSz; + union { + struct { + RsaKey key; + byte e[256]; + word32 eSz; + byte ePad; + byte n[256]; + word32 nSz; + byte nPad; + } rsa; + struct { + ecc_key key; + word32 keyBlobSz; + const char *keyBlobName; + word32 keyBlobNameSz; + byte q[256]; + word32 qSz; + byte qPad; + const char *primeName; + word32 primeNameSz; + } ecc; + } ks; +} WS_KeySignature; + + +static const char cannedAuths[] = "publickey"; static const word32 cannedAuthsSz = sizeof(cannedAuths) - 1; -int SendUserAuthRequest(WOLFSSH* ssh, byte authId) +/* Updates the payload size, and maybe loads keys. */ +static int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz, + const WS_UserAuthData* authData) +{ + int ret = WS_SUCCESS; + + if (ssh == NULL || payloadSz == NULL || authData == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + *payloadSz += BOOLEAN_SZ + LENGTH_SZ + + authData->sf.password.passwordSz; + + return ret; +} + + +static int BuildUserAuthRequestPassword(WOLFSSH* ssh, + byte* output, word32* idx, + const WS_UserAuthData* authData) +{ + int ret = WS_SUCCESS; + word32 begin; + + if (ssh == NULL || output == NULL || idx == NULL || authData == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + begin = *idx; + output[begin++] = 0; /* Boolean "FALSE" for password change */ + c32toa(authData->sf.password.passwordSz, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, authData->sf.password.password, + authData->sf.password.passwordSz); + begin += authData->sf.password.passwordSz; + *idx = begin; + } + + return ret; +} + + +static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz, + const WS_UserAuthData* authData, WS_KeySignature* keySig) +{ + int ret = WS_SUCCESS; + + if (ssh == NULL || payloadSz == NULL || authData == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + ret = wc_InitRsaKey(&keySig->ks.rsa.key, NULL); + + if (ret == WS_SUCCESS) { + word32 idx = 0; + ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey, + &idx, &keySig->ks.rsa.key, + authData->sf.publicKey.privateKeySz); + } + + if (ret == WS_SUCCESS) { + if (authData->sf.publicKey.hasSignature) { + int sigSz = wc_RsaEncryptSize(&keySig->ks.rsa.key); + + if (sigSz >= 0) { + *payloadSz += (LENGTH_SZ * 3) + (word32)sigSz + + authData->sf.publicKey.publicKeyTypeSz; + keySig->sigSz = sigSz; + } + else + ret = sigSz; + } + } + + return ret; +} + + +static int BuildUserAuthRequestRsa(WOLFSSH* ssh, + byte* output, word32* idx, + const WS_UserAuthData* authData, + const byte* sigStart, word32 sigStartIdx, + WS_KeySignature* keySig) +{ + wc_HashAlg hash; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 digestSz; + word32 begin; + enum wc_HashType hashId = WC_HASH_TYPE_SHA; + int ret = WS_SUCCESS; + + if (ssh == NULL || output == NULL || idx == NULL || authData == NULL || + sigStart == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + begin = *idx; + + if (ret == WS_SUCCESS) { + hashId = HashForId(keySig->keySigId); + WMEMSET(digest, 0, sizeof(digest)); + digestSz = wc_HashGetDigestSize(hashId); + ret = wc_HashInit(&hash, hashId); + } + + if (ret == WS_SUCCESS) { + c32toa(ssh->sessionIdSz, digest); + ret = wc_HashUpdate(&hash, hashId, digest, UINT32_SZ); + } + + if (ret == WS_SUCCESS) + ret = wc_HashUpdate(&hash, hashId, + ssh->sessionId, ssh->sessionIdSz); + + if (ret == WS_SUCCESS) + ret = wc_HashUpdate(&hash, hashId, + sigStart, begin - sigStartIdx); + + if (ret == WS_SUCCESS) + ret = wc_HashFinal(&hash, hashId, digest); + + if (ret == WS_SUCCESS) { + byte encDigest[MAX_ENCODED_SIG_SZ]; + int encDigestSz; + + c32toa(keySig->sigSz + 7 + LENGTH_SZ * 2, output + begin); + begin += LENGTH_SZ; + c32toa(7, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, "ssh-rsa", 7); + begin += 7; + c32toa(keySig->sigSz, output + begin); + begin += LENGTH_SZ; + encDigestSz = wc_EncodeSignature(encDigest, digest, digestSz, + wc_HashGetOID(hashId)); + if (encDigestSz <= 0) { + WLOG(WS_LOG_DEBUG, "SUAR: Bad Encode Sig"); + ret = WS_CRYPTO_FAILED; + } + else { + int sigSz; + WLOG(WS_LOG_INFO, "Signing hash with RSA."); + sigSz = wc_RsaSSL_Sign(encDigest, encDigestSz, + output + begin, keySig->sigSz, + &keySig->ks.rsa.key, ssh->rng); + if (sigSz <= 0 || (word32)sigSz != keySig->sigSz) { + WLOG(WS_LOG_DEBUG, "SUAR: Bad RSA Sign"); + ret = WS_RSA_E; + } + } + + if (ret == WS_SUCCESS) { + begin += keySig->sigSz; + *idx = begin; + } + } + + return ret; +} + + +static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz, + const WS_UserAuthData* authData, WS_KeySignature* keySig) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering PrepareUserAuthRequestEcc()"); + if (ssh == NULL || payloadSz == NULL || authData == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + ret = wc_ecc_init(&keySig->ks.ecc.key); + + if (ret == WS_SUCCESS) { + word32 idx = 0; + ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey, + &idx, &keySig->ks.ecc.key, + authData->sf.publicKey.privateKeySz); + } + + if (ret == WS_SUCCESS) { + if (authData->sf.publicKey.hasSignature) { + int sigSz = wc_ecc_sig_size(&keySig->ks.ecc.key); + sigSz = 64; + + if (sigSz >= 0) { + *payloadSz += (LENGTH_SZ * 5) + (word32)sigSz + + authData->sf.publicKey.publicKeyTypeSz; + keySig->sigSz = sigSz; + } + else + ret = sigSz; + } + } + + WLOG(WS_LOG_DEBUG, "Leaving PrepareUserAuthRequestEcc(), ret = %d", ret); + return ret; +} + + +static int BuildUserAuthRequestEcc(WOLFSSH* ssh, + byte* output, word32* idx, + const WS_UserAuthData* authData, + const byte* sigStart, word32 sigStartIdx, + WS_KeySignature* keySig) +{ + wc_HashAlg hash; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 digestSz; + word32 begin; + enum wc_HashType hashId = WC_HASH_TYPE_SHA; + int ret = WS_SUCCESS; + byte* r; + byte* s; + byte sig[512]; + word32 sigSz = sizeof(sig), rSz, sSz; + + if (ssh == NULL || output == NULL || idx == NULL || authData == NULL || + sigStart == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + begin = *idx; + + if (ret == WS_SUCCESS) { + hashId = HashForId(keySig->keySigId); + WMEMSET(digest, 0, sizeof(digest)); + digestSz = wc_HashGetDigestSize(hashId); + ret = wc_HashInit(&hash, hashId); + } + + if (ret == WS_SUCCESS) { + c32toa(ssh->sessionIdSz, digest); + ret = wc_HashUpdate(&hash, hashId, digest, UINT32_SZ); + } + + if (ret == WS_SUCCESS) + ret = wc_HashUpdate(&hash, hashId, + ssh->sessionId, ssh->sessionIdSz); + + if (ret == WS_SUCCESS) + ret = wc_HashUpdate(&hash, hashId, + sigStart, begin - sigStartIdx); + + if (ret == WS_SUCCESS) + ret = wc_HashFinal(&hash, hashId, digest); + + if (ret == WS_SUCCESS) { + WLOG(WS_LOG_INFO, "Signing hash with ECDSA."); + ret = wc_ecc_sign_hash(digest, digestSz, sig, &sigSz, + ssh->rng, &keySig->ks.ecc.key); + if (ret != WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "SUAR: Bad ECC Sign"); + ret = WS_ECC_E; + } + } + + if (ret == WS_SUCCESS) { + rSz = sSz = sizeof(sig) / 2; + r = sig; + s = sig + rSz; + ret = wc_ecc_sig_to_rs(sig, sigSz, r, &rSz, s, &sSz); + } + + if (ret == WS_SUCCESS) { + byte rPad = (r[0] & 0x80) ? 1 : 0; + byte sPad = (s[0] & 0x80) ? 1 : 0; + + rPad = 0; sPad = 0; + c32toa(rSz + rPad + sSz + sPad + + cannedKeyAlgoEcc256NamesSz + LENGTH_SZ * 4, + output + begin); + begin += LENGTH_SZ; + + c32toa(cannedKeyAlgoEcc256NamesSz, output + begin); + begin += LENGTH_SZ; + + WMEMCPY(output + begin, cannedKeyAlgoEcc256Names, + cannedKeyAlgoEcc256NamesSz); + begin += cannedKeyAlgoEcc256NamesSz; + + c32toa(rSz + rPad + sSz + sPad, output + begin); + begin += LENGTH_SZ; + + c32toa(rSz + rPad, output + begin); + begin += LENGTH_SZ; + + if (rPad) + output[begin++] = 0; + + WMEMCPY(output + begin, r, rSz); + begin += rSz; + + c32toa(sSz + sPad, output + begin); + begin += LENGTH_SZ; + + if (sPad) + output[begin++] = 0; + + WMEMCPY(output + begin, s, sSz); + begin += sSz; + } + + if (ret == WS_SUCCESS) + *idx = begin; + + return ret; +} + + +static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz, + const WS_UserAuthData* authData, WS_KeySignature* keySig) +{ + int ret = WS_SUCCESS; + + if (ssh == NULL || payloadSz == NULL || authData == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + keySig->keySigId = NameToId( + (const char*)authData->sf.publicKey.publicKeyType, + authData->sf.publicKey.publicKeyTypeSz); + + if (ret == WS_SUCCESS) { + /* Add the boolean size to the payload, and the lengths of + * the public key algorithm name, and the public key length. */ + *payloadSz += BOOLEAN_SZ + (LENGTH_SZ * 2) + + authData->sf.publicKey.publicKeyTypeSz + + authData->sf.publicKey.publicKeySz; + } + + if (keySig->keySigId == ID_SSH_RSA) + ret = PrepareUserAuthRequestRsa(ssh, payloadSz, authData, keySig); + else if (keySig->keySigId == ID_ECDSA_SHA2_NISTP256 || + keySig->keySigId == ID_ECDSA_SHA2_NISTP384 || + keySig->keySigId == ID_ECDSA_SHA2_NISTP521) + ret = PrepareUserAuthRequestEcc(ssh, payloadSz, authData, keySig); + else + ret = WS_INVALID_ALGO_ID; + + return ret; +} + + +static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh, + byte* output, word32* idx, + const WS_UserAuthData* authData, + const byte* sigStart, word32 sigStartIdx, + WS_KeySignature* keySig) +{ + const WS_UserAuthData_PublicKey* pk; + word32 begin; + int ret = WS_SUCCESS; + + if (ssh == NULL || output == NULL || idx == NULL || authData == NULL || + sigStart == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + begin = *idx; + pk = &authData->sf.publicKey; + output[begin++] = pk->hasSignature; + c32toa(pk->publicKeyTypeSz, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, pk->publicKeyType, pk->publicKeyTypeSz); + begin += pk->publicKeyTypeSz; + c32toa(pk->publicKeySz, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, pk->publicKey, pk->publicKeySz); + begin += pk->publicKeySz; + + if (pk->hasSignature) { + if (keySig->keySigId == ID_SSH_RSA) + ret = BuildUserAuthRequestRsa(ssh, output, &begin, + authData, sigStart, sigStartIdx, keySig); + else if (keySig->keySigId == ID_ECDSA_SHA2_NISTP256 || + keySig->keySigId == ID_ECDSA_SHA2_NISTP384 || + keySig->keySigId == ID_ECDSA_SHA2_NISTP521) + ret = BuildUserAuthRequestEcc(ssh, output, &begin, + authData, sigStart, sigStartIdx, keySig); + } + else + ret = WS_INVALID_ALGO_ID; + + if (ret == WS_SUCCESS) + *idx = begin; + } + + return ret; +} + + +static void CleanupUserAuthRequestPublicKey(WS_KeySignature* keySig) +{ + if (keySig != NULL) { + if (keySig->keySigId == ID_SSH_RSA) + wc_FreeRsaKey(&keySig->ks.rsa.key); + else + wc_ecc_free(&keySig->ks.ecc.key); + } +} + + +int SendUserAuthRequest(WOLFSSH* ssh, byte authId, int addSig) { byte* output; word32 idx; @@ -6712,22 +7146,44 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId) word32 payloadSz; int ret = WS_SUCCESS; WS_UserAuthData authData; + WS_KeySignature keySig; + + (void)addSig; WLOG(WS_LOG_DEBUG, "Entering SendUserAuthRequest()"); if (ssh == NULL) ret = WS_BAD_ARGUMENT; + WMEMSET(&keySig, 0, sizeof(WS_KeySignature)); + if (ret == WS_SUCCESS) { - WMEMSET(&authData, 0, sizeof(WS_UserAuthData)); - if (authId == ID_USERAUTH_PASSWORD && ssh->ctx->userAuthCb != NULL) { - WLOG(WS_LOG_DEBUG, "SUARPW: Calling the userauth callback"); - ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PASSWORD, - &authData, ssh->userAuthCtx); - if (ret != WOLFSSH_USERAUTH_SUCCESS) { - WLOG(WS_LOG_DEBUG, "SUARPW: Couldn't get password"); - ret = WS_FATAL_ERROR; + if (ssh->ctx->userAuthCb != NULL) { + WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback"); + + WMEMSET(&authData, 0, sizeof(authData)); + authData.type = authId; + + if (authId == ID_USERAUTH_PASSWORD) { + ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PASSWORD, + &authData, ssh->userAuthCtx); + if (ret != WOLFSSH_USERAUTH_SUCCESS) { + WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get password"); + ret = WS_FATAL_ERROR; + } } + else if (authId == ID_USERAUTH_PUBLICKEY) { + ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PUBLICKEY, + &authData, ssh->userAuthCtx); + if (ret != WOLFSSH_USERAUTH_SUCCESS) { + WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get key"); + ret = WS_FATAL_ERROR; + } + } + } + else { + WLOG(WS_LOG_DEBUG, "SUAR: No user auth callback"); + ret = WS_FATAL_ERROR; } } @@ -6740,9 +7196,12 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId) payloadSz = MSG_ID_SZ + (LENGTH_SZ * 3) + ssh->userNameSz + serviceNameSz + authNameSz; - if (authId == ID_USERAUTH_PASSWORD) { - payloadSz += BOOLEAN_SZ + LENGTH_SZ + - authData.sf.password.passwordSz; + if (authId == ID_USERAUTH_PASSWORD) + ret = PrepareUserAuthRequestPassword(ssh, &payloadSz, &authData); + else if (authId == ID_USERAUTH_PUBLICKEY) { + authData.sf.publicKey.hasSignature = 1; + ret = PrepareUserAuthRequestPublicKey(ssh, &payloadSz, &authData, + &keySig); } else if (authId != ID_NONE) ret = WS_INVALID_ALGO_ID; @@ -6752,9 +7211,15 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId) ret = PreparePacket(ssh, payloadSz); if (ret == WS_SUCCESS) { + byte* sigStart; + word32 sigStartIdx; + output = ssh->outputBuffer.buffer; idx = ssh->outputBuffer.length; + sigStart = output + idx; + sigStartIdx = idx; + output[idx++] = MSGID_USERAUTH_REQUEST; c32toa(ssh->userNameSz, output + idx); idx += LENGTH_SZ; @@ -6772,19 +7237,24 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId) idx += authNameSz; if (authId == ID_USERAUTH_PASSWORD) { - output[idx++] = 0; /* Boolean "FALSE" for password change */ - c32toa(authData.sf.password.passwordSz, output + idx); - idx += LENGTH_SZ; - WMEMCPY(output + idx, authData.sf.password.password, - authData.sf.password.passwordSz); - idx += authData.sf.password.passwordSz; + (void)sigStart; + (void)sigStartIdx; + + ret = BuildUserAuthRequestPassword(ssh, output, &idx, &authData); } + else if (authId == ID_USERAUTH_PUBLICKEY) + ret = BuildUserAuthRequestPublicKey(ssh, output, &idx, &authData, + sigStart, sigStartIdx, &keySig); - ssh->outputBuffer.length = idx; - - ret = BundlePacket(ssh); + if (ret == WS_SUCCESS) { + ssh->outputBuffer.length = idx; + ret = BundlePacket(ssh); + } } + if (authId == ID_USERAUTH_PUBLICKEY) + CleanupUserAuthRequestPublicKey(&keySig); + if (ret == WS_SUCCESS) ret = wolfSSH_SendPacket(ssh); diff --git a/src/ssh.c b/src/ssh.c index 61c8d9a..3be1fa9 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -636,7 +636,7 @@ int wolfSSH_connect(WOLFSSH* ssh) /* no break */ case CONNECT_SERVER_USERAUTH_REQUEST_DONE: - if ( (ssh->error = SendUserAuthRequest(ssh, ID_NONE)) < + if ( (ssh->error = SendUserAuthRequest(ssh, ID_NONE, 0)) < WS_SUCCESS) { WLOG(WS_LOG_DEBUG, connectError, "SERVER_USERAUTH_REQUEST_DONE", ssh->error); diff --git a/wolfssh/internal.h b/wolfssh/internal.h index a1fa14a..740db27 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -511,7 +511,7 @@ WOLFSSH_LOCAL int SendIgnore(WOLFSSH*, const unsigned char*, word32); WOLFSSH_LOCAL int SendDebug(WOLFSSH*, byte, const char*); WOLFSSH_LOCAL int SendServiceRequest(WOLFSSH*, byte); WOLFSSH_LOCAL int SendServiceAccept(WOLFSSH*, byte); -WOLFSSH_LOCAL int SendUserAuthRequest(WOLFSSH*, byte); +WOLFSSH_LOCAL int SendUserAuthRequest(WOLFSSH*, byte, int); WOLFSSH_LOCAL int SendUserAuthSuccess(WOLFSSH*); WOLFSSH_LOCAL int SendUserAuthFailure(WOLFSSH*, byte); WOLFSSH_LOCAL int SendUserAuthBanner(WOLFSSH*); diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index f5ebc0d..a47e3b3 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -110,32 +110,34 @@ WOLFSSH_API void* wolfSSH_GetIOWriteCtx(WOLFSSH*); /* User Authentication callback */ typedef struct WS_UserAuthData_Password { - byte* password; + const byte* password; word32 passwordSz; /* The following are present for future use. */ byte hasNewPassword; - byte* newPassword; + const byte* newPassword; word32 newPasswordSz; } WS_UserAuthData_Password; typedef struct WS_UserAuthData_PublicKey { - byte* dataToSign; - byte* publicKeyType; + const byte* dataToSign; + const byte* publicKeyType; word32 publicKeyTypeSz; - byte* publicKey; + const byte* publicKey; word32 publicKeySz; + const byte* privateKey; + word32 privateKeySz; byte hasSignature; - byte* signature; + const byte* signature; word32 signatureSz; } WS_UserAuthData_PublicKey; typedef struct WS_UserAuthData { byte type; - byte* username; + const byte* username; word32 usernameSz; - byte* serviceName; + const byte* serviceName; word32 serviceNameSz; - byte* authName; + const byte* authName; word32 authNameSz; union { WS_UserAuthData_Password password; From 56616d3416633fac25c3802b1af715c149d5d220 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 6 Jun 2019 11:59:35 -0700 Subject: [PATCH 2/3] Public key authentication 1. Cleanup some debug printouts. 2. Add option to the echoserver and wolfSFTP client to use ECC keys or RSA keys for user authentication. 3. Add option to the echoserver to use ECC keys for peer authentication. Note, the user authentication type is still hardcoded in the library as password. To use public key, need to update the authId in SendUserAuthFailure(). --- examples/client/client.c | 20 +++++---- examples/echoserver/echoserver.c | 17 +++++--- examples/sftpclient/sftpclient.c | 70 ++++++++++++++++++++++++-------- src/internal.c | 3 +- 4 files changed, 79 insertions(+), 31 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index b4e9e05..9aaf11a 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -184,7 +184,7 @@ static int wsUserAuth(byte authType, } } else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { - fprintf(stderr, "username = %p\n", authData->username); + ret = WOLFSSH_USERAUTH_INVALID_AUTHTYPE; } return ret; @@ -193,10 +193,16 @@ static int wsUserAuth(byte authType, static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) { - printf("Sample public key check callback\n" - " public key = %p\n" - " public key size = %u\n" - " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + #ifdef DEBUG_WOLFSSH + printf("Sample public key check callback\n" + " public key = %p\n" + " public key size = %u\n" + " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + #else + (void)pubKey; + (void)pubKeySz; + (void)ctx; + #endif return 0; } @@ -525,10 +531,8 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) ret = wolfSSH_connect(ssh); else ret = NonBlockSSH_connect(ssh); - if (ret != WS_SUCCESS) { - printf("err = %s\n", wolfSSH_get_error_name(ssh)); + if (ret != WS_SUCCESS) err_sys("Couldn't connect SSH stream."); - } #if !defined(SINGLE_THREADED) && !defined(WOLFSSL_NUCLEUS) if (keepOpen) /* set up for psuedo-terminal */ diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 9acad9f..5b40522 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -720,7 +720,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; word32 threadCount = 0; int multipleConnections = 1; - int useEcc = 0; + int userEcc = 0; + int peerEcc = 0; int ch; word16 port = wolfSshPort; char* readyFile = NULL; @@ -732,7 +733,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) serverArgs->return_code = 0; if (argc > 0) { - while ((ch = mygetopt(argc, argv, "?1d:ep:R:N")) != -1) { + while ((ch = mygetopt(argc, argv, "?1d:eEp:R:N")) != -1) { switch (ch) { case '?' : ShowUsage(); @@ -743,7 +744,11 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) break; case 'e' : - useEcc = 1; + userEcc = 1; + break; + + case 'E': + peerEcc = 1; break; case 'p': @@ -804,7 +809,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) byte buf[SCRATCH_BUFFER_SZ]; word32 bufSz; - bufSz = load_key(useEcc, buf, SCRATCH_BUFFER_SZ); + bufSz = load_key(peerEcc, buf, SCRATCH_BUFFER_SZ); if (bufSz == 0) { fprintf(stderr, "Couldn't load key file.\n"); exit(EXIT_FAILURE); @@ -820,8 +825,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) buf[bufSz] = 0; LoadPasswordBuffer(buf, bufSz, &pwMapList); - bufName = useEcc ? samplePublicKeyEccBuffer : - samplePublicKeyRsaBuffer; + bufName = userEcc ? samplePublicKeyEccBuffer : + samplePublicKeyRsaBuffer; bufSz = (word32)strlen(bufName); memcpy(buf, bufName, bufSz); buf[bufSz] = 0; diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 640c3cc..97db63f 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -280,6 +280,8 @@ static void ShowUsage(void) printf(" -P password for username, prompted if omitted\n"); printf(" -d set the default local path\n"); printf(" -N use non blocking sockets\n"); + printf(" -e use ECC user authentication\n"); + /*printf(" -E use ECC server authentication\n");*/ ShowCommands(); } @@ -289,6 +291,8 @@ byte userPassword[256]; byte userPublicKeyType[32]; byte userPublicKey[512]; word32 userPublicKeySz; +const byte* userPrivateKey; +word32 userPrivateKeySz; const char hanselPublicRsa[] = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho" @@ -443,7 +447,8 @@ static int wsUserAuth(byte authType, else { printf("Password: "); SetEcho(0); - if (WFGETS((char*)userPassword, sizeof(userPassword), stdin) == NULL) { + if (WFGETS((char*)userPassword, sizeof(userPassword), + stdin) == NULL) { printf("Getting password failed.\n"); ret = WOLFSSH_USERAUTH_FAILURE; } @@ -467,20 +472,12 @@ static int wsUserAuth(byte authType, else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { WS_UserAuthData_PublicKey* pk = &authData->sf.publicKey; - userPublicKeySz = (word32)sizeof(userPublicKey); - - Base64_Decode((byte*)hanselPublicRsa, - (word32)WSTRLEN(hanselPublicRsa), - (byte*)userPublicKey, &userPublicKeySz); - - strncpy((char*)userPublicKeyType, "ssh-rsa", - sizeof(userPublicKeyType)); pk->publicKeyType = userPublicKeyType; pk->publicKeyTypeSz = (word32)WSTRLEN((char*)userPublicKeyType); pk->publicKey = userPublicKey; pk->publicKeySz = userPublicKeySz; - pk->privateKey = hanselPrivateRsa; - pk->privateKeySz = hanselPrivateRsaSz; + pk->privateKey = userPrivateKey; + pk->privateKeySz = userPrivateKeySz; ret = WOLFSSH_USERAUTH_SUCCESS; } @@ -490,10 +487,16 @@ static int wsUserAuth(byte authType, static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) { - printf("Sample public key check callback\n" - " public key = %p\n" - " public key size = %u\n" - " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + #ifdef DEBUG_WOLFSSH + printf("Sample public key check callback\n" + " public key = %p\n" + " public key size = %u\n" + " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + #else + (void)pubKey; + (void)pubKeySz; + (void)ctx; + #endif return 0; } @@ -1146,6 +1149,8 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) socklen_t clientAddrSz = sizeof(clientAddr); int ret; int ch; + int userEcc = 0; + /* int peerEcc = 0; */ word16 port = wolfSshPort; char* host = (char*)wolfSshIp; const char* username = NULL; @@ -1157,12 +1162,22 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) char** argv = ((func_args*)args)->argv; ((func_args*)args)->return_code = 0; - while ((ch = mygetopt(argc, argv, "?d:h:p:u:P:N")) != -1) { + while ((ch = mygetopt(argc, argv, "?d:eEh:p:u:P:N")) != -1) { switch (ch) { case 'd': defaultSftpPath = myoptarg; break; + case 'e': + userEcc = 1; + break; + + case 'E': + /* peerEcc = 1; */ + err_sys("wolfSFTP ECC server authentication " + "not yet supported."); + break; + case 'h': host = myoptarg; break; @@ -1208,6 +1223,29 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) } #endif + if (userEcc) { + userPublicKeySz = (word32)sizeof(userPublicKey); + Base64_Decode((byte*)hanselPublicEcc, + (word32)WSTRLEN(hanselPublicEcc), + (byte*)userPublicKey, &userPublicKeySz); + + strncpy((char*)userPublicKeyType, "ecdsa-sha2-nistp256", + sizeof(userPublicKeyType)); + userPrivateKey = hanselPrivateEcc; + userPrivateKeySz = hanselPrivateEccSz; + } + else { + userPublicKeySz = (word32)sizeof(userPublicKey); + Base64_Decode((byte*)hanselPublicRsa, + (word32)WSTRLEN(hanselPublicRsa), + (byte*)userPublicKey, &userPublicKeySz); + + strncpy((char*)userPublicKeyType, "ssh-rsa", + sizeof(userPublicKeyType)); + userPrivateKey = hanselPrivateRsa; + userPrivateKeySz = hanselPrivateRsaSz; + } + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); if (ctx == NULL) err_sys("Couldn't create wolfSSH client context."); diff --git a/src/internal.c b/src/internal.c index 2158b1b..865e200 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3703,7 +3703,8 @@ static int DoUserAuthFailure(WOLFSSH* ssh, byte authList[3]; /* Should only ever be password, publickey, hostname */ word32 authListSz = 3; byte partialSuccess; - byte authId = ID_USERAUTH_PUBLICKEY; + byte authId = ID_USERAUTH_PASSWORD; + /* To use public key authentication, change authId. */ int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering DoUserAuthFailure()"); From 3db449d7369368f50d10f49ee1b73b263183a759 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 7 Jun 2019 16:05:10 -0700 Subject: [PATCH 3/3] Public key authentication 1. Remove a forced test value for a sigSz in PrepareUserAuthRequestEcc. 2. When building the PrepareUserAuthRequest message for ECC user public keys, the temporary buffer for the signature should be the size of a signature for prime256 signatures, not 512 bytes. --- src/internal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index 865e200..b38eddf 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6918,7 +6918,6 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz, if (ret == WS_SUCCESS) { if (authData->sf.publicKey.hasSignature) { int sigSz = wc_ecc_sig_size(&keySig->ks.ecc.key); - sigSz = 64; if (sigSz >= 0) { *payloadSz += (LENGTH_SZ * 5) + (word32)sigSz + @@ -6949,7 +6948,7 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh, int ret = WS_SUCCESS; byte* r; byte* s; - byte sig[512]; + byte sig[72]; /* wc_ecc_sig_size() for a prime256 key. */ word32 sigSz = sizeof(sig), rSz, sSz; if (ssh == NULL || output == NULL || idx == NULL || authData == NULL ||