+ *new_blob_addr_p = new_blob_addr;
+ *new_blob_size_p = new_blob_size;
+ *new_cd_p = new_cd;
+
+ return 0;
+}
+
+static int
+ubc_cs_convert_to_multilevel_hash(struct cs_blob *blob)
+{
+ const CS_CodeDirectory *old_cd, *cd;
+ CS_CodeDirectory *new_cd;
+ const CS_GenericBlob *entitlements;
+ vm_offset_t new_blob_addr;
+ vm_size_t new_blob_size;
+ vm_size_t new_cdsize;
+ int error;
+
+ uint32_t hashes_per_new_hash_shift = (uint32_t)(PAGE_SHIFT - blob->csb_hash_pageshift);
+
+ if (cs_debug > 1) {
+ printf("CODE SIGNING: Attempting to convert Code Directory for %lu -> %lu page shift\n",
+ (unsigned long)blob->csb_hash_pageshift, (unsigned long)PAGE_SHIFT);
+ }
+
+ old_cd = blob->csb_cd;
+
+ /* Up to the hashes, we can copy all data */
+ new_cdsize = ntohl(old_cd->hashOffset);
+ new_cdsize += (ntohl(old_cd->nCodeSlots) >> hashes_per_new_hash_shift) * old_cd->hashSize;
+
+ error = ubc_cs_reconstitute_code_signature(blob, new_cdsize,
+ &new_blob_addr, &new_blob_size, &new_cd,
+ &entitlements);
+ if (error != 0) {
+ printf("CODE SIGNING: Failed to reconsitute code signature: %d\n", error);
+ return error;
+ }
+
+ memcpy(new_cd, old_cd, ntohl(old_cd->hashOffset));
+
+ /* Update fields in the Code Directory structure */
+ new_cd->length = htonl((uint32_t)new_cdsize);
+
+ uint32_t nCodeSlots = ntohl(new_cd->nCodeSlots);
+ nCodeSlots >>= hashes_per_new_hash_shift;
+ new_cd->nCodeSlots = htonl(nCodeSlots);
+
+ new_cd->pageSize = PAGE_SHIFT; /* Not byte-swapped */
+
+ if ((ntohl(new_cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(new_cd->scatterOffset))) {
+ SC_Scatter *scatter = (SC_Scatter*)
+ ((char *)new_cd + ntohl(new_cd->scatterOffset));
+ /* iterate all scatter structs to scale their counts */
+ do {
+ uint32_t scount = ntohl(scatter->count);
+ uint32_t sbase = ntohl(scatter->base);
+
+ /* last scatter? */
+ if (scount == 0) {
+ break;
+ }
+
+ scount >>= hashes_per_new_hash_shift;
+ scatter->count = htonl(scount);
+
+ sbase >>= hashes_per_new_hash_shift;
+ scatter->base = htonl(sbase);
+
+ scatter++;
+ } while(1);
+ }
+
+ /* For each group of hashes, hash them together */
+ const unsigned char *src_base = (const unsigned char *)old_cd + ntohl(old_cd->hashOffset);
+ unsigned char *dst_base = (unsigned char *)new_cd + ntohl(new_cd->hashOffset);
+
+ uint32_t hash_index;
+ for (hash_index = 0; hash_index < nCodeSlots; hash_index++) {
+ union cs_hash_union mdctx;
+
+ uint32_t source_hash_len = old_cd->hashSize << hashes_per_new_hash_shift;
+ const unsigned char *src = src_base + hash_index * source_hash_len;
+ unsigned char *dst = dst_base + hash_index * new_cd->hashSize;
+
+ blob->csb_hashtype->cs_init(&mdctx);
+ blob->csb_hashtype->cs_update(&mdctx, src, source_hash_len);
+ blob->csb_hashtype->cs_final(dst, &mdctx);
+ }
+
+ error = cs_validate_csblob((const uint8_t *)new_blob_addr, new_blob_size, &cd, &entitlements);
+ if (error != 0) {
+
+ printf("CODE SIGNING: Failed to validate new Code Signing Blob: %d\n",
+ error);
+
+ ubc_cs_blob_deallocate(new_blob_addr, new_blob_size);
+ return error;
+ }
+
+ /* New Code Directory is ready for use, swap it out in the blob structure */
+ ubc_cs_blob_deallocate(blob->csb_mem_kaddr, blob->csb_mem_size);
+
+ blob->csb_mem_size = new_blob_size;
+ blob->csb_mem_kaddr = new_blob_addr;
+ blob->csb_cd = cd;
+ blob->csb_entitlements_blob = entitlements;
+
+ /* The blob has some cached attributes of the Code Directory, so update those */
+
+ blob->csb_hash_firstlevel_pagesize = blob->csb_hash_pagesize; /* Save the original page size */
+
+ blob->csb_hash_pagesize = PAGE_SIZE;
+ blob->csb_hash_pagemask = PAGE_MASK;
+ blob->csb_hash_pageshift = PAGE_SHIFT;
+ blob->csb_end_offset = ntohl(cd->codeLimit);
+ if((ntohl(cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(cd->scatterOffset))) {
+ const SC_Scatter *scatter = (const SC_Scatter*)
+ ((const char*)cd + ntohl(cd->scatterOffset));
+ blob->csb_start_offset = ((off_t)ntohl(scatter->base)) * PAGE_SIZE;
+ } else {
+ blob->csb_start_offset = 0;
+ }
+
+ return 0;