]>
Commit | Line | Data |
---|---|---|
0cf66b0f EB |
1 | /* |
2 | * Copyright (c) 2016 Google, Inc. All Rights Reserved. | |
3 | * | |
4 | * Author: Eric Biggers <ebiggers@google.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it would 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 this program; if not, write the Free Software Foundation, | |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | #include "platform_defs.h" | |
21 | #include "command.h" | |
22 | #include "init.h" | |
3fcab549 | 23 | #include "path.h" |
0cf66b0f EB |
24 | #include "io.h" |
25 | ||
26 | #ifndef ARRAY_SIZE | |
27 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | |
28 | #endif | |
29 | ||
30 | /* | |
31 | * We may have to declare the fscrypt ioctls ourselves because someone may be | |
32 | * compiling xfsprogs with old kernel headers. And since some old versions of | |
33 | * <linux/fs.h> declared the policy struct and ioctl numbers but not the flags | |
34 | * and modes, our declarations must be split into two conditional blocks. | |
35 | */ | |
36 | ||
37 | /* Policy struct and ioctl numbers */ | |
38 | #ifndef FS_IOC_SET_ENCRYPTION_POLICY | |
39 | #define FS_KEY_DESCRIPTOR_SIZE 8 | |
40 | ||
41 | struct fscrypt_policy { | |
42 | __u8 version; | |
43 | __u8 contents_encryption_mode; | |
44 | __u8 filenames_encryption_mode; | |
45 | __u8 flags; | |
46 | __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; | |
47 | } __attribute__((packed)); | |
48 | ||
49 | #define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy) | |
50 | #define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) | |
51 | #define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy) | |
52 | #endif /* FS_IOC_SET_ENCRYPTION_POLICY */ | |
53 | ||
54 | /* Policy flags and encryption modes */ | |
55 | #ifndef FS_ENCRYPTION_MODE_AES_256_XTS | |
56 | #define FS_POLICY_FLAGS_PAD_4 0x00 | |
57 | #define FS_POLICY_FLAGS_PAD_8 0x01 | |
58 | #define FS_POLICY_FLAGS_PAD_16 0x02 | |
59 | #define FS_POLICY_FLAGS_PAD_32 0x03 | |
60 | #define FS_POLICY_FLAGS_PAD_MASK 0x03 | |
61 | #define FS_POLICY_FLAGS_VALID 0x03 | |
62 | ||
63 | #define FS_ENCRYPTION_MODE_INVALID 0 | |
64 | #define FS_ENCRYPTION_MODE_AES_256_XTS 1 | |
65 | #define FS_ENCRYPTION_MODE_AES_256_GCM 2 | |
66 | #define FS_ENCRYPTION_MODE_AES_256_CBC 3 | |
67 | #define FS_ENCRYPTION_MODE_AES_256_CTS 4 | |
68 | #endif /* FS_ENCRYPTION_MODE_AES_256_XTS */ | |
69 | ||
70 | static cmdinfo_t get_encpolicy_cmd; | |
71 | static cmdinfo_t set_encpolicy_cmd; | |
72 | ||
73 | static void | |
74 | set_encpolicy_help(void) | |
75 | { | |
76 | printf(_( | |
77 | "\n" | |
78 | " assign an encryption policy to the currently open file\n" | |
79 | "\n" | |
80 | " Examples:\n" | |
81 | " 'set_encpolicy' - assign policy with default key [0000000000000000]\n" | |
82 | " 'set_encpolicy 0000111122223333' - assign policy with specified key\n" | |
83 | "\n" | |
84 | " -c MODE -- contents encryption mode\n" | |
85 | " -n MODE -- filenames encryption mode\n" | |
86 | " -f FLAGS -- policy flags\n" | |
87 | " -v VERSION -- version of policy structure\n" | |
88 | "\n" | |
89 | " MODE can be numeric or one of the following predefined values:\n" | |
90 | " AES-256-XTS, AES-256-CTS, AES-256-GCM, AES-256-CBC\n" | |
91 | " FLAGS and VERSION must be numeric.\n" | |
92 | "\n" | |
93 | " Note that it's only possible to set an encryption policy on an empty\n" | |
94 | " directory. It's then inherited by new files and subdirectories.\n" | |
95 | "\n")); | |
96 | } | |
97 | ||
98 | static const struct { | |
99 | __u8 mode; | |
100 | const char *name; | |
101 | } available_modes[] = { | |
102 | {FS_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"}, | |
103 | {FS_ENCRYPTION_MODE_AES_256_CTS, "AES-256-CTS"}, | |
104 | {FS_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"}, | |
105 | {FS_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"}, | |
106 | }; | |
107 | ||
108 | static bool | |
109 | parse_byte_value(const char *arg, __u8 *value_ret) | |
110 | { | |
111 | long value; | |
112 | char *tmp; | |
113 | ||
114 | value = strtol(arg, &tmp, 0); | |
115 | if (value < 0 || value > 255 || tmp == arg || *tmp != '\0') | |
116 | return false; | |
117 | *value_ret = value; | |
118 | return true; | |
119 | } | |
120 | ||
121 | static bool | |
122 | parse_mode(const char *arg, __u8 *mode_ret) | |
123 | { | |
124 | int i; | |
125 | ||
126 | for (i = 0; i < ARRAY_SIZE(available_modes); i++) { | |
127 | if (strcmp(arg, available_modes[i].name) == 0) { | |
128 | *mode_ret = available_modes[i].mode; | |
129 | return true; | |
130 | } | |
131 | } | |
132 | ||
133 | return parse_byte_value(arg, mode_ret); | |
134 | } | |
135 | ||
136 | static const char * | |
137 | mode2str(__u8 mode) | |
138 | { | |
139 | static char buf[32]; | |
140 | int i; | |
141 | ||
142 | for (i = 0; i < ARRAY_SIZE(available_modes); i++) | |
143 | if (mode == available_modes[i].mode) | |
144 | return available_modes[i].name; | |
145 | ||
146 | sprintf(buf, "0x%02x", mode); | |
147 | return buf; | |
148 | } | |
149 | ||
150 | static const char * | |
151 | keydesc2str(__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]) | |
152 | { | |
153 | static char buf[2 * FS_KEY_DESCRIPTOR_SIZE + 1]; | |
154 | int i; | |
155 | ||
156 | for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) | |
157 | sprintf(&buf[2 * i], "%02x", master_key_descriptor[i]); | |
158 | ||
159 | return buf; | |
160 | } | |
161 | ||
162 | static int | |
163 | get_encpolicy_f(int argc, char **argv) | |
164 | { | |
165 | struct fscrypt_policy policy; | |
166 | ||
167 | if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) < 0) { | |
168 | fprintf(stderr, "%s: failed to get encryption policy: %s\n", | |
169 | file->name, strerror(errno)); | |
170 | exitcode = 1; | |
171 | return 0; | |
172 | } | |
173 | ||
174 | printf("Encryption policy for %s:\n", file->name); | |
175 | printf("\tPolicy version: %u\n", policy.version); | |
176 | printf("\tMaster key descriptor: %s\n", | |
177 | keydesc2str(policy.master_key_descriptor)); | |
178 | printf("\tContents encryption mode: %u (%s)\n", | |
179 | policy.contents_encryption_mode, | |
180 | mode2str(policy.contents_encryption_mode)); | |
181 | printf("\tFilenames encryption mode: %u (%s)\n", | |
182 | policy.filenames_encryption_mode, | |
183 | mode2str(policy.filenames_encryption_mode)); | |
184 | printf("\tFlags: 0x%02x\n", policy.flags); | |
185 | return 0; | |
186 | } | |
187 | ||
188 | static int | |
189 | set_encpolicy_f(int argc, char **argv) | |
190 | { | |
191 | int c; | |
192 | struct fscrypt_policy policy; | |
193 | ||
194 | /* Initialize the policy structure with default values */ | |
195 | memset(&policy, 0, sizeof(policy)); | |
196 | policy.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; | |
197 | policy.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; | |
198 | policy.flags = FS_POLICY_FLAGS_PAD_16; | |
199 | ||
200 | /* Parse options */ | |
201 | while ((c = getopt(argc, argv, "c:n:f:v:")) != EOF) { | |
202 | switch (c) { | |
203 | case 'c': | |
204 | if (!parse_mode(optarg, | |
205 | &policy.contents_encryption_mode)) { | |
206 | fprintf(stderr, "invalid contents encryption " | |
207 | "mode: %s\n", optarg); | |
208 | return 0; | |
209 | } | |
210 | break; | |
211 | case 'n': | |
212 | if (!parse_mode(optarg, | |
213 | &policy.filenames_encryption_mode)) { | |
214 | fprintf(stderr, "invalid filenames encryption " | |
215 | "mode: %s\n", optarg); | |
216 | return 0; | |
217 | } | |
218 | break; | |
219 | case 'f': | |
220 | if (!parse_byte_value(optarg, &policy.flags)) { | |
221 | fprintf(stderr, "invalid flags: %s\n", optarg); | |
222 | return 0; | |
223 | } | |
224 | break; | |
225 | case 'v': | |
226 | if (!parse_byte_value(optarg, &policy.version)) { | |
227 | fprintf(stderr, "invalid policy version: %s\n", | |
228 | optarg); | |
229 | return 0; | |
230 | } | |
231 | break; | |
232 | default: | |
233 | return command_usage(&set_encpolicy_cmd); | |
234 | } | |
235 | } | |
236 | argc -= optind; | |
237 | argv += optind; | |
238 | ||
239 | if (argc > 1) | |
240 | return command_usage(&set_encpolicy_cmd); | |
241 | ||
242 | /* Parse key descriptor if specified */ | |
243 | if (argc > 0) { | |
244 | const char *keydesc = argv[0]; | |
245 | char *tmp; | |
246 | unsigned long long x; | |
247 | int i; | |
248 | ||
249 | if (strlen(keydesc) != FS_KEY_DESCRIPTOR_SIZE * 2) { | |
250 | fprintf(stderr, "invalid key descriptor: %s\n", | |
251 | keydesc); | |
252 | return 0; | |
253 | } | |
254 | ||
255 | x = strtoull(keydesc, &tmp, 16); | |
256 | if (tmp == keydesc || *tmp != '\0') { | |
257 | fprintf(stderr, "invalid key descriptor: %s\n", | |
258 | keydesc); | |
259 | return 0; | |
260 | } | |
261 | ||
262 | for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) { | |
263 | policy.master_key_descriptor[i] = x >> 56; | |
264 | x <<= 8; | |
265 | } | |
266 | } | |
267 | ||
268 | /* Set the encryption policy */ | |
269 | if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) < 0) { | |
270 | fprintf(stderr, "%s: failed to set encryption policy: %s\n", | |
271 | file->name, strerror(errno)); | |
272 | exitcode = 1; | |
273 | return 0; | |
274 | } | |
275 | ||
276 | return 0; | |
277 | } | |
278 | ||
279 | void | |
280 | encrypt_init(void) | |
281 | { | |
282 | get_encpolicy_cmd.name = "get_encpolicy"; | |
283 | get_encpolicy_cmd.cfunc = get_encpolicy_f; | |
284 | get_encpolicy_cmd.argmin = 0; | |
285 | get_encpolicy_cmd.argmax = 0; | |
286 | get_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; | |
287 | get_encpolicy_cmd.oneline = | |
288 | _("display the encryption policy of the current file"); | |
289 | ||
290 | set_encpolicy_cmd.name = "set_encpolicy"; | |
291 | set_encpolicy_cmd.cfunc = set_encpolicy_f; | |
292 | set_encpolicy_cmd.args = | |
293 | _("[-c mode] [-n mode] [-f flags] [-v version] [keydesc]"); | |
294 | set_encpolicy_cmd.argmin = 0; | |
295 | set_encpolicy_cmd.argmax = -1; | |
296 | set_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; | |
297 | set_encpolicy_cmd.oneline = | |
298 | _("assign an encryption policy to the current file"); | |
299 | set_encpolicy_cmd.help = set_encpolicy_help; | |
300 | ||
301 | add_command(&get_encpolicy_cmd); | |
302 | add_command(&set_encpolicy_cmd); | |
303 | } |