xref: /openbmc/qemu/crypto/secret_common.c (revision 0310641c)
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_common.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 
qcrypto_secret_decrypt(QCryptoSecretCommon * secret,const uint8_t * input,size_t inputlen,uint8_t ** output,size_t * outputlen,Error ** errp)31 static void qcrypto_secret_decrypt(QCryptoSecretCommon *secret,
32                                    const uint8_t *input,
33                                    size_t inputlen,
34                                    uint8_t **output,
35                                    size_t *outputlen,
36                                    Error **errp)
37 {
38     g_autofree uint8_t *iv = NULL;
39     g_autofree uint8_t *key = NULL;
40     g_autofree uint8_t *ciphertext = NULL;
41     size_t keylen, ciphertextlen, ivlen;
42     g_autoptr(QCryptoCipher) aes = NULL;
43     g_autofree uint8_t *plaintext = NULL;
44 
45     *output = NULL;
46     *outputlen = 0;
47 
48     if (qcrypto_secret_lookup(secret->keyid,
49                               &key, &keylen,
50                               errp) < 0) {
51         return;
52     }
53 
54     if (keylen != 32) {
55         error_setg(errp, "Key should be 32 bytes in length");
56         return;
57     }
58 
59     if (!secret->iv) {
60         error_setg(errp, "IV is required to decrypt secret");
61         return;
62     }
63 
64     iv = qbase64_decode(secret->iv, -1, &ivlen, errp);
65     if (!iv) {
66         return;
67     }
68     if (ivlen != 16) {
69         error_setg(errp, "IV should be 16 bytes in length not %zu",
70                    ivlen);
71         return;
72     }
73 
74     aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
75                              QCRYPTO_CIPHER_MODE_CBC,
76                              key, keylen,
77                              errp);
78     if (!aes) {
79         return;
80     }
81 
82     if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) {
83         return;
84     }
85 
86     if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
87         ciphertext = qbase64_decode((const gchar *)input,
88                                     inputlen,
89                                     &ciphertextlen,
90                                     errp);
91         if (!ciphertext) {
92             return;
93         }
94         plaintext = g_new0(uint8_t, ciphertextlen + 1);
95     } else {
96         ciphertextlen = inputlen;
97         plaintext = g_new0(uint8_t, inputlen + 1);
98     }
99     if (qcrypto_cipher_decrypt(aes,
100                                ciphertext ? ciphertext : input,
101                                plaintext,
102                                ciphertextlen,
103                                errp) < 0) {
104         return;
105     }
106 
107     if (plaintext[ciphertextlen - 1] > 16 ||
108         plaintext[ciphertextlen - 1] > ciphertextlen) {
109         error_setg(errp, "Incorrect number of padding bytes (%d) "
110                    "found on decrypted data",
111                    (int)plaintext[ciphertextlen - 1]);
112         return;
113     }
114 
115     /*
116      *  Even though plaintext may contain arbitrary NUL
117      * ensure it is explicitly NUL terminated.
118      */
119     ciphertextlen -= plaintext[ciphertextlen - 1];
120     plaintext[ciphertextlen] = '\0';
121 
122     *output = g_steal_pointer(&plaintext);
123     *outputlen = ciphertextlen;
124 }
125 
126 
qcrypto_secret_decode(const uint8_t * input,size_t inputlen,uint8_t ** output,size_t * outputlen,Error ** errp)127 static void qcrypto_secret_decode(const uint8_t *input,
128                                   size_t inputlen,
129                                   uint8_t **output,
130                                   size_t *outputlen,
131                                   Error **errp)
132 {
133     *output = qbase64_decode((const gchar *)input,
134                              inputlen,
135                              outputlen,
136                              errp);
137 }
138 
139 
140 static void
qcrypto_secret_complete(UserCreatable * uc,Error ** errp)141 qcrypto_secret_complete(UserCreatable *uc, Error **errp)
142 {
143     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(uc);
144     QCryptoSecretCommonClass *sec_class
145                                 = QCRYPTO_SECRET_COMMON_GET_CLASS(uc);
146 
147     Error *local_err = NULL;
148     uint8_t *input = NULL;
149     size_t inputlen = 0;
150     uint8_t *output = NULL;
151     size_t outputlen = 0;
152 
153     if (sec_class->load_data) {
154         sec_class->load_data(secret, &input, &inputlen, &local_err);
155         if (local_err) {
156             error_propagate(errp, local_err);
157             return;
158         }
159     } else {
160         error_setg(errp, "%s provides no 'load_data' method'",
161                          object_get_typename(OBJECT(uc)));
162         return;
163     }
164 
165     if (secret->keyid) {
166         qcrypto_secret_decrypt(secret, input, inputlen,
167                                &output, &outputlen, &local_err);
168         g_free(input);
169         if (local_err) {
170             error_propagate(errp, local_err);
171             return;
172         }
173         input = output;
174         inputlen = outputlen;
175     } else {
176         if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
177             qcrypto_secret_decode(input, inputlen,
178                                   &output, &outputlen, &local_err);
179             g_free(input);
180             if (local_err) {
181                 error_propagate(errp, local_err);
182                 return;
183             }
184             input = output;
185             inputlen = outputlen;
186         }
187     }
188 
189     secret->rawdata = input;
190     secret->rawlen = inputlen;
191 }
192 
193 
194 static bool
qcrypto_secret_prop_get_loaded(Object * obj,Error ** errp G_GNUC_UNUSED)195 qcrypto_secret_prop_get_loaded(Object *obj,
196                                Error **errp G_GNUC_UNUSED)
197 {
198     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
199     return secret->rawdata != NULL;
200 }
201 
202 
203 static void
qcrypto_secret_prop_set_format(Object * obj,int value,Error ** errp G_GNUC_UNUSED)204 qcrypto_secret_prop_set_format(Object *obj,
205                                int value,
206                                Error **errp G_GNUC_UNUSED)
207 {
208     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
209     creds->format = value;
210 }
211 
212 
213 static int
qcrypto_secret_prop_get_format(Object * obj,Error ** errp G_GNUC_UNUSED)214 qcrypto_secret_prop_get_format(Object *obj,
215                                Error **errp G_GNUC_UNUSED)
216 {
217     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
218     return creds->format;
219 }
220 
221 
222 static void
qcrypto_secret_prop_set_iv(Object * obj,const char * value,Error ** errp)223 qcrypto_secret_prop_set_iv(Object *obj,
224                            const char *value,
225                            Error **errp)
226 {
227     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
228 
229     g_free(secret->iv);
230     secret->iv = g_strdup(value);
231 }
232 
233 
234 static char *
qcrypto_secret_prop_get_iv(Object * obj,Error ** errp)235 qcrypto_secret_prop_get_iv(Object *obj,
236                            Error **errp)
237 {
238     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
239     return g_strdup(secret->iv);
240 }
241 
242 
243 static void
qcrypto_secret_prop_set_keyid(Object * obj,const char * value,Error ** errp)244 qcrypto_secret_prop_set_keyid(Object *obj,
245                               const char *value,
246                               Error **errp)
247 {
248     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
249 
250     g_free(secret->keyid);
251     secret->keyid = g_strdup(value);
252 }
253 
254 
255 static char *
qcrypto_secret_prop_get_keyid(Object * obj,Error ** errp)256 qcrypto_secret_prop_get_keyid(Object *obj,
257                               Error **errp)
258 {
259     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
260     return g_strdup(secret->keyid);
261 }
262 
263 
264 static void
qcrypto_secret_finalize(Object * obj)265 qcrypto_secret_finalize(Object *obj)
266 {
267     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
268 
269     g_free(secret->iv);
270     g_free(secret->keyid);
271     g_free(secret->rawdata);
272 }
273 
274 static void
qcrypto_secret_class_init(ObjectClass * oc,void * data)275 qcrypto_secret_class_init(ObjectClass *oc, void *data)
276 {
277     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
278 
279     ucc->complete = qcrypto_secret_complete;
280 
281     object_class_property_add_bool(oc, "loaded",
282                                    qcrypto_secret_prop_get_loaded,
283                                    NULL);
284     object_class_property_add_enum(oc, "format",
285                                    "QCryptoSecretFormat",
286                                    &QCryptoSecretFormat_lookup,
287                                    qcrypto_secret_prop_get_format,
288                                    qcrypto_secret_prop_set_format);
289     object_class_property_add_str(oc, "keyid",
290                                   qcrypto_secret_prop_get_keyid,
291                                   qcrypto_secret_prop_set_keyid);
292     object_class_property_add_str(oc, "iv",
293                                   qcrypto_secret_prop_get_iv,
294                                   qcrypto_secret_prop_set_iv);
295 }
296 
297 
qcrypto_secret_lookup(const char * secretid,uint8_t ** data,size_t * datalen,Error ** errp)298 int qcrypto_secret_lookup(const char *secretid,
299                           uint8_t **data,
300                           size_t *datalen,
301                           Error **errp)
302 {
303     Object *obj;
304     QCryptoSecretCommon *secret;
305 
306     obj = object_resolve_path_component(
307         object_get_objects_root(), secretid);
308     if (!obj) {
309         error_setg(errp, "No secret with id '%s'", secretid);
310         return -1;
311     }
312 
313     secret = (QCryptoSecretCommon *)
314         object_dynamic_cast(obj,
315                             TYPE_QCRYPTO_SECRET_COMMON);
316     if (!secret) {
317         error_setg(errp, "Object with id '%s' is not a secret",
318                    secretid);
319         return -1;
320     }
321 
322     if (!secret->rawdata) {
323         error_setg(errp, "Secret with id '%s' has no data",
324                    secretid);
325         return -1;
326     }
327 
328     *data = g_new0(uint8_t, secret->rawlen + 1);
329     memcpy(*data, secret->rawdata, secret->rawlen);
330     (*data)[secret->rawlen] = '\0';
331     *datalen = secret->rawlen;
332 
333     return 0;
334 }
335 
336 
qcrypto_secret_lookup_as_utf8(const char * secretid,Error ** errp)337 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
338                                     Error **errp)
339 {
340     uint8_t *data;
341     size_t datalen;
342 
343     if (qcrypto_secret_lookup(secretid,
344                               &data,
345                               &datalen,
346                               errp) < 0) {
347         return NULL;
348     }
349 
350     if (!g_utf8_validate((const gchar *)data, datalen, NULL)) {
351         error_setg(errp,
352                    "Data from secret %s is not valid UTF-8",
353                    secretid);
354         g_free(data);
355         return NULL;
356     }
357 
358     return (char *)data;
359 }
360 
361 
qcrypto_secret_lookup_as_base64(const char * secretid,Error ** errp)362 char *qcrypto_secret_lookup_as_base64(const char *secretid,
363                                       Error **errp)
364 {
365     uint8_t *data;
366     size_t datalen;
367     char *ret;
368 
369     if (qcrypto_secret_lookup(secretid,
370                               &data,
371                               &datalen,
372                               errp) < 0) {
373         return NULL;
374     }
375 
376     ret = g_base64_encode(data, datalen);
377     g_free(data);
378     return ret;
379 }
380 
381 
382 static const TypeInfo qcrypto_secret_info = {
383     .parent = TYPE_OBJECT,
384     .name = TYPE_QCRYPTO_SECRET_COMMON,
385     .instance_size = sizeof(QCryptoSecretCommon),
386     .instance_finalize = qcrypto_secret_finalize,
387     .class_size = sizeof(QCryptoSecretCommonClass),
388     .class_init = qcrypto_secret_class_init,
389     .abstract = true,
390     .interfaces = (InterfaceInfo[]) {
391         { TYPE_USER_CREATABLE },
392         { }
393     }
394 };
395 
396 
397 static void
qcrypto_secret_register_types(void)398 qcrypto_secret_register_types(void)
399 {
400     type_register_static(&qcrypto_secret_info);
401 }
402 
403 
404 type_init(qcrypto_secret_register_types);
405