GithubHelp home page GithubHelp logo

rust-spdm's Introduction

rust-spdm

RUN CODE codecov

A rust version SPDM implementation.

NOTE

This project is moved to https://github.com/intel/rust-spdm. This repo will be achieved as read-only.

Features

Specification

DSP0274 Security Protocol and Data Model (SPDM) Specification (version 1.0.1, version 1.1.2 and version 1.2.1)

DSP0277 Secured Messages using SPDM Specification (version 1.1.0)

Implemented Requests and Responses

SPDM 1.0: GET_VERSION, GET_CAPABILITIES, NEGOTIATE_ALGORITHMS, GET_DIGESTS, GET_CERTIFICATE, CHALLENGE, and GET_MEASUREMENTS.

SPDM 1.1: KEY_EXCHANGE, FINISH, PSK_EXCHANGE, PSK_FINISH, END_SESSION, HEARTBEAT, KEY_UPDATE messages.

SPDM 1.2: N/A. New SPDM 1.2 messages are not supported yet.

Capability Support

Requester: ENCRYPT_CAP, MAC_CAP, KEY_EX_CAP, PSK_CAP, HBEAT_CAP, KEY_UPD_CAP, HANDSHAKE_IN_THE_CLEAR_CAP.

Responder: CERT_CAP, CHAL_CAP, MEAS_CAP_NO_SIG, MEAS_CAP_SIG, MEAS_FRESH_CAP, ENCRYPT_CAP, MAC_CAP, KEY_EX_CAP, PSK_CAP_WITHOUT_CONTEXT, PSK_CAP_WITH_CONTEXT, HBEAT_CAP, KEY_UPD_CAP, HANDSHAKE_IN_THE_CLEAR_CAP.

Cryptographic Algorithm Support

It depends on crypto wrapper. Current support algorithms:

  • Hash: SHA2(256/384/512)
  • Signature: RSA-SSA(2048/3072/4096) / RSA-PSS(2048/3072/4096) / ECDSA (P256/P384)
  • KeyExchange: ECDHE(P256/P384)
  • AEAD: AES_GCM(128/256) / ChaCha20Poly1305

Documentation

All documents are put at doc folder.

Build Rust SPDM

Checkout repo

git clone https://github.com/jyao1/rust-spdm.git
git submodule update --init --recursive

Then patch the ring/webpki.

sh_script/pre-build.sh

Tools

  1. Install RUST

Please use nightly-2022-11-21.

  1. Install NASM

Please make sure nasm can be found in PATH.

  1. Install LLVM

Please make sure clang can be found in PATH.

  1. Install Perl

    1. This is for crate ring
    2. This is for windows

Please make sure perl can be found in PATH.

Unset env (CC and AR):

export CC=
export AR=

Set the following environment variables:

export AR_x86_64_unknown_none=llvm-ar
export CC_x86_64_unknown_none=clang

Build OS application

Enter linux shell or mingw shell (e.g. git bash) in windows.

cargo clippy
cargo fmt
cargo build

Build no_std spdm

pushd spdmlib
cargo build -Z build-std=core,alloc,compiler_builtins --target x86_64-unknown-none --release --no-default-features --features="spdm-ring"

Run emulator with default feature

Open one command windows and run:

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data"

Open another command windows and run:

cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data"

Run emulator with selected feature

The following list shows the supported combinations for both spdm-requester-emu and spdm-responder-emu

Features CryptoLibrary Hashed transcript data support Notes
spdm-ring ring No use ring as crypto library with hashed-transcript-data disabled
spdm-ring,hashed-transcript-data ring Yes use ring as crypto library with hashed-transcript-data enabled
spdm-mbedtls mbedtls No use mbedtls as crypto library with hashed-transcript-data disabled
spdm-mbedtls,hashed-transcript-data,spdm-mbedtls-hashed-transcript-data mbedtls Yes use mbedtls as crypto library with hashed-transcript-data

For example, run the emulator with spdm-ring enabled and without hashed-transcript-data enabled.
Open one command windows and run:

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring"

run the emulator with spdm-mbedtls enabled and with hashed-transcript-data enabled.
Open another command windows and run:

cargo run -p spdm-requester-emu --no-default-features --features "spdm-mbedtls,hashed-transcript-data,spdm-mbedtls-hashed-transcript-data"

NOTE: In order to run the emu without hashed-transcript-data, please change max_cert_chain_data_size in spdmlib/etc/config.json from 4096 to 3500.

Cross test with spdm_emu

Open one command windows in workspace and run:

git clone https://github.com/DMTF/spdm-emu.git
cd spdm-emu
git submodule update --init --recursive
mkdir build
cd build
cmake -G"NMake Makefiles" -DARCH=<x64|ia32> -DTOOLCHAIN=<toolchain> -DTARGET=<Debug|Release> -DCRYPTO=<mbedtls|openssl> ..
nmake copy_sample_key
nmake

Test rust-spdm as requester:

  1. run libspdm in spdm-emu as responder:
cd bin
spdm_responder_emu.exe --trans PCI_DOE
  1. run rust-spdm-emu as requester:
cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data"

Test rust-spdm as responder:

  1. run rust-spdm-emu as Test rust-spdm as responder:
cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data"
  1. run libspdm in spdm-emu as requester:
cd bin
spdm_requester_emu.exe --trans PCI_DOE --exe_conn DIGEST,CERT,CHAL,MEAS --exe_session KEY_EX,PSK,KEY_UPDATE,HEARTBEAT,MEAS,DIGEST,CERT

Run test cases

Test with hashed-transcript-data:

cargo test --no-default-features --features "spdmlib/std,spdmlib/spdm-ring,spdmlib/hashed-transcript-data" -- --test-threads=1

Test without hashed-transcript-data:

cargo test --no-default-features --features "spdmlib/std,spdmlib/spdm-ring" -- --test-threads=1

To run a specific test, use cargo test <test_func_name>

To run test with println!() message, use cargo test -- --nocapture

Known limitation

This package is only the sample code to show the concept. It does not have a full validation such as robustness functional test and fuzzing test. It does not meet the production quality yet. Any codes including the API definition, the libary and the drivers are subject to change.

rust-spdm's People

Contributors

andrewjstone avatar gaojiaqi7 avatar haowqs avatar jyao1 avatar kailun-qin avatar liuw1 avatar liyi77 avatar longlongyang avatar mxu9 avatar sameo avatar xiaohanjlll avatar xiaotia3 avatar xiaoyuxlu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rust-spdm's Issues

[bug fix] Data may be out of bounds

rust-spdm/spdmlib/src/requester/get_certificate_req.rs

line 61

if (offset + certificate.portion_length) as usize > config::MAX_SPDM_CERT_CHAIN_DATA_SIZE {
    return spdm_result_err!(ENOMEM);
}

enable rudra report

We need understand this case:
Component A includes Component B.
If component B has a security bug, can we scan Component A and find the issue?

Decouple SpdmDeviceIo from contexts ?

Hi maintainers,

Thank you for the wonderful project!

I'm opening this issue only to see if you are open to me making the change described below. Such a change will be relatively invasive, but will not change the core logic of the protocol, which should hopefully make it straightforward to review.

I'm looking to abstract out the SpdmDeviceIo from inside the SpdmContext and correspondingly the RequesterContext and ResponderContext. The end result is that the send_receive_xxx calls such as send_receive_spdm_key_exchange will be split into multiple methods. First a message is created and returned. Then the caller uses some mechanism(possibly an existingio_device), to send the message. Then the caller uses the same mechanism to receive and return a message. Finally a method is called to handle the received message. In a synchronous world this would look something like:

let send_used = request_ctx.spdm_key_exchange_req(send_buf, slot_id, measurement_summary_hash_type);
io_device.send_message(&send_buf[..send_used])?;
let received_used = io_device.receive_message(&mut recv_buf)?;
request_ctx.spdm_handle_key_exchange_rsp(&recv_buf[..receive_used])?;

If such a change was made, we could still keep the RequesterCtx::send_receive_xxx methods, but the internals would look similar to above. The signature would just change to take a &mut dyn SpdmDeviceIO rather than embedding it in the context. This would allow the calling code, such as RequesterCtx::start_session to continue to use this synchronous send/receive pattern. It would also allow other users to reuse the message creation and handler code without having to use a SpdmDeviceIo. This opens up the code base to being used in different contexts than originally anticipated, and will also likely make it easier to test.

It could even make sense to break the raw message creation and handler methods into their own types that can be used by the RequesterContext and ResponderContext. That would allow maintaining the same external interfaces to the contexts, including making the SpdmDeviceIo a member of RequesterContext and ResponderContext, just not SpdmContext. Such a change would allow different use cases from yours to use the bulk of the code from the lower level types, while the higher level types could still be used ergonomically for your purposes.

Now that I've described the change, let me describe my use cases which I'm using to justify such a change.

I have two vastly different use cases for SPDM:

  1. An embedded kernel running on a micro-controller with limited resources
  2. A secure bootstrapping mechanism in user space that will require many simultaneous network connections.

For the first case, tasks in our OS cannot share text, so removing the blocking SpdmDeviceIO calls from the protocol logic allows us to write code such that multiple sessions can live in a single kernel task without having to duplicate all the compiled code for this library.

For the second case, we are trying to use spdm for remote attestation purposes over TCP for 10s to potentially 100s of endpoints. We'd prefer not to have to maintain a thread per connection, and instead use async io.

The recommended change above would enable both of those and expand the reach of this code base to new domains. I hope you are ok with it!

Thank you for your time and consideration.

use case to run test with test key

Current design does not have test key as input parameter. So we only support below 5 cases:

  1. Visual Studio Code: debug
  2. Visual Studio Code: run
  3. command line: cargo test
  4. command line: cargo run
  5. arbitrary dir (local machine): run .exe

We do NOT support below case:
6) arbitrary dir (copy exe/test key to remote machine): run .exe -- not supported, unless all path are same.
Reason: test key dir is not a parameter.

[bug fix] Data may be out of bounds

rust-spdm/spdmlib/src/requester/get_certificate_req.rs

line 61

if certificate.portion_length as usize > config::MAX_SPDM_CERT_PORTION_LEN
                            || (offset + certificate.portion_length) as usize
                                > config::MAX_SPDM_CERT_CHAIN_DATA_SIZE

[bug fix] Data may be out of bounds

rust-spdm/spdmlib/src/requester/get_measurements_req.rs

line 150

for block_i in 1..total_number.checked_add(1).ok_or(spdm_err!(ENOMEM))? {

[bug fix] Data may be empty

rust-spdm/spdmlib/src/responder/psk_exchange_rsp.rs

line 52

if self.common.negotiate_info.base_hash_sel.is_empty() {
    return;
}

Fix default buffer size as used in send_secured_message

max_msg_buffer_size > max_transport_size which can result in an encrypted application message not being able able to be encoded because the source buffer is larger than the destination buffer.

See

  • "max_msg_buffer_size": 4608,
    "max_transport_size": 1024
  • pub fn send_secured_message(&mut self, session_id: u32, send_buffer: &[u8]) -> SpdmResult {
    let mut app_buffer = [0u8; config::MAX_SPDM_MESSAGE_BUFFER_SIZE];
    let used = self
    .common
    .transport_encap
    .encap_app(send_buffer, &mut app_buffer)?;
    let spdm_session = self
    .common
    .get_session_via_id(session_id)
    .ok_or(spdm_err!(EINVAL))?;
    let mut encoded_send_buffer = [0u8; config::MAX_SPDM_MESSAGE_BUFFER_SIZE];
    let encode_size = spdm_session.encode_spdm_secured_message(
    &app_buffer[0..used],
    &mut encoded_send_buffer,
    true,
    )?;
    let mut transport_buffer = [0u8; config::MAX_SPDM_TRANSPORT_SIZE];
    let used = self.common.transport_encap.encap(
    &encoded_send_buffer[..encode_size],
    &mut transport_buffer,
    true,
    )?;
    self.common.device_io.send(&transport_buffer[..used])
    }

CI: Need add `no_std` for building spmdlib

spdmlib can be used in no_std environment. CI should do this check.

cd spdmlib
cargo xbuild --target x86_64-unknown-uefi --release --no-default-features --features="spdm-ring"

[bug fix] Unpacking error may occur

rust-spdm/spdmlib/src/responder/algorithm_rsp.rs

line 98

if let Some(root_hash) = crypto::hash::hash_all(self.common.negotiate_info.base_hash_sel, root_cert) {
    let data_size = 4 + root_hash.data_size + cert_chain.data_size;
    let mut data = [0u8; config::MAX_SPDM_CERT_CHAIN_DATA_SIZE];
    data[0] = (data_size & 0xFF) as u8;
    data[1] = (data_size >> 8) as u8;
    data[4..(4 + root_hash.data_size as usize)]
        .copy_from_slice(&root_hash.data[..(root_hash.data_size as usize)]);
    data[(4 + root_hash.data_size as usize)..(data_size as usize)]
        .copy_from_slice(&cert_chain.data[..(cert_chain.data_size as usize)]);
    self.common.provision_info.my_cert_chain = Some(SpdmCertChainData { data_size, data });
    debug!("my_cert_chain - {:02x?}\n", &data[..(data_size as usize)]);
} else {
    return;
}

[bug fix] data out of bounds

rust-spdm/spdmlib/src/requester/get_certificate_req.rs
line 116
if self.common.peer_info.peer_cert_chain.cert_chain.data_size <= (4 + self.common.negotiate_info.base_hash_sel.get_size()) { return spdm_result_err!(EIO); }

[bug fix] Unpacking error may occur

rust-spdm/spdmlib/src/responder/key_exchange_rsp.rs

line 49

    .compute_final_key(&key_exchange_req.unwrap().exchange);
    
    if final_key.is_none(){
        return;
    }
    let final_key = final_key.unwrap();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.