MHEG5  18.9.0
MHEG5 Documentation
mh5hash.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*---includes for this file--------------------------------------------------*/
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <openssl/evp.h>
30 
31 #include "mh5hash.h"
32 #include "mh5base.h"
33 #include "mh5memory.h"
34 #include "mh5fileorm.h"
35 #include "mh5sig.h"
36 #include "stb_os.h"
37 
38 /*---constant definitions for this file--------------------------------------*/
39 
40 #define GET_16BITS_FROM_ARRAY(X, Y) ((X[Y] << 8) | X[Y + 1])
41 
42 
43 /*---local typedef structs for this file-------------------------------------*/
44 typedef enum
45 {
55 
56 typedef enum
57 {
62 
63 typedef struct sHashDigest
64 {
70  struct sHashDigest *next;
71 } HashDigest;
72 
73 typedef struct sHashfileData
74 {
86 } HashfileData;
87 
88 
89 /*---local (static) variable declarations for this file----------------------*/
90 static void (*VerificationCallback)(void) = NULL;
91 static HashfileData *hashfileList = NULL;
92 static U8BIT noFile; /*dummy pointer to indicate a failed load*/
93 
94 /*---local function definitions----------------------------------------------*/
95 
96 /*---global function definitions---------------------------------------------*/
97 static U8BIT* GetHashfileUrl(const U8BIT *url);
98 static MHEG5Bool ReloadHashfile(HashfileData *hashfile);
99 static MHEG5Bool LoadHashfile(U8BIT *url);
100 static void HashLoadFailCallback( void *userData );
101 static void HashLoadedCallback( void *userData, S_CONTENT *content );
102 static void FreeDigestList(HashDigest *listStart);
103 static MHEG5Bool ParseHashfile(HashfileData *hashfile);
104 static HashfileData* FindHashInfo(U8BIT *url);
105 static HashDigest* FindDigestForUrl(U8BIT *url, HashfileData *hashfile);
106 static MHEG5Bool CheckUrlPath(U8BIT *url, HashfileData *hashfile);
107 static MHEG5Bool CheckHashes(U8BIT *content, U32BIT contentLength, HashDigest *digest);
108 static U8BIT* GetNextSigUrl(HashfileData *hashfile);
109 static void SigLoadedCallback( void *userData, S_CONTENT *content );
110 static void SigLoadFailCallback( void *userData );
111 static void VerifyHashfile(HashfileData *hashfile);
112 static MHEG5Bool LoadNextSignatureFile(HashfileData *hashfile);
113 static void CertCallback(void);
114 static MHEG5ContentVerification_t GetFailureStatus(HashfileData *hashFile);
115 static MHEG5ContentVerification_t VerifyUrl(U8BIT *url, U8BIT *content, U32BIT length, HashfileData *hashFile);
116 
117 
118 /***********************
119  * FUNCTION DEFINITIONS *
120  ***********************/
121 
128 void MHEG5SetVerificationCallback(void (*callback)(void))
129 {
130  VerificationCallback = callback;
131  MHEG5SetSigVerifyCallback(CertCallback);
132 }
133 
139 {
140  HashfileData *listEntry;
141  HashfileData *nextEntry;
143 
144  listEntry = hashfileList;
145  hashfileList = NULL;
146 
147  while (listEntry)
148  {
149  /*save the pointer to the next entry*/
150  nextEntry = listEntry->next;
151 
152  /*free any asociated data*/
153  if (listEntry->url != NULL)
154  {
155  MHEG5freeMem(listEntry->url);
156  }
157 
158  hashData = &listEntry->hashData;
159 
160  if (hashData->data != &noFile && hashData->data != NULL)
161  {
162  MHEG5freeMem(hashData->data);
163  }
164 
165  FreeDigestList(listEntry->digestList);
166  listEntry->digestList = NULL;
167  /*free memory of the entry*/
168  MHEG5freeMem(listEntry);
169 
170  /*go to the next entry*/
171  listEntry = nextEntry;
172  }
173 }
174 
185  U32BIT length)
186 {
187  HashfileData *hashFile = NULL;
189  MHEG5Bool success;
190  U8BIT *hashfileUrl;
191 
192  hashfileUrl = GetHashfileUrl(url);
193  if (hashfileUrl == NULL)
194  {
196  }
197 
198  hashFile = FindHashInfo(hashfileUrl);
199  if (hashFile != NULL)
200  {
201  switch (hashFile->state)
202  {
203  case HASH_FILE_RELOAD:
204  success = ReloadHashfile(hashFile);
205  if (success == MHEG5TRUE)
206  {
208  }
209  else
210  {
211  status = GetFailureStatus(hashFile);
212  }
213  break;
214 
219  case HASH_FILE_VERIFYING:
220 
222  break;
223 
224  case HASH_FILE_VERIFIED:
225  status = VerifyUrl(url, content, length, hashFile);
226  break;
227  case HASH_FILE_FAILED:
228  status = GetFailureStatus(hashFile);
229  break;
230  default:
231  status = CONTENT_NOT_VERIFIED_NEW;
232  assert(0);
233  }
234 
235  /*finished with the url string*/
236  MHEG5freeMem(hashfileUrl);
237  }
238  else
239  {
240  success = LoadHashfile(hashfileUrl);
241  if (success)
242  {
244  }
245  else
246  {
247  /*finished with the url string*/
248  MHEG5freeMem(hashfileUrl);
249 
250  status = CONTENT_NOT_VERIFIED_NEW;
251  }
252  }
253 
254  return status;
255 }
256 
261 static MHEG5ContentVerification_t GetFailureStatus(HashfileData *hashFile)
262 {
264  if (hashFile->sameAsPrevious)
265  {
266  status = CONTENT_NOT_VERIFIED_SAME;
267  }
268  else
269  {
270  status = CONTENT_NOT_VERIFIED_NEW;
271  }
272  return status;
273 }
274 
279 static MHEG5ContentVerification_t VerifyUrl(U8BIT *url, U8BIT *content, U32BIT length, HashfileData *hashFile)
280 {
281  MHEG5Bool success;
284 
285  success = MHEG5FALSE;
286  status = GetFailureStatus(hashFile); /*default to failure*/
287 
288  if (hashFile->digestCount == 0)
289  {
290  success = CheckUrlPath(url, hashFile);
291  if (success)
292  {
293  status = CONTENT_VERIFIED_UNSIGNED;
294  }
295  }
296  else
297  {
298  digest = FindDigestForUrl(url, hashFile);
299  if (digest != NULL)
300  {
301  success = CheckHashes(content, length, digest);
302  }
303  if (success)
304  {
305  status = CONTENT_VERIFIED_SIGNED;
306  }
307  }
308 
309  return status;
310 }
311 
317 static HashfileData* FindHashInfo(U8BIT *url)
318 {
319  HashfileData *listEntry;
320  int differ;
321 
322  /*look through the list of loaded files for the provided url*/
323  listEntry = hashfileList;
324 
325  while (listEntry != NULL)
326  {
327  differ = strcmp((char *)url, (char *)listEntry->url);
328  if (!differ)
329  {
330  break;
331  }
332  else
333  {
334  listEntry = listEntry->next;
335  }
336  }
337 
338  return listEntry;
339 }
340 
346 static U8BIT* GetHashfileUrl(const U8BIT *url)
347 {
348  U32BIT length;
349  U8BIT *slash;
350  U8BIT *hashfileUrl;
351  U8BIT *hashfileName = (U8BIT *)"auth.hash";
352  U32BIT hashfileNameLen = strlen((char *)hashfileName);
353 
354  slash = (U8BIT *)strrchr((char *)url, '/');
355  assert(slash != NULL);
356  length = slash - url + 1;
357 
358  hashfileUrl = MHEG5getMem(length + hashfileNameLen + 1);
359  if (hashfileUrl != NULL)
360  {
361  memcpy(hashfileUrl, url, length);
362  memcpy(hashfileUrl + length, hashfileName, hashfileNameLen);
363  hashfileUrl[length + hashfileNameLen] = '\0';
364  }
365  return hashfileUrl;
366 }
367 
374 static MHEG5Bool ReloadHashfile(HashfileData *hashfile)
375 {
376  MHEG5String hashName;
377  MHEG5Bool success;
378 
379  assert(hashfile);
380  hashName.data = hashfile->url;
381  hashName.len = strlen((char *)hashfile->url);
382 
384  (void)MHEG5FileOrmGet( hashName, FRP_HASH | FRP_CACHE_DEFAULT,
385  (void *)hashfile, HashLoadedCallback, HashLoadFailCallback );
386  hashfile->signatureIndex = 0;
387  success = LoadNextSignatureFile(hashfile);
388  if (!success)
389  {
390  if (hashfile->hashData.data == &noFile)
391  {
392  hashfile->sameAsPrevious = MHEG5TRUE;
393  }
394  else
395  {
396  hashfile->hashData.data = &noFile;
397  hashfile->sameAsPrevious = MHEG5FALSE;
398  }
399  hashfile->state = HASH_FILE_FAILED;
400  }
401  return success;
402 }
403 
410 static MHEG5Bool LoadHashfile(U8BIT *url)
411 {
412  HashfileData *listEntry;
413  MHEG5String hashName;
414  MHEG5Bool success;
415 
416  success = MHEG5FALSE;
417 
418 
419  listEntry = MHEG5getMem(sizeof(HashfileData));
420  if (listEntry != NULL)
421  {
422  listEntry->url = url;
423  listEntry->hashData.len = 0;
424  listEntry->hashData.data = NULL;
425  listEntry->state = HASH_FILE_WAITING_FOR_HASH;
426  listEntry->digestCount = 0;
427  listEntry->sameAsPrevious = MHEG5FALSE;
428 
429  listEntry->signatureIndex = 0;
430  listEntry->signature.len = 0;
431  listEntry->signature.data = NULL;
432 
433  listEntry->digestList = NULL;
434 
435  /*put the new entry at the start of the list*/
436  listEntry->next = hashfileList;
437  listEntry->previous = NULL;
438  hashfileList = listEntry;
439  hashfileList->previous = listEntry;
440 
441  /*request the file*/
442  hashName.data = url;
443  hashName.len = strlen((char *)url);
444 
446  (void)MHEG5FileOrmGet( hashName, FRP_HASH | FRP_CACHE_DEFAULT,
447  (void *)listEntry, HashLoadedCallback, HashLoadFailCallback);
448 
449  success = LoadNextSignatureFile(listEntry);
450  }
451 
452  return success;
453 }
454 
460 static void HashLoadedCallback( void *userData, S_CONTENT *content )
461 {
462  HashfileData *cacheHandle;
463  HashfileData *listEntry;
464  MHEG5String *currentFile;
465  MHEG5String fileBuffer;
466  MHEG5Bool success;
467  MHEG5Bool call;
468  int differ;
469 
470  cacheHandle = (HashfileData *)userData;
471  listEntry = hashfileList;
472 
473  call = MHEG5FALSE;
474 
475  while (listEntry != NULL)
476  {
477  if (listEntry == cacheHandle)
478  {
479  break;
480  }
481  listEntry = listEntry->next;
482  }
483 
484  if (listEntry != NULL)
485  {
486  currentFile = &cacheHandle->hashData;
487 
488  /*copy the data into a buffer*/
489  fileBuffer.data = MHEG5getMem(content->size);
490  if (fileBuffer.data != NULL)
491  {
492  memcpy(fileBuffer.data, content->data, content->size);
493  fileBuffer.len = content->size;
494 
495  if (fileBuffer.len != currentFile->len)
496  {
497  cacheHandle->sameAsPrevious = MHEG5FALSE;
498  }
499  else if (currentFile->data == NULL || currentFile->data == &noFile)
500  {
501  cacheHandle->sameAsPrevious = MHEG5FALSE;
502  }
503  else
504  {
505  differ = memcmp(fileBuffer.data, currentFile->data, content->size);
506  if (!differ)
507  {
508  cacheHandle->sameAsPrevious = MHEG5TRUE;
509  }
510  else
511  {
512  cacheHandle->sameAsPrevious = MHEG5FALSE;
513  }
514  }
515 
516  /*free any file already loaded and load new file*/
517  if (currentFile->data != NULL && currentFile->data != &noFile)
518  {
519  MHEG5freeMem(currentFile->data);
520 
521  /* Free digest list */
522  FreeDigestList(listEntry->digestList);
523  listEntry->digestList = NULL;
524  }
525 
526  currentFile->data = fileBuffer.data;
527  currentFile->len = fileBuffer.len;
528 
529  success = ParseHashfile(cacheHandle);
530  if (success)
531  {
532  if (cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
533  {
534  cacheHandle->state = HASH_FILE_WAITING_FOR_SIG;
535  }
536  else
537  {
538  assert(cacheHandle->state == HASH_FILE_WAITING_FOR_HASH);
539  VerifyHashfile(cacheHandle);
540  }
541  }
542  else
543  {
544  if (cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
545  {
546  cacheHandle->state = HASH_FILE_WAITING_FOR_SIG;
547  }
548  else
549  {
550  cacheHandle->state = HASH_FILE_FAILED;
551  call = MHEG5TRUE;
552  }
553  }
554  }
555  else
556  {
557  if (cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
558  {
559  cacheHandle->state = HASH_FILE_WAITING_FOR_SIG;
560  }
561  else
562  {
563  cacheHandle->state = HASH_FILE_FAILED;
564  call = MHEG5TRUE;
565  }
566  cacheHandle->hashData.len = 0;
567  if (cacheHandle->hashData.data != &noFile)
568  {
569  cacheHandle->hashData.data = &noFile;
570  cacheHandle->sameAsPrevious = MHEG5FALSE;
571  }
572  else
573  {
574  cacheHandle->sameAsPrevious = MHEG5TRUE;
575  }
576  }
577  }
578  /*call the provided callback if required*/
579  if (call && VerificationCallback != NULL)
580  {
581  VerificationCallback();
582  }
583 }
584 
590 static void HashLoadFailCallback( void *userData )
591 {
592  HashfileData *cacheHandle;
593  HashfileData *listEntry;
595  MHEG5Bool call;
596 
597  call = MHEG5FALSE;
598 
599  cacheHandle = (HashfileData *)userData;
600  /*first ensure that the cache is still available
601  it may have been reset while we were loading*/
602  listEntry = hashfileList;
603  while (listEntry != NULL)
604  {
605  if (listEntry == cacheHandle)
606  {
607  break;
608  }
609  listEntry = listEntry->next;
610  }
611 
612  if (listEntry != NULL)
613  {
614  /*free any file already loaded*/
615  hashData = &cacheHandle->hashData;
616 
617  if (hashData->data != NULL)
618  {
619  if (hashData->data == &noFile)
620  {
621  cacheHandle->sameAsPrevious = MHEG5TRUE;
622  }
623  else
624  {
625  MHEG5freeMem(hashData->data);
626  hashData->len = 0;
627  hashData->data = &noFile;
628  cacheHandle->sameAsPrevious = MHEG5FALSE;
629  }
630  }
631  else
632  {
633  hashData->len = 0;
634  hashData->data = &noFile;
635  cacheHandle->sameAsPrevious = MHEG5FALSE;
636  }
637 
638  if (cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
639  {
640  cacheHandle->state = HASH_FILE_WAITING_FOR_SIG;
641  }
642  else
643  {
644  cacheHandle->state = HASH_FILE_FAILED;
645  call = MHEG5TRUE;
646  }
647  }
648 
649  /*call the provided callback if there is one*/
650  if (call && VerificationCallback != NULL)
651  {
652  VerificationCallback();
653  }
654 }
655 
661 static MHEG5Bool ParseHashfile(HashfileData *hashfile)
662 {
663  U32BIT fileSize;
664  int i;
665  U8BIT *fileData;
666  U8BIT *dataEnd;
668  HashDigest *previousDigest;
669  MHEG5Bool success;
670  MHEG5Bool continueParsing;
671 
672  /*buffers*/
673  U16BIT nameCount;
674  U8BIT type;
676  U8BIT *name;
678  U8BIT *digest;
679 
680  if (hashfile != NULL && hashfile->hashData.data != &noFile)
681  {
682  fileSize = hashfile->hashData.len;
683  fileData = hashfile->hashData.data;
684  dataEnd = fileData + fileSize;
685 
686  /*free the digest list if it already exists*/
687  FreeDigestList(hashfile->digestList);
688  hashfile->digestList = NULL;
689  }
690  else
691  {
692  fileSize = 0;
693  }
694 
695  /*get the digest count*/
696  if (fileSize >= 2)
697  {
698  digestCount = GET_16BITS_FROM_ARRAY(fileData, 0);
699  fileData += 2;
700  success = MHEG5TRUE;
701  continueParsing = MHEG5TRUE;
702  }
703  else
704  {
705  success = MHEG5FALSE;
706  continueParsing = MHEG5FALSE;
707  }
708 
709  if (success)
710  {
711  /*if digest count is 0 then the file contains only a directory pathname*/
712  if (digestCount == 0)
713  {
714  if (fileData + 2 <= dataEnd) /*make sure we have enough data*/
715  {
716  hashfile->digestPathname.len = GET_16BITS_FROM_ARRAY(fileData, 0);
717  fileData += 2;
718  hashfile->digestPathname.data = fileData;
719  }
720  else
721  {
722  success = MHEG5FALSE;
723  }
724  }
725  else
726  {
727  /*digestCount > 0*/
728  digestLength = 0;
729  type = 0;
730  nameCount = 0;
731 
732  previousDigest = NULL;
733  for (i = 0; i < digestCount; i++)
734  {
735  if (continueParsing)
736  {
737  hashfile->digestList = MHEG5getMem(sizeof(HashDigest));
738  if (hashfile->digestList != NULL)
739  {
740  hashfile->digestList->next = previousDigest;
741  if (fileData + 1 <= dataEnd)
742  {
743  type = *fileData;
744  fileData++;
745 
746  switch (type)
747  {
748  case 0:
749  digestLength = 0;
750  break;
751  case 2:
752  digestLength = 20;
753  break;
754  case 3:
755  digestLength = 20;
756  break;
757  default:
758  continueParsing = MHEG5FALSE;
759  break;
760  }
761  }
762  else
763  {
764  continueParsing = MHEG5FALSE;
765  }
766  }
767  else
768  {
769  /*if there was an error allocating, save what we have*/
770  hashfile->digestList = previousDigest;
771  continueParsing = MHEG5FALSE;
772  }
773  }
774  if (continueParsing)
775  {
776  if (fileData + 2 <= dataEnd)
777  {
778  nameCount = GET_16BITS_FROM_ARRAY(fileData, 0);
779  fileData += 2;
780  }
781  else
782  {
783  continueParsing = MHEG5FALSE;
784  }
785  if (continueParsing && nameCount != 1)
786  {
787  continueParsing = MHEG5FALSE;
788  }
789  }
790 
791  if (continueParsing)
792  {
793  if (fileData + 1 <= dataEnd)
794  {
795  nameLength = *fileData;
796  fileData++;
797  }
798  else
799  {
800  continueParsing = MHEG5FALSE;
801  }
802  }
803 
804  if (continueParsing)
805  {
806  if (fileData + nameLength <= dataEnd)
807  {
808  name = fileData;
809  fileData += nameLength;
810  }
811  else
812  {
813  continueParsing = MHEG5FALSE;
814  }
815  }
816 
817  if (continueParsing)
818  {
819  if (fileData + digestLength <= dataEnd)
820  {
821  digest = fileData;
822  fileData += digestLength;
823  }
824  else
825  {
826  continueParsing = MHEG5FALSE;
827  }
828  }
829 
830  if (continueParsing)
831  {
832  hashfile->digestList->name = name;
833  hashfile->digestList->nameLength = nameLength;
834  hashfile->digestList->type = type;
835  hashfile->digestList->digestLength = digestLength;
836  hashfile->digestList->digest = digest;
837  previousDigest = hashfile->digestList;
838  }
839  }
840  }
841 
842  if (success)
843  {
844  hashfile->digestCount = digestCount;
845  }
846  }
847  return success;
848 }
849 
855 static void FreeDigestList(HashDigest *listStart)
856 {
857  HashDigest *current;
858  HashDigest *next;
859  current = listStart;
860  while (current != NULL)
861  {
862  next = current->next;
863  MHEG5freeMem(current);
864  current = next;
865  }
866 }
867 
875 {
876  HashfileData *hashfile;
877  U8BIT *hashfileUrl;
878 
879  hashfileUrl = GetHashfileUrl(url);
880  if (hashfileUrl != NULL)
881  {
882  hashfile = FindHashInfo(hashfileUrl);
883 
884  /*finished with the url string*/
885  MHEG5freeMem(hashfileUrl);
886 
887  if (hashfile != NULL)
888  {
889  if (hashfile->state == HASH_FILE_FAILED ||
890  hashfile->state == HASH_FILE_VERIFIED)
891  {
892  hashfile->state = HASH_FILE_RELOAD;
893  if (hashfile->signature.data)
894  {
895  MHEG5freeMem(hashfile->signature.data);
896  hashfile->signature.data = NULL;
897  hashfile->signature.len = 0;
898  }
899  hashfile->signatureIndex = 0;
900  }
901  else
902  {
903  assert(0);
904  }
905  }
906  }
907 }
908 
916 static HashDigest* FindDigestForUrl(U8BIT *url, HashfileData *hashfile)
917 {
918  U8BIT *name;
921  int differ;
922  digest = NULL;
923 
924  name = (U8BIT *)strrchr((char *)url, '/') + 1;
925  assert(name != NULL);
926  nameLength = strlen((char *)name);
927 
928  digest = hashfile->digestList;
929  while (digest != NULL)
930  {
931  if (nameLength == digest->nameLength)
932  {
933  differ = memcmp(name, digest->name, digest->nameLength);
934  if (!differ)
935  {
936  break;
937  }
938  }
939  digest = digest->next;
940  }
941 
942  return digest;
943 }
944 
952 static MHEG5Bool CheckUrlPath(U8BIT *url, HashfileData *hashfile)
953 {
954  U16BIT urlDirectoryLength;
955  U8BIT *hashDirectory;
956  U16BIT hashDirectoryLength;
957  MHEG5Bool success;
958  U8BIT *slash;
959  int differ;
960 
961  success = MHEG5TRUE;
962 
963  if (hashfile->digestCount != 0)
964  {
965  success = MHEG5FALSE;
966  }
967 
968  if (success)
969  {
970  slash = (U8BIT *)strrchr((char *)url, '/');
971  urlDirectoryLength = slash - url;
972  hashDirectoryLength = (U16BIT)hashfile->digestPathname.len;
973  hashDirectory = hashfile->digestPathname.data;
974 
975  if (hashDirectoryLength == 0 || hashDirectoryLength > urlDirectoryLength)
976  {
977  success = MHEG5FALSE;
978  }
979  }
980  if (success)
981  {
982  differ = MHEG5strncmp(hashDirectory, url, hashDirectoryLength );
983  if (differ)
984  {
985  success = MHEG5FALSE;
986  }
987  }
988  if (success)
989  {
990  if (hashDirectory[hashDirectoryLength - 1] != '/' &&
991  url[hashDirectoryLength] != '/')
992  {
993  success = MHEG5FALSE;
994  }
995  }
996 
997  return success;
998 }
999 
1008 static MHEG5Bool CheckHashes(U8BIT *content, U32BIT contentLength, HashDigest *digest)
1009 {
1010  EVP_MD_CTX ctx;
1011  MHEG5Bool success;
1012  U8BIT contentDigest[EVP_MAX_MD_SIZE];
1013  U8BIT prefix[8];
1014  int differ;
1015  int digestSize;
1016 
1017  switch (digest->type)
1018  {
1019  case 0:
1020  success = MHEG5TRUE;
1021  break;
1022  case 2:
1023  /*type 2 is a straightforward hash-compare*/
1024 
1025  /*create the digest*/
1026  EVP_DigestInit(&ctx, EVP_sha1());
1027  EVP_DigestUpdate(&ctx, content, contentLength);
1028  digestSize = EVP_MD_CTX_size(&ctx);
1029  EVP_DigestFinal(&ctx, contentDigest, NULL);
1030 
1031  /*byte-compare it with the digest from the hashfile*/
1032  differ = memcmp(contentDigest, digest->digest, digestSize);
1033  if (!differ)
1034  {
1035  success = MHEG5TRUE;
1036  }
1037  else
1038  {
1039  success = MHEG5FALSE;
1040  }
1041  break;
1042 
1043  case 3:
1044 
1045  /*type 3 requires an 8 byte prefix*/
1046  /*1 in 32bit msbf form*/
1047  prefix[0] = 0;
1048  prefix[1] = 0;
1049  prefix[2] = 0;
1050  prefix[3] = 1;
1051 
1052  /*content length in 32bit msbf form*/
1053  prefix[4] = (U8BIT)(contentLength >> 24);
1054  prefix[5] = (U8BIT)(contentLength >> 16);
1055  prefix[6] = (U8BIT)(contentLength >> 8);
1056  prefix[7] = (U8BIT)contentLength;
1057 
1058  /*create the digest of the prefixed content*/
1059  EVP_DigestInit(&ctx, EVP_sha1());
1060  EVP_DigestUpdate(&ctx, prefix, 8);
1061  EVP_DigestUpdate(&ctx, content, contentLength);
1062  digestSize = EVP_MD_CTX_size(&ctx);
1063  EVP_DigestFinal(&ctx, contentDigest, NULL);
1064 
1065  /*byte-compare it with the digest from the hashfile*/
1066  differ = memcmp(contentDigest, digest->digest, digestSize);
1067  if (!differ)
1068  {
1069  success = MHEG5TRUE;
1070  }
1071  else
1072  {
1073  success = MHEG5FALSE;
1074  }
1075  break;
1076 
1077  default:
1078  success = MHEG5FALSE;
1079  }
1080  return success;
1081 }
1082 
1087 static void SigLoadFailCallback( void *userData )
1088 {
1089  HashfileData *cacheHandle;
1090  HashfileData *listEntry;
1091  MHEG5Bool call;
1092 
1093  cacheHandle = (HashfileData *)userData;
1094  listEntry = hashfileList;
1095 
1096  call = MHEG5FALSE;
1097  while (listEntry != NULL)
1098  {
1099  if (listEntry == cacheHandle)
1100  {
1101  break;
1102  }
1103  listEntry = listEntry->next;
1104  }
1105  if (listEntry != NULL)
1106  {
1107  call = MHEG5TRUE;
1108  if (listEntry->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
1109  {
1110  listEntry->state = HASH_FILE_WAITING_FOR_HASH;
1111  }
1112  else
1113  {
1114  assert(listEntry->state == HASH_FILE_WAITING_FOR_SIG);
1115  listEntry->state = HASH_FILE_FAILED;
1116  }
1117  }
1118 
1119  /*call the provided callback if there is one*/
1120  if (call && VerificationCallback)
1121  {
1122  VerificationCallback();
1123  }
1124 }
1125 
1130 static void SigLoadedCallback(void *userData, S_CONTENT *content )
1131 {
1132  HashfileData *cacheHandle;
1133  HashfileData *listEntry;
1134  MHEG5String *currentFile;
1135  MHEG5Bool call;
1136 
1137  cacheHandle = (HashfileData *)userData;
1138  listEntry = hashfileList;
1139 
1140  call = MHEG5FALSE;
1141  while (listEntry != NULL)
1142  {
1143  if (listEntry == cacheHandle)
1144  {
1145  break;
1146  }
1147  listEntry = listEntry->next;
1148  }
1149 
1150  if (listEntry != NULL)
1151  {
1152  currentFile = &cacheHandle->signature;
1153 
1154  /*free any file already loaded*/
1155  if (currentFile->data)
1156  {
1157  MHEG5freeMem(currentFile->data);
1158  currentFile->data = NULL;
1159  }
1160 
1161  /*copy the data into cache*/
1162  currentFile->data = MHEG5getMem(content->size);
1163  if (currentFile->data != NULL)
1164  {
1165  currentFile->len = content->size;
1166  memcpy(currentFile->data, content->data, content->size);
1167 
1168  if (cacheHandle->state == HASH_FILE_WAITING_FOR_SIG)
1169  {
1170  VerifyHashfile(cacheHandle);
1171  call = MHEG5TRUE;
1172  }
1173  else
1174  {
1175  assert(cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG);
1176  cacheHandle->state = HASH_FILE_WAITING_FOR_HASH;
1177  }
1178  }
1179  else
1180  {
1181  currentFile->len = 0;
1182  if (cacheHandle->state == HASH_FILE_WAITING_FOR_HASH_AND_SIG)
1183  {
1184  cacheHandle->state = HASH_FILE_WAITING_FOR_HASH;
1185  }
1186  else
1187  {
1188  cacheHandle->state = HASH_FILE_FAILED;
1189  call = MHEG5TRUE;
1190  }
1191  }
1192  }
1193  /*call the provided callback if there is one*/
1194  if (call && VerificationCallback)
1195  {
1196  VerificationCallback();
1197  }
1198 }
1199 
1205 static void VerifyHashfile(HashfileData *hashfile)
1206 {
1207  MHEG5SigVerifyStatus_t status;
1208 
1209  if ((hashfile->signature.data != NULL) &&
1210  (hashfile->hashData.data != &noFile))
1211  {
1212  status = MHEG5IsValidSignature(&hashfile->hashData, &hashfile->signature);
1213  switch (status)
1214  {
1215  case MHEG5_SIG_VERIFIED:
1216  hashfile->state = HASH_FILE_VERIFIED;
1217  if (VerificationCallback)
1218  {
1219  VerificationCallback();
1220  }
1221  break;
1223  hashfile->state = HASH_FILE_WAITING_FOR_SIG;
1224  LoadNextSignatureFile(hashfile);
1225  break;
1227  hashfile->state = HASH_FILE_WAITING_FOR_CERT;
1228  break;
1229  default:
1230  assert(0);
1231  }
1232  }
1233  else
1234  {
1235  /* Something wrong with signature or hash file */
1236  hashfile->state = HASH_FILE_FAILED;
1237  }
1238 }
1239 
1245 static MHEG5Bool LoadNextSignatureFile(HashfileData *hashfile)
1246 {
1247  U8BIT *sigUrl;
1248  MHEG5String sigName;
1249  MHEG5Bool success;
1250 
1251  success = MHEG5FALSE;
1252 
1253  sigUrl = GetNextSigUrl(hashfile);
1254  if (sigUrl)
1255  {
1256  sigName.data = sigUrl;
1257  sigName.len = strlen((char *)sigUrl);
1258  (void)MHEG5FileOrmGet( sigName, FRP_HASH | FRP_CACHE_DEFAULT,
1259  (void *)hashfile, SigLoadedCallback, SigLoadFailCallback );
1260 
1261  MHEG5freeMem(sigUrl);
1262  if (hashfile->state == HASH_FILE_FAILED)
1263  {
1264  success = MHEG5FALSE;
1265  }
1266  else
1267  {
1268  success = MHEG5TRUE;
1269  }
1270  }
1271 
1272  return success;
1273 }
1274 
1281 static U8BIT* GetNextSigUrl(HashfileData *hashfile)
1282 {
1283  U32BIT length;
1284  U8BIT *slash;
1285  U8BIT *sigUrl;
1286  U8BIT *sigName;
1287  U32BIT sigNameLen;
1288 
1289  sigName = (U8BIT *)"auth.sig.";
1290  sigNameLen = strlen((char *)sigName);
1291 
1292  slash = (U8BIT *)strrchr((char *)hashfile->url, '/');
1293  assert(slash != NULL);
1294  length = slash - hashfile->url + 1;
1295 
1296  sigUrl = MHEG5getMem(length + sigNameLen + 7);
1297  if (sigUrl != NULL)
1298  {
1299  memcpy(sigUrl, hashfile->url, length);
1300  memcpy(sigUrl + length, sigName, sigNameLen);
1301 
1302  hashfile->signatureIndex++;
1303 
1304  sprintf((char *)(sigUrl + length + sigNameLen), "%u", (unsigned int)hashfile->signatureIndex);
1305  }
1306  return sigUrl;
1307 }
1308 
1316 static void CertCallback(void)
1317 {
1318  HashfileData *cacheEntry;
1319 
1320  cacheEntry = hashfileList;
1321  while (cacheEntry != NULL)
1322  {
1323  if (cacheEntry->state == HASH_FILE_WAITING_FOR_CERT)
1324  {
1325  VerifyHashfile(cacheEntry);
1326  }
1327  cacheEntry = cacheEntry->next;
1328  }
1329 }
1330 
U8BIT digestLength
Definition: mh5hash.c:68
U8BIT * digest
Definition: mh5hash.c:69
Basis MHEG5 data types.
HashFileState_t
Definition: mh5hash.c:44
Functions relating to HTTPS Signature Certificates.
U32BIT size
Definition: fs_types.h:54
U32BIT signatureIndex
Definition: mh5hash.c:79
U16BIT digestCount
Definition: mh5hash.c:81
struct sHashfileData * next
Definition: mh5hash.c:84
void MHEG5ResetVerification(void)
Reset the state of the verification subsystem.
Definition: mh5hash.c:138
void MHEG5SetVerificationCallback(void(*callback)(void))
Register a callback to be fired when the state of the verification file changes.
Definition: mh5hash.c:128
U8BIT type
Definition: mh5hash.c:65
MHEG5String hashData
Definition: mh5hash.c:76
MHEG5Bool sameAsPrevious
Definition: mh5hash.c:78
void MHEG5ResetHashFile(U8BIT *url)
Reset the state and clear cache of the hashfile associated with a content file.
Definition: mh5hash.c:874
struct sHashDigest * next
Definition: mh5hash.c:70
#define MHEG5getMem
Definition: glue_memory.h:93
MHEG5ContentVerification_t MHEG5IsContentVerified(U8BIT *url, U8BIT *content, U32BIT length)
Definition: mh5hash.c:184
void * MHEG5FileOrmGet(MHEG5String name, U16BIT priority, void *userData, F_CB_Good cbGood, F_CB_Fail cbFail)
Get a file. The file will be loaded and one of the callback functions called when request is resolved...
Definition: mh5fileorm.c:1179
HashDigest * digestList
Definition: mh5hash.c:83
#define FRP_CACHE_DEFAULT
Definition: mh5fileorm.h:38
MHEG5String signature
Definition: mh5hash.c:80
U8BIT nameLength
Definition: mh5hash.c:66
uint8_t U8BIT
Definition: techtype.h:82
#define MHEG5freeMem
Definition: glue_memory.h:94
RequestState_t
Definition: mh5hash.c:56
U8BIT * url
Definition: mh5hash.c:75
struct sHashfileData HashfileData
short MHEG5Bool
Definition: mh5base.h:71
HashFileState_t state
Definition: mh5hash.c:77
Functions relating to HTTPS Content Verification.
MHEG5SigVerifyStatus_t MHEG5IsValidSignature(MHEG5String *hash, MHEG5String *signature)
Check whether the signature is valid.
Definition: mh5sig.c:181
MHEG5Byte * data
Definition: mh5base.h:85
struct sHashDigest HashDigest
#define MHEG5TRUE
Definition: mh5base.h:49
struct sHashfileData * previous
Definition: mh5hash.c:85
#define MHEG5strncmp(a, b, n)
Definition: mh5base.h:52
Definition: mh5hash.c:58
uint16_t U16BIT
Definition: techtype.h:84
File interface functions to DSMCC component.
redirection include
#define GET_16BITS_FROM_ARRAY(X, Y)
Definition: mh5hash.c:40
U8BIT * name
Definition: mh5hash.c:67
MHEG5SigVerifyStatus_t
Definition: mh5sig.h:37
void MHEG5SetSigVerifyCallback(void(*callback)(void))
Sets the callback to be called when pending requests are resolved.
Definition: mh5sig.c:290
#define FRP_HASH
Definition: mh5fileorm.h:45
MHEG5Int len
Definition: mh5base.h:84
MHEG5String digestPathname
Definition: mh5hash.c:82
U8BIT * data
Definition: fs_types.h:55
MHEG5ContentVerification_t
Definition: mh5hash.h:37
#define MHEG5FALSE
Definition: mh5base.h:48
uint32_t U32BIT
Definition: techtype.h:86
Header file - Function prototypes for operating system.