Add macaroone implementation from
https://weave.googlesource.com/weave/libuweave
BUG:25934771
Change-Id: Iba87e709a51006f3e966b9942a375d1c31b2f17d
Reviewed-on: https://weave-review.googlesource.com/1804
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/third_party/libuweave/src/macaroon_encoding.c b/third_party/libuweave/src/macaroon_encoding.c
new file mode 100644
index 0000000..214314d
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_encoding.c
@@ -0,0 +1,353 @@
+// Copyright 2015 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/macaroon_encoding.h"
+
+#include <string.h>
+
+#define MAJOR_TYPE_MASK 0xE0 // 0b11100000
+#define ADDITIONAL_DATA_MASK 0x1F // 0b00011111
+
+#define FLAG_1BYTE_UINT 24
+#define FLAG_2BYTE_UINT 25
+#define FLAG_4BYTE_UINT 26
+// #define FLAG_8BYTE_UINT 27 // Do not support 8-byte
+
+typedef enum {
+ kCborMajorTypeUint = 0, // type 0
+ kCborMajorTypeByteStr = 2 << 5, // type 2
+ kCborMajorTypeTextStr = 3 << 5, // type 3
+} CborMajorType;
+
+// -- Prototypes begin --
+static inline CborMajorType get_type_(const uint8_t* cbor);
+static inline uint8_t get_addtl_data_(const uint8_t* cbor);
+static inline void set_type_(CborMajorType type, uint8_t* cbor);
+static inline void set_addtl_data_(uint8_t addtl_data, uint8_t* cbor);
+
+// Compute the minimum number of bytes to store the unsigned integer.
+static inline size_t uint_min_len_(uint32_t unsigned_int);
+
+// Encoding or decoding without checking types
+static bool blindly_encode_uint_(uint32_t unsigned_int, uint8_t* buffer,
+ size_t buffer_size, size_t* result_len);
+static bool blindly_encode_str_(const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* result_len);
+static bool blindly_decode_uint_(const uint8_t* cbor, size_t cbor_len,
+ uint32_t* unsigned_int);
+static bool blindly_decode_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** out_str, size_t* out_str_len);
+// -- Prototypes end --
+
+bool uw_macaroon_encoding_get_item_len_(const uint8_t* cbor, size_t cbor_len,
+ size_t* first_item_len) {
+ if (cbor == NULL || cbor_len == 0 || first_item_len == NULL) {
+ return false;
+ }
+
+ CborMajorType type = get_type_(cbor);
+ if (type != kCborMajorTypeUint && type != kCborMajorTypeByteStr &&
+ type != kCborMajorTypeTextStr) {
+ // Other types are not supported
+ return false;
+ }
+
+ uint32_t unsigned_int;
+ if (!blindly_decode_uint_(cbor, cbor_len, &unsigned_int)) {
+ return false;
+ }
+
+ *first_item_len = uint_min_len_(unsigned_int) + 1;
+
+ if (type == kCborMajorTypeByteStr || type == kCborMajorTypeTextStr) {
+ *first_item_len += (size_t)unsigned_int;
+ }
+
+ if (*first_item_len > cbor_len) {
+ // Something is wrong. The CBOR string isn't long enough.
+ return false;
+ }
+ return true;
+}
+
+bool uw_macaroon_encoding_encode_uint_(const uint32_t unsigned_int,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* resulting_cbor_len) {
+ if (buffer == NULL || buffer_size == 0 || resulting_cbor_len == NULL) {
+ return false;
+ }
+
+ set_type_(kCborMajorTypeUint, buffer);
+ return blindly_encode_uint_(unsigned_int, buffer, buffer_size,
+ resulting_cbor_len);
+}
+
+bool uw_macaroon_encoding_encode_byte_str_(const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* resulting_cbor_len) {
+ if (buffer == NULL || buffer_size == 0 || resulting_cbor_len == NULL) {
+ return false;
+ }
+
+ set_type_(kCborMajorTypeByteStr, buffer);
+ return blindly_encode_str_(str, str_len, buffer, buffer_size,
+ resulting_cbor_len);
+}
+
+bool uw_macaroon_encoding_encode_text_str_(const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* resulting_cbor_len) {
+ if (buffer == NULL || buffer_size == 0 || resulting_cbor_len == NULL) {
+ return false;
+ }
+
+ set_type_(kCborMajorTypeTextStr, buffer);
+ return blindly_encode_str_(str, str_len, buffer, buffer_size,
+ resulting_cbor_len);
+}
+
+bool uw_macaroon_encoding_decode_uint_(const uint8_t* cbor, size_t cbor_len,
+ uint32_t* unsigned_int) {
+ if (cbor == NULL || cbor_len == 0 || unsigned_int == NULL) {
+ return false;
+ }
+
+ CborMajorType type = get_type_(cbor);
+ if (type != kCborMajorTypeUint) {
+ return false;
+ }
+
+ return blindly_decode_uint_(cbor, cbor_len, unsigned_int);
+}
+
+bool uw_macaroon_encoding_decode_byte_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** out_str,
+ size_t* out_str_len) {
+ if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL) {
+ return false;
+ }
+
+ CborMajorType type = get_type_(cbor);
+ if (type != kCborMajorTypeByteStr) {
+ return false;
+ }
+
+ return blindly_decode_str_(cbor, cbor_len, out_str, out_str_len);
+}
+
+bool uw_macaroon_encoding_decode_text_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** out_str,
+ size_t* out_str_len) {
+ if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL) {
+ return false;
+ }
+
+ CborMajorType type = get_type_(cbor);
+ if (type != kCborMajorTypeTextStr) {
+ return false;
+ }
+
+ return blindly_decode_str_(cbor, cbor_len, out_str, out_str_len);
+}
+
+static inline CborMajorType get_type_(const uint8_t* cbor) {
+ return (CborMajorType)((*cbor) & MAJOR_TYPE_MASK);
+}
+
+static inline uint8_t get_addtl_data_(const uint8_t* cbor) {
+ return (*cbor) & ADDITIONAL_DATA_MASK;
+}
+
+static inline void set_type_(CborMajorType type, uint8_t* cbor) {
+ *cbor = ((uint8_t)type) | ((*cbor) & ADDITIONAL_DATA_MASK);
+}
+
+static inline void set_addtl_data_(uint8_t addtl_data, uint8_t* cbor) {
+ *cbor = ((*cbor) & MAJOR_TYPE_MASK) | (addtl_data & ADDITIONAL_DATA_MASK);
+}
+
+static inline size_t uint_min_len_(uint32_t unsigned_int) {
+ if (unsigned_int < FLAG_1BYTE_UINT) {
+ return 0; // Should be stored in the 5-bit additional data part
+ } else if (unsigned_int <= 0xFF) {
+ return 1;
+ } else if (unsigned_int <= 0xFFFF) {
+ return 2;
+ }
+ return 4;
+}
+
+// Write the unsigned int in the big-endian fashion by using the minimum number
+// of bytes in CBOR
+static inline bool write_uint_big_endian_(uint32_t unsigned_int, uint8_t* buff,
+ size_t buff_len) {
+ if (buff == NULL || buff_len == 0) {
+ return false;
+ }
+
+ size_t num_bytes = uint_min_len_(unsigned_int);
+ if (num_bytes > buff_len) {
+ // Not enough memory
+ return false;
+ }
+
+ switch (num_bytes) {
+ // Falling through intentionally
+ case 4:
+ *(buff++) = (uint8_t)(0xFF & (unsigned_int >> 24));
+ *(buff++) = (uint8_t)(0xFF & (unsigned_int >> 16));
+ case 2:
+ *(buff++) = (uint8_t)(0xFF & (unsigned_int >> 8));
+ case 1:
+ *(buff++) = (uint8_t)(0xFF & (unsigned_int));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+// Read the unsigned int written in big-endian
+static inline bool read_uint_big_endian_(const uint8_t* bytes, size_t num_bytes,
+ uint32_t* unsigned_int) {
+ if (bytes == NULL || num_bytes == 0 || num_bytes > 4 ||
+ unsigned_int == NULL) {
+ return false;
+ }
+
+ *unsigned_int = 0;
+ switch (num_bytes) {
+ // Falling through intentionally
+ case 4:
+ *unsigned_int |= ((uint32_t)(*(bytes++))) << 24;
+ *unsigned_int |= ((uint32_t)(*(bytes++))) << 16;
+ case 2:
+ *unsigned_int |= ((uint32_t)(*(bytes++))) << 8;
+ case 1:
+ *unsigned_int |= ((uint32_t)(*(bytes++)));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool blindly_encode_uint_(uint32_t unsigned_int, uint8_t* buffer,
+ size_t buffer_size, size_t* result_len) {
+ if (buffer == NULL || buffer_size == 0 || result_len == NULL) {
+ return false;
+ }
+
+ // Don't need to set the data type in this function
+
+ *result_len = uint_min_len_(unsigned_int) + 1;
+
+ if (*result_len > buffer_size) {
+ // Not enough memory
+ return false;
+ }
+
+ switch (*result_len) {
+ case 1:
+ set_addtl_data_(unsigned_int, buffer);
+ return true;
+ case 2: // 1 + 1
+ set_addtl_data_(FLAG_1BYTE_UINT, buffer);
+ break;
+ case 3: // 1 + 2
+ set_addtl_data_(FLAG_2BYTE_UINT, buffer);
+ break;
+ case 5: // 1 + 4
+ set_addtl_data_(FLAG_4BYTE_UINT, buffer);
+ break;
+ default:
+ // Wrong length
+ return false;
+ }
+
+ return write_uint_big_endian_(unsigned_int, buffer + 1, buffer_size - 1);
+}
+
+static bool blindly_encode_str_(const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* result_len) {
+ if (buffer == NULL || buffer_size == 0) {
+ return false;
+ }
+ if (str == NULL && str_len != 0) {
+ // str_len should be 0 for empty strings
+ return false;
+ }
+
+ // Don't need to set the data type in this function
+
+ if (!blindly_encode_uint_((uint32_t)str_len, buffer, buffer_size,
+ result_len)) {
+ return false;
+ }
+
+ if (str_len == 0) {
+ return true;
+ }
+
+ if (str_len + (*result_len) > buffer_size) {
+ // Not enough memory
+ return false;
+ }
+
+ memcpy(buffer + (*result_len), str, str_len);
+ *result_len += str_len;
+ return true;
+}
+
+static bool blindly_decode_uint_(const uint8_t* cbor, size_t cbor_len,
+ uint32_t* unsigned_int) {
+ if (cbor == NULL || cbor_len == 0 || unsigned_int == NULL) {
+ return false;
+ }
+
+ uint8_t addtl_data = get_addtl_data_(cbor);
+ if (addtl_data < FLAG_1BYTE_UINT) {
+ *unsigned_int = (uint32_t)addtl_data;
+ return true;
+ }
+ if (addtl_data > FLAG_4BYTE_UINT) {
+ return false;
+ }
+
+ size_t uint_num_bytes = 1 << (addtl_data - (uint8_t)FLAG_1BYTE_UINT);
+ if (uint_num_bytes + 1 > cbor_len) {
+ // The CBOR string isn't long enough.
+ return false;
+ }
+
+ return read_uint_big_endian_(cbor + 1, uint_num_bytes, unsigned_int);
+}
+
+static bool blindly_decode_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** out_str, size_t* out_str_len) {
+ if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str == NULL) {
+ return false;
+ }
+
+ uint32_t unsigned_int;
+ if (!blindly_decode_uint_(cbor, cbor_len, &unsigned_int)) {
+ return false;
+ }
+
+ size_t offset = 1 + uint_min_len_(unsigned_int);
+ if (unsigned_int > (uint32_t)(cbor_len - offset)) {
+ // The CBOR string isn't long enough
+ return false;
+ }
+
+ *out_str = cbor + offset;
+ *out_str_len = unsigned_int;
+ return true;
+}