mirror of https://github.com/wolfSSL/wolfssh.git
commit
ef920ea047
19
README.md
19
README.md
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIPIxGlM2XBIY6NulXIJgXdOheM+mZ7ixU8RLaXy2OoJeoAoGCCqGSM49
|
||||
AwEHoUQDQgAEpalbz23q5UgbcVHU0uGllXYqEw9kAG/uyCSMfZ1wliKi6tXrs/9p
|
||||
WCseyyREeyKmmMqt6WkekGJd54jHPa/Wyw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKWpW89t6uVIG3FR1NLhpZV2KhMPZABv7sgkjH2dcJYiourV67P/aVgrHsskRHsippjKrelpHpBiXeeIxz2v1ss= john@johnwork.local
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
jill:upthehill
|
||||
jack:fetchapail
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
392
src/internal.c
392
src/internal.c
|
|
@ -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. "
|
||||
|
|
|
|||
28
src/ssh.c
28
src/ssh.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue