Home | History | Annotate | Download | only in src
      1 // Copyright 2015 The Weave Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/macaroon.h"
      6 
      7 #include <string.h>
      8 
      9 #include "src/crypto_utils.h"
     10 #include "src/macaroon_caveat.h"
     11 #include "src/macaroon_caveat_internal.h"
     12 #include "src/macaroon_encoding.h"
     13 
     14 static bool create_mac_tag_(const uint8_t* key,
     15                             size_t key_len,
     16                             const UwMacaroonContext* context,
     17                             const UwMacaroonCaveat* const caveats[],
     18                             size_t num_caveats,
     19                             uint8_t mac_tag[UW_MACAROON_MAC_LEN]) {
     20   if (key == NULL || key_len == 0 || context == NULL || caveats == NULL ||
     21       num_caveats == 0 || mac_tag == NULL) {
     22     return false;
     23   }
     24 
     25   // Store the intermediate MAC tags in an internal buffer before we finish the
     26   // whole computation.
     27   // If we use the output buffer mac_tag directly and certain errors happen in
     28   // the middle of this computation, mac_tag will probably contain a valid
     29   // macaroon tag with large scope than expected.
     30   uint8_t mac_tag_buff[UW_MACAROON_MAC_LEN];
     31 
     32   // Compute the first tag by using the key
     33   if (!uw_macaroon_caveat_sign_(key, key_len, context, caveats[0], mac_tag_buff,
     34                                 UW_MACAROON_MAC_LEN)) {
     35     return false;
     36   }
     37 
     38   // Compute the rest of the tags by using the tag as the key
     39   for (size_t i = 1; i < num_caveats; i++) {
     40     if (!uw_macaroon_caveat_sign_(mac_tag_buff, UW_MACAROON_MAC_LEN, context,
     41                                   caveats[i], mac_tag_buff,
     42                                   UW_MACAROON_MAC_LEN)) {
     43       return false;
     44     }
     45   }
     46 
     47   memcpy(mac_tag, mac_tag_buff, UW_MACAROON_MAC_LEN);
     48   return true;
     49 }
     50 
     51 static bool verify_mac_tag_(const uint8_t* root_key,
     52                             size_t root_key_len,
     53                             const UwMacaroonContext* context,
     54                             const UwMacaroonCaveat* const caveats[],
     55                             size_t num_caveats,
     56                             const uint8_t mac_tag[UW_MACAROON_MAC_LEN]) {
     57   if (root_key == NULL || root_key_len == 0 || context == NULL ||
     58       caveats == NULL || num_caveats == 0 || mac_tag == 0) {
     59     return false;
     60   }
     61 
     62   uint8_t computed_mac_tag[UW_MACAROON_MAC_LEN] = {0};
     63   if (!create_mac_tag_(root_key, root_key_len, context, caveats, num_caveats,
     64                        computed_mac_tag)) {
     65     return false;
     66   }
     67 
     68   return uw_crypto_utils_equal_(mac_tag, computed_mac_tag, UW_MACAROON_MAC_LEN);
     69 }
     70 
     71 bool uw_macaroon_create_from_root_key_(UwMacaroon* new_macaroon,
     72                                        const uint8_t* root_key,
     73                                        size_t root_key_len,
     74                                        const UwMacaroonContext* context,
     75                                        const UwMacaroonCaveat* const caveats[],
     76                                        size_t num_caveats) {
     77   if (new_macaroon == NULL || root_key == NULL || context == NULL ||
     78       root_key_len == 0 || caveats == NULL || num_caveats == 0) {
     79     return false;
     80   }
     81 
     82   if (!create_mac_tag_(root_key, root_key_len, context, caveats, num_caveats,
     83                        new_macaroon->mac_tag)) {
     84     return false;
     85   }
     86 
     87   new_macaroon->num_caveats = num_caveats;
     88   new_macaroon->caveats = caveats;
     89 
     90   return true;
     91 }
     92 
     93 bool uw_macaroon_extend_(const UwMacaroon* old_macaroon,
     94                          UwMacaroon* new_macaroon,
     95                          const UwMacaroonContext* context,
     96                          const UwMacaroonCaveat* additional_caveat,
     97                          uint8_t* buffer,
     98                          size_t buffer_size) {
     99   if (old_macaroon == NULL || new_macaroon == NULL || context == NULL ||
    100       additional_caveat == NULL || buffer == NULL || buffer_size == 0) {
    101     return false;
    102   }
    103 
    104   new_macaroon->num_caveats = old_macaroon->num_caveats + 1;
    105 
    106   // Extend the caveat pointer list
    107   if ((new_macaroon->num_caveats) * sizeof(UwMacaroonCaveat*) > buffer_size) {
    108     // Not enough memory to store the extended caveat pointer list
    109     return false;
    110   }
    111   const UwMacaroonCaveat** extended_list = (const UwMacaroonCaveat**)buffer;
    112   if (new_macaroon->caveats != old_macaroon->caveats) {
    113     memcpy(extended_list, old_macaroon->caveats,
    114            old_macaroon->num_caveats * sizeof(old_macaroon->caveats[0]));
    115   }
    116   extended_list[old_macaroon->num_caveats] = additional_caveat;
    117   new_macaroon->caveats = (const UwMacaroonCaveat* const*)extended_list;
    118 
    119   // Compute the new MAC tag
    120   return create_mac_tag_(old_macaroon->mac_tag, UW_MACAROON_MAC_LEN, context,
    121                          new_macaroon->caveats + old_macaroon->num_caveats, 1,
    122                          new_macaroon->mac_tag);
    123 }
    124 
    125 static void init_validation_result(UwMacaroonValidationResult* result) {
    126   // Start from the largest scope
    127   *result = (UwMacaroonValidationResult){
    128       .granted_scope = kUwMacaroonCaveatScopeTypeOwner,
    129       .expiration_time = UINT32_MAX,
    130   };
    131 }
    132 
    133 /** Reset the result object to the lowest scope when encountering errors */
    134 static void reset_validation_result(UwMacaroonValidationResult* result) {
    135   *result = (UwMacaroonValidationResult){
    136       .weave_app_restricted = true,
    137       .granted_scope = UW_MACAROON_CAVEAT_SCOPE_LOWEST_POSSIBLE};
    138 }
    139 
    140 /** Get the next closest scope (to the narrower side). */
    141 static UwMacaroonCaveatScopeType get_closest_scope(
    142     UwMacaroonCaveatScopeType scope) {
    143   if (scope <= kUwMacaroonCaveatScopeTypeOwner) {
    144     return kUwMacaroonCaveatScopeTypeOwner;
    145   } else if (scope <= kUwMacaroonCaveatScopeTypeManager) {
    146     return kUwMacaroonCaveatScopeTypeManager;
    147   } else if (scope <= kUwMacaroonCaveatScopeTypeUser) {
    148     return kUwMacaroonCaveatScopeTypeUser;
    149   } else if (scope <= kUwMacaroonCaveatScopeTypeViewer) {
    150     return kUwMacaroonCaveatScopeTypeViewer;
    151   }
    152   return scope;
    153 }
    154 
    155 bool uw_macaroon_validate_(const UwMacaroon* macaroon,
    156                            const uint8_t* root_key,
    157                            size_t root_key_len,
    158                            const UwMacaroonContext* context,
    159                            UwMacaroonValidationResult* result) {
    160   if (result == NULL) {
    161     return false;
    162   }
    163   init_validation_result(result);
    164 
    165   if (root_key == NULL || root_key_len == 0 || macaroon == NULL ||
    166       context == NULL || result == NULL ||
    167       !verify_mac_tag_(root_key, root_key_len, context, macaroon->caveats,
    168                        macaroon->num_caveats, macaroon->mac_tag)) {
    169     return false;
    170   }
    171 
    172   UwMacaroonValidationState state;
    173   if (!uw_macaroon_caveat_init_validation_state_(&state)) {
    174     return false;
    175   }
    176   for (size_t i = 0; i < macaroon->num_caveats; i++) {
    177     if (!uw_macaroon_caveat_validate_(macaroon->caveats[i], context, &state,
    178                                       result)) {
    179       reset_validation_result(result);  // Reset the result object
    180       return false;
    181     }
    182   }
    183 
    184   result->granted_scope = get_closest_scope(result->granted_scope);
    185   return true;
    186 }
    187 
    188 // Encode a Macaroon to a byte string
    189 bool uw_macaroon_serialize_(const UwMacaroon* macaroon,
    190                             uint8_t* out,
    191                             size_t out_len,
    192                             size_t* resulting_str_len) {
    193   if (macaroon == NULL || out == NULL ||
    194       out_len < UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN ||
    195       resulting_str_len == NULL) {
    196     return false;
    197   }
    198 
    199   // Need to encode the whole Macaroon again into a byte string.
    200 
    201   // First encode the part without the overall byte string header to the buffer
    202   // to get the total length.
    203   size_t item_len = 0;
    204   // Start with an offset
    205   size_t offset = UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN;
    206   if (!uw_macaroon_encoding_encode_array_len_((uint32_t)(macaroon->num_caveats),
    207                                               out + offset, out_len - offset,
    208                                               &item_len)) {
    209     return false;
    210   }
    211   offset += item_len;
    212 
    213   for (size_t i = 0; i < macaroon->num_caveats; i++) {
    214     if (!uw_macaroon_encoding_encode_byte_str_(
    215             macaroon->caveats[i]->bytes, macaroon->caveats[i]->num_bytes,
    216             out + offset, out_len - offset, &item_len)) {
    217       return false;
    218     }
    219     offset += item_len;
    220   }
    221 
    222   if (!uw_macaroon_encoding_encode_byte_str_(macaroon->mac_tag,
    223                                              UW_MACAROON_MAC_LEN, out + offset,
    224                                              out_len - offset, &item_len)) {
    225     return false;
    226   }
    227   offset += item_len;
    228 
    229   // Encode the length of the body at the beginning of the buffer
    230   size_t bstr_len = offset - UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN;
    231   if (!uw_macaroon_encoding_encode_byte_str_len_(
    232           bstr_len, out, UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN, &item_len)) {
    233     return false;
    234   }
    235 
    236   // Move the body part to be adjacent to the byte string header part
    237   memmove(out + item_len, out + UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN,
    238           bstr_len);
    239 
    240   *resulting_str_len = item_len + bstr_len;
    241   return true;
    242 }
    243 
    244 // Decode a byte string to a Macaroon
    245 bool uw_macaroon_deserialize_(const uint8_t* in,
    246                               size_t in_len,
    247                               uint8_t* buffer,
    248                               size_t buffer_size,
    249                               UwMacaroon* macaroon) {
    250   if (in == NULL || in_len == 0 || buffer == NULL || buffer_size == 0 ||
    251       macaroon == NULL) {
    252     return false;
    253   }
    254 
    255   size_t offset = 0;
    256   size_t item_len = 0;
    257 
    258   const uint8_t* bstr = NULL;
    259   size_t bstr_len = 0;
    260   if (!uw_macaroon_encoding_decode_byte_str_(in + offset, in_len - offset,
    261                                              &bstr, &bstr_len)) {
    262     return false;
    263   }
    264   item_len = bstr - in;  // The length of the first byte string header
    265   offset += item_len;
    266 
    267   if (item_len + bstr_len != in_len) {
    268     // The string length doesn't match
    269     return false;
    270   }
    271 
    272   uint32_t array_len = 0;
    273   if (!uw_macaroon_encoding_decode_array_len_(in + offset, in_len - offset,
    274                                               &array_len)) {
    275     return false;
    276   }
    277   macaroon->num_caveats = (size_t)array_len;
    278   if (buffer_size <
    279       (array_len * (sizeof(UwMacaroonCaveat) + sizeof(UwMacaroonCaveat*)))) {
    280     // Need two levels of abstraction, one for structs and one for pointers
    281     return false;
    282   }
    283 
    284   if (!uw_macaroon_encoding_get_item_len_(in + offset, in_len - offset,
    285                                           &item_len)) {
    286     return false;
    287   }
    288   offset += item_len;
    289 
    290   const UwMacaroonCaveat** caveat_pointers = (const UwMacaroonCaveat**)buffer;
    291   buffer += array_len * sizeof(UwMacaroonCaveat*);
    292   UwMacaroonCaveat* caveat_structs = (UwMacaroonCaveat*)buffer;
    293   for (size_t i = 0; i < array_len; i++) {
    294     caveat_pointers[i] = &(caveat_structs[i]);
    295 
    296     if (!uw_macaroon_encoding_decode_byte_str_(
    297             in + offset, in_len - offset, &(caveat_structs[i].bytes),
    298             &(caveat_structs[i].num_bytes))) {
    299       return false;
    300     }
    301 
    302     if (!uw_macaroon_encoding_get_item_len_(in + offset, in_len - offset,
    303                                             &item_len)) {
    304       return false;
    305     }
    306     offset += item_len;
    307   }
    308   macaroon->caveats = caveat_pointers;
    309 
    310   const uint8_t* tag;
    311   size_t tag_len;
    312   if (!uw_macaroon_encoding_decode_byte_str_(in + offset, in_len - offset, &tag,
    313                                              &tag_len) ||
    314       tag_len != UW_MACAROON_MAC_LEN) {
    315     return false;
    316   }
    317   memcpy(macaroon->mac_tag, tag, UW_MACAROON_MAC_LEN);
    318 
    319   return true;
    320 }
    321