spdm: Support vendor command in data phase

The vendor command is just wrapping the raw application messages the
requester is sending to the responder under the hood of spdm protocol.

BUG=b:284404632
TEST=cargo test

Change-Id: I973ca819974a03644ee4a347491708aedfdc1441
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/spdm/+/5019430
Tested-by: Howard Yang <hcyang@google.com>
Commit-Queue: Howard Yang <hcyang@google.com>
Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
diff --git a/spdm-core/src/deps/test/mod.rs b/spdm-core/src/deps/test/mod.rs
index 8798609..1ed9a2b 100644
--- a/spdm-core/src/deps/test/mod.rs
+++ b/spdm-core/src/deps/test/mod.rs
@@ -6,14 +6,17 @@
 
 mod crypto;
 mod identity;
+mod vendor;
 
 pub use crypto::*;
 pub use identity::*;
 use spdm_types::deps::SpdmDeps;
+pub use vendor::*;
 
 pub struct SpdmTestDeps;
 
 impl SpdmDeps for SpdmTestDeps {
     type Crypto = TestCrypto;
     type Identity = TestIdentity;
+    type Vendor = TestVendor;
 }
diff --git a/spdm-core/src/deps/test/vendor.rs b/spdm-core/src/deps/test/vendor.rs
new file mode 100644
index 0000000..0139897
--- /dev/null
+++ b/spdm-core/src/deps/test/vendor.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[cfg(feature = "mock")]
+use mocktopus::macros::*;
+use spdm_types::deps::Vendor;
+
+pub struct TestVendor;
+
+#[cfg_attr(feature = "mock", mockable)]
+impl Vendor for TestVendor {
+    fn process_vendor_request(&self, _buf: &mut [u8], req_size: usize) -> usize {
+        req_size
+    }
+}
diff --git a/spdm-core/src/dispatch/internal.rs b/spdm-core/src/dispatch/internal.rs
index fdb1eff..449795a 100644
--- a/spdm-core/src/dispatch/internal.rs
+++ b/spdm-core/src/dispatch/internal.rs
@@ -8,6 +8,7 @@
 use mocktopus::macros::*;
 use spdm_types::deps::{Crypto, SpdmDeps};
 
+use super::session_established::SessionEstablishedDispatcher;
 use super::wait_for_finish::WaitForFinishDispatcher;
 use super::wait_for_key_exchange::WaitForKeyExchangeDispatcher;
 use super::wait_for_requester_key::WaitForRequesterKeyDispatcher;
@@ -112,7 +113,10 @@
         self.session.sequence_numbers.request += 1;
         let req_buf = &mut buf[REQUEST_OFFSET..];
         let req_code = parse_header(&req_buf[..req_size])?;
-        let resp_size = self.dispatch_request_internal(req_buf, req_size, req_code)?;
+        let resp_size = match self.dispatch_request_internal(req_buf, req_size, req_code) {
+            Ok(resp_size) => resp_size,
+            Err(err) => err.write_response(buf),
+        };
         let resp_size =
             encrypt_secure_message(session_id, &session_keys.response_keys, buf, resp_size)?;
         self.session.sequence_numbers.response += 1;
@@ -135,8 +139,9 @@
             SpdmState::WaitForFinish => {
                 self.dispatch_request_wait_for_finish(buf, req_size, req_code)
             }
-            // TODO(b/284404632): Implement SessionEstablishedDispatcher.
-            SpdmState::SessionEstablished => Err(ErrorCode::Unspecified),
+            SpdmState::SessionEstablished => {
+                self.dispatch_request_session_established(buf, req_size, req_code)
+            }
         }
     }
 }
@@ -144,7 +149,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
     use crate::types::message::GET_PUBLIC_KEY_RESPONSE_SIZE;
     use crate::types::version::SPDM_THIS_VERSION;
 
@@ -153,7 +158,7 @@
         let mut buf = [0x10, RequestCode::GetVersion.0, 0, 0, 0, 0, 0, 0];
         let req_size = 4;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let fake_transcript = [0xCC; 12];
         // Simulate the scenario that there's already some state.
@@ -174,7 +179,7 @@
         buf.extend_from_slice(&[0; 100]);
         let req_size = 4;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let fake_transcript = [0xCC; 12];
         // Simulate the scenario that there's already some state.
@@ -195,7 +200,7 @@
         buf.extend_from_slice(&[0; 100]);
         let req_size = 4;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
         spdm.state = SpdmState::WaitForRequesterKey;
         let result = spdm.dispatch_plaintext_request(&mut buf, req_size);
         assert_eq!(result, Err(ErrorCode::SessionRequired));
@@ -219,7 +224,7 @@
             buf.extend_from_slice(&[0; 100]);
             let req_size = 28;
 
-            let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+            let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
             spdm.session.session_id = Some([0xaa, 0xbb, 0xcc, 0xdd]);
             spdm.session.th1 = Some([0xCC; 32]);
             spdm.session.handshake_secret = Some(());
diff --git a/spdm-core/src/dispatch/mod.rs b/spdm-core/src/dispatch/mod.rs
index 922a6ae..0cf23b9 100644
--- a/spdm-core/src/dispatch/mod.rs
+++ b/spdm-core/src/dispatch/mod.rs
@@ -5,6 +5,7 @@
 //! Implements the dispatcher state machine of the SPDM responder.
 
 pub mod internal;
+mod session_established;
 mod wait_for_finish;
 mod wait_for_key_exchange;
 mod wait_for_requester_key;
diff --git a/spdm-core/src/dispatch/session_established.rs b/spdm-core/src/dispatch/session_established.rs
new file mode 100644
index 0000000..908c039
--- /dev/null
+++ b/spdm-core/src/dispatch/session_established.rs
@@ -0,0 +1,119 @@
+// Copyright 2023 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use spdm_types::deps::{SpdmDeps, Vendor};
+
+use crate::types::code::{RequestCode, ResponseCode};
+use crate::types::error::{ErrorCode, SpdmResult};
+use crate::Spdm;
+
+///
+/// VendorCommand request format:
+///
+/// | Byte offset | Size (bytes)    | Field               | Description                |
+/// | :---------- | :-------------- | :------------------ | :------------------------- |
+/// | 0           | 1               | SPDMVersion         | SPDM_THIS_VERSION          |
+/// | 1           | 1               | RequestResponseCode | RequestCode::VendorCommand |
+/// | 2           | 1               | Param1              | Reserved                   |
+/// | 3           | 1               | Param2              | Reserved                   |
+/// | 4           | N               | VendorMessage       |                            |
+///
+/// VendorCommand response format:
+/// | Byte offset | Size (bytes) | Field               | Description                 |
+/// | :---------- | :----------- | :------------------ | :-------------------------- |
+/// | 0           | 1            | SPDMVersion         | SPDM_THIS_VERSION           |
+/// | 1           | 1            | RequestResponseCode | ResponseCode::VendorCommand |
+/// | 2           | 1            | Param1              | Reserved                    |
+/// | 3           | 1            | Param2              | Reserved                    |
+/// | 4           | N            | VendorMessage       |                             |
+const VENDOR_COMMAND_HEADER_SIZE: usize = 4;
+const VENDOR_COMMAND_CODE_OFFSET: usize = 1;
+
+/// SessionEstablishedDispatcher handles the state where the session is successfully
+/// established. Only vendor commands will be processed in this phase.
+///
+/// This trait is only used for separating impl blocks of `Spdm` struct by functionality.
+pub trait SessionEstablishedDispatcher {
+    fn dispatch_request_session_established(
+        &mut self,
+        buf: &mut [u8],
+        req_size: usize,
+        req_code: RequestCode,
+    ) -> SpdmResult<usize>;
+}
+
+/// VendorCommandDispatcher handles the VendorCommand request.
+///
+/// This trait is only used for separating impl blocks of `Spdm` struct by functionality.
+pub trait VendorCommandDispatcher {
+    /// Handles the VendorCommand request and if successful, writes the VendorCommand response
+    /// to `buf`.
+    /// This is a custom command defined by this SPDM implementation. It basically carries arbitrary
+    /// message that the responder knows how to handle and respond.
+    fn dispatch_vendor_command_request(
+        &mut self,
+        buf: &mut [u8],
+        req_size: usize,
+    ) -> SpdmResult<usize>;
+}
+
+impl<D: SpdmDeps> VendorCommandDispatcher for Spdm<D> {
+    fn dispatch_vendor_command_request(
+        &mut self,
+        buf: &mut [u8],
+        req_size: usize,
+    ) -> SpdmResult<usize> {
+        if req_size < VENDOR_COMMAND_HEADER_SIZE {
+            return Err(ErrorCode::InvalidRequest);
+        }
+        let resp_size = self.vendor.process_vendor_request(
+            &mut buf[VENDOR_COMMAND_HEADER_SIZE..],
+            req_size - VENDOR_COMMAND_HEADER_SIZE,
+        ) + VENDOR_COMMAND_HEADER_SIZE;
+        buf[VENDOR_COMMAND_CODE_OFFSET] = ResponseCode::VendorCommand.0;
+        Ok(resp_size)
+    }
+}
+
+impl<D: SpdmDeps> SessionEstablishedDispatcher for Spdm<D> {
+    fn dispatch_request_session_established(
+        &mut self,
+        buf: &mut [u8],
+        req_size: usize,
+        req_code: RequestCode,
+    ) -> SpdmResult<usize> {
+        match req_code {
+            RequestCode::VendorCommand => self.dispatch_vendor_command_request(buf, req_size),
+            _ => Err(ErrorCode::UnexpectedRequest),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
+    use crate::types::code::RequestCode;
+    use crate::types::version::SPDM_THIS_VERSION;
+
+    #[test]
+    fn give_pub_key_request() {
+        let mut buf = [
+            SPDM_THIS_VERSION,
+            RequestCode::VendorCommand.0,
+            0,
+            0,
+            1,
+            2,
+            3,
+            4,
+        ];
+        let req_size = 8;
+
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
+
+        let result = spdm.dispatch_vendor_command_request(&mut buf, req_size);
+        assert_eq!(result, Ok(8));
+    }
+}
diff --git a/spdm-core/src/dispatch/wait_for_finish.rs b/spdm-core/src/dispatch/wait_for_finish.rs
index bd72103..682f5d3 100644
--- a/spdm-core/src/dispatch/wait_for_finish.rs
+++ b/spdm-core/src/dispatch/wait_for_finish.rs
@@ -88,7 +88,7 @@
         use mocktopus::mocking::{MockResult, Mockable};
 
         use super::super::*;
-        use crate::deps::{SpdmTestDeps, TestIdentity};
+        use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
 
         #[test]
         fn finish_request() {
@@ -100,7 +100,7 @@
             Spdm::<SpdmTestDeps>::validate_finish_message_hmac
                 .mock_safe(|_, _| MockResult::Return(Ok(())));
 
-            let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+            let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
             let result = spdm.dispatch_finish_request(&mut buf, FinishRequest::SIZE);
             assert_eq!(result, Ok(4));
         }
diff --git a/spdm-core/src/dispatch/wait_for_key_exchange/get_pub_key.rs b/spdm-core/src/dispatch/wait_for_key_exchange/get_pub_key.rs
index d1a5b9b..0f3ed5d 100644
--- a/spdm-core/src/dispatch/wait_for_key_exchange/get_pub_key.rs
+++ b/spdm-core/src/dispatch/wait_for_key_exchange/get_pub_key.rs
@@ -62,7 +62,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity, TEST_IDENTITY_PUBLIC_KEY};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor, TEST_IDENTITY_PUBLIC_KEY};
     use crate::dispatch::internal::SpdmState;
     use crate::types::code::RequestCode;
     use crate::types::version::SPDM_THIS_VERSION;
@@ -73,7 +73,7 @@
         buf.extend_from_slice(&[0; 100]);
         let req_size = 4;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let result = spdm.dispatch_get_pub_key_request(&mut buf, req_size);
         assert_eq!(result, Ok(GET_PUBLIC_KEY_RESPONSE_SIZE));
diff --git a/spdm-core/src/dispatch/wait_for_key_exchange/get_version.rs b/spdm-core/src/dispatch/wait_for_key_exchange/get_version.rs
index eda864f..a159bb1 100644
--- a/spdm-core/src/dispatch/wait_for_key_exchange/get_version.rs
+++ b/spdm-core/src/dispatch/wait_for_key_exchange/get_version.rs
@@ -68,7 +68,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
     use crate::dispatch::internal::SpdmState;
     use crate::types::code::RequestCode;
 
@@ -77,7 +77,7 @@
         let mut buf = [0x10, RequestCode::GetVersion.0, 0, 0, 0, 0, 0, 0];
         let req_size = 4;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let result = spdm.dispatch_get_version_request(&mut buf, req_size);
         assert_eq!(result, Ok(8));
diff --git a/spdm-core/src/dispatch/wait_for_key_exchange/key_exchange.rs b/spdm-core/src/dispatch/wait_for_key_exchange/key_exchange.rs
index 5ba5c51..111c093 100644
--- a/spdm-core/src/dispatch/wait_for_key_exchange/key_exchange.rs
+++ b/spdm-core/src/dispatch/wait_for_key_exchange/key_exchange.rs
@@ -115,7 +115,7 @@
     use spdm_types::crypto::EC_P256_COORD_SIZE;
 
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
     use crate::dispatch::wait_for_key_exchange::get_version::GetVersionDispatcher;
     use crate::types::code::RequestCode;
     use crate::types::version::SPDM_THIS_VERSION;
@@ -146,7 +146,7 @@
         let mut buf = get_valid_key_exchange_buffer();
         let req_size = KeyExchangeRequest::SIZE;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         // A GetVersion request must come first to initialize the transcript.
         let mut get_version = [0x10, RequestCode::GetVersion.0, 0, 0, 0, 0, 0, 0];
@@ -173,7 +173,7 @@
         let mut buf = get_valid_key_exchange_buffer();
         let req_size = KeyExchangeRequest::SIZE;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let result = spdm.dispatch_key_exchange_request(&mut buf, req_size);
         assert_eq!(result, Err(ErrorCode::UnexpectedRequest));
diff --git a/spdm-core/src/dispatch/wait_for_requester_key.rs b/spdm-core/src/dispatch/wait_for_requester_key.rs
index 4a9fe1b..3c1f581 100644
--- a/spdm-core/src/dispatch/wait_for_requester_key.rs
+++ b/spdm-core/src/dispatch/wait_for_requester_key.rs
@@ -36,7 +36,7 @@
     /// | Byte offset | Size (bytes)    | Field               | Description              |
     /// | :---------- | :-------------- | :------------------ | :----------------------- |
     /// | 0           | 1               | SPDMVersion         | SPDM_THIS_VERSION        |
-    /// | 1           | 1               | RequestResponseCode | ResponseCode::GivePubKey |
+    /// | 1           | 1               | RequestResponseCode | RequestCode::GivePubKey  |
     /// | 2           | 1               | Param1              | Reserved                 |
     /// | 3           | 1               | Param2              | Reserved                 |
     /// | 4           | PUBLIC_KEY_SIZE | PublicKey           | Public Key               |
@@ -45,7 +45,7 @@
     /// | Byte offset | Size (bytes) | Field               | Description             |
     /// | :---------- | :----------- | :------------------ | :---------------------- |
     /// | 0           | 1            | SPDMVersion         | SPDM_THIS_VERSION       |
-    /// | 1           | 1            | RequestResponseCode | RequestCode::GivePubKey |
+    /// | 1           | 1            | RequestResponseCode | Response::GivePubKey    |
     /// | 2           | 1            | Param1              | Reserved                |
     /// | 3           | 1            | Param2              | Reserved                |
     fn dispatch_give_pub_key_request(
@@ -100,7 +100,7 @@
     use zerocopy::AsBytes;
 
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity, TEST_IDENTITY_PUBLIC_KEY};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor, TEST_IDENTITY_PUBLIC_KEY};
     use crate::dispatch::internal::SpdmState;
     use crate::types::code::RequestCode;
     use crate::types::version::SPDM_THIS_VERSION;
@@ -111,7 +111,7 @@
         buf.extend_from_slice(TEST_IDENTITY_PUBLIC_KEY.as_bytes());
         let req_size = GivePubKeyRequest::SIZE;
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
 
         let result = spdm.dispatch_give_pub_key_request(&mut buf, req_size);
         assert_eq!(result, Ok(4));
@@ -137,7 +137,7 @@
                     MockResult::Return(false)
                 })
                 .run(|| {
-                    let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+                    let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
                     spdm.state = SpdmState::WaitForRequesterKey;
 
                     let result = spdm.dispatch_give_pub_key_request(&mut buf, req_size);
diff --git a/spdm-core/src/lib.rs b/spdm-core/src/lib.rs
index 7608eee..68603c9 100644
--- a/spdm-core/src/lib.rs
+++ b/spdm-core/src/lib.rs
@@ -18,14 +18,16 @@
 pub struct Spdm<D: SpdmDeps> {
     state: SpdmState,
     identity: D::Identity,
+    vendor: D::Vendor,
     session: Session<D::Crypto>,
 }
 
 impl<D: SpdmDeps> Spdm<D> {
-    pub fn new(identity: D::Identity) -> Self {
+    pub fn new(identity: D::Identity, vendor: D::Vendor) -> Self {
         Self {
             state: SpdmState::default(),
             identity,
+            vendor,
             session: Session::<D::Crypto>::default(),
         }
     }
diff --git a/spdm-core/src/session/mod.rs b/spdm-core/src/session/mod.rs
index a1b6a1b..90c6710 100644
--- a/spdm-core/src/session/mod.rs
+++ b/spdm-core/src/session/mod.rs
@@ -407,7 +407,7 @@
     use zerocopy::FromBytes;
 
     use super::*;
-    use crate::deps::{SpdmTestDeps, TestIdentity};
+    use crate::deps::{SpdmTestDeps, TestIdentity, TestVendor};
 
     #[test]
     fn init_transcript_and_sign() {
@@ -417,7 +417,7 @@
         let key_exchange_response = [0xBB; 16];
         let mut signature = EcdsaP256Signature::new_zeroed();
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
         spdm.set_negotiation_transcript(get_version_request, version_response);
         assert!(spdm
             .init_transcript_hash_with_key_exchange_request(&key_exchange_request)
@@ -435,7 +435,7 @@
     fn init_transcript_hash_without_transcript() {
         let key_exchange_request = [0xAA; 8];
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
         assert_eq!(
             spdm.init_transcript_hash_with_key_exchange_request(&key_exchange_request),
             Err(ErrorCode::Unspecified)
@@ -446,7 +446,7 @@
     fn sign_without_transcript_hash() {
         let mut signature = EcdsaP256Signature::new_zeroed();
 
-        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity);
+        let mut spdm = Spdm::<SpdmTestDeps>::new(TestIdentity, TestVendor);
         assert_eq!(
             spdm.sign_key_exchange_message(&mut signature),
             Err(ErrorCode::Unspecified)
diff --git a/spdm-core/src/types/code.rs b/spdm-core/src/types/code.rs
index 61f9514..2b99cd4 100644
--- a/spdm-core/src/types/code.rs
+++ b/spdm-core/src/types/code.rs
@@ -23,6 +23,7 @@
     // we don't want to parse them as vendor commands.
     GetPubKey = 0xF0,
     GivePubKey = 0xF1,
+    VendorCommand = 0xF2,
 }
 
 #[repr(u8)]
@@ -38,6 +39,7 @@
     // we don't want to parse them as vendor commands.
     GetPubKey = 0x10,
     GivePubKey = 0x11,
+    VendorCommand = 0x12,
 }
 
 // `Param1` and `Param2` are 1-byte params that appear in most SPDM message formats
@@ -48,7 +50,12 @@
 fn is_request_code_supported(code: RequestCode) -> bool {
     matches!(
         code,
-        RequestCode::GetVersion | RequestCode::GetPubKey | RequestCode::KeyExchange
+        RequestCode::GetVersion
+            | RequestCode::KeyExchange
+            | RequestCode::Finish
+            | RequestCode::GetPubKey
+            | RequestCode::GivePubKey
+            | RequestCode::VendorCommand
     )
 }
 
diff --git a/spdm-types/src/deps/mod.rs b/spdm-types/src/deps/mod.rs
index 17af65a..4385b5d 100644
--- a/spdm-types/src/deps/mod.rs
+++ b/spdm-types/src/deps/mod.rs
@@ -7,13 +7,16 @@
 
 mod crypto;
 mod identity;
+mod vendor;
 
 pub use crypto::*;
 pub use identity::*;
+pub use vendor::*;
 
 /// `SpdmDeps` defines the trait dependencies of `Spdm` so it only needs
 /// to be generic on a single type with `SpdmDeps` trait bound.
 pub trait SpdmDeps {
     type Crypto: Crypto;
     type Identity: Identity<Crypto = Self::Crypto>;
+    type Vendor: Vendor;
 }
diff --git a/spdm-types/src/deps/vendor.rs b/spdm-types/src/deps/vendor.rs
new file mode 100644
index 0000000..4cf4a47
--- /dev/null
+++ b/spdm-types/src/deps/vendor.rs
@@ -0,0 +1,10 @@
+// Copyright 2023 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// Identity trait defines the interface to access the SPDM identity key pair.
+pub trait Vendor {
+    /// Processes the vendor request to the vendor request handler, and put the
+    /// response back into `buf`, and return the response size.
+    fn process_vendor_request(&self, buf: &mut [u8], req_size: usize) -> usize;
+}
diff --git a/src/deps.rs b/src/deps.rs
index 7cd7a92..078701e 100644
--- a/src/deps.rs
+++ b/src/deps.rs
@@ -5,7 +5,9 @@
 use spdm_types::crypto::{
     AesGcm128Iv, AesGcm128Tag, EcP256UncompressedPoint, EcdsaP256Signature, Sha256Hash,
 };
-use spdm_types::deps::{Crypto, CryptoResult, CryptoStatus, Identity, IdentityPublicKey, SpdmDeps};
+use spdm_types::deps::{
+    Crypto, CryptoResult, CryptoStatus, Identity, IdentityPublicKey, SpdmDeps, Vendor,
+};
 use uninit::prelude::*;
 
 type IdentityPrivateKey = [u8; 32];
@@ -166,9 +168,19 @@
     }
 }
 
+/// Implements Vendor by interacting with the eal callback functions.
+pub struct EalVendor;
+
+impl Vendor for EalVendor {
+    fn process_vendor_request(&self, _buf: &mut [u8], _req_size: usize) -> usize {
+        unimplemented!()
+    }
+}
+
 pub struct SpdmEalDeps;
 
 impl SpdmDeps for SpdmEalDeps {
     type Crypto = EalCrypto;
     type Identity = EalIdentity;
+    type Vendor = EalVendor;
 }
diff --git a/src/lib.rs b/src/lib.rs
index 6361716..74abf8b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,7 +9,7 @@
 
 use core::mem::size_of;
 
-use deps::{EalIdentity, SpdmEalDeps};
+use deps::{EalIdentity, EalVendor, SpdmEalDeps};
 use spdm::{Spdm, SpdmDispatcher};
 
 #[cfg(not(feature = "std"))]
@@ -33,13 +33,14 @@
 #[no_mangle]
 pub unsafe extern "C" fn spdm_initialize(spdm: *mut SpdmFFI) {
     let spdm: &mut Spdm<SpdmEalDeps> = &mut *spdm.cast();
-    *spdm = Spdm::<SpdmEalDeps>::new(EalIdentity);
+    *spdm = Spdm::<SpdmEalDeps>::new(EalIdentity, EalVendor);
 }
 
 /// # Safety
 /// - `spdm` must be valid pointer for `SpdmFFI`, and the pointed data should have
 /// been initialized by `spdm_initialize` first.
 /// - `buf` must be valid pointer for `req_size` bytes, and writeable for `resp_size` bytes.
+/// - `resp_size` must be non-null.
 ///
 /// Dispatches the SPDM request to the global SPDM responder state machine.
 ///