]> git.proxmox.com Git - grub2.git/blob - commands/password_pbkdf2.c
merge from trunk
[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 #include <grub/i18n.h>
28
29 static grub_dl_t my_mod;
30
31 struct pbkdf2_password
32 {
33 grub_uint8_t *salt;
34 grub_size_t saltlen;
35 unsigned int c;
36 grub_uint8_t *expected;
37 grub_size_t buflen;
38 };
39
40 static grub_err_t
41 check_password (const char *user, const char *entered, void *pin)
42 {
43 grub_uint8_t *buf;
44 struct pbkdf2_password *pass = pin;
45 gcry_err_code_t err;
46
47 buf = grub_malloc (pass->buflen);
48 if (!buf)
49 return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
50
51 err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered,
52 grub_strlen (entered),
53 pass->salt, pass->saltlen, pass->c,
54 buf, pass->buflen);
55 if (err)
56 {
57 grub_free (buf);
58 return grub_crypto_gcry_error (err);
59 }
60
61 if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0)
62 return GRUB_ACCESS_DENIED;
63
64 grub_auth_authenticate (user);
65
66 return GRUB_ERR_NONE;
67 }
68
69 static inline int
70 hex2val (char hex)
71 {
72 if ('0' <= hex && hex <= '9')
73 return hex - '0';
74 if ('a' <= hex && hex <= 'f')
75 return hex - 'a' + 10;
76 if ('A' <= hex && hex <= 'F')
77 return hex - 'A' + 10;
78 return -1;
79 }
80
81 static grub_err_t
82 grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
83 int argc, char **args)
84 {
85 grub_err_t err;
86 char *ptr, *ptr2;
87 grub_uint8_t *ptro;
88 struct pbkdf2_password *pass;
89
90 if (argc != 2)
91 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected.");
92
93 if (grub_memcmp (args[1], "grub.pbkdf2.sha512.",
94 sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
95 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
96
97 ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1;
98
99 pass = grub_malloc (sizeof (*pass));
100 if (!pass)
101 return grub_errno;
102
103 pass->c = grub_strtoul (ptr, &ptr, 0);
104 if (*ptr != '.')
105 {
106 grub_free (pass);
107 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
108 }
109 ptr++;
110
111 ptr2 = grub_strchr (ptr, '.');
112 if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1)
113 {
114 grub_free (pass);
115 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password.");
116 }
117
118 pass->saltlen = (ptr2 - ptr) >> 1;
119 pass->buflen = grub_strlen (ptr2 + 1) >> 1;
120 ptro = pass->salt = grub_malloc (pass->saltlen);
121 if (!ptro)
122 {
123 grub_free (pass);
124 return grub_errno;
125 }
126 while (ptr < ptr2)
127 {
128 int hex1, hex2;
129 hex1 = hex2val (*ptr);
130 ptr++;
131 hex2 = hex2val (*ptr);
132 ptr++;
133 if (hex1 < 0 || hex2 < 0)
134 {
135 grub_free (pass->salt);
136 grub_free (pass);
137 return grub_error (GRUB_ERR_BAD_ARGUMENT,
138 "Incorrect PBKDF2 password.");
139 }
140
141 *ptro = (hex1 << 4) | hex2;
142 ptro++;
143 }
144
145 ptro = pass->expected = grub_malloc (pass->buflen);
146 if (!ptro)
147 {
148 grub_free (pass->salt);
149 grub_free (pass);
150 return grub_errno;
151 }
152 ptr = ptr2 + 1;
153 ptr2 += grub_strlen (ptr2);
154 while (ptr < ptr2)
155 {
156 int hex1, hex2;
157 hex1 = hex2val (*ptr);
158 ptr++;
159 hex2 = hex2val (*ptr);
160 ptr++;
161 if (hex1 < 0 || hex2 < 0)
162 {
163 grub_free (pass->expected);
164 grub_free (pass->salt);
165 grub_free (pass);
166 return grub_error (GRUB_ERR_BAD_ARGUMENT,
167 "Incorrect PBKDF2 password.");
168 }
169
170 *ptro = (hex1 << 4) | hex2;
171 ptro++;
172 }
173
174 err = grub_auth_register_authentication (args[0], check_password, pass);
175 if (err)
176 {
177 grub_free (pass);
178 return err;
179 }
180 grub_dl_ref (my_mod);
181 return GRUB_ERR_NONE;
182 }
183
184 static grub_command_t cmd;
185 \f
186 GRUB_MOD_INIT(password_pbkdf2)
187 {
188 my_mod = mod;
189 cmd = grub_register_command ("password_pbkdf2", grub_cmd_password,
190 N_("USER PBKDF2_PASSWORD"),
191 N_("Set user password (PBKDF2). "));
192 }
193
194 GRUB_MOD_FINI(password_pbkdf2)
195 {
196 grub_unregister_command (cmd);
197 }