xref: /openbmc/qemu/crypto/secret.c (revision 65a117da)
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.1 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     g_autofree uint8_t *key = NULL;
76     g_autofree uint8_t *ciphertext = NULL;
77     g_autofree uint8_t *iv = NULL;
78     size_t keylen, ciphertextlen, ivlen;
79     g_autoptr(QCryptoCipher) aes = NULL;
80     g_autofree uint8_t *plaintext = NULL;
81 
82     *output = NULL;
83     *outputlen = 0;
84 
85     if (qcrypto_secret_lookup(secret->keyid,
86                               &key, &keylen,
87                               errp) < 0) {
88         return;
89     }
90 
91     if (keylen != 32) {
92         error_setg(errp, "Key should be 32 bytes in length");
93         return;
94     }
95 
96     if (!secret->iv) {
97         error_setg(errp, "IV is required to decrypt secret");
98         return;
99     }
100 
101     iv = qbase64_decode(secret->iv, -1, &ivlen, errp);
102     if (!iv) {
103         return;
104     }
105     if (ivlen != 16) {
106         error_setg(errp, "IV should be 16 bytes in length not %zu",
107                    ivlen);
108         return;
109     }
110 
111     aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
112                              QCRYPTO_CIPHER_MODE_CBC,
113                              key, keylen,
114                              errp);
115     if (!aes) {
116         return;
117     }
118 
119     if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) {
120         return;
121     }
122 
123     if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
124         ciphertext = qbase64_decode((const gchar*)input,
125                                     inputlen,
126                                     &ciphertextlen,
127                                     errp);
128         if (!ciphertext) {
129             return;
130         }
131         plaintext = g_new0(uint8_t, ciphertextlen + 1);
132     } else {
133         ciphertextlen = inputlen;
134         plaintext = g_new0(uint8_t, inputlen + 1);
135     }
136     if (qcrypto_cipher_decrypt(aes,
137                                ciphertext ? ciphertext : input,
138                                plaintext,
139                                ciphertextlen,
140                                errp) < 0) {
141         return;
142     }
143 
144     if (plaintext[ciphertextlen - 1] > 16 ||
145         plaintext[ciphertextlen - 1] > ciphertextlen) {
146         error_setg(errp, "Incorrect number of padding bytes (%d) "
147                    "found on decrypted data",
148                    (int)plaintext[ciphertextlen - 1]);
149         return;
150     }
151 
152     /* Even though plaintext may contain arbitrary NUL
153      * ensure it is explicitly NUL terminated.
154      */
155     ciphertextlen -= plaintext[ciphertextlen - 1];
156     plaintext[ciphertextlen] = '\0';
157 
158     *output = g_steal_pointer(&plaintext);
159     *outputlen = ciphertextlen;
160 }
161 
162 
163 static void qcrypto_secret_decode(const uint8_t *input,
164                                   size_t inputlen,
165                                   uint8_t **output,
166                                   size_t *outputlen,
167                                   Error **errp)
168 {
169     *output = qbase64_decode((const gchar*)input,
170                              inputlen,
171                              outputlen,
172                              errp);
173 }
174 
175 
176 static void
177 qcrypto_secret_prop_set_loaded(Object *obj,
178                                bool value,
179                                Error **errp)
180 {
181     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
182 
183     if (value) {
184         Error *local_err = NULL;
185         uint8_t *input = NULL;
186         size_t inputlen = 0;
187         uint8_t *output = NULL;
188         size_t outputlen = 0;
189 
190         qcrypto_secret_load_data(secret, &input, &inputlen, &local_err);
191         if (local_err) {
192             error_propagate(errp, local_err);
193             return;
194         }
195 
196         if (secret->keyid) {
197             qcrypto_secret_decrypt(secret, input, inputlen,
198                                    &output, &outputlen, &local_err);
199             g_free(input);
200             if (local_err) {
201                 error_propagate(errp, local_err);
202                 return;
203             }
204             input = output;
205             inputlen = outputlen;
206         } else {
207             if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
208                 qcrypto_secret_decode(input, inputlen,
209                                       &output, &outputlen, &local_err);
210                 g_free(input);
211                 if (local_err) {
212                     error_propagate(errp, local_err);
213                     return;
214                 }
215                 input = output;
216                 inputlen = outputlen;
217             }
218         }
219 
220         secret->rawdata = input;
221         secret->rawlen = inputlen;
222     } else {
223         g_free(secret->rawdata);
224         secret->rawdata = NULL;
225         secret->rawlen = 0;
226     }
227 }
228 
229 
230 static bool
231 qcrypto_secret_prop_get_loaded(Object *obj,
232                                Error **errp G_GNUC_UNUSED)
233 {
234     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
235     return secret->rawdata != NULL;
236 }
237 
238 
239 static void
240 qcrypto_secret_prop_set_format(Object *obj,
241                                int value,
242                                Error **errp G_GNUC_UNUSED)
243 {
244     QCryptoSecret *creds = QCRYPTO_SECRET(obj);
245 
246     creds->format = value;
247 }
248 
249 
250 static int
251 qcrypto_secret_prop_get_format(Object *obj,
252                                Error **errp G_GNUC_UNUSED)
253 {
254     QCryptoSecret *creds = QCRYPTO_SECRET(obj);
255 
256     return creds->format;
257 }
258 
259 
260 static void
261 qcrypto_secret_prop_set_data(Object *obj,
262                              const char *value,
263                              Error **errp)
264 {
265     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
266 
267     g_free(secret->data);
268     secret->data = g_strdup(value);
269 }
270 
271 
272 static char *
273 qcrypto_secret_prop_get_data(Object *obj,
274                              Error **errp)
275 {
276     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
277     return g_strdup(secret->data);
278 }
279 
280 
281 static void
282 qcrypto_secret_prop_set_file(Object *obj,
283                              const char *value,
284                              Error **errp)
285 {
286     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
287 
288     g_free(secret->file);
289     secret->file = g_strdup(value);
290 }
291 
292 
293 static char *
294 qcrypto_secret_prop_get_file(Object *obj,
295                              Error **errp)
296 {
297     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
298     return g_strdup(secret->file);
299 }
300 
301 
302 static void
303 qcrypto_secret_prop_set_iv(Object *obj,
304                            const char *value,
305                            Error **errp)
306 {
307     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
308 
309     g_free(secret->iv);
310     secret->iv = g_strdup(value);
311 }
312 
313 
314 static char *
315 qcrypto_secret_prop_get_iv(Object *obj,
316                            Error **errp)
317 {
318     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
319     return g_strdup(secret->iv);
320 }
321 
322 
323 static void
324 qcrypto_secret_prop_set_keyid(Object *obj,
325                               const char *value,
326                               Error **errp)
327 {
328     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
329 
330     g_free(secret->keyid);
331     secret->keyid = g_strdup(value);
332 }
333 
334 
335 static char *
336 qcrypto_secret_prop_get_keyid(Object *obj,
337                               Error **errp)
338 {
339     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
340     return g_strdup(secret->keyid);
341 }
342 
343 
344 static void
345 qcrypto_secret_complete(UserCreatable *uc, Error **errp)
346 {
347     object_property_set_bool(OBJECT(uc), true, "loaded", errp);
348 }
349 
350 
351 static void
352 qcrypto_secret_finalize(Object *obj)
353 {
354     QCryptoSecret *secret = QCRYPTO_SECRET(obj);
355 
356     g_free(secret->iv);
357     g_free(secret->file);
358     g_free(secret->keyid);
359     g_free(secret->rawdata);
360     g_free(secret->data);
361 }
362 
363 static void
364 qcrypto_secret_class_init(ObjectClass *oc, void *data)
365 {
366     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
367 
368     ucc->complete = qcrypto_secret_complete;
369 
370     object_class_property_add_bool(oc, "loaded",
371                                    qcrypto_secret_prop_get_loaded,
372                                    qcrypto_secret_prop_set_loaded);
373     object_class_property_add_enum(oc, "format",
374                                    "QCryptoSecretFormat",
375                                    &QCryptoSecretFormat_lookup,
376                                    qcrypto_secret_prop_get_format,
377                                    qcrypto_secret_prop_set_format);
378     object_class_property_add_str(oc, "data",
379                                   qcrypto_secret_prop_get_data,
380                                   qcrypto_secret_prop_set_data);
381     object_class_property_add_str(oc, "file",
382                                   qcrypto_secret_prop_get_file,
383                                   qcrypto_secret_prop_set_file);
384     object_class_property_add_str(oc, "keyid",
385                                   qcrypto_secret_prop_get_keyid,
386                                   qcrypto_secret_prop_set_keyid);
387     object_class_property_add_str(oc, "iv",
388                                   qcrypto_secret_prop_get_iv,
389                                   qcrypto_secret_prop_set_iv);
390 }
391 
392 
393 int qcrypto_secret_lookup(const char *secretid,
394                           uint8_t **data,
395                           size_t *datalen,
396                           Error **errp)
397 {
398     Object *obj;
399     QCryptoSecret *secret;
400 
401     obj = object_resolve_path_component(
402         object_get_objects_root(), secretid);
403     if (!obj) {
404         error_setg(errp, "No secret with id '%s'", secretid);
405         return -1;
406     }
407 
408     secret = (QCryptoSecret *)
409         object_dynamic_cast(obj,
410                             TYPE_QCRYPTO_SECRET);
411     if (!secret) {
412         error_setg(errp, "Object with id '%s' is not a secret",
413                    secretid);
414         return -1;
415     }
416 
417     if (!secret->rawdata) {
418         error_setg(errp, "Secret with id '%s' has no data",
419                    secretid);
420         return -1;
421     }
422 
423     *data = g_new0(uint8_t, secret->rawlen + 1);
424     memcpy(*data, secret->rawdata, secret->rawlen);
425     (*data)[secret->rawlen] = '\0';
426     *datalen = secret->rawlen;
427 
428     return 0;
429 }
430 
431 
432 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
433                                     Error **errp)
434 {
435     uint8_t *data;
436     size_t datalen;
437 
438     if (qcrypto_secret_lookup(secretid,
439                               &data,
440                               &datalen,
441                               errp) < 0) {
442         return NULL;
443     }
444 
445     if (!g_utf8_validate((const gchar*)data, datalen, NULL)) {
446         error_setg(errp,
447                    "Data from secret %s is not valid UTF-8",
448                    secretid);
449         g_free(data);
450         return NULL;
451     }
452 
453     return (char *)data;
454 }
455 
456 
457 char *qcrypto_secret_lookup_as_base64(const char *secretid,
458                                       Error **errp)
459 {
460     uint8_t *data;
461     size_t datalen;
462     char *ret;
463 
464     if (qcrypto_secret_lookup(secretid,
465                               &data,
466                               &datalen,
467                               errp) < 0) {
468         return NULL;
469     }
470 
471     ret = g_base64_encode(data, datalen);
472     g_free(data);
473     return ret;
474 }
475 
476 
477 static const TypeInfo qcrypto_secret_info = {
478     .parent = TYPE_OBJECT,
479     .name = TYPE_QCRYPTO_SECRET,
480     .instance_size = sizeof(QCryptoSecret),
481     .instance_finalize = qcrypto_secret_finalize,
482     .class_size = sizeof(QCryptoSecretClass),
483     .class_init = qcrypto_secret_class_init,
484     .interfaces = (InterfaceInfo[]) {
485         { TYPE_USER_CREATABLE },
486         { }
487     }
488 };
489 
490 
491 static void
492 qcrypto_secret_register_types(void)
493 {
494     type_register_static(&qcrypto_secret_info);
495 }
496 
497 
498 type_init(qcrypto_secret_register_types);
499