1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2019,Softathome
4  */
5 
6 #define OPENSSL_API_COMPAT 0x10101000L
7 
8 #include "mkimage.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <image.h>
12 #include <time.h>
13 #include <openssl/bn.h>
14 #include <openssl/rsa.h>
15 #include <openssl/pem.h>
16 #include <openssl/err.h>
17 #include <openssl/ssl.h>
18 #include <openssl/evp.h>
19 #include <openssl/engine.h>
20 #include <uboot_aes.h>
21 
22 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
23 #define HAVE_ERR_REMOVE_THREAD_STATE
24 #endif
25 
image_aes_encrypt(struct image_cipher_info * info,unsigned char * data,int size,unsigned char ** cipher,int * cipher_len)26 int image_aes_encrypt(struct image_cipher_info *info,
27 		      unsigned char *data, int size,
28 		      unsigned char **cipher, int *cipher_len)
29 {
30 	EVP_CIPHER_CTX *ctx;
31 	unsigned char *buf = NULL;
32 	int buf_len, len, ret = 0;
33 
34 	/* create and initialise the context */
35 	ctx = EVP_CIPHER_CTX_new();
36 	if (!ctx) {
37 		printf("Can't create context\n");
38 		return -1;
39 	}
40 
41 	/* allocate a buffer for the result */
42 	buf = malloc(size + AES_BLOCK_LENGTH);
43 	if (!buf) {
44 		printf("Can't allocate memory to encrypt\n");
45 		ret = -1;
46 		goto out;
47 	}
48 
49 	if (EVP_EncryptInit_ex(ctx, info->cipher->calculate_type(),
50 			       NULL, info->key, info->iv) != 1) {
51 		printf("Can't init encryption\n");
52 		ret = -1;
53 		goto out;
54 	}
55 
56 	if (EVP_EncryptUpdate(ctx, buf, &len, data, size) != 1) {
57 		printf("Can't encrypt data\n");
58 		ret = -1;
59 		goto out;
60 	}
61 
62 	buf_len = len;
63 
64 	if (EVP_EncryptFinal_ex(ctx, buf + len, &len) != 1) {
65 		printf("Can't finalise the encryption\n");
66 		ret = -1;
67 		goto out;
68 	}
69 
70 	buf_len += len;
71 
72 	*cipher = buf;
73 	*cipher_len = buf_len;
74 
75  out:
76 	EVP_CIPHER_CTX_free(ctx);
77 	return ret;
78 }
79 
image_aes_add_cipher_data(struct image_cipher_info * info,void * keydest,void * fit,int node_noffset)80 int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest,
81 			      void *fit, int node_noffset)
82 {
83 	int parent, node;
84 	char name[128];
85 	int ret = 0;
86 
87 	if (!keydest && !info->ivname) {
88 		/* At least, store the IV in the FIT image */
89 		ret = fdt_setprop(fit, node_noffset, "iv",
90 				  info->iv, info->cipher->iv_len);
91 		goto done;
92 	}
93 
94 	/* Either create or overwrite the named cipher node */
95 	parent = fdt_subnode_offset(keydest, 0, FIT_CIPHER_NODENAME);
96 	if (parent == -FDT_ERR_NOTFOUND) {
97 		parent = fdt_add_subnode(keydest, 0, FIT_CIPHER_NODENAME);
98 		if (parent < 0) {
99 			ret = parent;
100 			if (ret != -FDT_ERR_NOSPACE) {
101 				fprintf(stderr,
102 					"Couldn't create cipher node: %s\n",
103 					fdt_strerror(parent));
104 			}
105 		}
106 	}
107 	if (ret)
108 		goto done;
109 
110 	/* Either create or overwrite the named key node */
111 	if (info->ivname)
112 		snprintf(name, sizeof(name), "key-%s-%s-%s",
113 			 info->name, info->keyname, info->ivname);
114 	else
115 		snprintf(name, sizeof(name), "key-%s-%s",
116 			 info->name, info->keyname);
117 
118 	node = fdt_subnode_offset(keydest, parent, name);
119 	if (node == -FDT_ERR_NOTFOUND) {
120 		node = fdt_add_subnode(keydest, parent, name);
121 		if (node < 0) {
122 			ret = node;
123 			if (ret != -FDT_ERR_NOSPACE) {
124 				fprintf(stderr,
125 					"Could not create key subnode: %s\n",
126 					fdt_strerror(node));
127 			}
128 		}
129 	} else if (node < 0) {
130 		fprintf(stderr, "Cannot select keys parent: %s\n",
131 			fdt_strerror(node));
132 		ret = node;
133 	}
134 
135 	if (ret)
136 		goto done;
137 
138 	if (info->ivname)
139 		/* Store the IV in the u-boot device tree */
140 		ret = fdt_setprop(keydest, node, "iv",
141 				  info->iv, info->cipher->iv_len);
142 	else
143 		/* Store the IV in the FIT image */
144 		ret = fdt_setprop(fit, node_noffset, "iv",
145 				  info->iv, info->cipher->iv_len);
146 
147 	if (!ret)
148 		ret = fdt_setprop(keydest, node, "key",
149 				  info->key, info->cipher->key_len);
150 
151 	if (!ret)
152 		ret = fdt_setprop_u32(keydest, node, "key-len",
153 				      info->cipher->key_len);
154 
155 done:
156 	if (ret)
157 		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
158 
159 	return ret;
160 }
161