Final Project
Weifan Jiang (wj2301@columbia.edu)
Haotang Liu (hl3311@columbia.edu)
Yuan Xu (yx2537@columbia.edu)
A demonstration video of our project is available here. Lionmail account is required.
Install
install the project
- Setting up the ca: run
./setupca.sh
- Under
CAserver
folder- Run
./setcaserverkeypair.sh
- Run
make
- Run
- Under
server
folder,- Run
./setmailserverkeypair.sh
- Run
make
- Run
- Under
client
folder- Run
./getcacert.sh
- To install a client for a user, run
make install USER=<username>
. For example, runmake install USER=overrich
to get a client foroverrich
. There will be aclient-overrich
under the parent folder. Create more than 1 client for testing.
- Run
Note: the CAserver/config
, server/config
and client/config
files contain the ip addresses and por
numbers that each component hosts on and/or connects to. The current configurations allow three components
to run on one VM. If need to run on separate VMs, it is necessary to change the configuration files with
appropriate ip addresses and port numbers, and the ip/port for the same component in different files
must match. Once the project is compiled, three components: "client/
", "server/
", "CAserver
and ca
"
can be moved to different VMs.
required packages
The following commands can install required packages for the project that are not included in the default Google Cloud VM.
sudo apt-get install build-essential
sudo apt-get install -y libssl-dev
sudo apt install whois
Design
sandboxing
The program is divided into three components: client, mailing server, and CA server. The client sends requests to mailing server, and mailing server sends request to CA server for password verification and certificate generation. The three components are designed to be placed on separate VMs and communicate with HTTPS. The list of users and hashed passwords are stored with the CA. This architecture ensures that if the mailing server is compromised, the passwords and the CA private key will not leak.
encryption/decryption
The general idea of our mail encryption/decryption and authenticity verification:
- We use the symmetric encryption algorithm to encrypt/decrypt messages since:
- symmetric algorithm is faster
- OpenSSL does not support asymmetric algorithm over large files.
- We encrypt the key for the symmetric algorithm using the recipient's public key to utilize the advantage of the asymmetric encryption algorithm. Thus the recipient could decrypt it using its private key.
- For each <sender, recipient> pair, we maintain a unique id for every message. This pair could prevent the server from delivering the same one-time message to the sender again and again.
- For authenticity verification, the sender will sign the mail using its private key while the recipient will verify it using the sender's public key. Thus, we include the sender's client certificate in our mail, which will indicate the sender's identity and generate its public key. This sender's certificate also needs to be encrypted. Otherwise, chances could be that someone else (for example, the server) substitutes its certificate and the mail's signature, and the recipient cannot sense it.
- To sum up, our mail include 3 parts: (a) encrypted key (b) [id | encrypt(cert | msg)] (c) sign( [id | encrypt(cert | msg)] ). When receiving a mail, the receiver first decrypts the key for encryption, decrypts the sender's cert and message, and finally checks the id for this mail and verifies the signature.
The login logic of users using its client certificate:
- The user sends its certificate to the server. The server could verify the authenticity of the certificate by comparing it with the one it previously recorded.
- The server encrypts a random number using the public key obtained from the cert and sends it to the user to confirm that the user is the one who actually holds the certificate.
- Only those with the corresponding private key could decrypt the number correctly, which means the user could verify its authenticity by sending the correct original random number to the server.
detailed steps
sendmsg
- The client (sender) sends its certificate, a list of recipient names, and a message to the server.
- The server verifies the sender's certificate using the ca's certificate, then uses the public key derived from - the sender's certificate to encrypt a random number r and send the encrypted random number e(r) to the sender.
- The sender uses its private key to decrypt e(r), send r to the server.
- The server checks if the random number received matches the one it sent before, sends all the recipient's certificates to the sender.
- For each recipient, the sender use the recipient's public key from the certificate to encrypt a symmetric key, sends (a) encrypted key (b) [id | encrypt(cert | msg)] (c) sign( [id | encrypt(cert | msg)] ) 3 components to the mail server.
recvmsg
- The client (recipient) sends its certificate to the server.
- The server verifies the recipient certificate using the ca's certificate and then checks if the certificate matches the one stored on the server.
- "Random number identity verification"
- The server sends the message package to the recipient
- The recipient uses its private key to decrypt the symmetric key, checks the message's id, decrypt the message using the symmetric key, checks the sender's certificate, and check the signature using the sender's public key.
getcert
- The client generates a CSR, sends username, password, and CSR to the server.
- The server checks if the user's mailbox is empty, then forwards username, password, and CSR to CAserver.
- The CA server checks the user-password database; if it matches, it sends the user's certificate to the server; otherwise, it sends back an error code.
- The server gets the CA server's response, updates its certificate database, and sends the certificate to the user.
changepw
- The client sends the username, old password, and new password to the server.
- The server checks if the user's mailbox is empty, then forwards username, old password, and new CSR to CAserver.
- CA server checks and updates its user-password database, generates a new certificate and responds to the server.
- The server gets the CA server's response, updates its certificate database, and sends the new certificate to the user.
File layout
4181-final/
├── CAserver
│ ├── CAserver.cpp
│ ├── Makefile
│ ├── clear_password_db.sh
│ ├── config
│ ├── initial_users.txt
│ ├── password_permissions.sh
│ ├── setcaserverkeypair.sh
│ └── sgencert.sh
├── README.md
├── client
│ ├── Makefile
│ ├── cgencsr.sh
│ ├── changepw.cpp
│ ├── client_helper.hpp
│ ├── config
│ ├── getcacert.sh
│ ├── getcert.cpp
│ ├── openssl.cnf
│ ├── recvmsg.cpp
│ ├── sendmsg.cpp
│ └── test.txt
├── server
│ ├── Makefile
│ ├── config
│ ├── create-folders.sh
│ ├── server.cpp
│ └── setmailserverkeypair.sh
└── setupca.sh
File permission decisions
On the CA side, the passwords are saved as user_passwords.txt
, and the executable CAserver
hosts a
HTTPS server and handles requests from the mailing server.
The permission of user_passwords.txt
is set as follows:
-rw-rw---- 1 root CAserver_D6ijQa 4123 Dec 24 04:43 user_passwords.txt
The permission of the CAserver
executable is set as follows:
-rwxrwsr-x 1 wj2301 CAserver_D6ijQa 171112 Dec 24 04:43 CAserver
The group name CAserver_D6ijQa
is randomly generated when setting up the server. These permission settings
ensure that on the VM which the CA is hosted on, only the CA server application and root can read and modify
the password database.
Testing
- Under
CAserver
folder- Run
./CAserver
- Run
- Under
server
folder,- Run
./server
- Run
1. all good
- Install 3 clients: overrich, unrosed and addleness
- Generate certificates for the two users:
- Under
client-overrich
, run./getcert overrich Freemasonry_bruskest
- Test
changepw
: run./changepw overrich Freemasonry_bruskest 123
- Test
- Under
client-unrosed
, run./getcert unrosed shamed_Dow
- Under
client-addleness
, run./getcert addleness Cardin_pwns
- Under
- Send message from
overrich
tounrosed
andaddleness
- Under
client-overrich
, run./sendmsg unrosed addleness test.txt
- Under
client-unrosed
, run./recvmsg
- Under
client-addleness
, run./recvmsg
- Under
2. wrong password
- Install a client for
addleness
- Under
client-addleness
, run./getcert unrosed <wrong password>
3. getcert and changepw with not empty mailbox
- Install two clients for
overrich
andunrosed
getcert
foroverrich
andunrosed
overrich
sends a message tounrosed
- run
getcert
andchangepw
underunrosed
unrosed
cannot get a new certificate or change its password
4. one of the recipients doesn't have a certificate
- Install 3 clients: overrich, unrosed and addleness
- Generate certificates for the overrich and unrosed
- Send message from
overrich
tounrosed
andaddleness
- Under
client-overrich
, run./sendmsg unrosed addleness test.txt
- Under
client-unrosed
, run./recvmsg
- Under
addleness
can stillgetcert
andchangepw
. Its mailbox on the server is empty
5. server delivers the same mail for multiple times
- Install 3 clients:
overrish
,unrosed
- Generate certificates for the
overrich
andunrosed
- Under
client-overrich
, run./sendmsg unrosed test.txt
- Under
server/messages/unrosed
, runcp -r 00000 00001
- Under
client-unrosed
, run./recvmsg
for 2 times. The second mail would show "id corrupted."