Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69efe8e7 authored by Hasini Gunasinghe's avatar Hasini Gunasinghe Committed by Gerrit Code Review
Browse files

Merge "Update the VTS module according to the refactoring in aosp/2826571" into main

parents 634ecd5d 5df6ed5e
Loading
Loading
Loading
Loading
+7 −41
Original line number Diff line number Diff line
@@ -24,22 +24,19 @@ use android_hardware_security_authgraph::aidl::android::hardware::security::auth
    PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
};
use authgraph_boringssl as boring;
use authgraph_core::keyexchange as ke;
use authgraph_core::{arc, key, traits};
use authgraph_nonsecure::StdClock;
use authgraph_core::{error::Error as AgError, keyexchange as ke};
use coset::CborSerializable;

pub mod sink;
pub mod source;

/// Return a collection of AuthGraph trait implementations suitable for testing.
pub fn test_impls() -> traits::TraitImpl {
    // Note that the local implementation is using a clock with a potentially different epoch than
    // the implementation under test.
    boring::trait_impls(
/// Return an AuthGraphParticipant suitable for testing.
pub fn test_ag_participant() -> Result<ke::AuthGraphParticipant, AgError> {
    Ok(ke::AuthGraphParticipant::new(
        boring::crypto_trait_impls(),
        Box::<boring::test_device::AgDevice>::default(),
        Some(Box::new(StdClock::default())),
    )
        ke::MAX_OPENED_SESSIONS,
    )?)
}

fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
@@ -56,14 +53,6 @@ fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> &PlainPubKey {
    }
}

fn verification_key_from_identity(impls: &traits::TraitImpl, identity: &[u8]) -> key::EcVerifyKey {
    let identity = key::Identity::from_slice(identity).expect("invalid identity CBOR");
    impls
        .device
        .process_peer_cert_chain(&identity.cert_chain, &*impls.ecdsa)
        .expect("failed to extract signing key")
}

fn vec_to_identity(data: &[u8]) -> Identity {
    Identity {
        identity: data.to_vec(),
@@ -75,26 +64,3 @@ fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
        signature: data.to_vec(),
    }
}

/// Decrypt a pair of AES-256 keys encrypted with the AuthGraph PBK.
pub fn decipher_aes_keys(imp: &traits::TraitImpl, arc: &[Vec<u8>; 2]) -> [key::AesKey; 2] {
    [
        decipher_aes_key(imp, &arc[0]),
        decipher_aes_key(imp, &arc[1]),
    ]
}

/// Decrypt an AES-256 key encrypted with the AuthGraph PBK.
pub fn decipher_aes_key(imp: &traits::TraitImpl, arc: &[u8]) -> key::AesKey {
    let pbk = imp.device.get_per_boot_key().expect("no PBK available");
    let arc::ArcContent {
        payload,
        protected_headers: _,
        unprotected_headers: _,
    } = arc::decipher_arc(&pbk, arc, &*imp.aes_gcm).expect("failed to decrypt arc");
    assert_eq!(payload.0.len(), 32);
    let mut key = key::AesKey([0; 32]);
    key.0.copy_from_slice(&payload.0);
    assert_ne!(key.0, [0; 32], "agreed AES-256 key should be non-zero");
    key
}
+12 −12
Original line number Diff line number Diff line
@@ -48,31 +48,31 @@ macro_rules! require_nonsecure {

#[test]
fn test_nonsecure_source_mainline() {
    let mut impls = vts::test_impls();
    vts::source::test_mainline(&mut impls, require_nonsecure!());
    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
    vts::source::test_mainline(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_source_corrupt_sig() {
    let mut impls = vts::test_impls();
    vts::source::test_corrupt_sig(&mut impls, require_nonsecure!());
    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
    vts::source::test_corrupt_sig(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_source_corrupt_keys() {
    let mut impls = vts::test_impls();
    vts::source::test_corrupt_key(&mut impls, require_nonsecure!());
    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
    vts::source::test_corrupt_key(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_mainline() {
    let mut impls = vts::test_impls();
    vts::sink::test_mainline(&mut impls, require_nonsecure!());
    let mut source = vts::test_ag_participant().expect("failed to create a local source");
    vts::sink::test_mainline(&mut source, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_corrupt_sig() {
    let mut impls = vts::test_impls();
    vts::sink::test_corrupt_sig(&mut impls, require_nonsecure!());
    let mut source = vts::test_ag_participant().expect("failed to create a local source");
    vts::sink::test_corrupt_sig(&mut source, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_corrupt_keys() {
    let mut impls = vts::test_impls();
    vts::sink::test_corrupt_keys(&mut impls, require_nonsecure!());
    let mut source = vts::test_ag_participant().expect("failed to create a local source");
    vts::sink::test_corrupt_keys(&mut source, require_nonsecure!());
}
+80 −61
Original line number Diff line number Diff line
@@ -16,23 +16,28 @@

//! VTS tests for sinks
use super::*;
use authgraph_core::traits;
use authgraph_core::{key, keyexchange as ke};

/// Run AuthGraph tests against the provided sink, using a local test source implementation.
pub fn test(impls: &mut traits::TraitImpl, sink: binder::Strong<dyn IAuthGraphKeyExchange>) {
    test_mainline(impls, sink.clone());
    test_corrupt_sig(impls, sink.clone());
    test_corrupt_keys(impls, sink);
pub fn test(
    local_source: &mut ke::AuthGraphParticipant,
    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    test_mainline(local_source, sink.clone());
    test_corrupt_sig(local_source, sink.clone());
    test_corrupt_keys(local_source, sink);
}

/// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
/// Return the agreed AES keys in plaintext.
pub fn test_mainline(
    impls: &mut traits::TraitImpl,
    local_source: &mut ke::AuthGraphParticipant,
    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) -> [key::AesKey; 2] {
    // Step 1: create an ephemeral ECDH key at the (local) source.
    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
    let source_init_info = local_source
        .create()
        .expect("failed to create() with local impl");

    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
    let init_result = sink
@@ -50,20 +55,21 @@ pub fn test_mainline(
    assert!(!sink_info.sessionId.is_empty());

    // The AuthGraph core library will verify the session ID signature, but do it here too.
    let sink_verification_key =
        verification_key_from_identity(&impls, &sink_init_info.identity.identity);
    ke::verify_signature_on_session_id(
    let sink_verification_key = local_source
        .peer_verification_key_from_identity(&sink_init_info.identity.identity)
        .expect("failed to get peer verification from identity");
    local_source
        .verify_signature_on_session_id(
            &sink_verification_key,
            &sink_info.sessionId,
            &sink_info.signature.signature,
        &*impls.ecdsa,
        )
        .expect("failed verification of signed session ID");

    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
    // can calculate the same pair of symmetric keys.
    let source_info = ke::finish(
        impls,
    let source_info = local_source
        .finish(
            &sink_pub_key.plainPubKey,
            &sink_init_info.identity.identity,
            &sink_info.signature.signature,
@@ -75,13 +81,15 @@ pub fn test_mainline(
    assert!(!source_info.session_id.is_empty());

    // The AuthGraph core library will verify the session ID signature, but do it here too.
    let source_verification_key =
        verification_key_from_identity(&impls, &source_init_info.identity);
    ke::verify_signature_on_session_id(
    let source_verification_key = key::Identity::from_slice(&source_init_info.identity)
        .expect("invalid identity CBOR")
        .cert_chain
        .root_key;
    local_source
        .verify_signature_on_session_id(
            &source_verification_key,
            &source_info.session_id,
            &source_info.session_id_signature,
        &*impls.ecdsa,
        )
        .expect("failed verification of signed session ID");

@@ -96,19 +104,28 @@ pub fn test_mainline(
            &sink_info.sharedKeys,
        )
        .expect("failed to authenticationComplete() with remote sink");

    // Decrypt and return the session keys.
    decipher_aes_keys(&impls, &source_info.shared_keys)
    let decrypted_shared_keys = local_source
        .decipher_shared_keys_from_arcs(&source_info.shared_keys)
        .expect("failed to decrypt shared key arcs")
        .try_into();
    let decrypted_shared_keys_array = match decrypted_shared_keys {
        Ok(array) => array,
        Err(_) => panic!("wrong number of decrypted shared key arcs"),
    };
    decrypted_shared_keys_array
}

/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
/// session ID signature.
pub fn test_corrupt_sig(
    impls: &mut traits::TraitImpl,
    local_source: &mut ke::AuthGraphParticipant,
    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    // Step 1: create an ephemeral ECDH key at the (local) source.
    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
    let source_init_info = local_source
        .create()
        .expect("failed to create() with local impl");

    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
    let init_result = sink
@@ -127,8 +144,8 @@ pub fn test_corrupt_sig(

    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
    // can calculate the same pair of symmetric keys.
    let source_info = ke::finish(
        impls,
    let source_info = local_source
        .finish(
            &sink_pub_key.plainPubKey,
            &sink_init_info.identity.identity,
            &sink_info.signature.signature,
@@ -158,11 +175,13 @@ pub fn test_corrupt_sig(
/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
/// Arc for the sink's key.
pub fn test_corrupt_keys(
    impls: &mut traits::TraitImpl,
    local_source: &mut ke::AuthGraphParticipant,
    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    // Step 1: create an ephemeral ECDH key at the (local) source.
    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
    let source_init_info = local_source
        .create()
        .expect("failed to create() with local impl");

    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
    let init_result = sink
@@ -181,8 +200,8 @@ pub fn test_corrupt_keys(

    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
    // can calculate the same pair of symmetric keys.
    let source_info = ke::finish(
        impls,
    let source_info = local_source
        .finish(
            &sink_pub_key.plainPubKey,
            &sink_init_info.identity.identity,
            &sink_info.signature.signature,
+79 −65
Original line number Diff line number Diff line
@@ -16,19 +16,22 @@

//! VTS tests for sources
use super::*;
use authgraph_core::traits;
use authgraph_core::{key, keyexchange as ke};

/// Run AuthGraph tests against the provided source, using a local test sink implementation.
pub fn test(impls: &mut traits::TraitImpl, source: binder::Strong<dyn IAuthGraphKeyExchange>) {
    test_mainline(impls, source.clone());
    test_corrupt_sig(impls, source.clone());
    test_corrupt_key(impls, source);
pub fn test(
    local_sink: &mut ke::AuthGraphParticipant,
    source: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    test_mainline(local_sink, source.clone());
    test_corrupt_sig(local_sink, source.clone());
    test_corrupt_key(local_sink, source);
}

/// Perform mainline AuthGraph key exchange with the provided source.
/// Return the agreed AES keys in plaintext.
pub fn test_mainline(
    impls: &mut traits::TraitImpl,
    local_sink: &mut ke::AuthGraphParticipant,
    source: binder::Strong<dyn IAuthGraphKeyExchange>,
) -> [key::AesKey; 2] {
    // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -40,8 +43,8 @@ pub fn test_mainline(
    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);

    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
    let init_result = ke::init(
        impls,
    let init_result = local_sink
        .init(
            &source_pub_key.plainPubKey,
            &source_init_info.identity.identity,
            &source_init_info.nonce,
@@ -58,12 +61,15 @@ pub fn test_mainline(
    assert!(!sink_info.session_id.is_empty());

    // The AuthGraph core library will verify the session ID signature, but do it here too.
    let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
    ke::verify_signature_on_session_id(
    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
        .expect("invalid identity CBOR")
        .cert_chain
        .root_key;
    local_sink
        .verify_signature_on_session_id(
            &sink_verification_key,
            &sink_info.session_id,
            &sink_info.session_id_signature,
        &*impls.ecdsa,
        )
        .expect("failed verification of signed session ID");

@@ -86,13 +92,14 @@ pub fn test_mainline(
    assert!(!source_info.sessionId.is_empty());

    // The AuthGraph core library will verify the session ID signature, but do it here too.
    let source_verification_key =
        verification_key_from_identity(&impls, &source_init_info.identity.identity);
    ke::verify_signature_on_session_id(
    let source_verification_key = local_sink
        .peer_verification_key_from_identity(&source_init_info.identity.identity)
        .expect("failed to get peer verification from identity");
    local_sink
        .verify_signature_on_session_id(
            &source_verification_key,
            &source_info.sessionId,
            &source_info.signature.signature,
        &*impls.ecdsa,
        )
        .expect("failed verification of signed session ID");

@@ -101,21 +108,25 @@ pub fn test_mainline(

    // Step 4: pass the (remote) source's session ID signature back to the sink, so it can check it
    // and update the symmetric keys so they're marked as authentication complete.
    let sink_arcs = ke::authentication_complete(
        impls,
        &source_info.signature.signature,
        sink_info.shared_keys,
    )
    let sink_arcs = local_sink
        .authentication_complete(&source_info.signature.signature, sink_info.shared_keys)
        .expect("failed to authenticationComplete() with local sink");

    // Decrypt and return the session keys.
    decipher_aes_keys(&impls, &sink_arcs)
    let decrypted_shared_keys = local_sink
        .decipher_shared_keys_from_arcs(&sink_arcs)
        .expect("failed to decrypt shared key arcs")
        .try_into();
    let decrypted_shared_keys_array = match decrypted_shared_keys {
        Ok(array) => array,
        Err(_) => panic!("wrong number of decrypted shared key arcs"),
    };
    decrypted_shared_keys_array
}

/// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
/// ID signature.
pub fn test_corrupt_sig(
    impls: &mut traits::TraitImpl,
    local_sink: &mut ke::AuthGraphParticipant,
    source: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -127,8 +138,8 @@ pub fn test_corrupt_sig(
    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);

    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
    let init_result = ke::init(
        impls,
    let init_result = local_sink
        .init(
            &source_pub_key.plainPubKey,
            &source_init_info.identity.identity,
            &source_init_info.nonce,
@@ -172,7 +183,7 @@ pub fn test_corrupt_sig(
/// Perform mainline AuthGraph key exchange with the provided source, but give it back
/// a corrupted key.
pub fn test_corrupt_key(
    impls: &mut traits::TraitImpl,
    local_sink: &mut ke::AuthGraphParticipant,
    source: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
    // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -184,8 +195,8 @@ pub fn test_corrupt_key(
    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);

    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
    let init_result = ke::init(
        impls,
    let init_result = local_sink
        .init(
            &source_pub_key.plainPubKey,
            &source_init_info.identity.identity,
            &source_init_info.nonce,
@@ -202,12 +213,15 @@ pub fn test_corrupt_key(
    assert!(!sink_info.session_id.is_empty());

    // The AuthGraph core library will verify the session ID signature, but do it here too.
    let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
    ke::verify_signature_on_session_id(
    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
        .expect("invalid identity CBOR")
        .cert_chain
        .root_key;
    local_sink
        .verify_signature_on_session_id(
            &sink_verification_key,
            &sink_info.session_id,
            &sink_info.session_id_signature,
        &*impls.ecdsa,
        )
        .expect("failed verification of signed session ID");

+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ use libfuzzer_sys::fuzz_target;
use std::sync::{Arc, Mutex};

fuzz_target!(|data: &[u8]| {
    let local_ta = LocalTa::new();
    let local_ta = LocalTa::new().expect("Failed to create an AuthGraph local TA.");
    let service = AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
    fuzz_service(&mut service.as_binder(), data);
});
Loading