From: Pekka Riikonen Date: Sat, 21 Jul 2007 19:08:19 +0000 (+0000) Subject: Added SSH2 protocol compliant signature format. X-Git-Tag: 1.2.beta1~154 X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=commitdiff_plain;h=350f7d6bc38890ee67ef9475775df97e2a96a87b Added SSH2 protocol compliant signature format. --- diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 46eb84b9..96118661 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -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", diff --git a/lib/silccrypt/silcpkcs.h b/lib/silccrypt/silcpkcs.h index 978da199..2fd34f74 100644 --- a/lib/silccrypt/silcpkcs.h +++ b/lib/silccrypt/silcpkcs.h @@ -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); diff --git a/lib/silcssh/silcssh.h b/lib/silcssh/silcssh.h index 9f4e8b89..acc98929 100644 --- a/lib/silcssh/silcssh.h +++ b/lib/silcssh/silcssh.h @@ -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); diff --git a/lib/silcssh/silcssh_pkcs.c b/lib/silcssh/silcssh_pkcs.c index 1821709e..9417ad75 100644 --- a/lib/silcssh/silcssh_pkcs.c +++ b/lib/silcssh/silcssh_pkcs.c @@ -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,