xref: /openbmc/qemu/crypto/secret.c (revision 37677d7d)
1 /*
2  * QEMU crypto secret support
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "crypto/secret.h"
23 #include "crypto/cipher.h"
24 #include "qapi/error.h"
25 #include "qom/object_interfaces.h"
26 #include "qemu/base64.h"
27 #include "qemu/module.h"
28 #include "trace.h"
29 
30 
31 static void
32 qcrypto_secret_load_data(QCryptoSecret *secret,
33                          uint8_t **output,
34                          size_t *outputlen,
35                          Error **errp)
36 {
37     char *data = NULL;
38     size_t length = 0;
39     GError *gerr = NULL;
40 
41     *output = NULL;
42     *outputlen = 0;
43 
44     if (secret->file) {
45         if (secret->data) {
46             error_setg(errp,
47                        "'file' and 'data' are mutually exclusive");
48             return;
49         }
50         if (!g_file_get_contents(secret->file, &data, &length, &gerr)) {
51             error_setg(errp,
52                        "Unable to read %s: %s",
53                        secret->file, gerr->message);
54             g_error_free(gerr);
55             return;
56         }
57         *output = (uint8_t *)data;
58         *outputlen = length;
59     } else if (secret->data) {
60         *outputlen = strlen(secret->data);
61         *output = (uint8_t *)g_strdup(secret->data);
62     } else {
63         error_setg(errp, "Either 'file' or 'data' must be provided");
64     }
65 }
66 
67 
68 static void qcrypto_secret_decrypt(QCryptoSecret *secret,
69                                    const uint8_t *input,
70                                    size_t inputlen,
71                                    uint8_t **output,
72                                    size_t *outputlen,
73                                    Error **errp)
74 {
75     uint8_t *key = NULL, *ciphertext = NULL, *iv = NULL;
76     size_t keylen, ciphertextlen, ivlen;
77     QCryptoCipher *aes = NULL;
78     uint8_t *plaintext = NULL;
79 
80     *output = NULL;
81     *outputlen = 0;
82 
83     if (qcrypto_secret_lookup(secret->keyid,
84                               &key, &keylen,
85                               errp) < 0) {
86         goto cleanup;
87     }
88 
89     if (keylen != 32) {
90         error_setg(errp, "Key should be 32 bytes in length");
91         goto cleanup;
92     }
93 
94     if (!secret->iv) {
95         error_setg(errp, "IV is required to decrypt secret");
96         goto cleanup;
97     }
98 
99     iv = qbase64_decode(secret->iv, -1, &ivlen, errp);
100     if (!iv) {
101         goto cleanup;
102     }
103     if (ivlen != 16) {
104         error_setg(errp, "IV should be 16 bytes in length not %zu",
105                    ivlen);
106         goto cleanup;
107     }
108 
109     aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
110                              QCRYPTO_CIPHER_MODE_CBC,
111                              key, keylen,
112                              errp);
113     if (!aes) {
114         goto cleanup;
115     }
116 
117     if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) {
118         goto cleanup;
119     }
120 
121     if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
122         ciphertext = qbase64_decode((const gchar*)input,
123                                     inputlen,
124                                     &ciphertextlen,
125                                     errp);
126         if (!ciphertext) {
127             goto cleanup;
128         }
129         plaintext = g_new0(uint8_t, ciphertextlen + 1);
130     } else {
131         ciphertextlen = inputlen;
132         plaintext = g_new0(uint8_t, inputlen + 1);
133     }
134     if (qcrypto_cipher_decrypt(aes,
135                                ciphertext ? ciphertext : input,
136                                plaintext,
137                                ciphertextlen,
138                                errp) < 0) {
139         plaintext = NULL;
140         goto cleanup;
141     }
142 
143     if (plaintext[ciphertextlen - 1] > 16 ||
144         plaintext[ciphertextlen - 1] > ciphertextlen) {
145         error_setg(errp, "Incorrect number of padding bytes (%d) "
146                    "found on decrypted data",
147                    (int)plaintext[ciphertextlen - 1]);
148         g_free(plaintext);
149         plaintext = NULL;
150         goto cleanup;
151     }
152 
153     /* Even though plaintext may contain arbitrary NUL
154      * ensure it is explicitly NUL terminated.
155      */
156     ciphertextlen -= plaintext[ciphertextlen - 1];
157     plaintext[ciphertextlen] = '\0';
158 
159     *output = plaintext;
160     *outputlen = ciphertextlen;
161 
162  cleanup:
163     g_free(ciphertext);
164     g_free(iv);
165     g_free(key);
166     qcrypto_cipher_free(aes);
167 }
168 
169 
170 static void qcrypto_secret_decode(const uint8_t *input,
171                                   size_t inputlen,
172                                   uint8_t **output,
173                                   size_t *outputlen,
174                                   Error **errp)
175 {
176     *output = qbase64_decode((const gchar*)input,
177                              inputlen,
178                              outputlen,
179                              errp);
180 }
181 
182 
183 static void
184 qcrypto_secret_prop_set_loaded(Object *obj,
185                                bool value,
186                                Error **errp)
187 {
188     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
189 
190     if (value) {
191         Error *local_err = NULL;
192         uint8_t *input = NULL;
193         size_t inputlen = 0;
194         uint8_t *output = NULL;
195         size_t outputlen = 0;
196 
197         qcrypto_secret_load_data(secret, &input, &inputlen, &local_err);
198         if (local_err) {
199             error_propagate(errp, local_err);
200             return;
201         }
202 
203         if (secret->keyid) {
204             qcrypto_secret_decrypt(secret, input, inputlen,
205                                    &output, &outputlen, &local_err);
206             g_free(input);
207             if (local_err) {
208                 error_propagate(errp, local_err);
209                 return;
210             }
211             input = output;
212             inputlen = outputlen;
213         } else {
214             if (secret->format != QCRYPTO_SECRET_FORMAT_RAW) {
215                 qcrypto_secret_decode(input, inputlen,
216                                       &output, &outputlen, &local_err);
217                 g_free(input);
218                 if (local_err) {
219                     error_propagate(errp, local_err);
220                     return;
221                 }
222                 input = output;
223                 inputlen = outputlen;
224             }
225         }
226 
227         secret->rawdata = input;
228         secret->rawlen = inputlen;
229     } else {
230         g_free(secret->rawdata);
231         secret->rawlen = 0;
232     }
233 }
234 
235 
236 static bool
237 qcrypto_secret_prop_get_loaded(Object *obj,
238                                Error **errp G_GNUC_UNUSED)
239 {
240     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
241     return secret->data != NULL;
242 }
243 
244 
245 static void
246 qcrypto_secret_prop_set_format(Object *obj,
247                                int value,
248                                Error **errp G_GNUC_UNUSED)
249 {
250     QCryptoSecret *creds = QCRYPTO_SECRET(obj);
251 
252     creds->format = value;
253 }
254 
255 
256 static int
257 qcrypto_secret_prop_get_format(Object *obj,
258                                Error **errp G_GNUC_UNUSED)
259 {
260     QCryptoSecret *creds = QCRYPTO_SECRET(obj);
261 
262     return creds->format;
263 }
264 
265 
266 static void
267 qcrypto_secret_prop_set_data(Object *obj,
268                              const char *value,
269                              Error **errp)
270 {
271     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
272 
273     g_free(secret->data);
274     secret->data = g_strdup(value);
275 }
276 
277 
278 static char *
279 qcrypto_secret_prop_get_data(Object *obj,
280                              Error **errp)
281 {
282     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
283     return g_strdup(secret->data);
284 }
285 
286 
287 static void
288 qcrypto_secret_prop_set_file(Object *obj,
289                              const char *value,
290                              Error **errp)
291 {
292     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
293 
294     g_free(secret->file);
295     secret->file = g_strdup(value);
296 }
297 
298 
299 static char *
300 qcrypto_secret_prop_get_file(Object *obj,
301                              Error **errp)
302 {
303     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
304     return g_strdup(secret->file);
305 }
306 
307 
308 static void
309 qcrypto_secret_prop_set_iv(Object *obj,
310                            const char *value,
311                            Error **errp)
312 {
313     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
314 
315     g_free(secret->iv);
316     secret->iv = g_strdup(value);
317 }
318 
319 
320 static char *
321 qcrypto_secret_prop_get_iv(Object *obj,
322                            Error **errp)
323 {
324     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
325     return g_strdup(secret->iv);
326 }
327 
328 
329 static void
330 qcrypto_secret_prop_set_keyid(Object *obj,
331                               const char *value,
332                               Error **errp)
333 {
334     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
335 
336     g_free(secret->keyid);
337     secret->keyid = g_strdup(value);
338 }
339 
340 
341 static char *
342 qcrypto_secret_prop_get_keyid(Object *obj,
343                               Error **errp)
344 {
345     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
346     return g_strdup(secret->keyid);
347 }
348 
349 
350 static void
351 qcrypto_secret_complete(UserCreatable *uc, Error **errp)
352 {
353     object_property_set_bool(OBJECT(uc), true, "loaded", errp);
354 }
355 
356 
357 static void
358 qcrypto_secret_finalize(Object *obj)
359 {
360     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
361 
362     g_free(secret->iv);
363     g_free(secret->file);
364     g_free(secret->keyid);
365     g_free(secret->rawdata);
366     g_free(secret->data);
367 }
368 
369 static void
370 qcrypto_secret_class_init(ObjectClass *oc, void *data)
371 {
372     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
373 
374     ucc->complete = qcrypto_secret_complete;
375 
376     object_class_property_add_bool(oc, "loaded",
377                                    qcrypto_secret_prop_get_loaded,
378                                    qcrypto_secret_prop_set_loaded,
379                                    NULL);
380     object_class_property_add_enum(oc, "format",
381                                    "QCryptoSecretFormat",
382                                    &QCryptoSecretFormat_lookup,
383                                    qcrypto_secret_prop_get_format,
384                                    qcrypto_secret_prop_set_format,
385                                    NULL);
386     object_class_property_add_str(oc, "data",
387                                   qcrypto_secret_prop_get_data,
388                                   qcrypto_secret_prop_set_data,
389                                   NULL);
390     object_class_property_add_str(oc, "file",
391                                   qcrypto_secret_prop_get_file,
392                                   qcrypto_secret_prop_set_file,
393                                   NULL);
394     object_class_property_add_str(oc, "keyid",
395                                   qcrypto_secret_prop_get_keyid,
396                                   qcrypto_secret_prop_set_keyid,
397                                   NULL);
398     object_class_property_add_str(oc, "iv",
399                                   qcrypto_secret_prop_get_iv,
400                                   qcrypto_secret_prop_set_iv,
401                                   NULL);
402 }
403 
404 
405 int qcrypto_secret_lookup(const char *secretid,
406                           uint8_t **data,
407                           size_t *datalen,
408                           Error **errp)
409 {
410     Object *obj;
411     QCryptoSecret *secret;
412 
413     obj = object_resolve_path_component(
414         object_get_objects_root(), secretid);
415     if (!obj) {
416         error_setg(errp, "No secret with id '%s'", secretid);
417         return -1;
418     }
419 
420     secret = (QCryptoSecret *)
421         object_dynamic_cast(obj,
422                             TYPE_QCRYPTO_SECRET);
423     if (!secret) {
424         error_setg(errp, "Object with id '%s' is not a secret",
425                    secretid);
426         return -1;
427     }
428 
429     if (!secret->rawdata) {
430         error_setg(errp, "Secret with id '%s' has no data",
431                    secretid);
432         return -1;
433     }
434 
435     *data = g_new0(uint8_t, secret->rawlen + 1);
436     memcpy(*data, secret->rawdata, secret->rawlen);
437     (*data)[secret->rawlen] = '\0';
438     *datalen = secret->rawlen;
439 
440     return 0;
441 }
442 
443 
444 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
445                                     Error **errp)
446 {
447     uint8_t *data;
448     size_t datalen;
449 
450     if (qcrypto_secret_lookup(secretid,
451                               &data,
452                               &datalen,
453                               errp) < 0) {
454         return NULL;
455     }
456 
457     if (!g_utf8_validate((const gchar*)data, datalen, NULL)) {
458         error_setg(errp,
459                    "Data from secret %s is not valid UTF-8",
460                    secretid);
461         g_free(data);
462         return NULL;
463     }
464 
465     return (char *)data;
466 }
467 
468 
469 char *qcrypto_secret_lookup_as_base64(const char *secretid,
470                                       Error **errp)
471 {
472     uint8_t *data;
473     size_t datalen;
474     char *ret;
475 
476     if (qcrypto_secret_lookup(secretid,
477                               &data,
478                               &datalen,
479                               errp) < 0) {
480         return NULL;
481     }
482 
483     ret = g_base64_encode(data, datalen);
484     g_free(data);
485     return ret;
486 }
487 
488 
489 static const TypeInfo qcrypto_secret_info = {
490     .parent = TYPE_OBJECT,
491     .name = TYPE_QCRYPTO_SECRET,
492     .instance_size = sizeof(QCryptoSecret),
493     .instance_finalize = qcrypto_secret_finalize,
494     .class_size = sizeof(QCryptoSecretClass),
495     .class_init = qcrypto_secret_class_init,
496     .interfaces = (InterfaceInfo[]) {
497         { TYPE_USER_CREATABLE },
498         { }
499     }
500 };
501 
502 
503 static void
504 qcrypto_secret_register_types(void)
505 {
506     type_register_static(&qcrypto_secret_info);
507 }
508 
509 
510 type_init(qcrypto_secret_register_types);
511