]> git.proxmox.com Git - grub2.git/blob - commands/password_pbkdf2.c
merge mainline into newenv
[grub2.git] / commands / password_pbkdf2.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <grub/auth.h>
20 #include <grub/crypto.h>
21 #include <grub/list.h>
22 #include <grub/mm.h>
23 #include <grub/misc.h>
24 #include <grub/env.h>
25 #include <grub/normal.h>
26 #include <grub/dl.h>
27
28 static grub_dl_t my_mod;
29
30 struct pbkdf2_password
31 {
32 grub_uint8_t *salt;
33 grub_size_t saltlen;
34 unsigned int c;
35 grub_uint8_t *expected;
36 grub_size_t buflen;
37 };
38
39 static grub_err_t
40 check_password (const char *user, const char *entered, void *pin)
41 {
42 grub_uint8_t *buf;
43 struct pbkdf2_password *pass = pin;
44 gcry_err_code_t err;
45
46 buf = grub_malloc (pass->buflen);
47 if (!buf)
48 return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
49
50 err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered,
51 grub_strlen (entered),
52 pass->salt, pass->saltlen, pass->c,
53 buf, pass->buflen);
54 if (err)
55 {
56 grub_free (buf);
57 return grub_crypto_gcry_error (err);
58 }
59
60 if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0)
61 return GRUB_ACCESS_DENIED;
62
63 grub_auth_authenticate (user);
64
65 return GRUB_ERR_NONE;
66 }
67
68 static inline int
69 hex2val (char hex)
70 {
71 if ('0' <= hex && hex <= '9')
72 return hex - '0';
73 if ('a' <= hex && hex <= 'f')
74 return hex - 'a' + 10;
75 if ('A' <= hex && hex <= 'F')
76 return hex - 'A' + 10;
77 return -1;
78 }
79
80 static grub_err_t
81 grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
82 int argc, char **args)
83 {
84 grub_err_t err;
85 char *ptr, *ptr2;
86 grub_uint8_t *ptro;
87 struct pbkdf2_password *pass;
88
89 if (argc != 2)
90 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected.");
91
92 if (grub_memcmp (args[1], "grub.pbkdf2.sha512.",
93 sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
94 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
95
96 ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1;
97
98 pass = grub_malloc (sizeof (*pass));
99 if (!pass)
100 return grub_errno;
101
102 pass->c = grub_strtoul (ptr, &ptr, 0);
103 if (*ptr != '.')
104 {
105 grub_free (pass);
106 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
107 }
108 ptr++;
109
110 ptr2 = grub_strchr (ptr, '.');
111 if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1)
112 {
113 grub_free (pass);
114 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
115 }
116
117 pass->saltlen = (ptr2 - ptr) >> 1;
118 pass->buflen = grub_strlen (ptr2 + 1) >> 1;
119 ptro = pass->salt = grub_malloc (pass->saltlen);
120 if (!ptro)
121 {
122 grub_free (pass);
123 return grub_errno;
124 }
125 while (ptr < ptr2)
126 {
127 int hex1, hex2;
128 hex1 = hex2val (*ptr);
129 ptr++;
130 hex2 = hex2val (*ptr);
131 ptr++;
132 if (hex1 < 0 || hex2 < 0)
133 {
134 grub_free (pass->salt);
135 grub_free (pass);
136 return grub_error (GRUB_ERR_BAD_ARGUMENT,
137 "Incorrect PBKDF2 password.");
138 }
139
140 *ptro = (hex1 << 4) | hex2;
141 ptro++;
142 }
143
144 ptro = pass->expected = grub_malloc (pass->buflen);
145 if (!ptro)
146 {
147 grub_free (pass->salt);
148 grub_free (pass);
149 return grub_errno;
150 }
151 ptr = ptr2 + 1;
152 ptr2 += grub_strlen (ptr2);
153 while (ptr < ptr2)
154 {
155 int hex1, hex2;
156 hex1 = hex2val (*ptr);
157 ptr++;
158 hex2 = hex2val (*ptr);
159 ptr++;
160 if (hex1 < 0 || hex2 < 0)
161 {
162 grub_free (pass->expected);
163 grub_free (pass->salt);
164 grub_free (pass);
165 return grub_error (GRUB_ERR_BAD_ARGUMENT,
166 "Incorrect PBKDF2 password.");
167 }
168
169 *ptro = (hex1 << 4) | hex2;
170 ptro++;
171 }
172
173 err = grub_auth_register_authentication (args[0], check_password, pass);
174 if (err)
175 {
176 grub_free (pass);
177 return err;
178 }
179 grub_dl_ref (my_mod);
180 return GRUB_ERR_NONE;
181 }
182
183 static grub_command_t cmd;
184 \f
185 GRUB_MOD_INIT(password_pbkdf2)
186 {
187 my_mod = mod;
188 cmd = grub_register_command ("password_pbkdf2", grub_cmd_password,
189 "password_pbkdf2 USER PBKDF2_PASSWORD",
190 "Set user password (PBKDF2). ");
191 }
192
193 GRUB_MOD_FINI(password_pbkdf2)
194 {
195 grub_unregister_command (cmd);
196 }