/* * Copyright 2012 Red Hat, Inc. * All rights reserved. * * 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; version 2 of the License. * * 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, see . * * Author(s): Peter Jones */ #include #include #include #include #include #include #include #include "authvar.h" static char *default_namespace="global"; int authvar_context_init(authvar_context *ctx) { memset(ctx, '\0', sizeof (*ctx)); ctx->namespace = default_namespace; int rc = cms_context_alloc(&ctx->cms_ctx); ctx->attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; ctx->exportfd = -1; return rc; } void authvar_context_fini(authvar_context *ctx) { if (!ctx) return; cms_context_fini(ctx->cms_ctx); if (ctx->name) { xfree(ctx->name); } if (ctx->valuefile) { munmap(ctx->value, ctx->value_size); ctx->value = NULL; close(ctx->valuefd); ctx->valuefd = -1; ctx->value_size = 0; xfree(ctx->valuefile); ctx->valuefile = NULL; } else if (ctx->value) { xfree(ctx->value); ctx->value = NULL; ctx->value_size = 0; } if (ctx->exportfd >= 0) { close(ctx->exportfd); ctx->exportfd = -1; } } int generate_descriptor(authvar_context *ctx) { win_cert_uefi_guid_t *authinfo; SECItem sd_der; char *name_ptr; uint8_t *buf, *ptr; size_t buf_len; uint64_t offset; efi_char16_t *wptr; int rc; /* prepare buffer for varname, vendor_guid, attr, timestamp, value */ buf_len = strlen(ctx->name)*sizeof(efi_char16_t) + sizeof(efi_guid_t) + sizeof(uint32_t) + sizeof(efi_time_t) + ctx->value_size; buf = calloc(1, buf_len); if (!buf) return -1; ptr = buf; name_ptr = ctx->name; while (*name_ptr != '\0') { wptr = (efi_char16_t *)ptr; *wptr = *name_ptr; name_ptr++; ptr += sizeof(efi_char16_t); } memcpy(ptr, &ctx->guid, sizeof(efi_guid_t)); ptr += sizeof(efi_guid_t); memcpy(ptr, &ctx->attr, sizeof(uint32_t)); ptr += sizeof(uint32_t); memcpy(ptr, &ctx->timestamp, sizeof(efi_time_t)); ptr += sizeof(efi_time_t); memcpy(ptr, ctx->value, ctx->value_size); ctx->cms_ctx->authbuf_len = buf_len; ctx->cms_ctx->authbuf = buf; /* XXX set the value to get SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION from digest_get_signature_oid(). */ ctx->cms_ctx->selected_digest = 0; /* sign the digest */ memset(&sd_der, '\0', sizeof(sd_der)); rc = generate_authvar_signed_data(ctx->cms_ctx, &sd_der); if (rc < 0) cmsreterr(-1, ctx->cms_ctx, "could not create signed data"); #if __WORDSIZE == 64 offset = (uint64_t) &((win_cert_uefi_guid_t *)0)->data; #else offset = (uint32_t) &((win_cert_uefi_guid_t *)0)->data; #endif authinfo = calloc(offset + sd_der.len, 1); if (!authinfo) cmsreterr(-1, ctx->cms_ctx, "could not allocate authinfo"); authinfo->hdr.length = sd_der.len + (uint32_t)offset; authinfo->hdr.revision = WIN_CERT_REVISION_2_0; authinfo->hdr.cert_type = WIN_CERT_TYPE_EFI_GUID; authinfo->type = efi_guid_pkcs7_cert; memcpy(&authinfo->data, sd_der.data, sd_der.len); ctx->authinfo = authinfo; return 0; } int write_authvar(authvar_context *ctx) { efi_var_auth_2_t *descriptor; void *buffer, *ptr; size_t buf_len, des_len, remain; ssize_t wlen; if (!ctx->authinfo) cmsreterr(-1, ctx->cms_ctx, "Not a valid authvar"); des_len = sizeof(efi_var_auth_2_t) + ctx->authinfo->hdr.length - sizeof(win_cert_uefi_guid_t); buf_len = sizeof(ctx->attr) + des_len + ctx->value_size; buffer = calloc(buf_len, 1); if (!buffer) cmsreterr(-1, ctx->cms_ctx, "could not allocate buffer"); ptr = buffer; /* The attribute of the variable */ memcpy(ptr, &ctx->attr, sizeof(ctx->attr)); ptr += sizeof(ctx->attr); /* EFI_VARIABLE_AUTHENTICATION_2 */ descriptor = (efi_var_auth_2_t *)ptr; memcpy(&descriptor->timestamp, &ctx->timestamp, sizeof(efi_time_t)); memcpy(&descriptor->authinfo, ctx->authinfo, ctx->authinfo->hdr.length); ptr += des_len; /* Data */ if (ctx->value_size > 0) memcpy(ptr, ctx->value, ctx->value_size); if (!ctx->to_firmware) { ftruncate(ctx->exportfd, buf_len); lseek(ctx->exportfd, 0, SEEK_SET); } remain = buf_len; do { wlen = write(ctx->exportfd, buffer, remain); if (wlen < 0) cmsreterr(-1, ctx->cms_ctx, "failed to write authvar"); remain -= wlen; } while (remain > 0); return 0; }