From 5d7f509f1a98c2d45870e3877b4d7bfa756d2d2a Mon Sep 17 00:00:00 2001 From: pennae Date: Sun, 17 Jul 2022 13:21:16 +0200 Subject: use HawkKey everywhere hawk keys are handled the db already does this, crypto did not. --- src/api/auth/account.rs | 26 +++++++++++--------------- src/api/auth/mod.rs | 25 ++++++------------------- src/api/auth/oauth.rs | 12 +++--------- src/api/auth/password.rs | 35 +++++++---------------------------- src/auth.rs | 7 +++---- src/crypto.rs | 24 ++++++++++++++---------- 6 files changed, 44 insertions(+), 85 deletions(-) diff --git a/src/api/auth/account.rs b/src/api/auth/account.rs index c0c2099..bff2a66 100644 --- a/src/api/auth/account.rs +++ b/src/api/auth/account.rs @@ -15,14 +15,14 @@ use crate::crypto::{KeyFetchToken, SessionToken}; use crate::db::{Db, DbConn}; use crate::mailer::Mailer; use crate::push::PushClient; -use crate::types::AccountResetID; +use crate::types::{AccountResetID, HawkKey}; use crate::utils::DeferAction; use crate::Config; use crate::{ api::{auth, serialize_dt}, auth::{AuthSource, Authenticated}, crypto::{AuthPW, KeyBundle, KeyFetchReq, SecretBytes, SessionCredentials}, - types::{HawkKey, KeyFetchID, OauthToken, SecretKey, User, UserID, VerifyHash}, + types::{KeyFetchID, OauthToken, SecretKey, User, UserID, VerifyHash}, }; // TODO better error handling @@ -104,7 +104,7 @@ pub(crate) async fn create( ka: ka.clone(), wrap_kb: stretched.decrypt_wwkb(&wrapwrap_kb), }); - db.add_key_fetch(req.token_id, &HawkKey(req.req_hmac_key.0), &wrapped).await?; + db.add_key_fetch(req.token_id, &req.req_hmac_key, &wrapped).await?; Some(key_fetch_token) } else { None @@ -120,9 +120,8 @@ pub(crate) async fn create( verified: false, }) .await?; - let auth_at = db - .add_session(session.token_id.clone(), &uid, HawkKey(session.req_hmac_key.0), false, None) - .await?; + let auth_at = + db.add_session(session.token_id.clone(), &uid, session.req_hmac_key, false, None).await?; let verify_code = hex::encode(&SecretBytes::<16>::generate().0); db.add_verify_code(&uid, &session.token_id, &verify_code).await?; // NOTE we send the email in this context rather than a spawn to signal @@ -208,7 +207,7 @@ pub(crate) async fn login( ka: SecretBytes(user.ka.0), wrap_kb: stretched.decrypt_wwkb(&SecretBytes(user.wrapwrap_kb.0)), }); - db.add_key_fetch(req.token_id, &HawkKey(req.req_hmac_key.0), &wrapped).await?; + db.add_key_fetch(req.token_id, &req.req_hmac_key, &wrapped).await?; Some(key_fetch_token) } else { None @@ -219,7 +218,7 @@ pub(crate) async fn login( .add_session( session.token_id.clone(), &uid, - HawkKey(session.req_hmac_key.0), + session.req_hmac_key, false, Some(&verify_code), ) @@ -308,10 +307,10 @@ pub(crate) struct WithKeyFetch; impl AuthSource for WithKeyFetch { type ID = KeyFetchID; type Context = Vec; - async fn hawk(r: &Request<'_>, id: &KeyFetchID) -> Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &KeyFetchID) -> Result<(HawkKey, Self::Context)> { let db = Authenticated::<(), Self>::get_conn(r).await?; db.always_commit().await?; - Ok(db.finish_key_fetch(id).await.map(|(h, ks)| (SecretBytes(h.0), ks))?) + Ok(db.finish_key_fetch(id).await?) } async fn bearer_token(_: &Request<'_>, _: &OauthToken) -> Result<(KeyFetchID, Self::Context)> { // key fetch tokens are only valid in hawk requests @@ -335,17 +334,14 @@ pub(crate) struct WithResetToken; impl AuthSource for WithResetToken { type ID = AccountResetID; type Context = UserID; - async fn hawk( - r: &Request<'_>, - id: &AccountResetID, - ) -> Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &AccountResetID) -> Result<(HawkKey, Self::Context)> { // unlike key fetch we'll use a separate transaction here since the body of the // handler can fail. let pool = <&Db as FromRequest>::from_request(r) .await .success_or_else(|| anyhow!("could not open db connection"))?; let db = pool.begin().await?; - let result = db.finish_account_reset(id).await.map(|(h, ctx)| (SecretBytes(h.0), ctx))?; + let result = db.finish_account_reset(id).await?; db.commit().await?; Ok(result) } diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index d50dcc2..a2a94e0 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -8,8 +8,7 @@ use serde_json::json; use crate::{ auth::Authenticated, - crypto::SecretBytes, - types::{OauthToken, SessionID, UserSession}, + types::{HawkKey, OauthToken, SessionID, UserSession}, }; pub(crate) mod account; @@ -140,13 +139,10 @@ pub(crate) struct WithFxaLogin; impl crate::auth::AuthSource for WithFxaLogin { type ID = SessionID; type Context = UserSession; - async fn hawk( - r: &Request<'_>, - id: &SessionID, - ) -> anyhow::Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &SessionID) -> anyhow::Result<(HawkKey, Self::Context)> { let db = Authenticated::<(), Self>::get_conn(r).await?; let k = db.use_session(id).await?; - Ok((SecretBytes(k.req_hmac_key.0), k)) + Ok((k.req_hmac_key.clone(), k)) } async fn bearer_token( _: &Request<'_>, @@ -163,10 +159,7 @@ pub(crate) struct WithVerifiedFxaLogin; impl crate::auth::AuthSource for WithVerifiedFxaLogin { type ID = SessionID; type Context = UserSession; - async fn hawk( - r: &Request<'_>, - id: &SessionID, - ) -> anyhow::Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &SessionID) -> anyhow::Result<(HawkKey, Self::Context)> { let res = WithFxaLogin::hawk(r, id).await?; match res.1.verified { true => Ok(res), @@ -191,10 +184,7 @@ pub(crate) struct WithSession; impl crate::auth::AuthSource for WithSession { type ID = SessionID; type Context = UserSession; - async fn hawk( - r: &Request<'_>, - id: &SessionID, - ) -> anyhow::Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &SessionID) -> anyhow::Result<(HawkKey, Self::Context)> { WithFxaLogin::hawk(r, id).await } async fn bearer_token( @@ -213,10 +203,7 @@ pub(crate) struct WithVerifiedSession; impl crate::auth::AuthSource for WithVerifiedSession { type ID = SessionID; type Context = UserSession; - async fn hawk( - r: &Request<'_>, - id: &SessionID, - ) -> anyhow::Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &SessionID) -> anyhow::Result<(HawkKey, Self::Context)> { WithVerifiedFxaLogin::hawk(r, id).await } async fn bearer_token( diff --git a/src/api/auth/oauth.rs b/src/api/auth/oauth.rs index c159352..28d9fb2 100644 --- a/src/api/auth/oauth.rs +++ b/src/api/auth/oauth.rs @@ -17,7 +17,7 @@ use crate::{ auth::Authenticated, crypto::SessionCredentials, types::{ - HawkKey, OauthAccessToken, OauthAccessType, OauthAuthorization, OauthAuthorizationID, + OauthAccessToken, OauthAccessType, OauthAuthorization, OauthAuthorizationID, OauthRefreshToken, OauthToken, OauthTokenID, SessionID, UserID, }, }; @@ -394,14 +394,8 @@ async fn token_impl( let (session_token, session_id) = if scope.implies(&SESSION_SCOPE) { let session_token = SessionToken::generate(); let session = SessionCredentials::derive_from(&session_token); - db.add_session( - session.token_id.clone(), - &user_id, - HawkKey(session.req_hmac_key.0), - true, - None, - ) - .await?; + db.add_session(session.token_id.clone(), &user_id, session.req_hmac_key, true, None) + .await?; (Some(session_token), Some(session.token_id)) } else { (None, None) diff --git a/src/api/auth/password.rs b/src/api/auth/password.rs index ae5bd6d..e389261 100644 --- a/src/api/auth/password.rs +++ b/src/api/auth/password.rs @@ -15,10 +15,7 @@ use crate::{ }, db::{Db, DbConn}, mailer::Mailer, - types::{ - HawkKey, OauthToken, PasswordChangeID, SecretKey, UserID, - VerifyHash, - }, + types::{HawkKey, OauthToken, PasswordChangeID, SecretKey, UserID, VerifyHash}, }; // MISSING get /password/forgot/status @@ -70,15 +67,8 @@ pub(crate) async fn change_start( ka: SecretBytes(user.ka.0), wrap_kb: stretched.decrypt_wwkb(&SecretBytes(user.wrapwrap_kb.0)), }); - db.add_key_fetch(key_req.token_id, &HawkKey(key_req.req_hmac_key.0), &wrapped) - .await?; - db.add_password_change( - &uid, - &change_req.token_id, - &HawkKey(change_req.req_hmac_key.0), - None, - ) - .await?; + db.add_key_fetch(key_req.token_id, &key_req.req_hmac_key, &wrapped).await?; + db.add_password_change(&uid, &change_req.token_id, &change_req.req_hmac_key, None).await?; Ok(Json(ChangeStartResp { keyFetchToken: key_fetch_token, passwordChangeToken: change_token })) } @@ -92,20 +82,14 @@ pub(crate) struct WithChangeToken; impl AuthSource for WithChangeToken { type ID = PasswordChangeID; type Context = (UserID, Option); - async fn hawk( - r: &Request<'_>, - id: &PasswordChangeID, - ) -> Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(r: &Request<'_>, id: &PasswordChangeID) -> Result<(HawkKey, Self::Context)> { // unlike key fetch we'll use a separate transaction here since the body of the // handler can fail. let pool = <&Db as FromRequest>::from_request(r) .await .success_or_else(|| anyhow!("could not open db connection"))?; let db = pool.begin().await?; - let result = db - .finish_password_change(id, IS_FORGOT) - .await - .map(|(h, ctx)| (SecretBytes(h.0), ctx))?; + let result = db.finish_password_change(id, IS_FORGOT).await?; db.commit().await?; Ok(result) } @@ -215,7 +199,7 @@ pub(crate) async fn forgot_start( db.add_password_change( &uid, &forgot_req.token_id, - &HawkKey(forgot_req.req_hmac_key.0), + &forgot_req.req_hmac_key, Some(&forgot_code), ) .await?; @@ -255,12 +239,7 @@ pub(crate) async fn forgot_finish( let reset_token = AccountResetToken::generate(); let reset_req = AccountResetReq::derive_from(&reset_token); - db.add_account_reset( - &data.context.0, - &reset_req.token_id, - &HawkKey(reset_req.req_hmac_key.0), - ) - .await?; + db.add_account_reset(&data.context.0, &reset_req.token_id, &reset_req.req_hmac_key).await?; Ok(Json(ForgotFinishResp { accountResetToken: reset_token })) } diff --git a/src/auth.rs b/src/auth.rs index f56c5e2..304ab0f 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -11,17 +11,16 @@ use rocket::{request, Data, Ignite, Phase, Rocket, Sentinel}; use serde::Deserialize; use serde_json::error::Category; -use crate::crypto::SecretBytes; use crate::db::DbConn; use crate::types::oauth::ScopeSet; -use crate::types::{OauthToken, UserID}; +use crate::types::{HawkKey, OauthToken, UserID}; use crate::Config; #[rocket::async_trait] pub(crate) trait AuthSource { type ID: FromStr + Send + Sync + Clone; type Context: Send + Sync; - async fn hawk(r: &Request<'_>, id: &Self::ID) -> Result<(SecretBytes<32>, Self::Context)>; + async fn hawk(r: &Request<'_>, id: &Self::ID) -> Result<(HawkKey, Self::Context)>; async fn bearer_token(r: &Request<'_>, id: &OauthToken) -> Result<(Self::ID, Self::Context)>; } @@ -227,7 +226,7 @@ pub(crate) struct WithBearer; impl crate::auth::AuthSource for WithBearer { type ID = UserID; type Context = ScopeSet; - async fn hawk(_r: &Request<'_>, _id: &Self::ID) -> Result<(SecretBytes<32>, Self::Context)> { + async fn hawk(_r: &Request<'_>, _id: &Self::ID) -> Result<(HawkKey, Self::Context)> { bail!("hawk signatures not allowed here") } async fn bearer_token( diff --git a/src/crypto.rs b/src/crypto.rs index 7fba9cd..4413663 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -17,7 +17,7 @@ use sha2::Sha256; use crate::{ serde::as_hex, - types::{AccountResetID, KeyFetchID, PasswordChangeID, SessionID}, + types::{AccountResetID, HawkKey, KeyFetchID, PasswordChangeID, SessionID}, }; const NAMESPACE: &[u8] = b"identity.mozilla.com/picl/v1/"; @@ -191,13 +191,13 @@ impl SessionToken { pub(crate) struct SessionCredentials { pub token_id: SessionID, - pub req_hmac_key: SecretBytes<32>, + pub req_hmac_key: HawkKey, } impl SessionCredentials { pub fn derive_from(seed: &SessionToken) -> Self { let (token_id, req_hmac_key) = from_hkdf(&seed.0, &[NAMESPACE, b"sessionToken"]); - Self { token_id: SessionID(token_id), req_hmac_key } + Self { token_id: SessionID(token_id), req_hmac_key: HawkKey(req_hmac_key) } } } @@ -218,7 +218,7 @@ impl KeyFetchToken { pub(crate) struct KeyFetchReq { pub token_id: KeyFetchID, - pub req_hmac_key: SecretBytes<32>, + pub req_hmac_key: HawkKey, key_request_key: SecretBytes<32>, } @@ -226,7 +226,11 @@ impl KeyFetchReq { pub fn derive_from(key_fetch_token: &KeyFetchToken) -> Self { let (token_id, (req_hmac_key, key_request_key)) = from_hkdf(&key_fetch_token.0, &[NAMESPACE, b"keyFetchToken"]); - Self { token_id: KeyFetchID(token_id), req_hmac_key, key_request_key } + Self { + token_id: KeyFetchID(token_id), + req_hmac_key: HawkKey(req_hmac_key), + key_request_key, + } } pub fn derive_resp(&self) -> KeyFetchResp { @@ -298,18 +302,18 @@ impl PasswordChangeToken { pub(crate) struct PasswordChangeReq { pub token_id: PasswordChangeID, - pub req_hmac_key: SecretBytes<32>, + pub req_hmac_key: HawkKey, } impl PasswordChangeReq { pub fn derive_from_change_token(token: &PasswordChangeToken) -> Self { let (token_id, req_hmac_key) = from_hkdf(&token.0, &[NAMESPACE, b"passwordChangeToken"]); - Self { token_id: PasswordChangeID(token_id), req_hmac_key } + Self { token_id: PasswordChangeID(token_id), req_hmac_key: HawkKey(req_hmac_key) } } pub fn derive_from_forgot_token(token: &PasswordChangeToken) -> Self { let (token_id, req_hmac_key) = from_hkdf(&token.0, &[NAMESPACE, b"passwordForgotToken"]); - Self { token_id: PasswordChangeID(token_id), req_hmac_key } + Self { token_id: PasswordChangeID(token_id), req_hmac_key: HawkKey(req_hmac_key) } } } @@ -330,13 +334,13 @@ impl AccountResetToken { pub(crate) struct AccountResetReq { pub token_id: AccountResetID, - pub req_hmac_key: SecretBytes<32>, + pub req_hmac_key: HawkKey, } impl AccountResetReq { pub fn derive_from(token: &AccountResetToken) -> Self { let (token_id, req_hmac_key) = from_hkdf(&token.0, &[NAMESPACE, b"accountResetToken"]); - Self { token_id: AccountResetID(token_id), req_hmac_key } + Self { token_id: AccountResetID(token_id), req_hmac_key: HawkKey(req_hmac_key) } } } -- cgit v1.2.3