void CWriteNodeBase::write(IFileIOStream *out, CRC32 *crc) { if (isLeaf() && (keyType & HTREE_COMPRESSED_KEY)) lzwcomp.close(); assertex(hdr.keyBytes<=maxBytes); writeHdr(); assertex(fpos); out->seek(fpos, IFSbegin); out->write(keyHdr->getNodeSize(), nodeBuf); if (crc) crc->tally(keyHdr->getNodeSize(), nodeBuf); }
/* * This is more than just a little insane: * In order to write the signature, we need to know the size and * the size and digests of the header and payload, which are located * after the signature on disk. We also need a digest of the compressed * payload for the main header, and of course the payload is after the * header on disk. So we need to create placeholders for both the * signature and main header that exactly match the final sizes, calculate * the payload digest, then generate and write the real main header to * be able to FINALLY calculate the digests we need for the signature * header. In other words, we need to write things in the exact opposite * order to how the RPM format is laid on disk. */ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp, const char *fileName, char **cookie) { FD_t fd = NULL; char * rpmio_flags = NULL; char * SHA1 = NULL; char * SHA256 = NULL; uint8_t * MD5 = NULL; char * pld = NULL; uint32_t pld_algo = PGPHASHALGO_SHA256; /* TODO: macro configuration */ rpmRC rc = RPMRC_FAIL; /* assume failure */ rpm_loff_t archiveSize = 0; off_t sigStart, hdrStart, payloadStart, payloadEnd; if (pkgidp) *pkgidp = NULL; rpmio_flags = getIOFlags(pkg); if (!rpmio_flags) goto exit; finalizeDeps(pkg); /* Create and add the cookie */ if (cookie) { rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime())); headerPutString(pkg->header, RPMTAG_COOKIE, *cookie); } /* Create a dummy payload digest to get the header size right */ pld = nullDigest(pld_algo, 1); headerPutUint32(pkg->header, RPMTAG_PAYLOADDIGESTALGO, &pld_algo, 1); headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld); pld = _free(pld); /* Check for UTF-8 encoding of string tags, add encoding tag if all good */ if (checkForEncoding(pkg->header, 1)) goto exit; /* Open the output file */ fd = Fopen(fileName, "w+.ufdio"); if (fd == NULL || Ferror(fd)) { rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } /* Write the lead section into the package. */ if (rpmLeadWrite(fd, pkg->header)) { rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); goto exit; } /* Save the position of signature section */ sigStart = Ftell(fd); /* Generate and write a placeholder signature header */ SHA1 = nullDigest(PGPHASHALGO_SHA1, 1); SHA256 = nullDigest(PGPHASHALGO_SHA256, 1); MD5 = nullDigest(PGPHASHALGO_MD5, 0); if (rpmGenerateSignature(SHA256, SHA1, MD5, 0, 0, fd)) goto exit; SHA1 = _free(SHA1); SHA256 = _free(SHA256); MD5 = _free(MD5); /* Write a placeholder header. */ hdrStart = Ftell(fd); if (writeHdr(fd, pkg->header)) goto exit; /* Write payload section (cpio archive) */ payloadStart = Ftell(fd); if (cpio_doio(fd, pkg, rpmio_flags, &archiveSize)) goto exit; payloadEnd = Ftell(fd); /* Re-read payload to calculate compressed digest */ fdInitDigestID(fd, pld_algo, RPMTAG_PAYLOADDIGEST, 0); if (fdConsume(fd, payloadStart, payloadEnd - payloadStart)) goto exit; fdFiniDigest(fd, RPMTAG_PAYLOADDIGEST, (void **)&pld, NULL, 1); /* Insert the payload digest in main header */ headerDel(pkg->header, RPMTAG_PAYLOADDIGEST); headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld); pld = _free(pld); /* Write the final header */ if (fdJump(fd, hdrStart)) goto exit; if (writeHdr(fd, pkg->header)) goto exit; /* Calculate digests: SHA on header, legacy MD5 on header + payload */ fdInitDigestID(fd, PGPHASHALGO_MD5, RPMTAG_SIGMD5, 0); fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMTAG_SHA1HEADER, 0); fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMTAG_SHA256HEADER, 0); if (fdConsume(fd, hdrStart, payloadStart - hdrStart)) goto exit; fdFiniDigest(fd, RPMTAG_SHA1HEADER, (void **)&SHA1, NULL, 1); fdFiniDigest(fd, RPMTAG_SHA256HEADER, (void **)&SHA256, NULL, 1); if (fdConsume(fd, 0, payloadEnd - payloadStart)) goto exit; fdFiniDigest(fd, RPMTAG_SIGMD5, (void **)&MD5, NULL, 0); if (fdJump(fd, sigStart)) goto exit; /* Generate the signature. Now with right values */ if (rpmGenerateSignature(SHA256, SHA1, MD5, payloadEnd - hdrStart, archiveSize, fd)) goto exit; rc = RPMRC_OK; exit: free(rpmio_flags); free(SHA1); free(SHA256); /* XXX Fish the pkgid out of the signature header. */ if (pkgidp != NULL) { if (MD5 != NULL) { *pkgidp = MD5; } } else { free(MD5); } Fclose(fd); if (rc == RPMRC_OK) rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName); else (void) unlink(fileName); return rc; }
int main(int argc, char* argv[]) { int fdin, fdout; void *container = malloc(SECURE_BOOT_HEADERS_SIZE); struct stat s; char *buf = malloc(4096); off_t l; void *infile; int r; ROM_container_raw *c = (ROM_container_raw*)container; ROM_prefix_header_raw *ph; ROM_prefix_data_raw *pd; ROM_sw_header_raw *swh; ROM_sw_sig_raw *ssig; unsigned char md[SHA512_DIGEST_LENGTH]; void *p; ecc_key_t pubkeyraw; ecc_signature_t sigraw; int indexptr; progname = strrchr (argv[0], '/'); if (progname != NULL) ++progname; else progname = argv[0]; memset(container, 0, SECURE_BOOT_HEADERS_SIZE); while (1) { int opt; opt = getopt_long(argc, argv, "a:b:c:p:q:r:A:B:C:P:Q:R:L:I:dh", opts, &indexptr); if (opt == -1) break; switch (opt) { case 'h': case '?': usage(EX_OK); break; case 'd': debug = 1; break; case 'a': params.hw_keyfn_a = optarg; break; case 'b': params.hw_keyfn_b = optarg; break; case 'c': params.hw_keyfn_c = optarg; break; case 'p': params.sw_keyfn_p = optarg; break; case 'q': params.sw_keyfn_q = optarg; break; case 'r': params.sw_keyfn_r = optarg; break; case 'A': params.hw_sigfn_a = optarg; break; case 'B': params.hw_sigfn_b = optarg; break; case 'C': params.hw_sigfn_c = optarg; break; case 'P': params.sw_sigfn_p = optarg; break; case 'Q': params.sw_sigfn_q = optarg; break; case 'R': params.sw_sigfn_r = optarg; break; case 'L': params.payloadfn = optarg; break; case 'I': params.imagefn = optarg; break; case 128: params.prhdrfn = optarg; break; case 129: params.swhdrfn = optarg; break; default: usage(EX_USAGE); } } // } fdin = open(params.payloadfn, O_RDONLY); assert(fdin > 0); r = fstat(fdin, &s); assert(r==0); infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); assert(infile); fdout = open(params.imagefn, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert(fdout > 0); c->magic_number = cpu_to_be32(ROM_MAGIC_NUMBER); c->version = cpu_to_be16(1); c->container_size = cpu_to_be64(SECURE_BOOT_HEADERS_SIZE + s.st_size); c->target_hrmor = 0; c->stack_pointer = 0; memset(c->hw_pkey_a, 0, sizeof(ecc_key_t)); memset(c->hw_pkey_b, 0, sizeof(ecc_key_t)); memset(c->hw_pkey_c, 0, sizeof(ecc_key_t)); if (params.hw_keyfn_a) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_a); memcpy(c->hw_pkey_a, pubkeyraw, sizeof(ecc_key_t)); } if (params.hw_keyfn_b) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_b); memcpy(c->hw_pkey_b, pubkeyraw, sizeof(ecc_key_t)); } if (params.hw_keyfn_c) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_c); memcpy(c->hw_pkey_c, pubkeyraw, sizeof(ecc_key_t)); } ph = container + sizeof(ROM_container_raw); ph->ver_alg.version = cpu_to_be16(1); ph->ver_alg.hash_alg = 1; ph->ver_alg.sig_alg = 1; ph->code_start_offset = 0; ph->reserved = 0; ph->flags = cpu_to_be32(0x80000000); memset(ph->payload_hash, 0, sizeof(sha2_hash_t)); ph->ecid_count = 0; pd = (ROM_prefix_data_raw*)ph->ecid; memset(pd->hw_sig_a, 0, sizeof(ecc_signature_t)); memset(pd->hw_sig_b, 0, sizeof(ecc_signature_t)); memset(pd->hw_sig_c, 0, sizeof(ecc_signature_t)); if (params.hw_sigfn_a) { getSigRaw(&sigraw, params.hw_sigfn_a); memcpy(pd->hw_sig_a, sigraw, sizeof(ecc_key_t)); } if (params.hw_sigfn_b) { getSigRaw(&sigraw, params.hw_sigfn_b); memcpy(pd->hw_sig_b, sigraw, sizeof(ecc_key_t)); } if (params.hw_sigfn_c) { getSigRaw(&sigraw, params.hw_sigfn_c); memcpy(pd->hw_sig_c, sigraw, sizeof(ecc_key_t)); } memset(pd->sw_pkey_p, 0, sizeof(ecc_key_t)); memset(pd->sw_pkey_q, 0, sizeof(ecc_key_t)); memset(pd->sw_pkey_r, 0, sizeof(ecc_key_t)); if (params.sw_keyfn_p) { getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_p); memcpy(pd->sw_pkey_p, pubkeyraw, sizeof(ecc_key_t)); ph->sw_key_count++; } if (params.sw_keyfn_q) { getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_q); memcpy(pd->sw_pkey_q, pubkeyraw, sizeof(ecc_key_t)); ph->sw_key_count++; } if (params.sw_keyfn_r) { getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_r); memcpy(pd->sw_pkey_r, pubkeyraw, sizeof(ecc_key_t)); ph->sw_key_count++; } ph->payload_size = cpu_to_be64(ph->sw_key_count * sizeof(ecc_key_t)); p = SHA512(pd->sw_pkey_p, sizeof(ecc_key_t) * ph->sw_key_count, md); assert(p); memcpy(ph->payload_hash, md, sizeof(sha2_hash_t)); if (params.prhdrfn) writeHdr((void *)ph, params.prhdrfn, PREFIX_HDR); swh = (ROM_sw_header_raw*)(((uint8_t*)pd) + sizeof(ecc_signature_t)*3 + be64_to_cpu(ph->payload_size)); swh->ver_alg.version = cpu_to_be16(1); swh->ver_alg.hash_alg = 1; swh->ver_alg.sig_alg = 1; swh->code_start_offset = 0; swh->reserved = 0; swh->flags = 0; swh->reserved_0 = 0; swh->payload_size = cpu_to_be64(s.st_size); p = SHA512(infile, s.st_size, md); assert(p); memcpy(swh->payload_hash, md, sizeof(sha2_hash_t)); if (params.swhdrfn) writeHdr((void *)swh, params.swhdrfn, SOFTWARE_HDR); ssig = (ROM_sw_sig_raw*)(((uint8_t*)swh) + sizeof(ROM_sw_header_raw)); memset(ssig->sw_sig_p, 0, sizeof(ecc_signature_t)); memset(ssig->sw_sig_q, 0, sizeof(ecc_signature_t)); memset(ssig->sw_sig_r, 0, sizeof(ecc_signature_t)); if (params.sw_sigfn_p) { getSigRaw(&sigraw, params.sw_sigfn_p); memcpy(ssig->sw_sig_p, sigraw, sizeof(ecc_key_t)); } if (params.sw_sigfn_q) { getSigRaw(&sigraw, params.sw_sigfn_q); memcpy(ssig->sw_sig_q, sigraw, sizeof(ecc_key_t)); } if (params.sw_sigfn_r) { getSigRaw(&sigraw, params.sw_sigfn_r); memcpy(ssig->sw_sig_r, sigraw, sizeof(ecc_key_t)); } r = write(fdout, container, SECURE_BOOT_HEADERS_SIZE); assert(r == 4096); read(fdin, buf, s.st_size%4096); write(fdout, buf, s.st_size%4096); l = s.st_size - s.st_size%4096; while (l) { read(fdin, buf, 4096); write(fdout, buf, 4096); l-=4096; }; close(fdin); close(fdout); free(container); free(buf); return 0; }