xref: /openbmc/qemu/crypto/secret_common.c (revision 88dd060d)
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 
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_ALGO_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 
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
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 void
195 qcrypto_secret_prop_set_format(Object *obj,
196                                int value,
197                                Error **errp G_GNUC_UNUSED)
198 {
199     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
200     creds->format = value;
201 }
202 
203 
204 static int
205 qcrypto_secret_prop_get_format(Object *obj,
206                                Error **errp G_GNUC_UNUSED)
207 {
208     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
209     return creds->format;
210 }
211 
212 
213 static void
214 qcrypto_secret_prop_set_iv(Object *obj,
215                            const char *value,
216                            Error **errp)
217 {
218     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
219 
220     g_free(secret->iv);
221     secret->iv = g_strdup(value);
222 }
223 
224 
225 static char *
226 qcrypto_secret_prop_get_iv(Object *obj,
227                            Error **errp)
228 {
229     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
230     return g_strdup(secret->iv);
231 }
232 
233 
234 static void
235 qcrypto_secret_prop_set_keyid(Object *obj,
236                               const char *value,
237                               Error **errp)
238 {
239     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
240 
241     g_free(secret->keyid);
242     secret->keyid = g_strdup(value);
243 }
244 
245 
246 static char *
247 qcrypto_secret_prop_get_keyid(Object *obj,
248                               Error **errp)
249 {
250     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
251     return g_strdup(secret->keyid);
252 }
253 
254 
255 static void
256 qcrypto_secret_finalize(Object *obj)
257 {
258     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
259 
260     g_free(secret->iv);
261     g_free(secret->keyid);
262     g_free(secret->rawdata);
263 }
264 
265 static void
266 qcrypto_secret_class_init(ObjectClass *oc, void *data)
267 {
268     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
269 
270     ucc->complete = qcrypto_secret_complete;
271 
272     object_class_property_add_enum(oc, "format",
273                                    "QCryptoSecretFormat",
274                                    &QCryptoSecretFormat_lookup,
275                                    qcrypto_secret_prop_get_format,
276                                    qcrypto_secret_prop_set_format);
277     object_class_property_add_str(oc, "keyid",
278                                   qcrypto_secret_prop_get_keyid,
279                                   qcrypto_secret_prop_set_keyid);
280     object_class_property_add_str(oc, "iv",
281                                   qcrypto_secret_prop_get_iv,
282                                   qcrypto_secret_prop_set_iv);
283 }
284 
285 
286 int qcrypto_secret_lookup(const char *secretid,
287                           uint8_t **data,
288                           size_t *datalen,
289                           Error **errp)
290 {
291     Object *obj;
292     QCryptoSecretCommon *secret;
293 
294     obj = object_resolve_path_component(
295         object_get_objects_root(), secretid);
296     if (!obj) {
297         error_setg(errp, "No secret with id '%s'", secretid);
298         return -1;
299     }
300 
301     secret = (QCryptoSecretCommon *)
302         object_dynamic_cast(obj,
303                             TYPE_QCRYPTO_SECRET_COMMON);
304     if (!secret) {
305         error_setg(errp, "Object with id '%s' is not a secret",
306                    secretid);
307         return -1;
308     }
309 
310     if (!secret->rawdata) {
311         error_setg(errp, "Secret with id '%s' has no data",
312                    secretid);
313         return -1;
314     }
315 
316     *data = g_new0(uint8_t, secret->rawlen + 1);
317     memcpy(*data, secret->rawdata, secret->rawlen);
318     (*data)[secret->rawlen] = '\0';
319     *datalen = secret->rawlen;
320 
321     return 0;
322 }
323 
324 
325 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
326                                     Error **errp)
327 {
328     uint8_t *data;
329     size_t datalen;
330 
331     if (qcrypto_secret_lookup(secretid,
332                               &data,
333                               &datalen,
334                               errp) < 0) {
335         return NULL;
336     }
337 
338     if (!g_utf8_validate((const gchar *)data, datalen, NULL)) {
339         error_setg(errp,
340                    "Data from secret %s is not valid UTF-8",
341                    secretid);
342         g_free(data);
343         return NULL;
344     }
345 
346     return (char *)data;
347 }
348 
349 
350 char *qcrypto_secret_lookup_as_base64(const char *secretid,
351                                       Error **errp)
352 {
353     uint8_t *data;
354     size_t datalen;
355     char *ret;
356 
357     if (qcrypto_secret_lookup(secretid,
358                               &data,
359                               &datalen,
360                               errp) < 0) {
361         return NULL;
362     }
363 
364     ret = g_base64_encode(data, datalen);
365     g_free(data);
366     return ret;
367 }
368 
369 
370 static const TypeInfo qcrypto_secret_info = {
371     .parent = TYPE_OBJECT,
372     .name = TYPE_QCRYPTO_SECRET_COMMON,
373     .instance_size = sizeof(QCryptoSecretCommon),
374     .instance_finalize = qcrypto_secret_finalize,
375     .class_size = sizeof(QCryptoSecretCommonClass),
376     .class_init = qcrypto_secret_class_init,
377     .abstract = true,
378     .interfaces = (InterfaceInfo[]) {
379         { TYPE_USER_CREATABLE },
380         { }
381     }
382 };
383 
384 
385 static void
386 qcrypto_secret_register_types(void)
387 {
388     type_register_static(&qcrypto_secret_info);
389 }
390 
391 
392 type_init(qcrypto_secret_register_types);
393