/* * Copyright (C) 2016 Pengutronix, Steffen Trumtrar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include static LIST_HEAD(blobs); static struct blobgen *bg_default; /** * blob_gen_register - register a blob device * @dev: The parent device * @bg: The blobgen device * * This registers a blob device. Returns 0 for success or a negative error * code otherwise. */ int blob_gen_register(struct device_d *dev, struct blobgen *bg) { int ret; dev_set_name(&bg->dev, "blob"); bg->dev.parent = dev; ret = register_device(&bg->dev); if (ret) return ret; list_add_tail(&bg->list, &blobs); if (!bg_default) bg_default = bg; return 0; } /** * blobgen_get - get a blob generator of given name * @name: The name of the blob generator to look for * * Finds a blob generator by name and returns it. Returns NULL if none is found. */ struct blobgen *blobgen_get(const char *name) { struct device_d *dev; struct blobgen *bg; if (!name) return bg_default; dev = get_device_by_name(name); if (!dev) return NULL; list_for_each_entry(bg, &blobs, list) { if (dev == &bg->dev) return bg; } return NULL; } /** * blob_encrypt - encrypt a data blob * @bg: The blob generator to use * @modifier: Modifier string * @plain: The plaintext input * @plainsize: Length of the plain data in bytes * @retblob: The encrypted blob is returned here * @blobsize: The returned length of the encrypted blob * * This encrypts a blob passed in @plain to an allocated buffer returned in * @retblob. Returns 0 for success or a negative error code otherwise. @retblob * is valid when the function returns successfully. The caller must free the * buffer after use. */ int blob_encrypt(struct blobgen *bg, const char *modifier, const void *plain, int plainsize, void **retblob, int *blobsize) { void *blob; int ret; if (plainsize > bg->max_payload_size) return -EINVAL; pr_debug("%s plain:\n", __func__); pr_memory_display(MSG_DEBUG, plain, 0, plainsize, 1, 0); blob = dma_alloc(MAX_BLOB_LEN); if (!blob) return -ENOMEM; ret = bg->encrypt(bg, modifier, plain, plainsize, blob, blobsize); if (ret) { free(blob); } else { pr_debug("%s encrypted:\n", __func__); pr_memory_display(MSG_DEBUG, blob, 0, *blobsize, 1, 0); *retblob = blob; } return ret; } /** * blob_encrypt_to_env - encrypt blob to environment variable * @bg: The blob generator to use * @modifier: Modifier string * @plain: The plaintext input * @plainsize: Length of the plain data in bytes * @varname: Name of the variable to set with the output blob * * This uses blob_encrypt to encrypt a blob. The result is base64 encoded and * written to the environment variable @varname. Returns 0 for success or a * negative error code otherwise. */ int blob_encrypt_to_env(struct blobgen *bg, const char *modifier, const void *plain, int plainsize, const char *varname) { int ret; int blobsize; void *blob; char *value; ret = blob_encrypt(bg, modifier, plain, plainsize, &blob, &blobsize); if (ret) return ret; value = malloc(BASE64_LENGTH(blobsize) + 1); if (!value) return -ENOMEM; uuencode(value, blob, blobsize); pr_debug("%s encrypted base64: \"%s\"\n", __func__, value); ret = setenv(varname, value); free(value); free(blob); return ret; } /** * blob_decrypt - decrypt a blob * @bg: The blob generator to use * @modifier: Modifier string * @blob: The encrypted blob * @blobsize: Size of the encrypted blob * @plain: Plaintext is returned here * @plainsize: Size of the data returned in bytes * * This function decrypts a blob generated with blob_encrypt. @modifier must match * the modifier used to encrypt the data. Returns 0 when the data could be * decrypted successfully or a negative error code otherwise. */ int blob_decrypt(struct blobgen *bg, const char *modifier, const void *blob, int blobsize, void **plain, int *plainsize) { int ret; pr_debug("%s encrypted:\n", __func__); pr_memory_display(MSG_DEBUG, blob, 0, blobsize, 1, 0); ret = bg->decrypt(bg, modifier, blob, blobsize, plain, plainsize); if (!ret) { pr_debug("%s decrypted:\n", __func__); pr_memory_display(MSG_DEBUG, *plain, 0, *plainsize, 1, 0); } return ret; } /** * blob_decrypt_from_base64 - decrypt a base64 encoded blob * @bg: The blob generator to use * @modifier: Modifier string * @encrypted: base64 encoded encrypted data * @plain: Plaintext is returned here * @plainsize: Size of the data returned in bytes * * like blob_decrypt, but takes the encrypted data as a base64 encoded string. * Returns 0 when the data could be decrypted successfully or a negative error * code otherwise. */ int blob_decrypt_from_base64(struct blobgen *bg, const char *modifier, const char *encrypted, void **plain, int *plainsize) { char *data; int ret, len; data = dma_alloc(MAX_BLOB_LEN); if (!data) return -ENOMEM; pr_debug("encrypted base64: \"%s\"\n", encrypted); len = decode_base64(data, MAX_BLOB_LEN, encrypted); ret = blob_decrypt(bg, modifier, data, len, plain, plainsize); free(data); return ret; }