xref: /openbmc/qemu/crypto/secret_common.c (revision 9379ea9db3c0064fa2787db0794a23a30f7b2d2d)
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