Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "pkcs11/pkcs11.h"
24 : #include "pkcs11/pkcs11i.h"
25 :
26 : #include "gkm-aes-mechanism.h"
27 : #include "gkm-attributes.h"
28 : #include "gkm-crypto.h"
29 : #include "gkm-aes-key.h"
30 : #include "gkm-session.h"
31 : #include "gkm-transaction.h"
32 : #include "gkm-util.h"
33 :
34 : #include "egg/egg-secure-memory.h"
35 :
36 : struct _GkmAesKey {
37 : GkmSecretKey parent;
38 : gpointer value;
39 : gsize n_value;
40 : };
41 :
42 17 : G_DEFINE_TYPE (GkmAesKey, gkm_aes_key, GKM_TYPE_SECRET_KEY);
43 :
44 : static const CK_MECHANISM_TYPE GKM_AES_MECHANISMS[] = {
45 : CKM_AES_CBC_PAD,
46 : CKM_G_HKDF_SHA256_DERIVE
47 : };
48 :
49 1 : EGG_SECURE_DECLARE (aes_key);
50 :
51 : /* -----------------------------------------------------------------------------
52 : * INTERNAL
53 : */
54 :
55 : static int
56 3 : algorithm_for_length (gsize length)
57 : {
58 3 : switch (length) {
59 3 : case 16:
60 3 : return GCRY_CIPHER_AES128;
61 0 : case 24:
62 0 : return GCRY_CIPHER_AES192;
63 0 : case 32:
64 0 : return GCRY_CIPHER_AES256;
65 0 : default:
66 0 : return 0;
67 : }
68 : }
69 :
70 : static CK_RV
71 0 : attribute_set_check_value (GkmAesKey *self, CK_ATTRIBUTE *attr)
72 : {
73 : gcry_cipher_hd_t cih;
74 : gcry_error_t gcry;
75 : gpointer data;
76 : CK_RV rv;
77 :
78 0 : g_assert (GKM_IS_AES_KEY (self));
79 0 : g_assert (attr);
80 :
81 : /* Just asking for the length */
82 0 : if (!attr->pValue) {
83 0 : attr->ulValueLen = 3;
84 0 : return CKR_OK;
85 : }
86 :
87 0 : cih = gkm_aes_key_get_cipher (self, GCRY_CIPHER_MODE_ECB);
88 0 : if (cih == NULL)
89 0 : return CKR_FUNCTION_FAILED;
90 :
91 : /* Buffer of zeros */
92 0 : data = g_malloc0 (self->n_value);
93 :
94 : /* Encrypt it */
95 0 : gcry = gcry_cipher_encrypt (cih, data, self->n_value, NULL, 0);
96 0 : g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
97 :
98 : /* Use the first three bytes */
99 0 : g_assert (self->n_value > 3);
100 0 : rv = gkm_attribute_set_data (attr, data, 3);
101 :
102 0 : gcry_cipher_close (cih);
103 0 : g_free (data);
104 :
105 0 : return rv;
106 : }
107 :
108 : static GkmObject*
109 1 : factory_create_aes_key (GkmSession *session, GkmTransaction *transaction,
110 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
111 : {
112 : GkmAesKey *key;
113 : GkmManager *manager;
114 : CK_ATTRIBUTE_PTR value;
115 :
116 1 : value = gkm_attributes_find (attrs, n_attrs, CKA_VALUE);
117 1 : if (value == NULL) {
118 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
119 0 : return NULL;
120 : }
121 :
122 1 : if (algorithm_for_length (value->ulValueLen) == 0) {
123 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
124 0 : return NULL;
125 : }
126 :
127 1 : manager = gkm_manager_for_template (attrs, n_attrs, session);
128 1 : key = g_object_new (GKM_TYPE_AES_KEY,
129 : "module", gkm_session_get_module (session),
130 : "manager", manager,
131 : NULL);
132 :
133 1 : key->value = egg_secure_alloc (value->ulValueLen);
134 1 : key->n_value = value->ulValueLen;
135 1 : memcpy (key->value, value->pValue, key->n_value);
136 :
137 1 : gkm_attribute_consume (value);
138 :
139 1 : gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (key),
140 : TRUE, attrs, n_attrs);
141 1 : return GKM_OBJECT (key);
142 : }
143 :
144 : /* -----------------------------------------------------------------------------
145 : * OBJECT
146 : */
147 :
148 : static CK_RV
149 9 : gkm_aes_key_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE *attr)
150 : {
151 9 : GkmAesKey *self = GKM_AES_KEY (base);
152 :
153 9 : switch (attr->type)
154 : {
155 1 : case CKA_KEY_TYPE:
156 1 : return gkm_attribute_set_ulong (attr, CKK_AES);
157 :
158 0 : case CKA_DERIVE:
159 0 : return gkm_attribute_set_bool (attr, CK_TRUE);
160 :
161 1 : case CKA_UNWRAP:
162 : case CKA_WRAP:
163 1 : return gkm_attribute_set_bool (attr, CK_TRUE);
164 :
165 0 : case CKA_VALUE:
166 0 : return gkm_attribute_set_data (attr, self->value, self->n_value);
167 :
168 1 : case CKA_VALUE_LEN:
169 1 : return gkm_attribute_set_ulong (attr, self->n_value);
170 :
171 0 : case CKA_CHECK_VALUE:
172 0 : return attribute_set_check_value (self, attr);
173 :
174 2 : case CKA_ALLOWED_MECHANISMS:
175 2 : return gkm_attribute_set_data (attr, (CK_VOID_PTR)GKM_AES_MECHANISMS,
176 : sizeof (GKM_AES_MECHANISMS));
177 : };
178 :
179 4 : return GKM_OBJECT_CLASS (gkm_aes_key_parent_class)->get_attribute (base, session, attr);
180 : }
181 :
182 : static gconstpointer
183 0 : gkm_aes_key_get_key_value (GkmSecretKey *key, gsize *n_value)
184 : {
185 0 : GkmAesKey *self = GKM_AES_KEY (key);
186 0 : *n_value = self->n_value;
187 0 : return self->value;
188 : }
189 :
190 : static void
191 1 : gkm_aes_key_init (GkmAesKey *self)
192 : {
193 :
194 1 : }
195 :
196 : static void
197 1 : gkm_aes_key_finalize (GObject *obj)
198 : {
199 1 : GkmAesKey *self = GKM_AES_KEY (obj);
200 :
201 1 : if (self->value) {
202 1 : egg_secure_clear (self->value, self->n_value);
203 1 : egg_secure_free (self->value);
204 1 : self->value = NULL;
205 1 : self->n_value = 0;
206 : }
207 :
208 1 : G_OBJECT_CLASS (gkm_aes_key_parent_class)->finalize (obj);
209 1 : }
210 :
211 : static void
212 1 : gkm_aes_key_class_init (GkmAesKeyClass *klass)
213 : {
214 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
215 1 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
216 1 : GkmSecretKeyClass *key_class = GKM_SECRET_KEY_CLASS (klass);
217 :
218 1 : gkm_aes_key_parent_class = g_type_class_peek_parent (klass);
219 :
220 1 : gobject_class->finalize = gkm_aes_key_finalize;
221 :
222 1 : gkm_class->get_attribute = gkm_aes_key_get_attribute;
223 :
224 1 : key_class->get_key_value = gkm_aes_key_get_key_value;
225 1 : }
226 :
227 : /* -----------------------------------------------------------------------------
228 : * PUBLIC
229 : */
230 :
231 : GkmFactory*
232 287 : gkm_aes_key_get_factory (void)
233 : {
234 : static CK_OBJECT_CLASS klass = CKO_SECRET_KEY;
235 : static CK_KEY_TYPE type = CKK_AES;
236 :
237 : static CK_ATTRIBUTE attributes[] = {
238 : { CKA_CLASS, &klass, sizeof (klass) },
239 : { CKA_KEY_TYPE, &type, sizeof (type) }
240 : };
241 :
242 : static GkmFactory factory = {
243 : attributes,
244 : G_N_ELEMENTS (attributes),
245 : factory_create_aes_key
246 : };
247 :
248 287 : return &factory;
249 : }
250 :
251 : gsize
252 1 : gkm_aes_key_get_block_size (GkmAesKey *self)
253 : {
254 : int algorithm;
255 :
256 1 : g_return_val_if_fail (GKM_IS_AES_KEY (self), 0);
257 :
258 1 : algorithm = algorithm_for_length (self->n_value);
259 1 : g_return_val_if_fail (algorithm != 0, 0);
260 :
261 1 : return self->n_value;
262 : }
263 :
264 : gcry_cipher_hd_t
265 1 : gkm_aes_key_get_cipher (GkmAesKey *self, int mode)
266 : {
267 : gcry_cipher_hd_t cih;
268 : gcry_error_t gcry;
269 : int algorithm;
270 :
271 1 : g_return_val_if_fail (GKM_IS_AES_KEY (self), NULL);
272 :
273 1 : algorithm = algorithm_for_length (self->n_value);
274 1 : g_return_val_if_fail (algorithm != 0, NULL);
275 :
276 1 : gcry = gcry_cipher_open (&cih, algorithm, mode, 0);
277 1 : if (gcry != 0) {
278 0 : g_warning ("couldn't open %s cipher: %s",
279 : gcry_cipher_algo_name (algorithm), gcry_strerror (gcry));
280 0 : return NULL;
281 : }
282 :
283 : /* Setup the key */
284 1 : gcry = gcry_cipher_setkey (cih, self->value, self->n_value);
285 1 : g_return_val_if_fail (gcry == 0, NULL);
286 :
287 1 : return cih;
288 : }
|