Alexandru Gagniuc | 32abcbd | 2021-02-19 12:45:11 -0600 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (c) 2020, Alexandru Gagniuc <mr.nuke.me@gmail.com> |
| 4 | * Copyright (c) 2013, Google Inc. |
| 5 | */ |
| 6 | |
| 7 | #include <libfdt.h> |
| 8 | #include <u-boot/fdt-libcrypto.h> |
| 9 | |
| 10 | int fdt_add_bignum(void *blob, int noffset, const char *prop_name, |
| 11 | BIGNUM *num, int num_bits) |
| 12 | { |
| 13 | int nwords = num_bits / 32; |
| 14 | int size; |
| 15 | uint32_t *buf, *ptr; |
| 16 | BIGNUM *tmp, *big2, *big32, *big2_32; |
| 17 | BN_CTX *ctx; |
| 18 | int ret; |
| 19 | |
| 20 | tmp = BN_new(); |
| 21 | big2 = BN_new(); |
| 22 | big32 = BN_new(); |
| 23 | big2_32 = BN_new(); |
| 24 | |
| 25 | /* |
| 26 | * Note: This code assumes that all of the above succeed, or all fail. |
| 27 | * In practice memory allocations generally do not fail (unless the |
| 28 | * process is killed), so it does not seem worth handling each of these |
| 29 | * as a separate case. Technicaly this could leak memory on failure, |
| 30 | * but a) it won't happen in practice, and b) it doesn't matter as we |
| 31 | * will immediately exit with a failure code. |
| 32 | */ |
| 33 | if (!tmp || !big2 || !big32 || !big2_32) { |
| 34 | fprintf(stderr, "Out of memory (bignum)\n"); |
| 35 | return -ENOMEM; |
| 36 | } |
| 37 | ctx = BN_CTX_new(); |
| 38 | if (!ctx) { |
| 39 | fprintf(stderr, "Out of memory (bignum context)\n"); |
| 40 | return -ENOMEM; |
| 41 | } |
| 42 | BN_set_word(big2, 2L); |
| 43 | BN_set_word(big32, 32L); |
| 44 | BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ |
| 45 | |
| 46 | size = nwords * sizeof(uint32_t); |
| 47 | buf = malloc(size); |
| 48 | if (!buf) { |
| 49 | fprintf(stderr, "Out of memory (%d bytes)\n", size); |
| 50 | return -ENOMEM; |
| 51 | } |
| 52 | |
| 53 | /* Write out modulus as big endian array of integers */ |
| 54 | for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { |
| 55 | BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ |
| 56 | *ptr = cpu_to_fdt32(BN_get_word(tmp)); |
| 57 | BN_rshift(num, num, 32); /* N = N/B */ |
| 58 | } |
| 59 | |
| 60 | /* |
| 61 | * We try signing with successively increasing size values, so this |
| 62 | * might fail several times |
| 63 | */ |
| 64 | ret = fdt_setprop(blob, noffset, prop_name, buf, size); |
| 65 | free(buf); |
| 66 | BN_free(tmp); |
| 67 | BN_free(big2); |
| 68 | BN_free(big32); |
| 69 | BN_free(big2_32); |
| 70 | |
| 71 | return ret ? -FDT_ERR_NOSPACE : 0; |
| 72 | } |