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>
27 using namespace ustl;
28
29 const char *STR_RO_RIGHTS = "o-ex:rights";
30 const char *STR_RO_CONTEXT = "o-ex:context";
31 const char *STR_RO_AGREEMENT = "o-ex:agreement";
32 const char *STR_RO_ASSET = "o-ex:asset";
33 const char *STR_RO_INHERIT = "o-ex:inherit";
34 const char *STR_RO_DIGEST = "o-ex:digest";
35 const char *STR_RO_KEYINFO = "ds:KeyInfo";
36 const char *STR_RO_PERMISSION = "o-ex:permission";
37 const char *STR_RO_ASSET_ID = "o-ex:id";
38 const char *STR_RO_ASSET_IDREF = "o-ex:idref";
39 const char *STR_RO_CONTEXT_ID = "o-dd:uid";
40 const char *STR_RO_CONTEXT_VERSION = "o-dd:version";
41 const char *STR_RO_DIGEST_VALUE = "ds:DigestValue";
42 const char *STR_RO_CIPHER_VALUE = "xenc:CipherValue";
43 const char *STR_RO_RETRIEVAL_METHOD = "ds:RetrievalMethod";
44 const char *STR_RO_PLAY = "o-dd:play";
45 const char *STR_RO_DISPLAY = "o-dd:display";
46 const char *STR_RO_EXECUTE = "o-dd:execute";
47 const char *STR_RO_PRINT = "o-dd:print";
48 const char *STR_RO_EXPORT = "o-dd:export";
49 const char *STR_RO_CONSTRAINT = "o-ex:constraint";
50 const char *STR_RO_COUNT = "o-dd:count";
51 const char *STR_RO_TIMEDCOUNT = "o-dd:timed-count";
52 const char *STR_RO_TIMER = "oma-dd:timer";
53 const char *STR_RO_INTERVAL = "o-dd:interval";
54 const char *STR_RO_DATETIME = "o-dd:datetime";
55 const char *STR_RO_START = "o-dd:start";
56 const char *STR_RO_END = "o-dd:end";
57 const char *STR_RO_ACCUMULATED = "o-dd:accumulated";
58 const char *STR_RO_INDIVIDUAL = "o-dd:individual";
59 const char *STR_RO_SYSTEM = "o-dd:system";
60
61 /** see Ro.h */
Ro()62 Ro::Ro()
63 {
64 mDoc = new XMLDocumentImpl();
65 mProperRight = NULL;
66 }
67
68 /** see Ro.h */
~Ro()69 Ro::~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 */
setRoID(string & id)91 void Ro::setRoID(string& id)
92 {
93 mRoID = id;
94 }
95
96 /** see Ro.h */
getRoID() const97 const string& Ro::getRoID() const
98 {
99 return mRoID;
100 }
101
102 /** see Ro.h */
setRoVersion(string & version)103 void Ro::setRoVersion(string& version)
104 {
105 mRoVersion = version;
106 }
107
108 /** see Ro.h */
addAsset(Asset * asset)109 void Ro::addAsset(Asset* asset)
110 {
111 mAssetList.push_back(asset);
112 }
113
114 /** see Ro.h */
addRight(Right * right)115 void Ro::addRight(Right* right)
116 {
117 mRightList.push_back(right);
118 }
119
120 /** see Ro.h */
save()121 bool Ro::save()
122 {
123 LOGI("==============Ro save.=================");
124
125 return true;
126 }
127
128 /** see Ro.h */
parse(istringstream * roStream)129 Ro::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 */
handleDocument(const XMLDocumentImpl * doc)151 bool 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 */
handleRights(const NodeImpl * curNode)161 bool 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 */
handleAgreement(const NodeImpl * curNode)209 bool 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 */
handleAsset(const NodeImpl * curNode)250 bool 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 */
handlePermission(const NodeImpl * curNode)353 bool 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 */
convertISO8601DateTimeToLong(const char * ts)442 long 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 */
convertISO8601PeriodToLong(const char * ts)461 long 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 */
getConstraint(const NodeImpl * curNode)475 Constraint* 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 */
loadRights(const string & contentID)546 void 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 */
freeRights()581 void Ro::freeRights()
582 {
583 mContentRightList.clear();
584 }
585
586 /** see Ro.h */
checkPermission(OperationPermission::OPERATION type,const string & contentID)587 bool 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 */
consume(OperationPermission::OPERATION type,const string & contentID)606 Ro::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 */
getContentCek(const string & contentID)804 string 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 */
getContentHash(const string & contentID)819 string 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