• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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