Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2009 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 "gkm-aes-key.h"
24 : #include "gkm-aes-mechanism.h"
25 : #include "gkm-session.h"
26 : #include "gkm-transaction.h"
27 : #include "gkm-util.h"
28 :
29 : #include "egg/egg-libgcrypt.h"
30 : #include "egg/egg-padding.h"
31 : #include "egg/egg-secure-memory.h"
32 :
33 2 : EGG_SECURE_DECLARE (aes_mechanism);
34 :
35 : static CK_RV
36 0 : retrieve_length (GkmSession *session, GkmObject *wrapped, gsize *length)
37 : {
38 : CK_ATTRIBUTE attr;
39 : CK_RV rv;
40 :
41 0 : attr.type = CKA_VALUE;
42 0 : attr.pValue = NULL;
43 0 : attr.ulValueLen = 0;
44 :
45 0 : rv = gkm_object_get_attribute (wrapped, session, &attr);
46 0 : if (rv == CKR_OK)
47 0 : *length = attr.ulValueLen;
48 0 : return rv;
49 : }
50 :
51 : static CK_RV
52 0 : retrieve_value (GkmSession *session, GkmObject *wrapped,
53 : gpointer *value, gsize *n_value)
54 : {
55 : CK_ATTRIBUTE attr;
56 : CK_RV rv;
57 :
58 0 : rv = retrieve_length (session, wrapped, n_value);
59 0 : if (rv != CKR_OK)
60 0 : return rv;
61 :
62 0 : attr.type = CKA_VALUE;
63 0 : attr.pValue = egg_secure_alloc (*n_value);
64 0 : attr.ulValueLen = *n_value;
65 :
66 0 : rv = gkm_object_get_attribute (wrapped, session, &attr);
67 0 : if (rv == CKR_OK)
68 0 : *value = attr.pValue;
69 : else
70 0 : egg_secure_free (attr.pValue);
71 :
72 0 : return rv;
73 : }
74 :
75 : CK_RV
76 0 : gkm_aes_mechanism_wrap (GkmSession *session, CK_MECHANISM_PTR mech,
77 : GkmObject *wrapper, GkmObject *wrapped,
78 : CK_BYTE_PTR output, CK_ULONG_PTR n_output)
79 : {
80 : gcry_cipher_hd_t cih;
81 : gcry_error_t gcry;
82 : GkmAesKey *key;
83 : gpointer value, padded;
84 : gsize n_value, n_padded;
85 : gsize block, pos;
86 : gboolean ret;
87 : CK_RV rv;
88 :
89 0 : g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR);
90 0 : g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
91 0 : g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
92 0 : g_return_val_if_fail (GKM_IS_OBJECT (wrapped), CKR_GENERAL_ERROR);
93 0 : g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);
94 :
95 0 : if (!GKM_IS_AES_KEY (wrapper))
96 0 : return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
97 0 : key = GKM_AES_KEY (wrapper);
98 :
99 0 : block = gkm_aes_key_get_block_size (key);
100 0 : g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);
101 :
102 : /* They just want the length */
103 0 : if (!output) {
104 0 : rv = retrieve_length (session, wrapped, &n_value);
105 0 : if (rv != CKR_OK)
106 0 : return rv;
107 0 : if (!egg_padding_pkcs7_pad (NULL, block, NULL, n_value, NULL, &n_padded))
108 0 : return CKR_KEY_SIZE_RANGE;
109 0 : *n_output = n_padded;
110 0 : return CKR_OK;
111 : }
112 :
113 0 : cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
114 0 : if (cih == NULL)
115 0 : return CKR_FUNCTION_FAILED;
116 :
117 0 : if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
118 0 : gcry_cipher_close (cih);
119 0 : return CKR_MECHANISM_PARAM_INVALID;
120 : }
121 :
122 0 : rv = retrieve_value (session, wrapped, &value, &n_value);
123 0 : if (rv != CKR_OK) {
124 0 : gcry_cipher_close (cih);
125 0 : return rv;
126 : }
127 :
128 0 : ret = egg_padding_pkcs7_pad (egg_secure_realloc, block, value, n_value, &padded, &n_padded);
129 0 : egg_secure_free (value);
130 :
131 0 : if (ret == FALSE) {
132 0 : gcry_cipher_close (cih);
133 0 : return CKR_KEY_SIZE_RANGE;
134 : }
135 :
136 : /* In place encryption */
137 0 : for (pos = 0; pos < n_padded; pos += block) {
138 0 : gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, block, NULL, 0);
139 0 : g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
140 : }
141 :
142 0 : gcry_cipher_close (cih);
143 :
144 0 : rv = gkm_util_return_data (output, n_output, padded, n_padded);
145 0 : egg_secure_free (padded);
146 0 : return rv;
147 : }
148 :
149 : CK_RV
150 1 : gkm_aes_mechanism_unwrap (GkmSession *session, CK_MECHANISM_PTR mech,
151 : GkmObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input,
152 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
153 : GkmObject **unwrapped)
154 : {
155 : gcry_cipher_hd_t cih;
156 : gcry_error_t gcry;
157 : CK_ATTRIBUTE attr;
158 : GArray *array;
159 : GkmAesKey *key;
160 : gpointer padded, value;
161 : gsize n_padded, n_value;
162 : GkmTransaction *transaction;
163 : gsize block, pos;
164 : gboolean ret;
165 :
166 1 : g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR);
167 1 : g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
168 1 : g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
169 1 : g_return_val_if_fail (GKM_IS_OBJECT (wrapper), CKR_GENERAL_ERROR);
170 :
171 1 : if (!GKM_IS_AES_KEY (wrapper))
172 0 : return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
173 1 : key = GKM_AES_KEY (wrapper);
174 :
175 1 : block = gkm_aes_key_get_block_size (key);
176 1 : g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);
177 :
178 1 : if (n_input == 0 || n_input % block != 0)
179 0 : return CKR_WRAPPED_KEY_LEN_RANGE;
180 :
181 1 : cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
182 1 : if (cih == NULL)
183 0 : return CKR_FUNCTION_FAILED;
184 :
185 1 : if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
186 0 : gcry_cipher_close (cih);
187 0 : return CKR_MECHANISM_PARAM_INVALID;
188 : }
189 :
190 1 : padded = egg_secure_alloc (n_input);
191 1 : memcpy (padded, input, n_input);
192 1 : n_padded = n_input;
193 :
194 : /* In place decryption */
195 2 : for (pos = 0; pos < n_padded; pos += block) {
196 1 : gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, block, NULL, 0);
197 1 : g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
198 : }
199 :
200 1 : gcry_cipher_close (cih);
201 :
202 : /* Unpad the resulting value */
203 1 : ret = egg_padding_pkcs7_unpad (egg_secure_realloc, block, padded, n_padded, &value, &n_value);
204 1 : egg_secure_free (padded);
205 :
206 : /* TODO: This is dubious, there doesn't seem to be an rv for 'bad decrypt' */
207 1 : if (ret == FALSE)
208 0 : return CKR_WRAPPED_KEY_INVALID;
209 :
210 : /* Now setup the attributes with our new value */
211 1 : array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
212 :
213 : /* Prepend the value */
214 1 : attr.type = CKA_VALUE;
215 1 : attr.pValue = value;
216 1 : attr.ulValueLen = n_value;
217 1 : g_array_append_val (array, attr);
218 :
219 : /* Add the remainder of the attributes */
220 1 : g_array_append_vals (array, attrs, n_attrs);
221 :
222 1 : transaction = gkm_transaction_new ();
223 :
224 : /* Now create an object with these attributes */
225 2 : *unwrapped = gkm_session_create_object_for_attributes (session, transaction,
226 1 : (CK_ATTRIBUTE_PTR)array->data, array->len);
227 :
228 1 : egg_secure_free (value);
229 1 : g_array_free (array, TRUE);
230 :
231 1 : return gkm_transaction_complete_and_unref (transaction);
232 : }
|