Changeset 74747 in vbox for trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
- Timestamp:
- Oct 10, 2018 3:26:04 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
r74746 r74747 61 61 #include <iprt/asm.h> 62 62 #include <iprt/assert.h> 63 #include <iprt/base64.h> 64 #include <iprt/ctype.h> 63 65 #include <iprt/err.h> 64 66 #include <iprt/log.h> … … 4393 4395 * white-space, but right now let just make sure it's xml and get the 4394 4396 * data in the cdhashes array. 4397 * 4398 * @todo The code here is a little braindead and bulky. It should be 4399 * possible to describe the expected XML structure using a tables. 4395 4400 */ 4396 4401 static int rtldrMachO_VerifySignatureValidateCdHashesPlist(PRTLDRMACHOSIGNATURE pSignature, char *pszPlist, … … 4398 4403 { 4399 4404 const char * const pszStart = pszPlist; 4400 #define CHECK_ AND_SKIP_OR_RETURN(a_szLead) \4405 #define CHECK_ISTR_AND_SKIP_OR_RETURN(a_szLead) \ 4401 4406 do { \ 4402 4407 if (!RTStrNICmp(pszPlist, RT_STR_TUPLE(a_szLead))) \ … … 4405 4410 "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \ 4406 4411 } while (0) 4407 #define CHECK_ CASE_AND_SKIP_OR_RETURN(a_szLead) \4412 #define CHECK_STR_AND_SKIP_OR_RETURN(a_szLead) \ 4408 4413 do { \ 4409 4414 if (!RTStrNCmp(pszPlist, RT_STR_TUPLE(a_szLead))) \ … … 4412 4417 "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \ 4413 4418 } while (0) 4419 #define SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN() \ 4420 do { /* currently only permitting spaces, tabs and newline, following char must be '<'. */ \ 4421 char ch; \ 4422 while ((ch = *pszPlist) == ' ' || ch == '\n' || ch == '\t') \ 4423 pszPlist++; \ 4424 if (ch == '<') { /* likely */ } \ 4425 else return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, \ 4426 "Expected '<' found '%.16s...' at %#zu in plist", pszPlist, pszPlist - pszStart); \ 4427 } while (0) 4428 #define SKIP_SPACE_BEFORE_VALUE() \ 4429 do { /* currently only permitting spaces, tabs and newline. */ \ 4430 char ch; \ 4431 while ((ch = *pszPlist) == ' ' || ch == '\n' || ch == '\t') \ 4432 pszPlist++; \ 4433 } while (0) 4434 #define SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN() \ 4435 do { /* currently only permitting a single space */ \ 4436 if (pszPlist[0] == ' ' && pszPlist[1] != ' ') \ 4437 pszPlist++; \ 4438 else return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, \ 4439 "Expected ' ' found '%.16s...' at %#zu in plist", pszPlist, pszPlist - pszStart); \ 4440 } while (0) 4441 4442 /* Example: 4443 <?xml version="1.0" encoding="UTF-8"?> 4444 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 4445 <plist version="1.0"> 4446 <dict> 4447 <key>cdhashes</key> 4448 <array> 4449 <data> 4450 hul2SSkDQFRXbGlt3AmCp25MU0Y= 4451 </data> 4452 <data> 4453 N0kvxg0CJBNuZTq135PntAaRczw= 4454 </data> 4455 </array> 4456 </dict> 4457 </plist> 4458 */ 4414 4459 4415 4460 /* <?xml version="1.0" encoding="UTF-8"?> */ 4416 CHECK_CASE_AND_SKIP_OR_RETURN("<?xml"); 4417 RT_NOREF(pSignature, pbHash, cbHash); 4418 return VERR_NOT_IMPLEMENTED; 4461 CHECK_STR_AND_SKIP_OR_RETURN("<?xml"); 4462 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4463 CHECK_STR_AND_SKIP_OR_RETURN("version=\"1.0\""); 4464 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4465 CHECK_STR_AND_SKIP_OR_RETURN("encoding=\"UTF-8\""); 4466 CHECK_STR_AND_SKIP_OR_RETURN("?>"); 4467 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4468 4469 /* <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> */ 4470 CHECK_STR_AND_SKIP_OR_RETURN("<!DOCTYPE"); 4471 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4472 CHECK_STR_AND_SKIP_OR_RETURN("plist"); 4473 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4474 CHECK_STR_AND_SKIP_OR_RETURN("PUBLIC"); 4475 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4476 CHECK_STR_AND_SKIP_OR_RETURN("\"-//Apple//DTD PLIST 1.0//EN\""); 4477 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4478 CHECK_STR_AND_SKIP_OR_RETURN("\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\""); 4479 CHECK_STR_AND_SKIP_OR_RETURN(">"); 4480 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4481 4482 /* <plist version="1.0"> */ 4483 CHECK_STR_AND_SKIP_OR_RETURN("<plist"); 4484 SKIP_REQUIRED_SPACE_BETWEEN_ATTRIBUTES_OR_RETURN(); 4485 CHECK_STR_AND_SKIP_OR_RETURN("version=\"1.0\""); 4486 CHECK_STR_AND_SKIP_OR_RETURN(">"); 4487 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4488 4489 /* <dict> */ 4490 CHECK_STR_AND_SKIP_OR_RETURN("<dict>"); 4491 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4492 4493 /* <key>cdhashes</key> */ 4494 CHECK_STR_AND_SKIP_OR_RETURN("<key>cdhashes</key>"); 4495 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4496 4497 /* <array> */ 4498 CHECK_STR_AND_SKIP_OR_RETURN("<array>"); 4499 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4500 4501 /* 4502 * Repeated: <data>hul2SSkDQFRXbGlt3AmCp25MU0Y=</data> 4503 */ 4504 uint32_t iCodeDir = 0; 4505 for (;;) 4506 { 4507 /* Decode the binary data (base64) and skip it. */ 4508 CHECK_STR_AND_SKIP_OR_RETURN("<data>"); 4509 SKIP_SPACE_BEFORE_VALUE(); 4510 4511 char ch; 4512 size_t cchBase64 = 0; 4513 while (RT_C_IS_ALNUM(ch = pszPlist[cchBase64]) || ch == '+' || ch == '/' || ch == '=') 4514 cchBase64++; 4515 size_t cbActualHash = cbHash; 4516 char *pszEnd = NULL; 4517 int rc = RTBase64DecodeEx(pszPlist, cchBase64, pbHash, cbHash, &cbActualHash, &pszEnd); 4518 if (RT_FAILURE(rc)) 4519 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4520 "Failed to decode hash #%u in authenticated plist attribute: %Rrc (%.*s)", 4521 iCodeDir, rc, cchBase64, pszPlist); 4522 pszPlist += cchBase64; 4523 AssertReturn(pszPlist == pszEnd, VERR_INTERNAL_ERROR_2); 4524 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4525 4526 /* The binary hash data must be exactly the size of SHA1, larger 4527 hash like SHA-256 and SHA-384 are truncated for some reason. */ 4528 if (cbActualHash != RTSHA1_HASH_SIZE) 4529 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4530 "Hash #%u in authenticated plist attribute has the wrong length: %u, exepcted %u", 4531 iCodeDir, cbActualHash, RTSHA1_HASH_SIZE); 4532 4533 /* Skip closing tag. */ 4534 CHECK_STR_AND_SKIP_OR_RETURN("</data>"); 4535 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4536 4537 4538 /* Calculate the hash and compare. */ 4539 RTCRDIGEST hDigest; 4540 rc = RTCrDigestCreateByType(&hDigest, pSignature->aCodeDirs[iCodeDir].enmDigest); 4541 if (RT_SUCCESS(rc)) 4542 { 4543 rc = RTCrDigestUpdate(hDigest, pSignature->aCodeDirs[iCodeDir].pCodeDir, pSignature->aCodeDirs[iCodeDir].cb); 4544 if (RT_SUCCESS(rc)) 4545 { 4546 if (memcmp(pbHash, RTCrDigestGetHash(hDigest), cbActualHash) == 0) 4547 rc = VINF_SUCCESS; 4548 else 4549 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_IMAGE_HASH_MISMATCH, 4550 "Code directory #%u hash mismatch (plist):\n" 4551 "signed: %.*Rhxs\n" 4552 "our: %.*Rhxs\n", 4553 cbActualHash, pbHash, 4554 RTCrDigestGetHashSize(hDigest), RTCrDigestGetHash(hDigest)); 4555 } 4556 else 4557 rc = RTErrInfoSetF(pErrInfo, rc, "RTCrDigestUpdate failed: %Rrc", rc); 4558 RTCrDigestRelease(hDigest); 4559 } 4560 else 4561 rc = RTErrInfoSetF(pErrInfo, rc, "Failed to create a digest of type %u verifying code dir #%u: %Rrc", 4562 pSignature->aCodeDirs[iCodeDir].enmDigest, iCodeDir, rc); 4563 if (RT_FAILURE(rc)) 4564 return rc; 4565 4566 /* 4567 * Advance. 4568 */ 4569 iCodeDir++; 4570 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4571 if (RTStrNCmp(pszPlist, RT_STR_TUPLE("<data>")) == 0) 4572 { 4573 if (iCodeDir >= pSignature->cCodeDirs) 4574 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4575 "Authenticated plist attribute has too many code directories (%u in blob)", 4576 pSignature->cCodeDirs); 4577 } 4578 else if (iCodeDir == pSignature->cCodeDirs) 4579 break; 4580 else 4581 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4582 "Authenticated plist attribute does not include all code directors: %u out of %u", 4583 iCodeDir, pSignature->cCodeDirs); 4584 } 4585 4586 /*</array>*/ 4587 CHECK_STR_AND_SKIP_OR_RETURN("</array>"); 4588 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4589 4590 /*</dict>*/ 4591 CHECK_STR_AND_SKIP_OR_RETURN("</dict>"); 4592 SKIP_SPACE_BETWEEN_ELEMENTS_OR_RETURN(); 4593 4594 /*</plist>*/ 4595 CHECK_STR_AND_SKIP_OR_RETURN("</plist>"); 4596 SKIP_SPACE_BEFORE_VALUE(); 4597 4598 if (*pszPlist == '\0') 4599 return VINF_SUCCESS; 4600 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4601 "Authenticated plist attribute has unexpected trailing content: %.32s", pszPlist); 4419 4602 } 4420 4603 … … 4458 4641 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv, 4459 4642 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb)) 4460 r eturnRTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH,4461 4462 4463 4464 4465 4466 4643 rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, 4644 "Authenticated message-digest attribute mismatch:\n" 4645 "signed: %.*Rhxs\n" 4646 "our: %.*Rhxs\n", 4647 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb, 4648 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv, 4649 RTCrDigestGetHashSize(hDigest), RTCrDigestGetHash(hDigest)); 4467 4650 } 4468 4651 else 4469 4652 rc = RTErrInfoSetF(pErrInfo, rc, "RTCrDigestUpdate failed: %Rrc", rc); 4653 RTCrDigestRelease(hDigest); 4470 4654 } 4471 4655 else
Note:
See TracChangeset
for help on using the changeset viewer.