From e466f25ecfa356137523ee597b9fc6ab0da5df22 Mon Sep 17 00:00:00 2001 From: Yigit Sever Date: Wed, 14 Apr 2021 03:27:27 +0300 Subject: [WIP] Initial implementation of user auth There is a dance involved and everything Write down specs for RSA and AES, padding scheme, ugh. --- Cargo.lock | 169 ++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 + src/custom_filters.rs | 8 +-- src/handlers.rs | 34 +++++++++- src/lib.rs | 40 +++++++++++- src/schema.rs | 9 ++- 6 files changed, 249 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b91b30..03c6eb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "autocfg" version = "1.0.1" @@ -313,6 +319,7 @@ dependencies = [ name = "gradecoin" version = "0.1.0" dependencies = [ + "base64 0.13.0", "blake2", "chrono", "hex-literal", @@ -322,9 +329,11 @@ dependencies = [ "md-5", "parking_lot", "pretty_env_logger", + "rsa", "serde", "serde_json", "serde_test", + "sha2", "tokio", "warp", ] @@ -478,7 +487,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown", ] @@ -526,7 +535,7 @@ dependencies = [ "ring", "serde", "serde_json", - "simple_asn1", + "simple_asn1 0.4.1", ] [[package]] @@ -544,6 +553,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -551,6 +563,12 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + [[package]] name = "lock_api" version = "0.3.4" @@ -674,18 +692,58 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg", + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" +dependencies = [ + "autocfg 1.0.1", "num-integer", "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" +dependencies = [ + "autocfg 0.1.7", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.3", + "smallvec", + "zeroize", +] + [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg", + "autocfg 1.0.1", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg 1.0.1", + "num-integer", "num-traits", ] @@ -695,7 +753,8 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg", + "autocfg 1.0.1", + "libm", ] [[package]] @@ -987,6 +1046,26 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rsa" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ef841a26fc5d040ced0417c6c6a64ee851f42489df11cdf0218e545b6f8d28" +dependencies = [ + "byteorder", + "digest", + "lazy_static", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pem", + "rand 0.8.3", + "simple_asn1 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1076,6 +1155,19 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpuid-bool", + "digest", + "opaque-debug", +] + [[package]] name = "simple_asn1" version = "0.4.1" @@ -1083,8 +1175,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" dependencies = [ "chrono", - "num-bigint", + "num-bigint 0.2.6", + "num-traits", +] + +[[package]] +name = "simple_asn1" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8d597fce66eb0f19dd129b9956e4054cba21aeaf97d4116595027b670fac50" +dependencies = [ + "chrono", + "num-bigint 0.3.2", "num-traits", + "thiserror", ] [[package]] @@ -1133,6 +1237,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.2.0" @@ -1156,6 +1272,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.1.44" @@ -1550,3 +1686,24 @@ dependencies = [ "winapi 0.2.8", "winapi-build", ] + +[[package]] +name = "zeroize" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 6701daf..3b6e71e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ blake2 = "0.9.1" hex-literal = "0.3.1" jsonwebtoken = "7.2.0" md-5 = "0.9.1" +rsa = "0.4.0" +base64 = "0.13.0" +sha2 = "0.9.3" [dev-dependencies] serde_test = "1.0.117" diff --git a/src/custom_filters.rs b/src/custom_filters.rs index ae8a56c..299cd8d 100644 --- a/src/custom_filters.rs +++ b/src/custom_filters.rs @@ -1,5 +1,5 @@ /// Functions that extracts Structs to be used in warp routines -use crate::schema::{AuthRequest, Block, Db, Transaction}; +use crate::schema::{Block, Db, InitialAuthRequest, Transaction}; use std::convert::Infallible; use warp::{Filter, Rejection}; @@ -8,12 +8,12 @@ pub fn with_db(db: Db) -> impl Filter + Clo warp::any().map(move || db.clone()) } -/// Extracts an `AuthRequest` JSON body from the request +/// Extracts an `InitialAuthRequest` JSON body from the request /// Accepts only JSON encoded `AuthRequest` body and rejects big payloads /// // TODO: find a good limit for this, (=e2482057; 8 char String + rsa pem) <11-04-21, yigit> // -pub fn auth_request_json_body() -> impl Filter + Clone -{ +pub fn auth_request_json_body( +) -> impl Filter + Clone { warp::body::content_length_limit(1024 * 32).and(warp::body::json()) } diff --git a/src/handlers.rs b/src/handlers.rs index b9df931..9d1bb10 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -1,3 +1,4 @@ +use base64; /// API handlers, the ends of each filter chain use blake2::{Blake2s, Digest}; use jsonwebtoken::errors::ErrorKind; @@ -5,12 +6,16 @@ use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; use log::{debug, warn}; use md5::Md5; use parking_lot::RwLockUpgradableReadGuard; +use rsa::{PaddingScheme, RSAPrivateKey}; use serde::Serialize; use serde_json; +use sha2; use std::convert::Infallible; use std::fs; use warp::{http::StatusCode, reply}; +use crate::PRIVATE_KEY; + #[derive(Serialize, Debug)] struct GradeCoinResponse { res: ResponseType, @@ -23,7 +28,9 @@ enum ResponseType { Error, } -use crate::schema::{AuthRequest, Block, Claims, Db, MetuId, NakedBlock, Transaction, User}; +use crate::schema::{ + AuthRequest, Block, Claims, Db, InitialAuthRequest, MetuId, NakedBlock, Transaction, User, +}; const BEARER: &str = "Bearer "; @@ -32,11 +39,34 @@ const BEARER: &str = "Bearer "; /// Lets a [`User`] (=student) to authenticate themselves to the system /// This `request` can be rejected if the payload is malformed (= not authenticated properly) or if /// the [`AuthRequest.user_id`] of the `request` is not in the list of users that can hold a Gradecoin account +/// The request first comes in encrypted pub async fn authenticate_user( - request: AuthRequest, + request: InitialAuthRequest, db: Db, ) -> Result { debug!("POST request to /register, authenticate_user"); + + // TODO: lazyload or something <14-04-21, yigit> // + let der_encoded = PRIVATE_KEY + .lines() + .filter(|line| !line.starts_with("-")) + .fold(String::new(), |mut data, line| { + data.push_str(&line); + data + }); + let der_bytes = base64::decode(&der_encoded).expect("failed to decode base64 content"); + let private_key = RSAPrivateKey::from_pkcs1(&der_bytes).expect("failed to parse key"); + + let padding = PaddingScheme::new_oaep::(); + let dec_key = private_key + .decrypt(padding, &request.key.as_bytes()) + .expect("failed to decrypt"); + + // then decrypt c using key dec_key + + // let request: AuthRequest = serde_json::from_str(&String::from_utf8(dec_data).unwrap()).unwrap(); + let request; + let provided_id = request.student_id.clone(); let priv_student_id = match MetuId::new(request.student_id, request.passwd) { diff --git a/src/lib.rs b/src/lib.rs index 42def0f..7a24f9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,45 @@ //! `Authorization`: The request header should have Bearer JWT.Token signed with Student Public Key pub mod custom_filters; +pub mod error; pub mod handlers; pub mod routes; pub mod schema; -pub mod error; + +pub const PRIVATE_KEY: &'static str = "-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAyGuqiCPGcguy+Y9TH7Bl7XlEsalyqb9bYlzpbV0dnqZ3lPkE +PkuOhkN+GcuiV6iXtSwyh7nB+xTRXKJFRUBO/jbN8jfcxVwBu0JxjF3v1YRBxbOH +hz2A295mbKD9xHQCKxkfYBNkUXxj8gd+GaDvQiSW5NdrX/lEkvqfGtdEX1m2+Hdc +G0+3YW24Xg0znhCwLr+sorLuJaDy9Xa0Uo+DPWGC5s001U/BxkCIWJ+eJQCb7Bv+ +9vXb8BGRK/ecMb/fb6h5O+8fgB64RCHMgcc2v+Q/dPt8kHX1OJdMuYUrUJGACppM +QY3W6e1HdlRIBcZKL2LMZ2CrIB/2D5LiJhPThQIDAQABAoIBABbHrg1lS5QA4mnd +MYyDh0JTq0wqP18t4dwvRVTp5Yj30NW87A+MlPmLyFR0QdKG1h+Ak4m7wmGgfx9x +TkBNy+y3G/dxBAXmrEe1iKR0tOLm8nbfLgNgKTpUb/3e2pkuumRdqaRI7/kXE2Ea +Guoc0bUJ5aDDH3A8K+As3lK1rw7LNxwxZdmqmpO+EAldP6NaLnXNP5BegjLK50xP +NXTDNx6pw+I2ZHHwC/A6+QVksSA6zPipI1poANaO0frHffwKhcEZ/VucuXlJGGq/ +aqXT/cc7IkKUVq8EZUwUqHi4SrnyDDq/mtuikSD0MazxumbeC6fBKRP98Kavy2rT +JItHSYECgYEA8H/yC9GDrR1bwBesD0pKdKBy18UMFQF3BrB04OjqdGzugdVafF4e +7azYQQTQ0ZddLDvgYl0QYvQaZfv26L7o4VrN5XEg8WjUWKuww8XUYOCfPn4gOFL1 +ar8nQ0w3P65gYf/rw0rFMo3eB78rJMROYnG8nZ/3OdgQjVaYPJxFKmECgYEA1VZy +EQz8dHK3+F0EfQIFeXOSlYGUegmPZ9iYmh+yvW/zWKLYdXBEHNhAIRlBmfe7Yhj6 +1FNluNGjFqZYuRnP0RuiBxt2RCd+AL90Lqq+O6jem4XNgr3cOKoaV0FbaU49sI4s +/B6iiYBFdVuPBiknz+Wf1KEF9lQ+w2VYSLucY6UCgYAWPe73ste3sehjWo0aGOfL +427bj6ivZKRKZRVaG5BbVhu0vDOTHu1DU+HoGXbqe1ItnhgBYNP8ItEyL1xFaCqH +dOtn1c+TI/vHe5FseaZLk1qG4AlAzENQLP+HlMvjQtA9H/sA47BbHY20L7TgwJrz +NcuY1Et7+QSG3cRUjqtC4QKBgGuP+VUVehfwW0dzBrdMlJwGpGqS+dyKA271awOS +ZdlTn5saCA82OnFcqwDFLilGGYk9VQJGxivoLtVVq7gwBnLE/u2ccAWu773KyfZZ +ii6kVxCM5vA7b9R2F2/U+RTgKQRiutWnUIYJUXv5XORbTcJpYSugwFPRaA+2gkux +pAktAoGABRyVs5LOhQ/oeXe2H2kvuaUq9c7f/dTtnyMNdNxK0uZcQn4jcB2eK9kB +PDYHM9dfQ8xn51U0fTeaXjy/8Km8fyX2Jtxntlm6puyhSTJ8AX+FEgJkC4ajNEvA +mJ1Gsy2fXKUyyZdI2b74MLqOpzr9cvS60tmTIScuiHFzg/SJgiA= +-----END RSA PRIVATE KEY-----"; + +pub const PUB_KEY: &'static str = "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGuqiCPGcguy+Y9TH7Bl +7XlEsalyqb9bYlzpbV0dnqZ3lPkEPkuOhkN+GcuiV6iXtSwyh7nB+xTRXKJFRUBO +/jbN8jfcxVwBu0JxjF3v1YRBxbOHhz2A295mbKD9xHQCKxkfYBNkUXxj8gd+GaDv +QiSW5NdrX/lEkvqfGtdEX1m2+HdcG0+3YW24Xg0znhCwLr+sorLuJaDy9Xa0Uo+D +PWGC5s001U/BxkCIWJ+eJQCb7Bv+9vXb8BGRK/ecMb/fb6h5O+8fgB64RCHMgcc2 +v+Q/dPt8kHX1OJdMuYUrUJGACppMQY3W6e1HdlRIBcZKL2LMZ2CrIB/2D5LiJhPT +hQIDAQAB +-----END PUBLIC KEY-----"; diff --git a/src/schema.rs b/src/schema.rs index 9e157c7..f159d83 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -178,7 +178,7 @@ pub struct MetuId { passwd: String, } -// TODO: this will arrive encrypted <13-04-21, yigit> // +/// The plaintext of the initial user authentication request #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct AuthRequest { pub student_id: String, @@ -186,6 +186,13 @@ pub struct AuthRequest { pub public_key: String, } +/// Ciphertext of the initial authentication request, or what we will receive +#[derive(Serialize, Deserialize, Debug)] +pub struct InitialAuthRequest { + pub c: String, + pub key: String, +} + lazy_static! { static ref OUR_STUDENTS: HashSet<(&'static str, &'static str)> = { [ -- cgit v1.2.3-70-g09d2