Implement more RNG backend wrappers.
[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 #define CONST_CAST(x) (x)(uintptr_t)
27
28 static int crypto_backend_initialised = 0;
29 static char version[64];
30
31 struct hash_alg {
32         const char *name;
33         SECOidTag oid;
34         CK_MECHANISM_TYPE ck_type;
35         int length;
36 };
37
38 static struct hash_alg hash_algs[] = {
39         { "sha1", SEC_OID_SHA1, CKM_SHA_1_HMAC, 20 },
40         { "sha256", SEC_OID_SHA256, CKM_SHA256_HMAC, 32 },
41         { "sha384", SEC_OID_SHA384, CKM_SHA384_HMAC, 48 },
42         { "sha512", SEC_OID_SHA512, CKM_SHA512_HMAC, 64 },
43 //      { "ripemd160", SEC_OID_RIPEMD160, CKM_RIPEMD160_HMAC, 20 },
44         { NULL, 0, 0, 0 }
45 };
46
47 struct crypt_hash {
48         PK11Context *md;
49         const struct hash_alg *hash;
50 };
51
52 struct crypt_hmac {
53         PK11Context *md;
54         PK11SymKey *key;
55         PK11SlotInfo *slot;
56         const struct hash_alg *hash;
57 };
58
59 static struct hash_alg *_get_alg(const char *name)
60 {
61         int i = 0;
62
63         while (name && hash_algs[i].name) {
64                 if (!strcmp(name, hash_algs[i].name))
65                         return &hash_algs[i];
66                 i++;
67         }
68         return NULL;
69 }
70
71 int crypt_backend_init(struct crypt_device *ctx)
72 {
73         if (crypto_backend_initialised)
74                 return 0;
75
76         if (NSS_NoDB_Init(".") != SECSuccess)
77                 return -EINVAL;
78
79         snprintf(version, 64, "NSS %s", NSS_GetVersion());
80         crypto_backend_initialised = 1;
81         return 0;
82 }
83
84 uint32_t crypt_backend_flags(void)
85 {
86         return 0;
87 }
88
89 const char *crypt_backend_version(void)
90 {
91         return crypto_backend_initialised ? version : "";
92 }
93
94 /* HASH */
95 int crypt_hash_size(const char *name)
96 {
97         struct hash_alg *ha = _get_alg(name);
98
99         return ha ? ha->length : -EINVAL;
100 }
101
102 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
103 {
104         struct crypt_hash *h;
105
106         h = malloc(sizeof(*h));
107         if (!h)
108                 return -ENOMEM;
109
110         h->hash = _get_alg(name);
111         if (!h->hash) {
112                 free(h);
113                 return -EINVAL;
114         }
115
116         h->md = PK11_CreateDigestContext(h->hash->oid);
117         if (!h->md) {
118                 free(h);
119                 return -EINVAL;
120         }
121
122         if (PK11_DigestBegin(h->md) != SECSuccess) {
123                 PK11_DestroyContext(h->md, PR_TRUE);
124                 free(h);
125                 return -EINVAL;
126         }
127
128         *ctx = h;
129         return 0;
130 }
131
132 static int crypt_hash_restart(struct crypt_hash *ctx)
133 {
134         if (PK11_DigestBegin(ctx->md) != SECSuccess)
135                 return -EINVAL;
136
137         return 0;
138 }
139
140 int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
141 {
142         if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
143                 return -EINVAL;
144
145         return 0;
146 }
147
148 int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
149 {
150         unsigned char tmp[64];
151         unsigned int tmp_len;
152
153         if (length > (size_t)ctx->hash->length)
154                 return -EINVAL;
155
156         if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
157                 return -EINVAL;
158
159         memcpy(buffer, tmp, length);
160         memset(tmp, 0, sizeof(tmp));
161
162         if (tmp_len < length)
163                 return -EINVAL;
164
165         if (crypt_hash_restart(ctx))
166                 return -EINVAL;
167
168         return 0;
169 }
170
171 int crypt_hash_destroy(struct crypt_hash *ctx)
172 {
173         PK11_DestroyContext(ctx->md, PR_TRUE);
174         memset(ctx, 0, sizeof(*ctx));
175         free(ctx);
176         return 0;
177 }
178
179 /* HMAC */
180 int crypt_hmac_size(const char *name)
181 {
182         return crypt_hash_size(name);
183 }
184
185 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
186                     const void *buffer, size_t length)
187 {
188         struct crypt_hmac *h;
189         SECItem keyItem;
190         SECItem noParams;
191
192         keyItem.type = siBuffer;
193         keyItem.data = CONST_CAST(unsigned char *)buffer;
194         keyItem.len = (int)length;
195
196         noParams.type = siBuffer;
197         noParams.data = 0;
198         noParams.len = 0;
199
200         h = malloc(sizeof(*h));
201         if (!h)
202                 return -ENOMEM;
203         memset(ctx, 0, sizeof(*ctx));
204
205
206         h->hash = _get_alg(name);
207         if (!h->hash)
208                 goto bad;
209
210         h->slot = PK11_GetInternalKeySlot();
211         if (!h->slot)
212                 goto bad;
213
214         h->key = PK11_ImportSymKey(h->slot, h->hash->ck_type, PK11_OriginUnwrap,
215                                    CKA_SIGN,  &keyItem, NULL);
216         if (!h->key)
217                 goto bad;
218
219         h->md = PK11_CreateContextBySymKey(h->hash->ck_type, CKA_SIGN, h->key,
220                                            &noParams);
221         if (!h->md)
222                 goto bad;
223
224         if (PK11_DigestBegin(h->md) != SECSuccess)
225                 goto bad;
226
227         *ctx = h;
228         return 0;
229 bad:
230         crypt_hmac_destroy(h);
231         return -EINVAL;
232 }
233
234 static int crypt_hmac_restart(struct crypt_hmac *ctx)
235 {
236         if (PK11_DigestBegin(ctx->md) != SECSuccess)
237                 return -EINVAL;
238
239         return 0;
240 }
241
242 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
243 {
244         if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
245                 return -EINVAL;
246
247         return 0;
248 }
249
250 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
251 {
252         unsigned char tmp[64];
253         unsigned int tmp_len;
254
255         if (length > (size_t)ctx->hash->length)
256                 return -EINVAL;
257
258         if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
259                 return -EINVAL;
260
261         memcpy(buffer, tmp, length);
262         memset(tmp, 0, sizeof(tmp));
263
264         if (tmp_len < length)
265                 return -EINVAL;
266
267         if (crypt_hmac_restart(ctx))
268                 return -EINVAL;
269
270         return 0;
271 }
272
273 int crypt_hmac_destroy(struct crypt_hmac *ctx)
274 {
275         if (ctx->key)
276                 PK11_FreeSymKey(ctx->key);
277         if (ctx->slot)
278                 PK11_FreeSlot(ctx->slot);
279         if (ctx->md)
280                 PK11_DestroyContext(ctx->md, PR_TRUE);
281         memset(ctx, 0, sizeof(*ctx));
282         free(ctx);
283         return 0;
284 }
285
286 /* RNG */
287 int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
288 {
289         if (fips)
290                 return -EINVAL;
291
292         if (PK11_GenerateRandom((unsigned char *)buffer, length) != SECSuccess)
293                 return -EINVAL;
294
295         return 0;
296 }