aws_ne_sys/
lib.rs

1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3// Modifications Copyright (c) 2021, Foris Limited (licensed under the Apache License, Version 2.0)
4
5mod ffi;
6
7#[derive(Debug)]
8pub enum Error {
9    SdkInitError,
10    SdkGenericError,
11    SdkKmsConfigError,
12    SdkKmsClientError,
13    SdkKmsDecryptError,
14    SdkKmsEncryptError,
15}
16
17/// KMS decrypt FFI wrapper
18/// TODO: Add a trait for Drop wrappers for SDK resources
19pub fn kms_decrypt(
20    aws_region: &[u8],
21    aws_key_id: &[u8],
22    aws_secret_key: &[u8],
23    aws_session_token: &[u8],
24    ciphertext: &[u8],
25) -> Result<Vec<u8>, Error> {
26    // Initialize the SDK
27    unsafe {
28        ffi::aws_nitro_enclaves_library_init(std::ptr::null_mut());
29    };
30
31    // Fetch allocator
32    let allocator = unsafe { ffi::aws_nitro_enclaves_get_allocator() };
33    if allocator.is_null() {
34        unsafe {
35            ffi::aws_nitro_enclaves_library_clean_up();
36        }
37        return Err(Error::SdkInitError);
38    }
39    // REGION
40    let region = unsafe {
41        let reg = ffi::aws_string_new_from_array(allocator, aws_region.as_ptr(), aws_region.len());
42        if reg.is_null() {
43            ffi::aws_nitro_enclaves_library_clean_up();
44            return Err(Error::SdkGenericError);
45        }
46        reg
47    };
48    // ENDPOINT
49    let mut endpoint = {
50        let mut ep = ffi::aws_socket_endpoint {
51            address: [0; ffi::AWS_ADDRESS_MAX_LEN],
52            port: ffi::AWS_NE_VSOCK_PROXY_PORT,
53        };
54        ep.address[..ffi::AWS_NE_VSOCK_PROXY_ADDR.len()]
55            .copy_from_slice(&ffi::AWS_NE_VSOCK_PROXY_ADDR);
56        ep
57    };
58    // AWS_ACCESS_KEY_ID
59    let key_id = unsafe {
60        let kid = ffi::aws_string_new_from_array(allocator, aws_key_id.as_ptr(), aws_key_id.len());
61        if kid.is_null() {
62            ffi::aws_string_destroy_secure(region);
63            ffi::aws_nitro_enclaves_library_clean_up();
64            return Err(Error::SdkGenericError);
65        }
66        kid
67    };
68    // AWS_SECRET_ACCESS_KEY
69    let secret_key = unsafe {
70        let skey = ffi::aws_string_new_from_array(
71            allocator,
72            aws_secret_key.as_ptr(),
73            aws_secret_key.len(),
74        );
75        if skey.is_null() {
76            ffi::aws_string_destroy_secure(key_id);
77            ffi::aws_string_destroy_secure(region);
78            ffi::aws_nitro_enclaves_library_clean_up();
79            return Err(Error::SdkGenericError);
80        }
81        skey
82    };
83    // AWS_SESSION_TOKEN
84    let session_token = unsafe {
85        let sess_token = ffi::aws_string_new_from_array(
86            allocator,
87            aws_session_token.as_ptr(),
88            aws_session_token.len(),
89        );
90        if sess_token.is_null() {
91            ffi::aws_string_destroy_secure(secret_key);
92            ffi::aws_string_destroy_secure(key_id);
93            ffi::aws_string_destroy_secure(region);
94            ffi::aws_nitro_enclaves_library_clean_up();
95            return Err(Error::SdkGenericError);
96        }
97        sess_token
98    };
99    // Construct KMS client configuration
100    let kms_client_cfg = unsafe {
101        // Configure
102        let cfg = ffi::aws_nitro_enclaves_kms_client_config_default(
103            region,
104            &mut endpoint,
105            ffi::AWS_SOCKET_VSOCK_DOMAIN,
106            key_id,
107            secret_key,
108            session_token,
109        );
110
111        if cfg.is_null() {
112            ffi::aws_string_destroy_secure(key_id);
113            ffi::aws_string_destroy_secure(secret_key);
114            ffi::aws_string_destroy_secure(session_token);
115            ffi::aws_string_destroy_secure(region);
116            ffi::aws_nitro_enclaves_library_clean_up();
117            return Err(Error::SdkKmsConfigError);
118        }
119        cfg
120    };
121    // Construct KMS Client
122    let kms_client = unsafe { ffi::aws_nitro_enclaves_kms_client_new(kms_client_cfg) };
123    if kms_client.is_null() {
124        unsafe {
125            ffi::aws_string_destroy_secure(key_id);
126            ffi::aws_string_destroy_secure(secret_key);
127            ffi::aws_string_destroy_secure(session_token);
128            ffi::aws_string_destroy_secure(region);
129            ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
130            ffi::aws_nitro_enclaves_library_clean_up();
131        }
132        return Err(Error::SdkKmsClientError);
133    }
134    // Ciphertext
135    let ciphertext_buf = unsafe {
136        ffi::aws_byte_buf_from_array(ciphertext.as_ptr() as *mut ffi::c_void, ciphertext.len())
137    };
138
139    // Decrypt
140    let mut plaintext_buf: ffi::aws_byte_buf = unsafe { std::mem::zeroed() };
141    let rc =
142        unsafe { ffi::aws_kms_decrypt_blocking(kms_client, &ciphertext_buf, &mut plaintext_buf) };
143    if rc != 0 {
144        unsafe {
145            ffi::aws_string_destroy_secure(key_id);
146            ffi::aws_string_destroy_secure(secret_key);
147            ffi::aws_string_destroy_secure(session_token);
148            ffi::aws_string_destroy_secure(region);
149            ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
150            ffi::aws_nitro_enclaves_kms_client_destroy(kms_client);
151            ffi::aws_nitro_enclaves_library_clean_up();
152        }
153        return Err(Error::SdkKmsDecryptError);
154    }
155
156    // Cleanup
157    unsafe {
158        ffi::aws_string_destroy_secure(key_id);
159        ffi::aws_string_destroy_secure(secret_key);
160        ffi::aws_string_destroy_secure(session_token);
161        ffi::aws_string_destroy_secure(region);
162        ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
163        ffi::aws_nitro_enclaves_kms_client_destroy(kms_client);
164        ffi::aws_nitro_enclaves_library_clean_up();
165    }
166
167    // Plaintext
168    let plaintext = unsafe {
169        std::slice::from_raw_parts(plaintext_buf.buffer, plaintext_buf.len as usize).to_vec()
170    };
171    unsafe { ffi::aws_byte_buf_clean_up_secure(&mut plaintext_buf) };
172
173    Ok(plaintext)
174}
175
176/// FFI wrapper to seed initial entropy using NSM
177pub fn seed_entropy(bytes_to_seed: usize) -> Result<(), ()> {
178    let rc = unsafe { ffi::aws_nitro_enclaves_library_seed_entropy(bytes_to_seed) };
179    if rc == 0 {
180        Ok(())
181    } else {
182        Err(())
183    }
184}
185
186/// KMS encrypt FFI wrapper
187/// TODO: Add a trait for Drop wrappers for SDK resources
188pub fn kms_encrypt(
189    aws_region: &[u8],
190    aws_key_id: &[u8],
191    aws_secret_key: &[u8],
192    aws_session_token: &[u8],
193    aws_kms_key_id: &[u8],
194    plaintext: &[u8],
195) -> Result<Vec<u8>, Error> {
196    // Initialize the SDK
197    unsafe {
198        ffi::aws_nitro_enclaves_library_init(std::ptr::null_mut());
199    };
200
201    // Fetch allocator
202    let allocator = unsafe { ffi::aws_nitro_enclaves_get_allocator() };
203    if allocator.is_null() {
204        unsafe {
205            ffi::aws_nitro_enclaves_library_clean_up();
206        }
207        return Err(Error::SdkInitError);
208    }
209    // REGION
210    let region = unsafe {
211        let reg = ffi::aws_string_new_from_array(allocator, aws_region.as_ptr(), aws_region.len());
212        if reg.is_null() {
213            ffi::aws_nitro_enclaves_library_clean_up();
214            return Err(Error::SdkGenericError);
215        }
216        reg
217    };
218    // ENDPOINT
219    let mut endpoint = {
220        let mut ep = ffi::aws_socket_endpoint {
221            address: [0; ffi::AWS_ADDRESS_MAX_LEN],
222            port: ffi::AWS_NE_VSOCK_PROXY_PORT,
223        };
224        ep.address[..ffi::AWS_NE_VSOCK_PROXY_ADDR.len()]
225            .copy_from_slice(&ffi::AWS_NE_VSOCK_PROXY_ADDR);
226        ep
227    };
228    // AWS_ACCESS_KEY_ID
229    let key_id = unsafe {
230        let kid = ffi::aws_string_new_from_array(allocator, aws_key_id.as_ptr(), aws_key_id.len());
231        if kid.is_null() {
232            ffi::aws_string_destroy_secure(region);
233            ffi::aws_nitro_enclaves_library_clean_up();
234            return Err(Error::SdkGenericError);
235        }
236        kid
237    };
238    // AWS_SECRET_ACCESS_KEY
239    let secret_key = unsafe {
240        let skey = ffi::aws_string_new_from_array(
241            allocator,
242            aws_secret_key.as_ptr(),
243            aws_secret_key.len(),
244        );
245        if skey.is_null() {
246            ffi::aws_string_destroy_secure(key_id);
247            ffi::aws_string_destroy_secure(region);
248            ffi::aws_nitro_enclaves_library_clean_up();
249            return Err(Error::SdkGenericError);
250        }
251        skey
252    };
253    // AWS_SESSION_TOKEN
254    let session_token = unsafe {
255        let sess_token = ffi::aws_string_new_from_array(
256            allocator,
257            aws_session_token.as_ptr(),
258            aws_session_token.len(),
259        );
260        if sess_token.is_null() {
261            ffi::aws_string_destroy_secure(secret_key);
262            ffi::aws_string_destroy_secure(key_id);
263            ffi::aws_string_destroy_secure(region);
264            ffi::aws_nitro_enclaves_library_clean_up();
265            return Err(Error::SdkGenericError);
266        }
267        sess_token
268    };
269    // AWS KMS Key ID
270    let kms_key_id = unsafe {
271        let kms_kid = ffi::aws_string_new_from_array(
272            allocator,
273            aws_kms_key_id.as_ptr(),
274            aws_kms_key_id.len(),
275        );
276        if kms_kid.is_null() {
277            ffi::aws_string_destroy_secure(secret_key);
278            ffi::aws_string_destroy_secure(key_id);
279            ffi::aws_string_destroy_secure(region);
280            ffi::aws_string_destroy_secure(session_token);
281            ffi::aws_nitro_enclaves_library_clean_up();
282            return Err(Error::SdkGenericError);
283        }
284        kms_kid
285    };
286
287    // Construct KMS client configuration
288    let kms_client_cfg = unsafe {
289        // Configure
290        let cfg = ffi::aws_nitro_enclaves_kms_client_config_default(
291            region,
292            &mut endpoint,
293            ffi::AWS_SOCKET_VSOCK_DOMAIN,
294            key_id,
295            secret_key,
296            session_token,
297        );
298
299        if cfg.is_null() {
300            ffi::aws_string_destroy_secure(key_id);
301            ffi::aws_string_destroy_secure(secret_key);
302            ffi::aws_string_destroy_secure(session_token);
303            ffi::aws_string_destroy_secure(region);
304            ffi::aws_string_destroy_secure(kms_key_id);
305            ffi::aws_nitro_enclaves_library_clean_up();
306            return Err(Error::SdkKmsConfigError);
307        }
308        cfg
309    };
310    // Construct KMS Client
311    let kms_client = unsafe { ffi::aws_nitro_enclaves_kms_client_new(kms_client_cfg) };
312    if kms_client.is_null() {
313        unsafe {
314            ffi::aws_string_destroy_secure(key_id);
315            ffi::aws_string_destroy_secure(secret_key);
316            ffi::aws_string_destroy_secure(session_token);
317            ffi::aws_string_destroy_secure(region);
318            ffi::aws_string_destroy_secure(kms_key_id);
319            ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
320            ffi::aws_nitro_enclaves_library_clean_up();
321        }
322        return Err(Error::SdkKmsClientError);
323    }
324    // Plaintext
325    let plaintext_buf = unsafe {
326        ffi::aws_byte_buf_from_array(plaintext.as_ptr() as *mut ffi::c_void, plaintext.len())
327    };
328
329    // Encrypt
330    let mut ciphertext_buf: ffi::aws_byte_buf = unsafe { std::mem::zeroed() };
331    let rc = unsafe {
332        ffi::aws_kms_encrypt_blocking(kms_client, kms_key_id, &plaintext_buf, &mut ciphertext_buf)
333    };
334    if rc != 0 {
335        unsafe {
336            ffi::aws_string_destroy_secure(key_id);
337            ffi::aws_string_destroy_secure(secret_key);
338            ffi::aws_string_destroy_secure(session_token);
339            ffi::aws_string_destroy_secure(region);
340            ffi::aws_string_destroy_secure(kms_key_id);
341            ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
342            ffi::aws_nitro_enclaves_kms_client_destroy(kms_client);
343            ffi::aws_nitro_enclaves_library_clean_up();
344        }
345        return Err(Error::SdkKmsEncryptError);
346    }
347
348    // Cleanup
349    unsafe {
350        ffi::aws_string_destroy_secure(key_id);
351        ffi::aws_string_destroy_secure(secret_key);
352        ffi::aws_string_destroy_secure(session_token);
353        ffi::aws_string_destroy_secure(region);
354        ffi::aws_string_destroy_secure(kms_key_id);
355        ffi::aws_nitro_enclaves_kms_client_config_destroy(kms_client_cfg);
356        ffi::aws_nitro_enclaves_kms_client_destroy(kms_client);
357        ffi::aws_nitro_enclaves_library_clean_up();
358    }
359
360    // Ciphertext
361    let ciphertext = unsafe {
362        std::slice::from_raw_parts(ciphertext_buf.buffer, ciphertext_buf.len as usize).to_vec()
363    };
364    unsafe { ffi::aws_byte_buf_clean_up_secure(&mut ciphertext_buf) };
365
366    Ok(ciphertext)
367}