Attest: Get option flags from challenge object

Special option flags (for test purpose) can be passed in for
attestation service. These flags are encoded in the challenge object.
Previously a 36 bytes long challenge object was used to carry these
4 extra bytes, but attestation API requires the challenge object to be
only 32, 48 or 64 bytes long.

With this change the option flags are packed in a 64 bytes long
challenge object which has a predefined value. If the challenge object
is 64 byte long and the bytes from 4 to 63 have 0 value in this case
the first 4 bytes are handled as the option flags.

Change-Id: I2a4d0bf417905d74cca0fbdb5070cdef085fe308
Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
Co-authored-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/lib/ext/qcbor/inc/UsefulBuf.h b/lib/ext/qcbor/inc/UsefulBuf.h
index 0aaa9b6..682646e 100644
--- a/lib/ext/qcbor/inc/UsefulBuf.h
+++ b/lib/ext/qcbor/inc/UsefulBuf.h
@@ -1,7 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2019, Laurence Lundblade.
- All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -42,6 +41,7 @@
 
  when               who             what, where, why
  --------           ----            ---------------------------------------------------
+ 3/6/2019           llundblade      Add UsefulBuf_IsValue()
  12/17/2018         llundblade      Remove const from UsefulBuf and UsefulBufC .len
  12/13/2018         llundblade      Documentation improvements
  09/18/2018         llundblade      Cleaner distinction between UsefulBuf and UsefulBufC
@@ -480,10 +480,10 @@
 
 
 /**
- @brief Compare two UsefulBufCs
+ @brief Compare two UsefulBufCs.
 
- @param[in] UB1 The destination buffer to copy into
- @param[in] UB2  The source to copy from
+ @param[in] UB1  First UsefulBufC to compare.
+ @param[in] UB2  Second UsefulBufC to compare.
 
  @return 0 if equal...
 
@@ -504,6 +504,27 @@
 
 
 /**
+ @brief Find first byte that is not a particular byte value.
+
+ @param[in] UB     The destination buffer for byte comparison.
+ @param[in] uValue The byte value to compare to.
+
+ @return  Offset of first byte that isn't \c uValue or
+          SIZE_MAX if all bytes are \c uValue.
+
+ Note that unlike most comparison functions, 0
+ does not indicate a successful comparison,  so the
+ test for match is:
+
+      UsefulBuf_IsValue(...) == SIZE_MAX
+
+ If \c UB is NULL or empty, there is no match
+ and 0 is returned.
+ */
+size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
+
+
+/**
  @brief Find one UsefulBuf in another
 
  @param[in] BytesToSearch  UsefulBuf to search through
diff --git a/lib/ext/qcbor/inc/q_useful_buf.h b/lib/ext/qcbor/inc/q_useful_buf.h
index d7e38d4..4621fad 100644
--- a/lib/ext/qcbor/inc/q_useful_buf.h
+++ b/lib/ext/qcbor/inc/q_useful_buf.h
@@ -136,6 +136,12 @@
     return UsefulBuf_Compare(buf1, buf2);
 }
 
+static inline size_t q_useful_buf_is_value(const struct q_useful_buf_c buf,
+                                           uint8_t uValue)
+{
+    return UsefulBuf_IsValue(buf, uValue);
+}
+
 static inline size_t
 useful_buf_find_bytes(const struct q_useful_buf_c bytes_to_search,
                       const struct q_useful_buf_c bytes_to_find)
diff --git a/lib/ext/qcbor/src/UsefulBuf.c b/lib/ext/qcbor/src/UsefulBuf.c
index 5a7d37b..d27c146 100644
--- a/lib/ext/qcbor/src/UsefulBuf.c
+++ b/lib/ext/qcbor/src/UsefulBuf.c
@@ -1,7 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2019, Laurence Lundblade.
- All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -42,6 +41,7 @@
 
  when               who             what, where, why
  --------           ----            ---------------------------------------------------
+ 3/6/2019           llundblade      Add UsefulBuf_IsValue()
  09/07/17           llundbla        Fix critical bug in UsefulBuf_Find() -- a read off
                                     the end of memory when the bytes to find is longer
                                     than the bytes to search.
@@ -91,6 +91,28 @@
 }
 
 
+/*
+ Public function -- see UsefulBuf.h
+ */
+size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue)
+{
+   if(UsefulBuf_IsNULLOrEmptyC(UB)) {
+      /* Not a match */
+      return 0;
+   }
+
+   const uint8_t * const pEnd = (uint8_t *)UB.ptr + UB.len;
+   for(const uint8_t *p = UB.ptr; p < pEnd; p++) {
+      if(*p != uValue) {
+         /* Byte didn't match */
+         return p - (uint8_t *)UB.ptr;
+      }
+   }
+
+   /* Success. All bytes matched */
+   return SIZE_MAX;
+}
+
 
 /*
  Public function -- see UsefulBuf.h
diff --git a/lib/ext/qcbor/test/UsefulBuf_Tests.c b/lib/ext/qcbor/test/UsefulBuf_Tests.c
index cfa1262..388f8cf 100644
--- a/lib/ext/qcbor/test/UsefulBuf_Tests.c
+++ b/lib/ext/qcbor/test/UsefulBuf_Tests.c
@@ -544,6 +544,30 @@
       return "Copy null/empty failed";
    }
 
+   if(UsefulBuf_IsValue(ExpectedShorter, '+') != SIZE_MAX) {
+      return "IsValue failed to match all";
+   }
+
+   if(UsefulBuf_IsValue(ExpectedShorter, '-') != 0) {
+      return "IsValue should have failed right away";
+   }
+
+   if(UsefulBuf_IsValue(NULLUsefulBufC, 0x00) != 0) {
+      return "IsValue failed on NULLUsefulBufC";
+   }
+
+   if(UsefulBuf_IsValue((UsefulBufC){(uint8_t[]){0x00}, 1}, 0x00) != SIZE_MAX) {
+      return "IsValue failed finding 0 in one byte of 0";
+   }
+
+   if(UsefulBuf_IsValue((UsefulBufC){(uint8_t[]){0x00}, 1}, 0x01) != 0) {
+      return "IsValue failed not finding 1 in one byte of 0";
+   }
+
+   if(UsefulBuf_IsValue(ExpectedSmaller, '+') != ExpectedSmaller.len -1) {
+      return "IsValue failed to find final *";
+   }
+
    // Look for +++++... in +++++... and find it at the beginning
    if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){
       return "Failed to find";
diff --git a/secure_fw/services/initial_attestation/attestation_core.c b/secure_fw/services/initial_attestation/attestation_core.c
index 92c9e12..44c59c8 100644
--- a/secure_fw/services/initial_attestation/attestation_core.c
+++ b/secure_fw/services/initial_attestation/attestation_core.c
@@ -819,7 +819,6 @@
     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32:
     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48:
     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64:
-    case (PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 + 4): /* Test purpose */
         return PSA_ATTEST_ERR_SUCCESS;
     }
 
@@ -827,6 +826,55 @@
 }
 
 /*!
+ * \brief Static function to get the option flags from challenge object
+ *
+ * Option flags are passed in if the challenge is 64 bytes long and the last
+ * 60 bytes are all 0. In this case the first 4 bytes of the challenge is
+ * the option flags for test.
+ *
+ * See flag definition in attest_token.h
+ *
+ * \param[in]  challenge     Structure to carry the challenge value:
+ *                           pointer + challeng's length.
+ * \param[out] option_flags  Flags to select different custom options,
+ *                           for example \ref TOKEN_OPT_OMIT_CLAIMS.
+ * \param[out] key_select    Selects which attestation key to sign with.
+ */
+static void attest_get_option_flags(struct q_useful_buf_c *challenge,
+                                    uint32_t *option_flags,
+                                    int32_t  *key_select)
+{
+    uint32_t found_option_flags = 1;
+    uint32_t option_flags_size = sizeof(uint32_t);
+    uint8_t *challenge_end;
+    uint8_t *challenge_data;
+
+    /* Get option flags if there is encoded in the challenge object */
+    if (challenge->len == PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64) {
+        challenge_end  = ((uint8_t *)challenge->ptr) + challenge->len;
+        challenge_data = ((uint8_t *)challenge->ptr) + option_flags_size;
+
+        /* Compare bytes(4-63) with 0 */
+        while (challenge_data < challenge_end) {
+            if (*challenge_data++ != 0) {
+                found_option_flags = 0;
+                break;
+            }
+        }
+    }
+
+    if (found_option_flags) {
+        tfm_memcpy(option_flags, challenge->ptr, option_flags_size);
+
+        /* Lower three bits are the key select */
+        *key_select = *option_flags & 0x7;
+    } else {
+        *option_flags = 0;
+        *key_select = 0;
+    }
+}
+
+/*!
  * \brief Static function to create the initial attestation token
  *
  * \param[in]  challenge        Structure to carry the challenge value:
@@ -847,27 +895,9 @@
     enum attest_token_err_t token_err;
     struct attest_token_ctx attest_token_ctx;
     int32_t key_select;
-    int32_t alg_select;
-    uint32_t option_flags = 0;
+    uint32_t option_flags;
 
-    if (challenge->len == 36) {
-        /* FixMe: Special challenge with option flags appended. This might can
-         *        be removed when the public API can take option_flags.
-         */
-        option_flags = *(uint32_t *)(challenge->ptr + 32);
-        challenge->len = 32;
-    }
-
-    /* Lower three bits are the key select */
-    key_select = option_flags & 0x7;
-
-    /* Map the key select to an algorithm. Maybe someday we'll support something
-     * other than ES256
-     */
-    switch (key_select) {
-    default:
-        alg_select = COSE_ALGORITHM_ES256;
-    }
+    attest_get_option_flags(challenge, &option_flags, &key_select);
 
     /* Get started creating the token. This sets up the CBOR and COSE contexts
      * which causes the COSE headers to be constructed.
diff --git a/test/suites/attestation/attest_token_test.c b/test/suites/attestation/attest_token_test.c
index 5d617cf..703c335 100644
--- a/test/suites/attestation/attest_token_test.c
+++ b/test/suites/attestation/attest_token_test.c
@@ -51,21 +51,25 @@
                    struct q_useful_buf buffer,
                    struct q_useful_buf_c *completed_token)
 {
-    uint32_t completed_token_len;
+    int                          return_value;
+    uint32_t                     completed_token_len;
+    struct q_useful_buf_c        actual_nonce;
+    Q_USEFUL_BUF_MAKE_STACK_UB(  actual_nonce_storage, 64);
 
-    /* 36 = 32 + 4, the max expected nonce and 4 for the options */
-    Q_USEFUL_BUF_MAKE_STACK_UB(nonce2_storage, 36);
-    struct q_useful_buf_c nonce2;
-    int return_value;
-
-    nonce2 = q_useful_buf_copy(nonce2_storage, nonce);
-    /* Now for the hack... */
-    memcpy((uint8_t *)nonce2.ptr + nonce2.len, (uint8_t *) &option_flags, 4);
-    nonce2.len += 4;
+    if(nonce.len == 64 && q_useful_buf_is_value(nonce, 0)) {
+        /* Go into special option-packed nonce mode */
+        actual_nonce = q_useful_buf_copy(actual_nonce_storage, nonce);
+        /* Use memcpy as it always works and avoids type punning */
+        memcpy((uint8_t *)actual_nonce_storage.ptr,
+               &option_flags,
+               sizeof(uint32_t));
+    } else {
+        actual_nonce = nonce;
+    }
 
     completed_token_len = (uint32_t)buffer.len;
-    return_value = psa_initial_attest_get_token(nonce2.ptr,
-                                                (uint32_t)nonce2.len,
+    return_value = psa_initial_attest_get_token(actual_nonce.ptr,
+                                                (uint32_t)actual_nonce.len,
                                                 buffer.ptr,
                                                 &completed_token_len);
 
@@ -74,11 +78,6 @@
     return return_value;
 }
 
-
-/** A fake hard coded nonce for testing. */
-static const uint8_t nonce_bytes[] = { NONCE_FOR_TEST };
-
-
 /**
  * This is the expected output for the minimal test. It is the result
  * of creating a token with \ref TOKEN_OPT_SHORT_CIRCUIT_SIGN and \ref
@@ -96,11 +95,12 @@
  *               4: h'EF954B4BD9BDF670D0336082F5EF152AF8F35B6A6C00EFA6A9
  *                    A71F49517E18C6'
  *           },
- *           h'A13A000124FF5820010203040506070801020304050607080102030405
- *             0607080102030405060708',
- *           h'BD0990E025C671BF0FEB35D8908AF9E4F36706D04044BEB7325C2C
- *             A2753E4263BD0990E025C671BF0FEB35D8908AF9E4F36706D04044
- *             BEB7325C2CA2753E4263'
+ *           h'A13A000124FF5840000000C0000000000000000000000000000000000
+ *             000000000000000000000000000000000000000000000000000000000
+ *             000000000000000000000000000000',
+ *           h'CE52E46D564F1A6DBCEE106341CC80CDC0A3480999AFA8067747CA255
+ *             EEDFD8BCE52E46D564F1A6DBCEE106341CC80CDC0A3480999AFA80677
+ *             47CA255EEDFD8B'
  *       ]
  *     )
  *
@@ -112,20 +112,24 @@
     0xF6, 0x70, 0xD0, 0x33, 0x60, 0x82, 0xF5, 0xEF,
     0x15, 0x2A, 0xF8, 0xF3, 0x5B, 0x6A, 0x6C, 0x00,
     0xEF, 0xA6, 0xA9, 0xA7, 0x1F, 0x49, 0x51, 0x7E,
-    0x18, 0xC6, 0x58, 0x28, 0xA1, 0x3A, 0x00, 0x01,
-    0x24, 0xFF, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04,
-    0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04,
-    0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04,
-    0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04,
-    0x05, 0x06, 0x07, 0x08, 0x58, 0x40, 0xBD, 0x09,
-    0x90, 0xE0, 0x25, 0xC6, 0x71, 0xBF, 0x0F, 0xEB,
-    0x35, 0xD8, 0x90, 0x8A, 0xF9, 0xE4, 0xF3, 0x67,
-    0x06, 0xD0, 0x40, 0x44, 0xBE, 0xB7, 0x32, 0x5C,
-    0x2C, 0xA2, 0x75, 0x3E, 0x42, 0x63, 0xBD, 0x09,
-    0x90, 0xE0, 0x25, 0xC6, 0x71, 0xBF, 0x0F, 0xEB,
-    0x35, 0xD8, 0x90, 0x8A, 0xF9, 0xE4, 0xF3, 0x67,
-    0x06, 0xD0, 0x40, 0x44, 0xBE, 0xB7, 0x32, 0x5C,
-    0x2C, 0xA2, 0x75, 0x3E, 0x42, 0x63
+    0x18, 0xC6, 0x58, 0x48, 0xA1, 0x3A, 0x00, 0x01,
+    0x24, 0xFF, 0x58, 0x40, 0x00, 0x00, 0x00, 0xC0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0x40, 0xCE, 0x52,
+    0xE4, 0x6D, 0x56, 0x4F, 0x1A, 0x6D, 0xBC, 0xEE,
+    0x10, 0x63, 0x41, 0xCC, 0x80, 0xCD, 0xC0, 0xA3,
+    0x48, 0x09, 0x99, 0xAF, 0xA8, 0x06, 0x77, 0x47,
+    0xCA, 0x25, 0x5E, 0xED, 0xFD, 0x8B, 0xCE, 0x52,
+    0xE4, 0x6D, 0x56, 0x4F, 0x1A, 0x6D, 0xBC, 0xEE,
+    0x10, 0x63, 0x41, 0xCC, 0x80, 0xCD, 0xC0, 0xA3,
+    0x48, 0x09, 0x99, 0xAF, 0xA8, 0x06, 0x77, 0x47,
+    0xCA, 0x25, 0x5E, 0xED, 0xFD, 0x8B
 };
 
 
@@ -136,14 +140,14 @@
 {
     int_fast16_t return_value = 0;
     Q_USEFUL_BUF_MAKE_STACK_UB(token_storage,
-                             sizeof(expected_minimal_token_bytes));
+                               sizeof(expected_minimal_token_bytes));
     struct q_useful_buf_c completed_token;
     struct q_useful_buf_c expected_token;
 
     return_value =
         token_main_alt(TOKEN_OPT_SHORT_CIRCUIT_SIGN |
                            TOKEN_OPT_OMIT_CLAIMS,
-                       Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(nonce_bytes),
+                       TOKEN_TEST_VALUE_NONCE,
                        token_storage,
                        &completed_token);
     if(return_value) {
@@ -174,7 +178,7 @@
 
     return_value = 0;
 
-    nonce = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(nonce_bytes);
+    nonce = TOKEN_TEST_VALUE_NONCE;
     expected_token =
         Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(expected_minimal_token_bytes);
 
@@ -209,7 +213,7 @@
     struct q_useful_buf_c nonce;
 
 
-    nonce = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(nonce_bytes);
+    nonce = TOKEN_TEST_VALUE_NONCE;
 
     return_value = token_main_alt(TOKEN_OPT_SHORT_CIRCUIT_SIGN,
                                   nonce,
@@ -247,8 +251,9 @@
                     const struct attest_token_iat_simple_t *simple_claims)
 {
     int_fast16_t return_value;
-    /* Use a temp variable to make lines less than 80 columns below. */
+    /* Use temp variables to make lines less than 80 columns below. */
     struct q_useful_buf_c tmp;
+    struct q_useful_buf_c tail;
     /* Use a temporary string variable to make the static analyzer
      * happy. It doesn't like comparing a string literal to NULL
      */
@@ -269,11 +274,31 @@
         /* Claim is present */
         /* Don't have to check if its presence is required */
         tmp = TOKEN_TEST_VALUE_NONCE;
-        if(!q_useful_buf_c_is_null(tmp) &&
-           q_useful_buf_compare(simple_claims->nonce, tmp)) {
-            /* Check of its value was requested and failed */
-            return_value = -51;
-            goto Done;
+        if(!q_useful_buf_c_is_null(tmp)) {
+            /* request to check for the nonce */
+            if(q_useful_buf_compare(simple_claims->nonce, tmp)) {
+                /* Didn't match in the standard way. See if it is a
+                 * special option-packed nonce by checking for length
+                 * 64 and all bytes except the first four are 0.
+                 * nonce_tail is everything after the first 4 bytes.
+                 */
+                tail = q_useful_buf_tail(simple_claims->nonce, 4);
+                if(simple_claims->nonce.len == 64 &&
+                   q_useful_buf_is_value(tail, 0) == SIZE_MAX){
+                    /* It is an option-packed nonce.
+                     * Don't compare the first four bytes.
+                     */
+                    if(q_useful_buf_compare(q_useful_buf_tail(tmp, 4), tail)) {
+                        /* The option-packed nonce didn't match */
+                        return_value = -51;
+                        goto Done;
+                    }
+                } else {
+                    /* Just a normal nonce that didn't match */
+                    return_value = -51;
+                    goto Done;
+                }
+            }
         }
     }
 
@@ -410,7 +435,8 @@
         /* Don't have to check if its presence is required */
         tmp_string = TOKEN_TEST_VALUE_PROFILE_DEFINITION;
         if(tmp_string != NULL) {
-            tmp = Q_USEFUL_BUF_FROM_SZ_LITERAL(TOKEN_TEST_VALUE_PROFILE_DEFINITION);
+            tmp = Q_USEFUL_BUF_FROM_SZ_LITERAL(
+                                        TOKEN_TEST_VALUE_PROFILE_DEFINITION);
             if(q_useful_buf_compare(simple_claims->profile_definition, tmp)) {
                 /* Check of its value was requested and failed */
                 return_value = -65;
@@ -826,7 +852,7 @@
     }
 
     /* -- Make a token with all the claims -- */
-    tmp = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(nonce_bytes);
+    tmp = TOKEN_TEST_VALUE_NONCE;
     return_value = token_main_alt(token_encode_options,
                                   tmp,
                                   token_storage,
diff --git a/test/suites/attestation/attest_token_test_values.h b/test/suites/attestation/attest_token_test_values.h
index 4b574ca..0690206 100644
--- a/test/suites/attestation/attest_token_test_values.h
+++ b/test/suites/attestation/attest_token_test_values.h
@@ -74,11 +74,21 @@
                         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, \
                         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
 
-/* A 32 byte mostly random value. Binary. */
+/* The 64 byte special option-packed nonce where option flags
+ * are packed in at the start. Binary. */
+#define TOKEN_TEST_NONCE_BYTES \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 #define TOKEN_TEST_VALUE_NONCE \
     (struct q_useful_buf_c) {\
-        (uint8_t[]){ NONCE_FOR_TEST },\
-        32\
+      (uint8_t[]){TOKEN_TEST_NONCE_BYTES},\
+        64\
     }
 #define TOKEN_TEST_REQUIRE_NONCE true