Skip to content

Commit

Permalink
handle max_exp_data_secs overflow (#14931)
Browse files Browse the repository at this point in the history
  • Loading branch information
zjma authored Oct 10, 2024
1 parent f28fc55 commit 543d75f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 21 deletions.
12 changes: 11 additions & 1 deletion keyless/pepper/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,14 @@ async fn process_common(
return Err(BadRequest("epk expired".to_string()));
}

if exp_date_secs >= claims.claims.iat + config.max_exp_horizon_secs {
let (max_exp_data_secs, overflowed) = claims
.claims
.iat
.overflowing_add(config.max_exp_horizon_secs);
if overflowed {
return Err(BadRequest("max_exp_data_secs overflowed".to_string()));
}
if exp_date_secs >= max_exp_data_secs {
return Err(BadRequest("epk expiry date too far".to_string()));
}

Expand Down Expand Up @@ -538,3 +545,6 @@ async fn update_account_recovery_db(input: &PepperInput) -> Result<(), Processin
},
}
}

#[cfg(test)]
mod tests;
50 changes: 50 additions & 0 deletions keyless/pepper/service/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::{process_common, ProcessingFailure};
use aptos_crypto::ed25519::Ed25519PublicKey;
use aptos_types::{
keyless::{
circuit_testcases::{
sample_jwt_payload_json_overrides, SAMPLE_EXP_DATE, SAMPLE_JWT_EXTRA_FIELD,
SAMPLE_NONCE, SAMPLE_TEST_ISS_VALUE, SAMPLE_UID_VAL,
},
test_utils::{get_sample_epk_blinder, get_sample_esk, get_sample_jwt_token_from_payload},
},
transaction::authenticator::EphemeralPublicKey,
};
use uuid::Uuid;

#[tokio::test]
async fn process_common_should_fail_if_max_exp_data_secs_overflowed() {
let session_id = Uuid::new_v4();
let sk = get_sample_esk();
let pk = Ed25519PublicKey::from(&sk);

let jwt_payload = sample_jwt_payload_json_overrides(
SAMPLE_TEST_ISS_VALUE,
SAMPLE_UID_VAL,
SAMPLE_JWT_EXTRA_FIELD.as_str(),
u64::MAX - 1, // unusual iat
SAMPLE_NONCE.as_str(),
);

let jwt = get_sample_jwt_token_from_payload(&jwt_payload);

let process_result = process_common(
&session_id,
jwt,
EphemeralPublicKey::ed25519(pk),
SAMPLE_EXP_DATE,
get_sample_epk_blinder(),
None,
None,
false,
None,
false,
)
.await;
assert!(
matches!(process_result, Err(ProcessingFailure::BadRequest(e)) if e.as_str() == "max_exp_data_secs overflowed")
);
}
42 changes: 29 additions & 13 deletions types/src/keyless/circuit_testcases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) static SAMPLE_JWT_HEADER_B64: Lazy<String> =

/// The JWT payload, decoded as JSON
static SAMPLE_NONCE: Lazy<String> = Lazy::new(|| {
pub static SAMPLE_NONCE: Lazy<String> = Lazy::new(|| {
let config = Configuration::new_for_testing();
OpenIdSig::reconstruct_oauth_nonce(
SAMPLE_EPK_BLINDER.as_slice(),
Expand All @@ -49,9 +49,25 @@ static SAMPLE_NONCE: Lazy<String> = Lazy::new(|| {
.unwrap()
});

pub(crate) const SAMPLE_TEST_ISS_VALUE: &str = "test.oidc.provider";
pub const SAMPLE_TEST_ISS_VALUE: &str = "test.oidc.provider";

pub(crate) static SAMPLE_JWT_PAYLOAD_JSON: Lazy<String> = Lazy::new(|| {
pub fn sample_jwt_payload_json() -> String {
sample_jwt_payload_json_overrides(
SAMPLE_TEST_ISS_VALUE,
SAMPLE_UID_VAL,
SAMPLE_JWT_EXTRA_FIELD.as_str(),
SAMPLE_JWT_IAT,
SAMPLE_NONCE.as_str(),
)
}

pub fn sample_jwt_payload_json_overrides(
iss: &str,
uid_val: &str,
extra_field: &str,
iat: u64,
nonce: &str,
) -> String {
format!(
r#"{{
"iss":"{}",
Expand All @@ -67,27 +83,27 @@ pub(crate) static SAMPLE_JWT_PAYLOAD_JSON: Lazy<String> = Lazy::new(|| {
"given_name":"Michael",
{}
"locale":"en",
"iat":1700255944,
"iat":{},
"nonce":"{}",
"exp":2700259544
}}"#,
SAMPLE_TEST_ISS_VALUE,
SAMPLE_UID_VAL,
SAMPLE_JWT_EXTRA_FIELD.as_str(),
SAMPLE_NONCE.as_str()
iss, uid_val, extra_field, iat, nonce
)
});
}

/// An example IAT.
pub const SAMPLE_JWT_IAT: u64 = 1700255944;

/// Consistent with what is in `SAMPLE_JWT_PAYLOAD_JSON`
pub(crate) const SAMPLE_JWT_EXTRA_FIELD_KEY: &str = "family_name";

/// Consistent with what is in `SAMPLE_JWT_PAYLOAD_JSON`
pub(crate) static SAMPLE_JWT_EXTRA_FIELD: Lazy<String> =
pub static SAMPLE_JWT_EXTRA_FIELD: Lazy<String> =
Lazy::new(|| format!(r#""{}":"Straka","#, SAMPLE_JWT_EXTRA_FIELD_KEY));

/// The JWT parsed as a struct
pub(crate) static SAMPLE_JWT_PARSED: Lazy<Claims> =
Lazy::new(|| serde_json::from_str(SAMPLE_JWT_PAYLOAD_JSON.as_str()).unwrap());
Lazy::new(|| serde_json::from_str(sample_jwt_payload_json().as_str()).unwrap());

pub(crate) static SAMPLE_JWK: Lazy<RSA_JWK> = Lazy::new(insecure_test_rsa_jwk);

Expand All @@ -97,10 +113,10 @@ pub(crate) static SAMPLE_JWK_SK: Lazy<&RsaKeyPair> = Lazy::new(|| &*INSECURE_TES

pub(crate) const SAMPLE_UID_KEY: &str = "sub";

pub(crate) const SAMPLE_UID_VAL: &str = "113990307082899718775";
pub const SAMPLE_UID_VAL: &str = "113990307082899718775";

/// The nonce-committed expiration date (not the JWT `exp`), 12/21/5490
pub(crate) const SAMPLE_EXP_DATE: u64 = 111_111_111_111;
pub const SAMPLE_EXP_DATE: u64 = 111_111_111_111;

/// ~31,710 years
pub(crate) const SAMPLE_EXP_HORIZON_SECS: u64 = 999_999_999_999;
Expand Down
2 changes: 1 addition & 1 deletion types/src/keyless/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{

mod bn254_circom;
mod circuit_constants;
mod circuit_testcases;
pub mod circuit_testcases;
mod configuration;
mod groth16_sig;
mod groth16_vk;
Expand Down
16 changes: 10 additions & 6 deletions types/src/keyless/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use crate::{
keyless::{
base64url_encode_str,
circuit_testcases::{
SAMPLE_EPK, SAMPLE_EPK_BLINDER, SAMPLE_ESK, SAMPLE_EXP_DATE, SAMPLE_EXP_HORIZON_SECS,
SAMPLE_JWK, SAMPLE_JWK_SK, SAMPLE_JWT_EXTRA_FIELD, SAMPLE_JWT_HEADER_B64,
SAMPLE_JWT_HEADER_JSON, SAMPLE_JWT_PARSED, SAMPLE_JWT_PAYLOAD_JSON, SAMPLE_PEPPER,
sample_jwt_payload_json, SAMPLE_EPK, SAMPLE_EPK_BLINDER, SAMPLE_ESK, SAMPLE_EXP_DATE,
SAMPLE_EXP_HORIZON_SECS, SAMPLE_JWK, SAMPLE_JWK_SK, SAMPLE_JWT_EXTRA_FIELD,
SAMPLE_JWT_HEADER_B64, SAMPLE_JWT_HEADER_JSON, SAMPLE_JWT_PARSED, SAMPLE_PEPPER,
SAMPLE_PK, SAMPLE_PROOF, SAMPLE_PROOF_FOR_UPGRADED_VK, SAMPLE_PROOF_NO_EXTRA_FIELD,
SAMPLE_UID_KEY, SAMPLE_UID_VAL, SAMPLE_UPGRADED_VK,
},
Expand Down Expand Up @@ -272,8 +272,12 @@ pub fn get_sample_groth16_sig_and_pk_no_extra_field() -> (KeylessSignature, Keyl
}

pub fn get_sample_jwt_token() -> String {
get_sample_jwt_token_from_payload(sample_jwt_payload_json().as_str())
}

pub fn get_sample_jwt_token_from_payload(payload: &str) -> String {
let jwt_header_b64 = SAMPLE_JWT_HEADER_B64.to_string();
let jwt_payload_b64 = base64url_encode_str(SAMPLE_JWT_PAYLOAD_JSON.as_str());
let jwt_payload_b64 = base64url_encode_str(payload);
let msg = jwt_header_b64.clone() + "." + jwt_payload_b64.as_str();
let rng = ring::rand::SystemRandom::new();
let sk = &*SAMPLE_JWK_SK;
Expand All @@ -296,7 +300,7 @@ pub fn get_sample_jwt_token() -> String {
/// desired TXN.
pub fn get_sample_openid_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) {
let jwt_header_b64 = SAMPLE_JWT_HEADER_B64.to_string();
let jwt_payload_b64 = base64url_encode_str(SAMPLE_JWT_PAYLOAD_JSON.as_str());
let jwt_payload_b64 = base64url_encode_str(sample_jwt_payload_json().as_str());
let msg = jwt_header_b64.clone() + "." + jwt_payload_b64.as_str();
let rng = ring::rand::SystemRandom::new();
let sk = *SAMPLE_JWK_SK;
Expand All @@ -312,7 +316,7 @@ pub fn get_sample_openid_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) {

let openid_sig = OpenIdSig {
jwt_sig,
jwt_payload_json: SAMPLE_JWT_PAYLOAD_JSON.to_string(),
jwt_payload_json: sample_jwt_payload_json().to_string(),
uid_key: SAMPLE_UID_KEY.to_owned(),
epk_blinder: SAMPLE_EPK_BLINDER.clone(),
pepper: SAMPLE_PEPPER.clone(),
Expand Down

0 comments on commit 543d75f

Please sign in to comment.