Ro.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2007 The Android Open Source Project 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 <rights/Ro.h> 18#include <rights/Constraint.h> 19#include <rights/OperationPermission.h> 20#include <util/xml/DomExpatAgent.h> 21#include <util/domcore/DOMString.h> 22#include <utils/Log.h> 23 24#include <uassert.h> 25#include <time.h> 26#include <ofstream.h> 27using namespace ustl; 28 29const char *STR_RO_RIGHTS = "o-ex:rights"; 30const char *STR_RO_CONTEXT = "o-ex:context"; 31const char *STR_RO_AGREEMENT = "o-ex:agreement"; 32const char *STR_RO_ASSET = "o-ex:asset"; 33const char *STR_RO_INHERIT = "o-ex:inherit"; 34const char *STR_RO_DIGEST = "o-ex:digest"; 35const char *STR_RO_KEYINFO = "ds:KeyInfo"; 36const char *STR_RO_PERMISSION = "o-ex:permission"; 37const char *STR_RO_ASSET_ID = "o-ex:id"; 38const char *STR_RO_ASSET_IDREF = "o-ex:idref"; 39const char *STR_RO_CONTEXT_ID = "o-dd:uid"; 40const char *STR_RO_CONTEXT_VERSION = "o-dd:version"; 41const char *STR_RO_DIGEST_VALUE = "ds:DigestValue"; 42const char *STR_RO_CIPHER_VALUE = "xenc:CipherValue"; 43const char *STR_RO_RETRIEVAL_METHOD = "ds:RetrievalMethod"; 44const char *STR_RO_PLAY = "o-dd:play"; 45const char *STR_RO_DISPLAY = "o-dd:display"; 46const char *STR_RO_EXECUTE = "o-dd:execute"; 47const char *STR_RO_PRINT = "o-dd:print"; 48const char *STR_RO_EXPORT = "o-dd:export"; 49const char *STR_RO_CONSTRAINT = "o-ex:constraint"; 50const char *STR_RO_COUNT = "o-dd:count"; 51const char *STR_RO_TIMEDCOUNT = "o-dd:timed-count"; 52const char *STR_RO_TIMER = "oma-dd:timer"; 53const char *STR_RO_INTERVAL = "o-dd:interval"; 54const char *STR_RO_DATETIME = "o-dd:datetime"; 55const char *STR_RO_START = "o-dd:start"; 56const char *STR_RO_END = "o-dd:end"; 57const char *STR_RO_ACCUMULATED = "o-dd:accumulated"; 58const char *STR_RO_INDIVIDUAL = "o-dd:individual"; 59const char *STR_RO_SYSTEM = "o-dd:system"; 60 61/** see Ro.h */ 62Ro::Ro() 63{ 64 mDoc = new XMLDocumentImpl(); 65 mProperRight = NULL; 66} 67 68/** see Ro.h */ 69Ro::~Ro() 70{ 71 for (vector<Right*>::iterator itr = mRightList.begin(); itr != mRightList.end(); itr++) 72 { 73 delete(*itr); 74 } 75 76 mRightList.clear(); 77 78 for (vector<Asset*>::iterator ita = mAssetList.begin(); ita != mAssetList.end(); ita++) 79 { 80 delete(*ita); 81 } 82 83 mAssetList.clear(); 84 85 mProperRight = NULL; 86 delete mDoc; 87 88} 89 90/** see Ro.h */ 91void Ro::setRoID(string& id) 92{ 93 mRoID = id; 94} 95 96/** see Ro.h */ 97const string& Ro::getRoID() const 98{ 99 return mRoID; 100} 101 102/** see Ro.h */ 103void Ro::setRoVersion(string& version) 104{ 105 mRoVersion = version; 106} 107 108/** see Ro.h */ 109void Ro::addAsset(Asset* asset) 110{ 111 mAssetList.push_back(asset); 112} 113 114/** see Ro.h */ 115void Ro::addRight(Right* right) 116{ 117 mRightList.push_back(right); 118} 119 120/** see Ro.h */ 121bool Ro::save() 122{ 123 LOGI("==============Ro save.================="); 124 125 return true; 126} 127 128/** see Ro.h */ 129Ro::ERRCODE Ro::parse(istringstream *roStream) 130{ 131 DomExpatAgent xmlAgent(mDoc); 132 133 if (NULL == roStream) 134 { 135 LOGI("NULL stream"); 136 return RO_NULL_STREAM; 137 } 138 139 if (xmlAgent.generateDocumentFromXML(roStream) == false) 140 { 141 LOGI("generate xml doc error"); 142 return RO_ERR_BAD_XML; 143 } 144 145 handleDocument(mDoc); 146 147 return RO_OK; 148} 149 150/** see Ro.h */ 151bool Ro::handleDocument(const XMLDocumentImpl* doc) 152{ 153 assert(doc != NULL); 154 155 NodeImpl* node = doc->getDocumentElement(); 156 157 return handleRights(node); 158} 159 160/** see Ro.h */ 161bool Ro::handleRights(const NodeImpl *curNode) 162{ 163 assert(curNode != NULL); 164 165 NodeImpl *node = curNode->getFirstChild(); 166 167 while (NULL != node) 168 { 169 const DOMString* name; 170 171 name = static_cast<const XMLElementImpl*>(node)->getTagName(); 172 173 if (name->compare(STR_RO_CONTEXT) == 0) 174 { 175 LOGI("rights context"); 176 const DOMString *token = NULL; 177 token = static_cast<const XMLElementImpl*>(node)->getSoloText(STR_RO_CONTEXT_ID); 178 179 if (token) 180 { 181 LOGI(*token); 182 mRoID = *token; 183 } 184 185 token = static_cast<const XMLElementImpl*>(node)->getSoloText(STR_RO_CONTEXT_VERSION); 186 if (token) 187 { 188 LOGI(*token); 189 mRoVersion = *token; 190 } 191 } 192 193 if (name->compare(STR_RO_AGREEMENT) == 0) 194 { 195 196 LOGI("rights agreement"); 197 if (handleAgreement(node) == false) 198 { 199 return false; 200 } 201 } 202 203 node = node->getNextSibling(); 204 } 205 return true; 206} 207 208/** see Ro.h */ 209bool Ro::handleAgreement(const NodeImpl *curNode) 210{ 211 assert(curNode != NULL); 212 213 NodeImpl *node = curNode->getFirstChild(); 214 215 while (NULL != node) 216 { 217 const DOMString* name; 218 219 name = static_cast<const XMLElementImpl*>(node)->getTagName(); 220 221 if (name->compare(STR_RO_ASSET) == 0) 222 { 223 // do something about asset. 224 LOGI("asset"); 225 226 if (handleAsset(node) == false) 227 { 228 return false; 229 } 230 } 231 232 if (name->compare(STR_RO_PERMISSION) == 0) 233 { 234 // do something about permission. 235 LOGI("permission"); 236 237 if (handlePermission(node) == false) 238 { 239 return false; 240 } 241 } 242 243 node = node->getNextSibling(); 244 } 245 246 return true; 247} 248 249/** see Ro.h */ 250bool Ro::handleAsset(const NodeImpl *curNode) 251{ 252 assert(curNode != NULL); 253 254 Asset *asset = new Asset(); 255 256 const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); 257 258 if (curElement->hasAttributes()) 259 { 260 DOMString assetID(STR_RO_ASSET_ID); 261 LOGI("asset id:"); 262 263 const DOMString *id = curElement->getAttribute(&assetID); 264 265 if (id) 266 { 267 asset->setID(*id); 268 } 269 270 } 271 272 NodeImpl* node = curNode->getFirstChild(); 273 274 const DOMString *name = NULL; 275 const string *token = NULL; 276 277 while (NULL != node) 278 { 279 curElement = static_cast<const XMLElementImpl*>(node); 280 name = curElement->getTagName(); 281 282 if (name->compare(STR_RO_CONTEXT) == 0 || 283 name->compare(STR_RO_INHERIT) == 0) 284 { 285 LOGI("asset context"); 286 287 token = curElement->getSoloText(STR_RO_CONTEXT_ID); 288 if (token) 289 { 290 LOGI(*token); 291 292 if (name->compare(STR_RO_CONTEXT) == 0) 293 { 294 asset->setContentID(*token); 295 } 296 else 297 { 298 //parent ID. 299 asset->setParentContentID(*token); 300 } 301 } 302 } 303 304 if (name->compare(STR_RO_DIGEST) == 0) 305 { 306 LOGI("asset digest"); 307 //digest method is fixed value: 308 //http://www.w3.org/2000/09/xmldisig#sha1 309 token = curElement->getSoloText(STR_RO_DIGEST_VALUE); 310 if (token) 311 { 312 LOGI(*token); 313 asset->setDCFDigest(*token); 314 } 315 } 316 317 if (name->compare(STR_RO_KEYINFO) == 0) 318 { 319 LOGI("asset keyinfo"); 320 321 token = curElement->getSoloText(STR_RO_CIPHER_VALUE); 322 if (token) 323 { 324 LOGI(*token); 325 asset->setEncryptedKey(*token); 326 } 327 328 const XMLElementImpl *node = curElement->getSoloElement(STR_RO_RETRIEVAL_METHOD); 329 330 if (node) 331 { 332 if (node->hasAttributes()) 333 { 334 DOMString uri("URI"); 335 token = node->getAttribute(&uri); 336 if (token) 337 { 338 LOGI(*token); 339 asset->setKeyRetrievalMethod(*token); 340 } 341 } 342 } 343 } 344 345 node = node->getNextSibling(); 346 } 347 348 this->addAsset(asset); 349 return true; 350} 351 352/** see Ro.h */ 353bool Ro::handlePermission(const NodeImpl *curNode) 354{ 355 assert(curNode != NULL); 356 357 Right *right = new Right(); 358 359 const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); 360 361 NodeImpl* node = curNode->getFirstChild(); 362 363 while (NULL != node) 364 { 365 const DOMString *name = NULL; 366 NodeListImpl *nodeList = NULL; 367 368 const string *token = NULL; 369 curElement = static_cast<const XMLElementImpl*>(node); 370 name = curElement->getTagName(); 371 372 if (name->compare(STR_RO_ASSET) == 0) 373 { 374 LOGI("permission asset"); 375 if (curElement->hasAttributes()) 376 { 377 DOMString assetID(STR_RO_ASSET_IDREF); 378 const DOMString *id = curElement->getAttribute(&assetID); 379 if (id) 380 { 381 right->addAssetID(*id); 382 LOGI(*id); 383 } 384 } 385 } 386 387 OperationPermission::OPERATION type = OperationPermission::NONE; 388 389 if (name->compare(STR_RO_PLAY) == 0) 390 { 391 LOGI("permission play constraint"); 392 type = OperationPermission::PLAY; 393 } 394 395 if (name->compare(STR_RO_DISPLAY) == 0) 396 { 397 LOGI("permission display costraint"); 398 type = OperationPermission::DISPLAY; 399 } 400 401 if (name->compare(STR_RO_EXECUTE) == 0) 402 { 403 LOGI("permission execute constraint"); 404 type = OperationPermission::EXECUTE; 405 } 406 407 if (name->compare(STR_RO_EXPORT) == 0) 408 { 409 LOGI("permission export constraint"); 410 type = OperationPermission::EXPORT; 411 } 412 413 if (name->compare(STR_RO_PRINT) == 0) 414 { 415 LOGI("permission print constraint"); 416 type = OperationPermission::PRINT; 417 } 418 419 Constraint *cst = NULL; 420 421 if (name->compare(STR_RO_CONSTRAINT) == 0) 422 { 423 LOGI("permission common constraint"); 424 type = OperationPermission::COMMON; 425 } 426 427 cst = getConstraint(curElement); 428 if (cst) 429 { 430 OperationPermission *op = new OperationPermission(type, cst); 431 right->addOperationPermission(op); 432 } 433 434 node = node->getNextSibling(); 435 } 436 437 this->addRight(right); 438 return true; 439} 440 441/** see Ro.h */ 442long Ro::convertISO8601DateTimeToLong(const char* ts) 443{ 444 if (NULL == ts) 445 { 446 return -1; 447 } 448 449 struct tm time; 450 memset(&time, 0, sizeof(struct tm)); 451 452 strptime(ts, "%FT%T%z", &time); 453 454//need timezone support: return mktime(&time) - timezone; 455//It seems android-sooner doesn't support timezone function. 456//line below is just for building, value would be wrong if no timezone minus. 457 return mktime(&time); 458} 459 460/** see Ro.h */ 461long Ro::convertISO8601PeriodToLong(const char* ts) 462{ 463 if (NULL == ts) 464 { 465 return -1; 466 } 467 468 int date, hour, min, sec; 469 sscanf(ts, "P%dDT%dH%dM%dS", &date, &hour, &min, &sec); 470 LOGI("%d %d %d %d", date, hour, min, sec); 471 return (date*24*60*60 + hour*60*60 + min*60 + sec); 472} 473 474/** see Ro.h */ 475Constraint* Ro::getConstraint(const NodeImpl* curNode) 476{ 477 assert(curNode != NULL); 478 479 Constraint *constraint = new Constraint(); 480 481 const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); 482 483 const string *name = NULL; 484 const string *token = NULL; 485 486 if ((token = curElement->getSoloText(STR_RO_COUNT))) 487 { 488 LOGI(*token); 489 constraint->setCount(atoi(token->c_str())); 490 } 491 492 if ((token = curElement->getSoloText(STR_RO_START))) 493 { 494 LOGI(*token); 495 //start Time 496 constraint->setStartTime(convertISO8601DateTimeToLong(token->c_str())); 497 } 498 499 if ((token = curElement->getSoloText(STR_RO_END))) 500 { 501 LOGI(*token); 502 //end Time 503 constraint->setEndTime(convertISO8601DateTimeToLong(token->c_str())); 504 } 505 506 if ((token = curElement->getSoloText(STR_RO_INTERVAL))) 507 { 508 LOGI(*token); 509 constraint->setInterval(atoi(token->c_str())); 510 } 511 512 if ((token = curElement->getSoloText(STR_RO_ACCUMULATED))) 513 { 514 LOGI(*token); 515 //Period 516 constraint->setAccumulated(convertISO8601PeriodToLong(token->c_str())); 517 } 518 519 if ((token = curElement->getSoloText(STR_RO_TIMEDCOUNT))) 520 { 521 LOGI(*token); 522 constraint->setTimedCount(atoi(token->c_str())); 523 524 const XMLElementImpl *node = curElement->getSoloElement(STR_RO_TIMEDCOUNT); 525 526 if (node) 527 { 528 if (node->hasAttributes()) 529 { 530 DOMString timer(STR_RO_TIMER); 531 token = node->getAttribute(&timer); 532 if (token) 533 { 534 LOGI(*token); 535 constraint->setTimer(atoi(token->c_str())); 536 } 537 } 538 } 539 540 } 541 542 return constraint; 543} 544 545/** see Ro.h */ 546void Ro::loadRights(const string& contentID) 547{ 548 for (vector<Right*>::iterator it = this->mRightList.begin(); 549 it != this->mRightList.end(); it++) 550 { 551 if ((*it)->mAssetNameList.empty()) 552 { 553 mContentRightList.push_back(*it); 554 } 555 else 556 { 557 for (vector<Asset*>::iterator ita = this->mAssetList.begin(); 558 ita != this->mAssetList.end(); ita++) 559 { 560 for (vector<string>::iterator its = (*it)->mAssetNameList.begin(); 561 its != (*it)->mAssetNameList.end(); its++) 562 { 563 if ((*its).compare((*ita)->getID()) == 0) 564 { 565 if (contentID.compare((*ita)->getContentID()) == 0) 566 { 567 LOGI("find content right"); 568 mContentRightList.push_back(*it); 569 } 570 } 571 } 572 } 573 } 574 575 576 } 577 578} 579 580/** see Ro.h */ 581void Ro::freeRights() 582{ 583 mContentRightList.clear(); 584} 585 586/** see Ro.h */ 587bool Ro::checkPermission(OperationPermission::OPERATION type, 588 const string& contentID) 589{ 590 loadRights(contentID); 591 592 for (vector<Right*>::iterator it = mContentRightList.begin(); it != mContentRightList.end(); it++) 593 { 594 if ((*it)->checkPermission(type)) 595 { 596 freeRights(); 597 return true; 598 } 599 600 } 601 freeRights(); 602 return false; 603} 604 605/** see Ro.h */ 606Ro::ERRCODE Ro::consume(OperationPermission::OPERATION type, 607 const string& contentID) 608{ 609 loadRights(contentID); 610 611 //check in mRightList 612 vector<Right*>::iterator it; 613 vector<Right*> tmpList; 614 vector<Right*> retList; 615 Constraint *constraint = NULL; 616 long ealiestEnd = -1; 617 bool hasCommonConstraint = false; 618 bool hasUnconstraint = false; 619 bool hasDateTimeConstraint = false; 620 bool hasTimedCountConstraint = false; 621 bool hasIntervalConstraint = false; 622 623 624 //apply the RO rule, if do not satisfy the constraint, . 625 //proper right select process 626 627 for (it = mContentRightList.begin(); it != mContentRightList.end(); it++) 628 { 629 if ((*it)->checkPermission(type)) 630 { 631 constraint = (*it)->getConstraint(OperationPermission::COMMON); 632 if (constraint) 633 { 634 if (!constraint->isValid(time(NULL))) 635 { 636 continue; 637 } 638 639 hasCommonConstraint = true; 640 tmpList.push_back(*it); 641 } 642 643 constraint = (*it)->getConstraint(type); 644 assert(constraint != NULL); 645 646 if (!constraint->isValid(time(NULL))) 647 { 648 continue; 649 } 650 651 if (constraint->isUnConstraint()) 652 { 653 //use uncontrainted firstly. 654 hasUnconstraint = true; 655 tmpList.push_back(*it); 656 break; 657 } 658 659 if (constraint->isDateTimeConstraint()) 660 { 661 //use datetime constraint in high priority. 662 //if contain multipe constraints, use the earliest expire time. 663 hasDateTimeConstraint = true; 664 tmpList.push_back(*it); 665 continue; 666 } 667 668 if (constraint->isTimedCountConstraint()) 669 { 670 //illegal Operation when time counted 671 if (type == OperationPermission::PRINT || 672 type == OperationPermission::EXPORT) 673 { 674 continue; 675 } 676 677 hasTimedCountConstraint = true; 678 tmpList.push_back(*it); 679 continue; 680 } 681 682 if (constraint->isIntervalConstraint()) 683 { 684 hasIntervalConstraint = true; 685 tmpList.push_back(*it); 686 continue; 687 } 688 689 tmpList.push_back(*it); 690 } 691 } 692 693 694 for (it = tmpList.begin(); it != tmpList.end(); it++) 695 { 696 if (hasUnconstraint == true) 697 { 698 //delete other constraint 699 constraint = (*it)->getConstraint(type); 700 if (constraint) 701 { 702 if (constraint->isUnConstraint()) 703 { 704 retList.push_back(*it); 705 break; 706 } 707 } 708 continue; 709 } 710 711 if (hasDateTimeConstraint == true) 712 { 713 //delete other constraint 714 constraint = (*it)->getConstraint(type); 715 if (constraint) 716 { 717 if (constraint->isDateTimeConstraint()) 718 { 719 long tt = constraint->getEndTime(); 720 721 if (ealiestEnd == -1) 722 { 723 ealiestEnd = tt; 724 retList.push_back(*it); 725 } 726 else if (ealiestEnd > tt) 727 { 728 ealiestEnd = tt; 729 retList.pop_back(); 730 retList.push_back(*it); 731 } 732 } 733 } 734 continue; 735 } 736 737 if (hasIntervalConstraint == true) 738 { 739 //delete other constraint 740 constraint = (*it)->getConstraint(type); 741 if (constraint) 742 { 743 if (constraint->isIntervalConstraint()) 744 { 745 retList.push_back(*it); 746 } 747 } 748 continue; 749 } 750 751 if (hasTimedCountConstraint == true) 752 { 753 constraint = (*it)->getConstraint(type); 754 if (constraint) 755 { 756 if (constraint->isTimedCountConstraint()) 757 { 758 retList.push_back(*it); 759 } 760 } 761 continue; 762 } 763 764 retList.push_back(*it); 765 } 766 767 if (retList.size() == 0) 768 { 769 freeRights(); 770 return RO_BAD; 771 } 772 773 LOGI("Proper right has %d", retList.size()); 774 775 assert(retList.size() == 1); 776 777 mProperRight = retList[0]; 778 constraint = retList[0]->getConstraint(OperationPermission::COMMON); 779 if (constraint) 780 { 781 if (constraint->consume() == false) 782 { 783 freeRights(); 784 return RO_BAD; 785 } 786 } 787 788 constraint = retList[0]->getConstraint(type); 789 if (constraint) 790 { 791 if (constraint->consume() == false) 792 { 793 freeRights(); 794 return RO_BAD; 795 } 796 } 797 798 //update the constraint 799 freeRights(); 800 return RO_OK; 801} 802 803/** see Ro.h */ 804string Ro::getContentCek(const string& contentID) 805{ 806 for (vector<Asset*>::iterator it = mAssetList.begin(); 807 it != mAssetList.end(); it++) 808 { 809 if (contentID.compare((*it)->getContentID()) == 0) 810 { 811 return (*it)->getCek(); 812 } 813 } 814 815 return ""; 816} 817 818/** see Ro.h */ 819string Ro::getContentHash(const string& contentID) 820{ 821 for (vector<Asset*>::iterator it = mAssetList.begin(); 822 it != mAssetList.end(); it++) 823 { 824 if (contentID.compare((*it)->getContentID()) == 0) 825 { 826 return (*it)->getDCFDigest(); 827 } 828 } 829 830 return ""; 831} 832