]>
Commit | Line | Data |
---|---|---|
f163b202 SB |
1 | /* |
2 | * key.c -- Common key handling code for swtpm and swtpm_cuse | |
3 | * | |
ad976d1a | 4 | * (c) Copyright IBM Corporation 2014, 2015. |
f163b202 SB |
5 | * |
6 | * Author: Stefan Berger <stefanb@us.ibm.com> | |
7 | * | |
8 | * All rights reserved. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions are | |
12 | * met: | |
13 | * | |
14 | * Redistributions of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the names of the IBM Corporation nor the names of its | |
22 | * contributors may be used to endorse or promote products derived from | |
23 | * this software without specific prior written permission. | |
24 | * | |
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
29 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
36 | */ | |
37 | ||
38 | #include "config.h" | |
39 | ||
7849b6c6 | 40 | #include <openssl/sha.h> |
a39f098f | 41 | #include <openssl/evp.h> |
f163b202 SB |
42 | |
43 | #include <ctype.h> | |
44 | #include <errno.h> | |
45 | #include <fcntl.h> | |
46 | #include <string.h> | |
47 | #include <stdio.h> | |
a39f098f | 48 | #include <stdlib.h> |
f163b202 SB |
49 | #include <unistd.h> |
50 | #include <sys/types.h> | |
f163b202 SB |
51 | |
52 | #include "key.h" | |
cba81569 | 53 | #include "logging.h" |
a442092d | 54 | #include "utils.h" |
f163b202 | 55 | |
58548ac6 SB |
56 | /* |
57 | * key_format_from_string: | |
58 | * Convert the string into a key format identifier | |
59 | * @format: either 'hex' or 'binary' | |
60 | * | |
61 | * Returns a key format identifier | |
62 | */ | |
f163b202 SB |
63 | enum key_format |
64 | key_format_from_string(const char *format) | |
65 | { | |
66 | if (!strcmp(format, "hex")) { | |
67 | return KEY_FORMAT_HEX; | |
68 | } else if (!strcmp(format, "binary")) { | |
69 | return KEY_FORMAT_BINARY; | |
70 | } | |
cba81569 | 71 | logprintf(STDERR_FILENO, "Unknown key format '%s'.\n", format); |
f163b202 SB |
72 | |
73 | return KEY_FORMAT_UNKNOWN; | |
74 | } | |
75 | ||
58548ac6 SB |
76 | /* |
77 | * encryption_mode_from_string: | |
78 | * Convert the string into a encryption mode identifier | |
79 | * @mode: string describing encryption mode | |
68a5b241 | 80 | * @keylen: the length of the key in bytes |
58548ac6 SB |
81 | * |
82 | * Returns an encryption mode identifier | |
83 | */ | |
f163b202 | 84 | enum encryption_mode |
68a5b241 | 85 | encryption_mode_from_string(const char *mode, size_t *keylen) |
f163b202 | 86 | { |
68a5b241 SB |
87 | if (!strcmp(mode, "aes-cbc") || !strcmp(mode, "aes-128-cbc")) { |
88 | *keylen = 128/8; | |
89 | return ENCRYPTION_MODE_AES_CBC; | |
90 | } else if (!strcmp(mode, "aes-256-cbc")) { | |
91 | *keylen = 256/8; | |
f163b202 SB |
92 | return ENCRYPTION_MODE_AES_CBC; |
93 | } | |
94 | ||
95 | return ENCRYPTION_MODE_UNKNOWN; | |
96 | } | |
97 | ||
a39f098f SB |
98 | /* |
99 | * kdf_identifier_from_string: | |
100 | * Convert the string in a kdf identifier | |
101 | * @mode: string describing the kdf | |
102 | * | |
103 | * Return a kdf identifier | |
104 | */ | |
105 | enum kdf_identifier | |
106 | kdf_identifier_from_string(const char *kdf) | |
107 | { | |
108 | if (!strcmp(kdf, "sha512")) { | |
109 | return KDF_IDENTIFIER_SHA512; | |
110 | } else if (!strcmp(kdf, "pbkdf2")) { | |
111 | return KDF_IDENTIFIER_PBKDF2; | |
112 | } | |
113 | ||
114 | return KDF_IDENTIFIER_UNKNOWN; | |
115 | } | |
116 | ||
58548ac6 SB |
117 | /* |
118 | * key_stream_to_bin | |
119 | * Convert a stream of ASCII hex digits into a key; convert a maximum of | |
120 | * bin_size bytes; | |
121 | * | |
122 | * @input: input data holding hex digits | |
123 | * @bin: output field of bin_size | |
124 | * @bin_size: max. number of bytes to convert | |
125 | * | |
126 | * Returns the number of digits that were converted. | |
127 | */ | |
f163b202 SB |
128 | static ssize_t |
129 | key_stream_to_bin(const char *input, unsigned char *bin, size_t bin_size) | |
130 | { | |
131 | ssize_t digits = 0; | |
132 | int n, num; | |
133 | ||
134 | while (input[digits] && | |
dd92f458 | 135 | !isspace((int)input[digits]) && |
f163b202 SB |
136 | bin_size > (size_t)digits / 2) { |
137 | num = sscanf(&input[digits], "%2hhx%n", &bin[digits/2], &n); | |
138 | if (num != 1 || n != 2) | |
139 | return -1; | |
140 | digits += 2; | |
141 | } | |
142 | ||
dd92f458 | 143 | if (input[digits] && !isspace((int)input[digits])) |
f163b202 SB |
144 | return -1; |
145 | ||
146 | return (digits != 0) ? digits : -1; | |
147 | } | |
148 | ||
58548ac6 SB |
149 | /* |
150 | * key_parse_as_hexkey: | |
151 | * Parse the raw key data as a key in ASCII hex format; they key may | |
152 | * have a leading '0x'. | |
153 | * @rawkey: ASCII data for a hex key with possible leading '0x' | |
154 | * @key: buffer for key | |
155 | * @keylen: actual key len returned by this function | |
156 | * @maxkeylen: the max. size of the key; this is equivalent to the size of | |
157 | * the key buffer | |
158 | * Returns 0 on success, -1 on failure | |
159 | */ | |
f163b202 SB |
160 | static int |
161 | key_parse_as_hexkey(const char *rawkey, | |
162 | unsigned char *key, size_t *keylen, size_t maxkeylen) | |
163 | { | |
164 | ssize_t digits; | |
165 | off_t offset = 0; | |
166 | ||
167 | if (!strncmp(rawkey, "0x", 2)) | |
168 | offset = 2; | |
169 | ||
170 | digits = key_stream_to_bin(&rawkey[offset], key, maxkeylen); | |
171 | if (digits < 0) { | |
cba81569 SB |
172 | logprintf(STDERR_FILENO, |
173 | "Could not parse key hex string into %zu byte buffer.\n", | |
174 | maxkeylen); | |
f163b202 SB |
175 | return -1; |
176 | } else if (digits == 128/4) { | |
177 | *keylen = 128/8; | |
748df6ee SB |
178 | } else if (digits == 256/4) { |
179 | *keylen = 256/8; | |
f163b202 | 180 | } else { |
cba81569 SB |
181 | logprintf(STDERR_FILENO, |
182 | "Unsupported key length with %zu digits.\n", | |
183 | digits); | |
f163b202 SB |
184 | return -1; |
185 | } | |
748df6ee SB |
186 | if (*keylen < maxkeylen) { |
187 | logprintf(STDERR_FILENO, | |
188 | "The provided key is too short. Got %zu bytes, need %zu.\n", | |
189 | *keylen, maxkeylen); | |
190 | return -1; | |
191 | } | |
f163b202 SB |
192 | |
193 | return 0; | |
194 | } | |
195 | ||
58548ac6 | 196 | /* |
f4be1e86 | 197 | * key_load_key_fd: |
58548ac6 | 198 | * Load the raw key data from a file and convert it to a key. |
f4be1e86 | 199 | * @fd: file descriptor to read raw key data from |
58548ac6 SB |
200 | * @keyformat: the format the raw key data are in; may either indicate |
201 | * binary data or hex string | |
202 | * @key: the buffer for holding the converted key | |
203 | * @keylen: the actual key len of the converted key returned by this | |
204 | * function | |
205 | * @maxkeylen: the max. size of the key; corresponds to the size of the | |
206 | * key buffer | |
207 | */ | |
f163b202 | 208 | int |
f4be1e86 SB |
209 | key_load_key_fd(int fd, enum key_format keyformat, |
210 | unsigned char *key, size_t *keylen, size_t maxkeylen) | |
f163b202 SB |
211 | { |
212 | int ret = -1; | |
748df6ee | 213 | char filebuffer[2 + 256/4 + 1 + 1]; |
da521f04 | 214 | ssize_t len; |
f163b202 | 215 | |
a442092d | 216 | len = read_eintr(fd, filebuffer, sizeof(filebuffer) - 1); |
f163b202 | 217 | if (len < 0) { |
cba81569 SB |
218 | logprintf(STDERR_FILENO, "Unable to read key: %s\n", |
219 | strerror(errno)); | |
f163b202 SB |
220 | return -1; |
221 | } | |
222 | filebuffer[len] = 0; | |
223 | ||
224 | switch (keyformat) { | |
225 | case KEY_FORMAT_BINARY: | |
226 | *keylen = len; | |
da521f04 | 227 | if (maxkeylen < (size_t)len) { |
cba81569 SB |
228 | logprintf(STDERR_FILENO, |
229 | "Key is larger than buffer (%zu > %zu).\n", | |
230 | len, maxkeylen); | |
f163b202 SB |
231 | return -1; |
232 | } | |
233 | memcpy(key, filebuffer, len); | |
234 | ret = 0; | |
235 | break; | |
236 | case KEY_FORMAT_HEX: | |
237 | if (key_parse_as_hexkey(filebuffer, key, keylen, maxkeylen) < 0) | |
238 | return -1; | |
239 | ret = 0; | |
240 | break; | |
241 | case KEY_FORMAT_UNKNOWN: | |
242 | break; | |
243 | } | |
244 | ||
245 | return ret; | |
246 | } | |
f4be1e86 SB |
247 | /* |
248 | * key_load_key: | |
249 | * Load the raw key data from a file and convert it to a key. | |
250 | * @filename: file holding the raw key data | |
251 | * @keyformat: the format the raw key data are in; may either indicate | |
252 | * binary data or hex string | |
253 | * @key: the buffer for holding the converted key | |
254 | * @keylen: the actual key len of the converted key returned by this | |
255 | * function | |
256 | * @maxkeylen: the max. size of the key; corresponds to the size of the | |
257 | * key buffer | |
258 | */ | |
259 | int | |
260 | key_load_key(const char *filename, enum key_format keyformat, | |
261 | unsigned char *key, size_t *keylen, size_t maxkeylen) | |
262 | { | |
263 | int ret; | |
264 | int fd; | |
265 | ||
266 | fd = open(filename, O_RDONLY); | |
267 | if (fd < 0) { | |
268 | logprintf(STDERR_FILENO, "Unable to open file %s: %s\n", | |
269 | filename, strerror(errno)); | |
270 | return -1; | |
271 | } | |
272 | ret = key_load_key_fd(fd, keyformat, key, keylen, maxkeylen); | |
273 | ||
274 | close(fd); | |
275 | ||
276 | return ret; | |
277 | } | |
f163b202 | 278 | |
58548ac6 SB |
279 | /* |
280 | * key_from_pwdfile: | |
a947bebd SB |
281 | * Read the password from the given file descriptor, convert the password into |
282 | * a key by applying a KDF on the password and use the first bytes | |
58548ac6 | 283 | * of the hash as the key. |
a947bebd | 284 | * @fd: file descriptor to read password from |
58548ac6 | 285 | * @key: the buffer for holding the key |
58548ac6 SB |
286 | * @keylen: the actual key len of the converted key returned by this |
287 | * function | |
288 | * @maxkeylen: the max. size of the key; corresponds to the size of the | |
289 | * key buffer | |
a39f098f | 290 | * @kdfid: the kdf to invoke to create the key |
58548ac6 | 291 | */ |
f163b202 | 292 | int |
a947bebd SB |
293 | key_from_pwdfile_fd(int fd, unsigned char *key, size_t *keylen, |
294 | size_t maxkeylen, enum kdf_identifier kdfid) | |
f163b202 | 295 | { |
a39f098f | 296 | unsigned char *filebuffer = NULL; |
e7fb07e8 SB |
297 | size_t filelen = 1024; |
298 | off_t offset = 0; | |
0268ef45 | 299 | ssize_t len; |
3bbdd7bc | 300 | unsigned char hashbuf[SHA512_DIGEST_LENGTH]; |
a39f098f SB |
301 | int ret = -1; |
302 | const unsigned char salt[] = {'s','w','t','p','m'}; | |
f163b202 SB |
303 | |
304 | if (maxkeylen > sizeof(hashbuf)) { | |
cba81569 SB |
305 | logprintf(STDERR_FILENO, |
306 | "Request keylength is too big (%zu > %zu)\n", | |
307 | maxkeylen, sizeof(hashbuf)); | |
f163b202 SB |
308 | return -1; |
309 | } | |
310 | ||
e7fb07e8 | 311 | while (true) { |
4450856d SB |
312 | unsigned char *tmp = filebuffer; |
313 | ||
314 | filebuffer = realloc(tmp, filelen); | |
e7fb07e8 SB |
315 | if (!filebuffer) { |
316 | logprintf(STDERR_FILENO, | |
317 | "Could not allocate %zu bytes for filebuffer\n", | |
318 | filelen); | |
4450856d | 319 | free(tmp); |
e7fb07e8 SB |
320 | goto exit; |
321 | } | |
a39f098f | 322 | |
a442092d | 323 | len = read_eintr(fd, &filebuffer[offset], filelen - offset); |
e7fb07e8 SB |
324 | if (len < 0) { |
325 | logprintf(STDERR_FILENO, | |
326 | "Unable to read passphrase: %s\n", | |
327 | strerror(errno)); | |
87ce53ff | 328 | goto err_free_buffer; |
e7fb07e8 SB |
329 | } |
330 | /* EOF ? */ | |
331 | if ((size_t)len < filelen - offset) { | |
332 | len += offset; | |
333 | break; | |
334 | } | |
335 | /* expecting more bytes */ | |
336 | offset += len; | |
337 | filelen += 1024; | |
f163b202 SB |
338 | } |
339 | ||
f163b202 | 340 | *keylen = maxkeylen; |
f163b202 | 341 | |
a39f098f SB |
342 | switch (kdfid) { |
343 | case KDF_IDENTIFIER_SHA512: | |
748df6ee SB |
344 | if (sizeof(hashbuf) < *keylen) { |
345 | logprintf(STDERR_FILENO, | |
346 | "Requested %zu bytes for key, only got %zu.\n", | |
347 | *keylen, sizeof(hashbuf)); | |
87ce53ff | 348 | goto err_free_buffer; |
748df6ee | 349 | } |
63717f99 | 350 | SHA512(filebuffer, len, hashbuf); |
a39f098f SB |
351 | memcpy(key, hashbuf, *keylen); |
352 | break; | |
353 | case KDF_IDENTIFIER_PBKDF2: | |
354 | if (PKCS5_PBKDF2_HMAC((const char *)filebuffer, len, | |
355 | salt, sizeof(salt), 1000, | |
356 | EVP_sha512(), *keylen, key) != 1) { | |
357 | logprintf(STDERR_FILENO, | |
358 | "PKCS5_PBKDF2_HMAC with SHA512 failed\n"); | |
87ce53ff | 359 | goto err_free_buffer; |
a39f098f SB |
360 | } |
361 | break; | |
362 | case KDF_IDENTIFIER_UNKNOWN: | |
363 | logprintf(STDERR_FILENO, | |
364 | "Unknown KDF\n"); | |
87ce53ff | 365 | goto err_free_buffer; |
a39f098f SB |
366 | } |
367 | ||
a947bebd | 368 | ret = 0; |
a39f098f | 369 | |
87ce53ff | 370 | err_free_buffer: |
a39f098f SB |
371 | free(filebuffer); |
372 | ||
87ce53ff | 373 | exit: |
a39f098f | 374 | return ret; |
f163b202 | 375 | } |
a947bebd SB |
376 | |
377 | /* | |
378 | * key_from_pwdfile: | |
379 | * Read the password from the given file, convert the password into | |
380 | * a key by applying a KDF on the password and use the first bytes | |
381 | * of the hash as the key. | |
382 | * @filename: name of the file holding the password | |
383 | * @key: the buffer for holding the key | |
384 | * @keylen: the actual key len of the converted key returned by this | |
385 | * function | |
386 | * @maxkeylen: the max. size of the key; corresponds to the size of the | |
387 | * key buffer | |
388 | * @kdfid: the kdf to invoke to create the key | |
389 | */ | |
390 | int | |
391 | key_from_pwdfile(const char *filename, unsigned char *key, size_t *keylen, | |
392 | size_t maxkeylen, enum kdf_identifier kdfid) | |
393 | { | |
394 | int ret; | |
395 | int fd; | |
396 | ||
397 | fd = open(filename, O_RDONLY); | |
398 | if (fd < 0) { | |
399 | logprintf(STDERR_FILENO, | |
400 | "Unable to open file %s : %s\n", | |
401 | filename, strerror(errno)); | |
402 | return -1; | |
403 | } | |
404 | ||
405 | ret = key_from_pwdfile_fd(fd, key, keylen, maxkeylen, kdfid); | |
406 | ||
407 | close(fd); | |
408 | ||
409 | return ret; | |
410 | } |