Merge pull request #4 from ejohnstown/userauth-update

User Authentication Update
pull/5/head
dgarske 2016-06-20 10:57:23 -07:00 committed by GitHub
commit ef920ea047
12 changed files with 780 additions and 70 deletions

View File

@ -37,3 +37,22 @@ The server will send a canned banner to the client:
Characters typed into the client will be echoed to the screen by the server.
If the characters are echoed twice, the client has local echo enabled.
testing notes
-------------
Authentication against the example echoserver can be done with a password or
public key. To use a password the command line:
$ ssh_client -p 22222 USER@localhost
Where the `USER` and password pairs are:
jill:upthehill
jack:fetchapail
To use public key authentication use the command line:
$ ssh_client -l ./certs/key-USER.pem -p 22222 USER@localhost
Where the user can be `gretel` or `hansel`.

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPIxGlM2XBIY6NulXIJgXdOheM+mZ7ixU8RLaXy2OoJeoAoGCCqGSM49
AwEHoUQDQgAEpalbz23q5UgbcVHU0uGllXYqEw9kAG/uyCSMfZ1wliKi6tXrs/9p
WCseyyREeyKmmMqt6WkekGJd54jHPa/Wyw==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKWpW89t6uVIG3FR1NLhpZV2KhMPZABv7sgkjH2dcJYiourV67P/aVgrHsskRHsippjKrelpHpBiXeeIxz2v1ss= john@johnwork.local

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqg8EVU0VZP8Iz4aKOuvjM7a3N9SrMQ2fpAFdNd/Tx0PsLLnj
aW2uozZ+aOplExDq8a89CzLAyTgTOwphtPfN5BeIESIoRAqUNK3Izj+gUn21UxPZ
nyCuSLFImRnfEqBPZEldqSdhb2XgUBDaAMRBZNM2S/bXIT0vjglBmyuEg487jWZf
99DHM7O9zdzAc4uidaD6O7BZaswennAYytiqY7rOGNa2BaYSZ1MbSrwdLPoaGmna
7m4hOe3Sugax+YmcFS00Crsd9bgiSz4YpLSN4i23ZRmRHLSZE2rH1UrFIs8FSMkY
4VSpm3SERsJFN/A9ONwEdYdJlKBgjyCrqnBTHwIDAQABAoIBADTkttRRRXZEXNkv
X480D1bmXdZfr19yfVTll7hKBfTUi4Dd0H3aP5dEO80mGonzmR/TAYmaH5x2dITI
ldtTuBZZu1iY5y1CnRZFd0+vOo5tyxgr9GQqJgs2GP6FrXx9oDPxHdCfDw83AK3m
j+ftIunZR+oYvJD6FvB2sJEy1+STBoI6znDILaJzm0sR6YCnaH05cfVTB/UyNisy
8OAIJrhB+oiH/BdWyYDhVM3E09uFt8b5+rJVqhQ+G+dFzRNsTLLAzADGWtxr3Yl6
XtHjNDE/HobMgjlH6CkXPZ5ZO3wkUPg4EuTaS1atlaxWqHqp/3OffB8rPGxg0N+n
w9NRbwECgYEA1E6AgiCVOj7fIFcznoEJSu2tcdPcCD+PopWisNWNE678ZqlUsD/4
7Fxz24RUn+1+pO4VjQ0vmDkhgM+O28gJdd1O+3loht9+h3Ie2+/EUXQudmqs7sPV
8DAuhWrnqrO6W4/nO/6MEgcXI5iJyi+uCNclMARDN1T3bh60UbcfAksCgYEAzQ6n
xGBkkAm2gItkjdIlZFVKJikSpKhLnQV5D04y/S5nw1XBdk7iL8rWIqZVYlE+7sjX
TB4gCXtFFZDTnM8fSzQU5I3ggo5NxmKq/Q4hl2aFSPEK3PMQ4Ik4jud85rluhTG8
WRtIlvbqSKTSiuPbZXD/xmS3EL8Xf+V2wbK/zf0CgYEAsvCbZZIa1KXLIBH/Ytf1
Qh8Dcg4TxSv1Xx5pqkvDhVSWTdzokUjKAEWILPvi64ybkl1M8r6rX8y/TTcjfGCk
gKAQAup4TD0xAu4PzmXO/KxEwO/2Y6PRvIiPnUnWiszDBItMZQeNfWBWg1z8vdnk
AHV9VXQyRv+pMDpW1wzV6PMCgYAnL6HH2VPeYrzJm9m/cGVM4y+kUz0I0lCA1Ubp
Mdx0naWeooix/ykiUPTS8k5m13fbUe4y0Z71sOTm1iJaWQp16KIFe0doK6GZQ8nB
Si4JLMJTyhx1VM3o2tBAHuSzgsQoF/USYjBhCRaEg1rox9ppbEq0sxJ41Mu82TD0
myAkUQKBgFboHyz32Lx4/xB0fNTyw5c4tmnvQ8B1BFInXV3+yfL6vRIVDAfj5mMn
WUNo1Hd77uHLuB3n4TzU8KwbF1vD2aACLk3p+OVRramMyv98nrl83oBMONxUh9Qb
J1NBwEkdjaqk+s+r3SSl7avVJJOViEGwGnrm0a6kACd5zxdjx0vk
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvT92RaMDrDjVxw+TMFognIl8rQUWRoaDDYorFkoFLOR3R3AA
rh2D4tlumdTwRZgVk/aHTqxkY6GVyXww6D4vo/EknwxrHP4bApnNxqdshIVGVBJA
4bTl8qo57NYnJAvRoeLvNGklbcB0ZyWYfcT4UqubSzoSHeHj+tbPmuacI045xIQW
iD1CTtgvzNKRZ522cSoCZV+7dQ6Mu4eXl8b4spjiL2gmSlPseTqKX8zP8BZHstBD
1jZsyOcv/qc1OWn7HXhFnYkAyEHPNB+j8/H7KBT72EhvrOP8M9Hbru8nnldWKaIa
OuWa/qRJyH+3TtAfBG5YFrfrnfiSPMKwIXxOMQIDAQABAoIBAQCNpGEGL8NA9Gz0
hzC4AMzlvHWHHgaVFHoj+STUkuQavIiV/DtWFhsu/2QrWNfYjsKfsuWEubyNYVQ1
sHD+cgTAJG0vaWEGGx3mLW15YLf027dOlzbed8GfhU7Dd2lmLj5hdvNn+8aaxW+Z
/+aJQ5JEddJOVJFYskgq5voNSsrUFJ72J2e3JXpDuytn0f7RaCMGMHy/YEnezH4m
Wjv+pqbnqN2sua+CmjpBfmEhN6MI5MS8EfU7jk1R873aurLF7vvP34OhggHhUZ0H
Wl3Yx1s/lxNqTR6NOaxAlYJsoqHMipshMjpYzOctGnmkMVCxS3YjG7NAPT1ycjLs
Xzi1jbKNAoGBAO1afo6hYn0mXHjEh3HJQVd3lJOTJnjIoxW9WcsbtLJrD+eA8vr8
jjKpGx5/4SbvACXY3ckaIwAmO0YjwFDnzmKyNrKYCRY0GJ5GvK8sKJQv4F3Jssj7
XRPVNqoVD4mlFlldInSkR136+wxegL8PwpyVD+eqfxYb1Ns4fVguV3gvAoGBAMwd
f3Q2bbSSJWLFULBcodrzsv0emA2LBWlgjl7SiZBKDUZ+4lRprhbmy9W9ezAre1zu
kxLPY4mcPcgt5HphCV6A+zwDs3PWmNCEDFmfToDzRu0DndXci+ex6KpX3NFBVQfH
32c8cniwYI+FoZCZDKVnq/C2dJADVXtezMW/3qefAoGAQIFuka7UiHSrfvrSYJ80
jePm0jCUrRDCGb9rLuLpue+U0/Lclk+bCbOhtilE9ILRxHdq1yOuTXUWeNpwgsxs
76/FY8Yj+g/QfPt2fhj/Mj7MuFB/sVV3F1PD1neA0IS4TTMdkRuwdZ8nKVZpoQNU
fZ+ZQfm5LjYEJEv27MczaGsCgYBgNcs80Ob3BSggHVeCObeFB/enPcN4Jr4/RGb3
JQ/4dh85ylcOaN3JJ7KOpgip1OUKEd47MIv/cijg8VjPomuTIwLI8AmnIVDYgFV9
7QxI1eLplxnPk2xSotZDbLTF4aCd0UVpWOGwJ5rsK5XTHYELeglepfHda+TgCPhG
gcEGiwKBgAD28uslungErQ4NLqdp1lfmNjJQ0vLrrTFGZcAHl4NsZic+lCwFAV9c
4DEw7GHSdDW3nzjnjmexUAhozs/Y7oj9XcTN4oY9Sg4Ef+6K6JsWofwJguJiAzzo
JX88mqqD+NiT0VT5zrT6NTbMGFSq8pC3fJcLJy+u/MOTrxp17Bjb
-----END RSA PRIVATE KEY-----

2
certs/passwd.txt 100644
View File

@ -0,0 +1,2 @@
jill:upthehill
jack:fetchapail

View File

@ -0,0 +1,2 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGhoMNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3Gp2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTjnEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPWNmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pEnIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjOP6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjzuNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadrubiE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdIRGwkU38D043AR1h0mUoGCPIKuqcFMf gretel

View File

@ -33,6 +33,8 @@
#include <sys/socket.h>
#include <stdio.h>
#include <pthread.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/coding.h>
#include <wolfssh/ssh.h>
#ifndef SO_NOSIGPIPE
#include <signal.h>
@ -315,9 +317,251 @@ static int load_file(const char* fileName, uint8_t* buf, uint32_t bufSz)
}
static inline void c32toa(uint32_t u32, uint8_t* c)
{
c[0] = (u32 >> 24) & 0xff;
c[1] = (u32 >> 16) & 0xff;
c[2] = (u32 >> 8) & 0xff;
c[3] = u32 & 0xff;
}
/* Map user names to passwords */
/* Use arrays for username and p. The password or public key can
* be hashed and the hash stored here. Then I won't need the type. */
typedef struct PwMap {
uint8_t type;
uint8_t username[32];
uint32_t usernameSz;
uint8_t p[SHA256_DIGEST_SIZE];
struct PwMap* next;
} PwMap;
typedef struct PwMapList {
PwMap* head;
} PwMapList;
static PwMap* PwMapNew(PwMapList* list, uint8_t type, const uint8_t* username,
uint32_t usernameSz, const uint8_t* p, uint32_t pSz)
{
PwMap* map;
map = (PwMap*)malloc(sizeof(PwMap));
if (map != NULL) {
Sha256 sha;
uint8_t flatSz[4];
map->type = type;
if (usernameSz >= sizeof(map->username))
usernameSz = sizeof(map->username) - 1;
memcpy(map->username, username, usernameSz + 1);
map->username[usernameSz] = 0;
map->usernameSz = usernameSz;
wc_InitSha256(&sha);
c32toa(pSz, flatSz);
wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
wc_Sha256Update(&sha, p, pSz);
wc_Sha256Final(&sha, map->p);
map->next = list->head;
list->head = map;
}
return map;
}
static void PwMapListDelete(PwMapList* list)
{
if (list != NULL) {
PwMap* head = list->head;
while (head != NULL) {
PwMap* cur = head;
head = head->next;
memset(cur, 0, sizeof(PwMap));
}
}
}
static const char samplePasswordBuffer[] =
"jill:upthehill\n"
"jack:fetchapail\n";
static const char samplePublicKeyBuffer[] =
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho"
"MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G"
"p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj"
"nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW"
"NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE"
"nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ"
"+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO"
"P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz"
"uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru"
"biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI"
"RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n";
static int LoadPasswordBuffer(uint8_t* buf, uint32_t bufSz, PwMapList* list)
{
char* str = (char*)buf;
char* delimiter;
char* username;
char* password;
/* Each line of passwd.txt is in the format
* username:password\n
* This function modifies the passed-in buffer. */
if (list == NULL)
return -1;
if (buf == NULL || bufSz == 0)
return 0;
while (*str != 0) {
delimiter = strchr(str, ':');
username = str;
*delimiter = 0;
password = delimiter + 1;
str = strchr(password, '\n');
*str = 0;
str++;
if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD,
(uint8_t*)username, (uint32_t)strlen(username),
(uint8_t*)password, (uint32_t)strlen(password)) == NULL ) {
return -1;
}
}
return 0;
}
static int LoadPublicKeyBuffer(uint8_t* buf, uint32_t bufSz, PwMapList* list)
{
char* str = (char*)buf;
char* delimiter;
uint8_t* publicKey64;
uint32_t publicKey64Sz;
uint8_t* username;
uint32_t usernameSz;
uint8_t publicKey[300];
uint32_t publicKeySz;
int decodeResult;
/* Each line of passwd.txt is in the format
* ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n
* This function modifies the passed-in buffer. */
if (list == NULL)
return -1;
if (buf == NULL || bufSz == 0)
return 0;
while (*str != 0) {
/* Skip the public key type. This example will always be ssh-rsa. */
delimiter = strchr(str, ' ');
str = delimiter + 1;
delimiter = strchr(str, ' ');
publicKey64 = (uint8_t*)str;
publicKey64Sz = (uint32_t)(delimiter - str);
str = delimiter + 1;
delimiter = strchr(str, '\n');
username = (uint8_t*)str;
usernameSz = (uint32_t)(delimiter - str);
str = delimiter + 1;
publicKeySz = sizeof(publicKey);
decodeResult = Base64_Decode(publicKey64, publicKey64Sz,
publicKey, &publicKeySz);
if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY,
username, usernameSz,
publicKey, publicKeySz) == NULL ) {
return -1;
}
}
return 0;
}
static int wsUserAuth(uint8_t authType,
const WS_UserAuthData* authData,
void* ctx)
{
PwMapList* list;
PwMap* map;
uint8_t authHash[SHA256_DIGEST_SIZE];
if (ctx == NULL) {
fprintf(stderr, "wsUserAuth: ctx not set");
return WOLFSSH_USERAUTH_FAILURE;
}
if (authType != WOLFSSH_USERAUTH_PASSWORD &&
authType != WOLFSSH_USERAUTH_PUBLICKEY) {
return WOLFSSH_USERAUTH_FAILURE;
}
/* Hash the password or public key with its length. */
{
Sha256 sha;
uint8_t flatSz[4];
wc_InitSha256(&sha);
if (authType == WOLFSSH_USERAUTH_PASSWORD) {
c32toa(authData->sf.password.passwordSz, flatSz);
wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
wc_Sha256Update(&sha,
authData->sf.password.password,
authData->sf.password.passwordSz);
}
else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) {
c32toa(authData->sf.publicKey.publicKeySz, flatSz);
wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
wc_Sha256Update(&sha,
authData->sf.publicKey.publicKey,
authData->sf.publicKey.publicKeySz);
}
wc_Sha256Final(&sha, authHash);
}
list = (PwMapList*)ctx;
map = list->head;
while (map != NULL) {
if (authData->type == map->type &&
authData->usernameSz == map->usernameSz &&
memcmp(authData->username, map->username, map->usernameSz) == 0) {
if (memcmp(map->p, authHash, SHA256_DIGEST_SIZE) != 0) {
return (authType == WOLFSSH_USERAUTH_PASSWORD ?
WOLFSSH_USERAUTH_INVALID_PASSWORD :
WOLFSSH_USERAUTH_INVALID_PUBLICKEY);
}
return WOLFSSH_USERAUTH_SUCCESS;
}
map = map->next;
}
return WOLFSSH_USERAUTH_INVALID_USER;
}
int main(void)
{
WOLFSSH_CTX* ctx = NULL;
PwMapList pwMapList;
SOCKET_T listenFd = 0;
#ifdef DEBUG_WOLFSSH
@ -335,6 +579,9 @@ int main(void)
exit(EXIT_FAILURE);
}
memset(&pwMapList, 0, sizeof(pwMapList));
wolfSSH_SetUserAuth(ctx, wsUserAuth);
{
uint8_t buf[SCRATCH_BUFFER_SIZE];
uint32_t bufSz;
@ -360,6 +607,16 @@ int main(void)
fprintf(stderr, "Couldn't use key buffer.\n");
exit(EXIT_FAILURE);
}
bufSz = (uint32_t)strlen((char*)samplePasswordBuffer);
memcpy(buf, samplePasswordBuffer, bufSz);
buf[bufSz] = 0;
LoadPasswordBuffer(buf, bufSz, &pwMapList);
bufSz = (uint32_t)strlen((char*)samplePublicKeyBuffer);
memcpy(buf, samplePublicKeyBuffer, bufSz);
buf[bufSz] = 0;
LoadPublicKeyBuffer(buf, bufSz, &pwMapList);
}
tcp_bind(&listenFd, SERVER_PORT_NUMBER, 0);
@ -376,6 +633,7 @@ int main(void)
fprintf(stderr, "Couldn't allocate SSH data.\n");
exit(EXIT_FAILURE);
}
wolfSSH_SetUserAuthCtx(ssh, &pwMapList);
if (listen(listenFd, 5) != 0)
err_sys("tcp listen failed");
@ -391,6 +649,7 @@ int main(void)
pthread_detach(thread);
}
PwMapListDelete(&pwMapList);
if (wolfSSH_Cleanup() != WS_SUCCESS) {
fprintf(stderr, "Couldn't clean up wolfSSH.\n");
exit(EXIT_FAILURE);

View File

@ -163,6 +163,7 @@ static const NameIdPair NameIdMap[] = {
/* UserAuth IDs */
{ ID_USERAUTH_PASSWORD, "password" },
{ ID_USERAUTH_PUBLICKEY, "publickey" },
/* Channel Type IDs */
{ ID_CHANTYPE_SESSION, "session" }
@ -1275,11 +1276,13 @@ static int DoDisconnect(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx)
return WS_SUCCESS;
}
#if 0
static const char serviceNameUserAuth[] = "ssh-userauth";
static const char serviceNameConnection[] = "ssh-connection";
#endif
static int DoServiceRequest(WOLFSSH* ssh,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
@ -1305,45 +1308,6 @@ static int DoServiceRequest(WOLFSSH* ssh,
}
static int DoUserAuthRequest(WOLFSSH* ssh,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
uint32_t begin = *idx;
uint32_t valueSz;
char value[32];
(void)ssh;
(void)len;
ato32(buf + begin, &valueSz);
begin += LENGTH_SZ;
XMEMCPY(value, buf + begin, valueSz);
begin += valueSz;
value[valueSz] = 0;
ato32(buf + begin, &valueSz);
begin += LENGTH_SZ;
XMEMCPY(value, buf + begin, valueSz);
begin += valueSz;
value[valueSz] = 0;
ato32(buf + begin, &valueSz);
begin += LENGTH_SZ;
XMEMCPY(value, buf + begin, valueSz);
begin += valueSz;
value[valueSz] = 0;
*idx = begin;
ssh->clientState = CLIENT_USERAUTH_DONE;
return WS_SUCCESS;
}
static int GetBoolean(uint8_t* v, uint8_t* buf, uint32_t len, uint32_t* idx)
{
int result = WS_BUFFER_E;
@ -1366,6 +1330,7 @@ static int GetUint32(uint32_t* v, uint8_t* buf, uint32_t len, uint32_t* idx)
*idx += UINT32_SZ;
result = WS_SUCCESS;
}
return result;
}
@ -1391,6 +1356,252 @@ static int GetString(char* s, uint32_t* sSz,
}
/* Utility for DoUserAuthRequest() */
static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
uint32_t begin = *idx;
WS_UserAuthData_Password* pw = &authData->sf.password;
int ret;
authData->type = WOLFSSH_USERAUTH_PASSWORD;
ret = GetBoolean(&pw->hasNewPassword, buf, len, &begin);
ret = GetUint32(&pw->passwordSz, buf, len, &begin);
pw->password = buf + begin;
begin += pw->passwordSz;
if (pw->hasNewPassword) {
/* Skip the password change. Maybe error out since we aren't
* supporting password changes at this time. */
ret = GetUint32(&pw->newPasswordSz, buf, len, &begin);
pw->newPassword = buf + begin;
begin += pw->newPasswordSz;
}
else {
pw->newPassword = NULL;
pw->newPasswordSz = 0;
}
if (ssh->ctx->userAuthCb != NULL) {
WLOG(WS_LOG_DEBUG, "DUAR: Checking the password");
ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PASSWORD,
authData, ssh->userAuthCtx);
if (ret == WS_SUCCESS) {
WLOG(WS_LOG_DEBUG, "DUAR: password check successful");
ssh->clientState = CLIENT_USERAUTH_DONE;
}
else {
WLOG(WS_LOG_DEBUG, "DUAR: password check failed");
SendUserAuthFailure(ssh, 0);
}
}
else {
WLOG(WS_LOG_DEBUG, "DUAR: No user auth callback");
}
*idx = begin;
return WS_SUCCESS;
}
/* Utility for DoUserAuthRequestPublicKey() */
/* returns negative for error, positive is size of digest. */
static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
uint8_t* digest, uint32_t digestSz)
{
RsaKey key;
uint8_t* publicKeyType;
uint32_t publicKeyTypeSz;
uint8_t* n;
uint32_t nSz;
uint8_t* e;
uint32_t eSz;
uint32_t i = 0;
int ret;
/* First check that the public key's type matches the one we are
* expecting. */
GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
publicKeyType = pk->publicKey + i;
i += publicKeyTypeSz;
if (publicKeyTypeSz != pk->publicKeyTypeSz &&
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
WLOG(WS_LOG_DEBUG, "Public Key's type does not match public key type");
return WS_INVALID_ALGO_ID;
}
GetUint32(&eSz, pk->publicKey, pk->publicKeySz, &i);
e = pk->publicKey + i;
i += eSz;
GetUint32(&nSz, pk->publicKey, pk->publicKeySz, &i);
n = pk->publicKey + i;
wc_InitRsaKey(&key, ssh->ctx->heap);
ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, &key);
i = 0;
/* First check that the signature's public key type matches the one
* we are expecting. */
GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
publicKeyType = pk->publicKey + i;
i += publicKeyTypeSz;
if (publicKeyTypeSz != pk->publicKeyTypeSz &&
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
WLOG(WS_LOG_DEBUG, "Signature's type does not match public key type");
return WS_INVALID_ALGO_ID;
}
GetUint32(&nSz, pk->signature, pk->signatureSz, &i);
n = pk->signature + i;
ret = wc_RsaSSL_Verify(n, nSz, digest, digestSz, &key);
wc_FreeRsaKey(&key);
return ret;
}
/* Utility for DoUserAuthRequest() */
static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
uint32_t begin = *idx;
WS_UserAuthData_PublicKey* pk = &authData->sf.publicKey;
int ret = WS_SUCCESS;
authData->type = WOLFSSH_USERAUTH_PUBLICKEY;
GetBoolean(&pk->hasSignature, buf, len, &begin);
GetUint32(&pk->publicKeyTypeSz, buf, len, &begin);
pk->publicKeyType = buf + begin;
begin += pk->publicKeyTypeSz;
GetUint32(&pk->publicKeySz, buf, len, &begin);
pk->publicKey = buf + begin;
begin += pk->publicKeySz;
if (pk->hasSignature) {
GetUint32(&pk->signatureSz, buf, len, &begin);
pk->signature = buf + begin;
begin += pk->signatureSz;
}
else {
pk->signature = NULL;
pk->signatureSz = 0;
}
if (ssh->ctx->userAuthCb != NULL) {
ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PUBLICKEY,
authData, ssh->userAuthCtx);
}
if (pk->signature == NULL) {
WLOG(WS_LOG_DEBUG, "DUAR: Send the PK OK");
ret = SendUserAuthPkOk(ssh, pk->publicKeyType, pk->publicKeyTypeSz,
pk->publicKey, pk->publicKeySz);
}
else {
uint8_t checkDigest[MAX_ENCODED_SIG_SZ];
uint32_t checkDigestSz = sizeof(checkDigest);
uint8_t encDigest[MAX_ENCODED_SIG_SZ];
uint32_t encDigestSz;
uint8_t pkTypeId;
pkTypeId = NameToId((char*)pk->publicKeyType, pk->publicKeyTypeSz);
if (pkTypeId == ID_SSH_RSA)
ret = DoUserAuthRequestRsa(ssh, pk, checkDigest, checkDigestSz);
else
ret = WS_INVALID_ALGO_ID;
if (ret > 0) {
checkDigestSz = (uint32_t)ret;
ret = WS_SUCCESS;
}
{
Sha sha;
uint8_t digest[SHA_DIGEST_SIZE];
wc_InitSha(&sha);
c32toa(ssh->sessionIdSz, digest);
wc_ShaUpdate(&sha, digest, UINT32_SZ);
wc_ShaUpdate(&sha, ssh->sessionId, ssh->sessionIdSz);
digest[0] = MSGID_USERAUTH_REQUEST;
wc_ShaUpdate(&sha, digest, MSG_ID_SZ);
/* The rest of the fields in the signature are already
* in the buffer. Just need to account for the sizes. */
wc_ShaUpdate(&sha, pk->dataToSign,
authData->usernameSz + authData->serviceNameSz +
authData->authNameSz + BOOLEAN_SZ +
pk->publicKeyTypeSz + pk->publicKeySz +
(UINT32_SZ * 5));
wc_ShaFinal(&sha, digest);
encDigestSz = wc_EncodeSignature(encDigest, digest,
SHA_DIGEST_SIZE, SHAh);
}
{
volatile int compare;
volatile int sizeCompare;
compare = ConstantCompare(encDigest, checkDigest, encDigestSz);
sizeCompare = encDigestSz != checkDigestSz;
if (compare || sizeCompare || ret < 0) {
WLOG(WS_LOG_DEBUG, "signature compare failure");
SendUserAuthFailure(ssh, 0);
}
else {
ssh->clientState = CLIENT_USERAUTH_DONE;
}
}
}
*idx = begin;
return ret;
}
static int DoUserAuthRequest(WOLFSSH* ssh,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
uint32_t begin = *idx;
int ret;
uint8_t authNameId;
WS_UserAuthData authData;
GetUint32(&authData.usernameSz, buf, len, &begin);
authData.username = buf + begin;
begin += authData.usernameSz;
GetUint32(&authData.serviceNameSz, buf, len, &begin);
authData.serviceName = buf + begin;
begin += authData.serviceNameSz;
GetUint32(&authData.authNameSz, buf, len, &begin);
authData.authName = buf + begin;
begin += authData.authNameSz;
authNameId = NameToId((char*)authData.authName, authData.authNameSz);
if (authNameId == ID_USERAUTH_PASSWORD)
ret = DoUserAuthRequestPassword(ssh, &authData, buf, len, &begin);
else if (authNameId == ID_USERAUTH_PUBLICKEY) {
authData.sf.publicKey.dataToSign = buf + *idx;
ret = DoUserAuthRequestPublicKey(ssh, &authData, buf, len, &begin);
}
else {
WLOG(WS_LOG_DEBUG, "invalid userauth type: %s", IdToName(authNameId));
ret = SendUserAuthFailure(ssh, 0);
}
*idx = begin;
return ret;
}
static int DoChannelOpen(WOLFSSH* ssh,
uint8_t* buf, uint32_t len, uint32_t* idx)
{
@ -1622,22 +1833,22 @@ static int DoPacket(WOLFSSH* ssh)
case MSGID_DISCONNECT:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
DoDisconnect(ssh, buf, payloadSz, &idx);
DoDisconnect(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_IGNORE:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
DoIgnore(ssh, buf, payloadSz, &idx);
DoIgnore(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_UNIMPLEMENTED:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
DoUnimplemented(ssh, buf, payloadSz, &idx);
DoUnimplemented(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_DEBUG:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
DoDebug(ssh, buf, payloadSz, &idx);
DoDebug(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_KEXINIT:
@ -1649,52 +1860,48 @@ static int DoPacket(WOLFSSH* ssh)
wc_ShaUpdate(&ssh->handshake->hash, scratchLen, LENGTH_SZ);
wc_ShaUpdate(&ssh->handshake->hash, &msg, sizeof(msg));
wc_ShaUpdate(&ssh->handshake->hash, buf + idx, payloadSz);
DoKexInit(ssh, buf, payloadSz, &idx);
DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
}
break;
case MSGID_NEWKEYS:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_NEWKEYS");
DoNewKeys(ssh, buf, payloadSz, &idx);
DoNewKeys(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_KEXDH_INIT:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
DoKexDhInit(ssh, buf, payloadSz, &idx);
DoKexDhInit(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_SERVICE_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVICE_REQUEST");
DoServiceRequest(ssh, buf, payloadSz, &idx);
DoServiceRequest(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_USERAUTH_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_REQUEST");
DoUserAuthRequest(ssh, buf, payloadSz, &idx);
DoUserAuthRequest(ssh, buf + idx, payloadSz, &payloadIdx);
break;
case MSGID_CHANNEL_OPEN:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_OPEN");
DoChannelOpen(ssh, buf + idx, payloadSz, &payloadIdx);
idx += payloadIdx;
break;
case MSGID_CHANNEL_WINDOW_ADJUST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_WINDOW_ADJUST");
DoChannelWindowAdjust(ssh, buf + idx, payloadSz, &payloadIdx);
idx += payloadIdx;
break;
case MSGID_CHANNEL_DATA:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_DATA");
DoChannelData(ssh, buf + idx, payloadSz, &payloadIdx);
idx += payloadSz;
break;
case MSGID_CHANNEL_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_REQUEST");
DoChannelRequest(ssh, buf + idx, payloadSz, &payloadIdx);
idx += payloadIdx;
break;
default:
@ -1702,10 +1909,10 @@ static int DoPacket(WOLFSSH* ssh)
#ifdef SHOW_UNIMPLEMENTED
DumpOctetString(buf + idx, payloadSz);
#endif
idx += payloadSz;
SendUnimplemented(ssh);
break;
}
idx += payloadIdx;
if (idx + padSz > len) {
WLOG(WS_LOG_DEBUG, "Not enough data in buffer for pad.");
@ -2623,18 +2830,48 @@ int SendServiceAccept(WOLFSSH* ssh)
return ret;
}
#if 0
static const char cannedAuths[] = "password";
static const char cannedAuths[] = "publickey";
static const uint32_t cannedAuthsSz = sizeof(cannedAuths) - 1;
int SendUserAuthFailure(WOLFSSH* ssh, uint8_t partialSuccess)
{
(void)ssh;
uint8_t* output;
uint32_t idx;
int ret;
(void)partialSuccess;
return WS_SUCCESS;
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthFailure()");
if (ssh == NULL)
return WS_BAD_ARGUMENT;
ret = PreparePacket(ssh,
MSG_ID_SZ + LENGTH_SZ + cannedAuthsSz + BOOLEAN_SZ);
if (ret != WS_SUCCESS)
return ret;
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
output[idx++] = MSGID_USERAUTH_FAILURE;
c32toa(cannedAuthsSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, cannedAuths, cannedAuthsSz);
idx += cannedAuthsSz;
output[idx++] = 0;
ssh->outputBuffer.length = idx;
ret = BundlePacket(ssh);
if (ret == WS_SUCCESS)
ret = SendBuffered(ssh);
return ret;
}
#endif
int SendUserAuthSuccess(WOLFSSH* ssh)
{
@ -2664,6 +2901,45 @@ int SendUserAuthSuccess(WOLFSSH* ssh)
}
int SendUserAuthPkOk(WOLFSSH* ssh,
const uint8_t* algoName, uint32_t algoNameSz,
const uint8_t* publicKey, uint32_t publicKeySz)
{
uint8_t* output;
uint32_t idx;
int ret;
if (ssh == NULL ||
algoName == NULL || algoNameSz == 0 ||
publicKey == NULL || publicKeySz == 0) {
return WS_BAD_ARGUMENT;
}
PreparePacket(ssh, MSG_ID_SZ + (LENGTH_SZ * 2) + algoNameSz + publicKeySz);
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
output[idx++] = MSGID_USERAUTH_PK_OK;
c32toa(algoNameSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, algoName, algoNameSz);
idx += algoNameSz;
c32toa(publicKeySz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, publicKey, publicKeySz);
idx += publicKeySz;
ssh->outputBuffer.length = idx;
BundlePacket(ssh);
ret = SendBuffered(ssh);
return ret;
}
static const char cannedBanner[] =
"CANNED BANNER\r\n"
"This server is an example test server. "

View File

@ -228,6 +228,9 @@ static void SshResourceFree(WOLFSSH* ssh, void* heap)
/* FreeRng(ssh->rng); */
WFREE(ssh->rng, heap, DYNTYPE_RNG);
}
if (ssh->userName) {
WFREE(ssh->userName, heap, DYNTYPE_STRING);
}
}
@ -484,6 +487,31 @@ int wolfSSH_stream_send(WOLFSSH* ssh, uint8_t* buf, uint32_t bufSz)
}
void wolfSSH_SetUserAuth(WOLFSSH_CTX* ctx, WS_CallbackUserAuth cb)
{
if (ctx != NULL) {
ctx->userAuthCb = cb;
}
}
void wolfSSH_SetUserAuthCtx(WOLFSSH* ssh, void* userAuthCtx)
{
if (ssh != NULL) {
ssh->userAuthCtx = userAuthCtx;
}
}
void* wolfSSH_GetUserAuthCtx(WOLFSSH* ssh)
{
if (ssh != NULL) {
return ssh->userAuthCtx;
}
return NULL;
}
static int ProcessBuffer(WOLFSSH_CTX* ctx, const uint8_t* in, uint32_t inSz,
int format, int type)
{

View File

@ -80,6 +80,7 @@ enum {
/* UserAuth IDs */
ID_USERAUTH_PASSWORD,
ID_USERAUTH_PUBLICKEY,
/* Channel Type IDs */
ID_CHANTYPE_SESSION,
@ -133,16 +134,17 @@ WOLFSSH_LOCAL void ShrinkBuffer(Buffer* buf, int);
/* our wolfSSH Context */
struct WOLFSSH_CTX {
void* heap; /* heap hint */
WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */
WS_CallbackIOSend ioSendCb; /* I/O Send Callback */
void* heap; /* heap hint */
WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */
WS_CallbackIOSend ioSendCb; /* I/O Send Callback */
WS_CallbackUserAuth userAuthCb; /* User Authentication Callback */
uint8_t* cert; /* Owned by CTX */
uint32_t certSz;
uint8_t* caCert; /* Owned by CTX */
uint32_t caCertSz;
uint8_t* privateKey; /* Owned by CTX */
uint32_t privateKeySz;
uint8_t* cert; /* Owned by CTX */
uint32_t certSz;
uint8_t* caCert; /* Owned by CTX */
uint32_t caCertSz;
uint8_t* privateKey; /* Owned by CTX */
uint32_t privateKeySz;
};
@ -246,6 +248,12 @@ struct WOLFSSH {
uint8_t macKeyServerSz;
HandshakeInfo* handshake;
void* userAuthCtx;
uint8_t* userName;
uint32_t userNameSz;
uint8_t* pkBlob;
uint32_t pkBlobSz;
};
@ -272,6 +280,8 @@ WOLFSSH_LOCAL int SendServiceAccept(WOLFSSH*);
WOLFSSH_LOCAL int SendUserAuthSuccess(WOLFSSH*);
WOLFSSH_LOCAL int SendUserAuthFailure(WOLFSSH*, uint8_t);
WOLFSSH_LOCAL int SendUserAuthBanner(WOLFSSH*);
WOLFSSH_LOCAL int SendUserAuthPkOk(WOLFSSH*, const uint8_t*, uint32_t,
const uint8_t*, uint32_t);
WOLFSSH_LOCAL int SendChannelOpenConf(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelData(WOLFSSH* ssh, uint32_t, uint8_t*, uint32_t);
WOLFSSH_LOCAL int GenerateKey(uint8_t, uint8_t, uint8_t*, uint32_t,
@ -336,6 +346,7 @@ enum WS_MessageIds {
MSGID_USERAUTH_FAILURE = 51,
MSGID_USERAUTH_SUCCESS = 52,
MSGID_USERAUTH_BANNER = 53,
MSGID_USERAUTH_PK_OK = 60,
MSGID_CHANNEL_OPEN = 90,
MSGID_CHANNEL_OPEN_CONF = 91,

View File

@ -66,16 +66,54 @@ WOLFSSH_API const char* wolfSSH_get_error_name(const WOLFSSH*);
/* I/O callbacks */
typedef int (*WS_CallbackIORecv)(WOLFSSH*, void*, uint32_t, void*);
typedef int (*WS_CallbackIOSend)(WOLFSSH*, void*, uint32_t, void*);
WOLFSSH_API void wolfSSH_SetIORecv(WOLFSSH_CTX*, WS_CallbackIORecv);
WOLFSSH_API void wolfSSH_SetIOSend(WOLFSSH_CTX*, WS_CallbackIOSend);
WOLFSSH_API void wolfSSH_SetIOReadCtx(WOLFSSH*, void*);
WOLFSSH_API void wolfSSH_SetIOWriteCtx(WOLFSSH*, void*);
WOLFSSH_API void* wolfSSH_GetIOReadCtx(WOLFSSH*);
WOLFSSH_API void* wolfSSH_GetIOWriteCtx(WOLFSSH*);
/* User Authentication callback */
typedef struct WS_UserAuthData_Password {
uint8_t* password;
uint32_t passwordSz;
/* The following are present for future use. */
uint8_t hasNewPassword;
uint8_t* newPassword;
uint32_t newPasswordSz;
} WS_UserAuthData_Password;
typedef struct WS_UserAuthData_PublicKey {
uint8_t* dataToSign;
uint8_t* publicKeyType;
uint32_t publicKeyTypeSz;
uint8_t* publicKey;
uint32_t publicKeySz;
uint8_t hasSignature;
uint8_t* signature;
uint32_t signatureSz;
} WS_UserAuthData_PublicKey;
typedef struct WS_UserAuthData {
uint8_t type;
uint8_t* username;
uint32_t usernameSz;
uint8_t* serviceName;
uint32_t serviceNameSz;
uint8_t* authName;
uint32_t authNameSz;
union {
WS_UserAuthData_Password password;
WS_UserAuthData_PublicKey publicKey;
} sf;
} WS_UserAuthData;
typedef int (*WS_CallbackUserAuth)(uint8_t, const WS_UserAuthData*, void*);
WOLFSSH_API void wolfSSH_SetUserAuth(WOLFSSH_CTX*, WS_CallbackUserAuth);
WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*);
WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*);
WOLFSSH_API int wolfSSH_CTX_UsePrivateKey_buffer(WOLFSSH_CTX*,
const uint8_t*, uint32_t, int);
WOLFSSH_API int wolfSSH_CTX_UseCert_buffer(WOLFSSH_CTX*,
@ -104,6 +142,21 @@ enum WS_FormatTypes {
};
enum WS_UserAuthTypes {
WOLFSSH_USERAUTH_PASSWORD,
WOLFSSH_USERAUTH_PUBLICKEY
};
enum WS_UserAuthResults {
WOLFSSH_USERAUTH_SUCCESS,
WOLFSSH_USERAUTH_FAILURE,
WOLFSSH_USERAUTH_INVALID_USER,
WOLFSSH_USERAUTH_INVALID_PASSWORD,
WOLFSSH_USERAUTH_INVALID_PUBLICKEY
};
enum WS_DisconnectReasonCodes {
WOLFSSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1,
WOLFSSH_DISCONNECT_PROTOCOL_ERROR = 2,