summaryrefslogtreecommitdiffstats
path: root/crypto/chainiv.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-06-21 07:11:46 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2015-06-22 03:49:28 -0400
commit341476d6cf224f1dea5c439cd70181053629ce15 (patch)
tree23976bbcaf26202ea1082567bd4d402e7ba1c3eb /crypto/chainiv.c
parent9aa867e46565d61491f884c793e4988678fbffa3 (diff)
crypto: chainiv - Offer normal cipher functionality without RNG
The RNG may not be available during early boot, e.g., the relevant modules may not be included in the initramfs. As the RNG Is only needed for IPsec, we should not let this prevent use of ciphers without IV generators, e.g., for disk encryption. This patch postpones the RNG allocation to the init function so that one failure during early boot does not make the RNG unavailable for all subsequent users of the same cipher. More importantly, it lets the cipher live even if RNG allocation fails. Of course we no longer offer IV generation and which will fail with an error if invoked. But all other cipher capabilities will function as usual. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/chainiv.c')
-rw-r--r--crypto/chainiv.c55
1 files changed, 29 insertions, 26 deletions
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index be0bd521c46f..b4340018c8d4 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -83,21 +83,34 @@ unlock:
83static int chainiv_init_common(struct crypto_tfm *tfm, char iv[]) 83static int chainiv_init_common(struct crypto_tfm *tfm, char iv[])
84{ 84{
85 struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); 85 struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
86 int err = 0;
86 87
87 tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request); 88 tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
88 89
89 return crypto_rng_get_bytes(crypto_default_rng, iv, 90 if (iv) {
90 crypto_ablkcipher_ivsize(geniv)) ?: 91 err = crypto_rng_get_bytes(crypto_default_rng, iv,
91 skcipher_geniv_init(tfm); 92 crypto_ablkcipher_ivsize(geniv));
93 crypto_put_default_rng();
94 }
95
96 return err ?: skcipher_geniv_init(tfm);
92} 97}
93 98
94static int chainiv_init(struct crypto_tfm *tfm) 99static int chainiv_init(struct crypto_tfm *tfm)
95{ 100{
101 struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
96 struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm); 102 struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
103 char *iv;
97 104
98 spin_lock_init(&ctx->lock); 105 spin_lock_init(&ctx->lock);
99 106
100 return chainiv_init_common(tfm, ctx->iv); 107 iv = NULL;
108 if (!crypto_get_default_rng()) {
109 crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
110 iv = ctx->iv;
111 }
112
113 return chainiv_init_common(tfm, iv);
101} 114}
102 115
103static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx) 116static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx)
@@ -216,14 +229,23 @@ static void async_chainiv_do_postponed(struct work_struct *work)
216 229
217static int async_chainiv_init(struct crypto_tfm *tfm) 230static int async_chainiv_init(struct crypto_tfm *tfm)
218{ 231{
232 struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
219 struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm); 233 struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
234 char *iv;
220 235
221 spin_lock_init(&ctx->lock); 236 spin_lock_init(&ctx->lock);
222 237
223 crypto_init_queue(&ctx->queue, 100); 238 crypto_init_queue(&ctx->queue, 100);
224 INIT_WORK(&ctx->postponed, async_chainiv_do_postponed); 239 INIT_WORK(&ctx->postponed, async_chainiv_do_postponed);
225 240
226 return chainiv_init_common(tfm, ctx->iv); 241 iv = NULL;
242 if (!crypto_get_default_rng()) {
243 crypto_ablkcipher_crt(geniv)->givencrypt =
244 async_chainiv_givencrypt;
245 iv = ctx->iv;
246 }
247
248 return chainiv_init_common(tfm, iv);
227} 249}
228 250
229static void async_chainiv_exit(struct crypto_tfm *tfm) 251static void async_chainiv_exit(struct crypto_tfm *tfm)
@@ -241,21 +263,14 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
241{ 263{
242 struct crypto_attr_type *algt; 264 struct crypto_attr_type *algt;
243 struct crypto_instance *inst; 265 struct crypto_instance *inst;
244 int err;
245 266
246 algt = crypto_get_attr_type(tb); 267 algt = crypto_get_attr_type(tb);
247 if (IS_ERR(algt)) 268 if (IS_ERR(algt))
248 return ERR_CAST(algt); 269 return ERR_CAST(algt);
249 270
250 err = crypto_get_default_rng();
251 if (err)
252 return ERR_PTR(err);
253
254 inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0); 271 inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
255 if (IS_ERR(inst)) 272 if (IS_ERR(inst))
256 goto put_rng; 273 goto out;
257
258 inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt;
259 274
260 inst->alg.cra_init = chainiv_init; 275 inst->alg.cra_init = chainiv_init;
261 inst->alg.cra_exit = skcipher_geniv_exit; 276 inst->alg.cra_exit = skcipher_geniv_exit;
@@ -265,8 +280,6 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
265 if (!crypto_requires_sync(algt->type, algt->mask)) { 280 if (!crypto_requires_sync(algt->type, algt->mask)) {
266 inst->alg.cra_flags |= CRYPTO_ALG_ASYNC; 281 inst->alg.cra_flags |= CRYPTO_ALG_ASYNC;
267 282
268 inst->alg.cra_ablkcipher.givencrypt = async_chainiv_givencrypt;
269
270 inst->alg.cra_init = async_chainiv_init; 283 inst->alg.cra_init = async_chainiv_init;
271 inst->alg.cra_exit = async_chainiv_exit; 284 inst->alg.cra_exit = async_chainiv_exit;
272 285
@@ -277,22 +290,12 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
277 290
278out: 291out:
279 return inst; 292 return inst;
280
281put_rng:
282 crypto_put_default_rng();
283 goto out;
284}
285
286static void chainiv_free(struct crypto_instance *inst)
287{
288 skcipher_geniv_free(inst);
289 crypto_put_default_rng();
290} 293}
291 294
292static struct crypto_template chainiv_tmpl = { 295static struct crypto_template chainiv_tmpl = {
293 .name = "chainiv", 296 .name = "chainiv",
294 .alloc = chainiv_alloc, 297 .alloc = chainiv_alloc,
295 .free = chainiv_free, 298 .free = skcipher_geniv_free,
296 .module = THIS_MODULE, 299 .module = THIS_MODULE,
297}; 300};
298 301