Skip to main content

islet_sdk/
c_api.rs

1use crate::prelude::*;
2
3use bincode::{deserialize, serialize};
4use std::ffi::{c_char, c_int, c_uchar, CStr};
5use std::slice::{from_raw_parts, from_raw_parts_mut};
6
7const STR_REALM_CHALLENGE: &str = "Realm challenge";
8const STR_REALM_INITIAL_MEASUREMENT: &str = "Realm initial measurement";
9const STR_USER_DATA: &str = "User data";
10const STR_PLAT_PROFILE: &str = "Profile";
11
12#[allow(non_camel_case_types)]
13#[repr(C)]
14pub enum islet_status_t {
15    ISLET_SUCCESS = 0,
16    ISLET_FAILURE = -1,
17    ISLET_ERROR_INPUT = -2,
18    ISLET_ERROR_WRONG_REPORT = -3,
19    ISLET_ERROR_WRONG_CLAIMS = -4,
20    ISLET_ERROR_FEATURE_NOT_SUPPORTED = -5,
21}
22
23/// Get an attestation report(token).
24///
25/// # Note
26/// This API currently returns hard-coded report to simulate attest operation.
27/// In future, this will be finalized to support reports signed by RMM.
28/// `User data` could be used as nonce to prevent reply attack.
29#[no_mangle]
30pub unsafe extern "C" fn islet_attest(
31    user_data: *const c_uchar,
32    user_data_len: c_int,
33    report_out: *mut c_uchar,
34    report_out_len: *mut c_int,
35) -> islet_status_t {
36    if user_data_len > 64 {
37        return islet_status_t::ISLET_ERROR_INPUT;
38    }
39
40    let do_attest = || -> Result<(), Error> {
41        let user_data = from_raw_parts(user_data as *const u8, user_data_len as usize);
42        let report = attest(user_data)?;
43        let encoded = serialize(&report).or(Err(Error::Serialize))?;
44        *report_out_len = encoded.len() as c_int;
45        let out = from_raw_parts_mut(report_out, encoded.len());
46        out.copy_from_slice(&encoded[..]);
47        Ok(())
48    };
49
50    match do_attest() {
51        Ok(()) => islet_status_t::ISLET_SUCCESS,
52        Err(_) => islet_status_t::ISLET_FAILURE,
53    }
54}
55
56/// Verify the attestation report and returns attestation claims if succeeded.
57#[no_mangle]
58pub unsafe extern "C" fn islet_verify(
59    report: *const c_uchar,
60    report_len: c_int,
61    claims_out: *mut c_uchar,
62    claims_out_len: *mut c_int,
63) -> islet_status_t {
64    let do_verify = || -> Result<(), Error> {
65        let encoded = from_raw_parts(report as *const u8, report_len as usize);
66        let decoded: Report = deserialize(encoded).or(Err(Error::Report))?;
67
68        let _claims = verify(&decoded)?;
69
70        // Encode the report instead of the claims.
71        // Because the claims couldn't serialize now.
72        let out = std::slice::from_raw_parts_mut(claims_out, encoded.len());
73        out.copy_from_slice(&encoded[..]);
74        *claims_out_len = out.len() as c_int;
75        Ok(())
76    };
77
78    match do_verify() {
79        Ok(()) => islet_status_t::ISLET_SUCCESS,
80        Err(Error::Report) => islet_status_t::ISLET_ERROR_WRONG_REPORT,
81        Err(_) => islet_status_t::ISLET_FAILURE,
82    }
83}
84
85/// Parse the claims with the given title and returns the claim if succeeded.
86#[no_mangle]
87pub unsafe extern "C" fn islet_parse(
88    title: *const c_char,
89    claims: *const c_uchar,
90    claims_len: c_int,
91    value_out: *mut c_uchar,
92    value_out_len: *mut c_int,
93) -> islet_status_t {
94    let do_parse = || -> Result<(), Error> {
95        // Actually the report is passed instead of the claims
96        // ref. islet_verify()
97        let encoded = from_raw_parts(claims as *const u8, claims_len as usize);
98        let decoded: Report = deserialize(encoded).or(Err(Error::Report))?;
99
100        let claims = verify(&decoded)?;
101        let title = CStr::from_ptr(title).to_str().or(Err(Error::Decoding))?;
102
103        let (realm_claims, plat_claims) = parse(&claims)?;
104        let value = if title == STR_USER_DATA || title == STR_REALM_CHALLENGE {
105            Ok(realm_claims.challenge.clone())
106        } else if title == STR_REALM_INITIAL_MEASUREMENT {
107            Ok(realm_claims.rim.clone())
108        } else if title == STR_PLAT_PROFILE {
109            Ok(plat_claims.profile.as_bytes().to_vec())
110        } else {
111            Err(Error::NotSupported)
112        }?;
113        *value_out_len = value.len() as c_int;
114        let out = from_raw_parts_mut(value_out, value.len());
115        out.copy_from_slice(&value[..]);
116
117        Ok(())
118    };
119
120    match do_parse() {
121        Ok(()) => islet_status_t::ISLET_SUCCESS,
122        Err(Error::Claims) => islet_status_t::ISLET_ERROR_WRONG_CLAIMS,
123        Err(_) => islet_status_t::ISLET_FAILURE,
124    }
125}
126
127/// Print all claims including Realm Token and Platform Token.
128#[no_mangle]
129pub unsafe extern "C" fn islet_print_claims(claims: *const c_uchar, claims_len: c_int) {
130    // Actually the report is passed instead of the claims
131    // ref. islet_verify()
132    let encoded = from_raw_parts(claims as *const u8, claims_len as usize);
133    let decoded: Result<Report, Error> = deserialize(encoded).or(Err(Error::Report));
134    if decoded.is_err() {
135        println!("Wrong claims.");
136    }
137
138    match verify(&decoded.unwrap()) {
139        Ok(claims) => crate::parser::print_claims(&claims),
140        Err(error) => println!("Wrong claims {:?}", error),
141    }
142}
143
144/// Seals the plaintext given into the binary slice
145///
146/// # Note
147/// This API currently seals with a hard-coded key, to simulate seal operation.
148/// In future, this will be finalized to support keys derived from HES.
149#[no_mangle]
150pub unsafe extern "C" fn islet_seal(
151    plaintext: *const c_uchar,
152    plaintext_len: c_int,
153    sealed_out: *mut c_uchar,
154    sealed_out_len: *mut c_int,
155) -> islet_status_t {
156    let do_seal = || -> Result<(), Error> {
157        let plaintext = from_raw_parts(plaintext as *const u8, plaintext_len as usize);
158        let sealed = seal(plaintext)?;
159        *sealed_out_len = sealed.len() as c_int;
160        let out = from_raw_parts_mut(sealed_out, sealed.len());
161        out.copy_from_slice(&sealed[..]);
162        Ok(())
163    };
164
165    match do_seal() {
166        Ok(()) => islet_status_t::ISLET_SUCCESS,
167        Err(_) => islet_status_t::ISLET_FAILURE,
168    }
169}
170
171/// Unseals into plaintext the sealed binary provided.
172///
173/// # Note
174/// This API currently unseals with a hard-coded key, to simulate unseal operation.
175/// In future, this will be finalized to support keys derived from HES.
176#[no_mangle]
177pub unsafe extern "C" fn islet_unseal(
178    sealed: *const c_uchar,
179    sealed_len: c_int,
180    plaintext_out: *mut c_uchar,
181    plaintext_out_len: *mut c_int,
182) -> islet_status_t {
183    let do_unseal = || -> Result<(), Error> {
184        let sealed = from_raw_parts(sealed as *const u8, sealed_len as usize);
185        let plaintext = unseal(sealed)?;
186        *plaintext_out_len = plaintext.len() as c_int;
187        let out = from_raw_parts_mut(plaintext_out, plaintext.len());
188        out.copy_from_slice(&plaintext[..]);
189        Ok(())
190    };
191
192    match do_unseal() {
193        Ok(()) => islet_status_t::ISLET_SUCCESS,
194        Err(_) => islet_status_t::ISLET_FAILURE,
195    }
196}