Line data Source code
1 : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : /* p11-rpc-message.c - our marshalled PKCS#11 protocol.
3 :
4 : Copyright (C) 2008, Stef Walter
5 :
6 : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Library General Public License as
8 : published by the Free Software Foundation; either version 2 of the
9 : License, or (at your option) any later version.
10 :
11 : The Gnome Keyring Library is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Library General Public License for more details.
15 :
16 : You should have received a copy of the GNU Library General Public
17 : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : <http://www.gnu.org/licenses/>.
19 :
20 : Author: Stef Walter <stef@memberwebs.com>
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkm-rpc-layer.h"
26 : #include "gkm-rpc-private.h"
27 :
28 : #include <string.h>
29 :
30 : #ifdef G_DISABLE_ASSERT
31 : #define assert(x)
32 : #else
33 : #include <assert.h>
34 : #endif
35 :
36 : GkmRpcMessage*
37 8 : gkm_rpc_message_new (EggBufferAllocator allocator)
38 : {
39 : GkmRpcMessage *msg;
40 :
41 8 : assert (allocator);
42 :
43 8 : msg = (GkmRpcMessage*) (allocator)(NULL, sizeof (GkmRpcMessage));
44 8 : if (!msg)
45 0 : return NULL;
46 8 : memset (msg, 0, sizeof (*msg));
47 :
48 8 : if (!egg_buffer_init_full (&msg->buffer, 64, allocator)) {
49 0 : (allocator) (msg, 0); /* Frees allocation */
50 0 : return NULL;
51 : }
52 :
53 8 : gkm_rpc_message_reset (msg);
54 :
55 8 : return msg;
56 : }
57 :
58 : void
59 8 : gkm_rpc_message_free (GkmRpcMessage *msg)
60 : {
61 : EggBufferAllocator allocator;
62 :
63 8 : if (msg) {
64 8 : assert (msg->buffer.allocator);
65 8 : allocator = msg->buffer.allocator;
66 8 : egg_buffer_uninit (&msg->buffer);
67 :
68 : /* frees data buffer */
69 8 : (allocator) (msg, 0);
70 : }
71 8 : }
72 :
73 : void
74 52 : gkm_rpc_message_reset (GkmRpcMessage *msg)
75 : {
76 52 : assert (msg);
77 :
78 52 : msg->call_id = 0;
79 52 : msg->call_type = 0;
80 52 : msg->signature = NULL;
81 52 : msg->sigverify = NULL;
82 52 : msg->parsed = 0;
83 :
84 52 : egg_buffer_reset (&msg->buffer);
85 52 : }
86 :
87 : int
88 12 : gkm_rpc_message_prep (GkmRpcMessage *msg, int call_id, GkmRpcMessageType type)
89 : {
90 : int len;
91 :
92 12 : assert (type);
93 12 : assert (call_id >= GKM_RPC_CALL_ERROR);
94 12 : assert (call_id < GKM_RPC_CALL_MAX);
95 :
96 12 : gkm_rpc_message_reset (msg);
97 :
98 12 : if (call_id != GKM_RPC_CALL_ERROR) {
99 :
100 : /* The call id and signature */
101 12 : if (type == GKM_RPC_REQUEST)
102 6 : msg->signature = gkm_rpc_calls[call_id].request;
103 6 : else if (type == GKM_RPC_RESPONSE)
104 6 : msg->signature = gkm_rpc_calls[call_id].response;
105 : else
106 0 : assert (0 && "invalid message type");
107 12 : assert (msg->signature);
108 12 : msg->sigverify = msg->signature;
109 : }
110 :
111 12 : msg->call_id = call_id;
112 12 : msg->call_type = type;
113 :
114 : /* Encode the two of them */
115 12 : egg_buffer_add_uint32 (&msg->buffer, call_id);
116 12 : if (msg->signature) {
117 12 : len = strlen (msg->signature);
118 12 : egg_buffer_add_byte_array (&msg->buffer, (unsigned char*)msg->signature, len);
119 : }
120 :
121 12 : msg->parsed = 0;
122 12 : return !egg_buffer_has_error (&msg->buffer);
123 : }
124 :
125 : int
126 12 : gkm_rpc_message_parse (GkmRpcMessage *msg, GkmRpcMessageType type)
127 : {
128 : const unsigned char *val;
129 : size_t len;
130 : uint32_t call_id;
131 :
132 12 : msg->parsed = 0;
133 :
134 : /* Pull out the call identifier */
135 12 : if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &(msg->parsed), &call_id)) {
136 0 : gkm_rpc_warn ("invalid message: couldn't read call identifier");
137 0 : return 0;
138 : }
139 :
140 12 : msg->signature = msg->sigverify = NULL;
141 :
142 : /* If it's an error code then no more processing */
143 12 : if (call_id == GKM_RPC_CALL_ERROR) {
144 0 : if (type == GKM_RPC_REQUEST) {
145 0 : gkm_rpc_warn ("invalid message: error code in request");
146 0 : return 0;
147 : }
148 :
149 0 : return 1;
150 : }
151 :
152 : /* The call id and signature */
153 12 : if (call_id <= 0 || call_id >= GKM_RPC_CALL_MAX) {
154 0 : gkm_rpc_warn ("invalid message: bad call id: %d", call_id);
155 0 : return 0;
156 : }
157 12 : if (type == GKM_RPC_REQUEST)
158 6 : msg->signature = gkm_rpc_calls[call_id].request;
159 6 : else if (type == GKM_RPC_RESPONSE)
160 6 : msg->signature = gkm_rpc_calls[call_id].response;
161 : else
162 0 : assert (0 && "invalid message type");
163 12 : msg->call_id = call_id;
164 12 : msg->call_type = type;
165 12 : msg->sigverify = msg->signature;
166 :
167 : /* Verify the incoming signature */
168 12 : if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &(msg->parsed), &val, &len)) {
169 0 : gkm_rpc_warn ("invalid message: couldn't read signature");
170 0 : return 0;
171 : }
172 :
173 12 : if ((strlen (msg->signature) != len) || (memcmp (val, msg->signature, len) != 0)) {
174 0 : gkm_rpc_warn ("invalid message: signature doesn't match");
175 0 : return 0;
176 : }
177 :
178 12 : return 1;
179 : }
180 :
181 : int
182 0 : gkm_rpc_message_equals (GkmRpcMessage *m1, GkmRpcMessage *m2)
183 : {
184 0 : assert (m1 && m2);
185 :
186 : /* Any errors and messages are never equal */
187 0 : if (egg_buffer_has_error (&m1->buffer) ||
188 0 : egg_buffer_has_error (&m2->buffer))
189 0 : return 0;
190 :
191 : /* Calls and signatures must be identical */
192 0 : if (m1->call_id != m2->call_id)
193 0 : return 0;
194 0 : if (m1->call_type != m2->call_type)
195 0 : return 0;
196 0 : if (m1->signature && m2->signature) {
197 0 : if (strcmp (m1->signature, m2->signature) != 0)
198 0 : return 0;
199 0 : } else if (m1->signature != m2->signature) {
200 0 : return 0;
201 : }
202 :
203 : /* Data in buffer must be identical */
204 0 : return egg_buffer_equal (&m1->buffer, &m2->buffer);
205 : }
206 :
207 : int
208 24 : gkm_rpc_message_verify_part (GkmRpcMessage *msg, const char* part)
209 : {
210 : int len, ok;
211 :
212 24 : if (!msg->sigverify)
213 0 : return 1;
214 :
215 24 : len = strlen (part);
216 24 : ok = (strncmp (msg->sigverify, part, len) == 0);
217 24 : if (ok)
218 24 : msg->sigverify += len;
219 24 : return ok;
220 : }
221 :
222 : int
223 0 : gkm_rpc_message_write_attribute_buffer (GkmRpcMessage *msg, CK_ATTRIBUTE_PTR arr,
224 : CK_ULONG num)
225 : {
226 : CK_ATTRIBUTE_PTR attr;
227 : CK_ULONG i;
228 :
229 0 : assert (!num || arr);
230 0 : assert (msg);
231 :
232 : /* Make sure this is in the rigth order */
233 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "fA"));
234 :
235 : /* Write the number of items */
236 0 : egg_buffer_add_uint32 (&msg->buffer, num);
237 :
238 0 : for (i = 0; i < num; ++i) {
239 0 : attr = &(arr[i]);
240 :
241 : /* The attribute type */
242 0 : egg_buffer_add_uint32 (&msg->buffer, attr->type);
243 :
244 : /* And the attribute buffer length */
245 0 : egg_buffer_add_uint32 (&msg->buffer, attr->pValue ? attr->ulValueLen : 0);
246 : }
247 :
248 0 : return !egg_buffer_has_error (&msg->buffer);
249 : }
250 :
251 : int
252 0 : gkm_rpc_message_write_attribute_array (GkmRpcMessage *msg,
253 : CK_ATTRIBUTE_PTR arr, CK_ULONG num)
254 : {
255 : CK_ULONG i;
256 : CK_ATTRIBUTE_PTR attr;
257 : unsigned char validity;
258 :
259 0 : assert (!num || arr);
260 0 : assert (msg);
261 :
262 : /* Make sure this is in the rigth order */
263 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "aA"));
264 :
265 : /* Write the number of items */
266 0 : egg_buffer_add_uint32 (&msg->buffer, num);
267 :
268 0 : for (i = 0; i < num; ++i) {
269 0 : attr = &(arr[i]);
270 :
271 : /* The attribute type */
272 0 : egg_buffer_add_uint32 (&msg->buffer, attr->type);
273 :
274 : /* Write out the attribute validity */
275 0 : validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1;
276 0 : egg_buffer_add_byte (&msg->buffer, validity);
277 :
278 : /* The attribute length and value */
279 0 : if (validity) {
280 0 : egg_buffer_add_uint32 (&msg->buffer, attr->ulValueLen);
281 0 : egg_buffer_add_byte_array (&msg->buffer, attr->pValue, attr->ulValueLen);
282 : }
283 : }
284 :
285 0 : return !egg_buffer_has_error (&msg->buffer);
286 : }
287 :
288 : int
289 0 : gkm_rpc_message_read_byte (GkmRpcMessage *msg, CK_BYTE *val)
290 : {
291 0 : assert (msg);
292 :
293 : /* Make sure this is in the right order */
294 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "y"));
295 0 : return egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, val);
296 : }
297 :
298 : int
299 0 : gkm_rpc_message_write_byte (GkmRpcMessage *msg, CK_BYTE val)
300 : {
301 0 : assert (msg);
302 :
303 : /* Make sure this is in the right order */
304 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "y"));
305 0 : return egg_buffer_add_byte (&msg->buffer, val);
306 : }
307 :
308 : int
309 2 : gkm_rpc_message_read_ulong (GkmRpcMessage *msg, CK_ULONG *val)
310 : {
311 : uint64_t v;
312 2 : assert (msg);
313 :
314 : /* Make sure this is in the right order */
315 2 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "u"));
316 :
317 2 : if (!egg_buffer_get_uint64 (&msg->buffer, msg->parsed, &msg->parsed, &v))
318 0 : return 0;
319 2 : if (val)
320 2 : *val = (CK_ULONG)v;
321 2 : return 1;
322 : }
323 :
324 : int
325 2 : gkm_rpc_message_write_ulong (GkmRpcMessage *msg, CK_ULONG val)
326 : {
327 2 : assert (msg);
328 :
329 : /* Make sure this is in the rigth order */
330 2 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "u"));
331 2 : return egg_buffer_add_uint64 (&msg->buffer, val);
332 : }
333 :
334 : int
335 0 : gkm_rpc_message_write_byte_buffer (GkmRpcMessage *msg, CK_ULONG count)
336 : {
337 0 : assert (msg);
338 :
339 : /* Make sure this is in the right order */
340 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "fy"));
341 0 : return egg_buffer_add_uint32 (&msg->buffer, count);
342 : }
343 :
344 : int
345 2 : gkm_rpc_message_write_byte_array (GkmRpcMessage *msg, CK_BYTE_PTR arr, CK_ULONG num)
346 : {
347 2 : assert (msg);
348 :
349 : /* Make sure this is in the right order */
350 2 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "ay"));
351 :
352 : /* No array, no data, just length */
353 2 : if (!arr) {
354 0 : egg_buffer_add_byte (&msg->buffer, 0);
355 0 : egg_buffer_add_uint32 (&msg->buffer, num);
356 : } else {
357 2 : egg_buffer_add_byte (&msg->buffer, 1);
358 2 : egg_buffer_add_byte_array (&msg->buffer, arr, num);
359 : }
360 :
361 2 : return !egg_buffer_has_error (&msg->buffer);
362 : }
363 :
364 : int
365 0 : gkm_rpc_message_write_ulong_buffer (GkmRpcMessage *msg, CK_ULONG count)
366 : {
367 0 : assert (msg);
368 :
369 : /* Make sure this is in the right order */
370 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "fu"));
371 0 : return egg_buffer_add_uint32 (&msg->buffer, count);
372 : }
373 :
374 : int
375 0 : gkm_rpc_message_write_ulong_array (GkmRpcMessage *msg, CK_ULONG_PTR array, CK_ULONG n_array)
376 : {
377 : CK_ULONG i;
378 :
379 0 : assert (msg);
380 :
381 : /* Check that we're supposed to have this at this point */
382 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "au"));
383 :
384 : /* We send a byte which determines whether there's actual data present or not */
385 0 : egg_buffer_add_byte (&msg->buffer, array ? 1 : 0);
386 0 : egg_buffer_add_uint32 (&msg->buffer, n_array);
387 :
388 : /* Now send the data if valid */
389 0 : if (array) {
390 0 : for (i = 0; i < n_array; ++i)
391 0 : egg_buffer_add_uint64 (&msg->buffer, array[i]);
392 : }
393 :
394 0 : return !egg_buffer_has_error (&msg->buffer);
395 : }
396 :
397 : int
398 4 : gkm_rpc_message_read_version (GkmRpcMessage *msg, CK_VERSION* version)
399 : {
400 4 : assert (msg);
401 4 : assert (version);
402 :
403 : /* Check that we're supposed to have this at this point */
404 4 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "v"));
405 :
406 8 : return egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &version->major) &&
407 4 : egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &version->minor);
408 : }
409 :
410 : int
411 4 : gkm_rpc_message_write_version (GkmRpcMessage *msg, CK_VERSION* version)
412 : {
413 4 : assert (msg);
414 4 : assert (version);
415 :
416 : /* Check that we're supposed to have this at this point */
417 4 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "v"));
418 :
419 4 : egg_buffer_add_byte (&msg->buffer, version->major);
420 4 : egg_buffer_add_byte (&msg->buffer, version->minor);
421 :
422 4 : return !egg_buffer_has_error (&msg->buffer);
423 : }
424 :
425 : int
426 4 : gkm_rpc_message_read_space_string (GkmRpcMessage *msg, CK_UTF8CHAR* buffer, CK_ULONG length)
427 : {
428 : const unsigned char *data;
429 : size_t n_data;
430 :
431 4 : assert (msg);
432 4 : assert (buffer);
433 4 : assert (length);
434 :
435 4 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "s"));
436 :
437 4 : if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data))
438 0 : return 0;
439 :
440 4 : if (n_data != length) {
441 0 : gkm_rpc_warn ("invalid length space padded string received: %d != %d", length, n_data);
442 0 : return 0;
443 : }
444 :
445 4 : memcpy (buffer, data, length);
446 4 : return 1;
447 : }
448 :
449 : int
450 4 : gkm_rpc_message_write_space_string (GkmRpcMessage *msg, CK_UTF8CHAR* buffer, CK_ULONG length)
451 : {
452 4 : assert (msg);
453 4 : assert (buffer);
454 4 : assert (length);
455 :
456 4 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "s"));
457 :
458 4 : return egg_buffer_add_byte_array (&msg->buffer, buffer, length);
459 : }
460 :
461 : int
462 0 : gkm_rpc_message_write_zero_string (GkmRpcMessage *msg, CK_UTF8CHAR* string)
463 : {
464 0 : assert (msg);
465 0 : assert (string);
466 :
467 0 : assert (!msg->signature || gkm_rpc_message_verify_part (msg, "z"));
468 :
469 0 : return egg_buffer_add_string (&msg->buffer, (const char*)string);
470 : }
|