From 237fa34e91d8c1833c2dbd0244929669c271ab5e Mon Sep 17 00:00:00 2001
From: Yigit Sever
Date: Thu, 15 Apr 2021 14:30:41 +0300
Subject: Cleaned up user authentication

Removed TODOs, unrolled unwraps
---
 src/handlers.rs | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/schema.rs   |   2 +-
 2 files changed, 123 insertions(+), 15 deletions(-)

diff --git a/src/handlers.rs b/src/handlers.rs
index 848cb75..515caa5 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -60,9 +60,9 @@ const BEARER: &str = "Bearer ";
 ///     public_key: "---BEGIN PUBLIC KEY..."
 /// }
 ///
-/// - Encrypts the serialized string of `auth_plaintext` with 128 bit block AES in CBC mode with Pkcs7 padding using the temporary key (`k_temp`), the result is `auth_ciphertext` TODO should this be base64'd?
+/// - Encrypts the serialized string of `auth_plaintext` with 128 bit block AES in CBC mode with Pkcs7 padding using the temporary key (`k_temp`), the result is `auth_ciphertext`
 /// - The temporary key student has picked `k_temp` is encrypted using RSA with OAEP padding scheme
-/// using sha256 with `gradecoin_public_key` (TODO base64? same as above), giving us `key_ciphertext`
+/// using sha256 with `gradecoin_public_key`, giving us `key_ciphertext`
 /// - The payload JSON object (`auth_request`) can be JSON serialized now:
 /// {
 ///     c: "auth_ciphertext"
@@ -103,18 +103,126 @@ pub async fn authenticate_user(
     let gradecoin_private_key = RSAPrivateKey::from_pkcs1(&der_bytes).expect("failed to parse key");
 
     let padding = PaddingScheme::new_oaep::<sha2::Sha256>();
-    let temp_key = gradecoin_private_key
-        .decrypt(padding, &request.key.as_bytes())
-        .expect("failed to decrypt");
-
-    // decrypt c using key dec_key
-    let cipher = Aes128Cbc::new_var(&temp_key, &request.iv.as_bytes()).unwrap();
-    let auth_plaintext = cipher
-        .decrypt_vec(&base64::decode(request.c).unwrap())
-        .unwrap();
-
-    let request: AuthRequest =
-        serde_json::from_str(&String::from_utf8(auth_plaintext).unwrap()).unwrap();
+
+    let key_ciphertext = match base64::decode(&request.key) {
+        Ok(c) => c,
+        Err(err) => {
+            debug!(
+                "The ciphertext of the key was not base64 encoded {}, {}",
+                &request.key, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "The ciphertext of the key was not base64 encoded {}, {}".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let temp_key = match gradecoin_private_key.decrypt(padding, &key_ciphertext) {
+        Ok(k) => k,
+        Err(err) => {
+            debug!(
+                "Failed to decrypt ciphertext {:?}, {}",
+                &key_ciphertext, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "Failed to decrypt the ciphertext of the temporary key".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let cipher = match Aes128Cbc::new_var(&temp_key, &request.iv.as_bytes()) {
+        Ok(c) => c,
+        Err(err) => {
+            debug!(
+                "Could not create a cipher from temp_key and request.iv {:?}, {}, {}",
+                &temp_key, &request.iv, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "Given IV has invalid length".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let auth_packet = match base64::decode(&request.c) {
+        Ok(a) => a,
+
+        Err(err) => {
+            debug!(
+                "The auth_packet (c field) did not base64 decode {} {}",
+                &request.c, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "The c field was not correctly base64 encoded".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let auth_plaintext = match cipher.decrypt_vec(&auth_packet) {
+        Ok(p) => p,
+        Err(err) => {
+            debug!(
+                "Base64 decoded auth request did not decrypt correctly {:?} {}",
+                &auth_packet, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "The Bas64 decoded auth request did not decrypt correctly".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let utf8_auth_plaintext = match String::from_utf8(auth_plaintext.clone()) {
+        Ok(text) => text,
+        Err(err) => {
+            debug!(
+                "Auth plaintext did not convert into utf8 {:?} {}",
+                &auth_plaintext, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "Auth plaintext couldn't get converted to UTF-8".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
+
+    let request: AuthRequest = match serde_json::from_str(&utf8_auth_plaintext) {
+        Ok(req) => req,
+        Err(err) => {
+            debug!(
+                "Auth plaintext did not serialize correctly {:?} {}",
+                &utf8_auth_plaintext, err
+            );
+
+            let res_json = warp::reply::json(&GradeCoinResponse {
+                res: ResponseType::Error,
+                message: "The auth request JSON did not serialize correctly".to_owned(),
+            });
+
+            return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST));
+        }
+    };
 
     let provided_id = request.student_id.clone();
 
diff --git a/src/schema.rs b/src/schema.rs
index 6f2f1f3..dca0eef 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -163,7 +163,7 @@ impl Block {
         Block {
             transaction_list: vec!["gradecoin_bank".to_owned()],
             nonce: 0,
-            timestamp: NaiveDate::from_ymd(2021, 04, 11).and_hms(20, 45, 00),
+            timestamp: NaiveDate::from_ymd(2021, 4, 11).and_hms(20, 45, 00),
             hash: String::from("not_actually_mined"),
         }
     }
-- 
cgit v1.2.3-70-g09d2