VirtualBox

Ignore:
Timestamp:
Oct 10, 2018 3:26:04 PM (6 years ago)
Author:
vboxsync
Message:

IPRT/ldr: More Mach-O signing hacking. bugref:9232

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp

    r74746 r74747  
    6161#include <iprt/asm.h>
    6262#include <iprt/assert.h>
     63#include <iprt/base64.h>
     64#include <iprt/ctype.h>
    6365#include <iprt/err.h>
    6466#include <iprt/log.h>
     
    43934395 *          white-space, but right now let just make sure it's xml and get the
    43944396 *          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.
    43954400 */
    43964401static int rtldrMachO_VerifySignatureValidateCdHashesPlist(PRTLDRMACHOSIGNATURE pSignature, char *pszPlist,
     
    43984403{
    43994404    const char * const pszStart = pszPlist;
    4400 #define CHECK_AND_SKIP_OR_RETURN(a_szLead) \
     4405#define CHECK_ISTR_AND_SKIP_OR_RETURN(a_szLead) \
    44014406    do { \
    44024407        if (!RTStrNICmp(pszPlist, RT_STR_TUPLE(a_szLead))) \
     
    44054410                                  "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \
    44064411    } while (0)
    4407 #define CHECK_CASE_AND_SKIP_OR_RETURN(a_szLead) \
     4412#define CHECK_STR_AND_SKIP_OR_RETURN(a_szLead) \
    44084413    do { \
    44094414        if (!RTStrNCmp(pszPlist, RT_STR_TUPLE(a_szLead))) \
     
    44124417                                  "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \
    44134418    } 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    */
    44144459
    44154460    /* <?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);
    44194602}
    44204603
     
    44584641                                             pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv,
    44594642                                             pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb))
    4460                             return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH,
    4461                                                  "Authenticated message-digest attribute mismatch:\n"
    4462                                                  "signed: %.*Rhxs\n"
    4463                                                  "our:    %.*Rhxs\n",
    4464                                                  pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb,
    4465                                                  pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv,
    4466                                                  RTCrDigestGetHashSize(hDigest), RTCrDigestGetHash(hDigest));
     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));
    44674650                    }
    44684651                    else
    44694652                        rc = RTErrInfoSetF(pErrInfo, rc, "RTCrDigestUpdate failed: %Rrc", rc);
     4653                    RTCrDigestRelease(hDigest);
    44704654                }
    44714655                else
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette