summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Walter <stefw@src.gnome.org>2008-03-17 01:14:46 +0000
committerStefan Walter <stefw@src.gnome.org>2008-03-17 01:14:46 +0000
commitf3413460f5a2cb4d8c09f2973d92fb33c5b2ac98 (patch)
tree4cd568bd04b62ceb66715e4ba0bb2ec1a4c1fc86
parent7d18018e42f4306c19d61d9a4eacf089a5f870a2 (diff)
Move RSA padding functionality into a more accessible location.
* common/gkr-crypto.c: * common/gkr-crypto.h: * pk/gkr-pkcs11-daemon-session.c: * pk/gkr-pkcs11-rsa.c: * pk/gkr-pkcs11-rsa.h: Move RSA padding functionality into a more accessible location. * common/gkr-buffer.c: * common/gkr-buffer.h: * pk/gkr-pk-object-manager.c: * pk/gkr-pk-object-manager.h: * pk/gkr-pk-pubkey.c: * ssh/gkr-ssh-daemon-ops.c: * ssh/gkr-ssh-private.h: * ssh/gkr-ssh-proto.c: Add SSH agent protocol version 1 support. Cleanup how session keys are managed. Fixes bug #520860 svn path=/trunk/; revision=1122
-rw-r--r--ChangeLog19
-rw-r--r--common/gkr-buffer.c69
-rw-r--r--common/gkr-buffer.h25
-rw-r--r--common/gkr-crypto.c258
-rw-r--r--common/gkr-crypto.h28
-rw-r--r--pk/gkr-pk-object-manager.c6
-rw-r--r--pk/gkr-pk-object-manager.h2
-rw-r--r--pk/gkr-pk-pubkey.c1
-rw-r--r--pkcs11/gkr-pkcs11-daemon-session.c15
-rw-r--r--pkcs11/gkr-pkcs11-rsa.c199
-rw-r--r--pkcs11/gkr-pkcs11-rsa.h27
-rw-r--r--ssh/gkr-ssh-daemon-ops.c413
-rw-r--r--ssh/gkr-ssh-private.h10
-rw-r--r--ssh/gkr-ssh-proto.c163
14 files changed, 907 insertions, 328 deletions
diff --git a/ChangeLog b/ChangeLog
index 0d5f497b..7c6b1c82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2008-03-16 Stef Walter <stef@memberwebs.com>
+ * common/gkr-crypto.c:
+ * common/gkr-crypto.h:
+ * pk/gkr-pkcs11-daemon-session.c:
+ * pk/gkr-pkcs11-rsa.c:
+ * pk/gkr-pkcs11-rsa.h: Move RSA padding functionality into a
+ more accessible location.
+
+ * common/gkr-buffer.c:
+ * common/gkr-buffer.h:
+ * pk/gkr-pk-object-manager.c:
+ * pk/gkr-pk-object-manager.h:
+ * pk/gkr-pk-pubkey.c:
+ * ssh/gkr-ssh-daemon-ops.c:
+ * ssh/gkr-ssh-private.h:
+ * ssh/gkr-ssh-proto.c: Add SSH agent protocol version 1 support.
+ Cleanup how session keys are managed. Fixes bug #520860
+
+2008-03-16 Stef Walter <stef@memberwebs.com>
+
* library/Makefile.am: Include GNOME_KEYRING_NETWORK_PASSWORD
exported in libgnome-keyring.so. Patch by Andrea Del Signore.
Fixes bug #522651
diff --git a/common/gkr-buffer.c b/common/gkr-buffer.c
index b55a5bcd..4c0257e6 100644
--- a/common/gkr-buffer.c
+++ b/common/gkr-buffer.c
@@ -192,14 +192,14 @@ gkr_buffer_resize (GkrBuffer *buffer, size_t len)
return 1;
}
-int
+unsigned char*
gkr_buffer_add_empty (GkrBuffer *buffer, size_t len)
{
+ size_t pos = buffer->len;
if (!gkr_buffer_reserve (buffer, buffer->len + len))
- return 0;
-
+ return NULL;
buffer->len += len;
- return 1;
+ return buffer->buf + pos;
}
int
@@ -240,6 +240,60 @@ gkr_buffer_get_byte (GkrBuffer *buffer, size_t offset,
return 1;
}
+void
+gkr_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
+{
+ buf[0] = (val >> 8) & 0xff;
+ buf[1] = (val >> 0) & 0xff;
+}
+
+uint16_t
+gkr_buffer_decode_uint16 (unsigned char* buf)
+{
+ uint16_t val = buf[0] << 8 | buf[1];
+ return val;
+}
+
+int
+gkr_buffer_add_uint16 (GkrBuffer *buffer, uint16_t val)
+{
+ if (!gkr_buffer_reserve (buffer, buffer->len + 2))
+ return 0; /* failures already incremented */
+ buffer->len += 2;
+ gkr_buffer_set_uint16 (buffer, buffer->len - 2, val);
+ return 1;
+}
+
+int
+gkr_buffer_set_uint16 (GkrBuffer *buffer, size_t offset, uint16_t val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 2 || offset > buffer->len - 2) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ gkr_buffer_encode_uint16 (ptr, val);
+ return 1;
+}
+
+int
+gkr_buffer_get_uint16 (GkrBuffer *buffer, size_t offset,
+ size_t *next_offset, uint16_t *val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 2 || offset > buffer->len - 2) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ if (val != NULL)
+ *val = gkr_buffer_decode_uint16 (ptr);
+ if (next_offset != NULL)
+ *next_offset = offset + 2;
+ return 1;
+}
+
void
gkr_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
{
@@ -338,18 +392,13 @@ gkr_buffer_add_byte_array (GkrBuffer *buffer, const unsigned char *val,
unsigned char*
gkr_buffer_add_byte_array_empty (GkrBuffer *buffer, size_t vlen)
{
- size_t pos;
if (vlen >= 0x7fffffff) {
buffer->failures++;
return NULL;
}
if (!gkr_buffer_add_uint32 (buffer, vlen))
return NULL;
- pos = buffer->len;
- /* This, as any gkr_buffer_add_* can reallocate */
- if (!gkr_buffer_add_empty (buffer, vlen))
- return NULL;
- return buffer->buf + pos;
+ return gkr_buffer_add_empty (buffer, vlen);
}
int
diff --git a/common/gkr-buffer.h b/common/gkr-buffer.h
index 71df5ae2..4dd72a65 100644
--- a/common/gkr-buffer.h
+++ b/common/gkr-buffer.h
@@ -102,8 +102,8 @@ int gkr_buffer_append (GkrBuffer *buffer,
const unsigned char *val,
size_t len);
-int gkr_buffer_add_empty (GkrBuffer *buffer,
- size_t len);
+unsigned char* gkr_buffer_add_empty (GkrBuffer *buffer,
+ size_t len);
int gkr_buffer_add_byte (GkrBuffer *buffer,
unsigned char val);
@@ -130,6 +130,23 @@ int gkr_buffer_get_uint32 (GkrBuffer *buffer,
size_t *next_offset,
uint32_t *val);
+void gkr_buffer_encode_uint16 (unsigned char* buf,
+ uint16_t val);
+
+uint16_t gkr_buffer_decode_uint16 (unsigned char* buf);
+
+int gkr_buffer_add_uint16 (GkrBuffer *buffer,
+ uint16_t val);
+
+int gkr_buffer_set_uint16 (GkrBuffer *buffer,
+ size_t offset,
+ uint16_t val);
+
+int gkr_buffer_get_uint16 (GkrBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ uint16_t *val);
+
int gkr_buffer_add_byte_array (GkrBuffer *buffer,
const unsigned char *val,
size_t len);
@@ -158,8 +175,8 @@ int gkr_buffer_add_stringv (GkrBuffer *buffer,
int gkr_buffer_get_stringv (GkrBuffer *buffer,
size_t offset,
size_t *next_offset,
- char ***strv_ret,
- GkrBufferAllocator allocator);
+ char ***strv_ret,
+ GkrBufferAllocator allocator);
int gkr_buffer_add_uint64 (GkrBuffer *buffer,
uint64_t val);
diff --git a/common/gkr-crypto.c b/common/gkr-crypto.c
index 46d8bb32..24e76456 100644
--- a/common/gkr-crypto.c
+++ b/common/gkr-crypto.c
@@ -698,15 +698,78 @@ gkr_crypto_sexp_extract_mpi (gcry_sexp_t sexp, gcry_mpi_t *mpi, ...)
return (*mpi) ? TRUE : FALSE;
}
+static gboolean
+print_mpi_aligned (gcry_mpi_t mpi, guchar *block, gsize n_block)
+{
+ gcry_error_t gcry;
+ gsize offset, len;
+
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ if (n_block < len)
+ return FALSE;
+
+ offset = n_block - len;
+ memset (block, 0, offset);
+
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, block + offset, len, &len, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+ g_return_val_if_fail (len == n_block - offset, FALSE);
+
+ return TRUE;
+}
+
+guchar*
+gkr_crypto_sexp_extract_mpi_padded (gcry_sexp_t sexp, guint bits, gsize *n_data,
+ GkrCryptoPadding padfunc, ...)
+{
+ gcry_sexp_t at = NULL;
+ gcry_mpi_t mpi;
+ va_list va;
+ guchar *padded, *data;
+ gsize n_padded;
+
+ g_assert (sexp);
+ g_assert (n_data);
+ g_assert (padfunc);
+ g_assert (bits);
+
+ va_start (va, padfunc);
+ at = sexp_get_childv (sexp, va);
+ va_end (va);
+
+ if (!at)
+ return NULL;
+
+ /* Parse out the MPI */
+ mpi = gcry_sexp_nth_mpi (at ? at : sexp, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release (at);
+
+ if (!mpi)
+ return NULL;
+
+ /* Do we need to unpad the data? */
+ n_padded = (bits + 7) / 8;
+ data = NULL;
+
+ /* Extract it aligned into this buffer */
+ padded = g_malloc0 (n_padded);
+ if (print_mpi_aligned (mpi, padded, n_padded))
+ data = (padfunc) (bits, padded, n_padded, n_data);
+ g_free (padded);
+
+ gcry_mpi_release (mpi);
+ return data;
+}
+
gboolean
gkr_crypto_sexp_extract_mpi_aligned (gcry_sexp_t sexp, guchar* block, gsize n_block, ...)
{
gcry_sexp_t at = NULL;
- gcry_error_t gcry;
gboolean ret;
gcry_mpi_t mpi;
va_list va;
- gsize len;
g_assert (sexp);
g_assert (block);
@@ -725,27 +788,8 @@ gkr_crypto_sexp_extract_mpi_aligned (gcry_sexp_t sexp, guchar* block, gsize n_bl
if (!mpi)
return FALSE;
-
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- ret = FALSE;
-
- /* Is it too long? */
- if (len <= n_block) {
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, block, n_block, &len, mpi);
- g_return_val_if_fail (gcry == 0, FALSE);
- g_return_val_if_fail (len <= n_block, FALSE);
-
- /* Now align it if necessary */
- if (len < n_block) {
- memmove (block + (n_block - len), block, len);
- memset (block, 0, (n_block - len));
- }
-
- ret = TRUE;
- }
-
+
+ ret = print_mpi_aligned (mpi, block, n_block);
gcry_mpi_release (mpi);
return ret;
}
@@ -920,3 +964,171 @@ gkr_crypto_skey_private_to_public (gcry_sexp_t privkey, gcry_sexp_t *pubkey)
gcry_sexp_release (numbers);
return *pubkey ? TRUE : FALSE;
}
+
+/* -------------------------------------------------------------------
+ * RSA PADDING
+ */
+
+guchar*
+gkr_crypto_rsa_pad_raw (guint n_modulus, const guchar* raw,
+ gsize n_raw, gsize *n_padded)
+{
+ gint total, n_pad;
+ guchar *padded;
+
+ /*
+ * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
+ * padding data
+ */
+
+ total = n_modulus / 8;
+ n_pad = total - n_raw;
+ if (n_pad < 0) /* minumum padding */
+ return NULL;
+
+ padded = g_new0 (guchar, total);
+ memset (padded, 0x00, n_pad);
+ memcpy (padded + n_pad, raw, n_raw);
+
+ *n_padded = total;
+ return padded;
+}
+
+guchar*
+gkr_crypto_rsa_pad_one (guint n_modulus, const guchar* raw,
+ gsize n_raw, gsize *n_padded)
+{
+ gint total, n_pad;
+ guchar *padded;
+
+ /*
+ * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
+ * type padding data
+ */
+
+ total = n_modulus / 8;
+ n_pad = total - 3 - n_raw;
+ if (n_pad < 8) /* minumum padding */
+ return NULL;
+
+ padded = g_new0 (guchar, total);
+ padded[1] = 1; /* Block type */
+ memset (padded + 2, 0xff, n_pad);
+ memcpy (padded + 3 + n_pad, raw, n_raw);
+
+ *n_padded = total;
+ return padded;
+}
+
+static void
+fill_random_nonzero (guchar *data, gsize n_data)
+{
+ guchar *rnd;
+ guint n_zero, i, j;
+
+ gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
+
+ /* Find any zeros in random data */
+ n_zero = 0;
+ for (i = 0; i < n_data; ++i) {
+ if (data[i] == 0x00)
+ ++n_zero;
+ }
+
+ while (n_zero > 0) {
+ rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
+ n_zero = 0;
+ for (i = 0, j = 0; i < n_data; ++i) {
+ if (data[i] != 0x00)
+ continue;
+
+ /* Use some of the replacement data */
+ data[i] = rnd[j];
+ ++j;
+
+ /* It's zero again :( */
+ if (data[i] == 0x00)
+ n_zero++;
+ }
+
+ gcry_free (rnd);
+ }
+}
+
+guchar*
+gkr_crypto_rsa_pad_two (guint n_modulus, const guchar* raw,
+ gsize n_raw, gsize *n_padded)
+{
+ gint total, n_pad;
+ guchar *padded;
+
+ /*
+ * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
+ * type padding data
+ */
+
+ total = n_modulus / 8;
+ n_pad = total - 3 - n_raw;
+ if (n_pad < 8) /* minumum padding */
+ return NULL;
+
+ padded = g_new0 (guchar, total);
+ padded[1] = 2; /* Block type */
+ fill_random_nonzero (padded + 2, n_pad);
+ memcpy (padded + 3 + n_pad, raw, n_raw);
+
+ *n_padded = total;
+ return padded;
+}
+
+static guchar*
+unpad_rsa_pkcs1 (guchar bt, guint n_modulus, const guchar* padded,
+ gsize n_padded, gsize *n_raw)
+{
+ const guchar *at;
+ guchar *raw;
+
+ /* The absolute minimum size including padding */
+ g_return_val_if_fail (n_modulus / 8 >= 3 + 8, NULL);
+
+ if (n_padded != n_modulus / 8)
+ return NULL;
+
+ /* Check the header */
+ if (padded[0] != 0x00 || padded[1] != bt)
+ return NULL;
+
+ /* The first zero byte after the header */
+ at = memchr (padded + 2, 0x00, n_padded - 2);
+ if (!at)
+ return NULL;
+
+ ++at;
+ *n_raw = n_padded - (at - padded);
+ raw = g_new0 (guchar, *n_raw);
+ memcpy (raw, at, *n_raw);
+ return raw;
+}
+
+guchar*
+gkr_crypto_rsa_unpad_pkcs1 (guint bits, const guchar *padded,
+ gsize n_padded, gsize *n_raw)
+{
+ /* Further checks are done later */
+ g_return_val_if_fail (n_padded > 2, NULL);
+ return unpad_rsa_pkcs1 (padded[1], bits, padded, n_padded, n_raw);
+}
+
+guchar*
+gkr_crypto_rsa_unpad_one (guint bits, const guchar *padded,
+ gsize n_padded, gsize *n_raw)
+{
+ return unpad_rsa_pkcs1 (0x01, bits, padded, n_padded, n_raw);
+}
+
+guchar*
+gkr_crypto_rsa_unpad_two (guint bits, const guchar *padded,
+ gsize n_padded, gsize *n_raw)
+{
+ return unpad_rsa_pkcs1 (0x02, bits, padded, n_padded, n_raw);
+}
diff --git a/common/gkr-crypto.h b/common/gkr-crypto.h
index faa42eb7..4a5b78bc 100644
--- a/common/gkr-crypto.h
+++ b/common/gkr-crypto.h
@@ -29,6 +29,10 @@
#include "gkr-id.h"
+typedef guchar* (*GkrCryptoPadding) (guint n_modulus, const guchar* raw,
+ gsize n_raw, gsize *n_padded);
+
+
void gkr_crypto_setup (void);
gboolean gkr_crypto_hex_encode (const guchar *data, gsize n_data,
@@ -63,7 +67,11 @@ gcry_sexp_t gkr_crypto_sexp_get_child (gcry_sexp_t sexp, ...)
gboolean gkr_crypto_sexp_extract_mpi (gcry_sexp_t sexp, gcry_mpi_t *mpi, ...)
G_GNUC_NULL_TERMINATED;
-gboolean gkr_crypto_sexp_extract_mpi_aligned (gcry_sexp_t sexp, guchar* block, gsize n_block, ...)
+guchar* gkr_crypto_sexp_extract_mpi_padded (gcry_sexp_t sexp, guint bits, gsize *n_data,
+ GkrCryptoPadding padfunc, ...)
+ G_GNUC_NULL_TERMINATED;
+
+gboolean gkr_crypto_sexp_extract_mpi_aligned (gcry_sexp_t sexp, guchar* block, gsize n_block, ...)
G_GNUC_NULL_TERMINATED;
void gkr_crypto_sexp_dump (gcry_sexp_t sexp);
@@ -75,4 +83,22 @@ gkrid gkr_crypto_skey_make_id (gcry_sexp_t s_key);
gboolean gkr_crypto_skey_private_to_public (gcry_sexp_t privkey, gcry_sexp_t *pubkey);
+guchar* gkr_crypto_rsa_pad_raw (guint bits, const guchar* raw,
+ gsize n_raw, gsize *n_padded);
+
+guchar* gkr_crypto_rsa_pad_one (guint bits, const guchar* raw,
+ gsize n_raw, gsize *n_padded);
+
+guchar* gkr_crypto_rsa_pad_two (guint bits, const guchar* raw,
+ gsize n_raw, gsize *n_padded);
+
+guchar* gkr_crypto_rsa_unpad_pkcs1 (guint bits, const guchar *padded,
+ gsize n_padded, gsize *n_raw);
+
+guchar* gkr_crypto_rsa_unpad_one (guint bits, const guchar *padded,
+ gsize n_padded, gsize *n_raw);
+
+guchar* gkr_crypto_rsa_unpad_two (guint bits, const guchar* padded,
+ gsize n_padded, gsize *n_raw);
+
#endif /*GKRCRYPTO_H_*/
diff --git a/pk/gkr-pk-object-manager.c b/pk/gkr-pk-object-manager.c
index 6e2362a3..2fc1dfed 100644
--- a/pk/gkr-pk-object-manager.c
+++ b/pk/gkr-pk-object-manager.c
@@ -224,6 +224,12 @@ gkr_pk_object_manager_class_init (GkrPkObjectManagerClass *klass)
}
GkrPkObjectManager*
+gkr_pk_object_manager_new (void)
+{
+ return g_object_new (GKR_TYPE_PK_OBJECT_MANAGER, NULL);
+}
+
+GkrPkObjectManager*
gkr_pk_object_manager_for_token (void)
{
if (!object_manager_for_token) {
diff --git a/pk/gkr-pk-object-manager.h b/pk/gkr-pk-object-manager.h
index cf3aca71..c3cdbe00 100644
--- a/pk/gkr-pk-object-manager.h
+++ b/pk/gkr-pk-object-manager.h
@@ -72,6 +72,8 @@ GType gkr_pk_object_manager_get_type (void) G_GNUC_
GType gkr_pk_object_manager_type_from_string (const gchar *type);
+GkrPkObjectManager* gkr_pk_object_manager_new (void);
+
GkrPkObjectManager* gkr_pk_object_manager_for_token (void);
GkrPkObjectManager* gkr_pk_object_manager_for_client (pid_t pid);
diff --git a/pk/gkr-pk-pubkey.c b/pk/gkr-pk-pubkey.c
index 43fb28bc..0f2542c0 100644
--- a/pk/gkr-pk-pubkey.c
+++ b/pk/gkr-pk-pubkey.c
@@ -511,6 +511,7 @@ gkr_pk_pubkey_instance (GkrPkObjectManager *manager, GQuark location, gcry_sexp_
gkrid keyid;
g_return_val_if_fail (s_key, NULL);
+ g_return_val_if_fail (GKR_IS_PK_OBJECT_MANAGER (manager), NULL);
/* Make sure we have the keyid properly */
keyid = gkr_crypto_skey_make_id (s_key);
diff --git a/pkcs11/gkr-pkcs11-daemon-session.c b/pkcs11/gkr-pkcs11-daemon-session.c
index ca4c0cd6..3b4321f5 100644
--- a/pkcs11/gkr-pkcs11-daemon-session.c
+++ b/pkcs11/gkr-pkcs11-daemon-session.c
@@ -32,6 +32,7 @@
#include "common/gkr-async.h"
#include "common/gkr-buffer.h"
+#include "common/gkr-crypto.h"
#include "common/gkr-unix-credentials.h"
#include "keyrings/gkr-keyring-login.h"
@@ -849,12 +850,12 @@ session_C_Encrypt (SessionInfo *sinfo, GkrPkcs11Message *req,
ctx = (CryptContext*)sinfo->operation_data;
switch (ctx->mechanism) {
case CKM_RSA_PKCS:
- ret = gkr_pkcs11_rsa_encrypt (ctx->key, gkr_pkcs11_rsa_pad_two,
+ ret = gkr_pkcs11_rsa_encrypt (ctx->key, gkr_crypto_rsa_pad_two,
plain, n_plain,
&encrypted, &n_encrypted);
break;
case CKM_RSA_X_509:
- ret = gkr_pkcs11_rsa_encrypt (ctx->key, gkr_pkcs11_rsa_pad_raw,
+ ret = gkr_pkcs11_rsa_encrypt (ctx->key, gkr_crypto_rsa_pad_raw,
plain, n_plain,
&encrypted, &n_encrypted);
break;
@@ -948,7 +949,7 @@ session_C_Decrypt (SessionInfo *sinfo, GkrPkcs11Message *req,
ctx = (CryptContext*)sinfo->operation_data;
switch (ctx->mechanism) {
case CKM_RSA_PKCS:
- ret = gkr_pkcs11_rsa_decrypt (ctx->key, gkr_pkcs11_rsa_unpad_two,
+ ret = gkr_pkcs11_rsa_decrypt (ctx->key, gkr_crypto_rsa_unpad_two,
encrypted, n_encrypted,
&data, &n_data);
break;
@@ -1094,12 +1095,12 @@ session_C_Sign (SessionInfo *sinfo, GkrPkcs11Message *req,
ctx = (CryptContext*)sinfo->operation_data;
switch (ctx->mechanism) {
case CKM_RSA_PKCS:
- ret = gkr_pkcs11_rsa_sign (ctx->key, gkr_pkcs11_rsa_pad_one,
+ ret = gkr_pkcs11_rsa_sign (ctx->key, gkr_crypto_rsa_pad_one,
data, n_data,
&signature, &n_signature);
break;
case CKM_RSA_X_509:
- ret = gkr_pkcs11_rsa_sign (ctx->key, gkr_pkcs11_rsa_pad_raw,
+ ret = gkr_pkcs11_rsa_sign (ctx->key, gkr_crypto_rsa_pad_raw,
data, n_data,
&signature, &n_signature);
break;
@@ -1216,12 +1217,12 @@ session_C_Verify (SessionInfo *sinfo, GkrPkcs11Message *req,
ctx = (CryptContext*)sinfo->operation_data;
switch (ctx->mechanism) {
case CKM_RSA_PKCS:
- ret = gkr_pkcs11_rsa_verify (ctx->key, gkr_pkcs11_rsa_pad_one,
+ ret = gkr_pkcs11_rsa_verify (ctx->key, gkr_crypto_rsa_pad_one,
data, n_data,
signature, n_signature);
break;
case CKM_RSA_X_509:
- ret = gkr_pkcs11_rsa_verify (ctx->key, gkr_pkcs11_rsa_pad_raw,
+ ret = gkr_pkcs11_rsa_verify (ctx->key, gkr_crypto_rsa_pad_raw,
data, n_data,
signature, n_signature);
break;
diff --git a/pkcs11/gkr-pkcs11-rsa.c b/pkcs11/gkr-pkcs11-rsa.c
index cd2d305e..dea8923e 100644
--- a/pkcs11/gkr-pkcs11-rsa.c
+++ b/pkcs11/gkr-pkcs11-rsa.c
@@ -30,165 +30,6 @@
#include "pk/gkr-pk-pubkey.h"
#include "pk/gkr-pk-privkey.h"
-/* -------------------------------------------------------------------
- * RSA PADDING
- */
-
-guchar*
-gkr_pkcs11_rsa_pad_raw (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded)
-{
- gint total, n_pad;
- guchar *padded;
-
- /*
- * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
- * padding data
- */
-
- total = n_modulus / 8;
- n_pad = total - n_raw;
- if (n_pad < 0) /* minumum padding */
- return NULL;
-
- padded = g_new0 (guchar, total);
- memset (padded, 0x00, n_pad);
- memcpy (padded + n_pad, raw, n_raw);
-
- *n_padded = total;
- return padded;
-}
-
-guchar*
-gkr_pkcs11_rsa_pad_one (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded)
-{
- gint total, n_pad;
- guchar *padded;
-
- /*
- * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
- * type padding data
- */
-
- total = n_modulus / 8;
- n_pad = total - 3 - n_raw;
- if (n_pad < 8) /* minumum padding */
- return NULL;
-
- padded = g_new0 (guchar, total);
- padded[1] = 1; /* Block type */
- memset (padded + 2, 0xff, n_pad);
- memcpy (padded + 3 + n_pad, raw, n_raw);
-
- *n_padded = total;
- return padded;
-}
-
-static void
-fill_random_nonzero (guchar *data, gsize n_data)
-{
- guchar *rnd;
- guint n_zero, i, j;
-
- gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
-
- /* Find any zeros in random data */
- n_zero = 0;
- for (i = 0; i < n_data; ++i) {
- if (data[i] == 0x00)
- ++n_zero;
- }
-
- while (n_zero > 0) {
- rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
- n_zero = 0;
- for (i = 0, j = 0; i < n_data; ++i) {
- if (data[i] != 0x00)
- continue;
-
- /* Use some of the replacement data */
- data[i] = rnd[j];
- ++j;
-
- /* It's zero again :( */
- if (data[i] == 0x00)
- n_zero++;
- }
-
- gcry_free (rnd);
- }
-}
-
-guchar*
-gkr_pkcs11_rsa_pad_two (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded)
-{
- gint total, n_pad;
- guchar *padded;
-
- /*
- * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
- * type padding data
- */
-
- total = n_modulus / 8;
- n_pad = total - 3 - n_raw;
- if (n_pad < 8) /* minumum padding */
- return NULL;
-
- padded = g_new0 (guchar, total);
- padded[1] = 2; /* Block type */
- fill_random_nonzero (padded + 2, n_pad);
- memcpy (padded + 3 + n_pad, raw, n_raw);
-
- *n_padded = total;
- return padded;
-}
-
-static guchar*
-unpad_rsa_pkcs1 (guchar bt, guint n_modulus, const guchar* padded,
- gsize n_padded, gsize *n_raw)
-{
- const guchar *at;
- guchar *raw;
-
- /* The absolute minimum size including padding */
- g_return_val_if_fail (n_modulus / 8 >= 3 + 8, NULL);
-
- if (n_padded != n_modulus / 8)
- return NULL;
-
- /* Check the header */
- if (padded[0] != 0x00 || padded[1] != bt)
- return NULL;
-
- /* The first zero byte after the header */
- at = memchr (padded + 2, 0x00, n_padded - 2);
- if (!at)
- return NULL;
-
- ++at;
- *n_raw = n_padded - (at - padded);
- raw = g_new0 (guchar, *n_raw);
- memcpy (raw, at, *n_raw);
- return raw;
-}
-
-guchar*
-gkr_pkcs11_rsa_unpad_one (guint n_modulus, const guchar *raw,
- gsize n_raw, gsize *n_padded)
-{
- return unpad_rsa_pkcs1 (0x01, n_modulus, raw, n_raw, n_padded);
-}
-
-guchar*
-gkr_pkcs11_rsa_unpad_two (guint n_modulus, const guchar *raw,
- gsize n_raw, gsize *n_padded)
-{
- return unpad_rsa_pkcs1 (0x02, n_modulus, raw, n_raw, n_padded);
-}
-
static CK_RV
object_to_public_key (GkrPkObject *object, gcry_sexp_t *s_key)
{
@@ -236,7 +77,7 @@ object_to_private_key (GkrPkObject *object, gcry_sexp_t *s_key)
}
static CK_RV
-data_to_sexp (const gchar *format, guint nbits, GkrPkcs11RsaPadding padfunc,
+data_to_sexp (const gchar *format, guint nbits, GkrCryptoPadding padfunc,
const guchar *data, gsize n_data, gcry_sexp_t *sexp)
{
guchar *padded = NULL;
@@ -274,46 +115,24 @@ data_to_sexp (const gchar *format, guint nbits, GkrPkcs11RsaPadding padfunc,
static CK_RV
sexp_to_data (const gchar* format1, const gchar *format2, const gchar *format3,
- guint nbits, GkrPkcs11RsaPadding padfunc, gcry_sexp_t sexp,
+ guint nbits, GkrCryptoPadding padfunc, gcry_sexp_t sexp,
guchar **data, gsize *n_data)
{
- guchar *raw;
- gsize n_raw;
- gboolean res;
-
g_assert (format1);
g_assert (sexp);
g_assert (data);
g_assert (n_data);
- *n_data = nbits / 8;
- *data = g_malloc0 (*n_data);
-
/* Now extract and send it back out */
- res = gkr_crypto_sexp_extract_mpi_aligned (sexp, *data, *n_data,
- format1, format2, format3, NULL);
- g_return_val_if_fail (res, CKR_GENERAL_ERROR);
+ *data = gkr_crypto_sexp_extract_mpi_padded (sexp, nbits, n_data, padfunc,
+ format1, format2, format3, NULL);
+ g_return_val_if_fail (*data, CKR_GENERAL_ERROR);
- /* Now we unpad it if necessary */
- if (padfunc) {
- raw = (padfunc) (nbits, *data, *n_data, &n_raw);
-
- /*
- * If the unpadding failed, then it's probably
- * invalid data sent for decryption. Ignore.
- */
- if (raw) {
- g_free (*data);
- *data = raw;
- *n_data = n_raw;
- }
- }
-
return CKR_OK;
}
CK_RV
-gkr_pkcs11_rsa_encrypt (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
+gkr_pkcs11_rsa_encrypt (GkrPkObject *key, GkrCryptoPadding padfunc,
const guchar *plain, gsize n_plain,
guchar **encrypted, gsize *n_encrypted)
{
@@ -360,7 +179,7 @@ gkr_pkcs11_rsa_encrypt (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
}
CK_RV
-gkr_pkcs11_rsa_decrypt (GkrPkObject *object, GkrPkcs11RsaPadding padfunc,
+gkr_pkcs11_rsa_decrypt (GkrPkObject *object, GkrCryptoPadding padfunc,
const guchar *encrypted, gsize n_encrypted,
guchar **plain, gsize *n_plain)
{
@@ -412,7 +231,7 @@ gkr_crypto_sexp_dump (splain);
}
CK_RV
-gkr_pkcs11_rsa_sign (GkrPkObject *object, GkrPkcs11RsaPadding padfunc,
+gkr_pkcs11_rsa_sign (GkrPkObject *object, GkrCryptoPadding padfunc,
const guchar *input, gsize n_input,
guchar **signature, gsize *n_signature)
{
@@ -459,7 +278,7 @@ gkr_pkcs11_rsa_sign (GkrPkObject *object, GkrPkcs11RsaPadding padfunc,
}
CK_RV
-gkr_pkcs11_rsa_verify (GkrPkObject *object, GkrPkcs11RsaPadding padfunc,
+gkr_pkcs11_rsa_verify (GkrPkObject *object, GkrCryptoPadding padfunc,
const guchar *data, gsize n_data,
const guchar *signature, gsize n_signature)
{
diff --git a/pkcs11/gkr-pkcs11-rsa.h b/pkcs11/gkr-pkcs11-rsa.h
index 62280a8d..a0cc7e48 100644
--- a/pkcs11/gkr-pkcs11-rsa.h
+++ b/pkcs11/gkr-pkcs11-rsa.h
@@ -27,38 +27,21 @@
#include "pkcs11.h"
#include "pk/gkr-pk-object.h"
+#include "common/gkr-crypto.h"
-typedef guchar* (*GkrPkcs11RsaPadding) (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded);
-
-guchar* gkr_pkcs11_rsa_pad_raw (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded);
-
-guchar* gkr_pkcs11_rsa_pad_one (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded);
-
-guchar* gkr_pkcs11_rsa_pad_two (guint n_modulus, const guchar* raw,
- gsize n_raw, gsize *n_padded);
-
-guchar* gkr_pkcs11_rsa_unpad_one (guint n_modulus, const guchar* padded,
- gsize n_padded, gsize *n_raw);
-
-guchar* gkr_pkcs11_rsa_unpad_two (guint n_modulus, const guchar* padded,
- gsize n_padded, gsize *n_raw);
-
-CK_RV gkr_pkcs11_rsa_encrypt (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
+CK_RV gkr_pkcs11_rsa_encrypt (GkrPkObject *key, GkrCryptoPadding padfunc,
const guchar *plain, gsize n_plain,
guchar **encrypted, gsize *n_encrypted);
-CK_RV gkr_pkcs11_rsa_decrypt (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
+CK_RV gkr_pkcs11_rsa_decrypt (GkrPkObject *key, GkrCryptoPadding padfunc,
const guchar *encrypted, gsize n_encrypted,
guchar **plain, gsize *n_plain);
-CK_RV gkr_pkcs11_rsa_sign (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
+CK_RV gkr_pkcs11_rsa_sign (GkrPkObject *key, GkrCryptoPadding padfunc,
const guchar *data, gsize n_data,
guchar **signature, gsize *n_signature);
-CK_RV gkr_pkcs11_rsa_verify (GkrPkObject *key, GkrPkcs11RsaPadding padfunc,
+CK_RV gkr_pkcs11_rsa_verify (GkrPkObject *key, GkrCryptoPadding padfunc,
const guchar *data, gsize n_data,
const guchar *signature, gsize n_signature);
diff --git a/ssh/gkr-ssh-daemon-ops.c b/ssh/gkr-ssh-daemon-ops.c
index 4226ec08..171628bd 100644
--- a/ssh/gkr-ssh-daemon-ops.c
+++ b/ssh/gkr-ssh-daemon-ops.c
@@ -48,101 +48,125 @@
* SESSION KEYS
*/
-static gboolean had_session_keys = FALSE;
-static GList *ssh_session_keys = NULL;
+static GkrPkObjectManager *session_manager = NULL;
static void
-cleanup_session_keys (gpointer unused)
+mark_v1_key (GkrPkPrivkey *key)
{
- GList *l;
- for (l = ssh_session_keys; l; l = g_list_next (l))
- g_object_unref (l->data);
- g_list_free (ssh_session_keys);
- ssh_session_keys = NULL;
+ /* Track the version of the SSH protocol that this came in on */
+ g_object_set_data (G_OBJECT (key), "ssh-protocol-version", GUINT_TO_POINTER (1));
+}
+
+static gboolean
+check_v1_key (GkrPkPrivkey *key)
+{
+ return g_object_get_data (G_OBJECT (key), "ssh-protocol-version") == GUINT_TO_POINTER (1);
+}
+
+static void
+cleanup_session_manager (gpointer unused)
+{
+ g_return_if_fail (session_manager);
+ g_object_unref (session_manager);
+ session_manager = NULL;
}
static GkrPkPrivkey*
-find_private_key (gcry_sexp_t s_key, gboolean manager)
+find_private_key_in_manager (GkrPkObjectManager *manager, const gkrid keyid, guint version)
{
GkrPkPrivkey *key = NULL;
- gkrid keyid;
+ GList *l, *objects;
const guchar *data;
gsize n_data;
- GList *l, *objects;
-
- keyid = gkr_crypto_skey_make_id (s_key);
- g_return_val_if_fail (keyid != NULL, NULL);
+
+ data = gkr_id_get_raw (keyid, &n_data);
+ g_assert (data && n_data);
+
+ objects = gkr_pk_object_manager_findv (manager, GKR_TYPE_PK_PRIVKEY,
+ CKA_ID, data, n_data, NULL);
- for (l = ssh_session_keys; l; l = g_list_next (l)) {
- key = GKR_PK_PRIVKEY (l->data);
- if (gkr_id_equals (keyid, gkr_pk_privkey_get_keyid (key)))
- break;
+ for (l = objects; l; l = g_list_next (l)) {
+ key = GKR_PK_PRIVKEY (objects->data);
+ if ((version == 1) != check_v1_key (key))
+ continue;
+ break;
}
+
+ g_list_free (objects);
if (l == NULL)
key = NULL;
+
+ return key;
+}
+
+static GkrPkPrivkey*
+find_private_key (gcry_sexp_t skey, gboolean global, guint version)
+{
+ GkrPkPrivkey *key = NULL;
+ gkrid keyid;
- if (!key && manager) {
- data = gkr_id_get_raw (keyid, &n_data);
- g_assert (data && n_data);
-
- objects = gkr_pk_object_manager_findv (gkr_pk_object_manager_for_token (), GKR_TYPE_PK_PRIVKEY,
- CKA_ID, data, n_data, NULL);
- if (objects) {
- key = GKR_PK_PRIVKEY (objects->data);
- g_list_free (objects);
- }
- }
+ keyid = gkr_crypto_skey_make_id (skey);
+ g_return_val_if_fail (keyid != NULL, NULL);
- gkr_id_free (keyid);
+ /* Search through the session keys */
+ if (session_manager)
+ key = find_private_key_in_manager (session_manager, keyid, version);
+
+ /* Search through the global keys */
+ if (!key && global)
+ key = find_private_key_in_manager (gkr_pk_object_manager_for_token (), keyid, version);
+ gkr_id_free (keyid);
return key;
}
static void
remove_session_key (GkrPkPrivkey *key)
{
- GList *link = g_list_find (ssh_session_keys, key);
- if (!link)
- return;
- ssh_session_keys = g_list_remove_link (ssh_session_keys, link);
- g_object_unref (key);
- g_list_free_1 (link);
+ if (session_manager)
+ gkr_pk_object_manager_unregister (session_manager, GKR_PK_OBJECT (key));
}
static void
-add_session_key (gcry_sexp_t s_key, const gchar *comment)
+add_session_key (gcry_sexp_t skey, const gchar *comment, guint version)
{
GkrPkPrivkey *key, *prev;
+
+ if (!session_manager) {
+ session_manager = gkr_pk_object_manager_new ();
+ gkr_cleanup_register (cleanup_session_manager, NULL);
+ }
+
+ prev = find_private_key (skey, FALSE, version);
+ if (prev)
+ remove_session_key (prev);
- key = GKR_PK_PRIVKEY (gkr_pk_privkey_new (NULL, 0, s_key));
+ key = GKR_PK_PRIVKEY (gkr_pk_privkey_new (session_manager, 0, skey));
g_return_if_fail (key != NULL);
if (comment)
g_object_set (key, "label", comment, NULL);
- prev = find_private_key (s_key, FALSE);
- if (prev)
- remove_session_key (prev);
-
- ssh_session_keys = g_list_prepend (ssh_session_keys, key);
-
- if (!had_session_keys) {
- had_session_keys = TRUE;
- gkr_cleanup_register (cleanup_session_keys, NULL);
- }
+ if (version == 1)
+ mark_v1_key (key);
}
static void
-get_public_keys (GList *privates, GList** publics)
+get_public_keys (GList *objects, GList** publics, guint version)
{
GkrPkPrivkey *key;
GkrPkPubkey *pub;
- for (; privates; privates = g_list_next (privates)) {
+ for (; objects; objects = g_list_next (objects)) {
+
+ if (!GKR_IS_PK_PRIVKEY (objects->data))
+ continue;
+ key = GKR_PK_PRIVKEY (objects->data);
- key = GKR_PK_PRIVKEY (privates->data);
- g_return_if_fail (GKR_IS_PK_PRIVKEY (key));
+ /* When getting version one keys skip over any that aren't marked that way. */
+ if ((version == 1) != check_v1_key (key))
+ continue;
pub = GKR_PK_PUBKEY (gkr_pk_privkey_get_public (key));
if (!pub) {
@@ -205,7 +229,7 @@ op_add_identity (GkrBuffer *req, GkrBuffer *resp)
return FALSE;
}
- add_session_key (key, comment);
+ add_session_key (key, comment, 2);
g_free (comment);
gkr_buffer_add_byte (resp, GKR_SSH_RES_SUCCESS);
@@ -213,9 +237,31 @@ op_add_identity (GkrBuffer *req, GkrBuffer *resp)
}
static gboolean
+op_v1_add_identity (GkrBuffer *req, GkrBuffer *resp)
+{
+ gcry_sexp_t key;
+ gboolean ret;
+ gsize offset = 5;
+ guint32 unused;
+
+ if (!gkr_buffer_get_uint32 (req, offset, &offset, &unused))
+ return FALSE;
+
+ ret = gkr_ssh_proto_read_private_v1 (req, &offset, &key);
+ if (!ret || !key) {
+ g_warning ("couldn't read incoming SSH private key");
+ return FALSE;
+ }
+
+ add_session_key (key, "SSH1 RSA key", 1);
+
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_SUCCESS);
+ return TRUE;
+}
+
+static gboolean
op_request_identities (GkrBuffer *req, GkrBuffer *resp)
{
- gboolean ret = TRUE;
GList *objects, *pubkeys, *l;
GkrPkPubkey *pub;
const gchar *label;
@@ -225,8 +271,9 @@ op_request_identities (GkrBuffer *req, GkrBuffer *resp)
CKA_GNOME_PURPOSE_SSH_AUTH, CK_TRUE, 0, NULL);
pubkeys = NULL;
- get_public_keys (ssh_session_keys, &pubkeys);
- get_public_keys (objects, &pubkeys);
+ if (session_manager)
+ get_public_keys (session_manager->objects, &pubkeys, 2);
+ get_public_keys (objects, &pubkeys, 2);
g_list_free (objects);
@@ -249,7 +296,37 @@ op_request_identities (GkrBuffer *req, GkrBuffer *resp)
g_list_free (pubkeys);
- return ret;
+ return TRUE;
+}
+
+static gboolean
+op_v1_request_identities (GkrBuffer *req, GkrBuffer *resp)
+{
+ GList *l, *pubkeys = NULL;
+ GkrPkPubkey *pub;
+ const gchar *label;
+
+ if (session_manager)
+ get_public_keys (session_manager->objects, &pubkeys, 1);
+
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_RSA_IDENTITIES_ANSWER);
+ gkr_buffer_add_uint32 (resp, g_list_length (pubkeys));
+
+ for (l = pubkeys; l; l = g_list_next (l)) {
+
+ pub = GKR_PK_PUBKEY (l->data);
+ g_return_val_if_fail (GKR_IS_PK_PUBKEY (pub), FALSE);
+
+ if (!gkr_ssh_proto_write_public_v1 (resp, gkr_pk_pubkey_get_key (pub)))
+ return FALSE;
+
+ /* And now a per key comment */
+ label = gkr_pk_object_get_label (GKR_PK_OBJECT (pub));
+ gkr_buffer_add_string (resp, label ? label : "");
+ }
+
+ g_list_free (pubkeys);
+ return TRUE;
}
static gboolean
@@ -326,7 +403,7 @@ op_sign_request (GkrBuffer *req, GkrBuffer *resp)
}
/* Lookup the key */
- key = find_private_key (s_key, TRUE);
+ key = find_private_key (s_key, TRUE, 2);
gcry_sexp_release (s_key);
if (!key) {
@@ -358,8 +435,9 @@ op_sign_request (GkrBuffer *req, GkrBuffer *resp)
s_key = gkr_pk_privkey_get_key (key);
if (!s_key) {
- g_warning ("couldn't get private signing key");
- return FALSE;
+ g_message ("couldn't get private signing key");
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ return TRUE;
}
/* Do the magic */
@@ -404,6 +482,145 @@ op_sign_request (GkrBuffer *req, GkrBuffer *resp)
return TRUE;
}
+static gboolean
+make_decrypt_sexp (gcry_mpi_t mpi, gcry_sexp_t *sexp)
+{
+ gcry_error_t gcry;
+
+ gcry = gcry_sexp_build (sexp, NULL, "(enc-val (flags) (rsa (a %m)))", mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+op_v1_challenge (GkrBuffer *req, GkrBuffer *resp)
+{
+ guchar session_id[16];
+ gcry_error_t gcry;
+ gcry_md_hd_t hd = NULL;
+ gcry_sexp_t skey;
+ gcry_sexp_t splain = NULL;
+ gcry_sexp_t sdata = NULL;
+ GkrPkPrivkey *key;
+ const guchar *hash;
+ gcry_mpi_t challenge = NULL;
+ guchar *raw = NULL;
+ gsize offset, n_raw;
+ guint32 resp_type;
+ gboolean ret;
+ guint i, bits;
+ guchar b;
+
+ ret = FALSE;
+ offset = 5;
+
+ if (!gkr_ssh_proto_read_public_v1 (req, &offset, &skey))
+ return FALSE;
+
+ /* Lookup the key */
+ key = find_private_key (skey, TRUE, 1);
+ gcry_sexp_release (skey);
+
+ /* Read the entire challenge */
+ if (!gkr_ssh_proto_read_mpi_v1 (req, &offset, &challenge))
+ goto cleanup;
+
+ /* Only protocol 1.1 is supported */
+ if (req->len <= offset) {
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ ret = TRUE;
+ goto cleanup;
+ }
+
+ /* Read out the session id, raw, unbounded */
+ for (i = 0; i < 16; ++i) {
+ if (!gkr_buffer_get_byte (req, offset, &offset, &b))
+ goto cleanup;
+ session_id[i] = b;
+ }
+
+ /* And the response type */
+ if (!gkr_buffer_get_uint32 (req, offset, &offset, &resp_type))
+ goto cleanup;
+
+ /* Not supported request type */
+ if (resp_type != 1) {
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ ret = TRUE;
+ goto cleanup;
+ }
+
+ /* Didn't find a key earlier */
+ if (!key) {
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ ret = TRUE;
+ goto cleanup;
+ }
+
+ skey = gkr_pk_privkey_get_key (key);
+ if (!skey) {
+ g_message ("couldn't get private decryption key");
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ ret = TRUE;
+ goto cleanup;
+ }
+
+ /* Make our data sexpression */
+ if (!make_decrypt_sexp (challenge, &sdata))
+ return FALSE;
+
+gkr_crypto_sexp_dump (sdata);
+
+ /* Do the magic */
+ gcry = gcry_pk_decrypt (&splain, sdata, skey);
+
+ if (gcry) {
+ g_warning ("decryption of the data failed: %s", gcry_strerror (gcry));
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_FAILURE);
+ ret = TRUE;
+ goto cleanup;
+ }
+
+gkr_crypto_sexp_dump (splain);
+
+ /* Number of bits in the key */
+ bits = gcry_pk_get_nbits (skey);
+ g_return_val_if_fail (bits, FALSE);
+
+ /* Get out the value */
+ raw = gkr_crypto_sexp_extract_mpi_padded (splain, bits, &n_raw,
+ gkr_crypto_rsa_unpad_pkcs1, "value", NULL);
+ g_return_val_if_fail (raw, FALSE);
+
+ /* Now build up a hash of this and the session_id */
+ gcry = gcry_md_open (&hd, GCRY_MD_MD5, 0);
+ g_return_val_if_fail (gcry == 0, FALSE);
+ gcry_md_write (hd, raw, n_raw);
+ gcry_md_write (hd, session_id, sizeof (session_id));
+ hash = gcry_md_read (hd, 0);
+ g_return_val_if_fail (hash, FALSE);
+
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_RSA_RESPONSE);
+ gkr_buffer_append (resp, hash, 16);
+
+ ret = TRUE;
+
+cleanup:
+ if (hd)
+ gcry_md_close (hd);
+ if (challenge)
+ gcry_mpi_release (challenge);
+ if (sdata)
+ gcry_sexp_release (sdata);
+ if (splain)
+ gcry_sexp_release (splain);
+ if (raw)
+ g_free (raw);
+
+ return ret;
+}
+
static gboolean
op_remove_identity (GkrBuffer *req, GkrBuffer *resp)
{
@@ -415,7 +632,7 @@ op_remove_identity (GkrBuffer *req, GkrBuffer *resp)
if (!gkr_ssh_proto_read_public (req, &offset, &skey, NULL))
return FALSE;
- key = find_private_key (skey, FALSE);
+ key = find_private_key (skey, FALSE, 2);
gcry_sexp_release (skey);
if (key)
@@ -426,14 +643,68 @@ op_remove_identity (GkrBuffer *req, GkrBuffer *resp)
}
static gboolean
-op_remove_all_identities (GkrBuffer *req, GkrBuffer *resp)
+op_v1_remove_identity (GkrBuffer *req, GkrBuffer *resp)
{
GkrPkPrivkey *key;
+ gcry_sexp_t skey;
+ gsize offset;
- while (ssh_session_keys != NULL) {
- key = GKR_PK_PRIVKEY (ssh_session_keys->data);
- g_assert (GKR_IS_PK_PRIVKEY (key));
+ offset = 5;
+ if (!gkr_ssh_proto_read_public_v1 (req, &offset, &skey))
+ return FALSE;
+
+ key = find_private_key (skey, FALSE, 1);
+ gcry_sexp_release (skey);
+
+ if (key)
remove_session_key (key);
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_SUCCESS);
+
+ return TRUE;
+}
+
+static gboolean
+op_remove_all_identities (GkrBuffer *req, GkrBuffer *resp)
+{
+ GkrPkPrivkey *key;
+ GList *l, *removes = NULL;
+
+ if (session_manager) {
+ for (l = session_manager->objects; l; l = g_list_next (l)) {
+ if (!GKR_IS_PK_PRIVKEY (l->data))
+ continue;
+ key = GKR_PK_PRIVKEY (l->data);
+ if (!check_v1_key (key))
+ removes = g_list_prepend (removes, key);
+ }
+
+ for (l = removes; l; l = g_list_next (l))
+ remove_session_key (GKR_PK_PRIVKEY (l->data));
+ g_list_free (removes);
+ }
+
+ gkr_buffer_add_byte (resp, GKR_SSH_RES_SUCCESS);
+ return TRUE;
+}
+
+static gboolean
+op_v1_remove_all_identities (GkrBuffer *req, GkrBuffer *resp)
+{
+ GkrPkPrivkey *key;
+ GList *l, *removes = NULL;
+
+ if (session_manager) {
+ for (l = session_manager->objects; l; l = g_list_next (l)) {
+ if (!GKR_IS_PK_PRIVKEY (l->data))
+ continue;
+ key = GKR_PK_PRIVKEY (l->data);
+ if (check_v1_key (key))
+ removes = g_list_prepend (removes, key);
+ }
+
+ for (l = removes; l; l = g_list_next (l))
+ remove_session_key (GKR_PK_PRIVKEY (l->data));
+ g_list_free (removes);
}
gkr_buffer_add_byte (resp, GKR_SSH_RES_SUCCESS);
@@ -464,15 +735,15 @@ op_invalid (GkrBuffer *req, GkrBuffer *resp)
const GkrSshOperation gkr_ssh_operations[GKR_SSH_OP_MAX] = {
op_invalid, /* 0 */
- op_not_implemented_failure, /* GKR_SSH_OP_REQUEST_RSA_IDENTITIES */
+ op_v1_request_identities, /* GKR_SSH_OP_REQUEST_RSA_IDENTITIES */
op_invalid, /* 2 */
- op_not_implemented_failure, /* GKR_SSH_OP_RSA_CHALLENGE */
+ op_v1_challenge, /* GKR_SSH_OP_RSA_CHALLENGE */
op_invalid, /* 4 */
op_invalid, /* 5 */
op_invalid, /* 6 */
- op_not_implemented_failure, /* GKR_SSH_OP_ADD_RSA_IDENTITY */
- op_not_implemented_failure, /* GKR_SSH_OP_REMOVE_RSA_IDENTITY */
- op_not_implemented_success, /* GKR_SSH_OP_REMOVE_ALL_RSA_IDENTITIES */
+ op_v1_add_identity, /* GKR_SSH_OP_ADD_RSA_IDENTITY */
+ op_v1_remove_identity, /* GKR_SSH_OP_REMOVE_RSA_IDENTITY */
+ op_v1_remove_all_identities, /* GKR_SSH_OP_REMOVE_ALL_RSA_IDENTITIES */
op_invalid, /* 10 */
op_request_identities, /* GKR_SSH_OP_REQUEST_IDENTITIES */
op_invalid, /* 12 */
@@ -487,7 +758,7 @@ const GkrSshOperation gkr_ssh_operations[GKR_SSH_OP_MAX] = {
op_not_implemented_failure, /* GKR_SSH_OP_REMOVE_SMARTCARD_KEY */
op_not_implemented_success, /* GKR_SSH_OP_LOCK */
op_not_implemented_success, /* GKR_SSH_OP_UNLOCK */
- op_not_implemented_failure, /* GKR_SSH_OP_ADD_RSA_ID_CONSTRAINED */
+ op_v1_add_identity, /* GKR_SSH_OP_ADD_RSA_ID_CONSTRAINED */
op_not_implemented_failure, /* GKR_SSH_OP_ADD_ID_CONSTRAINED */
op_not_implemented_failure, /* GKR_SSH_OP_ADD_SMARTCARD_KEY_CONSTRAINED */
};
diff --git a/ssh/gkr-ssh-private.h b/ssh/gkr-ssh-private.h
index e4e49111..bbd1f2fd 100644
--- a/ssh/gkr-ssh-private.h
+++ b/ssh/gkr-ssh-private.h
@@ -88,24 +88,34 @@ const gchar* gkr_ssh_proto_algo_to_keytype (int algo);
gboolean gkr_ssh_proto_read_mpi (GkrBuffer *req, gsize *offset, gcry_mpi_t *mpi);
+gboolean gkr_ssh_proto_read_mpi_v1 (GkrBuffer *req, gsize *offset, gcry_mpi_t *mpi);
+
gboolean gkr_ssh_proto_write_mpi (GkrBuffer *resp, gcry_mpi_t mpi, int format);
+gboolean gkr_ssh_proto_write_mpi_v1 (GkrBuffer *resp, gcry_mpi_t mpi);
+
gboolean gkr_ssh_proto_read_public (GkrBuffer *req, gsize *offset, gcry_sexp_t *key, int *algo);
gboolean gkr_ssh_proto_read_public_rsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
gboolean gkr_ssh_proto_read_public_dsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
+gboolean gkr_ssh_proto_read_public_v1 (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
+
gboolean gkr_ssh_proto_read_private_rsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
gboolean gkr_ssh_proto_read_private_dsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
+gboolean gkr_ssh_proto_read_private_v1 (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp);
+
gboolean gkr_ssh_proto_write_public (GkrBuffer *resp, int algorithm, gcry_sexp_t key);
gboolean gkr_ssh_proto_write_public_rsa (GkrBuffer *resp, gcry_sexp_t key);
gboolean gkr_ssh_proto_write_public_dsa (GkrBuffer *resp, gcry_sexp_t key);
+gboolean gkr_ssh_proto_write_public_v1 (GkrBuffer *resp, gcry_sexp_t key);
+
gboolean gkr_ssh_proto_write_signature_rsa (GkrBuffer *resp, gcry_sexp_t ssig);
gboolean gkr_ssh_proto_write_signature_dsa (GkrBuffer *resp, gcry_sexp_t ssig);
diff --git a/ssh/gkr-ssh-proto.c b/ssh/gkr-ssh-proto.c
index 6cb79a1b..0c29d377 100644
--- a/ssh/gkr-ssh-proto.c
+++ b/ssh/gkr-ssh-proto.c
@@ -71,6 +71,36 @@ gkr_ssh_proto_read_mpi (GkrBuffer *req, gsize *offset, gcry_mpi_t *mpi)
}
gboolean
+gkr_ssh_proto_read_mpi_v1 (GkrBuffer *req, gsize *offset, gcry_mpi_t *mpi)
+{
+ const guchar *data;
+ gsize bytes;
+ gcry_error_t gcry;
+ guint16 bits;
+
+ /* Get the number of bits */
+ if (!gkr_buffer_get_uint16 (req, *offset, offset, &bits))
+ return FALSE;
+
+ /* Figure out the number of binary bytes following */
+ bytes = (bits + 7) / 8;
+ if (bytes > 8 * 1024)
+ return FALSE;
+
+ /* Pull these out directly */
+ if (req->len < *offset + bytes)
+ return FALSE;
+ data = req->buf + *offset;
+ *offset += bytes;
+
+ gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_USG, data, bytes, NULL);
+ if (gcry)
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
gkr_ssh_proto_write_mpi (GkrBuffer *resp, gcry_mpi_t mpi, int format)
{
guchar *buf;
@@ -94,6 +124,39 @@ gkr_ssh_proto_write_mpi (GkrBuffer *resp, gcry_mpi_t mpi, int format)
}
gboolean
+gkr_ssh_proto_write_mpi_v1 (GkrBuffer *resp, gcry_mpi_t mpi)
+{
+ gcry_error_t gcry;
+ guchar *buf;
+ gsize bits;
+ gsize bytes, len;
+
+ bits = gcry_mpi_get_nbits (mpi);
+ g_return_val_if_fail (bits <= G_MAXUSHORT, FALSE);
+
+ bytes = (bits + 7) / 8;
+
+ /* Get the size */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+ g_return_val_if_fail (bytes == len, FALSE);
+
+ if (!gkr_buffer_add_uint16 (resp, bits))
+ return FALSE;
+
+ /* Make a space for it in the buffer */
+ buf = gkr_buffer_add_empty (resp, len);
+ if (!buf)
+ return FALSE;
+
+ /* Write in directly to buffer */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buf, bytes, &len, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ return TRUE;
+}
+
+gboolean
gkr_ssh_proto_read_public (GkrBuffer *req, gsize *offset, gcry_sexp_t *key, int *algo)
{
gboolean ret;
@@ -191,6 +254,48 @@ gkr_ssh_proto_read_private_rsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp
return TRUE;
}
+gboolean
+gkr_ssh_proto_read_private_v1 (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp)
+{
+ gcry_mpi_t n, e, d, p, q, u;
+ gcry_mpi_t tmp;
+ int gcry;
+
+ if (!gkr_ssh_proto_read_mpi_v1 (req, offset, &n) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &e) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &d) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &u) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &p) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &q))
+ return FALSE;
+
+ /* Fix up the incoming key so gcrypt likes it */
+ if (gcry_mpi_cmp (p, q) > 0) {
+ /* P shall be smaller then Q! Swap primes. iqmp becomes u. */
+ tmp = p;
+ p = q;
+ q = tmp;
+ } else {
+ /* U needs to be recomputed. */
+ gcry_mpi_invm (u, p, q);
+ }
+
+ gcry = gcry_sexp_build (sexp, NULL, SEXP_PRIVATE_RSA, n, e, d, p, q, u);
+ if (gcry) {
+ g_warning ("couldn't parse incoming private RSA key: %s", gcry_strerror (gcry));
+ return FALSE;
+ }
+
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ gcry_mpi_release (p);
+ gcry_mpi_release (q);
+ gcry_mpi_release (u);
+
+ return TRUE;
+}
+
#define SEXP_PUBLIC_RSA \
"(public-key" \
" (rsa" \
@@ -219,6 +324,32 @@ gkr_ssh_proto_read_public_rsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp)
return TRUE;
}
+gboolean
+gkr_ssh_proto_read_public_v1 (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp)
+{
+ gcry_mpi_t n, e;
+ guint32 bits;
+ int gcry;
+
+ if (!gkr_buffer_get_uint32 (req, *offset, offset, &bits))
+ return FALSE;
+
+ if (!gkr_ssh_proto_read_mpi_v1 (req, offset, &e) ||
+ !gkr_ssh_proto_read_mpi_v1 (req, offset, &n))
+ return FALSE;
+
+ gcry = gcry_sexp_build (sexp, NULL, SEXP_PUBLIC_RSA, n, e);
+ if (gcry) {
+ g_warning ("couldn't parse incoming public RSA key: %s", gcry_strerror (gcry));
+ return FALSE;
+ }
+
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+
+ return TRUE;
+}
+
#define SEXP_PRIVATE_DSA \
"(private-key" \
" (dsa" \
@@ -392,6 +523,38 @@ gkr_ssh_proto_write_public_dsa (GkrBuffer *resp, gcry_sexp_t key)
}
gboolean
+gkr_ssh_proto_write_public_v1 (GkrBuffer *resp, gcry_sexp_t key)
+{
+ gboolean ret = FALSE;
+ gcry_mpi_t mpi;
+ unsigned int bits;
+
+ /* This is always an RSA key. */
+
+ /* Write out the number of bits of the key */
+ bits = gcry_pk_get_nbits (key);
+ g_return_val_if_fail (bits > 0, FALSE);
+ gkr_buffer_add_uint32 (resp, bits);
+
+ /* Write out the exponent */
+ ret = gkr_crypto_sexp_extract_mpi (key, &mpi, "rsa", "e", NULL);
+ g_return_val_if_fail (ret, FALSE);
+ ret = gkr_ssh_proto_write_mpi_v1 (resp, mpi);
+ gcry_mpi_release (mpi);
+
+ if (!ret)
+ return ret;
+
+ /* Write out the public value */
+ ret = gkr_crypto_sexp_extract_mpi (key, &mpi, "rsa", "n", NULL);
+ g_return_val_if_fail (ret, FALSE);
+ ret = gkr_ssh_proto_write_mpi_v1 (resp, mpi);
+ gcry_mpi_release (mpi);
+
+ return ret;
+}
+
+gboolean
gkr_ssh_proto_write_signature_rsa (GkrBuffer *resp, gcry_sexp_t ssig)
{
gboolean ret;