ClearKeyUtils.cpp (17206B)
1 /* 2 * Copyright 2015, Mozilla Foundation and contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ClearKeyUtils.h" 18 19 #include <assert.h> 20 #include <ctype.h> 21 #include <memory.h> 22 #include <stdarg.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 27 #include <algorithm> 28 #include <cctype> 29 #include <memory> 30 #include <sstream> 31 #include <vector> 32 33 #include "BigEndian.h" 34 #include "ClearKeyBase64.h" 35 #include "mozilla/Sprintf.h" 36 #include "pk11pub.h" 37 #include "prerror.h" 38 #include "psshparser/PsshParser.h" 39 #include "secmodt.h" 40 41 using namespace cdm; 42 using std::string; 43 using std::stringstream; 44 using std::vector; 45 46 struct DeleteHelper { 47 void operator()(PK11Context* value) { PK11_DestroyContext(value, true); } 48 void operator()(PK11SlotInfo* value) { PK11_FreeSlot(value); } 49 void operator()(PK11SymKey* value) { PK11_FreeSymKey(value); } 50 }; 51 52 template <class T> 53 struct MaybeDeleteHelper { 54 void operator()(T* ptr) { 55 if (ptr) { 56 DeleteHelper del; 57 del(ptr); 58 } 59 } 60 }; 61 62 void CK_Log(const char* aFmt, ...) { 63 FILE* out = stdout; 64 65 if (getenv("CLEARKEY_LOG_FILE")) { 66 out = fopen(getenv("CLEARKEY_LOG_FILE"), "a"); 67 } 68 69 va_list ap; 70 71 va_start(ap, aFmt); 72 const size_t len = 1024; 73 char buf[len]; 74 VsprintfLiteral(buf, aFmt, ap); 75 va_end(ap); 76 77 fprintf(out, "%s\n", buf); 78 fflush(out); 79 80 if (out != stdout) { 81 fclose(out); 82 } 83 } 84 85 static bool PrintableAsString(const uint8_t* aBytes, uint32_t aLength) { 86 return std::all_of(aBytes, aBytes + aLength, 87 [](uint8_t c) { return isprint(c) == 1; }); 88 } 89 90 void CK_LogArray(const char* prepend, const uint8_t* aData, 91 const uint32_t aDataSize) { 92 // If the data is valid ascii, use that. Otherwise print the hex 93 string data = PrintableAsString(aData, aDataSize) 94 ? string(aData, aData + aDataSize) 95 : ClearKeyUtils::ToHexString(aData, aDataSize); 96 97 CK_LOGD("%s%s", prepend, data.c_str()); 98 } 99 100 /* static */ 101 bool ClearKeyUtils::DecryptCbcs(const vector<uint8_t>& aKey, 102 const vector<uint8_t>& aIV, 103 mozilla::Span<uint8_t> aSubsample, 104 uint32_t aCryptByteBlock, 105 uint32_t aSkipByteBlock) { 106 if (aKey.size() != CENC_KEY_LEN || aIV.size() != CENC_KEY_LEN) { 107 CK_LOGE("Key and IV size should be 16!"); 108 return false; 109 } 110 111 if (aSubsample.Length() == 0) { 112 // Nothing to decrypt. 113 return true; 114 } 115 116 std::unique_ptr<PK11SlotInfo, MaybeDeleteHelper<PK11SlotInfo>> slot( 117 PK11_GetInternalKeySlot()); 118 119 if (!slot.get()) { 120 CK_LOGE("Failed to get internal PK11 slot"); 121 return false; 122 } 123 124 SECItem keyItem = {siBuffer, (unsigned char*)aKey.data(), CENC_KEY_LEN}; 125 SECItem ivItem = {siBuffer, (unsigned char*)aIV.data(), CENC_KEY_LEN}; 126 127 std::unique_ptr<PK11SymKey, MaybeDeleteHelper<PK11SymKey>> key( 128 PK11_ImportSymKey(slot.get(), CKM_AES_CBC, PK11_OriginUnwrap, CKA_DECRYPT, 129 &keyItem, nullptr)); 130 131 if (!key.get()) { 132 CK_LOGE("Failed to import sym key"); 133 return false; 134 } 135 136 std::unique_ptr<PK11Context, MaybeDeleteHelper<PK11Context>> ctx( 137 PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_DECRYPT, key.get(), &ivItem)); 138 139 if (!ctx) { 140 CK_LOGE("Failed to get PK11Context!"); 141 return false; 142 } 143 144 assert(aCryptByteBlock <= 0xFF); 145 assert(aSkipByteBlock <= 0xFF); 146 147 uint8_t* encryptedSubsample = aSubsample.data(); 148 const uint32_t BLOCK_SIZE = 16; 149 const uint32_t skipBytes = aSkipByteBlock * BLOCK_SIZE; 150 const uint32_t totalBlocks = aSubsample.size() / BLOCK_SIZE; 151 uint32_t blocksProcessed = 0; 152 153 if (aSkipByteBlock == 0) { 154 // ISO/IEC 23001 - 7 Section 9.6.1 155 // 'When the fields default_crypt_byte_block and default_skip_byte_block in 156 // a version 1 Track Encryption Box('tenc') are non - zero numbers, pattern 157 // encryption SHALL be applied.' 158 // So if both are 0, then everything is encrypted. Similarly, if skip is 0 159 // and crypt is non-0, everything is encrypted. 160 // In this case we can just decrypt all the blocks in one call. This is the 161 // same outcome as decrypting them using smaller steps, as either way the 162 // CBC result should be the same. 163 MOZ_ASSERT(skipBytes == 0); 164 aCryptByteBlock = totalBlocks; 165 } 166 167 while (blocksProcessed < totalBlocks) { 168 uint32_t blocksToDecrypt = aCryptByteBlock <= totalBlocks - blocksProcessed 169 ? aCryptByteBlock 170 : totalBlocks - blocksProcessed; 171 uint32_t bytesToDecrypt = blocksToDecrypt * BLOCK_SIZE; 172 int outLen; 173 SECStatus rv; 174 rv = PK11_CipherOp(ctx.get(), encryptedSubsample, &outLen, bytesToDecrypt, 175 encryptedSubsample, bytesToDecrypt); 176 if (rv != SECSuccess) { 177 CK_LOGE("PK11_CipherOp() failed"); 178 return false; 179 } 180 181 encryptedSubsample += skipBytes + bytesToDecrypt; 182 blocksProcessed += aSkipByteBlock + blocksToDecrypt; 183 } 184 185 return true; 186 } 187 188 /* static */ 189 bool ClearKeyUtils::DecryptAES(const vector<uint8_t>& aKey, 190 vector<uint8_t>& aData, vector<uint8_t>& aIV) { 191 assert(aIV.size() == CENC_KEY_LEN); 192 assert(aKey.size() == CENC_KEY_LEN); 193 194 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); 195 if (!slot) { 196 CK_LOGE("Failed to get internal PK11 slot"); 197 return false; 198 } 199 200 SECItem keyItem = {siBuffer, (unsigned char*)aKey.data(), CENC_KEY_LEN}; 201 PK11SymKey* key = PK11_ImportSymKey(slot, CKM_AES_CTR, PK11_OriginUnwrap, 202 CKA_ENCRYPT, &keyItem, nullptr); 203 PK11_FreeSlot(slot); 204 if (!key) { 205 CK_LOGE("Failed to import sym key"); 206 return false; 207 } 208 209 CK_AES_CTR_PARAMS params; 210 params.ulCounterBits = 32; 211 memcpy(¶ms.cb, aIV.data(), CENC_KEY_LEN); 212 SECItem paramItem = {siBuffer, (unsigned char*)¶ms, 213 sizeof(CK_AES_CTR_PARAMS)}; 214 215 unsigned int outLen = 0; 216 auto rv = PK11_Decrypt(key, CKM_AES_CTR, ¶mItem, aData.data(), &outLen, 217 aData.size(), aData.data(), aData.size()); 218 219 aData.resize(outLen); 220 PK11_FreeSymKey(key); 221 222 if (rv != SECSuccess) { 223 CK_LOGE("PK11_Decrypt() failed"); 224 return false; 225 } 226 227 return true; 228 } 229 230 /** 231 * ClearKey expects all Key IDs to be base64 encoded with non-standard alphabet 232 * and padding. 233 */ 234 static bool EncodeBase64Web(vector<uint8_t> aBinary, string& aEncoded) { 235 const char sAlphabet[] = 236 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 237 const uint8_t sMask = 0x3f; 238 239 aEncoded.resize((aBinary.size() * 8 + 5) / 6); 240 241 // Pad binary data in case there's rubbish past the last byte. 242 aBinary.push_back(0); 243 244 // Number of bytes not consumed in the previous character 245 uint32_t shift = 0; 246 247 auto out = aEncoded.begin(); 248 auto data = aBinary.begin(); 249 for (string::size_type i = 0; i < aEncoded.length(); i++) { 250 if (shift) { 251 out[i] = (*data << (6 - shift)) & sMask; 252 data++; 253 } else { 254 out[i] = 0; 255 } 256 257 out[i] += (*data >> (shift + 2)) & sMask; 258 shift = (shift + 2) % 8; 259 260 // Cast idx to size_t before using it as an array-index, 261 // to pacify clang 'Wchar-subscripts' warning: 262 size_t idx = static_cast<size_t>(out[i]); 263 264 // out of bounds index for 'sAlphabet' 265 assert(idx < std::size(sAlphabet)); 266 out[i] = sAlphabet[idx]; 267 } 268 269 return true; 270 } 271 272 /* static */ 273 void ClearKeyUtils::MakeKeyRequest(const vector<KeyId>& aKeyIDs, 274 string& aOutRequest, 275 SessionType aSessionType) { 276 assert(!aKeyIDs.empty() && aOutRequest.empty()); 277 278 aOutRequest.append("{\"kids\":["); 279 for (size_t i = 0; i < aKeyIDs.size(); i++) { 280 if (i) { 281 aOutRequest.append(","); 282 } 283 aOutRequest.append("\""); 284 285 string base64key; 286 EncodeBase64Web(aKeyIDs[i], base64key); 287 aOutRequest.append(base64key); 288 289 aOutRequest.append("\""); 290 } 291 aOutRequest.append("],\"type\":"); 292 293 aOutRequest.append("\""); 294 aOutRequest.append(SessionTypeToString(aSessionType)); 295 aOutRequest.append("\"}"); 296 } 297 298 #define EXPECT_SYMBOL(CTX, X) \ 299 do { \ 300 if (GetNextSymbol(CTX) != (X)) { \ 301 CK_LOGE("Unexpected symbol in JWK parser"); \ 302 return false; \ 303 } \ 304 } while (false) 305 306 struct ParserContext { 307 const uint8_t* mIter; 308 const uint8_t* mEnd; 309 }; 310 311 static uint8_t PeekSymbol(ParserContext& aCtx) { 312 for (; aCtx.mIter < aCtx.mEnd; (aCtx.mIter)++) { 313 if (!isspace(*aCtx.mIter)) { 314 return *aCtx.mIter; 315 } 316 } 317 318 return 0; 319 } 320 321 static uint8_t GetNextSymbol(ParserContext& aCtx) { 322 uint8_t sym = PeekSymbol(aCtx); 323 aCtx.mIter++; 324 return sym; 325 } 326 327 static bool SkipToken(ParserContext& aCtx); 328 329 static bool SkipString(ParserContext& aCtx) { 330 EXPECT_SYMBOL(aCtx, '"'); 331 for (uint8_t sym = GetNextSymbol(aCtx); sym; sym = GetNextSymbol(aCtx)) { 332 if (sym == '\\') { 333 sym = GetNextSymbol(aCtx); 334 if (!sym) { 335 return false; 336 } 337 } else if (sym == '"') { 338 return true; 339 } 340 } 341 342 return false; 343 } 344 345 /** 346 * Skip whole object and values it contains. 347 */ 348 static bool SkipObject(ParserContext& aCtx) { 349 EXPECT_SYMBOL(aCtx, '{'); 350 351 if (PeekSymbol(aCtx) == '}') { 352 GetNextSymbol(aCtx); 353 return true; 354 } 355 356 while (true) { 357 if (!SkipString(aCtx)) return false; 358 EXPECT_SYMBOL(aCtx, ':'); 359 if (!SkipToken(aCtx)) return false; 360 361 if (PeekSymbol(aCtx) == '}') { 362 GetNextSymbol(aCtx); 363 return true; 364 } 365 EXPECT_SYMBOL(aCtx, ','); 366 } 367 } 368 369 /** 370 * Skip array value and the values it contains. 371 */ 372 static bool SkipArray(ParserContext& aCtx) { 373 EXPECT_SYMBOL(aCtx, '['); 374 375 if (PeekSymbol(aCtx) == ']') { 376 GetNextSymbol(aCtx); 377 return true; 378 } 379 380 while (SkipToken(aCtx)) { 381 if (PeekSymbol(aCtx) == ']') { 382 GetNextSymbol(aCtx); 383 return true; 384 } 385 EXPECT_SYMBOL(aCtx, ','); 386 } 387 388 return false; 389 } 390 391 /** 392 * Skip unquoted literals like numbers, |true|, and |null|. 393 * (XXX and anything else that matches /([:alnum:]|[+-.])+/) 394 */ 395 static bool SkipLiteral(ParserContext& aCtx) { 396 for (; aCtx.mIter < aCtx.mEnd; aCtx.mIter++) { 397 if (!isalnum(*aCtx.mIter) && *aCtx.mIter != '.' && *aCtx.mIter != '-' && 398 *aCtx.mIter != '+') { 399 return true; 400 } 401 } 402 403 return false; 404 } 405 406 static bool SkipToken(ParserContext& aCtx) { 407 uint8_t startSym = PeekSymbol(aCtx); 408 if (startSym == '"') { 409 CK_LOGD("JWK parser skipping string"); 410 return SkipString(aCtx); 411 } else if (startSym == '{') { 412 CK_LOGD("JWK parser skipping object"); 413 return SkipObject(aCtx); 414 } else if (startSym == '[') { 415 CK_LOGD("JWK parser skipping array"); 416 return SkipArray(aCtx); 417 } else { 418 CK_LOGD("JWK parser skipping literal"); 419 return SkipLiteral(aCtx); 420 } 421 } 422 423 static bool GetNextLabel(ParserContext& aCtx, string& aOutLabel) { 424 EXPECT_SYMBOL(aCtx, '"'); 425 426 const uint8_t* start = aCtx.mIter; 427 for (uint8_t sym = GetNextSymbol(aCtx); sym; sym = GetNextSymbol(aCtx)) { 428 if (sym == '\\') { 429 GetNextSymbol(aCtx); 430 continue; 431 } 432 433 if (sym == '"') { 434 aOutLabel.assign(start, aCtx.mIter - 1); 435 return true; 436 } 437 } 438 439 return false; 440 } 441 442 static bool ParseKeyObject(ParserContext& aCtx, KeyIdPair& aOutKey) { 443 EXPECT_SYMBOL(aCtx, '{'); 444 445 // Reject empty objects as invalid licenses. 446 if (PeekSymbol(aCtx) == '}') { 447 GetNextSymbol(aCtx); 448 return false; 449 } 450 451 string keyId; 452 string key; 453 454 while (true) { 455 string label; 456 string value; 457 458 if (!GetNextLabel(aCtx, label)) { 459 return false; 460 } 461 462 EXPECT_SYMBOL(aCtx, ':'); 463 if (label == "kty") { 464 if (!GetNextLabel(aCtx, value)) return false; 465 // By spec, type must be "oct". 466 if (value != "oct") return false; 467 } else if (label == "k" && PeekSymbol(aCtx) == '"') { 468 // if this isn't a string we will fall through to the SkipToken() path. 469 if (!GetNextLabel(aCtx, key)) return false; 470 } else if (label == "kid" && PeekSymbol(aCtx) == '"') { 471 if (!GetNextLabel(aCtx, keyId)) return false; 472 } else { 473 if (!SkipToken(aCtx)) return false; 474 } 475 476 uint8_t sym = PeekSymbol(aCtx); 477 if (!sym || sym == '}') { 478 break; 479 } 480 EXPECT_SYMBOL(aCtx, ','); 481 } 482 483 return !key.empty() && !keyId.empty() && 484 DecodeBase64(keyId, aOutKey.mKeyId) && 485 DecodeBase64(key, aOutKey.mKey) && GetNextSymbol(aCtx) == '}'; 486 } 487 488 static bool ParseKeys(ParserContext& aCtx, vector<KeyIdPair>& aOutKeys) { 489 // Consume start of array. 490 EXPECT_SYMBOL(aCtx, '['); 491 492 while (true) { 493 KeyIdPair key; 494 if (!ParseKeyObject(aCtx, key)) { 495 CK_LOGE("Failed to parse key object"); 496 return false; 497 } 498 499 assert(!key.mKey.empty() && !key.mKeyId.empty()); 500 aOutKeys.push_back(key); 501 502 uint8_t sym = PeekSymbol(aCtx); 503 if (!sym || sym == ']') { 504 break; 505 } 506 507 EXPECT_SYMBOL(aCtx, ','); 508 } 509 510 return GetNextSymbol(aCtx) == ']'; 511 } 512 513 /* static */ 514 bool ClearKeyUtils::ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize, 515 vector<KeyIdPair>& aOutKeys, 516 SessionType aSessionType) { 517 ParserContext ctx; 518 ctx.mIter = aKeyData; 519 ctx.mEnd = aKeyData + aKeyDataSize; 520 521 // Consume '{' from start of object. 522 EXPECT_SYMBOL(ctx, '{'); 523 524 while (true) { 525 string label; 526 // Consume member key. 527 if (!GetNextLabel(ctx, label)) return false; 528 EXPECT_SYMBOL(ctx, ':'); 529 530 if (label == "keys") { 531 // Parse "keys" array. 532 if (!ParseKeys(ctx, aOutKeys)) return false; 533 } else if (label == "type") { 534 // Consume type string. 535 string type; 536 if (!GetNextLabel(ctx, type)) return false; 537 if (type != SessionTypeToString(aSessionType)) { 538 return false; 539 } 540 } else { 541 SkipToken(ctx); 542 } 543 544 // Check for end of object. 545 if (PeekSymbol(ctx) == '}') { 546 break; 547 } 548 549 // Consume ',' between object members. 550 EXPECT_SYMBOL(ctx, ','); 551 } 552 553 // Consume '}' from end of object. 554 EXPECT_SYMBOL(ctx, '}'); 555 556 return true; 557 } 558 559 static bool ParseKeyIds(ParserContext& aCtx, vector<KeyId>& aOutKeyIds) { 560 // Consume start of array. 561 EXPECT_SYMBOL(aCtx, '['); 562 563 while (true) { 564 string label; 565 vector<uint8_t> keyId; 566 if (!GetNextLabel(aCtx, label) || !DecodeBase64(label, keyId)) { 567 return false; 568 } 569 if (!keyId.empty() && keyId.size() <= kMaxKeyIdsLength) { 570 aOutKeyIds.push_back(keyId); 571 } 572 573 uint8_t sym = PeekSymbol(aCtx); 574 if (!sym || sym == ']') { 575 break; 576 } 577 578 EXPECT_SYMBOL(aCtx, ','); 579 } 580 581 return GetNextSymbol(aCtx) == ']'; 582 } 583 584 /* static */ 585 bool ClearKeyUtils::ParseKeyIdsInitData(const uint8_t* aInitData, 586 uint32_t aInitDataSize, 587 vector<KeyId>& aOutKeyIds) { 588 ParserContext ctx; 589 ctx.mIter = aInitData; 590 ctx.mEnd = aInitData + aInitDataSize; 591 592 // Consume '{' from start of object. 593 EXPECT_SYMBOL(ctx, '{'); 594 595 while (true) { 596 string label; 597 // Consume member kids. 598 if (!GetNextLabel(ctx, label)) return false; 599 EXPECT_SYMBOL(ctx, ':'); 600 601 if (label == "kids") { 602 // Parse "kids" array. 603 if (!ParseKeyIds(ctx, aOutKeyIds) || aOutKeyIds.empty()) { 604 return false; 605 } 606 } else { 607 SkipToken(ctx); 608 } 609 610 // Check for end of object. 611 if (PeekSymbol(ctx) == '}') { 612 break; 613 } 614 615 // Consume ',' between object members. 616 EXPECT_SYMBOL(ctx, ','); 617 } 618 619 // Consume '}' from end of object. 620 EXPECT_SYMBOL(ctx, '}'); 621 622 return true; 623 } 624 625 /* static */ const char* ClearKeyUtils::SessionTypeToString( 626 SessionType aSessionType) { 627 switch (aSessionType) { 628 case SessionType::kTemporary: 629 return "temporary"; 630 case SessionType::kPersistentLicense: 631 return "persistent-license"; 632 default: { 633 // We don't support any other license types. 634 assert(false); 635 return "invalid"; 636 } 637 } 638 } 639 640 /* static */ 641 bool ClearKeyUtils::IsValidSessionId(const char* aBuff, uint32_t aLength) { 642 if (aLength > 10) { 643 // 10 is the max number of characters in UINT32_MAX when 644 // represented as a string; ClearKey session ids are integers. 645 return false; 646 } 647 for (uint32_t i = 0; i < aLength; i++) { 648 if (!isdigit(aBuff[i])) { 649 return false; 650 } 651 } 652 return true; 653 } 654 655 string ClearKeyUtils::ToHexString(const uint8_t* aBytes, uint32_t aLength) { 656 stringstream ss; 657 ss << std::showbase << std::uppercase << std::hex; 658 for (uint32_t i = 0; i < aLength; ++i) { 659 ss << std::hex << static_cast<uint32_t>(aBytes[i]); 660 ss << " "; 661 } 662 663 return ss.str(); 664 }