From 71bcd94c5f2ee53916a81581c40569a8df868245 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 8 Dec 2014 21:59:21 -0800 Subject: [PATCH] 1. Starting to add in the Decryption and MAC Verification. 2. Fixed bug in getting the entire packet from the socket. --- src/internal.c | 115 ++++++++++++++++++++++++++++++++++++++------- src/ssh.c | 18 +++++-- wolfssh/error.h | 3 +- wolfssh/internal.h | 13 ++++- 4 files changed, 126 insertions(+), 23 deletions(-) diff --git a/src/internal.c b/src/internal.c index 064dbf1..64762d5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -34,9 +34,9 @@ #include #include #include -#include #include #include +#include /* convert opaque to 32 bit integer */ @@ -124,6 +124,9 @@ const char* GetErrorString(int err) case WS_BAD_FILE_E: return "bad file"; + case WS_DECRYPT_E: + return "decrypt error"; + default: return "Unknown error code"; } @@ -860,6 +863,21 @@ static int DoNewKeys(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx) ssh->peerEncryptId = ssh->handshake->encryptId; ssh->peerMacId = ssh->handshake->macId; + switch (ssh->peerEncryptId) { + case ID_NONE: + WLOG(WS_LOG_DEBUG, "DNK: peer using cipher none"); + break; + + case ID_AES128_CBC: + WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-cbc"); + AesSetKey(&ssh->decryptCipher.aes, ssh->encKeyClient, ssh->encKeyClientSz, ssh->ivClient, AES_DECRYPTION); + break; + + default: + WLOG(WS_LOG_DEBUG, "DNK: peer using cipher invalid"); + break; + } + ssh->clientState = CLIENT_USING_KEYS; return WS_SUCCESS; @@ -1122,6 +1140,8 @@ static int DoPacket(WOLFSSH* ssh) /* Problem: len is equal to the amount of data left in the input buffer. * The beginning part of that data is the packet we want to * decode. The remainder is the pad and the MAC. */ + /* Skip the packet_length field. */ + idx += LENGTH_SZ; padSz = buf[idx++]; payloadSz = ssh->curSz - PAD_LENGTH_SZ - padSz; @@ -1181,7 +1201,8 @@ static int DoPacket(WOLFSSH* ssh) } if (idx + padSz > len) { - return -1; + WLOG(WS_LOG_DEBUG, "Not enough data in buffer for pad."); + return WS_BUFFER_E; } idx += padSz; @@ -1190,12 +1211,46 @@ static int DoPacket(WOLFSSH* ssh) } +static INLINE int Decrypt(WOLFSSH* ssh, uint8_t* plain, const uint8_t* input, + uint16_t sz) +{ + int ret = WS_SUCCESS; + + if (ssh == NULL || plain == NULL || input == NULL || sz == 0) + return WS_BAD_ARGUMENT; + + switch (ssh->peerEncryptId) { + case ID_NONE: + WLOG(WS_LOG_DEBUG, "Decrypt none"); + break; + + case ID_AES128_CBC: + WLOG(WS_LOG_DEBUG, "Decrypt aes128-cbc"); + if (AesCbcDecrypt(&ssh->decryptCipher.aes, plain, input, sz) < 0) + ret = WS_DECRYPT_E; + + default: + WLOG(WS_LOG_DEBUG, "Decrypt invalid algo ID"); + ret = WS_INVALID_ALGO_ID; + } + + return ret; +} + + +static INLINE int VerifyMac(WOLFSSH* ssh) +{ + (void)ssh; + /* Verify the buffer is big enough for the data plus the mac. */ + return WS_SUCCESS; +} + + int ProcessReply(WOLFSSH* ssh) { int ret = WS_FATAL_ERROR; - int readSz; + uint32_t readSz; - (void)readSz; for (;;) { switch (ssh->processReplyState) { case PROCESS_INIT: @@ -1205,30 +1260,43 @@ int ProcessReply(WOLFSSH* ssh) return ret; } ssh->processReplyState = PROCESS_PACKET_LENGTH; + WLOG(WS_LOG_DEBUG, "idx = %u, length = %u", ssh->inputBuffer.idx, ssh->inputBuffer.length); - /* Decrypt first block if encrypted */ + /* Decrypt first block if encrypted */ + ret = Decrypt(ssh, + ssh->inputBuffer.buffer + ssh->inputBuffer.idx, + ssh->inputBuffer.buffer + ssh->inputBuffer.idx, + readSz); case PROCESS_PACKET_LENGTH: + /* Peek at the packet_length field. */ ato32(ssh->inputBuffer.buffer + ssh->inputBuffer.idx, &ssh->curSz); - ssh->inputBuffer.idx += LENGTH_SZ; ssh->processReplyState = PROCESS_PACKET_FINISH; case PROCESS_PACKET_FINISH: - WLOG(WS_LOG_DEBUG, "PR2: size = %d", ssh->curSz); - if ((ret = GetInputData(ssh, ssh->curSz)) < 0) { + readSz = ssh->curSz + LENGTH_SZ + ssh->macSz; + WLOG(WS_LOG_DEBUG, "PR2: size = %d", readSz); + if (readSz > 0) { + if ((ret = GetInputData(ssh, readSz)) < 0) { + return ret; + } - return ret; + ret = Decrypt(ssh, + ssh->inputBuffer.buffer + ssh->inputBuffer.idx + ssh->blockSz - LENGTH_SZ, + ssh->inputBuffer.buffer + ssh->inputBuffer.idx + ssh->blockSz - LENGTH_SZ, + ssh->curSz - ssh->blockSz); + + + ret = VerifyMac(ssh); } + ssh->processReplyState = PROCESS_PACKET; - /* Decrypt rest of packet here */ - - /* Check MAC here. */ - case PROCESS_PACKET: if ( (ret = DoPacket(ssh)) < 0) { return ret; } + ssh->inputBuffer.idx += ssh->macSz; break; default: @@ -1349,8 +1417,8 @@ static int BundlePacket(WOLFSSH* ssh) HmacSetKey(&hmac, SHA, ssh->macKeyServer, ssh->macKeyServerSz); HmacUpdate(&hmac, flatSeq, sizeof(flatSeq)); - HmacUpdate(&sha,); - HmacFinal(&sha, digest); + HmacUpdate(&hmac,); + HmacFinal(&hmac, digest); WMEMCPY(, digest, SHA1_96_SIZE); } break; @@ -1371,8 +1439,6 @@ static int BundlePacket(WOLFSSH* ssh) return WS_FATAL_ERROR; } - ssh->seq++; - /* Encrypt the packet */ switch (ssh->encryptId) { case ID_NONE: @@ -1706,6 +1772,21 @@ int SendNewKeys(WOLFSSH* ssh) ssh->encryptId = ssh->handshake->encryptId; ssh->macId = ssh->handshake->macId; + switch (ssh->encryptId) { + case ID_NONE: + WLOG(WS_LOG_DEBUG, "SNK: using cipher none"); + break; + + case ID_AES128_CBC: + WLOG(WS_LOG_DEBUG, "SNK: using cipher aes128-cbc"); + AesSetKey(&ssh->encryptCipher.aes, ssh->encKeyServer, ssh->encKeyServerSz, ssh->ivServer, AES_ENCRYPTION); + break; + + default: + WLOG(WS_LOG_DEBUG, "SNK: using cipher invalid"); + break; + } + return WS_SUCCESS; } diff --git a/src/ssh.c b/src/ssh.c index 8e15713..fb4bd5c 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -281,7 +281,7 @@ int wolfSSH_accept(WOLFSSH* ssh) case ACCEPT_BEGIN: while (ssh->clientState < CLIENT_VERSION_DONE) { if ( (ssh->error = ProcessClientVersion(ssh)) < 0) { - WLOG(WS_LOG_DEBUG, "accept reply error: %d", ssh->error); + WLOG(WS_LOG_DEBUG, "accept reply error 1: %d", ssh->error); return WS_FATAL_ERROR; } } @@ -296,7 +296,7 @@ int wolfSSH_accept(WOLFSSH* ssh) case SERVER_VERSION_SENT: while (ssh->clientState < CLIENT_ALGO_DONE) { if ( (ssh->error = ProcessReply(ssh)) < 0) { - WLOG(WS_LOG_DEBUG, "accept reply error: %d", ssh->error); + WLOG(WS_LOG_DEBUG, "accept reply error 2: %d", ssh->error); return WS_FATAL_ERROR; } } @@ -306,12 +306,22 @@ int wolfSSH_accept(WOLFSSH* ssh) case SERVER_ALGO_SENT: while (ssh->clientState < CLIENT_KEXDHINIT_DONE) { if ( (ssh->error = ProcessReply(ssh)) < 0) { - WLOG(WS_LOG_DEBUG, "accept reply error: %d", ssh->error); + WLOG(WS_LOG_DEBUG, "accept reply error 3: %d", ssh->error); return WS_FATAL_ERROR; } } SendKexDhReply(ssh); - break; + ssh->acceptState = SERVER_KEXDH_REPLY_SENT; + + case SERVER_KEXDH_REPLY_SENT: + while (ssh->clientState < CLIENT_USING_KEYS) { + if ( (ssh->error = ProcessReply(ssh)) < 0) { + WLOG(WS_LOG_DEBUG, "accept reply error 4: %d", ssh->error); + return WS_FATAL_ERROR; + } + } + SendNewKeys(ssh); + ssh->acceptState = SERVER_USING_KEYS; } return WS_FATAL_ERROR; diff --git a/wolfssh/error.h b/wolfssh/error.h index 80aa77b..70fa204 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -59,7 +59,8 @@ enum WS_ErrorCodes { WS_UNIMPLEMENTED_E = -17, WS_RSA_E = -18, WS_BAD_FILE_E = -19, - WS_INVALID_ALGO_ID = -20 + WS_INVALID_ALGO_ID = -20, + WS_DECRYPT_E = -21 }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 8bf1c24..676fca1 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -34,6 +34,7 @@ #include #include #include +#include #if !defined (ALIGN16) @@ -135,6 +136,11 @@ struct WOLFSSH_CTX { }; +typedef struct Ciphers { + Aes aes; +} Ciphers; + + typedef struct HandshakeInfo { uint8_t kexId; uint8_t pubKeyId; @@ -179,6 +185,9 @@ struct WOLFSSH { uint8_t peerEncryptId; uint8_t peerMacId; + Ciphers encryptCipher; + Ciphers decryptCipher; + Buffer inputBuffer; Buffer outputBuffer; RNG* rng; @@ -235,7 +244,9 @@ enum AcceptStates { ACCEPT_CLIENT_ALGO_DONE, SERVER_ALGO_SENT, ACCEPT_CLIENT_KEXDH_INIT_DONE, - SERVER_KEXDH_ACCEPT_SENT + SERVER_KEXDH_REPLY_SENT, + SERVER_KEXDH_ACCEPT_SENT, + SERVER_USING_KEYS };