diff options
author | Stefan Walter <stefw@src.gnome.org> | 2008-03-17 01:14:46 +0000 |
---|---|---|
committer | Stefan Walter <stefw@src.gnome.org> | 2008-03-17 01:14:46 +0000 |
commit | f3413460f5a2cb4d8c09f2973d92fb33c5b2ac98 (patch) | |
tree | 4cd568bd04b62ceb66715e4ba0bb2ec1a4c1fc86 | |
parent | 7d18018e42f4306c19d61d9a4eacf089a5f870a2 (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-- | ChangeLog | 19 | ||||
-rw-r--r-- | common/gkr-buffer.c | 69 | ||||
-rw-r--r-- | common/gkr-buffer.h | 25 | ||||
-rw-r--r-- | common/gkr-crypto.c | 258 | ||||
-rw-r--r-- | common/gkr-crypto.h | 28 | ||||
-rw-r--r-- | pk/gkr-pk-object-manager.c | 6 | ||||
-rw-r--r-- | pk/gkr-pk-object-manager.h | 2 | ||||
-rw-r--r-- | pk/gkr-pk-pubkey.c | 1 | ||||
-rw-r--r-- | pkcs11/gkr-pkcs11-daemon-session.c | 15 | ||||
-rw-r--r-- | pkcs11/gkr-pkcs11-rsa.c | 199 | ||||
-rw-r--r-- | pkcs11/gkr-pkcs11-rsa.h | 27 | ||||
-rw-r--r-- | ssh/gkr-ssh-daemon-ops.c | 413 | ||||
-rw-r--r-- | ssh/gkr-ssh-private.h | 10 | ||||
-rw-r--r-- | ssh/gkr-ssh-proto.c | 163 |
14 files changed, 907 insertions, 328 deletions
@@ -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; |