Added SSH2 protocol compliant signature format.
authorPekka Riikonen <priikone@silcnet.org>
Sat, 21 Jul 2007 19:08:19 +0000 (19:08 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 21 Jul 2007 19:08:19 +0000 (19:08 +0000)
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silcssh/silcssh.h
lib/silcssh/silcssh_pkcs.c

index 46eb84b97e0cf0afc6bea703e8738efac900352a..9611866171e7af8ba286dc5dc92cfb7a1a5102ea 100644 (file)
@@ -166,7 +166,7 @@ const SilcPKCSAlgorithm silc_default_pkcs_alg[] =
   },
 
 #ifdef SILC_DIST_SSH
-  /* PKCS #1, Version 1.5 without hash OIDs, SSH2 style public keys */
+  /* PKCS #1, SSH2 style public keys */
   {
     "rsa",
     "ssh",
index 978da199882dc82c95cac8b3a2e4d24de3f60eab..2fd34f7490650fb731eda7c30007401524b1f626 100644 (file)
@@ -469,7 +469,9 @@ SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
  *
  * DESCRIPTION
  *
- *    Frees the public key.
+ *    Frees the public key.  This will also automatically free the underlaying
+ *    PKCS specific public key.  All public keys allocated through the
+ *    PKCS API must be freed by calling this function.
  *
  ***/
 void silc_pkcs_public_key_free(SilcPublicKey public_key);
@@ -580,7 +582,9 @@ SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key);
  *
  * DESCRIPTION
  *
- *    Frees the private key.
+ *    Frees the public key.  This will also automatically free the underlaying
+ *    PKCS specific private key.  All private keys allocated through the
+ *    PKCS API must be freed by calling this function.
  *
  ***/
 void silc_pkcs_private_key_free(SilcPrivateKey private_key);
index 9f4e8b89a66aa28b3924b87a6d05acf44b504f7a..acc989299bd7c6d34ab1da5cb6086c0e89f16f84 100644 (file)
@@ -61,8 +61,9 @@
  * silc_pkcs_load_private_key("privkey.pub", passphrase, passphrase_len,
  *                            SILC_PKCS_SSH2, &public_key);
  *
- * // Compute signature
- * silc_pkcs_sign(private_key, src, src_len, TRUE, sha1, rng, sign_cb, ctx);
+ * // Free public and private key. Frees automatically the underlaying SSH keys.
+ * silc_pkcs_public_key_free(public_key);
+ * silc_pkcs_private_key_free(private_key);
  *
  ***/
 #ifndef SILCSSH_H
@@ -76,7 +77,7 @@
  *
  * DESCRIPTION
  *
- *    SSH2 public and private key types.  The default when new ke pair
+ *    SSH2 public and private key types.  The default when new key pair
  *    is created is SILC_SSH_KEY_OPENSSH.
  *
  * SOURCE
@@ -96,7 +97,7 @@ typedef enum {
  *
  *    This structure defines the SSH2 public key.  This context can be
  *    retrieved from SilcPublicKey by calling silc_pkcs_public_key_get_pkcs
- *    for the PKCS type SILC_PKCS_SSH2 type.
+ *    for the PKCS type SILC_PKCS_SSH2.
  *
  * SOURCE
  */
@@ -118,7 +119,7 @@ typedef struct SilcSshPublicKeyStruct  {
  *
  *    This structure defines the SSH2 private key.  This context can be
  *    retrieved from SilcPrivateKey by calling silc_pkcs_private_key_get_pkcs
- *    for the PKCS type SILC_PKCS_SSH2 type.
+ *    for the PKCS type SILC_PKCS_SSH2.
  *
  * SOURCE
  */
@@ -174,6 +175,8 @@ SilcBool silc_ssh_generate_key(const char *algorithm,
  *    function.  This function expects the public key to be in raw binary
  *    format, without any public key file markers or headers.
  *
+ *    This decodes SSH2 protocol compliant raw public key.
+ *
  *    This function returns the number of bytes decoded from the public
  *    key buffer or 0 on error.
  *
@@ -194,6 +197,8 @@ int silc_ssh_public_key_decode(unsigned char *key, SilcUInt32 key_len,
  *    Encodes SSH Public key and returns the encoded buffer.  Caller must
  *    free the returned buffer.
  *
+ *    This encodes SSH2 protocol compliant raw public key.
+ *
  *    If the `stack' is non-NULL the returned buffer is allocated from the
  *    `stack'.  This call will consume `stack' so caller should push the stack
  *    before calling and then later pop it.
@@ -211,7 +216,9 @@ unsigned char *silc_ssh_public_key_encode(SilcStack stack,
  *
  * DESCRIPTION
  *
- *    Frees the public key.
+ *    Frees the public key.  This need to be called only if you called
+ *    silc_ssh_public_key_decode.  SSH public keys allocated through the
+ *    SILC PKCS API can be freed by calling silc_pkcs_public_key_free.
  *
  ***/
 void silc_ssh_public_key_free(SilcSshPublicKey public_key);
index 1821709e4c18d5e6a2c426a00ff8de2646228a58..9417ad75e7da6359f576e0df8ccc782b66be90e8 100644 (file)
@@ -843,21 +843,71 @@ SILC_PKCS_DECRYPT(silc_pkcs_ssh_decrypt)
                                src, src_len, decrypt_cb, context);
 }
 
+/* Sign context */
+typedef struct {
+  SilcSshPrivateKey privkey;
+  SilcPKCSSignCb sign_cb;
+  void *context;
+} *SilcSshSign;
+
+/* Sign callback.  This formats the signature into SSH2 protocool compliant
+   format. */
+
+static void silc_pkcs_ssh_sign_cb(SilcBool success,
+                                 const unsigned char *signature,
+                                 SilcUInt32 signature_len,
+                                 void *context)
+{
+  SilcSshSign sign = context;
+  SilcBufferStruct sig;
+
+  memset(&sig, 0, sizeof(sig));
+  if (silc_buffer_format(&sig,
+                        SILC_STR_UI_INT(7),
+                        SILC_STR_UI32_STRING("ssh-"),
+                        SILC_STR_UI32_STRING(sign->privkey->pkcs->name),
+                        SILC_STR_UI_INT(signature_len),
+                        SILC_STR_DATA(signature, signature_len),
+                        SILC_STR_END) < 0) {
+    silc_free(sign);
+    sign->sign_cb(FALSE, NULL, 0, sign->context);
+  }
+
+  /* Deliver result */
+  sign->sign_cb(TRUE, silc_buffer_data(&sig), silc_buffer_len(&sig),
+               sign->context);
+
+  silc_buffer_purge(&sig);
+  silc_free(sign);
+}
+
 /* Sign */
 
 SILC_PKCS_SIGN(silc_pkcs_ssh_sign)
 {
   SilcSshPrivateKey privkey = private_key;
+  SilcSshSign sign;
 
   if (!privkey->pkcs->sign) {
     sign_cb(FALSE, NULL, 0, context);
     return NULL;
   }
 
+  sign = silc_calloc(1, sizeof(*sign));
+  if (!sign) {
+    sign_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
+
+  sign->privkey = privkey;
+  sign->sign_cb = sign_cb;
+  sign->context = context;
+
+  /* Sign.  The callback will format it to SSH2 compliant format. */
   return privkey->pkcs->sign(privkey->pkcs, privkey->private_key,
                             src, src_len,
                             compute_hash, hash, rng,
-                            sign_cb, context);
+                            silc_pkcs_ssh_sign_cb, sign);
 }
 
 /* Verify */
@@ -865,12 +915,25 @@ SILC_PKCS_SIGN(silc_pkcs_ssh_sign)
 SILC_PKCS_VERIFY(silc_pkcs_ssh_verify)
 {
   SilcSshPublicKey pubkey = public_key;
+  SilcBufferStruct sig;
 
   if (!pubkey->pkcs->verify) {
     verify_cb(FALSE, context);
     return NULL;
   }
 
+  /* Decode the SSH2 protocol style signature encoding.  Ignore the
+     algorithm name.  We know the algorithm. */
+  silc_buffer_set(&sig, signature, signature_len);
+  if (silc_buffer_unformat(&sig,
+                          SILC_STR_UI32_NSTRING(NULL, NULL),
+                          SILC_STR_UI32_NSTRING(&signature, &signature_len),
+                          SILC_STR_END) < 0) {
+    verify_cb(FALSE, context);
+    return NULL;
+  }
+
+  /* Verify */
   return pubkey->pkcs->verify(pubkey->pkcs, pubkey->public_key,
                              signature, signature_len,
                              data, data_len, hash, rng,