Try to remove device even if it is busy (libdevmapper now handle retry).
[platform/upstream/cryptsetup.git] / lib / crypto_backend / crypto_nss.c
1 /*
2  * NSS crypto backend implementation
3  *
4  * Copyright (C) 2010-2012, Red Hat, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <string.h>
21 #include <errno.h>
22 #include <nss.h>
23 #include <pk11pub.h>
24 #include "crypto_backend.h"
25
26 static int crypto_backend_initialised = 0;
27
28 struct hash_alg {
29         const char *name;
30         SECOidTag oid;
31         CK_MECHANISM_TYPE ck_type;
32         int length;
33 };
34
35 static struct hash_alg hash_algs[] = {
36         { "sha1", SEC_OID_SHA1, CKM_SHA_1_HMAC, 20 },
37         { "sha256", SEC_OID_SHA256, CKM_SHA256_HMAC, 32 },
38         { "sha384", SEC_OID_SHA384, CKM_SHA384_HMAC, 48 },
39         { "sha512", SEC_OID_SHA512, CKM_SHA512_HMAC, 64 },
40 //      { "ripemd160", SEC_OID_RIPEMD160, CKM_RIPEMD160_HMAC, 20 },
41         { NULL, 0, 0, 0 }
42 };
43
44 struct crypt_hash {
45         PK11Context *md;
46         const struct hash_alg *hash;
47 };
48
49 struct crypt_hmac {
50         PK11Context *md;
51         PK11SymKey *key;
52         PK11SlotInfo *slot;
53         const struct hash_alg *hash;
54 };
55
56 static struct hash_alg *_get_alg(const char *name)
57 {
58         int i = 0;
59
60         while (name && hash_algs[i].name) {
61                 if (!strcmp(name, hash_algs[i].name))
62                         return &hash_algs[i];
63                 i++;
64         }
65         return NULL;
66 }
67
68 int crypt_backend_init(struct crypt_device *ctx)
69 {
70         if (crypto_backend_initialised)
71                 return 0;
72
73         log_dbg("Initialising NSS crypto backend.");
74         if (NSS_NoDB_Init(".") != SECSuccess)
75                 return -EINVAL;
76
77         crypto_backend_initialised = 1;
78         return 0;
79 }
80
81 uint32_t crypt_backend_flags(void)
82 {
83         return 0;
84 }
85
86 /* HASH */
87 int crypt_hash_size(const char *name)
88 {
89         struct hash_alg *ha = _get_alg(name);
90
91         return ha ? ha->length : -EINVAL;
92 }
93
94 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
95 {
96         struct crypt_hash *h;
97
98         h = malloc(sizeof(*h));
99         if (!h)
100                 return -ENOMEM;
101
102         h->hash = _get_alg(name);
103         if (!h->hash) {
104                 free(h);
105                 return -EINVAL;
106         }
107
108         h->md = PK11_CreateDigestContext(h->hash->oid);
109         if (!h->md) {
110                 free(h);
111                 return -EINVAL;
112         }
113
114         if (PK11_DigestBegin(h->md) != SECSuccess) {
115                 PK11_DestroyContext(h->md, PR_TRUE);
116                 free(h);
117                 return -EINVAL;
118         }
119
120         *ctx = h;
121         return 0;
122 }
123
124 static int crypt_hash_restart(struct crypt_hash *ctx)
125 {
126         if (PK11_DigestBegin(ctx->md) != SECSuccess)
127                 return -EINVAL;
128
129         return 0;
130 }
131
132 int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
133 {
134         if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
135                 return -EINVAL;
136
137         return 0;
138 }
139
140 int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
141 {
142         unsigned char tmp[64];
143         unsigned int tmp_len;
144
145         if (length > (size_t)ctx->hash->length)
146                 return -EINVAL;
147
148         if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
149                 return -EINVAL;
150
151         memcpy(buffer, tmp, length);
152         memset(tmp, 0, sizeof(tmp));
153
154         if (tmp_len < length)
155                 return -EINVAL;
156
157         if (crypt_hash_restart(ctx))
158                 return -EINVAL;
159
160         return 0;
161 }
162
163 int crypt_hash_destroy(struct crypt_hash *ctx)
164 {
165         PK11_DestroyContext(ctx->md, PR_TRUE);
166         memset(ctx, 0, sizeof(*ctx));
167         free(ctx);
168         return 0;
169 }
170
171 /* HMAC */
172 int crypt_hmac_size(const char *name)
173 {
174         return crypt_hash_size(name);
175 }
176
177 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
178                     const void *buffer, size_t length)
179 {
180         struct crypt_hmac *h;
181         SECItem keyItem;
182         SECItem noParams;
183
184         keyItem.type = siBuffer;
185         keyItem.data = CONST_CAST(unsigned char *)buffer;
186         keyItem.len = (int)length;
187
188         noParams.type = siBuffer;
189         noParams.data = 0;
190         noParams.len = 0;
191
192         h = malloc(sizeof(*h));
193         if (!h)
194                 return -ENOMEM;
195         memset(ctx, 0, sizeof(*ctx));
196
197
198         h->hash = _get_alg(name);
199         if (!h->hash)
200                 goto bad;
201
202         h->slot = PK11_GetInternalKeySlot();
203         if (!h->slot)
204                 goto bad;
205
206         h->key = PK11_ImportSymKey(h->slot, h->hash->ck_type, PK11_OriginUnwrap,
207                                    CKA_SIGN,  &keyItem, NULL);
208         if (!h->key)
209                 goto bad;
210
211         h->md = PK11_CreateContextBySymKey(h->hash->ck_type, CKA_SIGN, h->key,
212                                            &noParams);
213         if (!h->md)
214                 goto bad;
215
216         if (PK11_DigestBegin(h->md) != SECSuccess)
217                 goto bad;
218
219         *ctx = h;
220         return 0;
221 bad:
222         crypt_hmac_destroy(h);
223         return -EINVAL;
224 }
225
226 static int crypt_hmac_restart(struct crypt_hmac *ctx)
227 {
228         if (PK11_DigestBegin(ctx->md) != SECSuccess)
229                 return -EINVAL;
230
231         return 0;
232 }
233
234 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
235 {
236         if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
237                 return -EINVAL;
238
239         return 0;
240 }
241
242 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
243 {
244         unsigned char tmp[64];
245         unsigned int tmp_len;
246
247         if (length > (size_t)ctx->hash->length)
248                 return -EINVAL;
249
250         if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
251                 return -EINVAL;
252
253         memcpy(buffer, tmp, length);
254         memset(tmp, 0, sizeof(tmp));
255
256         if (tmp_len < length)
257                 return -EINVAL;
258
259         if (crypt_hmac_restart(ctx))
260                 return -EINVAL;
261
262         return 0;
263 }
264
265 int crypt_hmac_destroy(struct crypt_hmac *ctx)
266 {
267         if (ctx->key)
268                 PK11_FreeSymKey(ctx->key);
269         if (ctx->slot)
270                 PK11_FreeSlot(ctx->slot);
271         if (ctx->md)
272                 PK11_DestroyContext(ctx->md, PR_TRUE);
273         memset(ctx, 0, sizeof(*ctx));
274         free(ctx);
275         return 0;
276 }