1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2018-2020 NXP
4  *
5  * Crypto Cipher interface implementation to enable HW driver.
6  */
7 #include <assert.h>
8 #include <crypto/crypto.h>
9 #include <crypto/crypto_impl.h>
10 #include <drvcrypt.h>
11 #include <drvcrypt_cipher.h>
12 #include <kernel/panic.h>
13 #include <malloc.h>
14 #include <utee_defines.h>
15 #include <util.h>
16 
17 static const struct crypto_cipher_ops cipher_ops;
18 
19 /*
20  * Returns the reference to the driver context
21  *
22  * @ctx    Reference the API context pointer
23  */
to_cipher_ctx(struct crypto_cipher_ctx * ctx)24 static struct crypto_cipher *to_cipher_ctx(struct crypto_cipher_ctx *ctx)
25 {
26 	assert(ctx && ctx->ops == &cipher_ops);
27 
28 	return container_of(ctx, struct crypto_cipher, cipher_ctx);
29 }
30 
31 /*
32  * Free cipher context
33  *
34  * @ctx    Reference the API context pointer
35  */
cipher_free_ctx(struct crypto_cipher_ctx * ctx)36 static void cipher_free_ctx(struct crypto_cipher_ctx *ctx)
37 {
38 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
39 
40 	if (cipher->op && cipher->op->free_ctx)
41 		cipher->op->free_ctx(cipher->ctx);
42 
43 	free(cipher);
44 }
45 
46 /*
47  * Copy cipher context
48  *
49  * @dst_ctx  [out] Reference the API context pointer destination
50  * @src_ctx  Reference the API context pointer source
51  */
cipher_copy_state(struct crypto_cipher_ctx * dst_ctx,struct crypto_cipher_ctx * src_ctx)52 static void cipher_copy_state(struct crypto_cipher_ctx *dst_ctx,
53 			      struct crypto_cipher_ctx *src_ctx)
54 {
55 	struct crypto_cipher *cipher_src = to_cipher_ctx(src_ctx);
56 	struct crypto_cipher *cipher_dst = to_cipher_ctx(dst_ctx);
57 
58 	if (cipher_src->op && cipher_src->op->copy_state)
59 		cipher_src->op->copy_state(cipher_dst->ctx, cipher_src->ctx);
60 }
61 
62 /*
63  * Initialization of the cipher operation
64  *
65  * @ctx      Reference the API context pointer
66  * @mode     Operation mode
67  * @key1     First Key
68  * @key1_len Length of the first key
69  * @key2     Second Key
70  * @key2_len Length of the second key
71  * @iv       Initial Vector
72  * @iv_len   Length of the IV
73  */
cipher_init(struct crypto_cipher_ctx * ctx,TEE_OperationMode mode,const uint8_t * key1,size_t key1_len,const uint8_t * key2,size_t key2_len,const uint8_t * iv,size_t iv_len)74 static TEE_Result cipher_init(struct crypto_cipher_ctx *ctx,
75 			      TEE_OperationMode mode, const uint8_t *key1,
76 			      size_t key1_len, const uint8_t *key2,
77 			      size_t key2_len, const uint8_t *iv, size_t iv_len)
78 {
79 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
80 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
81 
82 	if ((!key1 && key1_len) || (!key2 && key2_len) || (!iv && iv_len)) {
83 		CRYPTO_TRACE("One of the key is not correct");
84 		CRYPTO_TRACE("key1 @%p-%zu bytes", key1, key1_len);
85 		CRYPTO_TRACE("key2 @%p-%zu bytes", key1, key1_len);
86 		CRYPTO_TRACE("iv   @%p-%zu bytes", iv, iv_len);
87 		return TEE_ERROR_BAD_PARAMETERS;
88 	}
89 
90 	if (cipher->op && cipher->op->init) {
91 		struct drvcrypt_cipher_init dinit = {
92 			.ctx = cipher->ctx,
93 			.encrypt = (mode == TEE_MODE_ENCRYPT),
94 			.key1.data = (uint8_t *)key1,
95 			.key1.length = key1_len,
96 			.key2.data = (uint8_t *)key2,
97 			.key2.length = key2_len,
98 			.iv.data = (uint8_t *)iv,
99 			.iv.length = iv_len,
100 		};
101 
102 		ret = cipher->op->init(&dinit);
103 	}
104 
105 	CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret);
106 	return ret;
107 }
108 
109 /*
110  * Update of the cipher operation
111  *
112  * @ctx        Reference the API context pointer
113  * @last_block True if last block to handle
114  * @data       Data to encrypt/decrypt
115  * @len        Length of the input data and output result
116  * @dst        [out] Output data of the operation
117  */
cipher_update(struct crypto_cipher_ctx * ctx,bool last_block,const uint8_t * data,size_t len,uint8_t * dst)118 static TEE_Result cipher_update(struct crypto_cipher_ctx *ctx, bool last_block,
119 				const uint8_t *data, size_t len, uint8_t *dst)
120 {
121 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
122 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
123 
124 	if (!dst) {
125 		CRYPTO_TRACE("Destination buffer error");
126 		return TEE_ERROR_BAD_PARAMETERS;
127 	}
128 
129 	if (!data && len) {
130 		CRYPTO_TRACE("Bad data data @%p-%zu bytes", data, len);
131 		return TEE_ERROR_BAD_PARAMETERS;
132 	}
133 
134 	if (cipher->op && cipher->op->update) {
135 		struct drvcrypt_cipher_update dupdate = {
136 			.ctx = cipher->ctx,
137 			.last = last_block,
138 			.src.data = (uint8_t *)data,
139 			.src.length = len,
140 			.dst.data = dst,
141 			.dst.length = len,
142 		};
143 
144 		ret = cipher->op->update(&dupdate);
145 	}
146 
147 	CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret);
148 	return ret;
149 }
150 
151 /*
152  * Finalize the cipher operation
153  *
154  * @ctx   Reference the API context pointer
155  */
cipher_final(struct crypto_cipher_ctx * ctx)156 static void cipher_final(struct crypto_cipher_ctx *ctx)
157 {
158 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
159 
160 	if (cipher->op && cipher->op->final)
161 		cipher->op->final(cipher->ctx);
162 }
163 
164 static const struct crypto_cipher_ops cipher_ops = {
165 	.init = cipher_init,
166 	.update = cipher_update,
167 	.final = cipher_final,
168 	.free_ctx = cipher_free_ctx,
169 	.copy_state = cipher_copy_state,
170 };
171 
drvcrypt_cipher_alloc_ctx(struct crypto_cipher_ctx ** ctx,uint32_t algo)172 TEE_Result drvcrypt_cipher_alloc_ctx(struct crypto_cipher_ctx **ctx,
173 				     uint32_t algo)
174 {
175 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
176 	struct crypto_cipher *cipher = NULL;
177 
178 	CRYPTO_TRACE("Cipher alloc_ctx algo 0x%" PRIX32, algo);
179 
180 	assert(ctx);
181 
182 	cipher = calloc(1, sizeof(*cipher));
183 	if (!cipher)
184 		return TEE_ERROR_OUT_OF_MEMORY;
185 
186 	cipher->op = drvcrypt_get_ops(CRYPTO_CIPHER);
187 	if (cipher->op && cipher->op->alloc_ctx)
188 		ret = cipher->op->alloc_ctx(&cipher->ctx, algo);
189 
190 	if (ret != TEE_SUCCESS) {
191 		free(cipher);
192 	} else {
193 		cipher->cipher_ctx.ops = &cipher_ops;
194 		*ctx = &cipher->cipher_ctx;
195 	}
196 
197 	CRYPTO_TRACE("Cipher alloc_ctx ret 0x%" PRIX32, ret);
198 
199 	return ret;
200 }
201