efirng.c revision 1.1 1 /* $NetBSD: efirng.c,v 1.1 2020/05/14 19:19:08 riastradh 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
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
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 /* Query the list of supported algorithms. */
86 status = uefi_call_wrapper(rng->GetInfo, 3, rng, &alglistsz, alglist);
87 if (EFI_ERROR(status)) {
88 Print(L"efirng: GetInfo: %r\n", status);
89 return;
90 }
91
92 /* Print the list of supported algorithms. */
93 for (i = 0; i < alglistsz/sizeof(alglist[0]); i++) {
94 const CHAR16 *name = L"[unknown]";
95 for (j = 0; j < __arraycount(algname); j++) {
96 if (memcmp(&alglist[i], &algname[j].guid,
97 sizeof(EFI_GUID)) == 0) {
98 name = algname[j].name;
99 break;
100 }
101 }
102 Print(L"RNG: %s (%g)\n", name, &alglist[i]);
103 }
104 }
105
106 int
107 efi_rng_available(void)
108 {
109
110 return rng != NULL;
111 }
112
113 int
114 efi_rng(void *buf, UINTN len)
115 {
116 EFI_STATUS status;
117
118 if (rng == NULL)
119 return EIO;
120
121 status = uefi_call_wrapper(rng->GetRNG, 3, rng, &RngAlgorithmRawGuid,
122 len, buf);
123 if (status == EFI_UNSUPPORTED) {
124 /*
125 * Fall back to any supported RNG `algorithm' even
126 * though we would prefer raw samples.
127 */
128 status = uefi_call_wrapper(rng->GetRNG, 3, rng, NULL, len, buf);
129 }
130 if (EFI_ERROR(status)) {
131 DPRINT(L"efirng: GetRNG: %r\n", status);
132 return EIO;
133 }
134
135 return 0;
136 }
137