1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
/* gkd-ssh-agent-proto.c - SSH agent protocol helpers
4
Copyright (C) 2007 Stefan Walter
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.
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.
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.
20
Author: Stef Walter <stef@memberwebs.com>
25
#include "gkd-ssh-agent-private.h"
27
#include "egg/egg-buffer.h"
29
#include <gp11/gp11.h>
36
gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo)
38
g_return_val_if_fail (salgo, G_MAXULONG);
39
if (strcmp (salgo, "ssh-rsa") == 0)
41
else if (strcmp (salgo, "ssh-dss") == 0)
47
gkd_ssh_agent_proto_algo_to_keytype (gulong algo)
51
else if (algo == CKK_DSA)
57
gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gsize *offset, GP11Attributes *attrs,
58
CK_ATTRIBUTE_TYPE type)
63
if (!egg_buffer_get_byte_array (req, *offset, offset, &data, &len))
66
/* Convert to unsigned format */
67
if (len >= 2 && data[0] == 0 && (data[1] & 0x80)) {
72
gp11_attributes_add_data (attrs, type, data, len);
77
gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req, gsize *offset, GP11Attributes *attrs,
78
CK_ATTRIBUTE_TYPE type)
84
/* Get the number of bits */
85
if (!egg_buffer_get_uint16 (req, *offset, offset, &bits))
88
/* Figure out the number of binary bytes following */
89
bytes = (bits + 7) / 8;
93
/* Pull these out directly */
94
if (req->len < *offset + bytes)
96
data = req->buf + *offset;
99
gp11_attributes_add_data (attrs, type, data, bytes);
104
gkd_ssh_agent_proto_write_mpi (EggBuffer *resp, GP11Attribute *attr)
112
/* Convert from unsigned format */
114
if (attr->length && (attr->value[0] & 0x80))
117
data = egg_buffer_add_byte_array_empty (resp, attr->length + n_extra);
121
memset (data, 0, n_extra);
122
memcpy (data + n_extra, attr->value, attr->length);
127
gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp, GP11Attribute *attr)
131
g_return_val_if_fail (attr->length * 8 < G_MAXUSHORT, FALSE);
133
if (!egg_buffer_add_uint16 (resp, attr->length * 8))
136
data = egg_buffer_add_empty (resp, attr->length);
139
memcpy (data, attr->value, attr->length);
144
gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *req, gsize *offset, gsize *n_challenge)
150
/* Get the number of bits */
151
if (!egg_buffer_get_uint16 (req, *offset, offset, &bits))
154
/* Figure out the number of binary bytes following */
155
bytes = (bits + 7) / 8;
156
if (bytes > 8 * 1024)
159
/* Pull these out directly */
160
if (req->len < *offset + bytes)
162
data = req->buf + *offset;
164
*n_challenge = bytes;
169
gkd_ssh_agent_proto_read_public (EggBuffer *req, gsize *offset, GP11Attributes* attrs, gulong *algo)
178
/* The string algorithm */
179
if (!egg_buffer_get_string (req, *offset, offset, &stype, (EggBufferAllocator)g_realloc))
182
alg = gkd_ssh_agent_proto_keytype_to_algo (stype);
183
if (alg == G_MAXULONG) {
184
g_warning ("unsupported algorithm from SSH: %s", stype);
192
ret = gkd_ssh_agent_proto_read_public_rsa (req, offset, attrs);
195
ret = gkd_ssh_agent_proto_read_public_dsa (req, offset, attrs);
198
g_assert_not_reached ();
203
g_warning ("couldn't read incoming SSH private key");
213
gkd_ssh_agent_proto_read_pair_rsa (EggBuffer *req, gsize *offset,
214
GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
220
g_assert (priv_attrs);
221
g_assert (pub_attrs);
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))
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);
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);
247
gkd_ssh_agent_proto_read_pair_v1 (EggBuffer *req, gsize *offset,
248
GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
254
g_assert (priv_attrs);
255
g_assert (pub_attrs);
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))
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);
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);
281
gkd_ssh_agent_proto_read_public_rsa (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
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))
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);
299
gkd_ssh_agent_proto_read_public_v1 (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
307
if (!egg_buffer_get_uint32 (req, *offset, offset, &bits))
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))
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);
322
gkd_ssh_agent_proto_read_pair_dsa (EggBuffer *req, gsize *offset,
323
GP11Attributes *priv_attrs, GP11Attributes *pub_attrs)
329
g_assert (priv_attrs);
330
g_assert (pub_attrs);
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))
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);
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);
357
gkd_ssh_agent_proto_read_public_dsa (EggBuffer *req, gsize *offset, GP11Attributes *attrs)
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))
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);
377
gkd_ssh_agent_proto_write_public (EggBuffer *resp, GP11Attributes *attrs)
379
gboolean ret = FALSE;
386
if (!gp11_attributes_find_ulong (attrs, CKA_KEY_TYPE, &algo))
387
g_return_val_if_reached (FALSE);
389
salgo = gkd_ssh_agent_proto_algo_to_keytype (algo);
391
egg_buffer_add_string (resp, salgo);
395
ret = gkd_ssh_agent_proto_write_public_rsa (resp, attrs);
399
ret = gkd_ssh_agent_proto_write_public_dsa (resp, attrs);
403
g_return_val_if_reached (FALSE);
411
gkd_ssh_agent_proto_write_public_rsa (EggBuffer *resp, GP11Attributes *attrs)
418
attr = gp11_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
419
g_return_val_if_fail (attr, FALSE);
421
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
424
attr = gp11_attributes_find (attrs, CKA_MODULUS);
425
g_return_val_if_fail (attr, FALSE);
427
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
434
gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GP11Attributes *attrs)
441
attr = gp11_attributes_find (attrs, CKA_PRIME);
442
g_return_val_if_fail (attr, FALSE);
444
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
447
attr = gp11_attributes_find (attrs, CKA_SUBPRIME);
448
g_return_val_if_fail (attr, FALSE);
450
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
453
attr = gp11_attributes_find (attrs, CKA_BASE);
454
g_return_val_if_fail (attr, FALSE);
456
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
459
attr = gp11_attributes_find (attrs, CKA_VALUE);
460
g_return_val_if_fail (attr, FALSE);
462
if (!gkd_ssh_agent_proto_write_mpi (resp, attr))
469
gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, GP11Attributes *attrs)
477
/* This is always an RSA key. */
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);
484
/* Write out the exponent */
485
attr = gp11_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
486
g_return_val_if_fail (attr, FALSE);
488
if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
491
/* Write out the modulus */
492
attr = gp11_attributes_find (attrs, CKA_MODULUS);
493
g_return_val_if_fail (attr, FALSE);
495
if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
502
gkd_ssh_agent_proto_write_signature_rsa (EggBuffer *resp, CK_BYTE_PTR signature, CK_ULONG n_signature)
504
return egg_buffer_add_byte_array (resp, signature, n_signature);
508
gkd_ssh_agent_proto_write_signature_dsa (EggBuffer *resp, CK_BYTE_PTR signature, CK_ULONG n_signature)
510
g_return_val_if_fail (n_signature == 40, FALSE);
511
return egg_buffer_add_byte_array (resp, signature, n_signature);