From 1bab91bb3c763783f8558909bdab7efa8e4ab2d6 Mon Sep 17 00:00:00 2001 From: Jo Van Bulck Date: Wed, 20 Oct 2021 12:08:18 +0200 Subject: [PATCH] Merge pull request #37 from gianlu33/sancus-untag Add `sancus_untag` functions and fix `sancus_unwrap_with_key` --- src/sancus_support/sm_support.h | 107 ++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/src/sancus_support/sm_support.h b/src/sancus_support/sm_support.h index 0537f12..5b9f11d 100644 --- a/src/sancus_support/sm_support.h +++ b/src/sancus_support/sm_support.h @@ -340,8 +340,47 @@ always_inline int is_buffer_outside_region(void *start_p, void *end_p, return 0; } +/** + * Performs constant time comparison between to buffers + * Returns 0 if the first `n` bytes of the two buffers are equal, -1 otherwise + * NOTE: Function copied from NaCL's libsodium, re-use allowed under ISC license. + */ +always_inline int constant_time_cmp(const unsigned char *x_, + const unsigned char *y_, + const unsigned int n) +{ + const volatile unsigned char *volatile x = + (const volatile unsigned char *volatile) x_; + const volatile unsigned char *volatile y = + (const volatile unsigned char *volatile) y_; + volatile unsigned int d = 0U; + int i; + + for (i = 0; i < n; i++) { + d |= x[i] ^ y[i]; + } + + return (1 & ((d - 1) >> 8)) - 1; +} + /** * Disable the protection of the calling module. + * DANGEROUS: Disable the protection of the calling module. + * + * NOTE: On Sancus cores that support interruptible enclaves, the + * compiler/runtime does _not_ transparently take care of atomicity concerns + * when disabling enclaves, i.e., secure linking is currently not meant to be + * interrupt-safe. If this SM is being called by another one, the other SM may + * be interrupted between the sm_verify check and the actual call into the + * function. If sancus_disable is executed in this window, an attacker could + * fully control the SM call and the return to the other SM. + + * Thus, for callee SMs that may disable themselves, local attestation through + * sancus_verify and jumping to callee SM entry point needs to happen + * atomically. This concern is left to the application developer, e.g., SMs + * should not call sancus_disable when they might still be called by a + * trusted caller SM (and the caller SM can verify this is indeed not the case + * by local attestation of the callee SM code section). */ always_inline void sancus_disable(void *continuation) { @@ -492,6 +531,51 @@ always_inline int sancus_wrap(const void* ad, size_t ad_len, return sancus_wrap_with_key(NULL, ad, ad_len, body, body_len, cipher, tag); } +/** + * The same as sancus_wrap_with_key() but only produces the MAC of the message. + */ +always_inline int sancus_tag_with_key(const void* key, + const void* body, size_t body_len, + void* tag) +{ + return sancus_wrap_with_key(key, body, body_len, NULL, 0, NULL, tag); +} + +/** + * The same as sancus_wrap() but only produces the MAC of the message. + */ +always_inline int sancus_tag(const void* body, size_t body_len, void* tag) +{ + return sancus_wrap(body, body_len, NULL, 0, NULL, tag); +} + +/** + * Verify if the MAC computed over `body` matches with the content of `tag` + */ +always_inline int sancus_untag_with_key(const void* key, const void* body, + size_t body_len, const void* tag) +{ + unsigned char computed_tag[SANCUS_TAG_SIZE]; + + // compute MAC over `body` + if ( !sancus_tag_with_key(key, body, body_len, computed_tag) ) { + return 0; + } + + // compare MAC with provided reference `tag` + return (constant_time_cmp(tag, computed_tag, SANCUS_TAG_SIZE) == 0); +} + +/** +* Verify if the MAC computed over `body` matches with the content of `tag` +* +* This is the same as sancus_untag_with_key using the key of the caller module. +*/ +always_inline int sancus_untag(const void* body, size_t body_len, const void* tag) +{ + return sancus_untag_with_key(NULL, body, body_len, tag); +} + /** * Unwrap a message using the Sancus authenticated encryption features. * @@ -503,6 +587,11 @@ always_inline int sancus_unwrap_with_key(const void* key, size_t cipher_len, const void* tag, void* body) { + // fix: if cipher_len is zero, just compare the MACs using sancus_untag + if(cipher_len == 0) { + return sancus_untag_with_key(key, ad, ad_len, tag); + } + void* ad_end = (char*)ad + ad_len; void* cipher_end = (char*)cipher + cipher_len; int ret; @@ -542,24 +631,6 @@ always_inline int sancus_unwrap(const void* ad, size_t ad_len, tag, body); } -/** - * The same as sancus_wrap() but only produces the MAC of the message. - */ -always_inline int sancus_tag(const void* body, size_t body_len, void* tag) -{ - return sancus_wrap(body, body_len, NULL, 0, NULL, tag); -} - -/** - * The same as sancus_wrap_with_key() but only produces the MAC of the message. - */ -always_inline int sancus_tag_with_key(const void* key, - const void* body, size_t body_len, - void* tag) -{ - return sancus_wrap_with_key(key, body, body_len, NULL, 0, NULL, tag); -} - /** * Get the Sancus ID of the module loaded at @p addr. */