summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2009-03-05 07:18:20 +0000
committerDamien Miller <djm@cvs.openbsd.org>2009-03-05 07:18:20 +0000
commit963b49d130359226086bd920156e5ceb7e6a6e98 (patch)
tree3cd37899e8fb0234571b558ab0a75c59b6dff7e3 /usr.bin/ssh
parent2b3d8146716d5c03b85049d1d4ab3f7452a18dab (diff)
refactor the (disabled) Schnorr proof code to make it a little more
generally useful
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/auth2-jpake.c5
-rw-r--r--usr.bin/ssh/jpake.c181
-rw-r--r--usr.bin/ssh/jpake.h38
-rw-r--r--usr.bin/ssh/monitor_wrap.c9
-rw-r--r--usr.bin/ssh/monitor_wrap.h10
-rw-r--r--usr.bin/ssh/schnorr.c374
-rw-r--r--usr.bin/ssh/schnorr.h60
-rw-r--r--usr.bin/ssh/sshconnect2.c3
8 files changed, 403 insertions, 277 deletions
diff --git a/usr.bin/ssh/auth2-jpake.c b/usr.bin/ssh/auth2-jpake.c
index cdd8af2f93c..5de5506a664 100644
--- a/usr.bin/ssh/auth2-jpake.c
+++ b/usr.bin/ssh/auth2-jpake.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-jpake.c,v 1.2 2008/11/07 23:34:48 dtucker Exp $ */
+/* $OpenBSD: auth2-jpake.c,v 1.3 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright (c) 2008 Damien Miller. All rights reserved.
*
@@ -55,6 +55,7 @@
#endif
#include "monitor_wrap.h"
+#include "schnorr.h"
#include "jpake.h"
/*
@@ -359,7 +360,7 @@ auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
}
/*
- * Being authentication attempt.
+ * Begin authentication attempt.
* Note, sets authctxt->postponed while in subprotocol
*/
static int
diff --git a/usr.bin/ssh/jpake.c b/usr.bin/ssh/jpake.c
index 2dfe1230fc6..450b4cb2853 100644
--- a/usr.bin/ssh/jpake.c
+++ b/usr.bin/ssh/jpake.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: jpake.c,v 1.1 2008/11/04 08:22:12 djm Exp $ */
+/* $OpenBSD: jpake.c,v 1.2 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright (c) 2008 Damien Miller. All rights reserved.
*
@@ -45,6 +45,7 @@
#include "log.h"
#include "jpake.h"
+#include "schnorr.h"
#ifdef JPAKE
@@ -58,165 +59,10 @@
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB" \
"9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
-struct jpake_group *
+struct modp_group *
jpake_default_group(void)
{
- struct jpake_group *ret;
-
- ret = xmalloc(sizeof(*ret));
- ret->p = ret->q = ret->g = NULL;
- if (BN_hex2bn(&ret->p, JPAKE_GROUP_P) == 0 ||
- BN_hex2bn(&ret->g, JPAKE_GROUP_G) == 0)
- fatal("%s: BN_hex2bn", __func__);
- /* Subgroup order is p/2 (p is a safe prime) */
- if ((ret->q = BN_new()) == NULL)
- fatal("%s: BN_new", __func__);
- if (BN_rshift1(ret->q, ret->p) != 1)
- fatal("%s: BN_rshift1", __func__);
-
- return ret;
-}
-
-/*
- * Generate uniformly distributed random number in range (1, high).
- * Return number on success, NULL on failure.
- */
-BIGNUM *
-bn_rand_range_gt_one(const BIGNUM *high)
-{
- BIGNUM *r, *tmp;
- int success = -1;
-
- if ((tmp = BN_new()) == NULL) {
- error("%s: BN_new", __func__);
- return NULL;
- }
- if ((r = BN_new()) == NULL) {
- error("%s: BN_new failed", __func__);
- goto out;
- }
- if (BN_set_word(tmp, 2) != 1) {
- error("%s: BN_set_word(tmp, 2)", __func__);
- goto out;
- }
- if (BN_sub(tmp, high, tmp) == -1) {
- error("%s: BN_sub failed (tmp = high - 2)", __func__);
- goto out;
- }
- if (BN_rand_range(r, tmp) == -1) {
- error("%s: BN_rand_range failed", __func__);
- goto out;
- }
- if (BN_set_word(tmp, 2) != 1) {
- error("%s: BN_set_word(tmp, 2)", __func__);
- goto out;
- }
- if (BN_add(r, r, tmp) == -1) {
- error("%s: BN_add failed (r = r + 2)", __func__);
- goto out;
- }
- success = 0;
- out:
- BN_clear_free(tmp);
- if (success == 0)
- return r;
- BN_clear_free(r);
- return NULL;
-}
-
-/*
- * Hash contents of buffer 'b' with hash 'md'. Returns 0 on success,
- * with digest via 'digestp' (caller to free) and length via 'lenp'.
- * Returns -1 on failure.
- */
-int
-hash_buffer(const u_char *buf, u_int len, const EVP_MD *md,
- u_char **digestp, u_int *lenp)
-{
- u_char digest[EVP_MAX_MD_SIZE];
- u_int digest_len;
- EVP_MD_CTX evp_md_ctx;
- int success = -1;
-
- EVP_MD_CTX_init(&evp_md_ctx);
-
- if (EVP_DigestInit_ex(&evp_md_ctx, md, NULL) != 1) {
- error("%s: EVP_DigestInit_ex", __func__);
- goto out;
- }
- if (EVP_DigestUpdate(&evp_md_ctx, buf, len) != 1) {
- error("%s: EVP_DigestUpdate", __func__);
- goto out;
- }
- if (EVP_DigestFinal_ex(&evp_md_ctx, digest, &digest_len) != 1) {
- error("%s: EVP_DigestFinal_ex", __func__);
- goto out;
- }
- *digestp = xmalloc(digest_len);
- *lenp = digest_len;
- memcpy(*digestp, digest, *lenp);
- success = 0;
- out:
- EVP_MD_CTX_cleanup(&evp_md_ctx);
- bzero(digest, sizeof(digest));
- digest_len = 0;
- return success;
-}
-
-/* print formatted string followed by bignum */
-void
-jpake_debug3_bn(const BIGNUM *n, const char *fmt, ...)
-{
- char *out, *h;
- va_list args;
-
- out = NULL;
- va_start(args, fmt);
- vasprintf(&out, fmt, args);
- va_end(args);
- if (out == NULL)
- fatal("%s: vasprintf failed", __func__);
-
- if (n == NULL)
- debug3("%s(null)", out);
- else {
- h = BN_bn2hex(n);
- debug3("%s0x%s", out, h);
- free(h);
- }
- free(out);
-}
-
-/* print formatted string followed by buffer contents in hex */
-void
-jpake_debug3_buf(const u_char *buf, u_int len, const char *fmt, ...)
-{
- char *out, h[65];
- u_int i, j;
- va_list args;
-
- out = NULL;
- va_start(args, fmt);
- vasprintf(&out, fmt, args);
- va_end(args);
- if (out == NULL)
- fatal("%s: vasprintf failed", __func__);
-
- debug3("%s length %u%s", out, len, buf == NULL ? " (null)" : "");
- free(out);
- if (buf == NULL)
- return;
-
- *h = '\0';
- for (i = j = 0; i < len; i++) {
- snprintf(h + j, sizeof(h) - j, "%02x", buf[i]);
- j += 2;
- if (j >= sizeof(h) - 1 || i == len - 1) {
- debug3(" %s", h);
- *h = '\0';
- j = 0;
- }
- }
+ return modp_group_from_g_and_safe_p(JPAKE_GROUP_G, JPAKE_GROUP_P);
}
struct jpake_ctx *
@@ -241,7 +87,6 @@ jpake_new(void)
return ret;
}
-
void
jpake_free(struct jpake_ctx *pctx)
{
@@ -342,7 +187,7 @@ jpake_dump(struct jpake_ctx *pctx, const char *fmt, ...)
/* Shared parts of step 1 exchange calculation */
void
-jpake_step1(struct jpake_group *grp,
+jpake_step1(struct modp_group *grp,
u_char **id, u_int *id_len,
BIGNUM **priv1, BIGNUM **priv2, BIGNUM **g_priv1, BIGNUM **g_priv2,
u_char **priv1_proof, u_int *priv1_proof_len,
@@ -381,11 +226,11 @@ jpake_step1(struct jpake_group *grp,
fatal("%s: BN_mod_exp", __func__);
/* Generate proofs for holding x1/x3 and x2/x4 */
- if (schnorr_sign(grp->p, grp->q, grp->g,
+ if (schnorr_sign_buf(grp->p, grp->q, grp->g,
*priv1, *g_priv1, *id, *id_len,
priv1_proof, priv1_proof_len) != 0)
fatal("%s: schnorr_sign", __func__);
- if (schnorr_sign(grp->p, grp->q, grp->g,
+ if (schnorr_sign_buf(grp->p, grp->q, grp->g,
*priv2, *g_priv2, *id, *id_len,
priv2_proof, priv2_proof_len) != 0)
fatal("%s: schnorr_sign", __func__);
@@ -395,7 +240,7 @@ jpake_step1(struct jpake_group *grp,
/* Shared parts of step 2 exchange calculation */
void
-jpake_step2(struct jpake_group *grp, BIGNUM *s,
+jpake_step2(struct modp_group *grp, BIGNUM *s,
BIGNUM *mypub1, BIGNUM *theirpub1, BIGNUM *theirpub2, BIGNUM *mypriv2,
const u_char *theirid, u_int theirid_len,
const u_char *myid, u_int myid_len,
@@ -413,10 +258,10 @@ jpake_step2(struct jpake_group *grp, BIGNUM *s,
if (BN_cmp(theirpub2, BN_value_one()) <= 0)
fatal("%s: theirpub2 <= 1", __func__);
- if (schnorr_verify(grp->p, grp->q, grp->g, theirpub1,
+ if (schnorr_verify_buf(grp->p, grp->q, grp->g, theirpub1,
theirid, theirid_len, theirpub1_proof, theirpub1_proof_len) != 1)
fatal("%s: schnorr_verify theirpub1 failed", __func__);
- if (schnorr_verify(grp->p, grp->q, grp->g, theirpub2,
+ if (schnorr_verify_buf(grp->p, grp->q, grp->g, theirpub2,
theirid, theirid_len, theirpub2_proof, theirpub2_proof_len) != 1)
fatal("%s: schnorr_verify theirpub2 failed", __func__);
@@ -457,7 +302,7 @@ jpake_step2(struct jpake_group *grp, BIGNUM *s,
JPAKE_DEBUG_BN((exponent, "%s: exponent = ", __func__));
/* Note the generator here is 'tmp', not g */
- if (schnorr_sign(grp->p, grp->q, tmp, exponent, *newpub,
+ if (schnorr_sign_buf(grp->p, grp->q, tmp, exponent, *newpub,
myid, myid_len,
newpub_exponent_proof, newpub_exponent_proof_len) != 0)
fatal("%s: schnorr_sign newpub", __func__);
@@ -494,7 +339,7 @@ jpake_confirm_hash(const BIGNUM *k,
/* Shared parts of key derivation and confirmation calculation */
void
-jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val,
+jpake_key_confirm(struct modp_group *grp, BIGNUM *s, BIGNUM *step2_val,
BIGNUM *mypriv2, BIGNUM *mypub1, BIGNUM *mypub2,
BIGNUM *theirpub1, BIGNUM *theirpub2,
const u_char *my_id, u_int my_id_len,
@@ -529,7 +374,7 @@ jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val,
JPAKE_DEBUG_BN((tmp, "%s: tmp = ", __func__));
- if (schnorr_verify(grp->p, grp->q, tmp, step2_val,
+ if (schnorr_verify_buf(grp->p, grp->q, tmp, step2_val,
their_id, their_id_len,
theirpriv2_s_proof, theirpriv2_s_proof_len) != 1)
fatal("%s: schnorr_verify theirpriv2_s_proof failed", __func__);
diff --git a/usr.bin/ssh/jpake.h b/usr.bin/ssh/jpake.h
index a3d800cd3c4..a3f2cf0256c 100644
--- a/usr.bin/ssh/jpake.h
+++ b/usr.bin/ssh/jpake.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: jpake.h,v 1.1 2008/11/04 08:22:13 djm Exp $ */
+/* $OpenBSD: jpake.h,v 1.2 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright (c) 2008 Damien Miller. All rights reserved.
*
@@ -28,20 +28,16 @@
# define JPAKE_DEBUG_BUF(a)
# define JPAKE_DEBUG_CTX(a)
#else
-# define JPAKE_DEBUG_BN(a) jpake_debug3_bn a
-# define JPAKE_DEBUG_BUF(a) jpake_debug3_buf a
+# define JPAKE_DEBUG_BN(a) debug3_bn a
+# define JPAKE_DEBUG_BUF(a) debug3_buf a
# define JPAKE_DEBUG_CTX(a) jpake_dump a
-#endif /* SCHNORR_DEBUG */
-
-struct jpake_group {
- BIGNUM *p, *q, *g;
-};
+#endif /* JPAKE_DEBUG */
#define KZP_ID_LEN 16 /* Length of client and server IDs */
struct jpake_ctx {
/* Parameters */
- struct jpake_group *grp;
+ struct modp_group *grp;
/* Private values shared by client and server */
BIGNUM *s; /* Secret (salted, crypted password) */
@@ -83,26 +79,18 @@ struct jpake_ctx {
};
/* jpake.c */
-struct jpake_group *jpake_default_group(void);
-BIGNUM *bn_rand_range_gt_one(const BIGNUM *high);
-int hash_buffer(const u_char *, u_int, const EVP_MD *, u_char **, u_int *);
-void jpake_debug3_bn(const BIGNUM *, const char *, ...)
- __attribute__((__nonnull__ (2)))
- __attribute__((format(printf, 2, 3)));
-void jpake_debug3_buf(const u_char *, u_int, const char *, ...)
- __attribute__((__nonnull__ (3)))
- __attribute__((format(printf, 3, 4)));
+struct modp_group *jpake_default_group(void);
void jpake_dump(struct jpake_ctx *, const char *, ...)
__attribute__((__nonnull__ (2)))
__attribute__((format(printf, 2, 3)));
struct jpake_ctx *jpake_new(void);
void jpake_free(struct jpake_ctx *);
-void jpake_step1(struct jpake_group *, u_char **, u_int *,
+void jpake_step1(struct modp_group *, u_char **, u_int *,
BIGNUM **, BIGNUM **, BIGNUM **, BIGNUM **,
u_char **, u_int *, u_char **, u_int *);
-void jpake_step2(struct jpake_group *, BIGNUM *,
+void jpake_step2(struct modp_group *, BIGNUM *,
BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
const u_char *, u_int, const u_char *, u_int,
const u_char *, u_int, const u_char *, u_int,
@@ -113,7 +101,7 @@ void jpake_confirm_hash(const BIGNUM *,
const u_char *, u_int,
u_char **, u_int *);
-void jpake_key_confirm(struct jpake_group *, BIGNUM *, BIGNUM *,
+void jpake_key_confirm(struct modp_group *, BIGNUM *, BIGNUM *,
BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
const u_char *, u_int, const u_char *, u_int,
const u_char *, u_int, const u_char *, u_int,
@@ -122,13 +110,5 @@ void jpake_key_confirm(struct jpake_group *, BIGNUM *, BIGNUM *,
int jpake_check_confirm(const BIGNUM *, const u_char *, u_int,
const u_char *, u_int, const u_char *, u_int);
-/* schnorr.c */
-int schnorr_sign(const BIGNUM *, const BIGNUM *, const BIGNUM *,
- const BIGNUM *, const BIGNUM *, const u_char *, u_int ,
- u_char **, u_int *);
-int schnorr_verify(const BIGNUM *, const BIGNUM *, const BIGNUM *,
- const BIGNUM *, const u_char *, u_int,
- const u_char *, u_int);
-
#endif /* JPAKE_H */
diff --git a/usr.bin/ssh/monitor_wrap.c b/usr.bin/ssh/monitor_wrap.c
index d9422683f32..055fc9c5b45 100644
--- a/usr.bin/ssh/monitor_wrap.c
+++ b/usr.bin/ssh/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.64 2008/11/04 08:22:13 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.65 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -62,6 +62,7 @@
#include "atomicio.h"
#include "monitor_fdpass.h"
#include "misc.h"
+#include "schnorr.h"
#include "jpake.h"
#include "channels.h"
@@ -1049,7 +1050,7 @@ mm_auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
}
void
-mm_jpake_step1(struct jpake_group *grp,
+mm_jpake_step1(struct modp_group *grp,
u_char **id, u_int *id_len,
BIGNUM **priv1, BIGNUM **priv2, BIGNUM **g_priv1, BIGNUM **g_priv2,
u_char **priv1_proof, u_int *priv1_proof_len,
@@ -1084,7 +1085,7 @@ mm_jpake_step1(struct jpake_group *grp,
}
void
-mm_jpake_step2(struct jpake_group *grp, BIGNUM *s,
+mm_jpake_step2(struct modp_group *grp, BIGNUM *s,
BIGNUM *mypub1, BIGNUM *theirpub1, BIGNUM *theirpub2, BIGNUM *mypriv2,
const u_char *theirid, u_int theirid_len,
const u_char *myid, u_int myid_len,
@@ -1124,7 +1125,7 @@ mm_jpake_step2(struct jpake_group *grp, BIGNUM *s,
}
void
-mm_jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val,
+mm_jpake_key_confirm(struct modp_group *grp, BIGNUM *s, BIGNUM *step2_val,
BIGNUM *mypriv2, BIGNUM *mypub1, BIGNUM *mypub2,
BIGNUM *theirpub1, BIGNUM *theirpub2,
const u_char *my_id, u_int my_id_len,
diff --git a/usr.bin/ssh/monitor_wrap.h b/usr.bin/ssh/monitor_wrap.h
index 677521bcd5e..544a8bf9ba9 100644
--- a/usr.bin/ssh/monitor_wrap.h
+++ b/usr.bin/ssh/monitor_wrap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.h,v 1.21 2008/11/04 08:22:13 djm Exp $ */
+/* $OpenBSD: monitor_wrap.h,v 1.22 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -87,17 +87,17 @@ int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
int mm_skey_respond(void *, u_int, char **);
/* jpake */
-struct jpake_group;
+struct modp_group;
void mm_auth2_jpake_get_pwdata(struct Authctxt *, BIGNUM **, char **, char **);
-void mm_jpake_step1(struct jpake_group *, u_char **, u_int *,
+void mm_jpake_step1(struct modp_group *, u_char **, u_int *,
BIGNUM **, BIGNUM **, BIGNUM **, BIGNUM **,
u_char **, u_int *, u_char **, u_int *);
-void mm_jpake_step2(struct jpake_group *, BIGNUM *,
+void mm_jpake_step2(struct modp_group *, BIGNUM *,
BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
const u_char *, u_int, const u_char *, u_int,
const u_char *, u_int, const u_char *, u_int,
BIGNUM **, u_char **, u_int *);
-void mm_jpake_key_confirm(struct jpake_group *, BIGNUM *, BIGNUM *,
+void mm_jpake_key_confirm(struct modp_group *, BIGNUM *, BIGNUM *,
BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
const u_char *, u_int, const u_char *, u_int,
const u_char *, u_int, const u_char *, u_int,
diff --git a/usr.bin/ssh/schnorr.c b/usr.bin/ssh/schnorr.c
index 1e4543d2da6..c9348f7a0e9 100644
--- a/usr.bin/ssh/schnorr.c
+++ b/usr.bin/ssh/schnorr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: schnorr.c,v 1.2 2009/02/18 04:31:21 djm Exp $ */
+/* $OpenBSD: schnorr.c,v 1.3 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright (c) 2008 Damien Miller. All rights reserved.
*
@@ -38,36 +38,32 @@
#include "buffer.h"
#include "log.h"
-#include "jpake.h"
+#include "schnorr.h"
/* #define SCHNORR_DEBUG */ /* Privacy-violating debugging */
/* #define SCHNORR_MAIN */ /* Include main() selftest */
-/* XXX */
-/* Parametise signature hash? (sha256, sha1, etc.) */
-/* Signature format - include type name, hash type, group params? */
-
#ifndef SCHNORR_DEBUG
# define SCHNORR_DEBUG_BN(a)
# define SCHNORR_DEBUG_BUF(a)
#else
-# define SCHNORR_DEBUG_BN(a) jpake_debug3_bn a
-# define SCHNORR_DEBUG_BUF(a) jpake_debug3_buf a
+# define SCHNORR_DEBUG_BN(a) debug3_bn a
+# define SCHNORR_DEBUG_BUF(a) debug3_buf a
#endif /* SCHNORR_DEBUG */
/*
* Calculate hash component of Schnorr signature H(g || g^v || g^x || id)
- * using SHA1. Returns signature as bignum or NULL on error.
+ * using the hash function defined by "evp_md". Returns signature as
+ * bignum or NULL on error.
*/
static BIGNUM *
schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
- const BIGNUM *g_v, const BIGNUM *g_x,
+ const EVP_MD *evp_md, const BIGNUM *g_v, const BIGNUM *g_x,
const u_char *id, u_int idlen)
{
u_char *digest;
u_int digest_len;
BIGNUM *h;
- EVP_MD_CTX evp_md_ctx;
Buffer b;
int success = -1;
@@ -77,7 +73,6 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
}
buffer_init(&b);
- EVP_MD_CTX_init(&evp_md_ctx);
/* h = H(g || p || q || g^v || g^x || id) */
buffer_put_bignum2(&b, g);
@@ -89,7 +84,7 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
"%s: hashblob", __func__));
- if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(),
+ if (hash_buffer(buffer_ptr(&b), buffer_len(&b), evp_md,
&digest, &digest_len) != 0) {
error("%s: hash_buffer", __func__);
goto out;
@@ -102,7 +97,6 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
SCHNORR_DEBUG_BN((h, "%s: h = ", __func__));
out:
buffer_free(&b);
- EVP_MD_CTX_cleanup(&evp_md_ctx);
bzero(digest, digest_len);
xfree(digest);
digest_len = 0;
@@ -115,18 +109,20 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
/*
* Generate Schnorr signature to prove knowledge of private value 'x' used
* in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g'
+ * using the hash function "evp_md".
* 'idlen' bytes from 'id' will be included in the signature hash as an anti-
* replay salt.
- * On success, 0 is returned and *siglen bytes of signature are returned in
- * *sig (caller to free). Returns -1 on failure.
+ *
+ * On success, 0 is returned. The signature values are returned as *e_p
+ * (g^v mod p) and *r_p (v - xh mod q). The caller must free these values.
+ * On failure, -1 is returned.
*/
int
schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
- const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen,
- u_char **sig, u_int *siglen)
+ const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x,
+ const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p)
{
int success = -1;
- Buffer b;
BIGNUM *h, *tmp, *v, *g_v, *r;
BN_CTX *bn_ctx;
@@ -169,7 +165,7 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__));
/* h = H(g || g^v || g^x || id) */
- if ((h = schnorr_hash(grp_p, grp_q, grp_g, g_v, g_x,
+ if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, g_v, g_x,
id, idlen)) == NULL) {
error("%s: schnorr_hash failed", __func__);
goto out;
@@ -184,12 +180,49 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
error("%s: BN_mod_mul (r = v - tmp)", __func__);
goto out;
}
+ SCHNORR_DEBUG_BN((g_v, "%s: e = ", __func__));
SCHNORR_DEBUG_BN((r, "%s: r = ", __func__));
- /* Signature is (g_v, r) */
+ *e_p = g_v;
+ *r_p = r;
+
+ success = 0;
+ out:
+ BN_CTX_free(bn_ctx);
+ if (h != NULL)
+ BN_clear_free(h);
+ if (v != NULL)
+ BN_clear_free(v);
+ BN_clear_free(tmp);
+
+ return success;
+}
+
+/*
+ * Generate Schnorr signature to prove knowledge of private value 'x' used
+ * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g'
+ * using a SHA256 hash.
+ * 'idlen' bytes from 'id' will be included in the signature hash as an anti-
+ * replay salt.
+ * On success, 0 is returned and *siglen bytes of signature are returned in
+ * *sig (caller to free). Returns -1 on failure.
+ */
+int
+schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+ const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen,
+ u_char **sig, u_int *siglen)
+{
+ Buffer b;
+ BIGNUM *r, *e;
+
+ if (schnorr_sign(grp_p, grp_q, grp_g, EVP_sha256(),
+ x, g_x, id, idlen, &r, &e) != 0)
+ return -1;
+
+ /* Signature is (e, r) */
buffer_init(&b);
/* XXX sigtype-hash as string? */
- buffer_put_bignum2(&b, g_v);
+ buffer_put_bignum2(&b, e);
buffer_put_bignum2(&b, r);
*siglen = buffer_len(&b);
*sig = xmalloc(*siglen);
@@ -197,36 +230,28 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
"%s: sigblob", __func__));
buffer_free(&b);
- success = 0;
- out:
- BN_CTX_free(bn_ctx);
- if (h != NULL)
- BN_clear_free(h);
- if (v != NULL)
- BN_clear_free(v);
+
BN_clear_free(r);
- BN_clear_free(g_v);
- BN_clear_free(tmp);
+ BN_clear_free(e);
- return success;
+ return 0;
}
/*
- * Verify Schnorr signature 'sig' of length 'siglen' against public exponent
- * g_x (g^x) under group defined by 'grp_p', 'grp_q' and 'grp_g'.
+ * Verify Schnorr signature { r (v - xh mod q), e (g^v mod p) } against
+ * public exponent g_x (g^x) under group defined by 'grp_p', 'grp_q' and
+ * 'grp_g' using hash "evp_md".
* Signature hash will be salted with 'idlen' bytes from 'id'.
* Returns -1 on failure, 0 on incorrect signature or 1 on matching signature.
*/
int
schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
- const BIGNUM *g_x, const u_char *id, u_int idlen,
- const u_char *sig, u_int siglen)
+ const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen,
+ const BIGNUM *r, const BIGNUM *e)
{
int success = -1;
- Buffer b;
- BIGNUM *g_v, *h, *r, *g_xh, *g_r, *expected;
+ BIGNUM *h, *g_xh, *g_r, *expected;
BN_CTX *bn_ctx;
- u_int rlen;
SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__));
@@ -236,39 +261,23 @@ schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
return -1;
}
- g_v = h = r = g_xh = g_r = expected = NULL;
+ h = g_xh = g_r = expected = NULL;
if ((bn_ctx = BN_CTX_new()) == NULL) {
error("%s: BN_CTX_new", __func__);
goto out;
}
- if ((g_v = BN_new()) == NULL ||
- (r = BN_new()) == NULL ||
- (g_xh = BN_new()) == NULL ||
+ if ((g_xh = BN_new()) == NULL ||
(g_r = BN_new()) == NULL ||
(expected = BN_new()) == NULL) {
error("%s: BN_new", __func__);
goto out;
}
- /* Extract g^v and r from signature blob */
- buffer_init(&b);
- buffer_append(&b, sig, siglen);
- SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
- "%s: sigblob", __func__));
- buffer_get_bignum2(&b, g_v);
- buffer_get_bignum2(&b, r);
- rlen = buffer_len(&b);
- buffer_free(&b);
- if (rlen != 0) {
- error("%s: remaining bytes in signature %d", __func__, rlen);
- goto out;
- }
- buffer_free(&b);
- SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__));
+ SCHNORR_DEBUG_BN((e, "%s: e = ", __func__));
SCHNORR_DEBUG_BN((r, "%s: r = ", __func__));
/* h = H(g || g^v || g^x || id) */
- if ((h = schnorr_hash(grp_p, grp_q, grp_g, g_v, g_x,
+ if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, e, g_x,
id, idlen)) == NULL) {
error("%s: schnorr_hash failed", __func__);
goto out;
@@ -295,20 +304,248 @@ schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
}
SCHNORR_DEBUG_BN((expected, "%s: expected = ", __func__));
- /* Check g_v == expected */
- success = BN_cmp(expected, g_v) == 0;
+ /* Check e == expected */
+ success = BN_cmp(expected, e) == 0;
out:
BN_CTX_free(bn_ctx);
if (h != NULL)
BN_clear_free(h);
- BN_clear_free(g_v);
- BN_clear_free(r);
BN_clear_free(g_xh);
BN_clear_free(g_r);
BN_clear_free(expected);
return success;
}
+/*
+ * Verify Schnorr signature 'sig' of length 'siglen' against public exponent
+ * g_x (g^x) under group defined by 'grp_p', 'grp_q' and 'grp_g' using a
+ * SHA256 hash.
+ * Signature hash will be salted with 'idlen' bytes from 'id'.
+ * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature.
+ */
+int
+schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q,
+ const BIGNUM *grp_g,
+ const BIGNUM *g_x, const u_char *id, u_int idlen,
+ const u_char *sig, u_int siglen)
+{
+ Buffer b;
+ int ret = -1;
+ u_int rlen;
+ BIGNUM *r, *e;
+
+ e = r = NULL;
+ if ((e = BN_new()) == NULL ||
+ (r = BN_new()) == NULL) {
+ error("%s: BN_new", __func__);
+ goto out;
+ }
+
+ /* Extract g^v and r from signature blob */
+ buffer_init(&b);
+ buffer_append(&b, sig, siglen);
+ SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
+ "%s: sigblob", __func__));
+ buffer_get_bignum2(&b, e);
+ buffer_get_bignum2(&b, r);
+ rlen = buffer_len(&b);
+ buffer_free(&b);
+ if (rlen != 0) {
+ error("%s: remaining bytes in signature %d", __func__, rlen);
+ goto out;
+ }
+
+ ret = schnorr_verify(grp_p, grp_q, grp_g, EVP_sha256(),
+ g_x, id, idlen, r, e);
+ out:
+ BN_clear_free(e);
+ BN_clear_free(r);
+
+ return ret;
+}
+
+/* Helper functions */
+
+/*
+ * Generate uniformly distributed random number in range (1, high).
+ * Return number on success, NULL on failure.
+ */
+BIGNUM *
+bn_rand_range_gt_one(const BIGNUM *high)
+{
+ BIGNUM *r, *tmp;
+ int success = -1;
+
+ if ((tmp = BN_new()) == NULL) {
+ error("%s: BN_new", __func__);
+ return NULL;
+ }
+ if ((r = BN_new()) == NULL) {
+ error("%s: BN_new failed", __func__);
+ goto out;
+ }
+ if (BN_set_word(tmp, 2) != 1) {
+ error("%s: BN_set_word(tmp, 2)", __func__);
+ goto out;
+ }
+ if (BN_sub(tmp, high, tmp) == -1) {
+ error("%s: BN_sub failed (tmp = high - 2)", __func__);
+ goto out;
+ }
+ if (BN_rand_range(r, tmp) == -1) {
+ error("%s: BN_rand_range failed", __func__);
+ goto out;
+ }
+ if (BN_set_word(tmp, 2) != 1) {
+ error("%s: BN_set_word(tmp, 2)", __func__);
+ goto out;
+ }
+ if (BN_add(r, r, tmp) == -1) {
+ error("%s: BN_add failed (r = r + 2)", __func__);
+ goto out;
+ }
+ success = 0;
+ out:
+ BN_clear_free(tmp);
+ if (success == 0)
+ return r;
+ BN_clear_free(r);
+ return NULL;
+}
+
+/*
+ * Hash contents of buffer 'b' with hash 'md'. Returns 0 on success,
+ * with digest via 'digestp' (caller to free) and length via 'lenp'.
+ * Returns -1 on failure.
+ */
+int
+hash_buffer(const u_char *buf, u_int len, const EVP_MD *md,
+ u_char **digestp, u_int *lenp)
+{
+ u_char digest[EVP_MAX_MD_SIZE];
+ u_int digest_len;
+ EVP_MD_CTX evp_md_ctx;
+ int success = -1;
+
+ EVP_MD_CTX_init(&evp_md_ctx);
+
+ if (EVP_DigestInit_ex(&evp_md_ctx, md, NULL) != 1) {
+ error("%s: EVP_DigestInit_ex", __func__);
+ goto out;
+ }
+ if (EVP_DigestUpdate(&evp_md_ctx, buf, len) != 1) {
+ error("%s: EVP_DigestUpdate", __func__);
+ goto out;
+ }
+ if (EVP_DigestFinal_ex(&evp_md_ctx, digest, &digest_len) != 1) {
+ error("%s: EVP_DigestFinal_ex", __func__);
+ goto out;
+ }
+ *digestp = xmalloc(digest_len);
+ *lenp = digest_len;
+ memcpy(*digestp, digest, *lenp);
+ success = 0;
+ out:
+ EVP_MD_CTX_cleanup(&evp_md_ctx);
+ bzero(digest, sizeof(digest));
+ digest_len = 0;
+ return success;
+}
+
+/* print formatted string followed by bignum */
+void
+debug3_bn(const BIGNUM *n, const char *fmt, ...)
+{
+ char *out, *h;
+ va_list args;
+
+ out = NULL;
+ va_start(args, fmt);
+ vasprintf(&out, fmt, args);
+ va_end(args);
+ if (out == NULL)
+ fatal("%s: vasprintf failed", __func__);
+
+ if (n == NULL)
+ debug3("%s(null)", out);
+ else {
+ h = BN_bn2hex(n);
+ debug3("%s0x%s", out, h);
+ free(h);
+ }
+ free(out);
+}
+
+/* print formatted string followed by buffer contents in hex */
+void
+debug3_buf(const u_char *buf, u_int len, const char *fmt, ...)
+{
+ char *out, h[65];
+ u_int i, j;
+ va_list args;
+
+ out = NULL;
+ va_start(args, fmt);
+ vasprintf(&out, fmt, args);
+ va_end(args);
+ if (out == NULL)
+ fatal("%s: vasprintf failed", __func__);
+
+ debug3("%s length %u%s", out, len, buf == NULL ? " (null)" : "");
+ free(out);
+ if (buf == NULL)
+ return;
+
+ *h = '\0';
+ for (i = j = 0; i < len; i++) {
+ snprintf(h + j, sizeof(h) - j, "%02x", buf[i]);
+ j += 2;
+ if (j >= sizeof(h) - 1 || i == len - 1) {
+ debug3(" %s", h);
+ *h = '\0';
+ j = 0;
+ }
+ }
+}
+
+/*
+ * Construct a MODP group from hex strings p (which must be a safe
+ * prime) and g, automatically calculating subgroup q as (p / 2)
+ */
+struct modp_group *
+modp_group_from_g_and_safe_p(const char *grp_g, const char *grp_p)
+{
+ struct modp_group *ret;
+
+ ret = xmalloc(sizeof(*ret));
+ ret->p = ret->q = ret->g = NULL;
+ if (BN_hex2bn(&ret->p, grp_p) == 0 ||
+ BN_hex2bn(&ret->g, grp_g) == 0)
+ fatal("%s: BN_hex2bn", __func__);
+ /* Subgroup order is p/2 (p is a safe prime) */
+ if ((ret->q = BN_new()) == NULL)
+ fatal("%s: BN_new", __func__);
+ if (BN_rshift1(ret->q, ret->p) != 1)
+ fatal("%s: BN_rshift1", __func__);
+
+ return ret;
+}
+
+void
+modp_group_free(struct modp_group *grp)
+{
+ if (grp->g != NULL)
+ BN_clear_free(grp->g);
+ if (grp->p != NULL)
+ BN_clear_free(grp->p);
+ if (grp->q != NULL)
+ BN_clear_free(grp->q);
+ bzero(grp, sizeof(*grp));
+ xfree(grp);
+}
+
+/* main() function for self-test */
+
#ifdef SCHNORR_MAIN
static void
schnorr_selftest_one(const BIGNUM *grp_p, const BIGNUM *grp_q,
@@ -326,16 +563,17 @@ schnorr_selftest_one(const BIGNUM *grp_p, const BIGNUM *grp_q,
if (BN_mod_exp(g_x, grp_g, x, grp_p, bn_ctx) == -1)
fatal("%s: g_x", __func__);
- if (schnorr_sign(grp_p, grp_q, grp_g, x, g_x, "junk", 4, &sig, &siglen))
+ if (schnorr_sign_buf(grp_p, grp_q, grp_g, x, g_x, "junk", 4,
+ &sig, &siglen))
fatal("%s: schnorr_sign", __func__);
- if (schnorr_verify(grp_p, grp_q, grp_g, g_x, "junk", 4,
+ if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4,
sig, siglen) != 1)
fatal("%s: verify fail", __func__);
- if (schnorr_verify(grp_p, grp_q, grp_g, g_x, "JUNK", 4,
+ if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "JUNK", 4,
sig, siglen) != 0)
fatal("%s: verify should have failed (bad ID)", __func__);
sig[4] ^= 1;
- if (schnorr_verify(grp_p, grp_q, grp_g, g_x, "junk", 4,
+ if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4,
sig, siglen) != 0)
fatal("%s: verify should have failed (bit error)", __func__);
xfree(sig);
@@ -347,7 +585,7 @@ static void
schnorr_selftest(void)
{
BIGNUM *x;
- struct jpake_group *grp;
+ struct modp_group *grp;
u_int i;
char *hh;
diff --git a/usr.bin/ssh/schnorr.h b/usr.bin/ssh/schnorr.h
new file mode 100644
index 00000000000..9730b47cef3
--- /dev/null
+++ b/usr.bin/ssh/schnorr.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: schnorr.h,v 1.1 2009/03/05 07:18:19 djm Exp $ */
+/*
+ * Copyright (c) 2009 Damien Miller. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SCHNORR_H
+#define SCHNORR_H
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+
+struct modp_group {
+ BIGNUM *p, *q, *g;
+};
+
+BIGNUM *bn_rand_range_gt_one(const BIGNUM *high);
+int hash_buffer(const u_char *, u_int, const EVP_MD *, u_char **, u_int *);
+void debug3_bn(const BIGNUM *, const char *, ...)
+ __attribute__((__nonnull__ (2)))
+ __attribute__((format(printf, 2, 3)));
+void debug3_buf(const u_char *, u_int, const char *, ...)
+ __attribute__((__nonnull__ (3)))
+ __attribute__((format(printf, 3, 4)));
+struct modp_group *modp_group_from_g_and_safe_p(const char *, const char *);
+void modp_group_free(struct modp_group *);
+
+/* Signature and verification functions */
+int
+schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+ const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x,
+ const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p);
+int
+schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+ const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen,
+ u_char **sig, u_int *siglen);
+int
+schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+ const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen,
+ const BIGNUM *r, const BIGNUM *e);
+int
+schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q,
+ const BIGNUM *grp_g,
+ const BIGNUM *g_x, const u_char *id, u_int idlen,
+ const u_char *sig, u_int siglen);
+
+#endif /* JPAKE_H */
+
diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c
index a3f34cf9a30..5a3c47c60aa 100644
--- a/usr.bin/ssh/sshconnect2.c
+++ b/usr.bin/ssh/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.170 2008/11/04 08:22:13 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.171 2009/03/05 07:18:19 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -62,6 +62,7 @@
#include "msg.h"
#include "pathnames.h"
#include "uidswap.h"
+#include "schnorr.h"
#include "jpake.h"
#ifdef GSSAPI