Skip to content

Programming Assignment 3 – Secured chat application - Reykjavik University

Notifications You must be signed in to change notification settings

scr4bble/TSAM-P3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

/*
 * Programming Assignment 3 – Secured chat application
 *
 * Team:
 * Einar Örn Gissurarson <[email protected]>
 * Óskar Örn <[email protected]>
 * Peter Hostačný <[email protected]>
 */


===============================================================================

                         =======================
                         ||     PROTOCOL      ||
                         =======================


 Our chat application is implemented as a client/server architecture.
 Designed protocol is very simple - packets consist only of opcode (4 bytes)
 and data. Opcode is stored in binary form inside packet. Data are created by
 user and thus it will be probably ASCII sequence of characters but server must
 be able to handle also binary data.

 Detailed description of possible opcodes is bellow. All opcodes are listed
 inside enumeration types in chat_common.h.


 Packet example:

  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ...              MAX_PACKET_SIZE
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |opcode |                     data                              |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


                     ==============================
                     || CLIENT_TO_SERVER_OPCODES ||
                     ==============================

 ### Query packets:

 OPCODE: WHO
COMMAND: /who   # print list of all users
 PACKET: <WHO>

 OPCODE: LIST
COMMAND: /list   # print list of all rooms
 PACKET: <LIST>


 ### Control packets:

 OPCODE: JOIN
COMMAND: /join <room>   # join the room
 PACKET: <JOIN> + <room>

 OPCODE: USER
COMMAND: /user <username>   # log in
 PACKET: <USER> + <username> + WHITESPACE + <password>


 ### Message packets:

 OPCODE: SAY
COMMAND: /say <username> <msg>   # private message
 PACKET: <SAY> + <username> + WHITESPACE + <message>

 OPCODE: MSG
COMMAND: <message>  # room message
 PACKET: <MSG> + <message>


 ### Game packets:

 OPCODE: GAME
COMMAND: /game <username>   # challenge user to play a game
 PACKET: <GAME> + <username>

 OPCODE: ROLL
COMMAND: /roll    # roll a number
 PACKET: <ROLL>

 OPCODE: ACCEPT
COMMAND: /roll    # accept game
 PACKET: <ACCEPT>

 OPCODE: DECLINE
COMMAND: /decline    # decline game
 PACKET: <DECLINE>

Commands /bye and /quit just close the connection. No packet is sent to server.


                     ==============================
                     || SERVER_TO_CLIENT_OPCODES ||
                     ==============================

 OPCODE: ERROR   // error message from server
 PACKET: <ERROR> + <message>


 OPCODE: INFO   // info message from server
 PACKET: <INFO> + <message>


 OPCODE: CHANGE_ROOM   // user's room was successfully changed
 PACKET: <CHANGE_ROOM> + <room>


 OPCODE: LOGGED_IN   // user was successfully logged into existing account
 PACKET: <LOGGED_IN> + <username>


 OPCODE: USER_CREATED   // same as LOGGED_IN but new user was created
 PACKET: <USER_CREATED> + <username>


 OPCODE: ROOM_MESSAGE   // new chat message inside room
 PACKET: <ROOM_MESSAGE> + <sender_username> + <message>


 OPCODE: PRIVATE_MESSAGE_SENT   // notification about delivered message
                                // sent to the sender
 PACKET: <PRIVATE_MESSAGE_SENT> + <recipient_username> + " " + <message>


 OPCODE: PRIVATE_MESSAGE_RECEIVED   // private message sent to the recipient
 PACKET: <PRIVATE_MESSAGE_RECEIVED> + <sender_username> + " " + <message>


 OPCODE: CHALLENGE   // challenge from another user (game)
 PACKET: <CHALLENGE> + <challenger>


// this opcode is not part of communication protocol
// it is just for internal use of chat client
 OPCODE: CLIENT_ERROR   // error message from the client
 PACKET: <CLIENT_ERROR> + <message>


================================================================================

                         =======================
                         ||      Answers      ||
                         =======================

6.2. Answers:

 Passwords are stored in a hashed form together with salt strings inside
 'passwords.ini' file.

 Client application sends password to the server in a plain text form. Since
 communication is encrypted, possible eavesdropper cannot retrieve it from
 packets. He could do that only in the case, he would get access to client's
 device and replaces the CA certificate before starting client application and
 do man-in-the-middle attack or get the private key of the server.

 Password is then processed through hash function (openssl/ssl.h:
 PKCS5_PBKDF2_HMAC_SHA1) together with salt string and result hash string
 is stored inside passwords file 'passwords.ini' (there is also salt string
 stored for each password).

 Parameters used for hashing passwords (chat_common.h)
        #define HASH_ITERATION 10000
        #define SIZE_OF_HASH 128
        #define SALT_LENGTH 32

7.2. Answers:

 Question about logging of private messages is in my opinion question about
 ethics. In this world, where we have enough of memory to store whole
 communication, so we can decide if we want to have possibility of searching
 inside history of client's messages. I can imagine that in some countries
 could be laws/rules for this (example: terrorist group used my server for
 communication about assassination/attack). In case I am using self-signed
 certificate even NSA probably cannot see the communication :)
 Another possibility is log only some "headers" - who communicated with who,
 what time from what IP (without storing messages).

 After all, this can be included inside Terms of Use and then it is ok to
 decide how I want.


8.2. Answers:

 If we didn't use idle and client would left his device unattended, his good
 colleagues could post some messges on his behalf. We could use some KEEP-ALIVE
 packets from client for making sure that idle time out happens on time.
 These packets would be sent only in case of device activity (moving mouse,
 typing on keyboard, etc.)


9.2. Answers:

 Our server is secure and it is not possible to cheat in this game :D
 Every check and action is performed by server and server doesn't allow users
 to use commands in bad order or cheat. Also messages about game (roll numbers,
 win message) are sent by server and since we made nice colored output, clients
 can easily differ between messages from other clients and server (example: if
 somebody loged in as SERVER his name will be grey inside chat, while server's
 messages are green/red according to their role).


================================================================================

                         ========================
                         ||   IMPLEMENTATION   ||
                         ========================

 Data inside packets are probably ASCII text but since should be able to handle
 also binary data and we didn't want to rely on such an assumption
 we implemented it in the way it can process almost any packet (with few
 restrictions preventing clients from trying to break the server).

 We use non-blocking sockets for client connections so no client can block
 the server by stucking at SSL handshake or by any message.

 Server uses select() and complicated internal structure for handling multiple
 connections. Connections are stored inside double-ended queue (glibc).

 Certificate is self-signed but until we can distribute it to all clients
 in a secure way, it provides the same level of security as CA-signed
 certificates do.

 Maximal size of one packet is specified in chat_common.h:
    #define MAX_PACKET_SIZE 1200


SERVER RESTRICTIONS:

    - User is allowed to max. 3 unsuccessful tries
      MAX_FAILED_PASSWD_TRIES constant (chat_common.h)
    - User is allowed to try next password after static delay (after failed
      attempt to login) ... FAILED_LOGIN_DELAY_TIME (chat_common.h)
    - Client is kicked out by server (connection is closed) in case of:
        - client sent unknown opcode
        - client sent packet smaller than size of opcode (4 bytes)
        - client sent packet bigger than MAX_PACKET_SIZE
        - client haven't sent any packet for MAX_IDLE_TIME (chat_common.h)


CHAT CLIENT RESTRICTIONS:

    - Chat client will split message into more messages if it exceed
      MAX_MESSAGE_SIZE (chat_common.h)
    - User is forced to use only these characters in username: "A-Za-z0-9._-|"

    - Maximal length of username is MAX_USERNAME_LENGTH (chat_common.h)
      Maximal length of password is MAX_PASSWORD_LENGTH (chat_common.h)
      (server uses dynamic data structures for these strings and
      MAX_PACKET_SIZE so he doesn't have to care about security of this and
      it is just up to client implementation)


Interesting functions in chat.c:
    - clean_and_die()  // frees memory and ends the application
    - log_msg() // takes care of all server's logging (printed to output)
    - send_packet() // takes care of transmitting all outgoing packets
            If packet was not successfully transmitted, it is added into
            write queue and server will try to transmit it right after socket
            is ready.
    - initialize_openssl() // initialize openssl structures and loads keys
    - run_loop() // server loop for serving clients
    - parse_client_message() // parse packet received from a client
    - build_and_send_packet() // build packet from opcode and message + send it

Interesting functions in chatd.c:
    - clean_and_die()  // frees memory and ends the application
    - build_and_send_packet() // build packet from opcode and message + send it
    - print_message()  // print message from server in nice format
                          (colored, with timestamp)
    - readline_callback()  // function callback for handling user's input
    - process_server_message()  // read packet from socket and process it
    - initialize_openssl() // initialize openssl structures and loads CA-cert

Interesting functions in chat_common.c:
    - recv_packet() // read packet from SSL connection and store into GString


================================================================================


Possible attacks:

    - Generate thousands of users (this could be prevented by solid database
      of users and force users to create new "accounts" by another interface -
      either by new command or through some web interface, probably using
      captcha and/or mail verification.

    - Overload server by sending too many requests/packets (for example
      spamming /who command).
      This could be prevented by disabling query commands for not authenticated
      users and/or use for these commands some limitation -
      for example min. 5 seconds delay between queries or disconnecting user
      after detecting such an activity

    - Spamming in the room could be prevented by limiting users for max.
      of 5 messages in 5 seconds.



======================
 Used commands (internal notes)
======================

- generating private key (-aes128 option for key encrypted by passphrase)
openssl genrsa -out server.key 2048

- generating public key from private key (not needed)
openssl rsa -in server.key -pubout -out server-public.key

- generating certificate
openssl req -new -x509 -days 365 -key server.key -out server.crt

- printing info about certificate
openssl x509 -text -in server.crt -noout

- checking if key matches the certificate (compare the values)
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5

About

Programming Assignment 3 – Secured chat application - Reykjavik University

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published