/* * Copyright (C) 2012 Jeremy Kerr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #include #include #include #include #include #include #include #include #include #include #include "ccan/talloc/talloc.h" struct efi_guid { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; }; #if __BYTE_ORDER != __LITTLE_ENDIAN #error Only little-endian machines are supported currently #endif const struct efi_guid x509_guid = { 0xa5c059a1, 0x94e4, 0x4aa7, \ { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } }; struct efi_signature_data { struct efi_guid SignatureOwner; uint8_t SignatureData[]; }; struct efi_signature_list { struct efi_guid SignatureType; uint32_t SignatureListSize; uint32_t SignatureHeaderSize; uint32_t SignatureSize; /* this can follow directly, as we don't have a header */ struct efi_signature_data Signatures[]; }; struct keydata { void *buf; unsigned int size; }; static void uuid_to_efi_guid(uuid_t u, struct efi_guid *e) { /* The UUID is in raw format, so no byte-swapping is required */ memcpy(e, u, sizeof(*e)); } static struct keydata *slurp_file(const char *filename) { unsigned int bytes_read; struct stat statbuf; struct keydata *keydata; int rc, fd; keydata = talloc(NULL, struct keydata); if (!keydata) { perror("talloc(keydata)"); return NULL; } fd = open(filename, O_RDONLY); if (fd < 0) { perror("open"); goto err_free; } rc = fstat(fd, &statbuf); if (rc) { perror("fstat"); goto err_close; } keydata->size = statbuf.st_size; keydata->buf = talloc_size(keydata, keydata->size); if (!keydata->buf) { perror("talloc(buf)"); goto err_close; } for (bytes_read = 0; bytes_read < keydata->size; bytes_read += rc) { rc = read(fd, keydata->buf + bytes_read, keydata->size - bytes_read); if (rc < 0) { perror("read"); break; } if (rc == 0) break; } if (bytes_read < keydata->size) { fprintf(stderr, "error reading input file\n"); goto err_close; } close(fd); return keydata; err_close: close(fd); err_free: talloc_free(keydata); return NULL; } static int write_file(const char *filename, void *buf, unsigned int size) { int fd, rc; fd = open(filename, O_WRONLY | O_CREAT, 0644); if (fd < 0) { perror("open"); return -1; } rc = write(fd, buf, size); if (rc != (int)size) { perror("write"); rc = -1; } else rc = 0; close(fd); return rc; } static int write_output(const char *basename, struct efi_signature_list *siglist) { char *filename; /* write list */ filename = talloc_asprintf(NULL, "%s.siglist", basename); write_file(filename, siglist, siglist->SignatureListSize); talloc_free(filename); /* write single entry data */ filename = talloc_asprintf(NULL, "%s.sigdata", basename); write_file(filename, siglist->Signatures, siglist->SignatureSize); talloc_free(filename); return 0; } int main(int argc, char **argv) { struct efi_signature_list *siglist; struct efi_signature_data *sigdata; struct keydata *keydata; const char *filename; int rc, siglist_size; uuid_t owner_uuid; if (argc != 3) { fprintf(stderr, "usage: %s \n", argv[0]); return EXIT_FAILURE; } rc = uuid_parse(argv[1], owner_uuid); if (rc) { fprintf(stderr, "failed to parse uuid '%s'\n", argv[1]); return EXIT_FAILURE; } filename = argv[2]; keydata = slurp_file(filename); if (!keydata) return EXIT_FAILURE; siglist_size = sizeof(struct efi_signature_list) + sizeof(struct efi_signature_data) + keydata->size; siglist = talloc_size(keydata, siglist_size); siglist->SignatureType = x509_guid; siglist->SignatureListSize = siglist_size; siglist->SignatureHeaderSize = 0; siglist->SignatureSize = sizeof(struct efi_signature_data) + keydata->size; sigdata = siglist->Signatures; uuid_to_efi_guid(owner_uuid, &sigdata->SignatureOwner); memcpy(sigdata->SignatureData, keydata->buf, keydata->size); write_output(filename, siglist); return 0; }