From d42cb6fa69c4c7d497dd30a9172b3cbd554a9719 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 3 Oct 2023 15:58:13 +0100 Subject: [PATCH] authgraph: add parallel session VTS tests Test: VtsAidlAuthGraphSessionTest Change-Id: Idcf79afe838fdbfb88bd7f43fe758ac03d9ba0d1 --- .../vts/functional/AuthGraphSessionTest.cpp | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp b/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp index cab8074417..d9dea7735a 100644 --- a/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp +++ b/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp @@ -166,6 +166,171 @@ TEST_P(AuthGraphSessionTest, Mainline) { // encoded as `sink_info.sharedKeys` and `source_info.sharedKeys`. } +TEST_P(AuthGraphSessionTest, ParallelSink) { + std::shared_ptr source = authNode_; + std::shared_ptr sink1 = authNode_; + std::shared_ptr sink2 = authNode_; + + // Step 1: create ephemeral ECDH keys at the source. + SessionInitiationInfo source_init1_info; + ASSERT_EQ(OK, GetReturnError(source->create(&source_init1_info))); + ASSERT_TRUE(source_init1_info.key.pubKey.has_value()); + ASSERT_TRUE(source_init1_info.key.arcFromPBK.has_value()); + SessionInitiationInfo source_init2_info; + ASSERT_EQ(OK, GetReturnError(source->create(&source_init2_info))); + ASSERT_TRUE(source_init2_info.key.pubKey.has_value()); + ASSERT_TRUE(source_init2_info.key.arcFromPBK.has_value()); + + // Step 2: pass the source's ECDH public keys and other session info to the sinks. + KeInitResult init1_result; + ASSERT_EQ(OK, GetReturnError(sink1->init(source_init1_info.key.pubKey.value(), + source_init1_info.identity, source_init1_info.nonce, + source_init1_info.version, &init1_result))); + SessionInitiationInfo sink1_init_info = init1_result.sessionInitiationInfo; + ASSERT_TRUE(sink1_init_info.key.pubKey.has_value()); + + SessionInfo sink1_info = init1_result.sessionInfo; + ASSERT_EQ((int)sink1_info.sharedKeys.size(), 2) << "Expect two symmetric keys from init()"; + ASSERT_GT((int)sink1_info.sessionId.size(), 0) << "Expect non-empty session ID from sink"; + std::vector sink1_signing_key = SigningKeyFromIdentity(sink1_init_info.identity); + CheckSignature(sink1_signing_key, sink1_info.sessionId, sink1_info.signature); + KeInitResult init2_result; + ASSERT_EQ(OK, GetReturnError(sink2->init(source_init2_info.key.pubKey.value(), + source_init2_info.identity, source_init2_info.nonce, + source_init2_info.version, &init2_result))); + SessionInitiationInfo sink2_init_info = init2_result.sessionInitiationInfo; + ASSERT_TRUE(sink2_init_info.key.pubKey.has_value()); + + SessionInfo sink2_info = init2_result.sessionInfo; + ASSERT_EQ((int)sink2_info.sharedKeys.size(), 2) << "Expect two symmetric keys from init()"; + ASSERT_GT((int)sink2_info.sessionId.size(), 0) << "Expect non-empty session ID from sink"; + std::vector sink2_signing_key = SigningKeyFromIdentity(sink2_init_info.identity); + CheckSignature(sink2_signing_key, sink2_info.sessionId, sink2_info.signature); + + // Step 3: pass each sink's ECDH public key and other session info to the source, so it can + // calculate the same pair of symmetric keys. + SessionInfo source_info1; + ASSERT_EQ(OK, GetReturnError(source->finish(sink1_init_info.key.pubKey.value(), + sink1_init_info.identity, sink1_info.signature, + sink1_init_info.nonce, sink1_init_info.version, + source_init1_info.key, &source_info1))); + ASSERT_EQ((int)source_info1.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()"; + ASSERT_GT((int)source_info1.sessionId.size(), 0) << "Expect non-empty session ID from source"; + std::vector source_signing_key1 = SigningKeyFromIdentity(source_init1_info.identity); + CheckSignature(source_signing_key1, source_info1.sessionId, source_info1.signature); + SessionInfo source_info2; + ASSERT_EQ(OK, GetReturnError(source->finish(sink2_init_info.key.pubKey.value(), + sink2_init_info.identity, sink2_info.signature, + sink2_init_info.nonce, sink2_init_info.version, + source_init2_info.key, &source_info2))); + ASSERT_EQ((int)source_info2.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()"; + ASSERT_GT((int)source_info2.sessionId.size(), 0) << "Expect non-empty session ID from source"; + std::vector source_signing_key2 = SigningKeyFromIdentity(source_init2_info.identity); + CheckSignature(source_signing_key2, source_info2.sessionId, source_info2.signature); + + // Both ends should agree on the session ID. + ASSERT_EQ(source_info1.sessionId, sink1_info.sessionId); + ASSERT_EQ(source_info2.sessionId, sink2_info.sessionId); + + // Step 4: pass the source's session ID info back to the sink, so it can check it and + // update the symmetric keys so they're marked as authentication complete. + std::array auth_complete_result1; + ASSERT_EQ(OK, GetReturnError(sink1->authenticationComplete( + source_info1.signature, sink1_info.sharedKeys, &auth_complete_result1))); + ASSERT_EQ((int)auth_complete_result1.size(), 2) + << "Expect two symmetric keys from authComplete()"; + sink1_info.sharedKeys = auth_complete_result1; + std::array auth_complete_result2; + ASSERT_EQ(OK, GetReturnError(sink2->authenticationComplete( + source_info2.signature, sink2_info.sharedKeys, &auth_complete_result2))); + ASSERT_EQ((int)auth_complete_result2.size(), 2) + << "Expect two symmetric keys from authComplete()"; + sink2_info.sharedKeys = auth_complete_result2; +} + +TEST_P(AuthGraphSessionTest, ParallelSource) { + std::shared_ptr source1 = authNode_; + std::shared_ptr source2 = authNode_; + std::shared_ptr sink = authNode_; + + // Step 1: create an ephemeral ECDH key at each of the sources. + SessionInitiationInfo source1_init_info; + ASSERT_EQ(OK, GetReturnError(source1->create(&source1_init_info))); + ASSERT_TRUE(source1_init_info.key.pubKey.has_value()); + ASSERT_TRUE(source1_init_info.key.arcFromPBK.has_value()); + SessionInitiationInfo source2_init_info; + ASSERT_EQ(OK, GetReturnError(source1->create(&source2_init_info))); + ASSERT_TRUE(source2_init_info.key.pubKey.has_value()); + ASSERT_TRUE(source2_init_info.key.arcFromPBK.has_value()); + + // Step 2: pass each source's ECDH public key and other session info to the sink. + KeInitResult init1_result; + ASSERT_EQ(OK, GetReturnError(sink->init(source1_init_info.key.pubKey.value(), + source1_init_info.identity, source1_init_info.nonce, + source1_init_info.version, &init1_result))); + SessionInitiationInfo sink_init1_info = init1_result.sessionInitiationInfo; + ASSERT_TRUE(sink_init1_info.key.pubKey.has_value()); + + SessionInfo sink_info1 = init1_result.sessionInfo; + ASSERT_EQ((int)sink_info1.sharedKeys.size(), 2) << "Expect two symmetric keys from init()"; + ASSERT_GT((int)sink_info1.sessionId.size(), 0) << "Expect non-empty session ID from sink"; + std::vector sink_signing_key1 = SigningKeyFromIdentity(sink_init1_info.identity); + CheckSignature(sink_signing_key1, sink_info1.sessionId, sink_info1.signature); + + KeInitResult init2_result; + ASSERT_EQ(OK, GetReturnError(sink->init(source2_init_info.key.pubKey.value(), + source2_init_info.identity, source2_init_info.nonce, + source2_init_info.version, &init2_result))); + SessionInitiationInfo sink_init2_info = init2_result.sessionInitiationInfo; + ASSERT_TRUE(sink_init2_info.key.pubKey.has_value()); + + SessionInfo sink_info2 = init2_result.sessionInfo; + ASSERT_EQ((int)sink_info2.sharedKeys.size(), 2) << "Expect two symmetric keys from init()"; + ASSERT_GT((int)sink_info2.sessionId.size(), 0) << "Expect non-empty session ID from sink"; + std::vector sink_signing_key2 = SigningKeyFromIdentity(sink_init2_info.identity); + CheckSignature(sink_signing_key2, sink_info2.sessionId, sink_info2.signature); + + // Step 3: pass the sink's ECDH public keys and other session info to the each of the sources. + SessionInfo source1_info; + ASSERT_EQ(OK, GetReturnError(source1->finish(sink_init1_info.key.pubKey.value(), + sink_init1_info.identity, sink_info1.signature, + sink_init1_info.nonce, sink_init1_info.version, + source1_init_info.key, &source1_info))); + ASSERT_EQ((int)source1_info.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()"; + ASSERT_GT((int)source1_info.sessionId.size(), 0) << "Expect non-empty session ID from source"; + std::vector source1_signing_key = SigningKeyFromIdentity(source1_init_info.identity); + CheckSignature(source1_signing_key, source1_info.sessionId, source1_info.signature); + + SessionInfo source2_info; + ASSERT_EQ(OK, GetReturnError(source2->finish(sink_init2_info.key.pubKey.value(), + sink_init2_info.identity, sink_info2.signature, + sink_init2_info.nonce, sink_init2_info.version, + source2_init_info.key, &source2_info))); + ASSERT_EQ((int)source2_info.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()"; + ASSERT_GT((int)source2_info.sessionId.size(), 0) << "Expect non-empty session ID from source"; + std::vector source2_signing_key = SigningKeyFromIdentity(source2_init_info.identity); + CheckSignature(source2_signing_key, source2_info.sessionId, source2_info.signature); + + // Both ends should agree on the session ID. + ASSERT_EQ(source1_info.sessionId, sink_info1.sessionId); + ASSERT_EQ(source2_info.sessionId, sink_info2.sessionId); + + // Step 4: pass the each source's session ID info back to the sink, so it can check it and + // update the symmetric keys so they're marked as authentication complete. + std::array auth_complete_result1; + ASSERT_EQ(OK, GetReturnError(sink->authenticationComplete( + source1_info.signature, sink_info1.sharedKeys, &auth_complete_result1))); + ASSERT_EQ((int)auth_complete_result1.size(), 2) + << "Expect two symmetric keys from authComplete()"; + sink_info1.sharedKeys = auth_complete_result1; + std::array auth_complete_result2; + ASSERT_EQ(OK, GetReturnError(sink->authenticationComplete( + source2_info.signature, sink_info2.sharedKeys, &auth_complete_result2))); + ASSERT_EQ((int)auth_complete_result2.size(), 2) + << "Expect two symmetric keys from authComplete()"; + sink_info2.sharedKeys = auth_complete_result2; +} + TEST_P(AuthGraphSessionTest, FreshNonces) { std::shared_ptr source = authNode_; std::shared_ptr sink = authNode_;