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