linux/drivers/firmware/efi/libstub/random.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
   4 */
   5
   6#include <linux/efi.h>
   7#include <asm/efi.h>
   8
   9#include "efistub.h"
  10
  11typedef union efi_rng_protocol efi_rng_protocol_t;
  12
  13union efi_rng_protocol {
  14        struct {
  15                efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *,
  16                                                  unsigned long *,
  17                                                  efi_guid_t *);
  18                efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *,
  19                                                 efi_guid_t *, unsigned long,
  20                                                 u8 *out);
  21        };
  22        struct {
  23                u32 get_info;
  24                u32 get_rng;
  25        } mixed_mode;
  26};
  27
  28/**
  29 * efi_get_random_bytes() - fill a buffer with random bytes
  30 * @size:       size of the buffer
  31 * @out:        caller allocated buffer to receive the random bytes
  32 *
  33 * The call will fail if either the firmware does not implement the
  34 * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
  35 * the buffer.
  36 *
  37 * Return:      status code
  38 */
  39efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
  40{
  41        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
  42        efi_status_t status;
  43        efi_rng_protocol_t *rng = NULL;
  44
  45        status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
  46        if (status != EFI_SUCCESS)
  47                return status;
  48
  49        return efi_call_proto(rng, get_rng, NULL, size, out);
  50}
  51
  52/**
  53 * efi_random_get_seed() - provide random seed as configuration table
  54 *
  55 * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are
  56 * saved as a configuration table which can be used as entropy by the kernel
  57 * for the initialization of its pseudo random number generator.
  58 *
  59 * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes
  60 * available, the configuration table will not be installed and an error code
  61 * will be returned.
  62 *
  63 * Return:      status code
  64 */
  65efi_status_t efi_random_get_seed(void)
  66{
  67        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
  68        efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW;
  69        efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID;
  70        efi_rng_protocol_t *rng = NULL;
  71        struct linux_efi_random_seed *seed = NULL;
  72        efi_status_t status;
  73
  74        status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
  75        if (status != EFI_SUCCESS)
  76                return status;
  77
  78        status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
  79                             sizeof(*seed) + EFI_RANDOM_SEED_SIZE,
  80                             (void **)&seed);
  81        if (status != EFI_SUCCESS)
  82                return status;
  83
  84        status = efi_call_proto(rng, get_rng, &rng_algo_raw,
  85                                 EFI_RANDOM_SEED_SIZE, seed->bits);
  86
  87        if (status == EFI_UNSUPPORTED)
  88                /*
  89                 * Use whatever algorithm we have available if the raw algorithm
  90                 * is not implemented.
  91                 */
  92                status = efi_call_proto(rng, get_rng, NULL,
  93                                        EFI_RANDOM_SEED_SIZE, seed->bits);
  94
  95        if (status != EFI_SUCCESS)
  96                goto err_freepool;
  97
  98        seed->size = EFI_RANDOM_SEED_SIZE;
  99        status = efi_bs_call(install_configuration_table, &rng_table_guid, seed);
 100        if (status != EFI_SUCCESS)
 101                goto err_freepool;
 102
 103        return EFI_SUCCESS;
 104
 105err_freepool:
 106        efi_bs_call(free_pool, seed);
 107        return status;
 108}
 109