~ubuntu-branches/ubuntu/natty/gnome-keyring/natty

« back to all changes in this revision

Viewing changes to daemon/ssh-agent/gkd-ssh-agent-proto.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-02-16 19:00:06 UTC
  • mfrom: (1.1.58 upstream)
  • Revision ID: james.westby@ubuntu.com-20100216190006-cqpnic4zxlkmmi0o
Tags: 2.29.90git20100218-0ubuntu1
Updated to a git snapshot version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 
2
/* gkd-ssh-agent-proto.c - SSH agent protocol helpers
 
3
 
 
4
   Copyright (C) 2007 Stefan Walter
 
5
 
 
6
   Gnome keyring is free software; you can redistribute it and/or
 
7
   modify it under the terms of the GNU 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
   Gnome keyring 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
   General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program; if not, write to the Free Software
 
18
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 
 
20
   Author: Stef Walter <stef@memberwebs.com>
 
21
*/
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include "gkd-ssh-agent-private.h"
 
26
 
 
27
#include "egg/egg-buffer.h"
 
28
 
 
29
#include <gp11/gp11.h>
 
30
 
 
31
#include <glib.h>
 
32
 
 
33
#include <string.h>
 
34
 
 
35
gulong
 
36
gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo)
 
37
{
 
38
        g_return_val_if_fail (salgo, G_MAXULONG);
 
39
        if (strcmp (salgo, "ssh-rsa") == 0)
 
40
                return CKK_RSA;
 
41
        else if (strcmp (salgo, "ssh-dss") == 0)
 
42
                return CKK_DSA;
 
43
        return G_MAXULONG;
 
44
}
 
45
 
 
46
const gchar*
 
47
gkd_ssh_agent_proto_algo_to_keytype (gulong algo)
 
48
{
 
49
        if (algo == CKK_RSA)
 
50
                return "ssh-rsa";
 
51
        else if (algo == CKK_DSA)
 
52
                return "ssh-dss";
 
53
        return NULL;
 
54
}
 
55
 
 
56
gboolean
 
57
gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gsize *offset, GP11Attributes *attrs,
 
58
                              CK_ATTRIBUTE_TYPE type)
 
59
{
 
60
        const guchar *data;
 
61
        gsize len;
 
62
 
 
63
        if (!egg_buffer_get_byte_array (req, *offset, offset, &data, &len))
 
64
                return FALSE;
 
65
 
 
66
        /* Convert to unsigned format */
 
67
        if (len >= 2 && data[0] == 0 && (data[1] & 0x80)) {
 
68
                ++data;
 
69
                --len;
 
70
        }
 
71
 
 
72
        gp11_attributes_add_data (attrs, type, data, len);
 
73
        return TRUE;
 
74
}
 
75
 
 
76
gboolean
 
77
gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req, gsize *offset, GP11Attributes *attrs,
 
78
                                 CK_ATTRIBUTE_TYPE type)
 
79
{
 
80
        const guchar *data;
 
81
        gsize bytes;
 
82
        guint16 bits;
 
83
 
 
84
        /* Get the number of bits */
 
85
        if (!egg_buffer_get_uint16 (req, *offset, offset, &bits))
 
86
                return FALSE;
 
87
 
 
88
        /* Figure out the number of binary bytes following */
 
89
        bytes = (bits + 7) / 8;
 
90
        if (bytes > 8 * 1024)
 
91
                return FALSE;
 
92
 
 
93
        /* Pull these out directly */
 
94
        if (req->len < *offset + bytes)
 
95
                return FALSE;
 
96
        data = req->buf + *offset;
 
97
        *offset += bytes;
 
98
 
 
99
        gp11_attributes_add_data (attrs, type, data, bytes);
 
100
        return TRUE;
 
101
}
 
102
 
 
103
gboolean
 
104
gkd_ssh_agent_proto_write_mpi (EggBuffer *resp, GP11Attribute *attr)
 
105
{
 
106
        guchar *data;
 
107
        gsize n_extra;
 
108
 
 
109
        g_assert (resp);
 
110
        g_assert (attr);
 
111
 
 
112
        /* Convert from unsigned format */
 
113
        n_extra = 0;
 
114
        if (attr->length && (attr->value[0] & 0x80))
 
115
                ++n_extra;
 
116
 
 
117
        data = egg_buffer_add_byte_array_empty (resp, attr->length + n_extra);
 
118
        if (data == NULL)
 
119
                return FALSE;
 
120
 
 
121
        memset (data, 0, n_extra);
 
122
        memcpy (data + n_extra, attr->value, attr->length);
 
123
        return TRUE;
 
124
}
 
125
 
 
126
gboolean
 
127
gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp, GP11Attribute *attr)
 
128
{
 
129
        guchar *data;
 
130
 
 
131
        g_return_val_if_fail (attr->length * 8 < G_MAXUSHORT, FALSE);
 
132
 
 
133
        if (!egg_buffer_add_uint16 (resp, attr->length * 8))
 
134
                return FALSE;
 
135
 
 
136
        data = egg_buffer_add_empty (resp, attr->length);
 
137
        if (data == NULL)
 
138
                return FALSE;
 
139
        memcpy (data, attr->value, attr->length);
 
140
        return TRUE;
 
141
}
 
142
 
 
143
const guchar*
 
144
gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *req, gsize *offset, gsize *n_challenge)
 
145
{
 
146
        const guchar *data;
 
147
        gsize bytes;
 
148
        guint16 bits;
 
149
 
 
150
        /* Get the number of bits */
 
151
        if (!egg_buffer_get_uint16 (req, *offset, offset, &bits))
 
152
                return FALSE;
 
153
 
 
154
        /* Figure out the number of binary bytes following */
 
155
        bytes = (bits + 7) / 8;
 
156
        if (bytes > 8 * 1024)
 
157
                return FALSE;
 
158
 
 
159
        /* Pull these out directly */
 
160
        if (req->len < *offset + bytes)
 
161
                return FALSE;
 
162
        data = req->buf + *offset;
 
163
        *offset += bytes;
 
164
        *n_challenge = bytes;
 
165
        return data;
 
166
}
 
167
 
 
168
gboolean
 
169
gkd_ssh_agent_proto_read_public (EggBuffer *req, gsize *offset, GP11Attributes* attrs, gulong *algo)
 
170
{
 
171
        gboolean ret;
 
172
        gchar *stype;
 
173
        gulong alg;
 
174
 
 
175
        g_assert (req);
 
176
        g_assert (offset);
 
177
 
 
178
        /* The string algorithm */
 
179
        if (!egg_buffer_get_string (req, *offset, offset, &stype, (EggBufferAllocator)g_realloc))
 
180
                return FALSE;
 
181
 
 
182
        alg = gkd_ssh_agent_proto_keytype_to_algo (stype);
 
183
        if (alg == G_MAXULONG) {
 
184
                g_warning ("unsupported algorithm from SSH: %s", stype);
 
185
                g_free (stype);
 
186
                return FALSE;
 
187
        }
 
188
 
 
189
        g_free (stype);
 
190
        switch (alg) {
 
191
        case CKK_RSA:
 
192
                ret = gkd_ssh_agent_proto_read_public_rsa (req, offset, attrs);
 
193
                break;
 
194
        case CKK_DSA:
 
195
                ret = gkd_ssh_agent_proto_read_public_dsa (req, offset, attrs);
 
196
                break;
 
197
        default:
 
198
                g_assert_not_reached ();
 
199
                return FALSE;
 
200
        }
 
201
 
 
202
        if (!ret) {
 
203
                g_warning ("couldn't read incoming SSH private key");
 
204
                return FALSE;
 
205
        }
 
206
 
 
207
        if (algo)
 
208
                *algo = alg;
 
209
        return ret;
 
210
}
 
211
 
 
212
gboolean
 
213
gkd_ssh_agent_proto_read_pair_rsa (EggBuffer *req, gsize *offset,
 
214
                                   GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
 
215
{
 
216
        GP11Attribute *attr;
 
217
 
 
218
        g_assert (req);
 
219
        g_assert (offset);
 
220
        g_assert (priv_attrs);
 
221
        g_assert (pub_attrs);
 
222
 
 
223
        if (!gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_MODULUS) ||
 
224
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PUBLIC_EXPONENT) ||
 
225
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PRIVATE_EXPONENT) ||
 
226
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_COEFFICIENT) ||
 
227
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PRIME_1) ||
 
228
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PRIME_2))
 
229
                return FALSE;
 
230
 
 
231
        /* Copy attributes to the public key */
 
232
        attr = gp11_attributes_find (priv_attrs, CKA_MODULUS);
 
233
        gp11_attributes_add (pub_attrs, attr);
 
234
        attr = gp11_attributes_find (priv_attrs, CKA_PUBLIC_EXPONENT);
 
235
        gp11_attributes_add (pub_attrs, attr);
 
236
 
 
237
        /* Add in your basic other required attributes */
 
238
        gp11_attributes_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
 
239
        gp11_attributes_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_RSA);
 
240
        gp11_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
241
        gp11_attributes_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_RSA);
 
242
 
 
243
        return TRUE;
 
244
}
 
245
 
 
246
gboolean
 
247
gkd_ssh_agent_proto_read_pair_v1 (EggBuffer *req, gsize *offset,
 
248
                                  GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
 
249
{
 
250
        GP11Attribute *attr;
 
251
 
 
252
        g_assert (req);
 
253
        g_assert (offset);
 
254
        g_assert (priv_attrs);
 
255
        g_assert (pub_attrs);
 
256
 
 
257
        if (!gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_MODULUS) ||
 
258
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PUBLIC_EXPONENT) ||
 
259
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIVATE_EXPONENT) ||
 
260
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_COEFFICIENT) ||
 
261
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIME_1) ||
 
262
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIME_2))
 
263
                return FALSE;
 
264
 
 
265
        /* Copy attributes to the public key */
 
266
        attr = gp11_attributes_find (priv_attrs, CKA_MODULUS);
 
267
        gp11_attributes_add (pub_attrs, attr);
 
268
        attr = gp11_attributes_find (priv_attrs, CKA_PUBLIC_EXPONENT);
 
269
        gp11_attributes_add (pub_attrs, attr);
 
270
 
 
271
        /* Add in your basic other required attributes */
 
272
        gp11_attributes_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
 
273
        gp11_attributes_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_RSA);
 
274
        gp11_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
275
        gp11_attributes_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_RSA);
 
276
 
 
277
        return TRUE;
 
278
}
 
279
 
 
280
gboolean
 
281
gkd_ssh_agent_proto_read_public_rsa (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
 
282
{
 
283
        g_assert (req);
 
284
        g_assert (offset);
 
285
        g_assert (attrs);
 
286
 
 
287
        if (!gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_PUBLIC_EXPONENT) ||
 
288
            !gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_MODULUS))
 
289
                return FALSE;
 
290
 
 
291
        /* Add in your basic other required attributes */
 
292
        gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
293
        gp11_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
 
294
 
 
295
        return TRUE;
 
296
}
 
297
 
 
298
gboolean
 
299
gkd_ssh_agent_proto_read_public_v1 (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
 
300
{
 
301
        guint32 bits;
 
302
 
 
303
        g_assert (req);
 
304
        g_assert (offset);
 
305
        g_assert (attrs);
 
306
 
 
307
        if (!egg_buffer_get_uint32 (req, *offset, offset, &bits))
 
308
                return FALSE;
 
309
 
 
310
        if (!gkd_ssh_agent_proto_read_mpi_v1 (req, offset, attrs, CKA_PUBLIC_EXPONENT) ||
 
311
            !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, attrs, CKA_MODULUS))
 
312
                return FALSE;
 
313
 
 
314
        /* Add in your basic other required attributes */
 
315
        gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
316
        gp11_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
 
317
 
 
318
        return TRUE;
 
319
}
 
320
 
 
321
gboolean
 
322
gkd_ssh_agent_proto_read_pair_dsa (EggBuffer *req, gsize *offset,
 
323
                                   GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
 
324
{
 
325
        GP11Attribute *attr;
 
326
 
 
327
        g_assert (req);
 
328
        g_assert (offset);
 
329
        g_assert (priv_attrs);
 
330
        g_assert (pub_attrs);
 
331
 
 
332
        if (!gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PRIME) ||
 
333
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_SUBPRIME) ||
 
334
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_BASE) ||
 
335
            !gkd_ssh_agent_proto_read_mpi (req, offset, pub_attrs, CKA_VALUE) ||
 
336
            !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_VALUE))
 
337
                return FALSE;
 
338
 
 
339
        /* Copy attributes to the public key */
 
340
        attr = gp11_attributes_find (priv_attrs, CKA_PRIME);
 
341
        gp11_attributes_add (pub_attrs, attr);
 
342
        attr = gp11_attributes_find (priv_attrs, CKA_SUBPRIME);
 
343
        gp11_attributes_add (pub_attrs, attr);
 
344
        attr = gp11_attributes_find (priv_attrs, CKA_BASE);
 
345
        gp11_attributes_add (pub_attrs, attr);
 
346
 
 
347
        /* Add in your basic other required attributes */
 
348
        gp11_attributes_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
 
349
        gp11_attributes_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_DSA);
 
350
        gp11_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
351
        gp11_attributes_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_DSA);
 
352
 
 
353
        return TRUE;
 
354
}
 
355
 
 
356
gboolean
 
357
gkd_ssh_agent_proto_read_public_dsa (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
 
358
{
 
359
        g_assert (req);
 
360
        g_assert (offset);
 
361
        g_assert (attrs);
 
362
 
 
363
        if (!gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_PRIME) ||
 
364
            !gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_SUBPRIME) ||
 
365
            !gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_BASE) ||
 
366
            !gkd_ssh_agent_proto_read_mpi (req, offset, attrs, CKA_VALUE))
 
367
                return FALSE;
 
368
 
 
369
        /* Add in your basic other required attributes */
 
370
        gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
 
371
        gp11_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_DSA);
 
372
 
 
373
        return TRUE;
 
374
}
 
375
 
 
376
gboolean
 
377
gkd_ssh_agent_proto_write_public (EggBuffer *resp, GP11Attributes *attrs)
 
378
{
 
379
        gboolean ret = FALSE;
 
380
        const gchar *salgo;
 
381
        gulong algo;
 
382
 
 
383
        g_assert (resp);
 
384
        g_assert (attrs);
 
385
 
 
386
        if (!gp11_attributes_find_ulong (attrs, CKA_KEY_TYPE, &algo))
 
387
                g_return_val_if_reached (FALSE);
 
388
 
 
389
        salgo = gkd_ssh_agent_proto_algo_to_keytype (algo);
 
390
        g_assert (salgo);
 
391
        egg_buffer_add_string (resp, salgo);
 
392
 
 
393
        switch (algo) {
 
394
        case CKK_RSA:
 
395
                ret = gkd_ssh_agent_proto_write_public_rsa (resp, attrs);
 
396
                break;
 
397
 
 
398
        case CKK_DSA:
 
399
                ret = gkd_ssh_agent_proto_write_public_dsa (resp, attrs);
 
400
                break;
 
401
 
 
402
        default:
 
403
                g_return_val_if_reached (FALSE);
 
404
                break;
 
405
        }
 
406
 
 
407
        return ret;
 
408
}
 
409
 
 
410
gboolean
 
411
gkd_ssh_agent_proto_write_public_rsa (EggBuffer *resp, GP11Attributes *attrs)
 
412
{
 
413
        GP11Attribute *attr;
 
414
 
 
415
        g_assert (resp);
 
416
        g_assert (attrs);
 
417
 
 
418
        attr = gp11_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
 
419
        g_return_val_if_fail (attr, FALSE);
 
420
 
 
421
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
422
                return FALSE;
 
423
 
 
424
        attr = gp11_attributes_find (attrs, CKA_MODULUS);
 
425
        g_return_val_if_fail (attr, FALSE);
 
426
 
 
427
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
428
                return FALSE;
 
429
 
 
430
        return TRUE;
 
431
}
 
432
 
 
433
gboolean
 
434
gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GP11Attributes *attrs)
 
435
{
 
436
        GP11Attribute *attr;
 
437
 
 
438
        g_assert (resp);
 
439
        g_assert (attrs);
 
440
 
 
441
        attr = gp11_attributes_find (attrs, CKA_PRIME);
 
442
        g_return_val_if_fail (attr, FALSE);
 
443
 
 
444
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
445
                return FALSE;
 
446
 
 
447
        attr = gp11_attributes_find (attrs, CKA_SUBPRIME);
 
448
        g_return_val_if_fail (attr, FALSE);
 
449
 
 
450
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
451
                return FALSE;
 
452
 
 
453
        attr = gp11_attributes_find (attrs, CKA_BASE);
 
454
        g_return_val_if_fail (attr, FALSE);
 
455
 
 
456
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
457
                return FALSE;
 
458
 
 
459
        attr = gp11_attributes_find (attrs, CKA_VALUE);
 
460
        g_return_val_if_fail (attr, FALSE);
 
461
 
 
462
        if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
 
463
                return FALSE;
 
464
 
 
465
        return TRUE;
 
466
}
 
467
 
 
468
gboolean
 
469
gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, GP11Attributes *attrs)
 
470
{
 
471
        GP11Attribute *attr;
 
472
        gulong bits;
 
473
 
 
474
        g_assert (resp);
 
475
        g_assert (attrs);
 
476
 
 
477
        /* This is always an RSA key. */
 
478
 
 
479
        /* Write out the number of bits of the key */
 
480
        if (!gp11_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits))
 
481
                g_return_val_if_reached (FALSE);
 
482
        egg_buffer_add_uint32 (resp, bits);
 
483
 
 
484
        /* Write out the exponent */
 
485
        attr = gp11_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
 
486
        g_return_val_if_fail (attr, FALSE);
 
487
 
 
488
        if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
 
489
                return FALSE;
 
490
 
 
491
        /* Write out the modulus */
 
492
        attr = gp11_attributes_find (attrs, CKA_MODULUS);
 
493
        g_return_val_if_fail (attr, FALSE);
 
494
 
 
495
        if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
 
496
                return FALSE;
 
497
 
 
498
        return TRUE;
 
499
}
 
500
 
 
501
gboolean
 
502
gkd_ssh_agent_proto_write_signature_rsa (EggBuffer *resp, CK_BYTE_PTR signature, CK_ULONG n_signature)
 
503
{
 
504
        return egg_buffer_add_byte_array (resp, signature, n_signature);
 
505
}
 
506
 
 
507
gboolean
 
508
gkd_ssh_agent_proto_write_signature_dsa (EggBuffer *resp, CK_BYTE_PTR signature, CK_ULONG n_signature)
 
509
{
 
510
        g_return_val_if_fail (n_signature == 40, FALSE);
 
511
        return egg_buffer_add_byte_array (resp, signature, n_signature);
 
512
}