1 /*
2  * gnome-keyring
3  *
4  * Copyright (C) 2010 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 "egg/egg-secure-memory.h"
24 
25 #include "gkm/gkm-attributes.h"
26 #include "gkm/gkm-mock.h"
27 #include "gkm/gkm-test.h"
28 
29 #include "wrap-layer/gkm-wrap-layer.h"
30 
31 static guint secret_identifier = 8800;
32 
33 EGG_SECURE_DEFINE_GLIB_GLOBALS ();
34 
35 static CK_RV
mock_secret_C_Initialize(CK_VOID_PTR pInitArgs)36 mock_secret_C_Initialize (CK_VOID_PTR pInitArgs)
37 {
38 	GArray *attrs;
39 	CK_RV rv;
40 
41 	rv = gkm_mock_C_Initialize (pInitArgs);
42 	if (rv != CKR_OK)
43 		return rv;
44 
45 	attrs = gkm_template_new (NULL, 0);
46 	gkm_template_set_ulong (attrs, CKA_CLASS, CKO_G_COLLECTION);
47 	gkm_template_set_boolean (attrs, CKA_G_LOGIN_COLLECTION, CK_TRUE);
48 	gkm_template_set_string (attrs, CKA_ID, "login");
49 	gkm_template_set_string (attrs, CKA_LABEL, "Login Keyring");
50 	gkm_template_set_boolean (attrs, CKA_TRUSTED, CK_TRUE);
51 	gkm_template_set_boolean (attrs, CKA_G_LOCKED, CK_FALSE);
52 	gkm_template_set_boolean (attrs, CKA_TOKEN, CK_TRUE);
53 	gkm_mock_module_take_object (attrs);
54 
55 	attrs = gkm_template_new (NULL, 0);
56 	gkm_template_set_ulong (attrs, CKA_CLASS, CKO_G_COLLECTION);
57 	gkm_template_set_boolean (attrs, CKA_G_LOGIN_COLLECTION, CK_FALSE);
58 	gkm_template_set_string (attrs, CKA_ID, "other");
59 	gkm_template_set_string (attrs, CKA_LABEL, "Other Keyring");
60 	gkm_template_set_boolean (attrs, CKA_TRUSTED, CK_TRUE);
61 	gkm_template_set_boolean (attrs, CKA_G_LOCKED, CK_TRUE);
62 	gkm_template_set_boolean (attrs, CKA_TOKEN, CK_TRUE);
63 	gkm_mock_module_take_object (attrs);
64 
65 	attrs = gkm_template_new (NULL, 0);
66 	gkm_template_set_string (attrs, CKA_G_COLLECTION, "login");
67 	gkm_template_set_string (attrs, CKA_ID, "23");
68 	gkm_template_set_string (attrs, CKA_LABEL, "Unlock password for: Mock");
69 	gkm_template_set_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY);
70 	gkm_template_set_value (attrs, CKA_G_FIELDS, "one\0" "1\0" "two\0" "2\0", 12);
71 	gkm_template_set_string (attrs, CKA_VALUE, "mock");
72 	gkm_template_set_boolean (attrs, CKA_TOKEN, CK_TRUE);
73 	gkm_template_set_boolean (attrs, CKA_G_LOCKED, CK_FALSE);
74 	gkm_mock_module_take_object (attrs);
75 
76 	return CKR_OK;
77 }
78 
79 typedef struct {
80 	GArray *template;
81 	GArray *objects;
82 } FieldSearch;
83 
84 static gboolean
match_fields(gconstpointer fields,gsize n_fields,gconstpointer all,gsize n_all)85 match_fields (gconstpointer fields, gsize n_fields, gconstpointer all, gsize n_all)
86 {
87 	const guchar *field;
88 	gsize n_field;
89 	const guchar *ptr;
90 	const guchar *last;
91 
92 	g_assert (all);
93 	g_assert (fields);
94 
95 	ptr = fields;
96 	last = ptr + n_fields;
97 
98 	g_assert (ptr || last == ptr);
99 	while (ptr && ptr != last) {
100 		g_assert (ptr < last);
101 
102 		field = ptr;
103 		ptr = memchr (ptr, 0, last - ptr);
104 		g_assert (ptr);
105 		++ptr;
106 
107 		ptr = memchr (ptr, 0, last - ptr);
108 		g_assert (ptr);
109 		++ptr;
110 
111 		n_field = ptr - field;
112 		if (!memmem (all, n_all, field, n_field))
113 			return FALSE;
114 	}
115 
116 	return TRUE;
117 }
118 
119 static gboolean
enumerate_field_search(CK_OBJECT_HANDLE handle,GArray * attrs,gpointer user_data)120 enumerate_field_search (CK_OBJECT_HANDLE handle, GArray *attrs, gpointer user_data)
121 {
122 	FieldSearch *ctx = user_data;
123 	CK_ATTRIBUTE_PTR tattr;
124 	CK_ATTRIBUTE_PTR oattr;
125 
126 	tattr = gkm_template_find (ctx->template, CKA_G_FIELDS);
127 	g_assert (tattr);
128 
129 	oattr = gkm_template_find (attrs, CKA_G_FIELDS);
130 	if (!oattr)
131 		return TRUE; /* Continue */
132 	if (!match_fields (tattr->pValue, tattr->ulValueLen, oattr->pValue, oattr->ulValueLen))
133 		return TRUE; /* Continue */
134 
135 	tattr = gkm_template_find (ctx->template, CKA_G_COLLECTION);
136 	if (tattr) {
137 		oattr = gkm_template_find (attrs, CKA_G_COLLECTION);
138 		if (!oattr || oattr->ulValueLen != tattr->ulValueLen)
139 			return TRUE; /* Continue */
140 		if (memcmp (oattr->pValue, tattr->pValue, oattr->ulValueLen) != 0)
141 			return TRUE; /* Continue */
142 	}
143 
144 	/* Add it to the set */
145 	g_array_append_val (ctx->objects, handle);
146 	return TRUE; /* Continue */
147 }
148 
149 static CK_RV
mock_secret_C_CreateObject(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phObject)150 mock_secret_C_CreateObject (CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
151                             CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
152 {
153 	GArray *template = NULL;
154 	CK_OBJECT_CLASS klass;
155 	CK_ATTRIBUTE_PTR attr;
156 	gchar *text;
157 	CK_RV rv;
158 
159 	g_return_val_if_fail (phObject, CKR_ARGUMENTS_BAD);
160 
161 	if (!gkm_attributes_find_ulong (pTemplate, ulCount, CKA_CLASS, &klass))
162 		klass = (CK_ULONG)-1;
163 
164 	/* Is it a search object? */
165 	if (klass == CKO_G_SEARCH) {
166 
167 		FieldSearch ctx;
168 		ctx.template = template = gkm_template_new (pTemplate, ulCount);
169 		ctx.objects = g_array_new (FALSE, FALSE, sizeof (CK_OBJECT_HANDLE));
170 
171 		/* Find all the fields */
172 		gkm_mock_module_enumerate_objects (hSession, enumerate_field_search, &ctx);
173 
174 		gkm_template_set_value (template, CKA_G_MATCHED, ctx.objects->data,
175 		                        ctx.objects->len * sizeof (CK_OBJECT_HANDLE));
176 		g_array_free (ctx.objects, TRUE);
177 
178 	} else if (klass == CKO_SECRET_KEY) {
179 
180 		/* If it's a secret key and id set, just overwrite */
181 		attr = gkm_attributes_find (pTemplate, ulCount, CKA_ID);
182 		if (attr) {
183 			CK_ATTRIBUTE attrs[2];
184 
185 			memcpy (attrs, attr, sizeof (CK_ATTRIBUTE));
186 			attrs[1].type = CKA_CLASS;
187 			attrs[1].ulValueLen = sizeof (klass);
188 			attrs[1].pValue = &klass;
189 
190 			*phObject = gkm_mock_module_find_object (hSession, attrs, 2);
191 			g_return_val_if_fail (*phObject, CKR_TEMPLATE_INCONSISTENT);
192 			return gkm_mock_C_SetAttributeValue (hSession, *phObject, pTemplate, ulCount);
193 		}
194 
195 		/* Otherwise add a unique identifier */
196 		template = gkm_template_new (pTemplate, ulCount);
197 		text = g_strdup_printf ("%d", ++secret_identifier);
198 		gkm_template_set_string (template, CKA_ID, text);
199 		g_free (text);
200 	}
201 
202 	if (template) {
203 		pTemplate = (CK_ATTRIBUTE_PTR)template->data;
204 		ulCount = template->len;
205 	}
206 
207 	rv = gkm_mock_C_CreateObject (hSession, pTemplate, ulCount, phObject);
208 
209 	if (template)
210 		gkm_template_free (template);
211 
212 	return rv;
213 }
214 
215 CK_FUNCTION_LIST mock_secret_store = {
216 	{ 2, 11 },	/* version */
217 	mock_secret_C_Initialize,
218 	gkm_mock_C_Finalize,
219 	gkm_mock_C_GetInfo,
220 	gkm_mock_C_GetFunctionList,
221 	gkm_mock_C_GetSlotList,
222 	gkm_mock_C_GetSlotInfo,
223 	gkm_mock_C_GetTokenInfo,
224 	gkm_mock_C_GetMechanismList,
225 	gkm_mock_C_GetMechanismInfo,
226 	gkm_mock_C_InitToken,
227 	gkm_mock_C_InitPIN,
228 	gkm_mock_C_SetPIN,
229 	gkm_mock_C_OpenSession,
230 	gkm_mock_C_CloseSession,
231 	gkm_mock_C_CloseAllSessions,
232 	gkm_mock_C_GetSessionInfo,
233 	gkm_mock_unsupported_C_GetOperationState,
234 	gkm_mock_unsupported_C_SetOperationState,
235 	gkm_mock_C_Login,
236 	gkm_mock_C_Logout,
237 	mock_secret_C_CreateObject,
238 	gkm_mock_unsupported_C_CopyObject,
239 	gkm_mock_C_DestroyObject,
240 	gkm_mock_unsupported_C_GetObjectSize,
241 	gkm_mock_C_GetAttributeValue,
242 	gkm_mock_C_SetAttributeValue,
243 	gkm_mock_C_FindObjectsInit,
244 	gkm_mock_C_FindObjects,
245 	gkm_mock_C_FindObjectsFinal,
246 	gkm_mock_C_EncryptInit,
247 	gkm_mock_C_Encrypt,
248 	gkm_mock_unsupported_C_EncryptUpdate,
249 	gkm_mock_unsupported_C_EncryptFinal,
250 	gkm_mock_C_DecryptInit,
251 	gkm_mock_C_Decrypt,
252 	gkm_mock_unsupported_C_DecryptUpdate,
253 	gkm_mock_unsupported_C_DecryptFinal,
254 	gkm_mock_unsupported_C_DigestInit,
255 	gkm_mock_unsupported_C_Digest,
256 	gkm_mock_unsupported_C_DigestUpdate,
257 	gkm_mock_unsupported_C_DigestKey,
258 	gkm_mock_unsupported_C_DigestFinal,
259 	gkm_mock_C_SignInit,
260 	gkm_mock_C_Sign,
261 	gkm_mock_unsupported_C_SignUpdate,
262 	gkm_mock_unsupported_C_SignFinal,
263 	gkm_mock_unsupported_C_SignRecoverInit,
264 	gkm_mock_unsupported_C_SignRecover,
265 	gkm_mock_C_VerifyInit,
266 	gkm_mock_C_Verify,
267 	gkm_mock_unsupported_C_VerifyUpdate,
268 	gkm_mock_unsupported_C_VerifyFinal,
269 	gkm_mock_unsupported_C_VerifyRecoverInit,
270 	gkm_mock_unsupported_C_VerifyRecover,
271 	gkm_mock_unsupported_C_DigestEncryptUpdate,
272 	gkm_mock_unsupported_C_DecryptDigestUpdate,
273 	gkm_mock_unsupported_C_SignEncryptUpdate,
274 	gkm_mock_unsupported_C_DecryptVerifyUpdate,
275 	gkm_mock_unsupported_C_GenerateKey,
276 	gkm_mock_unsupported_C_GenerateKeyPair,
277 	gkm_mock_unsupported_C_WrapKey,
278 	gkm_mock_unsupported_C_UnwrapKey,
279 	gkm_mock_unsupported_C_DeriveKey,
280 	gkm_mock_unsupported_C_SeedRandom,
281 	gkm_mock_unsupported_C_GenerateRandom,
282 	gkm_mock_C_GetFunctionStatus,
283 	gkm_mock_C_CancelFunction,
284 	gkm_mock_unsupported_C_WaitForSlotEvent
285 };
286