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