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/LICENSE b/third_party/libuweave/LICENSE
new file mode 100644
index 0000000..942662d
--- /dev/null
+++ b/third_party/libuweave/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2015, The Weave Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Weave Authors nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libuweave/README b/third_party/libuweave/README
new file mode 100644
index 0000000..f170307
--- /dev/null
+++ b/third_party/libuweave/README
@@ -0,0 +1,4 @@
+URL: https://weave.googlesource.com/weave/libuweave/+/master
+
+Description:
+Macaroon related code from libuweave.
diff --git a/third_party/libuweave/src/crypto_hmac.h b/third_party/libuweave/src/crypto_hmac.h
new file mode 100644
index 0000000..bac634a
--- /dev/null
+++ b/third_party/libuweave/src/crypto_hmac.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef LIBUWEAVE_SRC_CRYPTO_HMAC_H_
+#define LIBUWEAVE_SRC_CRYPTO_HMAC_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// Return the minimum required number of bytes for the state_buffer used in the
+// init, update and final functions.
+size_t uw_crypto_hmac_required_buffer_size_();
+
+bool uw_crypto_hmac_init_(uint8_t* state_buffer,
+ size_t state_buffer_len,
+ const uint8_t* key,
+ size_t key_len);
+bool uw_crypto_hmac_update_(uint8_t* state_buffer,
+ size_t state_buffer_len,
+ const uint8_t* data,
+ size_t data_len);
+bool uw_crypto_hmac_final_(uint8_t* state_buffer,
+ size_t state_buffer_len,
+ uint8_t* truncated_digest,
+ size_t truncated_digest_len);
+
+#endif // LIBUWEAVE_SRC_CRYPTO_HMAC_H_
diff --git a/third_party/libuweave/src/crypto_utils.c b/third_party/libuweave/src/crypto_utils.c
new file mode 100644
index 0000000..75bd2e5
--- /dev/null
+++ b/third_party/libuweave/src/crypto_utils.c
@@ -0,0 +1,23 @@
+// 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/crypto_utils.h"
+
+bool uw_crypto_utils_equal_(const uint8_t* arr1,
+ const uint8_t* arr2,
+ size_t len) {
+ if (arr1 == NULL || arr2 == NULL) {
+ if (arr1 == NULL && arr2 == NULL && len == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ uint8_t diff = 0;
+ for (size_t i = 0; i < len; i++) {
+ diff |= arr1[0] ^ arr2[0];
+ }
+
+ return 0 == diff;
+}
diff --git a/third_party/libuweave/src/crypto_utils.h b/third_party/libuweave/src/crypto_utils.h
new file mode 100644
index 0000000..54bfcae
--- /dev/null
+++ b/third_party/libuweave/src/crypto_utils.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef LIBUWEAVE_SRC_CRYPTO_UTILS_H_
+#define LIBUWEAVE_SRC_CRYPTO_UTILS_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Check if two byte arrays are the same in constant time (the running time
+ * should only depend on the length of the given arrays). It's critical to use
+ * constant-time methods to compare secret data. Timing information can lead to
+ * full recovery of the secret data.
+ */
+bool uw_crypto_utils_equal_(const uint8_t* arr1,
+ const uint8_t* arr2,
+ size_t len);
+
+#endif // LIBUWEAVE_SRC_CRYPTO_UTILS_H_
diff --git a/third_party/libuweave/src/macaroon.c b/third_party/libuweave/src/macaroon.c
new file mode 100644
index 0000000..d7e6491
--- /dev/null
+++ b/third_party/libuweave/src/macaroon.c
@@ -0,0 +1,126 @@
+// 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.h"
+
+#include <string.h>
+
+#include "src/crypto_utils.h"
+
+static bool create_mac_tag_(const uint8_t* key, size_t key_len,
+ const UwMacaroonCaveat* caveats, size_t num_caveats,
+ uint8_t mac_tag[UW_MACAROON_MAC_LEN]) {
+ if (key == NULL || key_len == 0 || caveats == NULL || num_caveats == 0 ||
+ mac_tag == NULL) {
+ return false;
+ }
+
+ // Store the intermediate MAC tags in an internal buffer before we finish the
+ // whole computation.
+ // If we use the output buffer mac_tag directly and certain errors happen in
+ // the middle of this computation, mac_tag will probably contain a valid
+ // macaroon tag with large scope than expected.
+ uint8_t mac_tag_buff[UW_MACAROON_MAC_LEN];
+
+ // Compute the first tag by using the key
+ if (!uw_macaroon_caveat_sign_(key, key_len, &(caveats[0]), mac_tag_buff,
+ UW_MACAROON_MAC_LEN)) {
+ return false;
+ }
+
+ // Compute the rest of the tags by using the tag as the key
+ for (size_t i = 1; i < num_caveats; i++) {
+ if (!uw_macaroon_caveat_sign_(mac_tag_buff, UW_MACAROON_MAC_LEN,
+ &(caveats[i]), mac_tag_buff,
+ UW_MACAROON_MAC_LEN)) {
+ return false;
+ }
+ }
+
+ memcpy(mac_tag, mac_tag_buff, UW_MACAROON_MAC_LEN);
+ return true;
+}
+
+bool uw_macaroon_new_from_mac_tag_(UwMacaroon* new_macaroon,
+ const uint8_t mac_tag[UW_MACAROON_MAC_LEN],
+ const UwMacaroonCaveat* caveats,
+ size_t num_caveats) {
+ if (new_macaroon == NULL || mac_tag == NULL || caveats == NULL ||
+ num_caveats == 0) {
+ return false;
+ }
+
+ memcpy(new_macaroon->mac_tag, mac_tag, UW_MACAROON_MAC_LEN);
+ new_macaroon->num_caveats = num_caveats;
+ new_macaroon->caveats = caveats;
+
+ return true;
+}
+
+bool uw_macaroon_new_from_root_key_(UwMacaroon* new_macaroon,
+ const uint8_t* root_key,
+ size_t root_key_len,
+ const UwMacaroonCaveat* caveats,
+ size_t num_caveats) {
+ if (new_macaroon == NULL || root_key == NULL || root_key_len == 0 ||
+ caveats == NULL || num_caveats == 0) {
+ return false;
+ }
+
+ if (!create_mac_tag_(root_key, root_key_len, caveats, num_caveats,
+ new_macaroon->mac_tag)) {
+ return false;
+ }
+
+ new_macaroon->num_caveats = num_caveats;
+ new_macaroon->caveats = caveats;
+
+ return true;
+}
+
+bool uw_macaroon_verify_(const UwMacaroon* macaroon,
+ const uint8_t* root_key,
+ size_t root_key_len) {
+ if (macaroon == NULL || root_key == NULL) {
+ return false;
+ }
+
+ uint8_t mac_tag[UW_MACAROON_MAC_LEN] = {0};
+ if (!create_mac_tag_(root_key, root_key_len, macaroon->caveats,
+ macaroon->num_caveats, mac_tag)) {
+ return false;
+ }
+
+ return uw_crypto_utils_equal_(mac_tag, macaroon->mac_tag,
+ UW_MACAROON_MAC_LEN);
+}
+
+bool uw_macaroon_extend_(const UwMacaroon* old_macaroon,
+ UwMacaroon* new_macaroon,
+ const UwMacaroonCaveat* additional_caveat,
+ uint8_t* buffer, size_t buffer_size) {
+ if (old_macaroon == NULL || new_macaroon == NULL ||
+ additional_caveat == NULL || buffer == NULL || buffer_size == 0) {
+ return false;
+ }
+
+ new_macaroon->num_caveats = old_macaroon->num_caveats + 1;
+
+ // Extend the caveat list
+ if ((new_macaroon->num_caveats) * sizeof(UwMacaroonCaveat) > buffer_size) {
+ // Not enough memory to store the extended caveat list
+ return false;
+ }
+ UwMacaroonCaveat* extended_list = (UwMacaroonCaveat*)buffer;
+ if (old_macaroon->caveats != NULL && extended_list != old_macaroon->caveats) {
+ memcpy(extended_list, old_macaroon->caveats,
+ (old_macaroon->num_caveats) * sizeof(UwMacaroonCaveat));
+ }
+ extended_list[old_macaroon->num_caveats] = *additional_caveat;
+ new_macaroon->caveats = extended_list;
+
+ // Compute the new MAC tag
+ return create_mac_tag_(old_macaroon->mac_tag, UW_MACAROON_MAC_LEN,
+ additional_caveat, 1, new_macaroon->mac_tag);
+}
diff --git a/third_party/libuweave/src/macaroon.h b/third_party/libuweave/src/macaroon.h
new file mode 100644
index 0000000..98ada11
--- /dev/null
+++ b/third_party/libuweave/src/macaroon.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef LIBUWEAVE_SRC_MACAROON_H_
+#define LIBUWEAVE_SRC_MACAROON_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "macaroon_caveat.h"
+
+#define UW_MACAROON_MAC_LEN 16
+
+// Note: If we are looking to make memory savings on MCUs,
+// at the cost of a little extra processing, we can make
+// the macaroon encoding the actual in-memory representation.
+// This can save much copying of macaroon data if need be.
+typedef struct {
+ uint8_t mac_tag[UW_MACAROON_MAC_LEN];
+ size_t num_caveats;
+ const UwMacaroonCaveat* caveats;
+} UwMacaroon;
+
+bool uw_macaroon_new_from_mac_tag_(UwMacaroon* new_macaroon,
+ const uint8_t mac_tag[UW_MACAROON_MAC_LEN],
+ const UwMacaroonCaveat* caveats,
+ size_t num_caveats);
+
+bool uw_macaroon_new_from_root_key_(UwMacaroon* new_macaroon,
+ const uint8_t* root_key,
+ size_t root_key_len,
+ const UwMacaroonCaveat* caveats,
+ size_t num_caveats);
+
+bool uw_macaroon_verify_(const UwMacaroon* macaroon,
+ const uint8_t* root_key,
+ size_t root_key_len);
+
+// Create a new macaroon with a new caveat
+bool uw_macaroon_extend_(const UwMacaroon* old_macaroon,
+ UwMacaroon* new_macaroon,
+ const UwMacaroonCaveat* additional_caveat,
+ uint8_t* buffer, size_t buffer_size);
+
+#endif // LIBUWEAVE_SRC_MACAROON_H_
diff --git a/third_party/libuweave/src/macaroon_caveat.c b/third_party/libuweave/src/macaroon_caveat.c
new file mode 100644
index 0000000..a04c30d
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_caveat.c
@@ -0,0 +1,247 @@
+// 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_caveat.h"
+
+#include <string.h>
+
+#include "src/crypto_hmac.h"
+#include "src/macaroon_context.h"
+#include "src/macaroon_encoding.h"
+
+// TODO(bozhu): Find a better way to pre-allocate memory for HMACc computations?
+// Are C99 variable-length arrays allowed on embedded devices?
+#define HMAC_STATE_BUFFER_SIZE 300
+
+static bool create_caveat_(UwMacaroonCaveatType type, const void* value,
+ size_t value_len, uint8_t* buffer,
+ size_t buffer_size, UwMacaroonCaveat* caveat) {
+ if (buffer == NULL || buffer_size == 0 || caveat == NULL) {
+ // Here value can be NULL, and value_len can be 0
+ return false;
+ }
+
+ caveat->bytes = buffer;
+ size_t encoded_str_len, total_str_len;
+
+ uint32_t unsigned_int = (uint32_t)type;
+ if (!uw_macaroon_encoding_encode_uint_(unsigned_int, buffer, buffer_size,
+ &encoded_str_len)) {
+ return false;
+ }
+ total_str_len = encoded_str_len;
+ buffer += encoded_str_len;
+ buffer_size -= encoded_str_len;
+
+ switch (type) {
+ case kUwMacaroonCaveatTypeStop:
+ case kUwMacaroonCaveatTypeSessionIdentifier:
+ // No value
+ encoded_str_len = 0;
+ break;
+
+ case kUwMacaroonCaveatTypeScope:
+ case kUwMacaroonCaveatTypeIssued:
+ case kUwMacaroonCaveatTypeTTL:
+ case kUwMacaroonCaveatTypeExpiration:
+ // Integer
+ if (value_len != sizeof(uint32_t)) {
+ // Wrong size for integers
+ return false;
+ }
+ unsigned_int = *((uint32_t*)value);
+ if (!uw_macaroon_encoding_encode_uint_(unsigned_int, buffer, buffer_size,
+ &encoded_str_len)) {
+ return false;
+ }
+ break;
+
+ case kUwMacaroonCaveatTypeIdentifier:
+ // Text string
+ if (!uw_macaroon_encoding_encode_text_str_((uint8_t*)value, value_len,
+ buffer, buffer_size,
+ &encoded_str_len)) {
+ return false;
+ }
+ break;
+
+ default:
+ // Should never reach here
+ return false;
+ }
+
+ total_str_len += encoded_str_len;
+ caveat->num_bytes = total_str_len;
+ return true;
+}
+
+bool uw_macaroon_caveat_create_without_value_(UwMacaroonCaveatType type,
+ uint8_t* buffer,
+ size_t buffer_size,
+ UwMacaroonCaveat* caveat) {
+ if (buffer == NULL || buffer_size == 0 || caveat == NULL) {
+ return false;
+ }
+ if (type != kUwMacaroonCaveatTypeStop &&
+ type != kUwMacaroonCaveatTypeSessionIdentifier) {
+ return false;
+ }
+
+ return create_caveat_(type, NULL, 0, buffer, buffer_size, caveat);
+}
+
+bool uw_macaroon_caveat_create_with_uint_(UwMacaroonCaveatType type,
+ uint32_t value, uint8_t* buffer,
+ size_t buffer_size,
+ UwMacaroonCaveat* caveat) {
+ if (buffer == NULL || buffer_size == 0 || caveat == NULL) {
+ return false;
+ }
+ if (type != kUwMacaroonCaveatTypeScope &&
+ type != kUwMacaroonCaveatTypeIssued &&
+ type != kUwMacaroonCaveatTypeTTL &&
+ type != kUwMacaroonCaveatTypeExpiration) {
+ return false;
+ }
+
+ return create_caveat_(type, &value, sizeof(uint32_t), buffer, buffer_size,
+ caveat);
+}
+
+bool uw_macaroon_caveat_create_with_str_(UwMacaroonCaveatType type,
+ const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ UwMacaroonCaveat* caveat) {
+ if (buffer == NULL || buffer_size == 0 || caveat == NULL ||
+ (str == NULL && str_len != 0)) {
+ return false;
+ }
+ if (type != kUwMacaroonCaveatTypeIdentifier) {
+ return false;
+ }
+
+ return create_caveat_(type, str, str_len, buffer, buffer_size, caveat);
+}
+
+bool uw_macaroon_caveat_get_type_(const UwMacaroonCaveat* caveat,
+ UwMacaroonCaveatType* type) {
+ if (caveat == NULL || type == NULL) {
+ return false;
+ }
+
+ uint32_t unsigned_int;
+ if (!uw_macaroon_encoding_decode_uint_(caveat->bytes, caveat->num_bytes,
+ &unsigned_int)) {
+ return false;
+ }
+
+ *type = (UwMacaroonCaveatType)unsigned_int;
+
+ if (*type != kUwMacaroonCaveatTypeStop &&
+ *type != kUwMacaroonCaveatTypeScope &&
+ *type != kUwMacaroonCaveatTypeIdentifier &&
+ *type != kUwMacaroonCaveatTypeIssued &&
+ *type != kUwMacaroonCaveatTypeTTL &&
+ *type != kUwMacaroonCaveatTypeExpiration &&
+ *type != kUwMacaroonCaveatTypeSessionIdentifier) {
+ return false;
+ }
+
+ return true;
+}
+
+bool uw_macaroon_caveat_get_value_uint_(const UwMacaroonCaveat* caveat,
+ uint32_t* unsigned_int) {
+ if (caveat == NULL || unsigned_int == NULL) {
+ return false;
+ }
+
+ UwMacaroonCaveatType type;
+ if (!uw_macaroon_caveat_get_type_(caveat, &type)) {
+ return false;
+ }
+ if (type != kUwMacaroonCaveatTypeScope &&
+ type != kUwMacaroonCaveatTypeIssued &&
+ type != kUwMacaroonCaveatTypeTTL &&
+ type != kUwMacaroonCaveatTypeExpiration) {
+ // Wrong type
+ return false;
+ }
+
+ size_t offset;
+ if (!uw_macaroon_encoding_get_item_len_(caveat->bytes, caveat->num_bytes,
+ &offset)) {
+ return false;
+ }
+
+ return uw_macaroon_encoding_decode_uint_(
+ caveat->bytes + offset, caveat->num_bytes - offset, unsigned_int);
+}
+
+bool uw_macaroon_caveat_get_value_str_(const UwMacaroonCaveat* caveat,
+ const uint8_t** str, size_t* str_len) {
+ if (caveat == NULL || str == NULL || str_len == NULL) {
+ return false;
+ }
+
+ UwMacaroonCaveatType type;
+ if (!uw_macaroon_caveat_get_type_(caveat, &type)) {
+ return false;
+ }
+ if (type != kUwMacaroonCaveatTypeIdentifier) {
+ // Wrong type
+ return false;
+ }
+
+ size_t offset;
+ if (!uw_macaroon_encoding_get_item_len_(caveat->bytes, caveat->num_bytes,
+ &offset)) {
+ return false;
+ }
+
+ return uw_macaroon_encoding_decode_text_str_(
+ caveat->bytes + offset, caveat->num_bytes - offset, str, str_len);
+}
+
+bool uw_macaroon_caveat_sign_(const uint8_t* key, size_t key_len,
+ const UwMacaroonCaveat* caveat, uint8_t* mac_tag,
+ size_t mac_tag_size) {
+ if (key == NULL || key_len == 0 || caveat == NULL || mac_tag == NULL ||
+ mac_tag_size == 0) {
+ return false;
+ }
+
+ uint8_t hmac_state_buffer[HMAC_STATE_BUFFER_SIZE];
+ if (HMAC_STATE_BUFFER_SIZE < uw_crypto_hmac_required_buffer_size_()) {
+ return false;
+ }
+
+ if (!uw_crypto_hmac_init_(hmac_state_buffer, HMAC_STATE_BUFFER_SIZE, key,
+ key_len)) {
+ return false;
+ }
+
+ if (!uw_crypto_hmac_update_(hmac_state_buffer, HMAC_STATE_BUFFER_SIZE,
+ caveat->bytes, caveat->num_bytes)) {
+ return false;
+ }
+
+ const uint8_t* context;
+ size_t context_len;
+ UwMacaroonCaveatType caveat_type;
+
+ if ((!uw_macaroon_caveat_get_type_(caveat, &caveat_type)) ||
+ (!uw_macaroon_context_get_(caveat_type, &context, &context_len))) {
+ return false;
+ }
+ if (context != NULL && context_len != 0) {
+ if (!uw_crypto_hmac_update_(hmac_state_buffer, HMAC_STATE_BUFFER_SIZE,
+ context, context_len)) {
+ return false;
+ }
+ }
+
+ return uw_crypto_hmac_final_(hmac_state_buffer, HMAC_STATE_BUFFER_SIZE,
+ mac_tag, mac_tag_size);
+}
diff --git a/third_party/libuweave/src/macaroon_caveat.h b/third_party/libuweave/src/macaroon_caveat.h
new file mode 100644
index 0000000..5f2c384
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_caveat.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef LIBUWEAVE_SRC_MACAROON_CAVEAT_H_
+#define LIBUWEAVE_SRC_MACAROON_CAVEAT_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ size_t num_bytes;
+ const uint8_t* bytes;
+} UwMacaroonCaveat;
+
+typedef enum {
+ kUwMacaroonCaveatTypeStop = 0,
+ kUwMacaroonCaveatTypeScope = 1,
+ kUwMacaroonCaveatTypeIdentifier = 2,
+ kUwMacaroonCaveatTypeIssued = 3,
+ kUwMacaroonCaveatTypeTTL = 4,
+ kUwMacaroonCaveatTypeExpiration = 5,
+ kUwMacaroonCaveatTypeSessionIdentifier = 16
+} UwMacaroonCaveatType;
+
+bool uw_macaroon_caveat_create_without_value_(UwMacaroonCaveatType type,
+ uint8_t* buffer,
+ size_t buffer_size,
+ UwMacaroonCaveat* new_caveat);
+bool uw_macaroon_caveat_create_with_uint_(UwMacaroonCaveatType type,
+ uint32_t value, uint8_t* buffer,
+ size_t buffer_size,
+ UwMacaroonCaveat* new_caveat);
+bool uw_macaroon_caveat_create_with_str_(UwMacaroonCaveatType type,
+ const uint8_t* str, size_t str_len,
+ uint8_t* buffer, size_t buffer_size,
+ UwMacaroonCaveat* new_caveat);
+
+bool uw_macaroon_caveat_get_type_(const UwMacaroonCaveat* caveat,
+ UwMacaroonCaveatType* type);
+bool uw_macaroon_caveat_get_value_uint_(const UwMacaroonCaveat* caveat,
+ uint32_t* unsigned_int);
+bool uw_macaroon_caveat_get_value_str_(const UwMacaroonCaveat* caveat,
+ const uint8_t** str, size_t* str_len);
+
+bool uw_macaroon_caveat_sign_(const uint8_t* key, size_t key_len,
+ const UwMacaroonCaveat* caveat, uint8_t* mac_tag,
+ size_t mac_tag_size);
+
+#endif // LIBUWEAVE_SRC_MACAROON_CAVEAT_H_
diff --git a/third_party/libuweave/src/macaroon_context.c b/third_party/libuweave/src/macaroon_context.c
new file mode 100644
index 0000000..7477784
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_context.c
@@ -0,0 +1,22 @@
+// 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_context.h"
+
+#include "src/macaroon_caveat.h"
+
+bool uw_macaroon_context_get_(UwMacaroonCaveatType type,
+ const uint8_t** context, size_t* context_len) {
+ if (type != kUwMacaroonCaveatTypeSessionIdentifier) {
+ *context = NULL;
+ *context_len = 0;
+ }
+
+ // TODO(bozhu): Waiting for a proper way to obtain the session identifier.
+ // Have we already implemented something related to session identifiers?
+ *context = NULL;
+ *context_len = 0;
+
+ return true;
+}
diff --git a/third_party/libuweave/src/macaroon_context.h b/third_party/libuweave/src/macaroon_context.h
new file mode 100644
index 0000000..8522b69
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_context.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef UW_LIBUWEAVE_SRC_MACAROON_CONTEXT_
+#define UW_LIBUWEAVE_SRC_MACAROON_CONTEXT_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "src/macaroon_caveat.h"
+
+bool uw_macaroon_context_get_(UwMacaroonCaveatType type,
+ const uint8_t** context, size_t* context_len);
+
+#endif // UW_LIBUWEAVE_SRC_MACAROON_CONTEXT_
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;
+}
diff --git a/third_party/libuweave/src/macaroon_encoding.h b/third_party/libuweave/src/macaroon_encoding.h
new file mode 100644
index 0000000..2c11fd1
--- /dev/null
+++ b/third_party/libuweave/src/macaroon_encoding.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef UW_LIBUWEAVE_SRC_MACAROON_ENCODING_
+#define UW_LIBUWEAVE_SRC_MACAROON_ENCODING_
+
+/*
+ * Utility functions to encode and decode canonical CBOR representations for
+ * cryptographic use, such as signatures. We only need to support a very small
+ * subset of the CBOR standard, since only these are used in our cryptographic
+ * designs. The supported data types are: unsigned integers (maximum 32 bits),
+ * byte strings, and text strings.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// Get the number of bytes that is occupied by the first data item in the give
+// CBOR string.
+bool uw_macaroon_encoding_get_item_len_(const uint8_t* cbor, size_t cbor_len,
+ size_t* first_item_len);
+
+bool uw_macaroon_encoding_encode_uint_(const uint32_t unsigned_int,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* 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);
+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);
+
+bool uw_macaroon_encoding_decode_uint_(const uint8_t* cbor, size_t cbor_len,
+ uint32_t* unsigned_int);
+bool uw_macaroon_encoding_decode_byte_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** str,
+ size_t* str_len);
+bool uw_macaroon_encoding_decode_text_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** str,
+ size_t* str_len);
+
+#endif // UW_LIBUWEAVE_SRC_MACAROON_ENCODING_
diff --git a/third_party/libuweave/update.sh b/third_party/libuweave/update.sh
new file mode 100755
index 0000000..e34065d
--- /dev/null
+++ b/third_party/libuweave/update.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# 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.
+
+DIR=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
+ROOT_DIR=$(cd -P -- "$(dirname -- "$0")/../.." && pwd -P)
+
+cd $ROOT_DIR
+
+git subtree add --prefix third_party/temp_libuweave \
+ https://weave.googlesource.com/weave/libuweave master --squash || exit 1
+
+mkdir -p third_party/libuweave/src
+pushd third_party
+git mv -kf temp_libuweave/LICENSE libuweave/
+git mv -kf temp_libuweave/src/crypto_hmac.h libuweave/src/crypto_hmac.h
+git mv -kf temp_libuweave/src/macaroon* libuweave/src/
+git mv -kf temp_libuweave/src/crypto_utils.* libuweave/src/
+popd
+
+git rm -rf third_party/temp_libuweave
+git reset --soft weave/master
+git commit -av