iBoot/lib/nonce/nonce.c

211 lines
4.8 KiB
C

/*
* Copyright (c) 2012-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <stdlib.h>
#include <lib/env.h>
#include <lib/mib.h>
#include <lib/nonce.h>
#include <lib/nvram.h>
#include <lib/random.h>
#include <debug.h>
#include <platform.h>
#include <sys/hash.h>
#include <sys/menu.h>
static const char *kBootNoncePropertyKey = "com.apple.System.boot-nonce";
static const size_t kExpectedNonceLength = (sizeof(uint64_t) * 2) + 2;
int
mobile_ap_nonce_consume_nonce(uint64_t *nonce)
{
const char* nonce_string;
size_t nonce_length = 0;
int result = 0;
ASSERT(nonce != NULL);
*nonce = 0;
nonce_string = env_get(kBootNoncePropertyKey);
if (nonce_string != NULL) {
dprintf(DEBUG_SPEW, "%s: nonce_string='%s'\n", __func__, nonce_string);
nonce_length = strlen(nonce_string);
dprintf(DEBUG_SPEW, "%s: nonce_length='%zu'\n", __func__, nonce_length);
if (nonce_length == kExpectedNonceLength) {
*nonce = strtoull(nonce_string, NULL, 16);
result = 1;
} else {
#if DEBUG_BUILD
dprintf(DEBUG_CRITICAL,
"%s: nonce value has invalid length %zu %s\n",
__func__, nonce_length, nonce_string);
#else
dprintf(DEBUG_CRITICAL,
"%s: nonce value has invalid length\n",
__func__);
#endif
}
// The nonce environment variable exists.
// Remove it whether it is valid or not.
if (env_unset(kBootNoncePropertyKey)) {
// Save the updated nvram contents.
if (nvram_save() != 0) {
dprintf(DEBUG_CRITICAL,
"%s: Could not save nvram contents\n",
__func__);
}
} else {
dprintf(DEBUG_CRITICAL,
"%s: could not clear nonce\n",
__func__);
}
}
return result;
}
// =============================================================================
static void
print_usage(int argc, struct cmd_arg *args)
{
printf("USAGE: %s <subcmd>\n\n", ((0 < argc) ? args[0].str : "?"));
printf(" Where <subcmd> is one of following\n\n");
printf(" get - read the nonce and clear it, then report its hash and value\n");
printf(" if no nonce was previously set, one is generated\n");
if (mib_get_bool(kMIBTargetWithEffaceable)) {
return;
}
printf(" clear - clear the nonce\n");
printf(" consume - read the raw nonce, report its hash and value, and comsume it\n");
printf(" read - read the raw nonce, report its hash and value, but don't consume it\n");
}
static void
print_nonce_and_hash(uint64_t nonce)
{
uint8_t hash[HASH_OUTPUT_SIZE];
int idx;
hash_calculate(&nonce, sizeof(nonce), hash, sizeof(hash));
printf("boot-nonce: 0x%016llx\n", nonce);
printf("boot-nonce hash:");
for (idx = 0; idx < HASH_OUTPUT_SIZE; idx++) {
printf(" %02X", hash[idx]);
}
printf("\n");
}
static int
get_nonce(void)
{
uint64_t nonce;
nonce = platform_get_nonce();
print_nonce_and_hash(nonce);
return 0;
}
static int
clear_nonce(void)
{
const char* nonce_string;
nonce_string = env_get(kBootNoncePropertyKey);
if (nonce_string != NULL) {
if (env_unset(kBootNoncePropertyKey)) {
// Save the updated nvram contents.
if (nvram_save() == 0) {
printf("Boot nonce cleared\n");
} else {
printf("Failed to update nvram\n");
}
} else {
printf("Failed to clear boot nonce\n");
}
} else {
printf("Boot nonce not found\n");
}
return 0;
}
static int
consume_nonce(void)
{
uint64_t nonce;
nonce = platform_consume_nonce();
print_nonce_and_hash(nonce);
return 0;
}
static int
read_nonce(void)
{
uint64_t nonce;
const char* nonce_string;
size_t nonce_length = 0;
nonce_string = env_get(kBootNoncePropertyKey);
if (nonce_string != NULL)
nonce_length = strlen(nonce_string);
if (nonce_length != 0) {
// The nonce string must be the exact length of a
// 64-bit integer plus 2 for the "0x" prefix.
if (nonce_length == kExpectedNonceLength) {
nonce = strtoull(nonce_string, NULL, 16);
print_nonce_and_hash(nonce);
} else {
printf("Boot nonce value (%s) has invalid length %zu should be %zu",
nonce_string, nonce_length, kExpectedNonceLength);
}
} else {
printf("Boot nonce not found\n");
}
return 0;
}
int
do_nonce(int argc, struct cmd_arg *args)
{
int err;
bool with_effaceable = mib_get_bool(kMIBTargetWithEffaceable);
if (1 >= argc) {
print_usage(argc, args);
err = 0;
} else if (0 == strcmp("get", args[1].str)) {
err = get_nonce();
} else if (!with_effaceable && (0 == strcmp("clear", args[1].str))) {
err = clear_nonce();
} else if (!with_effaceable && (0 == strcmp("consume", args[1].str))) {
err = consume_nonce();
} else if (!with_effaceable && (0 == strcmp("read", args[1].str))) {
err = read_nonce();
} else {
print_usage(argc, args);
printf("unrecognized subcommand\n");
err = -1;
}
return err;
}