io: improve docs for QIOChannelSocket async functions
[qemu/ar7.git] / crypto / secret.c
blobbe736f2cd56ca48c6a4db714954e8d903279395e
1 /*
2 * QEMU crypto secret support
4 * Copyright (c) 2015 Red Hat, Inc.
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "crypto/secret.h"
23 #include "crypto/cipher.h"
24 #include "qom/object_interfaces.h"
25 #include "qemu/base64.h"
26 #include "trace.h"
29 static void
30 qcrypto_secret_load_data(QCryptoSecret *secret,
31 uint8_t **output,
32 size_t *outputlen,
33 Error **errp)
35 char *data = NULL;
36 size_t length = 0;
37 GError *gerr = NULL;
39 *output = NULL;
40 *outputlen = 0;
42 if (secret->file) {
43 if (secret->data) {
44 error_setg(errp,
45 "'file' and 'data' are mutually exclusive");
46 return;
48 if (!g_file_get_contents(secret->file, &data, &length, &gerr)) {
49 error_setg(errp,
50 "Unable to read %s: %s",
51 secret->file, gerr->message);
52 g_error_free(gerr);
53 return;
55 *output = (uint8_t *)data;
56 *outputlen = length;
57 } else if (secret->data) {
58 *outputlen = strlen(secret->data);
59 *output = (uint8_t *)g_strdup(secret->data);
60 } else {
61 error_setg(errp, "Either 'file' or 'data' must be provided");
66 static void qcrypto_secret_decrypt(QCryptoSecret *secret,
67 const uint8_t *input,
68 size_t inputlen,
69 uint8_t **output,
70 size_t *outputlen,
71 Error **errp)
73 uint8_t *key = NULL, *ciphertext = NULL, *iv = NULL;
74 size_t keylen, ciphertextlen, ivlen;
75 QCryptoCipher *aes = NULL;
76 uint8_t *plaintext = NULL;
78 *output = NULL;
79 *outputlen = 0;
81 if (qcrypto_secret_lookup(secret->keyid,
82 &key, &keylen,
83 errp) < 0) {
84 goto cleanup;
87 if (keylen != 32) {
88 error_setg(errp, "Key should be 32 bytes in length");
89 goto cleanup;
92 if (!secret->iv) {
93 error_setg(errp, "IV is required to decrypt secret");
94 goto cleanup;
97 iv = qbase64_decode(secret->iv, -1, &ivlen, errp);
98 if (!iv) {
99 goto cleanup;
101 if (ivlen != 16) {
102 error_setg(errp, "IV should be 16 bytes in length not %zu",
103 ivlen);
104 goto cleanup;
107 aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
108 QCRYPTO_CIPHER_MODE_CBC,
109 key, keylen,
110 errp);
111 if (!aes) {
112 goto cleanup;
115 if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) {
116 goto cleanup;
119 if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
120 ciphertext = qbase64_decode((const gchar*)input,
121 inputlen,
122 &ciphertextlen,
123 errp);
124 if (!ciphertext) {
125 goto cleanup;
127 plaintext = g_new0(uint8_t, ciphertextlen + 1);
128 } else {
129 ciphertextlen = inputlen;
130 plaintext = g_new0(uint8_t, inputlen + 1);
132 if (qcrypto_cipher_decrypt(aes,
133 ciphertext ? ciphertext : input,
134 plaintext,
135 ciphertextlen,
136 errp) < 0) {
137 plaintext = NULL;
138 goto cleanup;
141 if (plaintext[ciphertextlen - 1] > 16 ||
142 plaintext[ciphertextlen - 1] > ciphertextlen) {
143 error_setg(errp, "Incorrect number of padding bytes (%d) "
144 "found on decrypted data",
145 (int)plaintext[ciphertextlen - 1]);
146 g_free(plaintext);
147 plaintext = NULL;
148 goto cleanup;
151 /* Even though plaintext may contain arbitrary NUL
152 * ensure it is explicitly NUL terminated.
154 ciphertextlen -= plaintext[ciphertextlen - 1];
155 plaintext[ciphertextlen] = '\0';
157 *output = plaintext;
158 *outputlen = ciphertextlen;
160 cleanup:
161 g_free(ciphertext);
162 g_free(iv);
163 g_free(key);
164 qcrypto_cipher_free(aes);
168 static void qcrypto_secret_decode(const uint8_t *input,
169 size_t inputlen,
170 uint8_t **output,
171 size_t *outputlen,
172 Error **errp)
174 *output = qbase64_decode((const gchar*)input,
175 inputlen,
176 outputlen,
177 errp);
181 static void
182 qcrypto_secret_prop_set_loaded(Object *obj,
183 bool value,
184 Error **errp)
186 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
188 if (value) {
189 Error *local_err = NULL;
190 uint8_t *input = NULL;
191 size_t inputlen = 0;
192 uint8_t *output = NULL;
193 size_t outputlen = 0;
195 qcrypto_secret_load_data(secret, &input, &inputlen, &local_err);
196 if (local_err) {
197 error_propagate(errp, local_err);
198 return;
201 if (secret->keyid) {
202 qcrypto_secret_decrypt(secret, input, inputlen,
203 &output, &outputlen, &local_err);
204 g_free(input);
205 if (local_err) {
206 error_propagate(errp, local_err);
207 return;
209 input = output;
210 inputlen = outputlen;
211 } else {
212 if (secret->format != QCRYPTO_SECRET_FORMAT_RAW) {
213 qcrypto_secret_decode(input, inputlen,
214 &output, &outputlen, &local_err);
215 g_free(input);
216 if (local_err) {
217 error_propagate(errp, local_err);
218 return;
220 input = output;
221 inputlen = outputlen;
225 secret->rawdata = input;
226 secret->rawlen = inputlen;
227 } else {
228 g_free(secret->rawdata);
229 secret->rawlen = 0;
234 static bool
235 qcrypto_secret_prop_get_loaded(Object *obj,
236 Error **errp G_GNUC_UNUSED)
238 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
239 return secret->data != NULL;
243 static void
244 qcrypto_secret_prop_set_format(Object *obj,
245 int value,
246 Error **errp G_GNUC_UNUSED)
248 QCryptoSecret *creds = QCRYPTO_SECRET(obj);
250 creds->format = value;
254 static int
255 qcrypto_secret_prop_get_format(Object *obj,
256 Error **errp G_GNUC_UNUSED)
258 QCryptoSecret *creds = QCRYPTO_SECRET(obj);
260 return creds->format;
264 static void
265 qcrypto_secret_prop_set_data(Object *obj,
266 const char *value,
267 Error **errp)
269 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
271 g_free(secret->data);
272 secret->data = g_strdup(value);
276 static char *
277 qcrypto_secret_prop_get_data(Object *obj,
278 Error **errp)
280 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
281 return g_strdup(secret->data);
285 static void
286 qcrypto_secret_prop_set_file(Object *obj,
287 const char *value,
288 Error **errp)
290 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
292 g_free(secret->file);
293 secret->file = g_strdup(value);
297 static char *
298 qcrypto_secret_prop_get_file(Object *obj,
299 Error **errp)
301 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
302 return g_strdup(secret->file);
306 static void
307 qcrypto_secret_prop_set_iv(Object *obj,
308 const char *value,
309 Error **errp)
311 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
313 g_free(secret->iv);
314 secret->iv = g_strdup(value);
318 static char *
319 qcrypto_secret_prop_get_iv(Object *obj,
320 Error **errp)
322 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
323 return g_strdup(secret->iv);
327 static void
328 qcrypto_secret_prop_set_keyid(Object *obj,
329 const char *value,
330 Error **errp)
332 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
334 g_free(secret->keyid);
335 secret->keyid = g_strdup(value);
339 static char *
340 qcrypto_secret_prop_get_keyid(Object *obj,
341 Error **errp)
343 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
344 return g_strdup(secret->keyid);
348 static void
349 qcrypto_secret_complete(UserCreatable *uc, Error **errp)
351 object_property_set_bool(OBJECT(uc), true, "loaded", errp);
355 static void
356 qcrypto_secret_finalize(Object *obj)
358 QCryptoSecret *secret = QCRYPTO_SECRET(obj);
360 g_free(secret->iv);
361 g_free(secret->file);
362 g_free(secret->keyid);
363 g_free(secret->rawdata);
364 g_free(secret->data);
367 static void
368 qcrypto_secret_class_init(ObjectClass *oc, void *data)
370 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
372 ucc->complete = qcrypto_secret_complete;
374 object_class_property_add_bool(oc, "loaded",
375 qcrypto_secret_prop_get_loaded,
376 qcrypto_secret_prop_set_loaded,
377 NULL);
378 object_class_property_add_enum(oc, "format",
379 "QCryptoSecretFormat",
380 QCryptoSecretFormat_lookup,
381 qcrypto_secret_prop_get_format,
382 qcrypto_secret_prop_set_format,
383 NULL);
384 object_class_property_add_str(oc, "data",
385 qcrypto_secret_prop_get_data,
386 qcrypto_secret_prop_set_data,
387 NULL);
388 object_class_property_add_str(oc, "file",
389 qcrypto_secret_prop_get_file,
390 qcrypto_secret_prop_set_file,
391 NULL);
392 object_class_property_add_str(oc, "keyid",
393 qcrypto_secret_prop_get_keyid,
394 qcrypto_secret_prop_set_keyid,
395 NULL);
396 object_class_property_add_str(oc, "iv",
397 qcrypto_secret_prop_get_iv,
398 qcrypto_secret_prop_set_iv,
399 NULL);
403 int qcrypto_secret_lookup(const char *secretid,
404 uint8_t **data,
405 size_t *datalen,
406 Error **errp)
408 Object *obj;
409 QCryptoSecret *secret;
411 obj = object_resolve_path_component(
412 object_get_objects_root(), secretid);
413 if (!obj) {
414 error_setg(errp, "No secret with id '%s'", secretid);
415 return -1;
418 secret = (QCryptoSecret *)
419 object_dynamic_cast(obj,
420 TYPE_QCRYPTO_SECRET);
421 if (!secret) {
422 error_setg(errp, "Object with id '%s' is not a secret",
423 secretid);
424 return -1;
427 if (!secret->rawdata) {
428 error_setg(errp, "Secret with id '%s' has no data",
429 secretid);
430 return -1;
433 *data = g_new0(uint8_t, secret->rawlen + 1);
434 memcpy(*data, secret->rawdata, secret->rawlen);
435 (*data)[secret->rawlen] = '\0';
436 *datalen = secret->rawlen;
438 return 0;
442 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
443 Error **errp)
445 uint8_t *data;
446 size_t datalen;
448 if (qcrypto_secret_lookup(secretid,
449 &data,
450 &datalen,
451 errp) < 0) {
452 return NULL;
455 if (!g_utf8_validate((const gchar*)data, datalen, NULL)) {
456 error_setg(errp,
457 "Data from secret %s is not valid UTF-8",
458 secretid);
459 g_free(data);
460 return NULL;
463 return (char *)data;
467 char *qcrypto_secret_lookup_as_base64(const char *secretid,
468 Error **errp)
470 uint8_t *data;
471 size_t datalen;
472 char *ret;
474 if (qcrypto_secret_lookup(secretid,
475 &data,
476 &datalen,
477 errp) < 0) {
478 return NULL;
481 ret = g_base64_encode(data, datalen);
482 g_free(data);
483 return ret;
487 static const TypeInfo qcrypto_secret_info = {
488 .parent = TYPE_OBJECT,
489 .name = TYPE_QCRYPTO_SECRET,
490 .instance_size = sizeof(QCryptoSecret),
491 .instance_finalize = qcrypto_secret_finalize,
492 .class_size = sizeof(QCryptoSecretClass),
493 .class_init = qcrypto_secret_class_init,
494 .interfaces = (InterfaceInfo[]) {
495 { TYPE_USER_CREATABLE },
501 static void
502 qcrypto_secret_register_types(void)
504 type_register_static(&qcrypto_secret_info);
508 type_init(qcrypto_secret_register_types);