blob: 594f9de333587daca10e83c9bdfac79bc7b9c457 [file] [log] [blame]
// 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);
}