Prevent to initialise backends twice.
[platform/upstream/cryptsetup.git] / lib / crypto_backend / crypto_nss.c
1 /*
2  * NSS crypto backend implementation
3  *
4  * Copyright (C) 2010 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <string.h>
21 #include <errno.h>
22 #include <nss.h>
23 #include <nss/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(void)
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 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, (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 > 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         return 0;
158 }
159
160 int crypt_hash_destroy(struct crypt_hash *ctx)
161 {
162         PK11_DestroyContext(ctx->md, PR_TRUE);
163         memset(ctx, 0, sizeof(*ctx));
164         free(ctx);
165         return 0;
166 }
167
168 /* HMAC */
169 int crypt_hmac_size(const char *name)
170 {
171         return crypt_hash_size(name);
172 }
173
174 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
175                     const void *buffer, size_t length)
176 {
177         struct crypt_hmac *h;
178         SECItem keyItem;
179         SECItem noParams;
180
181         keyItem.type = siBuffer;
182         keyItem.data = (unsigned char *)buffer;
183         keyItem.len = (int)length;
184
185         noParams.type = siBuffer;
186         noParams.data = 0;
187         noParams.len = 0;
188
189         h = malloc(sizeof(*h));
190         if (!h)
191                 return -ENOMEM;
192         memset(ctx, 0, sizeof(*ctx));
193
194
195         h->hash = _get_alg(name);
196         if (!h->hash)
197                 goto bad;
198
199         h->slot = PK11_GetInternalKeySlot();
200         if (!h->slot)
201                 goto bad;
202
203         h->key = PK11_ImportSymKey(h->slot, h->hash->ck_type, PK11_OriginUnwrap,
204                                    CKA_SIGN,  &keyItem, NULL);
205         if (!h->key)
206                 goto bad;
207
208         h->md = PK11_CreateContextBySymKey(h->hash->ck_type, CKA_SIGN, h->key,
209                                            &noParams);
210         if (!h->md)
211                 goto bad;
212
213         if (PK11_DigestBegin(h->md) != SECSuccess)
214                 goto bad;
215
216         *ctx = h;
217         return 0;
218 bad:
219         crypt_hmac_destroy(h);
220         return -EINVAL;
221 }
222
223 int crypt_hmac_restart(struct crypt_hmac *ctx)
224 {
225         if (PK11_DigestBegin(ctx->md) != SECSuccess)
226                 return -EINVAL;
227
228         return 0;
229 }
230
231 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
232 {
233         if (PK11_DigestOp(ctx->md, (unsigned char *)buffer, length) != SECSuccess)
234                 return -EINVAL;
235
236         return 0;
237 }
238
239 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
240 {
241         unsigned char tmp[64];
242         unsigned int tmp_len;
243
244         if (length > ctx->hash->length)
245                 return -EINVAL;
246
247         if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
248                 return -EINVAL;
249
250         memcpy(buffer, tmp, length);
251         memset(tmp, 0, sizeof(tmp));
252
253         if (tmp_len < length)
254                 return -EINVAL;
255
256         return 0;
257 }
258
259 int crypt_hmac_destroy(struct crypt_hmac *ctx)
260 {
261         if (ctx->key)
262                 PK11_FreeSymKey(ctx->key);
263         if (ctx->slot)
264                 PK11_FreeSlot(ctx->slot);
265         if (ctx->md)
266                 PK11_DestroyContext(ctx->md, PR_TRUE);
267         memset(ctx, 0, sizeof(*ctx));
268         free(ctx);
269         return 0;
270 }