// 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 #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 1024 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); }