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_caveat.h" 6 #include "src/macaroon_caveat_internal.h" 7 8 #include <string.h> 9 10 #include "src/crypto_hmac.h" 11 #include "src/macaroon.h" 12 #include "src/macaroon_context.h" 13 #include "src/macaroon_encoding.h" 14 15 static bool is_valid_caveat_type_(UwMacaroonCaveatType type) { 16 switch (type) { 17 case kUwMacaroonCaveatTypeNonce: 18 case kUwMacaroonCaveatTypeScope: 19 case kUwMacaroonCaveatTypeExpirationAbsolute: 20 case kUwMacaroonCaveatTypeTTL1Hour: 21 case kUwMacaroonCaveatTypeTTL24Hour: 22 case kUwMacaroonCaveatTypeDelegationTimestamp: 23 case kUwMacaroonCaveatTypeDelegateeUser: 24 case kUwMacaroonCaveatTypeDelegateeApp: 25 case kUwMacaroonCaveatTypeAppCommandsOnly: 26 case kUwMacaroonCaveatTypeDelegateeService: 27 case kUwMacaroonCaveatTypeBleSessionID: 28 case kUwMacaroonCaveatTypeLanSessionID: 29 case kUwMacaroonCaveatTypeClientAuthorizationTokenV1: 30 case kUwMacaroonCaveatTypeServerAuthenticationTokenV1: 31 return true; 32 } 33 return false; 34 } 35 36 static bool is_valid_scope_type_(UwMacaroonCaveatScopeType type) { 37 switch (type) { 38 case kUwMacaroonCaveatScopeTypeOwner: 39 case kUwMacaroonCaveatScopeTypeManager: 40 case kUwMacaroonCaveatScopeTypeUser: 41 case kUwMacaroonCaveatScopeTypeViewer: 42 return true; 43 } 44 return false; 45 } 46 47 static bool create_caveat_no_value_(UwMacaroonCaveatType type, 48 uint8_t* buffer, 49 size_t buffer_size, 50 UwMacaroonCaveat* new_caveat) { 51 // (buffer_size == 0 || get_buffer_size_() > buffer_size) will conver the case 52 // that get_buffer_size_() returns 0 (for errors), so there is no need to 53 // check get_buffer_size_() == 0 again. 54 if (buffer == NULL || buffer_size == 0 || new_caveat == NULL || 55 uw_macaroon_caveat_creation_get_buffsize_(type, 0) > buffer_size) { 56 return false; 57 } 58 59 size_t encoded_str_len = 0, total_str_len = 0; 60 if (!uw_macaroon_encoding_encode_uint_((uint32_t)type, buffer, buffer_size, 61 &encoded_str_len)) { 62 return false; 63 } 64 total_str_len += encoded_str_len; 65 66 new_caveat->bytes = buffer; 67 new_caveat->num_bytes = total_str_len; 68 return true; 69 } 70 71 static bool create_caveat_uint_value_(UwMacaroonCaveatType type, 72 uint32_t unsigned_int, 73 uint8_t* buffer, 74 size_t buffer_size, 75 UwMacaroonCaveat* new_caveat) { 76 if (buffer == NULL || buffer_size == 0 || new_caveat == NULL || 77 uw_macaroon_caveat_creation_get_buffsize_(type, 0) > buffer_size) { 78 return false; 79 } 80 81 size_t encoded_str_len = 0, total_str_len = 0; 82 if (!uw_macaroon_encoding_encode_uint_((uint32_t)type, buffer, buffer_size, 83 &encoded_str_len)) { 84 return false; 85 } 86 total_str_len += encoded_str_len; 87 if (!uw_macaroon_encoding_encode_uint_(unsigned_int, buffer + total_str_len, 88 buffer_size - total_str_len, 89 &encoded_str_len)) { 90 return false; 91 } 92 total_str_len += encoded_str_len; 93 94 new_caveat->bytes = buffer; 95 new_caveat->num_bytes = total_str_len; 96 return true; 97 } 98 99 static bool create_caveat_bstr_value_(UwMacaroonCaveatType type, 100 const uint8_t* str, 101 size_t str_len, 102 uint8_t* buffer, 103 size_t buffer_size, 104 UwMacaroonCaveat* new_caveat) { 105 if ((str == NULL && str_len != 0) || buffer == NULL || buffer_size == 0 || 106 new_caveat == NULL || 107 uw_macaroon_caveat_creation_get_buffsize_(type, str_len) > buffer_size) { 108 return false; 109 } 110 111 size_t encoded_str_len = 0, total_str_len = 0; 112 if (!uw_macaroon_encoding_encode_uint_((uint32_t)type, buffer, buffer_size, 113 &encoded_str_len)) { 114 return false; 115 } 116 total_str_len += encoded_str_len; 117 if (!uw_macaroon_encoding_encode_byte_str_( 118 str, str_len, buffer + total_str_len, buffer_size - total_str_len, 119 &encoded_str_len)) { 120 return false; 121 } 122 total_str_len += encoded_str_len; 123 124 new_caveat->bytes = buffer; 125 new_caveat->num_bytes = total_str_len; 126 return true; 127 } 128 129 size_t uw_macaroon_caveat_creation_get_buffsize_(UwMacaroonCaveatType type, 130 size_t str_len) { 131 switch (type) { 132 // No values 133 case kUwMacaroonCaveatTypeTTL1Hour: 134 case kUwMacaroonCaveatTypeTTL24Hour: 135 case kUwMacaroonCaveatTypeAppCommandsOnly: 136 case kUwMacaroonCaveatTypeBleSessionID: 137 return UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN; 138 139 // Unsigned integers 140 case kUwMacaroonCaveatTypeScope: 141 case kUwMacaroonCaveatTypeExpirationAbsolute: 142 case kUwMacaroonCaveatTypeDelegationTimestamp: 143 return 2 * UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN; 144 145 // Byte strings 146 case kUwMacaroonCaveatTypeNonce: 147 case kUwMacaroonCaveatTypeDelegateeUser: 148 case kUwMacaroonCaveatTypeDelegateeApp: 149 case kUwMacaroonCaveatTypeDelegateeService: 150 case kUwMacaroonCaveatTypeLanSessionID: 151 case kUwMacaroonCaveatTypeClientAuthorizationTokenV1: 152 case kUwMacaroonCaveatTypeServerAuthenticationTokenV1: 153 return str_len + UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN; 154 155 default: 156 return 0; // For errors 157 } 158 } 159 160 bool uw_macaroon_caveat_create_nonce_(const uint8_t* nonce, 161 size_t nonce_size, 162 uint8_t* buffer, 163 size_t buffer_size, 164 UwMacaroonCaveat* new_caveat) { 165 return create_caveat_bstr_value_(kUwMacaroonCaveatTypeNonce, nonce, 166 nonce_size, buffer, buffer_size, new_caveat); 167 } 168 169 bool uw_macaroon_caveat_create_scope_(UwMacaroonCaveatScopeType scope, 170 uint8_t* buffer, 171 size_t buffer_size, 172 UwMacaroonCaveat* new_caveat) { 173 if (!is_valid_scope_type_(scope)) { 174 return false; 175 } 176 177 return create_caveat_uint_value_(kUwMacaroonCaveatTypeScope, scope, buffer, 178 buffer_size, new_caveat); 179 } 180 181 bool uw_macaroon_caveat_create_expiration_absolute_( 182 uint32_t expiration_time, 183 uint8_t* buffer, 184 size_t buffer_size, 185 UwMacaroonCaveat* new_caveat) { 186 return create_caveat_uint_value_(kUwMacaroonCaveatTypeExpirationAbsolute, 187 expiration_time, buffer, buffer_size, 188 new_caveat); 189 } 190 191 bool uw_macaroon_caveat_create_ttl_1_hour_(uint8_t* buffer, 192 size_t buffer_size, 193 UwMacaroonCaveat* new_caveat) { 194 return create_caveat_no_value_(kUwMacaroonCaveatTypeTTL1Hour, buffer, 195 buffer_size, new_caveat); 196 } 197 198 bool uw_macaroon_caveat_create_ttl_24_hour_(uint8_t* buffer, 199 size_t buffer_size, 200 UwMacaroonCaveat* new_caveat) { 201 return create_caveat_no_value_(kUwMacaroonCaveatTypeTTL24Hour, buffer, 202 buffer_size, new_caveat); 203 } 204 205 bool uw_macaroon_caveat_create_delegation_timestamp_( 206 uint32_t timestamp, 207 uint8_t* buffer, 208 size_t buffer_size, 209 UwMacaroonCaveat* new_caveat) { 210 return create_caveat_uint_value_(kUwMacaroonCaveatTypeDelegationTimestamp, 211 timestamp, buffer, buffer_size, new_caveat); 212 } 213 214 bool uw_macaroon_caveat_create_delegatee_user_(const uint8_t* id_str, 215 size_t id_str_len, 216 uint8_t* buffer, 217 size_t buffer_size, 218 UwMacaroonCaveat* new_caveat) { 219 return create_caveat_bstr_value_(kUwMacaroonCaveatTypeDelegateeUser, id_str, 220 id_str_len, buffer, buffer_size, new_caveat); 221 } 222 223 bool uw_macaroon_caveat_create_delegatee_app_(const uint8_t* id_str, 224 size_t id_str_len, 225 uint8_t* buffer, 226 size_t buffer_size, 227 UwMacaroonCaveat* new_caveat) { 228 return create_caveat_bstr_value_(kUwMacaroonCaveatTypeDelegateeApp, id_str, 229 id_str_len, buffer, buffer_size, new_caveat); 230 } 231 232 bool uw_macaroon_caveat_create_app_commands_only_( 233 uint8_t* buffer, 234 size_t buffer_size, 235 UwMacaroonCaveat* new_caveat) { 236 return create_caveat_no_value_(kUwMacaroonCaveatTypeAppCommandsOnly, buffer, 237 buffer_size, new_caveat); 238 } 239 240 bool uw_macaroon_caveat_create_delegatee_service_( 241 const uint8_t* id_str, 242 size_t id_str_len, 243 uint8_t* buffer, 244 size_t buffer_size, 245 UwMacaroonCaveat* new_caveat) { 246 return create_caveat_bstr_value_(kUwMacaroonCaveatTypeDelegateeService, 247 id_str, id_str_len, buffer, buffer_size, 248 new_caveat); 249 } 250 251 bool uw_macaroon_caveat_create_ble_session_id_(uint8_t* buffer, 252 size_t buffer_size, 253 UwMacaroonCaveat* new_caveat) { 254 return create_caveat_no_value_(kUwMacaroonCaveatTypeBleSessionID, buffer, 255 buffer_size, new_caveat); 256 } 257 258 bool uw_macaroon_caveat_create_lan_session_id_(const uint8_t* session_id, 259 size_t session_id_len, 260 uint8_t* buffer, 261 size_t buffer_size, 262 UwMacaroonCaveat* new_caveat) { 263 return create_caveat_bstr_value_(kUwMacaroonCaveatTypeLanSessionID, 264 session_id, session_id_len, buffer, 265 buffer_size, new_caveat); 266 } 267 268 bool uw_macaroon_caveat_create_client_authorization_token_( 269 const uint8_t* str, 270 size_t str_len, 271 uint8_t* buffer, 272 size_t buffer_size, 273 UwMacaroonCaveat* new_caveat) { 274 if (str_len == 0) { 275 return create_caveat_no_value_( 276 kUwMacaroonCaveatTypeClientAuthorizationTokenV1, buffer, buffer_size, 277 new_caveat); 278 } 279 return create_caveat_bstr_value_( 280 kUwMacaroonCaveatTypeClientAuthorizationTokenV1, str, str_len, buffer, 281 buffer_size, new_caveat); 282 } 283 284 bool uw_macaroon_caveat_create_server_authentication_token_( 285 const uint8_t* str, 286 size_t str_len, 287 uint8_t* buffer, 288 size_t buffer_size, 289 UwMacaroonCaveat* new_caveat) { 290 if (str_len == 0) { 291 return create_caveat_no_value_( 292 kUwMacaroonCaveatTypeServerAuthenticationTokenV1, buffer, buffer_size, 293 new_caveat); 294 } 295 return create_caveat_bstr_value_( 296 kUwMacaroonCaveatTypeServerAuthenticationTokenV1, str, str_len, buffer, 297 buffer_size, new_caveat); 298 } 299 300 bool uw_macaroon_caveat_get_type_(const UwMacaroonCaveat* caveat, 301 UwMacaroonCaveatType* type) { 302 if (caveat == NULL || type == NULL) { 303 return false; 304 } 305 306 uint32_t unsigned_int; 307 if (!uw_macaroon_encoding_decode_uint_(caveat->bytes, caveat->num_bytes, 308 &unsigned_int)) { 309 return false; 310 } 311 312 *type = (UwMacaroonCaveatType)unsigned_int; 313 return is_valid_caveat_type_(*type); 314 } 315 316 /* === Some internal functions defined in macaroon_caveat_internal.h === */ 317 318 bool uw_macaroon_caveat_sign_(const uint8_t* key, 319 size_t key_len, 320 const UwMacaroonContext* context, 321 const UwMacaroonCaveat* caveat, 322 uint8_t* mac_tag, 323 size_t mac_tag_size) { 324 if (key == NULL || key_len == 0 || context == NULL || caveat == NULL || 325 mac_tag == NULL || mac_tag_size == 0) { 326 return false; 327 } 328 329 UwMacaroonCaveatType caveat_type; 330 if (!uw_macaroon_caveat_get_type_(caveat, &caveat_type) || 331 !is_valid_caveat_type_(caveat_type)) { 332 return false; 333 } 334 335 // Need to encode the whole caveat as a byte string and then sign it 336 337 // If there is no additional value from the context, just compute the HMAC on 338 // the current byte string. 339 uint8_t bstr_cbor_prefix[UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN] = {0}; 340 size_t bstr_cbor_prefix_len = 0; 341 if (caveat_type != kUwMacaroonCaveatTypeBleSessionID) { 342 if (!uw_macaroon_encoding_encode_byte_str_len_( 343 (uint32_t)(caveat->num_bytes), bstr_cbor_prefix, 344 sizeof(bstr_cbor_prefix), &bstr_cbor_prefix_len)) { 345 return false; 346 } 347 348 UwCryptoHmacMsg messages[] = { 349 {bstr_cbor_prefix, bstr_cbor_prefix_len}, 350 {caveat->bytes, caveat->num_bytes}, 351 }; 352 353 return uw_crypto_hmac_(key, key_len, messages, 354 sizeof(messages) / sizeof(messages[0]), mac_tag, 355 mac_tag_size); 356 } 357 358 // If there is additional value from the context. 359 if (context->ble_session_id == NULL || context->ble_session_id_len == 0) { 360 return false; 361 } 362 363 // The length here includes the length of the BLE session ID string. 364 if (!uw_macaroon_encoding_encode_byte_str_len_( 365 (uint32_t)(context->ble_session_id_len + caveat->num_bytes), 366 bstr_cbor_prefix, sizeof(bstr_cbor_prefix), &bstr_cbor_prefix_len)) { 367 return false; 368 } 369 370 uint8_t value_cbor_prefix[UW_MACAROON_ENCODING_MAX_UINT_CBOR_LEN] = {0}; 371 size_t value_cbor_prefix_len = 0; 372 if (!uw_macaroon_encoding_encode_byte_str_len_( 373 (uint32_t)(context->ble_session_id_len), value_cbor_prefix, 374 sizeof(value_cbor_prefix), &value_cbor_prefix_len)) { 375 return false; 376 } 377 378 UwCryptoHmacMsg messages[] = { 379 {bstr_cbor_prefix, bstr_cbor_prefix_len}, 380 {caveat->bytes, caveat->num_bytes}, 381 {value_cbor_prefix, value_cbor_prefix_len}, 382 {context->ble_session_id, context->ble_session_id_len}, 383 }; 384 385 return uw_crypto_hmac_(key, key_len, messages, 386 sizeof(messages) / sizeof(messages[0]), mac_tag, 387 mac_tag_size); 388 } 389 390 static bool update_and_check_expiration_time( 391 uint32_t current_time, 392 uint32_t new_expiration_time, 393 UwMacaroonValidationResult* result) { 394 if (result->expiration_time > new_expiration_time) { 395 result->expiration_time = new_expiration_time; 396 } 397 398 return current_time <= result->expiration_time; 399 } 400 401 static bool update_delegatee_list(UwMacaroonCaveatType caveat_type, 402 const UwMacaroonCaveat* caveat, 403 uint32_t issued_time, 404 UwMacaroonValidationResult* result) { 405 if (result->num_delegatees >= MAX_NUM_DELEGATEES || issued_time == 0) { 406 return false; 407 } 408 409 UwMacaroonDelegateeType delegatee_type = kUwMacaroonDelegateeTypeNone; 410 switch (caveat_type) { 411 case kUwMacaroonCaveatTypeDelegateeUser: 412 delegatee_type = kUwMacaroonDelegateeTypeUser; 413 break; 414 415 case kUwMacaroonCaveatTypeDelegateeApp: 416 delegatee_type = kUwMacaroonDelegateeTypeApp; 417 break; 418 419 case kUwMacaroonCaveatTypeDelegateeService: 420 delegatee_type = kUwMacaroonDelegateeTypeService; 421 break; 422 423 default: 424 return false; 425 } 426 427 if (caveat_type != kUwMacaroonCaveatTypeDelegateeUser) { 428 for (size_t i = 0; i < result->num_delegatees; i++) { 429 // There must have at most one DelegateeApp or DelegateeService 430 if (result->delegatees[i].type == delegatee_type) { 431 return false; 432 } 433 } 434 } 435 436 if (!uw_macaroon_caveat_get_value_bstr_( 437 caveat, &(result->delegatees[result->num_delegatees].id), 438 &(result->delegatees[result->num_delegatees].id_len))) { 439 return false; 440 } 441 result->delegatees[result->num_delegatees].type = delegatee_type; 442 result->delegatees[result->num_delegatees].timestamp = issued_time; 443 result->num_delegatees++; 444 return true; 445 } 446 447 bool uw_macaroon_caveat_validate_(const UwMacaroonCaveat* caveat, 448 const UwMacaroonContext* context, 449 UwMacaroonValidationState* state, 450 UwMacaroonValidationResult* result) { 451 if (caveat == NULL || context == NULL || state == NULL || result == NULL) { 452 return false; 453 } 454 455 uint32_t expiration_time = 0; 456 uint32_t issued_time = 0; 457 uint32_t scope = UW_MACAROON_CAVEAT_SCOPE_LOWEST_POSSIBLE; 458 459 UwMacaroonCaveatType caveat_type; 460 if (!uw_macaroon_caveat_get_type_(caveat, &caveat_type)) { 461 return false; 462 } 463 464 switch (caveat_type) { 465 // The types that always validate 466 case kUwMacaroonCaveatTypeClientAuthorizationTokenV1: 467 case kUwMacaroonCaveatTypeServerAuthenticationTokenV1: 468 case kUwMacaroonCaveatTypeNonce: 469 case kUwMacaroonCaveatTypeBleSessionID: 470 return true; 471 472 case kUwMacaroonCaveatTypeDelegationTimestamp: 473 if (!uw_macaroon_caveat_get_value_uint_(caveat, &issued_time) || 474 issued_time < state->issued_time) { 475 return false; 476 } 477 state->issued_time = issued_time; 478 return true; 479 480 case kUwMacaroonCaveatTypeTTL1Hour: 481 if (state->issued_time == 0) { 482 return false; 483 } 484 return update_and_check_expiration_time( 485 context->current_time, state->issued_time + 60 * 60, result); 486 487 case kUwMacaroonCaveatTypeTTL24Hour: 488 if (state->issued_time == 0) { 489 return false; 490 } 491 return update_and_check_expiration_time( 492 context->current_time, state->issued_time + 24 * 60 * 60, result); 493 494 // Need to create a list of delegatees 495 case kUwMacaroonCaveatTypeDelegateeUser: 496 case kUwMacaroonCaveatTypeDelegateeApp: 497 case kUwMacaroonCaveatTypeDelegateeService: 498 return update_delegatee_list(caveat_type, caveat, state->issued_time, 499 result); 500 501 // Time related caveats 502 case kUwMacaroonCaveatTypeExpirationAbsolute: 503 if (!uw_macaroon_caveat_get_value_uint_(caveat, &expiration_time)) { 504 return false; 505 } 506 return update_and_check_expiration_time(context->current_time, 507 expiration_time, result); 508 509 // The caveats that update the values of the result object 510 case kUwMacaroonCaveatTypeScope: 511 if (!uw_macaroon_caveat_get_value_uint_(caveat, &scope) || 512 // Larger value means less priviledge 513 scope > UW_MACAROON_CAVEAT_SCOPE_LOWEST_POSSIBLE) { 514 return false; 515 } 516 if (scope > (uint32_t)(result->granted_scope)) { 517 result->granted_scope = (UwMacaroonCaveatScopeType)scope; 518 } 519 return true; 520 521 case kUwMacaroonCaveatTypeAppCommandsOnly: 522 result->weave_app_restricted = true; 523 return true; 524 525 case kUwMacaroonCaveatTypeLanSessionID: 526 return uw_macaroon_caveat_get_value_bstr_( 527 caveat, &(result->lan_session_id), &(result->lan_session_id_len)); 528 } 529 530 return false; 531 } 532 533 bool uw_macaroon_caveat_get_value_uint_(const UwMacaroonCaveat* caveat, 534 uint32_t* unsigned_int) { 535 if (caveat == NULL || unsigned_int == NULL) { 536 return false; 537 } 538 539 UwMacaroonCaveatType type; 540 if (!uw_macaroon_caveat_get_type_(caveat, &type)) { 541 return false; 542 } 543 if (type != kUwMacaroonCaveatTypeScope && 544 type != kUwMacaroonCaveatTypeExpirationAbsolute && 545 type != kUwMacaroonCaveatTypeDelegationTimestamp) { 546 // Wrong type 547 return false; 548 } 549 550 // Skip the portion for CBOR type 551 size_t offset; 552 if (!uw_macaroon_encoding_get_item_len_(caveat->bytes, caveat->num_bytes, 553 &offset)) { 554 return false; 555 } 556 557 return uw_macaroon_encoding_decode_uint_( 558 caveat->bytes + offset, caveat->num_bytes - offset, unsigned_int); 559 } 560 561 bool uw_macaroon_caveat_get_value_bstr_(const UwMacaroonCaveat* caveat, 562 const uint8_t** str, 563 size_t* str_len) { 564 if (caveat == NULL || str == NULL || str_len == NULL) { 565 return false; 566 } 567 568 UwMacaroonCaveatType type; 569 if (!uw_macaroon_caveat_get_type_(caveat, &type)) { 570 return false; 571 } 572 if (type != kUwMacaroonCaveatTypeNonce && 573 type != kUwMacaroonCaveatTypeDelegateeUser && 574 type != kUwMacaroonCaveatTypeDelegateeApp && 575 type != kUwMacaroonCaveatTypeDelegateeService && 576 type != kUwMacaroonCaveatTypeLanSessionID && 577 type != kUwMacaroonCaveatTypeClientAuthorizationTokenV1 && 578 type != kUwMacaroonCaveatTypeServerAuthenticationTokenV1) { 579 // Wrong type 580 return false; 581 } 582 583 size_t offset; 584 if (!uw_macaroon_encoding_get_item_len_(caveat->bytes, caveat->num_bytes, 585 &offset)) { 586 return false; 587 } 588 589 return uw_macaroon_encoding_decode_byte_str_( 590 caveat->bytes + offset, caveat->num_bytes - offset, str, str_len); 591 } 592 593 bool uw_macaroon_caveat_init_validation_state_( 594 UwMacaroonValidationState* state) { 595 if (state == NULL) { 596 return false; 597 } 598 599 state->issued_time = 0; 600 return true; 601 } 602