1 /* $NetBSD: efirng.c,v 1.4 2022/08/14 11:26:41 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * UEFI Forum, Inc.: UEFI Specification, Version 2.8 Errata A, February
31 * 2020, Sec. 37.5 EFI Random Number Generator Protocol, pp. 2158--2162
32 * https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_A_Feb14.pdf
33 */
34
35 #include "efirng.h"
36
37 #include "efiboot.h"
38
39 static EFI_GUID RngProtocolGuid = EFI_RNG_PROTOCOL_GUID;
40 static EFI_GUID RngAlgorithmRawGuid = EFI_RNG_ALGORITHM_RAW;
41 static EFI_RNG_PROTOCOL *rng;
42
43 #ifndef EFIBOOT_DEBUG
44 #define DPRINT(...) __nothing
45 #else
46 #define DPRINT Print
47 #endif
48
49 static const struct {
50 EFI_GUID guid;
51 const CHAR16 *name;
52 } algname[] = {
53 {EFI_RNG_ALGORITHM_SP800_90_HASH_256_GUID,
54 L"NIST SP800-90 Hash_DRBG SHA-256"},
55 {EFI_RNG_ALGORITHM_SP800_90_HMAC_256_GUID,
56 L"NIST SP800-90 HMAC_DRBG SHA-256"},
57 {EFI_RNG_ALGORITHM_SP800_90_CTR_256_GUID,
58 L"NIST SP800-90 CTR_DRBG AES-256"},
59 {EFI_RNG_ALGORITHM_X9_31_3DES_GUID, L"ANSI X9.31 3DES"},
60 {EFI_RNG_ALGORITHM_X9_31_AES_GUID, L"ANSI X9.31 AES"},
61 {EFI_RNG_ALGORITHM_RAW, L"raw"},
62 };
63
64 void
efi_rng_probe(void)65 efi_rng_probe(void)
66 {
67 EFI_STATUS status;
68
69 /* Get the RNG protocol. */
70 status = LibLocateProtocol(&RngProtocolGuid, (void **)&rng);
71 if (EFI_ERROR(status)) {
72 DPRINT(L"efirng: protocol: %r\n", status);
73 rng = NULL;
74 return;
75 }
76 }
77
78 void
efi_rng_show(void)79 efi_rng_show(void)
80 {
81 EFI_RNG_ALGORITHM alglist[10];
82 UINTN i, j, alglistsz = sizeof(alglist);
83 EFI_STATUS status;
84
85 if (!efi_rng_available())
86 return;
87
88 command_printtab("RNG", "");
89
90 /* Query the list of supported algorithms. */
91 status = uefi_call_wrapper(rng->GetInfo, 3, rng, &alglistsz, alglist);
92 if (EFI_ERROR(status)) {
93 Print(L"GetInfo: %r\n", status);
94 return;
95 }
96
97 /* Print the list of supported algorithms. */
98 for (i = 0; i < alglistsz/sizeof(alglist[0]); i++) {
99 const CHAR16 *name = L"[unknown]";
100 for (j = 0; j < __arraycount(algname); j++) {
101 if (memcmp(&alglist[i], &algname[j].guid,
102 sizeof(EFI_GUID)) == 0) {
103 name = algname[j].name;
104 break;
105 }
106 }
107 Print(L"%s (%g)\n", name, &alglist[i]);
108 }
109 }
110
111 int
efi_rng_available(void)112 efi_rng_available(void)
113 {
114
115 return rng != NULL;
116 }
117
118 int
efi_rng(void * buf,UINTN len)119 efi_rng(void *buf, UINTN len)
120 {
121 EFI_STATUS status;
122
123 if (!efi_rng_available())
124 return EIO;
125
126 status = uefi_call_wrapper(rng->GetRNG, 4, rng, &RngAlgorithmRawGuid,
127 len, buf);
128 if (status == EFI_UNSUPPORTED) {
129 /*
130 * Fall back to any supported RNG `algorithm' even
131 * though we would prefer raw samples.
132 */
133 status = uefi_call_wrapper(rng->GetRNG, 4, rng, NULL, len, buf);
134 }
135 if (EFI_ERROR(status)) {
136 DPRINT(L"efirng: GetRNG: %r\n", status);
137 return EIO;
138 }
139
140 return 0;
141 }
142