summaryrefslogtreecommitdiffstats
path: root/nping/NEPContext.cc
diff options
context:
space:
mode:
Diffstat (limited to 'nping/NEPContext.cc')
-rw-r--r--nping/NEPContext.cc552
1 files changed, 552 insertions, 0 deletions
diff --git a/nping/NEPContext.cc b/nping/NEPContext.cc
new file mode 100644
index 0000000..2368234
--- /dev/null
+++ b/nping/NEPContext.cc
@@ -0,0 +1,552 @@
+
+/***************************************************************************
+ * NEPContext.cc -- *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+
+#include "nping.h"
+#include "NEPContext.h"
+#include "Crypto.h"
+#include "EchoHeader.h"
+#include "nbase.h"
+#include "NpingOps.h"
+
+extern NpingOps o;
+
+NEPContext::NEPContext() {
+ this->reset();
+} /* End of NEPContext constructor */
+
+
+NEPContext::~NEPContext() {
+} /* End of NEPContext destructor */
+
+
+/** Sets every attribute to its default value- */
+void NEPContext::reset() {
+ this->id=CLIENT_NOT_FOUND;
+ this->nsi=NULL;
+ this->state=STATE_LISTEN;
+ this->last_seq_client=0;
+ this->last_seq_server=0;
+ memset(this->next_iv_enc, 0, CIPHER_BLOCK_SIZE);
+ memset(this->next_iv_dec, 0, CIPHER_BLOCK_SIZE);
+ memset(this->nep_key_mac_c2s, 0, MAC_KEY_LEN);
+ memset(this->nep_key_mac_s2c, 0, MAC_KEY_LEN);
+ memset(this->nep_key_ciphertext_c2s, 0, CIPHER_KEY_LEN);
+ memset(this->nep_key_ciphertext_s2c, 0, CIPHER_KEY_LEN);
+ memset(this->server_nonce, 0, NONCE_LEN);
+ memset(this->client_nonce, 0, NONCE_LEN);
+ memset(&this->clnt_addr, 0, sizeof(struct sockaddr_storage ));
+ server_nonce_set=false;
+ client_nonce_set=false;
+} /* End of reset() */
+
+
+clientid_t NEPContext::getIdentifier(){
+ return this->id;
+} /* End of getIdentifier() */
+
+
+int NEPContext::setIdentifier(clientid_t clnt){
+ this->id=clnt;
+ return OP_SUCCESS;
+} /* End of setIdentifier() */
+
+
+struct sockaddr_storage NEPContext::getAddress(){
+ return this->clnt_addr;
+} /* End of getAddress() */
+
+
+int NEPContext::setAddress(const struct sockaddr_storage &a){
+ this->clnt_addr=a;
+ return OP_SUCCESS;
+} /* End of setAddress() */
+
+nsock_iod NEPContext::getNsockIOD(){
+ return this->nsi;
+} /* End of getNsockIOD() */
+
+
+int NEPContext::setNsockIOD(nsock_iod iod){
+ this->nsi=iod;
+ return OP_SUCCESS;
+} /* End of setNsockIOD() */
+
+
+bool NEPContext::ready(){
+ return (this->state==STATE_READY_SENT);
+}
+
+int NEPContext::setState(int st){
+ this->state=st;
+ return OP_SUCCESS;
+} /* End of setState() */
+
+
+int NEPContext::getState(){
+ return this->state;
+} /* End of getState() */
+
+
+int NEPContext::setNextEncryptionIV(u8 *block){
+ if(block==NULL)
+ return OP_FAILURE;
+ else{
+ memcpy(this->next_iv_enc, block, CIPHER_BLOCK_SIZE);
+ return OP_SUCCESS;
+ }
+} /* End of setLastBlock4Encryption() */
+
+
+u8 *NEPContext::getNextEncryptionIV(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=CIPHER_BLOCK_SIZE;
+ return this->next_iv_enc;
+} /* End of getLastBlock4Encryption() */
+
+
+u8 *NEPContext::getNextEncryptionIV(){
+ return this->getNextEncryptionIV(NULL);
+} /* End of getLastBlock4Encryption() */
+
+
+int NEPContext::setNextDecryptionIV(u8 *block){
+ if(block==NULL)
+ return OP_FAILURE;
+ else{
+ memcpy(this->next_iv_dec, block, CIPHER_BLOCK_SIZE);
+ return OP_SUCCESS;
+ }
+} /* End of setLastBlock4Decryption() */
+
+
+u8 *NEPContext::getNextDecryptionIV(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=CIPHER_BLOCK_SIZE;
+ return this->next_iv_dec;
+} /* End of getLastBlock4Decryption() */
+
+
+u8 *NEPContext::getNextDecryptionIV(){
+ return this->getNextDecryptionIV(NULL);
+} /* End of getLastBlock4Decryption() */
+
+
+int NEPContext::setLastServerSequence(u32 seq){
+ this->last_seq_server=seq;
+ return OP_SUCCESS;
+} /* End of setLastServerSequence() */
+
+
+u32 NEPContext::getLastServerSequence(){
+ return this->last_seq_server;
+} /* End of getLastServerSequence() */
+
+
+/** Increments current server sequence number by one and returns it.
+ * @warning this function changes object's internal state. It should be
+ * called only when the caller wants to increment the internal last_seq_client
+ * attribute. */
+u32 NEPContext::getNextServerSequence(){
+ if( this->last_seq_server==0xFFFFFFFF)
+ this->last_seq_server=0; /* Wrap back to zero */
+ else
+ this->last_seq_server++;
+ return this->last_seq_server;
+} /* End of getNextServerSequence() */
+
+
+int NEPContext::setLastClientSequence(u32 seq){
+ this->last_seq_client=seq;
+ return OP_SUCCESS;
+} /* End of setLastClientSequence() */
+
+
+u32 NEPContext::getLastClientSequence(){
+ return this->last_seq_client;
+} /* End of getLastClientSequence() */
+
+
+/** Increments current client sequence number by one and returns it.
+ * @warning this function changes object's internal state. It should be
+ * called only when the caller wants to increment the internal last_seq_client
+ * attribute. */
+u32 NEPContext::getNextClientSequence(){
+ if( this->last_seq_client==0xFFFFFFFF)
+ this->last_seq_client=0; /* Wrap back to zero */
+ else
+ this->last_seq_client++;
+ return this->last_seq_client;
+} /* End of getNextClientSequence() */
+
+
+int NEPContext::generateInitialServerSequence(){
+ return Crypto::generateNonce((u8 *)&(this->last_seq_server), sizeof(u32));
+} /* End of generateInitialServerSequence() */
+
+
+int NEPContext::generateInitialClientSequence(){
+ return Crypto::generateNonce((u8 *)&(this->last_seq_client), sizeof(u32));
+} /* End of generateInitialClientSequence() */
+
+
+u8 *NEPContext::generateKey(int key_type, size_t *final_len){
+ u8 data[1024];
+ char key_type_id[128+1];
+ size_t len=0;
+
+ /* Copy the passphrase */
+ char *passphrase=o.getEchoPassphrase();
+ size_t plen=strlen(passphrase);
+ memcpy(data, passphrase, plen);
+ len+=plen;
+
+ /* Copy the nonces */
+ memcpy(data+len, this->getServerNonce(), NONCE_LEN );
+ len+=NONCE_LEN;
+ if(key_type==MAC_KEY_S2C_INITIAL){
+ memset(data+len, 0, NONCE_LEN); /* Empty nonce in this case */
+ len+=NONCE_LEN;
+ }else{
+ memcpy(data+len, this->getClientNonce(), NONCE_LEN);
+ len+=NONCE_LEN;
+ }
+
+ switch(key_type){
+
+ case MAC_KEY_S2C_INITIAL:
+ strncpy(key_type_id, "NEPkeyforMACServer2ClientInitial", 128);
+ break;
+ case MAC_KEY_S2C:
+ strncpy(key_type_id, "NEPkeyforMACServer2Client", 128);
+ break;
+ case MAC_KEY_C2S:
+ strncpy(key_type_id, "NEPkeyforMACClient2Server", 128);
+ break;
+ case CIPHER_KEY_C2S:
+ strncpy(key_type_id, "NEPkeyforCiphertextClient2Server", 128);
+ break;
+ case CIPHER_KEY_S2C:
+ strncpy(key_type_id, "NEPkeyforCiphertextServer2Client", 128);
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ /* Copy the id */
+ memcpy(data+len, key_type_id, strlen(key_type_id));
+ len+=strlen(key_type_id);
+
+ return Crypto::deriveKey(data, len, final_len);
+} /* End of generateKey() */
+
+
+/** Set key for C->S MAC computation (NEP_KEY_MAC_C2S)*/
+int NEPContext::setMacKeyC2S(u8 *key){
+ if(key==NULL)
+ return OP_FAILURE;
+ else
+ memcpy(this->nep_key_mac_c2s, key, MAC_KEY_LEN);
+ return OP_SUCCESS;
+} /* End of setMacKeyC2S() */
+
+
+/** Returns NEP_KEY_MAC_C2S key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getMacKeyC2S(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=MAC_KEY_LEN;
+ return this->nep_key_mac_c2s;
+} /* End of getMacKeyC2S() */
+
+
+/** Returns NEP_KEY_MAC_C2S key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getMacKeyC2S(){
+ return this->getMacKeyC2S(NULL);
+} /* End of getMacKeyC2S() */
+
+
+int NEPContext::generateMacKeyC2S(){
+ u8 *key=NULL;
+ size_t len=0;
+ if( (key=this->generateKey(MAC_KEY_C2S, &len))==NULL )
+ return OP_FAILURE;
+ return this->setMacKeyC2S(key);
+} /* End of generateMacKeyC2S() */
+
+
+/** Set key for S->C MAC computation (NEP_KEY_MAC_S2C) */
+int NEPContext::setMacKeyS2C(u8 *key){
+ if(key==NULL)
+ return OP_FAILURE;
+ else
+ memcpy(this->nep_key_mac_s2c, key, MAC_KEY_LEN);
+ return OP_SUCCESS;
+} /* End of setMacKeyS2C() */
+
+
+/** Returns NEP_KEY_MAC_S2C key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getMacKeyS2C(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=MAC_KEY_LEN;
+ return this->nep_key_mac_s2c;
+} /* End of getMacKeyS2C() */
+
+
+
+/** Returns NEP_KEY_MAC_S2C key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getMacKeyS2C(){
+ return this->getMacKeyS2C(NULL);
+} /* End of getMacKeyS2C() */
+
+
+int NEPContext::generateMacKeyS2C(){
+ u8 *key=NULL;
+ size_t len=0;
+ if( (key=this->generateKey(MAC_KEY_S2C, &len))==NULL )
+ return OP_FAILURE;
+ return this->setMacKeyS2C(key);
+} /* End of generateMacKeyS2C() */
+
+
+int NEPContext::generateMacKeyS2CInitial(){
+ u8 *key=NULL;
+ size_t len=0;
+ if( (key=this->generateKey(MAC_KEY_S2C_INITIAL, &len))==NULL )
+ return OP_FAILURE;
+ return this->setMacKeyS2C(key);
+} /* End of generateMacKeyS2CInitial() */
+
+
+/** Set cipher key for C->S ciphertext (NEP_KEY_CIPHERTEXT_C2S) */
+int NEPContext::setCipherKeyC2S(u8 *key){
+ if(key==NULL)
+ return OP_FAILURE;
+ else
+ memcpy(this->nep_key_ciphertext_c2s, key, CIPHER_KEY_LEN);
+ return OP_SUCCESS;
+} /* End of setCipherKeyC2S() */
+
+
+/** Returns NEP_KEY_CIPHERTEXT_C2S key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getCipherKeyC2S(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=MAC_KEY_LEN;
+ return this->nep_key_ciphertext_c2s;
+} /* End of getCipherKeyC2S() */
+
+
+/** Returns NEP_KEY_CIPHERTEXT_C2S key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getCipherKeyC2S(){
+ return this->getCipherKeyC2S(NULL);
+} /* End of getCipherKeyC2S() */
+
+
+int NEPContext::generateCipherKeyC2S(){
+ u8 *key=NULL;
+ size_t len=0;
+ if( (key=this->generateKey(CIPHER_KEY_C2S, &len))==NULL )
+ return OP_FAILURE;
+ return this->setCipherKeyC2S(key);
+} /* End of generateCipherKeyC2S() */
+
+
+/** Set cipher key for S->C ciphertext (NEP_KEY_CIPHERTEXT_S2C) */
+int NEPContext::setCipherKeyS2C(u8 *key){
+ if(key==NULL)
+ return OP_FAILURE;
+ else
+ memcpy(this->nep_key_ciphertext_s2c, key, CIPHER_KEY_LEN);
+ return OP_SUCCESS;
+} /* End of setCipherKeyS2C() */
+
+
+/** Returns NEP_KEY_CIPHERTEXT_S2C key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getCipherKeyS2C(size_t *final_len){
+ if(final_len!=NULL)
+ *final_len=CIPHER_KEY_LEN;
+ return this->nep_key_ciphertext_s2c;
+} /* End of getCipherKeyS2C() */
+
+
+/** Returns NEP_KEY_CIPHERTEXT_S2C key. If final_len is not NULL, key length
+ * is stored in it. */
+u8 *NEPContext::getCipherKeyS2C(){
+ return this->getCipherKeyS2C(NULL);
+} /* End of getCipherKeyS2C() */
+
+
+int NEPContext::generateCipherKeyS2C(){
+ u8 *key=NULL;
+ size_t len=0;
+ if( (key=this->generateKey(CIPHER_KEY_S2C, &len))==NULL )
+ return OP_FAILURE;
+ return this->setCipherKeyS2C(key);
+} /* End of generateCipherKeyS2C() */
+
+
+/** Generates a random nonce which is, if possible, cryptographically secure.
+ * This method is used by the Echo client to generate its own nonce for the
+ * initial NEP_HANDSHAKE_CLIENT message */
+int NEPContext::generateClientNonce(){
+ return Crypto::generateNonce(this->client_nonce, NONCE_LEN);
+} /* End of generateClientNonce() */
+
+
+/** Generates a random nonce which is, if possible, cryptographically secure.
+ * This method is used by the Echo server to generate its own nonce for the
+ * initial NEP_HANDSHAKE_SERVER message */
+int NEPContext::generateServerNonce(){
+ return Crypto::generateNonce(this->server_nonce, NONCE_LEN);
+} /* End of generateServerNonce() */
+
+
+/** This method is used by the Echo server to store the initial nonce received
+ * from the client. */
+int NEPContext::setClientNonce(u8 *buff){
+ if(buff==NULL)
+ return OP_FAILURE;
+ else{
+ memcpy(this->client_nonce, buff, NONCE_LEN);
+ this->client_nonce_set=true;
+ }
+ return OP_SUCCESS;
+} /* End of setClientNonce() */
+
+
+/** This method is used by the Echo client to store the initial nonce received
+ * from the server. */
+int NEPContext::setServerNonce(u8 *buff){
+ if(buff==NULL)
+ return OP_FAILURE;
+ else{
+ memcpy(this->server_nonce, buff, NONCE_LEN);
+ this->server_nonce_set=true;
+ }
+ return OP_SUCCESS;
+} /* End of setServerNonce() */
+
+
+u8 *NEPContext::getClientNonce(){
+ return this->client_nonce;
+} /* End of getClientNonce() */
+
+
+u8 *NEPContext::getServerNonce(){
+ return this->server_nonce;
+} /* End of getServerNonce() */
+
+
+/** Adds a field specifier, received from the client in a NEP_PACKET_SPEC
+ * message. */
+int NEPContext::addClientFieldSpec(u8 field, u8 len, u8 *value){
+ fspec_t t;
+ if(value==NULL){
+ return OP_FAILURE;
+ }else{
+ t.field=field;
+ t.len=MIN(len, PACKETSPEC_FIELD_LEN);
+ memcpy(t.value, value, t.len);
+ this->fspecs.push_back(t);
+ }
+ return OP_SUCCESS;
+} /* End of addClientFieldSpec() */
+
+
+/** Returns a pointer to the N-th client's field specifier. Callers should start
+ * passing 0 and then incrementing the index by one until it returns NULL */
+fspec_t *NEPContext::getClientFieldSpec(int index){
+ if(index<0 || index>=(int)this->fspecs.size() )
+ return NULL;
+ else
+ return &(this->fspecs[index]);
+} /* End of getClientFieldSpec() */
+
+
+/** Returns true if we already have a packet spec of the same type. This
+ * method should be called for EVERY spec in a NEP_PACKET_SPEC message, to
+ * ensure that malicious clients are not supplying the same spec repeatedly
+ * to increase their packet score. */
+bool NEPContext::isDuplicateFieldSpec(u8 test_field){
+ int i=0;
+ fspec_t *spec=NULL;
+
+ /* Iterate through the list of stored specs and determine if we already
+ have a spec of the same type. */
+ while( (spec=this->getClientFieldSpec(i++))!=NULL ){
+ if(spec->field==test_field)
+ return true;
+ }
+ return false;
+} /* End of isDuplicateFieldSpect() */
+
+
+/** Deletes all previous field specifiers. This should be used when dealing
+ * with clients that send multiple NEP_PACKET_SPEC messages, so only the last
+ * PacketSpec is taken into account. */
+int NEPContext::resetClientFieldSpecs(){
+ this->fspecs.clear();
+ return OP_SUCCESS;
+} /* End of resetClientFieldSpecs() */