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