summaryrefslogtreecommitdiff
path: root/ssh-ecdsa.c
diff options
context:
space:
mode:
authordjm <djm>2010-08-31 12:41:14 +0000
committerdjm <djm>2010-08-31 12:41:14 +0000
commitec4796209c12ff791e323f7022848f7ec5283d85 (patch)
tree7d738920e0031c92f456ae6b7d0247d4c973c496 /ssh-ecdsa.c
parentdac0b76fb075046228ec5f2f1168a87be7398e3f (diff)
downloadopenssh-ec4796209c12ff791e323f7022848f7ec5283d85.tar.gz
- djm@cvs.openbsd.org 2010/08/31 11:54:45
[PROTOCOL PROTOCOL.agent PROTOCOL.certkeys auth2-jpake.c authfd.c] [authfile.c buffer.h dns.c kex.c kex.h key.c key.h monitor.c] [monitor_wrap.c myproposal.h packet.c packet.h pathnames.h readconf.c] [ssh-add.1 ssh-add.c ssh-agent.1 ssh-agent.c ssh-keygen.1 ssh-keygen.c] [ssh-keyscan.1 ssh-keyscan.c ssh-keysign.8 ssh.1 ssh.c ssh2.h] [ssh_config.5 sshconnect.c sshconnect2.c sshd.8 sshd.c sshd_config.5] [uuencode.c uuencode.h bufec.c kexecdh.c kexecdhc.c kexecdhs.c ssh-ecdsa.c] Implement Elliptic Curve Cryptography modes for key exchange (ECDH) and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA offer better performance than plain DH and DSA at the same equivalent symmetric key length, as well as much shorter keys. Only the mandatory sections of RFC5656 are implemented, specifically the three REQUIRED curves nistp256, nistp384 and nistp521 and only ECDH and ECDSA. Point compression (optional in RFC5656 is NOT implemented). Certificate host and user keys using the new ECDSA key types are supported. Note that this code has not been tested for interoperability and may be subject to change. feedback and ok markus@
Diffstat (limited to 'ssh-ecdsa.c')
-rw-r--r--ssh-ecdsa.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
new file mode 100644
index 00000000..a1c1bdb6
--- /dev/null
+++ b/ssh-ecdsa.c
@@ -0,0 +1,160 @@
+/* $OpenBSD */
+/*
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2010 Damien Miller. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+
+#include <string.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "compat.h"
+#include "log.h"
+#include "key.h"
+
+int
+ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp,
+ const u_char *data, u_int datalen)
+{
+ ECDSA_SIG *sig;
+ const EVP_MD *evp_md = EVP_sha256();
+ EVP_MD_CTX md;
+ u_char digest[EVP_MAX_MD_SIZE];
+ u_int len, dlen;
+ Buffer b, bb;
+
+ if (key == NULL || key->ecdsa == NULL ||
+ (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
+ error("%s: no ECDSA key", __func__);
+ return -1;
+ }
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, &dlen);
+
+ sig = ECDSA_do_sign(digest, dlen, key->ecdsa);
+ memset(digest, 'd', sizeof(digest));
+
+ if (sig == NULL) {
+ error("%s: sign failed", __func__);
+ return -1;
+ }
+
+ buffer_init(&bb);
+ buffer_put_bignum2(&bb, sig->r);
+ buffer_put_bignum2(&bb, sig->s);
+ ECDSA_SIG_free(sig);
+
+ buffer_init(&b);
+ buffer_put_cstring(&b, key_ssh_name_plain(key));
+ buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
+ buffer_free(&bb);
+ len = buffer_len(&b);
+ if (lenp != NULL)
+ *lenp = len;
+ if (sigp != NULL) {
+ *sigp = xmalloc(len);
+ memcpy(*sigp, buffer_ptr(&b), len);
+ }
+ buffer_free(&b);
+
+ return 0;
+}
+int
+ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
+ const u_char *data, u_int datalen)
+{
+ ECDSA_SIG *sig;
+ const EVP_MD *evp_md = EVP_sha256();
+ EVP_MD_CTX md;
+ u_char digest[EVP_MAX_MD_SIZE], *sigblob;
+ u_int len, dlen;
+ int rlen, ret;
+ Buffer b, bb;
+
+ if (key == NULL || key->ecdsa == NULL ||
+ (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
+ error("%s: no ECDSA key", __func__);
+ return -1;
+ }
+
+ /* fetch signature */
+ char *ktype;
+ buffer_init(&b);
+ buffer_append(&b, signature, signaturelen);
+ ktype = buffer_get_string(&b, NULL);
+ if (strcmp(key_ssh_name_plain(key), ktype) != 0) {
+ error("%s: cannot handle type %s", __func__, ktype);
+ buffer_free(&b);
+ xfree(ktype);
+ return -1;
+ }
+ xfree(ktype);
+ sigblob = buffer_get_string(&b, &len);
+ rlen = buffer_len(&b);
+ buffer_free(&b);
+ if (rlen != 0) {
+ error("%s: remaining bytes in signature %d", __func__, rlen);
+ xfree(sigblob);
+ return -1;
+ }
+
+ /* parse signature */
+ if ((sig = ECDSA_SIG_new()) == NULL)
+ fatal("%s: ECDSA_SIG_new failed", __func__);
+ if ((sig->r = BN_new()) == NULL ||
+ (sig->s = BN_new()) == NULL)
+ fatal("%s: BN_new failed", __func__);
+
+ buffer_init(&bb);
+ buffer_append(&bb, sigblob, len);
+ buffer_get_bignum2(&bb, sig->r);
+ buffer_get_bignum2(&bb, sig->s);
+ if (buffer_len(&bb) != 0)
+ fatal("%s: remaining bytes in inner sigblob", __func__);
+
+ /* clean up */
+ memset(sigblob, 0, len);
+ xfree(sigblob);
+
+ /* hash the data */
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, data, datalen);
+ EVP_DigestFinal(&md, digest, &dlen);
+
+ ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa);
+ memset(digest, 'd', sizeof(digest));
+
+ ECDSA_SIG_free(sig);
+
+ debug("%s: signature %s", __func__,
+ ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
+ return ret;
+}