]> git.proxmox.com Git - swtpm.git/blame - src/swtpm/key.c
swtpm: Implement read_eintr() to read into a buffer and handle EINTR
[swtpm.git] / src / swtpm / key.c
CommitLineData
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"
f163b202 54
58548ac6
SB
55/*
56 * key_format_from_string:
57 * Convert the string into a key format identifier
58 * @format: either 'hex' or 'binary'
59 *
60 * Returns a key format identifier
61 */
f163b202
SB
62enum key_format
63key_format_from_string(const char *format)
64{
65 if (!strcmp(format, "hex")) {
66 return KEY_FORMAT_HEX;
67 } else if (!strcmp(format, "binary")) {
68 return KEY_FORMAT_BINARY;
69 }
cba81569 70 logprintf(STDERR_FILENO, "Unknown key format '%s'.\n", format);
f163b202
SB
71
72 return KEY_FORMAT_UNKNOWN;
73}
74
58548ac6
SB
75/*
76 * encryption_mode_from_string:
77 * Convert the string into a encryption mode identifier
78 * @mode: string describing encryption mode
68a5b241 79 * @keylen: the length of the key in bytes
58548ac6
SB
80 *
81 * Returns an encryption mode identifier
82 */
f163b202 83enum encryption_mode
68a5b241 84encryption_mode_from_string(const char *mode, size_t *keylen)
f163b202 85{
68a5b241
SB
86 if (!strcmp(mode, "aes-cbc") || !strcmp(mode, "aes-128-cbc")) {
87 *keylen = 128/8;
88 return ENCRYPTION_MODE_AES_CBC;
89 } else if (!strcmp(mode, "aes-256-cbc")) {
90 *keylen = 256/8;
f163b202
SB
91 return ENCRYPTION_MODE_AES_CBC;
92 }
93
94 return ENCRYPTION_MODE_UNKNOWN;
95}
96
a39f098f
SB
97/*
98 * kdf_identifier_from_string:
99 * Convert the string in a kdf identifier
100 * @mode: string describing the kdf
101 *
102 * Return a kdf identifier
103 */
104enum kdf_identifier
105kdf_identifier_from_string(const char *kdf)
106{
107 if (!strcmp(kdf, "sha512")) {
108 return KDF_IDENTIFIER_SHA512;
109 } else if (!strcmp(kdf, "pbkdf2")) {
110 return KDF_IDENTIFIER_PBKDF2;
111 }
112
113 return KDF_IDENTIFIER_UNKNOWN;
114}
115
58548ac6
SB
116/*
117 * key_stream_to_bin
118 * Convert a stream of ASCII hex digits into a key; convert a maximum of
119 * bin_size bytes;
120 *
121 * @input: input data holding hex digits
122 * @bin: output field of bin_size
123 * @bin_size: max. number of bytes to convert
124 *
125 * Returns the number of digits that were converted.
126 */
f163b202
SB
127static ssize_t
128key_stream_to_bin(const char *input, unsigned char *bin, size_t bin_size)
129{
130 ssize_t digits = 0;
131 int n, num;
132
133 while (input[digits] &&
134 !isspace(input[digits]) &&
135 bin_size > (size_t)digits / 2) {
136 num = sscanf(&input[digits], "%2hhx%n", &bin[digits/2], &n);
137 if (num != 1 || n != 2)
138 return -1;
139 digits += 2;
140 }
141
142 if (input[digits] && !isspace(input[digits]))
143 return -1;
144
145 return (digits != 0) ? digits : -1;
146}
147
58548ac6
SB
148/*
149 * key_parse_as_hexkey:
150 * Parse the raw key data as a key in ASCII hex format; they key may
151 * have a leading '0x'.
152 * @rawkey: ASCII data for a hex key with possible leading '0x'
153 * @key: buffer for key
154 * @keylen: actual key len returned by this function
155 * @maxkeylen: the max. size of the key; this is equivalent to the size of
156 * the key buffer
157 * Returns 0 on success, -1 on failure
158 */
f163b202
SB
159static int
160key_parse_as_hexkey(const char *rawkey,
161 unsigned char *key, size_t *keylen, size_t maxkeylen)
162{
163 ssize_t digits;
164 off_t offset = 0;
165
166 if (!strncmp(rawkey, "0x", 2))
167 offset = 2;
168
169 digits = key_stream_to_bin(&rawkey[offset], key, maxkeylen);
170 if (digits < 0) {
cba81569
SB
171 logprintf(STDERR_FILENO,
172 "Could not parse key hex string into %zu byte buffer.\n",
173 maxkeylen);
f163b202
SB
174 return -1;
175 } else if (digits == 128/4) {
176 *keylen = 128/8;
748df6ee
SB
177 } else if (digits == 256/4) {
178 *keylen = 256/8;
f163b202 179 } else {
cba81569
SB
180 logprintf(STDERR_FILENO,
181 "Unsupported key length with %zu digits.\n",
182 digits);
f163b202
SB
183 return -1;
184 }
748df6ee
SB
185 if (*keylen < maxkeylen) {
186 logprintf(STDERR_FILENO,
187 "The provided key is too short. Got %zu bytes, need %zu.\n",
188 *keylen, maxkeylen);
189 return -1;
190 }
f163b202
SB
191
192 return 0;
193}
194
58548ac6 195/*
f4be1e86 196 * key_load_key_fd:
58548ac6 197 * Load the raw key data from a file and convert it to a key.
f4be1e86 198 * @fd: file descriptor to read raw key data from
58548ac6
SB
199 * @keyformat: the format the raw key data are in; may either indicate
200 * binary data or hex string
201 * @key: the buffer for holding the converted key
202 * @keylen: the actual key len of the converted key returned by this
203 * function
204 * @maxkeylen: the max. size of the key; corresponds to the size of the
205 * key buffer
206 */
f163b202 207int
f4be1e86
SB
208key_load_key_fd(int fd, enum key_format keyformat,
209 unsigned char *key, size_t *keylen, size_t maxkeylen)
f163b202
SB
210{
211 int ret = -1;
748df6ee 212 char filebuffer[2 + 256/4 + 1 + 1];
da521f04 213 ssize_t len;
f163b202 214
f163b202 215 len = read(fd, filebuffer, sizeof(filebuffer) - 1);
f163b202 216 if (len < 0) {
cba81569
SB
217 logprintf(STDERR_FILENO, "Unable to read key: %s\n",
218 strerror(errno));
f163b202
SB
219 return -1;
220 }
221 filebuffer[len] = 0;
222
223 switch (keyformat) {
224 case KEY_FORMAT_BINARY:
225 *keylen = len;
da521f04 226 if (maxkeylen < (size_t)len) {
cba81569
SB
227 logprintf(STDERR_FILENO,
228 "Key is larger than buffer (%zu > %zu).\n",
229 len, maxkeylen);
f163b202
SB
230 return -1;
231 }
232 memcpy(key, filebuffer, len);
233 ret = 0;
234 break;
235 case KEY_FORMAT_HEX:
236 if (key_parse_as_hexkey(filebuffer, key, keylen, maxkeylen) < 0)
237 return -1;
238 ret = 0;
239 break;
240 case KEY_FORMAT_UNKNOWN:
241 break;
242 }
243
244 return ret;
245}
f4be1e86
SB
246/*
247 * key_load_key:
248 * Load the raw key data from a file and convert it to a key.
249 * @filename: file holding the raw key data
250 * @keyformat: the format the raw key data are in; may either indicate
251 * binary data or hex string
252 * @key: the buffer for holding the converted key
253 * @keylen: the actual key len of the converted key returned by this
254 * function
255 * @maxkeylen: the max. size of the key; corresponds to the size of the
256 * key buffer
257 */
258int
259key_load_key(const char *filename, enum key_format keyformat,
260 unsigned char *key, size_t *keylen, size_t maxkeylen)
261{
262 int ret;
263 int fd;
264
265 fd = open(filename, O_RDONLY);
266 if (fd < 0) {
267 logprintf(STDERR_FILENO, "Unable to open file %s: %s\n",
268 filename, strerror(errno));
269 return -1;
270 }
271 ret = key_load_key_fd(fd, keyformat, key, keylen, maxkeylen);
272
273 close(fd);
274
275 return ret;
276}
f163b202 277
58548ac6
SB
278/*
279 * key_from_pwdfile:
a947bebd
SB
280 * Read the password from the given file descriptor, convert the password into
281 * a key by applying a KDF on the password and use the first bytes
58548ac6 282 * of the hash as the key.
a947bebd 283 * @fd: file descriptor to read password from
58548ac6 284 * @key: the buffer for holding the key
58548ac6
SB
285 * @keylen: the actual key len of the converted key returned by this
286 * function
287 * @maxkeylen: the max. size of the key; corresponds to the size of the
288 * key buffer
a39f098f 289 * @kdfid: the kdf to invoke to create the key
58548ac6 290 */
f163b202 291int
a947bebd
SB
292key_from_pwdfile_fd(int fd, unsigned char *key, size_t *keylen,
293 size_t maxkeylen, enum kdf_identifier kdfid)
f163b202 294{
a39f098f 295 unsigned char *filebuffer = NULL;
e7fb07e8
SB
296 size_t filelen = 1024;
297 off_t offset = 0;
0268ef45 298 ssize_t len;
3bbdd7bc 299 unsigned char hashbuf[SHA512_DIGEST_LENGTH];
a39f098f
SB
300 int ret = -1;
301 const unsigned char salt[] = {'s','w','t','p','m'};
f163b202
SB
302
303 if (maxkeylen > sizeof(hashbuf)) {
cba81569
SB
304 logprintf(STDERR_FILENO,
305 "Request keylength is too big (%zu > %zu)\n",
306 maxkeylen, sizeof(hashbuf));
f163b202
SB
307 return -1;
308 }
309
e7fb07e8
SB
310 while (true) {
311 filebuffer = realloc(filebuffer, filelen);
312 if (!filebuffer) {
313 logprintf(STDERR_FILENO,
314 "Could not allocate %zu bytes for filebuffer\n",
315 filelen);
316 goto exit;
317 }
a39f098f 318
e7fb07e8
SB
319 len = read(fd, &filebuffer[offset], filelen - offset);
320 if (len < 0) {
321 logprintf(STDERR_FILENO,
322 "Unable to read passphrase: %s\n",
323 strerror(errno));
324 goto exit;
325 }
326 /* EOF ? */
327 if ((size_t)len < filelen - offset) {
328 len += offset;
329 break;
330 }
331 /* expecting more bytes */
332 offset += len;
333 filelen += 1024;
f163b202
SB
334 }
335
f163b202 336 *keylen = maxkeylen;
f163b202 337
a39f098f
SB
338 switch (kdfid) {
339 case KDF_IDENTIFIER_SHA512:
748df6ee
SB
340 if (sizeof(hashbuf) < *keylen) {
341 logprintf(STDERR_FILENO,
342 "Requested %zu bytes for key, only got %zu.\n",
343 *keylen, sizeof(hashbuf));
a947bebd 344 goto exit;
748df6ee 345 }
63717f99 346 SHA512(filebuffer, len, hashbuf);
a39f098f
SB
347 memcpy(key, hashbuf, *keylen);
348 break;
349 case KDF_IDENTIFIER_PBKDF2:
350 if (PKCS5_PBKDF2_HMAC((const char *)filebuffer, len,
351 salt, sizeof(salt), 1000,
352 EVP_sha512(), *keylen, key) != 1) {
353 logprintf(STDERR_FILENO,
354 "PKCS5_PBKDF2_HMAC with SHA512 failed\n");
a947bebd 355 goto exit;
a39f098f
SB
356 }
357 break;
358 case KDF_IDENTIFIER_UNKNOWN:
359 logprintf(STDERR_FILENO,
360 "Unknown KDF\n");
a947bebd 361 goto exit;
a39f098f
SB
362 }
363
a947bebd 364 ret = 0;
a39f098f 365
a947bebd 366exit:
a39f098f
SB
367
368 free(filebuffer);
369
370 return ret;
f163b202 371}
a947bebd
SB
372
373/*
374 * key_from_pwdfile:
375 * Read the password from the given file, convert the password into
376 * a key by applying a KDF on the password and use the first bytes
377 * of the hash as the key.
378 * @filename: name of the file holding the password
379 * @key: the buffer for holding the key
380 * @keylen: the actual key len of the converted key returned by this
381 * function
382 * @maxkeylen: the max. size of the key; corresponds to the size of the
383 * key buffer
384 * @kdfid: the kdf to invoke to create the key
385 */
386int
387key_from_pwdfile(const char *filename, unsigned char *key, size_t *keylen,
388 size_t maxkeylen, enum kdf_identifier kdfid)
389{
390 int ret;
391 int fd;
392
393 fd = open(filename, O_RDONLY);
394 if (fd < 0) {
395 logprintf(STDERR_FILENO,
396 "Unable to open file %s : %s\n",
397 filename, strerror(errno));
398 return -1;
399 }
400
401 ret = key_from_pwdfile_fd(fd, key, keylen, maxkeylen, kdfid);
402
403 close(fd);
404
405 return ret;
406}