summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn>2000-12-06 12:25:34 +0000
committercvs2svn <cvs2svn>2000-12-06 12:25:34 +0000
commitf8a5c03cdf952c047f4f76ccb3d2cf12f4704a1b (patch)
tree4146d8b72ff2f0be194b607bffe3101c329096f9
parentd0905a24988257be3458689f8793a86d2b05ecb0 (diff)
parentbac685417a0890642bada45bfaf1e44de9c92beb (diff)
downloadopenssl-new-f8a5c03cdf952c047f4f76ccb3d2cf12f4704a1b.tar.gz
This commit was manufactured by cvs2svn to create branch 'BRANCH_ASN1'.
-rw-r--r--crypto/bn/bn_kron.c182
-rw-r--r--crypto/bn/bn_mod.c296
-rw-r--r--crypto/bn/bn_mont2.c349
-rw-r--r--crypto/bn/bn_mont2.h36
-rw-r--r--crypto/bn/bn_sqrt.c382
-rw-r--r--crypto/ec/ec.c120
-rw-r--r--crypto/ec/ec.h86
-rw-r--r--crypto/ec/ec_point.c1477
-rw-r--r--crypto/ocsp/.cvsignore2
-rw-r--r--crypto/ocsp/Makefile.ssl236
-rw-r--r--crypto/ocsp/ocsp.h595
-rw-r--r--crypto/ocsp/ocsp_ext.c349
-rw-r--r--crypto/rijndael/.cvsignore2
-rwxr-xr-xcrypto/rijndael/rd_fst.c476
-rwxr-xr-xcrypto/rijndael/rd_fst.h46
-rw-r--r--demos/tunala/.cvsignore2
-rw-r--r--demos/tunala/Makefile41
-rw-r--r--demos/tunala/buffer.c181
-rw-r--r--demos/tunala/cb.c133
-rw-r--r--demos/tunala/sm.c151
-rw-r--r--demos/tunala/tunala.c885
-rw-r--r--demos/tunala/tunala.h154
-rw-r--r--doc/HOWTO/certificates.txt85
-rw-r--r--doc/crypto/BN_swap.pod23
-rw-r--r--ssl/kssl.c1040
-rw-r--r--ssl/kssl.h162
26 files changed, 7491 insertions, 0 deletions
diff --git a/crypto/bn/bn_kron.c b/crypto/bn/bn_kron.c
new file mode 100644
index 0000000000..49f75594ae
--- /dev/null
+++ b/crypto/bn/bn_kron.c
@@ -0,0 +1,182 @@
+/* crypto/bn/bn_kron.c */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "bn_lcl.h"
+
+
+/* least significant word */
+#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
+
+/* Returns -2 for errors because both -1 and 0 are valid results. */
+int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
+ {
+ int i;
+ int ret = -2; /* avoid 'uninitialized' warning */
+ int err = 0;
+ BIGNUM *A, *B, *tmp;
+ /* In 'tab', only odd-indexed entries are relevant:
+ * For any odd BIGNUM n,
+ * tab[BN_lsw(n) & 7]
+ * is $(-1)^{(n^2-1)/8}$ (using TeX notation).
+ * Note that the sign of n does not matter.
+ */
+ static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1};
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ B = BN_CTX_get(ctx);
+ if (B == NULL) goto end;
+
+ err = !BN_copy(A, a);
+ if (err) goto end;
+ err = !BN_copy(B, b);
+ if (err) goto end;
+
+ /*
+ * Kronecker symbol, imlemented according to Henri Cohen,
+ * "A Course in Computational Algebraic Number Theory"
+ * (algorithm 1.4.10).
+ */
+
+ /* Cohen's step 1: */
+
+ if (BN_is_zero(B))
+ {
+ ret = BN_abs_is_word(A, 1);
+ goto end;
+ }
+
+ /* Cohen's step 2: */
+
+ if (!BN_is_odd(A) && !BN_is_odd(B))
+ {
+ ret = 0;
+ goto end;
+ }
+
+ /* now B is non-zero */
+ i = 0;
+ while (!BN_is_bit_set(B, i))
+ i++;
+ err = !BN_rshift(B, B, i);
+ if (err) goto end;
+ if (i & 1)
+ {
+ /* i is odd */
+ /* (thus B was even, thus A must be odd!) */
+
+ /* set 'ret' to $(-1)^{(A^2-1)/8}$ */
+ ret = tab[BN_lsw(A) & 7];
+ }
+ else
+ {
+ /* i is even */
+ ret = 1;
+ }
+
+ if (B->neg)
+ {
+ B->neg = 0;
+ if (A->neg)
+ ret = -ret;
+ }
+
+ /* now B is positive and odd, so what remains to be done is
+ * to compute the Jacobi symbol (A/B) and multiply it by 'ret' */
+
+ while (1)
+ {
+ /* Cohen's step 3: */
+
+ /* B is positive and odd */
+
+ if (BN_is_zero(A))
+ {
+ ret = BN_is_one(B) ? ret : 0;
+ goto end;
+ }
+
+ /* now A is non-zero */
+ i = 0;
+ while (!BN_is_bit_set(A, i))
+ i++;
+ err = !BN_rshift(A, A, i);
+ if (err) goto end;
+ if (i & 1)
+ {
+ /* i is odd */
+ /* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */
+ ret = ret * tab[BN_lsw(B) & 7];
+ }
+
+ /* Cohen's step 4: */
+ /* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */
+ if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2)
+ ret = -ret;
+
+ /* (A, B) := (B mod |A|, |A|) */
+ err = !BN_nnmod(B, B, A, ctx);
+ if (err) goto end;
+ tmp = A; A = B; B = tmp;
+ tmp->neg = 0;
+ }
+
+ end:
+ BN_CTX_end(ctx);
+ if (err)
+ return -2;
+ else
+ return ret;
+ }
diff --git a/crypto/bn/bn_mod.c b/crypto/bn/bn_mod.c
new file mode 100644
index 0000000000..92fe11684c
--- /dev/null
+++ b/crypto/bn/bn_mod.c
@@ -0,0 +1,296 @@
+/* crypto/bn/bn_mod.c */
+/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
+ * for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "cryptlib.h"
+#include "bn_lcl.h"
+
+
+#if 0 /* now just a #define */
+int BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
+ {
+ return(BN_div(NULL,rem,m,d,ctx));
+ /* note that rem->neg == m->neg (unless the remainder is zero) */
+ }
+#endif
+
+
+int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
+ {
+ /* like BN_mod, but returns non-negative remainder
+ * (i.e., 0 <= r < |d| always holds) */
+
+ if (!(BN_mod(r,m,d,ctx)))
+ return 0;
+ if (!r->neg)
+ return 1;
+ /* now -|d| < r < 0, so we have to set r := r + |d| */
+ return (d->neg ? BN_sub : BN_add)(r, r, d);
+}
+
+
+int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
+ {
+ if (!BN_add(r, a, b)) return 0;
+ return BN_nnmod(r, r, m, ctx);
+ }
+
+
+/* BN_mod_add variant that may be used if both a and b are non-negative
+ * and less than m */
+int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m)
+ {
+ if (!BN_add(r, a, b)) return 0;
+ if (BN_cmp(r, m) >= 0)
+ return BN_sub(r, r, m);
+ return 1;
+ }
+
+
+int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
+ {
+ if (!BN_sub(r, a, b)) return 0;
+ return BN_nnmod(r, r, m, ctx);
+ }
+
+
+/* BN_mod_sub variant that may be used if both a and b are non-negative
+ * and less than m */
+int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m)
+ {
+ if (!BN_sub(r, a, b)) return 0;
+ if (r->neg)
+ return BN_add(r, r, m);
+ return 1;
+ }
+
+
+/* slow but works */
+int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx)
+ {
+ BIGNUM *t;
+ int ret=0;
+
+ bn_check_top(a);
+ bn_check_top(b);
+ bn_check_top(m);
+
+ BN_CTX_start(ctx);
+ if ((t = BN_CTX_get(ctx)) == NULL) goto err;
+ if (a == b)
+ { if (!BN_sqr(t,a,ctx)) goto err; }
+ else
+ { if (!BN_mul(t,a,b,ctx)) goto err; }
+ if (!BN_nnmod(r,t,m,ctx)) goto err;
+ ret=1;
+err:
+ BN_CTX_end(ctx);
+ return(ret);
+ }
+
+
+int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
+ {
+ if (!BN_sqr(r, a, ctx)) return 0;
+ /* r->neg == 0, thus we don't need BN_nnmod */
+ return BN_mod(r, r, m, ctx);
+ }
+
+
+int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
+ {
+ if (!BN_lshift1(r, a)) return 0;
+ return BN_nnmod(r, r, m, ctx);
+ }
+
+
+/* BN_mod_lshift1 variant that may be used if a is non-negative
+ * and less than m */
+int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m)
+ {
+ if (!BN_lshift1(r, a)) return 0;
+ if (BN_cmp(r, m) >= 0)
+ return BN_sub(r, r, m);
+ return 1;
+ }
+
+
+int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, BN_CTX *ctx)
+ {
+ BIGNUM *abs_m = NULL;
+ int ret;
+
+ if (!BN_nnmod(r, a, m, ctx)) return 0;
+
+ if (m->neg)
+ {
+ abs_m = BN_dup(m);
+ if (abs_m == NULL) return 0;
+ abs_m->neg = 0;
+ }
+
+ ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
+
+ if (abs_m)
+ BN_free(abs_m);
+ return ret;
+ }
+
+
+/* BN_mod_lshift variant that may be used if a is non-negative
+ * and less than m */
+int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m)
+ {
+ if (r != a)
+ {
+ if (BN_copy(r, a) == NULL) return 0;
+ }
+
+ while (n > 0)
+ {
+ int max_shift;
+
+ /* 0 < r < m */
+ max_shift = BN_num_bits(m) - BN_num_bits(r);
+ /* max_shift >= 0 */
+
+ if (max_shift < 0)
+ {
+ BNerr(BN_F_BN_MOD_LSHIFT_QUICK, BN_R_INPUT_NOT_REDUCED);
+ return 0;
+ }
+
+ if (max_shift > n)
+ max_shift = n;
+
+ if (max_shift)
+ {
+ if (!BN_lshift(r, r, max_shift)) return 0;
+ n -= max_shift;
+ }
+ else
+ {
+ if (!BN_lshift1(r, r)) return 0;
+ --n;
+ }
+
+ /* BN_num_bits(r) <= BN_num_bits(m) */
+
+ if (BN_cmp(r, m) >= 0)
+ {
+ if (!BN_sub(r, r, m)) return 0;
+ }
+ }
+
+ return 1;
+ }
diff --git a/crypto/bn/bn_mont2.c b/crypto/bn/bn_mont2.c
new file mode 100644
index 0000000000..367eb09c5e
--- /dev/null
+++ b/crypto/bn/bn_mont2.c
@@ -0,0 +1,349 @@
+/*
+ *
+ * bn_mont2.c
+ *
+ * Montgomery Modular Arithmetic Functions.
+ *
+ * Copyright (C) Lenka Fibikova 2000
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "bn_lcl.h"
+#include "bn_mont2.h"
+
+#define BN_mask_word(x, m) ((x->d[0]) & (m))
+
+BN_MONTGOMERY *BN_mont_new()
+ {
+ BN_MONTGOMERY *ret;
+
+ ret=(BN_MONTGOMERY *)malloc(sizeof(BN_MONTGOMERY));
+
+ if (ret == NULL) return NULL;
+
+ if ((ret->p = BN_new()) == NULL)
+ {
+ free(ret);
+ return NULL;
+ }
+
+ return ret;
+ }
+
+
+void BN_mont_clear_free(BN_MONTGOMERY *mont)
+ {
+ if (mont == NULL) return;
+
+ if (mont->p != NULL) BN_clear_free(mont->p);
+
+ mont->p_num_bytes = 0;
+ mont->R_num_bits = 0;
+ mont->p_inv_b_neg = 0;
+ }
+
+
+int BN_to_mont(BIGNUM *x, BN_MONTGOMERY *mont, BN_CTX *ctx)
+ {
+ assert(x != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (!BN_lshift(x, x, mont->R_num_bits)) return 0;
+ if (!BN_mod(x, x, mont->p, ctx)) return 0;
+
+ return 1;
+ }
+
+
+static BN_ULONG BN_mont_inv(BIGNUM *a, int e, BN_CTX *ctx)
+/* y = a^{-1} (mod 2^e) for an odd number a */
+ {
+ BN_ULONG y, exp, mask;
+ BIGNUM *x, *xy, *x_sh;
+ int i;
+
+ assert(a != NULL && ctx != NULL);
+ assert(e <= BN_BITS2);
+ assert(BN_is_odd(a));
+ assert(!BN_is_zero(a) && !a->neg);
+
+
+ y = 1;
+ exp = 2;
+ mask = 3;
+ if((x = BN_dup(a)) == NULL) return 0;
+ if(!BN_mask_bits(x, e)) return 0;
+
+ BN_CTX_start(ctx);
+ xy = BN_CTX_get(ctx);
+ x_sh = BN_CTX_get(ctx);
+ if (x_sh == NULL) goto err;
+
+ if (BN_copy(xy, x) == NULL) goto err;
+ if (!BN_lshift1(x_sh, x)) goto err;
+
+
+ for (i = 2; i <= e; i++)
+ {
+ if (exp < BN_mask_word(xy, mask))
+ {
+ y = y + exp;
+ if (!BN_add(xy, xy, x_sh)) goto err;
+ }
+
+ exp <<= 1;
+ if (!BN_lshift1(x_sh, x_sh)) goto err;
+ mask <<= 1;
+ mask++;
+ }
+
+
+#ifdef TEST
+ if (xy->d[0] != 1) goto err;
+#endif
+
+ if (x != NULL) BN_clear_free(x);
+ BN_CTX_end(ctx);
+ return y;
+
+
+err:
+ if (x != NULL) BN_clear_free(x);
+ BN_CTX_end(ctx);
+ return 0;
+ }
+
+
+int BN_mont_set(BIGNUM *p, BN_MONTGOMERY *mont, BN_CTX *ctx)
+ {
+ assert(p != NULL && ctx != NULL);
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+ assert(!BN_is_zero(p) && !p->neg);
+
+
+ mont->p_num_bytes = p->top;
+ mont->R_num_bits = (mont->p_num_bytes) * BN_BITS2;
+
+ if (BN_copy(mont->p, p) == NULL);
+
+ mont->p_inv_b_neg = BN_mont_inv(p, BN_BITS2, ctx);
+ mont->p_inv_b_neg = 0 - mont->p_inv_b_neg;
+
+ return 1;
+ }
+
+
+#ifdef BN_LLONG
+#define cpy_mul_add(r, b, a, w, c) { \
+ BN_ULLONG t; \
+ t = (BN_ULLONG)w * (a) + (b) + (c); \
+ (r)= Lw(t); \
+ (c)= Hw(t); \
+ }
+
+BN_ULONG BN_mul_add_rshift(BN_ULONG *r, BN_ULONG *a, int num, BN_ULONG w)
+/* r = (r + a * w) >> BN_BITS2 */
+ {
+ BN_ULONG c = 0;
+
+ mul_add(r[0], a[0], w, c);
+ if (--num == 0) return c;
+ a++;
+
+ for (;;)
+ {
+ cpy_mul_add(r[0], r[1], a[0], w, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[1], r[2], a[1], w, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[2], r[3], a[2], w, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[3], r[4], a[3], w, c);
+ if (--num == 0) break;
+ a += 4;
+ r += 4;
+ }
+
+ return c;
+ }
+#else
+
+#define cpy_mul_add(r, b, a, bl, bh, c) { \
+ BN_ULONG l,h; \
+ \
+ h=(a); \
+ l=LBITS(h); \
+ h=HBITS(h); \
+ mul64(l,h,(bl),(bh)); \
+ \
+ /* non-multiply part */ \
+ l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
+ (c)=(b); \
+ l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
+ (c)=h&BN_MASK2; \
+ (r)=l; \
+ }
+
+static BN_ULONG BN_mul_add_rshift(BN_ULONG *r, BN_ULONG *a, int num, BN_ULONG w)
+/* ret = (ret + a * w) << shift * BN_BITS2 */
+ {
+ BN_ULONG c = 0;
+ BN_ULONG bl, bh;
+
+ bl = LBITS(w);
+ bh = HBITS(w);
+
+ mul_add(r[0], a[0], bl, bh, c);
+ if (--num == 0) return c;
+ a++;
+
+ for (;;)
+ {
+ cpy_mul_add(r[0], r[1], a[0], bl, bh, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[1], r[2], a[1], bl, bh, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[2], r[3], a[2], bl, bh, c);
+ if (--num == 0) break;
+ cpy_mul_add(r[3], r[4], a[3], bl, bh, c);
+ if (--num == 0) break;
+ a += 4;
+ r += 4;
+ }
+ return c;
+ }
+#endif /* BN_LLONG */
+
+
+
+int BN_mont_red(BIGNUM *y, BN_MONTGOMERY *mont)
+/* yR^{-1} (mod p) */
+ {
+ BIGNUM *p;
+ BN_ULONG c;
+ int i, max;
+
+ assert(y != NULL && mont != NULL);
+ assert(mont->p != NULL);
+ assert(BN_cmp(y, mont->p) < 0);
+ assert(!y->neg);
+
+
+ if (BN_is_zero(y)) return 1;
+
+ p = mont->p;
+ max = mont->p_num_bytes;
+
+ if (bn_wexpand(y, max) == NULL) return 0;
+ for (i = y->top; i < max; i++) y->d[i] = 0;
+ y->top = max;
+
+ /* r = [r + (y_0 * p') * p] / b */
+ for (i = 0; i < max; i++)
+ {
+ c = BN_mul_add_rshift(y->d, p->d, max, ((y->d[0]) * mont->p_inv_b_neg) & BN_MASK2);
+ y->d[max - 1] = c;
+ }
+
+ while (y->d[y->top - 1] == 0) y->top--;
+
+ if (BN_cmp(y, p) >= 0)
+ {
+ if (!BN_sub(y, y, p)) return 0;
+ }
+
+ return 1;
+ }
+
+
+int BN_mont_mod_mul(BIGNUM *r, BIGNUM *x, BIGNUM *y, BN_MONTGOMERY *mont)
+/* r = x * y mod p */
+/* r != x && r! = y !!! */
+ {
+ BN_ULONG c;
+ BIGNUM *p;
+ int i, j, max;
+
+ assert(r != x && r != y);
+ assert(r != NULL && x != NULL && y != NULL && mont != NULL);
+ assert(mont->p != NULL);
+ assert(BN_cmp(x, mont->p) < 0);
+ assert(BN_cmp(y, mont->p) < 0);
+ assert(!x->neg);
+ assert(!y->neg);
+
+ if (BN_is_zero(x) || BN_is_zero(y))
+ {
+ if (!BN_zero(r)) return 0;
+ return 1;
+ }
+
+ p = mont->p;
+ max = mont->p_num_bytes;
+
+ /* for multiplication we need at most max + 2 words
+ the last one --- max + 3 --- is only as a backstop
+ for incorrect input
+ */
+ if (bn_wexpand(r, max + 3) == NULL) return 0;
+ for (i = 0; i < max + 3; i++) r->d[i] = 0;
+ r->top = max + 2;
+
+ for (i = 0; i < x->top; i++)
+ {
+ /* r = r + (r_0 + x_i * y_0) * p' * p */
+ c = bn_mul_add_words(r->d, p->d, max, \
+ ((r->d[0] + x->d[i] * y->d[0]) * mont->p_inv_b_neg) & BN_MASK2);
+ if (c)
+ {
+ if (((r->d[max] += c) & BN_MASK2) < c)
+ if (((r->d[max + 1] ++) & BN_MASK2) == 0) return 0;
+ }
+
+ /* r = (r + x_i * y) / b */
+ c = BN_mul_add_rshift(r->d, y->d, y->top, x->d[i]);
+ for(j = y->top; j <= max + 1; j++) r->d[j - 1] = r->d[j];
+ if (c)
+ {
+ if (((r->d[y->top - 1] += c) & BN_MASK2) < c)
+ {
+ j = y->top;
+ while (((++ (r->d[j]) ) & BN_MASK2) == 0)
+ j++;
+ if (j > max) return 0;
+ }
+ }
+ r->d[max + 1] = 0;
+ }
+
+ for (i = x->top; i < max; i++)
+ {
+ /* r = (r + r_0 * p' * p) / b */
+ c = BN_mul_add_rshift(r->d, p->d, max, ((r->d[0]) * mont->p_inv_b_neg) & BN_MASK2);
+ j = max - 1;
+ r->d[j] = c + r->d[max];
+ if (r->d[j++] < c) r->d[j] = r->d[++j] + 1;
+ else r->d[j] = r->d[++j];
+ r->d[max + 1] = 0;
+ }
+
+ while (r->d[r->top - 1] == 0) r->top--;
+
+ if (BN_cmp(r, mont->p) >= 0)
+ {
+ if (!BN_sub(r, r, mont->p)) return 0;
+ }
+
+ return 1;
+ }
diff --git a/crypto/bn/bn_mont2.h b/crypto/bn/bn_mont2.h
new file mode 100644
index 0000000000..cb42d67ad1
--- /dev/null
+++ b/crypto/bn/bn_mont2.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * bn_mont2.h
+ *
+ * Montgomery Modular Arithmetic Functions.
+ *
+ * Copyright (C) Lenka Fibikova 2000
+ *
+ *
+ */
+
+#ifndef HEADER_MONT2_H
+#define HEADER_MONT2_H
+
+#define MONTGOMERY
+
+#include <openssl/bn.h>
+
+typedef struct bn_mont_st{
+ int R_num_bits;
+ int p_num_bytes;
+ BIGNUM *p;
+ BN_ULONG p_inv_b_neg; /* p' = p^{-1} mod b; b = 2^BN_BITS */
+} BN_MONTGOMERY;
+
+#define BN_from_mont(x, mont) (BN_mont_red((x), (mont)))
+
+
+BN_MONTGOMERY *BN_mont_new();
+int BN_to_mont(BIGNUM *x, BN_MONTGOMERY *mont, BN_CTX *ctx);
+void BN_mont_clear_free(BN_MONTGOMERY *mont);
+int BN_mont_set(BIGNUM *p, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int BN_mont_red(BIGNUM *y, BN_MONTGOMERY *mont);
+int BN_mont_mod_mul(BIGNUM *r, BIGNUM *x, BIGNUM *y, BN_MONTGOMERY *mont);
+
+#endif
diff --git a/crypto/bn/bn_sqrt.c b/crypto/bn/bn_sqrt.c
new file mode 100644
index 0000000000..a54d9d2919
--- /dev/null
+++ b/crypto/bn/bn_sqrt.c
@@ -0,0 +1,382 @@
+/* crypto/bn/bn_mod.c */
+/* Written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
+ * and Bodo Moeller for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "cryptlib.h"
+#include "bn_lcl.h"
+
+
+BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
+/* Returns 'ret' such that
+ * ret^2 == a (mod p),
+ * using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course
+ * in Algebraic Computational Number Theory", algorithm 1.5.1).
+ * 'p' must be prime!
+ */
+ {
+ BIGNUM *ret = in;
+ int err = 1;
+ int r;
+ BIGNUM *b, *q, *t, *x, *y;
+ int e, i, j;
+
+ if (!BN_is_odd(p) || BN_abs_is_word(p, 1))
+ {
+ if (BN_abs_is_word(p, 2))
+ {
+ if (ret == NULL)
+ ret = BN_new();
+ if (ret == NULL)
+ goto end;
+ if (!BN_set_word(ret, BN_is_bit_set(a, 0)))
+ {
+ BN_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
+ return(NULL);
+ }
+
+ if (BN_is_zero(a) || BN_is_one(a))
+ {
+ if (ret == NULL)
+ ret = BN_new();
+ if (ret == NULL)
+ goto end;
+ if (!BN_set_word(ret, BN_is_one(a)))
+ {
+ BN_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+#if 0 /* if BN_mod_sqrt is used with correct input, this just wastes time */
+ r = BN_kronecker(a, p, ctx);
+ if (r < -1) return NULL;
+ if (r == -1)
+ {
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_NOT_A_SQUARE);
+ return(NULL);
+ }
+#endif
+
+ BN_CTX_start(ctx);
+ b = BN_CTX_get(ctx);
+ q = BN_CTX_get(ctx);
+ t = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) goto end;
+
+ if (ret == NULL)
+ ret = BN_new();
+ if (ret == NULL) goto end;
+
+ /* now write |p| - 1 as 2^e*q where q is odd */
+ e = 1;
+ while (!BN_is_bit_set(p, e))
+ e++;
+ if (e > 2)
+ /* we don't need this q if e = 1 or 2 */
+ if (!BN_rshift(q, p, e)) goto end;
+ q->neg = 0;
+
+ if (e == 1)
+ {
+ /* The easy case: (p-1)/2 is odd, so 2 has an inverse
+ * modulo (p-1)/2, and square roots can be computed
+ * directly by modular exponentiation.
+ * We have
+ * 2 * (p+1)/4 == 1 (mod (p-1)/2),
+ * so we can use exponent (p+1)/4, i.e. (p-3)/4 + 1.
+ */
+ if (!BN_rshift(q, p, 2)) goto end;
+ if (!BN_add_word(q, 1)) goto end;
+ if (!BN_mod_exp(ret, a, q, p, ctx)) goto end;
+ err = 0;
+ goto end;
+ }
+
+ if (e == 2)
+ {
+ /* p == 5 (mod 8)
+ *
+ * In this case 2 is always a non-square since
+ * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime.
+ * So if a really is a square, then 2*a is a non-square.
+ * Thus for
+ * b := (2*a)^((p-5)/8),
+ * i := (2*a)*b^2
+ * we have
+ * i^2 = (2*a)^((1 + (p-5)/4)*2)
+ * = (2*a)^((p-1)/2)
+ * = -1;
+ * so if we set
+ * x := a*b*(i-1),
+ * then
+ * x^2 = a^2 * b^2 * (i^2 - 2*i + 1)
+ * = a^2 * b^2 * (-2*i)
+ * = a*(-i)*(2*a*b^2)
+ * = a*(-i)*i
+ * = a.
+ *
+ * (This is due to A.O.L. Atkin,
+ * <URL: http://listserv.nodak.edu/scripts/wa.exe?A2=ind9211&L=nmbrthry&O=T&P=562>,
+ * November 1992.)
+ */
+
+ /* make sure that a is reduced modulo p */
+ if (a->neg || BN_ucmp(a, p) >= 0)
+ {
+ if (!BN_nnmod(x, a, p, ctx)) goto end;
+ a = x; /* use x as temporary variable */
+ }
+
+ /* t := 2*a */
+ if (!BN_mod_lshift1_quick(t, a, p)) goto end;
+
+ /* b := (2*a)^((p-5)/8) */
+ if (!BN_rshift(q, p, 3)) goto end;
+ if (!BN_mod_exp(b, t, q, p, ctx)) goto end;
+
+ /* y := b^2 */
+ if (!BN_mod_sqr(y, b, p, ctx)) goto end;
+
+ /* t := (2*a)*b^2 - 1*/
+ if (!BN_mod_mul(t, t, y, p, ctx)) goto end;
+ if (!BN_sub_word(t, 1)) goto end; /* cannot become negative */
+
+ /* x = a*b*t */
+ if (!BN_mod_mul(x, a, b, p, ctx)) goto end;
+ if (!BN_mod_mul(x, x, t, p, ctx)) goto end;
+
+ if (!BN_copy(ret, x)) goto end;
+ err = 0;
+ goto end;
+ }
+
+ /* e > 2, so we really have to use the Tonelli/Shanks algorithm.
+ * First, find some y that is not a square. */
+ i = 2;
+ do
+ {
+ /* For efficiency, try small numbers first;
+ * if this fails, try random numbers.
+ */
+ if (i < 22)
+ {
+ if (!BN_set_word(y, i)) goto end;
+ }
+ else
+ {
+ if (!BN_pseudo_rand(y, BN_num_bits(p), 0, 0)) goto end;
+ if (BN_ucmp(y, p) >= 0)
+ {
+ if (!(p->neg ? BN_add : BN_sub)(y, y, p)) goto end;
+ }
+ /* now 0 <= y < |p| */
+ if (BN_is_zero(y))
+ if (!BN_set_word(y, i)) goto end;
+ }
+
+ r = BN_kronecker(y, p, ctx);
+ if (r < -1) goto end;
+ if (r == 0)
+ {
+ /* m divides p */
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
+ goto end;
+ }
+ }
+ while (r == 1 && ++i < 82);
+
+ if (r != -1)
+ {
+ /* Many rounds and still no non-square -- this is more likely
+ * a bug than just bad luck.
+ * Even if p is not prime, we should have found some y
+ * such that r == -1.
+ */
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_TOO_MANY_ITERATIONS);
+ goto end;
+ }
+
+
+ /* Now that we have some non-square, we can find an element
+ * of order 2^e by computing its q'th power. */
+ if (!BN_mod_exp(y, y, q, p, ctx)) goto end;
+ if (BN_is_one(y))
+ {
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
+ goto end;
+ }
+
+ /* Now we know that (if p is indeed prime) there is an integer
+ * k, 0 <= k < 2^e, such that
+ *
+ * a^q * y^k == 1 (mod p).
+ *
+ * As a^q is a square and y is not, k must be even.
+ * q+1 is even, too, so there is an element
+ *
+ * X := a^((q+1)/2) * y^(k/2),
+ *
+ * and it satisfies
+ *
+ * X^2 = a^q * a * y^k
+ * = a,
+ *
+ * so it is the square root that we are looking for.
+ */
+
+ /* t := (q-1)/2 (note that q is odd) */
+ if (!BN_rshift1(t, q)) goto end;
+
+ /* x := a^((q-1)/2) */
+ if (BN_is_zero(t)) /* special case: p = 2^e + 1 */
+ {
+ if (!BN_nnmod(t, a, p, ctx)) goto end;
+ if (BN_is_zero(t))
+ {
+ /* special case: a == 0 (mod p) */
+ if (!BN_zero(ret)) goto end;
+ err = 0;
+ goto end;
+ }
+ else
+ if (!BN_one(x)) goto end;
+ }
+ else
+ {
+ if (!BN_mod_exp(x, a, t, p, ctx)) goto end;
+ if (BN_is_zero(x))
+ {
+ /* special case: a == 0 (mod p) */
+ if (!BN_zero(ret)) goto end;
+ err = 0;
+ goto end;
+ }
+ }
+
+ /* b := a*x^2 (= a^q) */
+ if (!BN_mod_sqr(b, x, p, ctx)) goto end;
+ if (!BN_mod_mul(b, b, a, p, ctx)) goto end;
+
+ /* x := a*x (= a^((q+1)/2)) */
+ if (!BN_mod_mul(x, x, a, p, ctx)) goto end;
+
+ while (1)
+ {
+ /* Now b is a^q * y^k for some even k (0 <= k < 2^E
+ * where E refers to the original value of e, which we
+ * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2).
+ *
+ * We have a*b = x^2,
+ * y^2^(e-1) = -1,
+ * b^2^(e-1) = 1.
+ */
+
+ if (BN_is_one(b))
+ {
+ if (!BN_copy(ret, x)) goto end;
+ err = 0;
+ goto end;
+ }
+
+
+ /* find smallest i such that b^(2^i) = 1 */
+ i = 1;
+ if (!BN_mod_sqr(t, b, p, ctx)) goto end;
+ while (!BN_is_one(t))
+ {
+ i++;
+ if (i == e)
+ {
+ BNerr(BN_F_BN_MOD_SQRT, BN_R_NOT_A_SQUARE);
+ goto end;
+ }
+ if (!BN_mod_mul(t, t, t, p, ctx)) goto end;
+ }
+
+
+ /* t := y^2^(e - i - 1) */
+ if (!BN_copy(t, y)) goto end;
+ for (j = e - i - 1; j > 0; j--)
+ {
+ if (!BN_mod_sqr(t, t, p, ctx)) goto end;
+ }
+ if (!BN_mod_mul(y, t, t, p, ctx)) goto end;
+ if (!BN_mod_mul(x, x, t, p, ctx)) goto end;
+ if (!BN_mod_mul(b, b, y, p, ctx)) goto end;
+ e = i;
+ }
+
+ end:
+ if (err)
+ {
+ if (ret != NULL && ret != in)
+ {
+ BN_clear_free(ret);
+ }
+ ret = NULL;
+ }
+ BN_CTX_end(ctx);
+ return ret;
+ }
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
new file mode 100644
index 0000000000..df54b47c0b
--- /dev/null
+++ b/crypto/ec/ec.c
@@ -0,0 +1,120 @@
+/*
+ *
+ * ec.c
+ *
+ * Elliptic Curve Arithmetic Functions
+ *
+ * Copyright (C) Lenka Fibikova 2000
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "ec.h"
+
+
+
+EC *EC_new()
+{
+ EC *ret;
+
+ ret=(EC *)malloc(sizeof(EC));
+ if (ret == NULL) return NULL;
+ ret->A = BN_new();
+ ret->B = BN_new();
+ ret->p = BN_new();
+ ret->h = BN_new();
+ ret->is_in_mont = 0;
+
+ if (ret->A == NULL || ret->B == NULL || ret->p == NULL || ret->h == NULL)
+ {
+ if (ret->A != NULL) BN_free(ret->A);
+ if (ret->B != NULL) BN_free(ret->B);
+ if (ret->p != NULL) BN_free(ret->p);
+ if (ret->h != NULL) BN_free(ret->h);
+ free(ret);
+ return(NULL);
+ }
+ return(ret);
+}
+
+
+void EC_clear_free(EC *E)
+{
+ if (E == NULL) return;
+
+ if (E->A != NULL) BN_clear_free(E->A);
+ if (E->B != NULL) BN_clear_free(E->B);
+ if (E->p != NULL) BN_clear_free(E->p);
+ if (E->h != NULL) BN_clear_free(E->h);
+ E->is_in_mont = 0;
+ free(E);
+}
+
+
+#ifdef MONTGOMERY
+int EC_to_montgomery(EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+{
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (E->is_in_mont) return 1;
+
+ if (!BN_lshift(E->A, E->A, mont->R_num_bits)) return 0;
+ if (!BN_mod(E->A, E->A, mont->p, ctx)) return 0;
+
+ if (!BN_lshift(E->B, E->B, mont->R_num_bits)) return 0;
+ if (!BN_mod(E->B, E->B, mont->p, ctx)) return 0;
+
+ if (!BN_lshift(E->h, E->h, mont->R_num_bits)) return 0;
+ if (!BN_mod(E->h, E->h, mont->p, ctx)) return 0;
+
+ E->is_in_mont = 1;
+ return 1;
+
+}
+
+
+int EC_from_montgomery(EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+{
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (!E->is_in_mont) return 1;
+
+ if (!BN_mont_red(E->A, mont)) return 0;
+ if (!BN_mont_red(E->B, mont)) return 0;
+ if (!BN_mont_red(E->h, mont)) return 0;
+
+ E->is_in_mont = 0;
+ return 1;
+}
+#endif /* MONTGOMERY */
+
+int EC_set_half(EC *E)
+/* h <- 1/2 mod p = (p + 1)/2 */
+{
+ assert(E != NULL);
+ assert(E->p != NULL);
+ assert(E->h != NULL);
+ assert(!E->is_in_mont);
+
+ if (BN_copy(E->h, E->p) == NULL) return 0;
+ if (!BN_add_word(E->h, 1)) return 0;
+ if (!BN_rshift1(E->h, E->h)) return 0;
+ return 1;
+}
diff --git a/crypto/ec/ec.h b/crypto/ec/ec.h
new file mode 100644
index 0000000000..dd7a4b892f
--- /dev/null
+++ b/crypto/ec/ec.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * ec.h
+ *
+ * Elliptic Curve Arithmetic Functions
+ *
+ * Copyright (C) Lenka Fibikova 2000
+ *
+ *
+ */
+
+
+#ifndef HEADER_EC_H
+#define HEADER_EC_H
+
+
+#include <openssl/bn.h>
+#include "../bn/bn_mont2.h" /* XXX */
+
+typedef struct bn_ec_struct /* E: y^2 = x^3 + Ax + B (mod p) */
+{
+ BIGNUM *A, *B, *p, *h; /* h = 1/2 mod p = (p + 1)/2 */
+ int is_in_mont;
+} EC;
+
+typedef struct bn_ec_point_struct /* P = [X, Y, Z] */
+{
+ BIGNUM *X, *Y, *Z;
+ int is_in_mont;
+} EC_POINT;
+
+typedef struct bn_ecp_precompute_struct /* Pi[i] = [2i + 1]P i = 0..2^{r-1} - 1 */
+{
+ int r;
+ EC_POINT **Pi;
+} ECP_PRECOMPUTE;
+
+
+#define ECP_is_infty(P) (BN_is_zero(P->Z))
+#define ECP_is_norm(P) (BN_is_one(P->Z))
+
+#define ECP_mont_minus(P, mont) (ECP_minus((P), (mont)->p))
+
+
+EC *EC_new();
+void EC_clear_free(EC *E);
+int EC_set_half(EC *E);
+#ifdef MONTGOMERY
+int EC_to_montgomery(EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int EC_from_montgomery(EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+#endif /* MONTGOMERY */
+
+
+EC_POINT *ECP_new();
+void ECP_clear_free(EC_POINT *P);
+void ECP_clear_free_precompute(ECP_PRECOMPUTE *prec);
+
+EC_POINT *ECP_generate(BIGNUM *x, BIGNUM *z, EC *E, BN_CTX *ctx);
+EC_POINT *ECP_dup(EC_POINT *P);
+int ECP_copy(EC_POINT *R, EC_POINT *P);
+int ECP_normalize(EC_POINT *P, EC *E, BN_CTX *ctx);
+EC_POINT *ECP_minus(EC_POINT *P, BIGNUM *p);
+int ECP_is_on_ec(EC_POINT *P, EC *E, BN_CTX *ctx);
+int ECP_ecp2bin(EC_POINT *P, unsigned char *to, int form); /* form(ANSI 9.62): 1-compressed; 2-uncompressed; 3-hybrid */
+int ECP_bin2ecp(unsigned char *from, int len, EC_POINT *P, EC *E, BN_CTX *ctx);
+
+#ifdef SIMPLE
+int ECP_cmp(EC_POINT *P, EC_POINT *Q, BIGNUM *p, BN_CTX *ctx);
+int ECP_double(EC_POINT *R, EC_POINT *P, EC *E, BN_CTX *ctx);
+int ECP_add(EC_POINT *R, EC_POINT *P, EC_POINT *Q, EC *E, BN_CTX *ctx);
+ECP_PRECOMPUTE *ECP_precompute(int r, EC_POINT *P, EC *E, BN_CTX *ctx);
+int ECP_multiply(EC_POINT *R, BIGNUM *k, ECP_PRECOMPUTE *prec, EC *E, BN_CTX *ctx);
+#endif /* SIMPLE */
+
+#ifdef MONTGOMERY
+int ECP_to_montgomery(EC_POINT *P, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_from_montgomery(EC_POINT *P, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_mont_cmp(EC_POINT *P, EC_POINT *Q, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_mont_double(EC_POINT *R, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_mont_add(EC_POINT *R, EC_POINT *P, EC_POINT *Q, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+ECP_PRECOMPUTE *ECP_mont_precompute(int r, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_mont_multiply(EC_POINT *R, BIGNUM *k, ECP_PRECOMPUTE *prec, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+int ECP_mont_multiply2(EC_POINT *R, BIGNUM *k, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx);
+#endif /* MONTGOMERY */
+
+#endif
diff --git a/crypto/ec/ec_point.c b/crypto/ec/ec_point.c
new file mode 100644
index 0000000000..5dd2da3b11
--- /dev/null
+++ b/crypto/ec/ec_point.c
@@ -0,0 +1,1477 @@
+/*
+ *
+ * ec_point.c
+ *
+ * Elliptic Curve Arithmetic Functions
+ *
+ * Copyright (C) Lenka Fibikova 2000
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <memory.h>
+
+#include <openssl/bn.h>
+
+#include "../bn/bn_mont2.h" /* XXX */
+#include "ec.h"
+
+
+EC_POINT *ECP_new()
+ {
+ EC_POINT *ret;
+
+ ret=(EC_POINT *)malloc(sizeof(EC_POINT));
+ if (ret == NULL) return NULL;
+ ret->X = BN_new();
+ ret->Y = BN_new();
+ ret->Z = BN_new();
+ ret->is_in_mont = 0;
+
+ if (ret->X == NULL || ret->Y == NULL || ret->Z == NULL)
+ {
+ if (ret->X != NULL) BN_free(ret->X);
+ if (ret->Y != NULL) BN_free(ret->Y);
+ if (ret->Z != NULL) BN_free(ret->Z);
+ free(ret);
+ return(NULL);
+ }
+ return(ret);
+ }
+
+
+void ECP_clear_free(EC_POINT *P)
+ {
+ if (P == NULL) return;
+
+ P->is_in_mont = 0;
+ if (P->X != NULL) BN_clear_free(P->X);
+ if (P->Y != NULL) BN_clear_free(P->Y);
+ if (P->Z != NULL) BN_clear_free(P->Z);
+ free(P);
+ }
+
+
+void ECP_clear_free_precompute(ECP_PRECOMPUTE *prec)
+ {
+ int i;
+ int max;
+
+ if (prec == NULL) return;
+ if (prec->Pi != NULL)
+ {
+ max = 1;
+ max <<= (prec->r - 1);
+
+ for (i = 0; i < max; i++)
+ {
+ if (prec->Pi[i] != NULL) ECP_clear_free(prec->Pi[i]);
+ }
+ }
+ free(prec);
+ }
+
+
+int ECP_is_on_ec(EC_POINT *P, EC *E, BN_CTX *ctx)
+ {
+ BIGNUM *n0, *n1, *n2, *p;
+ int Pnorm;
+ int ret = -1;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL);
+
+ assert(ctx != NULL);
+
+ assert(!P->is_in_mont);
+
+ if (ECP_is_infty(P)) return 1;
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ if (n2 == NULL)
+ goto err;
+
+ p = E->p;
+
+ Pnorm = (ECP_is_norm(P));
+
+ if (!Pnorm)
+ {
+ if (!BN_mod_mul(n0, P->Z, P->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n1, n0, n0, p, ctx)) goto err;
+ if (!BN_mod_mul(n2, n0, n1, p, ctx)) goto err;
+ }
+
+ if (!BN_mod_mul(n0, P->X, P->X, p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n0, P->X, p, ctx)) goto err;
+
+ if (Pnorm)
+ {
+ if (!BN_mod_mul(n1, P->X, E->A, p, ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_mod_mul(n1, n1, P->X, p, ctx)) goto err;
+ if (!BN_mod_mul(n1, n1, E->A, p, ctx)) goto err;
+ }
+ if (!BN_mod_add(n0, n0, n1, p, ctx)) goto err;
+
+ if (Pnorm)
+ {
+ if (!BN_mod_add(n0, n0, E->B, p, ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_mod_mul(n2, n2, E->B, p, ctx)) goto err;
+ if (!BN_mod_add(n0, n0, n2, p, ctx)) goto err;
+ }
+
+ if (!BN_mod_mul(n1, P->Y, P->Y, p, ctx)) goto err;
+
+ if (BN_cmp(n0, n1))
+ ret = 0;
+ else
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+ }
+
+
+EC_POINT *ECP_generate(BIGNUM *x, BIGNUM *z,EC *E, BN_CTX *ctx)
+/* x == NULL || z = 0 -> point of infinity */
+/* z == NULL || z = 1 -> normalized */
+ {
+ BIGNUM *n0, *n1;
+ EC_POINT *ret = NULL;
+ int Pnorm, Pinfty, X0, A0;
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(ctx != NULL);
+
+ Pinfty = (x == NULL);
+ Pnorm = (z == NULL);
+ if (!Pnorm)
+ {
+ Pnorm = BN_is_one(z);
+ Pinfty = (Pinfty || BN_is_zero(z));
+ }
+
+ if (Pinfty)
+ {
+ if ((ret = ECP_new()) == NULL) return NULL;
+ if (!BN_zero(ret->Z))
+ {
+ ECP_clear_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ X0 = BN_is_zero(x);
+ A0 = BN_is_zero(E->A);
+
+ if ((ret = ECP_new()) == NULL) return NULL;
+
+ ret->is_in_mont = 0;
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ if (n1 == NULL) goto err;
+
+ if (!BN_zero(n0)) goto err;
+ if (!BN_zero(n1)) goto err;
+
+ if (!X0)
+ {
+ if (!BN_mod_sqr(n0, x, E->p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n0, x, E->p, ctx)) goto err; /* x^3 */
+ }
+
+ if (!X0 && !A0)
+ {
+ if (!BN_mod_mul(n1, E->A, x, E->p, ctx)) goto err; /* Ax */
+ if (!BN_mod_add(n0, n0, n1, E->p, ctx)) goto err; /* x^3 + Ax */
+ }
+
+ if (!BN_is_zero(E->B))
+ if (!BN_mod_add(n0, n0, E->B, E->p, ctx)) goto err; /* x^3 + Ax +B */
+
+ if (!BN_mod_sqrt(ret->Y, n0, E->p, ctx)) goto err;
+ if (BN_copy(ret->X, x) == NULL) goto err;
+
+ if (Pnorm)
+ {
+ if (!BN_one(ret->Z)) goto err;
+ }
+ else
+ {
+ if (BN_copy(ret->Z, z) == NULL) goto err;
+ if (!BN_mod_sqr(n0, z, E->p, ctx)) goto err;
+ if (!BN_mod_mul(ret->X, ret->X, n0, E->p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n0, z, E->p, ctx)) goto err;
+ if (!BN_mod_mul(ret->Y, ret->Y, n0, E->p, ctx)) goto err;
+ }
+
+#ifdef TEST
+ if (!ECP_is_on_ec(ret, E, ctx)) goto err;
+#endif
+
+ BN_CTX_end(ctx);
+ return ret;
+
+err:
+ if (ret != NULL) ECP_clear_free(ret);
+ BN_CTX_end(ctx);
+ return NULL;
+ }
+
+
+int ECP_ecp2bin(EC_POINT *P, unsigned char *to, int form)
+/* form = 1 ... compressed
+ 2 ... uncompressed
+ 3 ... hybrid */
+ {
+ int bytes, bx, by;
+
+ assert (P != NULL);
+ assert (P->X != NULL && P->Y != NULL && P->Z != NULL);
+ assert (!P->is_in_mont);
+ assert (ECP_is_norm(P) || ECP_is_infty(P));
+ assert (to != NULL);
+ assert (form > 0 && form < 4);
+
+ if (BN_is_zero(P->Z))
+ {
+ to[0] = 0;
+ return 1;
+ }
+
+ bx = BN_num_bytes(P->X);
+ if (form == 1 ) bytes = bx + 1;
+ else
+ {
+ by = BN_num_bytes(P->Y);
+ bytes = (bx > by ? bx : by);
+ bytes = bytes * 2 + 1;
+ }
+ memset(to, 0, bytes);
+
+ switch (form)
+ {
+ case 1: to[0] = 2; break;
+ case 2: to[0] = 4; break;
+ case 3: to[0] = 6; break;
+ }
+ if (form != 2) to[0] += BN_is_bit_set(P->Y, 0);
+
+
+ if ((BN_bn2bin(P->X, to + 1)) != bx) return 0;
+ if (form != 1)
+ {
+ if ((BN_bn2bin(P->Y, to + bx + 1)) != by) return 0;
+ }
+
+ return bytes;
+ }
+
+
+int ECP_bin2ecp(unsigned char *from, int len, EC_POINT *P, EC *E, BN_CTX *ctx)
+ {
+ int y;
+ BIGNUM *x;
+ EC_POINT *pp;
+
+ assert (E != NULL);
+ assert (E->A != NULL && E->B != NULL && E->p != NULL);
+ assert (!E->is_in_mont);
+
+ assert (ctx != NULL);
+ assert (from != NULL);
+ assert (P != NULL);
+ assert (P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ if (len == 1 && from[0] != 0) return 0;
+
+ if (len == 0 || len == 1)
+ {
+ if (!BN_zero(P->Z)) return 0;
+ return 1;
+ }
+
+ switch (from[0])
+ {
+ case 2:
+ case 3:
+ y = from[0] - 2;
+ if ((x = BN_new()) == NULL) return 0;
+ if (BN_bin2bn(from + 1, len - 1, x) == NULL) return 0;
+
+ pp = ECP_generate(x, NULL, E, ctx);
+ BN_clear_free(x);
+ if (pp == NULL) return 0;
+
+ ECP_copy(P, pp);
+ ECP_clear_free(pp);
+
+ if (BN_is_bit_set(P->Y, 0) != y)
+ if (!BN_sub(P->Y, E->p, P->Y)) return 0;
+ break;
+
+ case 4:
+ case 6:
+ case 7:
+ y = (len - 1)/2;
+ if (BN_bin2bn(from + 1, y, P->X) == NULL) return 0;
+ if (BN_bin2bn(from + y + 1, y, P->Y) == NULL) return 0;
+ if (!BN_set_word(P->Z, 1)) return 0;
+ break;
+
+ default:
+ assert(0);
+
+ }
+
+ if (!ECP_is_on_ec(P, E, ctx)) return 0;
+ return 1;
+ }
+
+
+int ECP_normalize(EC_POINT *P, EC *E, BN_CTX *ctx)
+ {
+ BIGNUM *z, *zm;
+
+ assert (P != NULL);
+ assert (P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert (E != NULL);
+ assert (E->A != NULL && E->B != NULL && E->p != NULL);
+
+ assert (ctx != NULL);
+
+ if (ECP_is_norm(P)) return 1;
+ if (ECP_is_infty(P)) return 0;
+
+ if ((zm = BN_mod_inverse(P->Z, P->Z, E->p, ctx)) == NULL) return 0;
+
+ assert(!P->is_in_mont);
+
+
+ BN_CTX_start(ctx);
+ z = BN_CTX_get(ctx);
+ if (z == NULL) goto err;
+
+ if (!BN_mod_mul(z, zm, zm, E->p, ctx)) goto err;
+ if (!BN_mod_mul(P->X, P->X, z, E->p, ctx)) goto err;
+
+ if (!BN_mod_mul(z, z, zm, E->p, ctx)) goto err;
+ if (!BN_mod_mul(P->Y, P->Y, z, E->p, ctx)) goto err;
+
+ if (!BN_one(P->Z)) goto err;
+
+ if (zm != NULL) BN_clear_free(zm);
+
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ if (zm != NULL) BN_clear_free(zm);
+ BN_CTX_end(ctx);
+ return 0;
+ }
+
+
+int ECP_copy(EC_POINT *R, EC_POINT *P)
+ {
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ if (BN_copy(R->X, P->X) == NULL) return 0;
+ if (BN_copy(R->Y, P->Y) == NULL) return 0;
+ if (BN_copy(R->Z, P->Z) == NULL) return 0;
+ R->is_in_mont = P->is_in_mont;
+
+ return 1;
+ }
+
+
+EC_POINT *ECP_dup(EC_POINT *P)
+ {
+ EC_POINT *ret;
+
+ ret = ECP_new();
+ if (ret == NULL) return NULL;
+
+ if (!ECP_copy(ret, P))
+ {
+ ECP_clear_free(ret);
+ return(NULL);
+ }
+
+ return(ret);
+ }
+
+
+EC_POINT *ECP_minus(EC_POINT *P, BIGNUM *p) /* mont || non-mont */
+ {
+ EC_POINT *ret;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(p != NULL);
+
+ assert(BN_cmp(P->Y, p) < 0);
+
+ ret = ECP_dup(P);
+ if (ret == NULL) return NULL;
+
+ if (BN_is_zero(ret->Y)) return ret;
+
+ if (!BN_sub(ret->Y, p, ret->Y))
+ {
+ ECP_clear_free(ret);
+ return NULL;
+ }
+
+ return ret;
+ }
+
+
+#ifdef SIMPLE
+int ECP_cmp(EC_POINT *P, EC_POINT *Q, BIGNUM *p, BN_CTX *ctx)
+/* return values:
+ -2 ... error
+ 0 ... P = Q
+ -1 ... P = -Q
+ 1 ... else
+*/
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *n4;
+ int Pnorm, Qnorm;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(Q != NULL);
+ assert(Q->X != NULL && Q->Y != NULL && Q->Z != NULL);
+
+ assert(p != NULL);
+ assert(ctx != NULL);
+
+ assert(!P->is_in_mont);
+ assert(!Q->is_in_mont);
+
+ if (ECP_is_infty(P) && ECP_is_infty(Q)) return 0;
+ if (ECP_is_infty(P) || ECP_is_infty(Q)) return 1;
+
+
+ Pnorm = (ECP_is_norm(P));
+ Qnorm = (ECP_is_norm(Q));
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ if (n4 == NULL) goto err;
+
+ if (Qnorm)
+ {
+ if (BN_copy(n1, P->X) == NULL) goto err; /* L1 = x_p */
+ if (BN_copy(n2, P->Y) == NULL) goto err; /* L2 = y_p */
+ }
+ else
+ {
+ if (!BN_sqr(n0, Q->Z, ctx)) goto err;
+ if (!BN_mod_mul(n1, P->X, n0, p, ctx)) goto err; /* L1 = x_p * z_q^2 */
+
+ if (!BN_mod_mul(n0, n0, Q->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n2, P->Y, n0, p, ctx)) goto err; /* L2 = y_p * z_q^3 */
+ }
+
+ if (Pnorm)
+ {
+ if (BN_copy(n3, Q->X) == NULL) goto err; /* L3 = x_q */
+ if (BN_copy(n4, Q->Y) == NULL) goto err; /* L4 = y_q */
+ }
+ else
+ {
+ if (!BN_sqr(n0, P->Z, ctx)) goto err;
+ if (!BN_mod_mul(n3, Q->X, n0, p, ctx)) goto err; /* L3 = x_q * z_p^2 */
+
+ if (!BN_mod_mul(n0, n0, P->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n4, Q->Y, n0, p, ctx)) goto err; /* L4 = y_q * z_p^3 */
+ }
+
+ if (!BN_mod_sub(n0, n1, n3, p, ctx)) goto err; /* L5 = L1 - L3 */
+
+ if (!BN_is_zero(n0))
+ {
+ BN_CTX_end(ctx);
+ return 1;
+ }
+
+ if (!BN_mod_sub(n0, n2, n4, p, ctx)) goto err; /* L6 = L2 - L4 */
+
+ if (!BN_is_zero(n0))
+ {
+ BN_CTX_end(ctx);
+ return -1;
+ }
+
+ BN_CTX_end(ctx);
+ return 0;
+
+err:
+ BN_CTX_end(ctx);
+ return -2;
+ }
+
+
+int ECP_double(EC_POINT *R, EC_POINT *P, EC *E, BN_CTX *ctx)
+/* R <- 2P (on E) */
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *p;
+ int Pnorm, A0;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(ctx != NULL);
+
+ assert(!P->is_in_mont);
+
+ if (ECP_is_infty(P))
+ {
+ if (!BN_zero(R->Z)) return 0;
+ return 1;
+ }
+
+ Pnorm = (ECP_is_norm(P));
+ A0 = (BN_is_zero(E->A));
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ if (n3 == NULL) goto err;
+
+ p = E->p;
+
+ /* L1 */
+ if (Pnorm || A0)
+ {
+ if (!BN_mod_sqr(n1, P->X, p, ctx)) goto err;
+ if (!BN_mul_word(n1, 3)) goto err;
+ if (!A0) /* if A = 0: L1 = 3 * x^2 + a * z^4 = 3 * x ^2 */
+ if (!BN_mod_add(n1, n1, E->A, p, ctx)) goto err; /* L1 = 3 * x^2 + a * z^4 = 3 * x^2 + a */
+ }
+ else
+ {
+ if (!BN_mod_sqr(n0, P->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n0, n0, p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n0, E->A, p, ctx)) goto err;
+ if (!BN_mod_sqr(n1, P->X, p, ctx)) goto err;
+ if (!BN_mul_word(n1, 3)) goto err;
+ if (!BN_mod_add(n1, n1, n0, p, ctx)) goto err; /* L1 = 3 * x^2 + a * z^4 */
+ }
+
+ /* Z */
+ if (Pnorm)
+ {
+ if (BN_copy(n0, P->Y) == NULL) goto err;
+ }
+ else
+ {
+ if (!BN_mod_mul(n0, P->Y, P->Z, p, ctx)) goto err;
+ }
+ if (!BN_lshift1(n0, n0)) goto err;
+ if (!BN_smod(R->Z, n0, p, ctx)) goto err; /* Z = 2 * y * z */
+
+ /* L2 */
+ if (!BN_mod_sqr(n3, P->Y, p, ctx)) goto err;
+ if (!BN_mod_mul(n2, P->X, n3, p, ctx)) goto err;
+ if (!BN_lshift(n2, n2, 2)) goto err;
+ if (!BN_smod(n2, n2, p, ctx)) goto err; /* L2 = 4 * x * y^2 */
+
+ /* X */
+ if (!BN_lshift1(n0, n2)) goto err;
+ if (!BN_mod_sqr(R->X, n1, p, ctx)) goto err;
+ if (!BN_mod_sub(R->X, R->X, n0, p, ctx)) goto err; /* X = L1^2 - 2 * L2 */
+
+ /* L3 */
+ if (!BN_mod_sqr(n0, n3, p, ctx)) goto err;
+ if (!BN_lshift(n3, n0, 3)) goto err;
+ if (!BN_smod(n3, n3, p, ctx)) goto err; /* L3 = 8 * y^4 */
+
+ /* Y */
+ if (!BN_mod_sub(n0, n2, R->X, p, ctx)) goto err;
+ if (!BN_mod_mul(n0, n1, n0, p, ctx)) goto err;
+ if (!BN_mod_sub(R->Y, n0, n3, p, ctx)) goto err; /* Y = L1 * (L2 - X) - L3 */
+
+
+#ifdef TEST
+ if (!ECP_is_on_ec(R, E, ctx)) return 0;
+#endif
+
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ BN_CTX_end(ctx);
+ return 0;
+ }
+
+
+int ECP_add(EC_POINT *R, EC_POINT *P, EC_POINT *Q, EC *E, BN_CTX *ctx)
+/* R <- P + Q (on E) */
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6, *p;
+ int Pnorm, Qnorm;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(Q != NULL);
+ assert(Q->X != NULL && Q->Y != NULL && Q->Z != NULL);
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+ assert(!BN_is_zero(E->h));;
+
+ assert(ctx != NULL);
+
+ assert(!P->is_in_mont);
+ assert(!Q->is_in_mont);
+
+ if (P == Q) return ECP_double(R, P, E, ctx);
+
+ if (ECP_is_infty(P)) return ECP_copy(R, Q);
+ if (ECP_is_infty(Q)) return ECP_copy(R, P);
+
+ Pnorm = (ECP_is_norm(P));
+ Qnorm = (ECP_is_norm(Q));
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ n5 = BN_CTX_get(ctx);
+ n6 = BN_CTX_get(ctx);
+ if (n6 == NULL) goto err;
+
+ p = E->p;
+
+ /* L1; L2 */
+ if (Qnorm)
+ {
+ if (BN_copy(n1, P->X) == NULL) goto err; /* L1 = x_p */
+ if (BN_copy(n2, P->Y) == NULL) goto err; /* L2 = y_p */
+ }
+ else
+ {
+ if (!BN_sqr(n0, Q->Z, ctx)) goto err;
+ if (!BN_mod_mul(n1, P->X, n0, p, ctx)) goto err; /* L1 = x_p * z_q^2 */
+
+ if (!BN_mod_mul(n0, n0, Q->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n2, P->Y, n0, p, ctx)) goto err; /* L2 = y_p * z_q^3 */
+ }
+
+ /* L3; L4 */
+ if (Pnorm)
+ {
+ if (BN_copy(n3, Q->X) == NULL) goto err; /* L3 = x_q */
+ if (BN_copy(n4, Q->Y) == NULL) goto err; /* L4 = y_q */
+ }
+ else
+ {
+ if (!BN_sqr(n0, P->Z, ctx)) goto err;
+ if (!BN_mod_mul(n3, Q->X, n0, p, ctx)) goto err; /* L3 = x_q * z_p^2 */
+
+ if (!BN_mod_mul(n0, n0, P->Z, p, ctx)) goto err;
+ if (!BN_mod_mul(n4, Q->Y, n0, p, ctx)) goto err; /* L4 = y_q * z_p^3 */
+ }
+
+ /* L5; L6 */
+ if (!BN_mod_sub(n5, n1, n3, p, ctx)) goto err; /* L5 = L1 - L3 */
+ if (!BN_mod_sub(n6, n2, n4, p, ctx)) goto err; /* L6 = L2 - L4 */
+
+ /* pata */
+ if (BN_is_zero(n5))
+ {
+ if (BN_is_zero(n6)) /* P = Q => P + Q = 2P */
+ {
+ BN_CTX_end(ctx);
+ return ECP_double(R, P, E, ctx);
+ }
+ else /* P = -Q => P + Q = \infty */
+ {
+ BN_CTX_end(ctx);
+ if (!BN_zero(R->Z)) return 0;
+ return 1;
+ }
+ }
+
+ /* L7; L8 */
+ if (!BN_mod_add(n1, n1, n3, p, ctx)) goto err; /* L7 = L1 + L3 */
+ if (!BN_mod_add(n2, n2, n4, p, ctx)) goto err; /* L8 = L2 + L4 */
+
+ /* Z */
+ if (Pnorm)
+ {
+ if (BN_copy(n0, Q->Z) == NULL) goto err;
+ }
+ else
+ {
+ if (!BN_mod_mul(n0, P->Z, Q->Z, p, ctx)) goto err;
+ }
+ if (!BN_mod_mul(R->Z, n0, n5, p, ctx)) goto err; /* Z = z_p * z_q * L_5 */
+
+ /* X */
+ if (!BN_mod_sqr(n0, n6, p, ctx)) goto err;
+ if (!BN_mod_sqr(n4, n5, p, ctx)) goto err;
+ if (!BN_mod_mul(n3, n1, n4, p, ctx)) goto err;
+ if (!BN_mod_sub(R->X, n0, n3, p, ctx)) goto err; /* X = L6^2 - L5^2 * L7 */
+
+ /* L9 */
+ if (!BN_lshift1(n0, R->X)) goto err;
+ if (!BN_mod_sub(n0, n3, n0, p, ctx)) goto err; /* L9 = L5^2 * L7 - 2X */
+
+ /* Y */
+ if (!BN_mod_mul(n0, n0, n6, p, ctx)) goto err;
+ if (!BN_mod_mul(n5, n4, n5, p, ctx)) goto err;
+ if (!BN_mod_mul(n1, n2, n5, p, ctx)) goto err;
+ if (!BN_mod_sub(n0, n0, n1, p, ctx)) goto err;
+ if (!BN_mod_mul(R->Y, n0, E->h, p, ctx)) goto err; /* Y = (L6 * L9 - L8 * L5^3) / 2 */
+
+
+
+#ifdef TEST
+ if (!ECP_is_on_ec(R, E, ctx)) return 0;
+#endif
+
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ BN_CTX_end(cxt);
+ return 0;
+ }
+
+
+ECP_PRECOMPUTE *ECP_precompute(int r, EC_POINT *P, EC *E, BN_CTX *ctx)
+ {
+ ECP_PRECOMPUTE *ret;
+ EC_POINT *P2;
+ int i, max;
+
+ assert(r > 2);
+ assert(!P->is_in_mont);
+ assert(!E->is_in_mont);
+
+ ret=(ECP_PRECOMPUTE *)malloc(sizeof(ECP_PRECOMPUTE));
+ if (ret == NULL) return NULL;
+
+ max = 1;
+ max <<= (r - 1);
+
+ ret->r = 0;
+
+ ret->Pi=(EC_POINT **)malloc(sizeof(EC_POINT *) * max);
+ if (ret->Pi == NULL) goto err;
+
+
+ /* P2 = [2]P */
+ if ((P2 = ECP_new()) == NULL) goto err;
+ if (!ECP_double(P2, P, E, ctx)) goto err;
+
+ /* P_0 = P */
+ if((ret->Pi[0] = ECP_dup(P)) == NULL) goto err;
+
+
+ /* P_i = P_(i-1) + P2 */
+ for (i = 1; i < max; i++)
+ {
+ if ((ret->Pi[i] = ECP_new()) == NULL) goto err;
+
+ if (!ECP_add(ret->Pi[i], P2, ret->Pi[i - 1], E, ctx)) goto err;
+ }
+
+ ret->r = r;
+ ECP_clear_free(P2);
+
+ return ret;
+
+err:
+ ECP_clear_free(P2);
+ ECP_clear_free_precompute(ret);
+ return NULL;
+ }
+
+
+int ECP_multiply(EC_POINT *R, BIGNUM *k, ECP_PRECOMPUTE *prec, EC *E, BN_CTX *ctx)
+/* R = [k]P */
+ {
+ int j;
+ int t, nextw, h, r;
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(k != NULL);
+ assert(!k->neg);
+
+ assert(ctx != NULL);
+ assert(prec != NULL);
+
+ assert(!E->is_in_mont);
+
+ if (BN_is_zero(k))
+ {
+ if (!BN_zero(R->Z)) return 0;
+ R->is_in_mont = 0;
+ return 1;
+ }
+
+
+ j = BN_num_bits(k);
+ j--;
+
+ r = prec->r;
+
+ if (!BN_zero(R->Z)) return 0;
+ R->is_in_mont = 0;
+
+ while(j >= 0)
+ {
+ if (!BN_is_bit_set(k, j))
+ {
+ if (!ECP_double(R, R, E, ctx)) return 0;
+ j--;
+ }
+ else
+ {
+ nextw = j - r;
+ if (nextw < -1) nextw = -1;
+ t = nextw + 1;
+ while(!BN_is_bit_set(k, t))
+ t++;
+
+ if (!ECP_double(R, R, E, ctx)) return 0;
+
+ j--;
+ if (j < t) h = 0;
+ else
+ {
+ h = 1;
+ for(; j > t; j--)
+ {
+ h <<= 1;
+ if (BN_is_bit_set(k, j)) h++;
+ if (!ECP_double(R, R, E, ctx)) return 0;
+ }
+ if (!ECP_double(R, R, E, ctx)) return 0;
+ j--;
+ }
+
+ if (!ECP_add(R, R, prec->Pi[h], E, ctx)) return 0;
+
+ for (; j > nextw; j--)
+ {
+ if (!ECP_double(R, R, E, ctx)) return 0;
+ }
+
+ }
+ }
+
+ return 1;
+ }
+
+#endif /* SIMPLE */
+
+
+#ifdef MONTGOMERY
+
+int ECP_to_montgomery(EC_POINT *P, BN_MONTGOMERY *mont, BN_CTX *ctx)
+ {
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (P->is_in_mont) return 1;
+
+ if (!BN_lshift(P->X, P->X, mont->R_num_bits)) return 0;
+ if (!BN_mod(P->X, P->X, mont->p, ctx)) return 0;
+
+ if (!BN_lshift(P->Y, P->Y, mont->R_num_bits)) return 0;
+ if (!BN_mod(P->Y, P->Y, mont->p, ctx)) return 0;
+
+ if (!BN_lshift(P->Z, P->Z, mont->R_num_bits)) return 0;
+ if (!BN_mod(P->Z, P->Z, mont->p, ctx)) return 0;
+
+ P->is_in_mont = 1;
+ return 1;
+ }
+
+
+int ECP_from_montgomery(EC_POINT *P, BN_MONTGOMERY *mont, BN_CTX *ctx)
+ {
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (!P->is_in_mont) return 1;
+
+ if (!BN_mont_red(P->X, mont)) return 0;
+ if (!BN_mont_red(P->Y, mont)) return 0;
+ if (!BN_mont_red(P->Z, mont)) return 0;
+
+ P->is_in_mont = 0;
+ return 1;
+ }
+
+
+int ECP_mont_cmp(EC_POINT *P, EC_POINT *Q, BN_MONTGOMERY *mont, BN_CTX *ctx)
+/* return values:
+ -2 ... error
+ 0 ... P = Q
+ -1 ... P = -Q
+ 1 ... else
+*/
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *p;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(Q != NULL);
+ assert(Q->X != NULL && Q->Y != NULL && Q->Z != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ assert(ctx != NULL);
+
+ if (!P->is_in_mont)
+ if (!ECP_to_montgomery(P, mont, ctx)) return 0;
+
+ if (!Q->is_in_mont)
+ if (!ECP_to_montgomery(Q, mont, ctx)) return 0;
+
+
+ if (ECP_is_infty(P) && ECP_is_infty(Q)) return 0;
+ if (ECP_is_infty(P) || ECP_is_infty(Q)) return 1;
+
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ n5 = BN_CTX_get(ctx);
+ if (n5 == 0) goto err;
+
+
+ p = mont->p;
+
+
+ if (!BN_mont_mod_mul(n5, Q->Z, Q->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n1, P->X, n5, mont)) goto err; /* L1 = x_p * z_q^2 */
+
+ if (!BN_mont_mod_mul(n0, n5, Q->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n2, P->Y, n0, mont)) goto err; /* L2 = y_p * z_q^3 */
+
+ if (!BN_mont_mod_mul(n5, P->Z, P->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n3, Q->X, n5, mont)) goto err; /* L3 = x_q * z_p^2 */
+
+ if (!BN_mont_mod_mul(n0, n5, P->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n4, Q->Y, n0, mont)) goto err; /* L4 = y_q * z_p^3 */
+
+
+ if (!BN_mod_sub_quick(n0, n1, n3, p)) goto err; /* L5 = L1 - L3 */
+
+ if (!BN_is_zero(n0))
+ {
+ BN_CTX_end(ctx);
+ return 1;
+ }
+
+ if (!BN_mod_sub_quick(n0, n2, n4, p)) goto err; /* L6 = L2 - L4 */
+
+ if (!BN_is_zero(n0))
+ {
+ BN_CTX_end(ctx);
+ return -1;
+ }
+
+ BN_CTX_end(ctx);
+ return 0;
+
+err:
+ BN_CTX_end(ctx);
+ return -2;
+ }
+
+
+int ECP_mont_double(EC_POINT *R, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+/* R <- 2P (on E) */
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *p;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(ctx != NULL);
+
+ if (!P->is_in_mont)
+ if (!ECP_to_montgomery(P, mont, ctx)) return 0;
+
+ if (!E->is_in_mont)
+ if (!EC_to_montgomery(E, mont, ctx)) return 0;
+
+ R->is_in_mont = 1;
+
+ if (ECP_is_infty(P))
+ {
+ if (!BN_zero(R->Z)) return 0;
+ return 1;
+ }
+
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ if (n3 == 0) goto err;
+
+ p = E->p;
+
+ /* L1 */
+ if (!BN_mont_mod_mul(n0, P->Z, P->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n2, n0, n0, mont)) goto err;
+ if (!BN_mont_mod_mul(n0, n2, E->A, mont)) goto err;
+ if (!BN_mont_mod_mul(n1, P->X, P->X, mont)) goto err;
+ if (!BN_mod_lshift1_quick(n2, n1, p)) goto err;
+ if (!BN_mod_add_quick(n1, n1, n2, p)) goto err;
+ if (!BN_mod_add_quick(n1, n1, n0, p)) goto err; /* L1 = 3 * x^2 + a * z^4 */
+
+ /* Z */
+ if (!BN_mont_mod_mul(n0, P->Y, P->Z, mont)) goto err;
+ if (!BN_mod_lshift1_quick(R->Z, n0, p)) goto err; /* Z = 2 * y * z */
+
+ /* L2 */
+ if (!BN_mont_mod_mul(n3, P->Y, P->Y, mont)) goto err;
+ if (!BN_mont_mod_mul(n2, P->X, n3, mont)) goto err;
+ if (!BN_mod_lshift_quick(n2, n2, 2, p)) goto err; /* L2 = 4 * x * y^2 */
+
+ /* X */
+ if (!BN_mod_lshift1_quick(n0, n2, p)) goto err;
+ if (!BN_mont_mod_mul(R->X, n1, n1, mont)) goto err;
+ if (!BN_mod_sub_quick(R->X, R->X, n0, p)) goto err; /* X = L1^2 - 2 * L2 */
+
+ /* L3 */
+ if (!BN_mont_mod_mul(n0, n3, n3, mont)) goto err;
+ if (!BN_mod_lshift_quick(n3, n0, 3, p)) goto err; /* L3 = 8 * y^4 */
+
+
+ /* Y */
+ if (!BN_mod_sub_quick(n2, n2, R->X, p)) goto err;
+ if (!BN_mont_mod_mul(n0, n1, n2, mont)) goto err;
+ if (!BN_mod_sub_quick(R->Y, n0, n3, p)) goto err; /* Y = L1 * (L2 - X) - L3 */
+
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ BN_CTX_end(ctx);
+ return 0;
+ }
+
+
+int ECP_mont_add(EC_POINT *R, EC_POINT *P, EC_POINT *Q, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+/* R <- P + Q (on E) */
+ {
+ BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6, *p;
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(Q != NULL);
+ assert(Q->X != NULL && Q->Y != NULL && Q->Z != NULL);
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+ assert(!BN_is_zero(E->h));;
+
+ assert(ctx != NULL);
+
+ if (!Q->is_in_mont)
+ if (!ECP_to_montgomery(Q, mont, ctx)) return 0;
+
+ if (!P->is_in_mont)
+ if (!ECP_to_montgomery(P, mont, ctx)) return 0;
+
+ if (!E->is_in_mont)
+ if (!EC_to_montgomery(E, mont, ctx)) return 0;
+
+ if (P == Q) return ECP_mont_double(R, P, E, mont, ctx);
+
+ if (ECP_is_infty(P)) return ECP_copy(R, Q);
+ if (ECP_is_infty(Q)) return ECP_copy(R, P);
+
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ n5 = BN_CTX_get(ctx);
+ n6 = BN_CTX_get(ctx);
+ if (n6 == NULL) goto err;
+
+
+ p = E->p;
+
+ R->is_in_mont = 1;
+
+ /* L1; L2 */
+ if (!BN_mont_mod_mul(n6, Q->Z, Q->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n1, P->X, n6, mont)) goto err; /* L1 = x_p * z_q^2 */
+
+ if (!BN_mont_mod_mul(n0, n6, Q->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n2, P->Y, n0, mont)) goto err; /* L2 = y_p * z_q^3 */
+
+
+ /* L3; L4 */
+ if (!BN_mont_mod_mul(n6, P->Z, P->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n3, Q->X, n6, mont)) goto err; /* L3 = x_q * z_p^2 */
+
+ if (!BN_mont_mod_mul(n0, n6, P->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(n4, Q->Y, n0, mont)) goto err; /* L4 = y_q * z_p^3 */
+
+
+ /* L5; L6 */
+ if (!BN_mod_sub_quick(n5, n1, n3, p)) goto err; /* L5 = L1 - L3 */
+ if (!BN_mod_sub_quick(n6, n2, n4, p)) goto err; /*L6 = L2 - L4 */
+
+
+ /* pata */
+ if (BN_is_zero(n5))
+ {
+ if (BN_is_zero(n6)) /* P = Q => P + Q = 2P */
+ {
+ BN_CTX_end(ctx);
+ return ECP_mont_double(R, P, E, mont, ctx);
+ }
+ else /* P = -Q => P + Q = \infty */
+ {
+ BN_CTX_end(ctx);
+ if (!BN_zero(R->Z)) return 0;
+ return 1;
+ }
+ }
+
+ /* L7; L8 */
+ if (!BN_mod_add_quick(n1, n1, n3, p)) goto err; /* L7 = L1 + L3 */
+ if (!BN_mod_add_quick(n2, n2, n4, p)) goto err; /* L8 = L2 + L4 */
+
+
+ /* Z */
+ if (!BN_mont_mod_mul(n0, P->Z, Q->Z, mont)) goto err;
+ if (!BN_mont_mod_mul(R->Z, n0, n5, mont)) goto err; /* Z = z_p * z_q * L_5 */
+
+
+ /* X */
+ if (!BN_mont_mod_mul(n0, n6, n6, mont)) goto err;
+ if (!BN_mont_mod_mul(n4, n5, n5, mont)) goto err;
+ if (!BN_mont_mod_mul(n3, n1, n4, mont)) goto err;
+ if (!BN_mod_sub_quick(R->X, n0, n3, p)) goto err; /* X = L6^2 - L5^2 * L7 */
+
+
+ /* L9 */
+ if (!BN_mod_lshift1_quick(n0, R->X, p)) goto err;
+ if (!BN_mod_sub_quick(n3, n3, n0, p)) goto err; /* L9 = L5^2 * L7 - 2X */
+
+
+ /* Y */
+ if (!BN_mont_mod_mul(n0, n3, n6, mont)) goto err;
+ if (!BN_mont_mod_mul(n6, n4, n5, mont)) goto err;
+ if (!BN_mont_mod_mul(n1, n2, n6, mont)) goto err;
+ if (!BN_mod_sub_quick(n0, n0, n1, p)) goto err;
+ if (!BN_mont_mod_mul(R->Y, n0, E->h, mont)) goto err; /* Y = (L6 * L9 - L8 * L5^3) / 2 */
+
+
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ BN_CTX_end(ctx);
+ return 0;
+ }
+
+
+ECP_PRECOMPUTE *ECP_mont_precompute(int r, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+ {
+ ECP_PRECOMPUTE *ret;
+ EC_POINT *P2;
+ int i, max;
+
+ assert(r > 2);
+ assert(r < sizeof(unsigned int) * 8 - 1);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ if (!P->is_in_mont)
+ if (!ECP_to_montgomery(P, mont, ctx)) return 0;
+
+ if (!E->is_in_mont)
+ if (!EC_to_montgomery(E, mont, ctx)) return 0;
+
+ ret=(ECP_PRECOMPUTE *)malloc(sizeof(ECP_PRECOMPUTE));
+ if (ret == NULL) return NULL;
+
+ max = 1;
+ max <<= (r - 1);
+
+ ret->r = 0;
+
+ ret->Pi=(EC_POINT **)malloc(sizeof(EC_POINT *) * max);
+ if (ret->Pi == NULL) goto err;
+
+
+ /* P2 = [2]P */
+ if ((P2 = ECP_new()) == NULL) goto err;
+ if (!ECP_mont_double(P2, P, E, mont, ctx)) goto err;
+
+ /* P_0 = P */
+ if((ret->Pi[0] = ECP_dup(P)) == NULL) goto err;
+
+
+ /* P_i = P_(i-1) + P2 */
+ for (i = 1; i < max; i++)
+ {
+ if ((ret->Pi[i] = ECP_new()) == NULL) goto err;
+ if (!ECP_mont_add(ret->Pi[i], P2, ret->Pi[i - 1], E, mont, ctx)) goto err;
+ }
+
+ ret->r = r;
+ ECP_clear_free(P2);
+
+ return ret;
+
+err:
+ ECP_clear_free(P2);
+ ECP_clear_free_precompute(ret);
+ return NULL;
+ }
+
+
+int ECP_mont_multiply(EC_POINT *R, BIGNUM *k, ECP_PRECOMPUTE *prec, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+/* R = [k]P P = prec->Pi[0]*/
+ {
+ int j;
+ int t, nextw, h, r;
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(k != NULL);
+ assert(!k->neg);
+
+ assert(ctx != NULL);
+ assert(prec != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ if (!E->is_in_mont)
+ if (!EC_to_montgomery(E, mont, ctx)) return 0;
+
+
+ if (BN_is_zero(k))
+ {
+ if (!BN_zero(R->Z)) return 0;
+ R->is_in_mont = 1;
+ return 1;
+ }
+
+ j = BN_num_bits(k);
+ j--;
+
+ r = prec->r;
+
+ if (!BN_zero(R->Z)) return 0;
+ R->is_in_mont = 1;
+
+ while(j >= 0)
+ {
+ if (!BN_is_bit_set(k, j))
+ {
+ if (!ECP_mont_double(R, R, E, mont, ctx)) return 0;
+ j--;
+ }
+ else
+ {
+ nextw = j - r;
+ if (nextw < -1) nextw = -1;
+ t = nextw + 1;
+ while(!BN_is_bit_set(k, t))
+ t++;
+
+ if (!ECP_mont_double(R, R, E, mont, ctx)) return 0;
+
+ j--;
+ if (j < t) h = 0;
+ else
+ {
+ h = 1;
+ for(; j > t; j--)
+ {
+ h <<= 1;
+ if (BN_is_bit_set(k, j)) h++;
+ if (!ECP_mont_double(R, R, E, mont, ctx)) return 0;
+ }
+ if (!ECP_mont_double(R, R, E, mont, ctx)) return 0;
+ j--;
+ }
+
+ if (!ECP_mont_add(R, R, prec->Pi[h], E, mont, ctx)) return 0;
+
+ for (; j > nextw; j--)
+ {
+ if (!ECP_mont_double(R, R, E, mont, ctx)) return 0;
+ }
+
+ }
+ }
+
+ return 1;
+ }
+
+
+int ECP_mont_multiply2(EC_POINT *R, BIGNUM *k, EC_POINT *P, EC *E, BN_MONTGOMERY *mont, BN_CTX *ctx)
+/* R = [k]P */
+ {
+ int j, hj, kj;
+ BIGNUM *h;
+ EC_POINT *mP;
+
+ assert(R != NULL);
+ assert(R->X != NULL && R->Y != NULL && R->Z != NULL);
+
+ assert(P != NULL);
+ assert(P->X != NULL && P->Y != NULL && P->Z != NULL);
+
+ assert(E != NULL);
+ assert(E->A != NULL && E->B != NULL && E->p != NULL && E->h != NULL);
+
+ assert(k != NULL);
+ assert(!k->neg);
+
+ assert(ctx != NULL);
+
+ assert(mont != NULL);
+ assert(mont->p != NULL);
+
+ if (!E->is_in_mont)
+ if (!EC_to_montgomery(E, mont, ctx)) return 0;
+
+ if (!P->is_in_mont)
+ if (!ECP_to_montgomery(P, mont, ctx)) return 0;
+
+
+ if (BN_is_zero(k))
+ {
+ if (!BN_zero(R->Z)) return 0;
+ R->is_in_mont = 1;
+ return 1;
+ }
+
+ if ((h = BN_dup(k)) == NULL) return 0;
+
+ if (!BN_lshift1(h, h)) goto err;
+ if (!BN_add(h, h, k)) goto err;
+
+ if (!ECP_copy(R, P)) goto err;
+ if ((mP = ECP_mont_minus(P, mont)) == NULL) goto err;
+
+ for(j = BN_num_bits(h) - 2; j > 0; j--)
+ {
+ if (!ECP_mont_double(R, R, E, mont, ctx)) goto err;
+ kj = BN_is_bit_set(k, j);
+ hj = BN_is_bit_set(h, j);
+ if (hj == 1 && kj == 0)
+ if (!ECP_mont_add(R, R, P, E, mont, ctx)) goto err;
+ if (hj == 0 && kj == 1)
+ if (!ECP_mont_add(R, R, mP, E, mont, ctx)) goto err;
+ }
+
+ if (h != NULL) BN_free(h);
+ if (mP != NULL) ECP_clear_free(mP);
+ return 1;
+
+err:
+ if (h != NULL) BN_free(h);
+ if (mP != NULL) ECP_clear_free(mP);
+ return 0;
+ }
+
+#endif /* MONTGOMERY */
diff --git a/crypto/ocsp/.cvsignore b/crypto/ocsp/.cvsignore
new file mode 100644
index 0000000000..c6d03a9dbc
--- /dev/null
+++ b/crypto/ocsp/.cvsignore
@@ -0,0 +1,2 @@
+lib
+Makefile.save
diff --git a/crypto/ocsp/Makefile.ssl b/crypto/ocsp/Makefile.ssl
new file mode 100644
index 0000000000..bae9226844
--- /dev/null
+++ b/crypto/ocsp/Makefile.ssl
@@ -0,0 +1,236 @@
+#
+# OpenSSL/ocsp/Makefile.ssl
+#
+
+DIR= ocsp
+TOP= ../..
+CC= cc
+INCLUDES= -I.. -I../../include
+CFLAG=-g
+INSTALL_PREFIX=
+OPENSSLDIR= /usr/local/ssl
+INSTALLTOP=/usr/local/ssl
+MAKE= make -f Makefile.ssl
+MAKEDEPEND= $(TOP)/util/domd $(TOP)
+MAKEFILE= Makefile.ssl
+AR= ar r
+
+CFLAGS= $(INCLUDES) $(CFLAG)
+
+GENERAL=Makefile README
+TEST=
+APPS=
+
+LIB=$(TOP)/libcrypto.a
+LIBSRC= ocsp_req.c ocsp_res.c ocsp_sig.c ocsp_cid.c ocsp_ext.c \
+ ocsp_lib.c ocsp_err.c
+#ocsp_v3.c
+LIBOBJ= ocsp_req.o ocsp_res.o ocsp_sig.o ocsp_cid.o ocsp_ext.o \
+ ocsp_lib.o ocsp_err.o
+#ocsp_v3.o
+
+SRC= $(LIBSRC)
+
+EXHEADER= ocsp.h
+HEADER= $(EXHEADER)
+
+ALL= $(GENERAL) $(SRC) $(HEADER)
+
+top:
+ (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
+
+all: lib
+
+lib: $(LIBOBJ)
+ $(AR) $(LIB) $(LIBOBJ)
+ $(RANLIB) $(LIB)
+ @touch lib
+
+files:
+ perl $(TOP)/util/files.pl Makefile.ssl >> $(TOP)/MINFO
+
+links:
+ $(TOP)/util/point.sh Makefile.ssl Makefile ;
+ $(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
+ $(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
+ $(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
+
+install:
+ @for i in $(EXHEADER) ; \
+ do \
+ (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+ chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+ done;
+
+tags:
+ ctags $(SRC)
+
+tests:
+
+lint:
+ lint -DLINT $(INCLUDES) $(SRC)>fluff
+
+depend:
+ $(MAKEDEPEND) $(INCLUDES) $(DEPFLAG) $(LIBSRC)
+
+dclean:
+ $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
+ mv -f Makefile.new $(MAKEFILE)
+
+clean:
+ rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+ocsp_cid.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_cid.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_cid.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_cid.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_cid.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_cid.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_cid.o: ../../include/openssl/e_os.h ../../include/openssl/e_os2.h
+ocsp_cid.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+ocsp_cid.o: ../../include/openssl/idea.h ../../include/openssl/lhash.h
+ocsp_cid.o: ../../include/openssl/md2.h ../../include/openssl/md4.h
+ocsp_cid.o: ../../include/openssl/md5.h ../../include/openssl/mdc2.h
+ocsp_cid.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
+ocsp_cid.o: ../../include/openssl/ocsp.h ../../include/openssl/opensslconf.h
+ocsp_cid.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_cid.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_cid.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_cid.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_cid.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_cid.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_cid.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_cid.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_err.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
+ocsp_err.o: ../../include/openssl/blowfish.h ../../include/openssl/bn.h
+ocsp_err.o: ../../include/openssl/buffer.h ../../include/openssl/cast.h
+ocsp_err.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h
+ocsp_err.o: ../../include/openssl/des.h ../../include/openssl/dh.h
+ocsp_err.o: ../../include/openssl/dsa.h ../../include/openssl/e_os.h
+ocsp_err.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
+ocsp_err.o: ../../include/openssl/evp.h ../../include/openssl/idea.h
+ocsp_err.o: ../../include/openssl/lhash.h ../../include/openssl/md2.h
+ocsp_err.o: ../../include/openssl/md4.h ../../include/openssl/md5.h
+ocsp_err.o: ../../include/openssl/mdc2.h ../../include/openssl/obj_mac.h
+ocsp_err.o: ../../include/openssl/objects.h ../../include/openssl/ocsp.h
+ocsp_err.o: ../../include/openssl/opensslconf.h
+ocsp_err.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_err.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_err.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_err.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_err.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_err.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_err.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_err.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_ext.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_ext.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_ext.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_ext.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_ext.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_ext.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_ext.o: ../../include/openssl/e_os.h ../../include/openssl/e_os.h
+ocsp_ext.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
+ocsp_ext.o: ../../include/openssl/evp.h ../../include/openssl/idea.h
+ocsp_ext.o: ../../include/openssl/lhash.h ../../include/openssl/md2.h
+ocsp_ext.o: ../../include/openssl/md4.h ../../include/openssl/md5.h
+ocsp_ext.o: ../../include/openssl/mdc2.h ../../include/openssl/obj_mac.h
+ocsp_ext.o: ../../include/openssl/objects.h ../../include/openssl/ocsp.h
+ocsp_ext.o: ../../include/openssl/opensslconf.h
+ocsp_ext.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_ext.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_ext.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_ext.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_ext.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_ext.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_ext.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_ext.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_ext.o: ../cryptlib.h
+ocsp_lib.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_lib.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_lib.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_lib.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_lib.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_lib.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_lib.o: ../../include/openssl/e_os.h ../../include/openssl/e_os.h
+ocsp_lib.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
+ocsp_lib.o: ../../include/openssl/evp.h ../../include/openssl/idea.h
+ocsp_lib.o: ../../include/openssl/lhash.h ../../include/openssl/md2.h
+ocsp_lib.o: ../../include/openssl/md4.h ../../include/openssl/md5.h
+ocsp_lib.o: ../../include/openssl/mdc2.h ../../include/openssl/obj_mac.h
+ocsp_lib.o: ../../include/openssl/objects.h ../../include/openssl/ocsp.h
+ocsp_lib.o: ../../include/openssl/opensslconf.h
+ocsp_lib.o: ../../include/openssl/opensslv.h ../../include/openssl/pem.h
+ocsp_lib.o: ../../include/openssl/pem2.h ../../include/openssl/pkcs7.h
+ocsp_lib.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_lib.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_lib.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_lib.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_lib.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_lib.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_lib.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_lib.o: ../cryptlib.h
+ocsp_req.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_req.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_req.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_req.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_req.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_req.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_req.o: ../../include/openssl/e_os.h ../../include/openssl/e_os2.h
+ocsp_req.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+ocsp_req.o: ../../include/openssl/idea.h ../../include/openssl/lhash.h
+ocsp_req.o: ../../include/openssl/md2.h ../../include/openssl/md4.h
+ocsp_req.o: ../../include/openssl/md5.h ../../include/openssl/mdc2.h
+ocsp_req.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
+ocsp_req.o: ../../include/openssl/ocsp.h ../../include/openssl/opensslconf.h
+ocsp_req.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_req.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_req.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_req.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_req.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_req.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_req.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_req.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_res.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_res.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_res.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_res.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_res.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_res.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_res.o: ../../include/openssl/e_os.h ../../include/openssl/e_os2.h
+ocsp_res.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+ocsp_res.o: ../../include/openssl/idea.h ../../include/openssl/lhash.h
+ocsp_res.o: ../../include/openssl/md2.h ../../include/openssl/md4.h
+ocsp_res.o: ../../include/openssl/md5.h ../../include/openssl/mdc2.h
+ocsp_res.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
+ocsp_res.o: ../../include/openssl/ocsp.h ../../include/openssl/opensslconf.h
+ocsp_res.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_res.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_res.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_res.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_res.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_res.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_res.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_res.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ocsp_sig.o: ../../include/openssl/asn1.h ../../include/openssl/asn1_mac.h
+ocsp_sig.o: ../../include/openssl/bio.h ../../include/openssl/blowfish.h
+ocsp_sig.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
+ocsp_sig.o: ../../include/openssl/cast.h ../../include/openssl/conf.h
+ocsp_sig.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
+ocsp_sig.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
+ocsp_sig.o: ../../include/openssl/e_os.h ../../include/openssl/e_os2.h
+ocsp_sig.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+ocsp_sig.o: ../../include/openssl/idea.h ../../include/openssl/lhash.h
+ocsp_sig.o: ../../include/openssl/md2.h ../../include/openssl/md4.h
+ocsp_sig.o: ../../include/openssl/md5.h ../../include/openssl/mdc2.h
+ocsp_sig.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
+ocsp_sig.o: ../../include/openssl/ocsp.h ../../include/openssl/opensslconf.h
+ocsp_sig.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
+ocsp_sig.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
+ocsp_sig.o: ../../include/openssl/rc5.h ../../include/openssl/rd_fst.h
+ocsp_sig.o: ../../include/openssl/rijndael.h ../../include/openssl/ripemd.h
+ocsp_sig.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
+ocsp_sig.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ocsp_sig.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ocsp_sig.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h
new file mode 100644
index 0000000000..4899a1ae49
--- /dev/null
+++ b/crypto/ocsp/ocsp.h
@@ -0,0 +1,595 @@
+/* ocsp.h */
+/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
+ * project. */
+
+/* History:
+ This file was transfered to Richard Levitte from CertCo by Kathy
+ Weinhold in mid-spring 2000 to be included in OpenSSL or released
+ as a patch kit. */
+
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_OCSP_H
+#define HEADER_OCSP_H
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/safestack.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key (excluding the tag & length fields)
+ * serialNumber CertificateSerialNumber }
+ */
+typedef struct ocsp_cert_id_st
+ {
+ X509_ALGOR *hashAlgorithm;
+ ASN1_OCTET_STRING *issuerNameHash;
+ ASN1_OCTET_STRING *issuerKeyHash;
+ ASN1_INTEGER *serialNumber;
+ } OCSP_CERTID;
+
+/* Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_one_request_st
+ {
+ OCSP_CERTID *reqCert;
+ STACK_OF(X509_EXTENSION) *singleRequestExtensions;
+ } OCSP_ONEREQ;
+
+DECLARE_STACK_OF(OCSP_ONEREQ)
+DECLARE_ASN1_SET_OF(OCSP_ONEREQ)
+
+
+/* TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_req_info_st
+ {
+ ASN1_INTEGER *version;
+ GENERAL_NAME *requestorName;
+ STACK_OF(OCSP_ONEREQ) *requestList;
+ STACK_OF(X509_EXTENSION) *requestExtensions;
+ } OCSP_REQINFO;
+
+/* Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct ocsp_signature_st
+ {
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+ } OCSP_SIGNATURE;
+
+/* OCSPRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ */
+typedef struct ocsp_request_st
+ {
+ OCSP_REQINFO *tbsRequest;
+ OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */
+ } OCSP_REQUEST;
+
+/* OCSPResponseStatus ::= ENUMERATED {
+ * successful (0), --Response has valid confirmations
+ * malformedRequest (1), --Illegal confirmation request
+ * internalError (2), --Internal error in issuer
+ * tryLater (3), --Try again later
+ * --(4) is not used
+ * sigRequired (5), --Must sign the request
+ * unauthorized (6) --Request unauthorized
+ * }
+ */
+#define OCSP_RESPONSE_STATUS_SUCCESSFULL 0
+#define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST 1
+#define OCSP_RESPONSE_STATUS_INTERNALERROR 2
+#define OCSP_RESPONSE_STATUS_TRYLATER 3
+#define OCSP_RESPONSE_STATUS_SIGREQUIRED 5
+#define OCSP_RESPONSE_STATUS_UNAUTHORIZED 6
+
+/* ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+typedef struct ocsp_resp_bytes_st
+ {
+ ASN1_OBJECT *responseType;
+ ASN1_OCTET_STRING *response;
+ } OCSP_RESPBYTES;
+
+/* OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct ocsp_response_st
+ {
+ ASN1_ENUMERATED *responseStatus;
+ OCSP_RESPBYTES *responseBytes;
+ } OCSP_RESPONSE;
+
+/* ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ */
+#define V_OCSP_RESPID_NAME 1
+#define V_OCSP_RESPID_KEY 2
+typedef struct ocsp_responder_id_st
+ {
+ int tag;
+ union {
+ X509_NAME* byName;
+ ASN1_OCTET_STRING *byKey;
+ } value;
+ } OCSP_RESPID;
+/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
+ * --(excluding the tag and length fields)
+ */
+
+/* RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct ocsp_revoked_info_st
+ {
+ ASN1_GENERALIZEDTIME *revocationTime;
+ ASN1_ENUMERATED *revocationReason;
+ } OCSP_REVOKEDINFO;
+
+/* CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ */
+#define V_OCSP_CERTSTATUS_GOOD 0
+#define V_OCSP_CERTSTATUS_REVOKED 1
+#define V_OCSP_CERTSTATUS_UNKNOWN 2
+typedef struct ocsp_cert_status_st
+ {
+ int tag;
+ /* good [0] IMPLICIT NULL */
+ OCSP_REVOKEDINFO *revoked;
+ /* unknown [2] OCSP_UNKNOWNINFO *unknown, which is NULL */
+ } OCSP_CERTSTATUS;
+
+/* SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_single_response_st
+ {
+ OCSP_CERTID *certId;
+ OCSP_CERTSTATUS *certStatus;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ STACK_OF(X509_EXTENSION) *singleExtensions;
+ } OCSP_SINGLERESP;
+
+DECLARE_STACK_OF(OCSP_SINGLERESP)
+DECLARE_ASN1_SET_OF(OCSP_SINGLERESP)
+
+/* ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_response_data_st
+ {
+ ASN1_INTEGER *version;
+ OCSP_RESPID *responderId;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(OCSP_SINGLERESP) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+ } OCSP_RESPDATA;
+
+/* BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+ /* Note 1:
+ The value for "signature" is specified in the OCSP rfc2560 as follows:
+ "The value for the signature SHALL be computed on the hash of the DER
+ encoding ResponseData." This means that you must hash the DER-encoded
+ tbsResponseData, and then run it through a crypto-signing function, which
+ will (at least w/RSA) do a hash-'n'-private-encrypt operation. This seems
+ a bit odd, but that's the spec. Also note that the data structures do not
+ leave anywhere to independently specify the algorithm used for the initial
+ hash. So, we look at the signature-specification algorithm, and try to do
+ something intelligent. -- Kathy Weinhold, CertCo */
+ /* Note 2:
+ It seems that the mentioned passage from RFC 2560 (section 4.2.1) is open
+ for interpretation. I've done tests against another responder, and found
+ that it doesn't do the double hashing that the RFC seems to say one
+ should. Therefore, all relevant functions take a flag saying which
+ variant should be used. -- Richard Levitte, OpenSSL team and CeloCom */
+typedef struct ocsp_basic_response_st
+ {
+ OCSP_RESPDATA *tbsResponseData;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+ } OCSP_BASICRESP;
+
+/*
+ * CRLReason ::= ENUMERATED {
+ * unspecified (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6),
+ * removeFromCRL (8) }
+ */
+#define OCSP_REVOKED_STATUS_NOSTATUS -1
+#define OCSP_REVOKED_STATUS_UNSPECIFIED 0
+#define OCSP_REVOKED_STATUS_KEYCOMPROMISE 1
+#define OCSP_REVOKED_STATUS_CACOMPROMISE 2
+#define OCSP_REVOKED_STATUS_AFFILIATIONCHANGED 3
+#define OCSP_REVOKED_STATUS_SUPERSEDED 4
+#define OCSP_REVOKED_STATUS_CESSATIONOFOPERATION 5
+#define OCSP_REVOKED_STATUS_CERTIFICATEHOLD 6
+#define OCSP_REVOKED_STATUS_REMOVEFROMCRL 8
+
+/* CrlID ::= SEQUENCE {
+ * crlUrl [0] EXPLICIT IA5String OPTIONAL,
+ * crlNum [1] EXPLICIT INTEGER OPTIONAL,
+ * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }
+ */
+typedef struct ocsp_crl_id_st
+ {
+ ASN1_IA5STRING *crlUrl;
+ ASN1_INTEGER *crlNum;
+ ASN1_GENERALIZEDTIME *crlTime;
+ } OCSP_CRLID;
+
+/* ServiceLocator ::= SEQUENCE {
+ * issuer Name,
+ * locator AuthorityInfoAccessSyntax OPTIONAL }
+ */
+typedef struct ocsp_service_locator_st
+ {
+ X509_NAME* issuer;
+ STACK_OF(ACCESS_DESCRIPTION) *locator;
+ } OCSP_SERVICELOC;
+
+#define PEM_STRING_OCSP_REQUEST "OCSP REQUEST"
+#define PEM_STRING_OCSP_RESPONSE "OCSP RESPONSE"
+
+#define d2i_OCSP_REQUEST_bio(bp,p) (OCSP_REQUEST*)ASN1_d2i_bio((char*(*)()) \
+ OCSP_REQUEST_new,(char *(*)())d2i_OCSP_REQUEST, (bp),\
+ (unsigned char **)(p))
+
+#define d2i_OCSP_RESPONSE_bio(bp,p) (OCSP_RESPONSE*)ASN1_d2i_bio((char*(*)())\
+ OCSP_REQUEST_new,(char *(*)())d2i_OCSP_RESPONSE, (bp),\
+ (unsigned char **)(p))
+
+#define PEM_read_bio_OCSP_REQUEST(bp,x,cb) (OCSP_REQUEST *)PEM_ASN1_read_bio( \
+ (char *(*)())d2i_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,bp,(char **)x,cb,NULL)
+
+#define PEM_read_bio_OCSP_RESPONSE(bp,x,cb)(OCSP_RESPONSE *)PEM_ASN1_read_bio(\
+ (char *(*)())d2i_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,bp,(char **)x,cb,NULL)
+
+#define PEM_write_bio_OCSP_REQUEST(bp,o) \
+ PEM_ASN1_write_bio((int (*)())i2d_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,\
+ bp,(char *)o, NULL,NULL,0,NULL,NULL)
+
+#define PEM_write_bio_OCSP_RESPONSE(bp,o) \
+ PEM_ASN1_write_bio((int (*)())i2d_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,\
+ bp,(char *)o, NULL,NULL,0,NULL,NULL)
+
+#define i2d_OCSP_RESPONSE_bio(bp,o) ASN1_i2d_bio(i2d_OCSP_RESPONSE,bp,\
+ (unsigned char *)o)
+
+#define i2d_OCSP_REQUEST_bio(bp,o) ASN1_i2d_bio(i2d_OCSP_REQUEST,bp,\
+ (unsigned char *)o)
+
+#define OCSP_REQUEST_sign(o,pkey,md) \
+ ASN1_sign((int(*)())i2d_OCSP_REQINFO,\
+ o->optionalSignature->signatureAlgorithm,NULL,\
+ o->optionalSignature->signature,(char *)o->tbsRequest,pkey,md)
+
+#define OCSP_BASICRESP_sign(o,pkey,md,d) \
+ ASN1_sign((int(*)())i2d_OCSP_RESPDATA,o->signatureAlgorithm,NULL,\
+ o->signature,(char *)o->tbsResponseData,pkey,md)
+
+#define OCSP_REQUEST_verify(a,r) ASN1_verify((int (*)())i2d_OCSP_REQINFO,\
+ a->optionalSignature->signatureAlgorithm,\
+ a->optionalSignature->signature,(char *)a->tbsRequest,r)
+
+#define OCSP_BASICRESP_verify(a,r,d) ASN1_verify((int (*)())i2d_OCSP_RESPDATA,\
+ a->signatureAlgorithm,a->signature,(char *)a->tbsResponseData,r)
+
+#define ASN1_BIT_STRING_digest(data,type,md,len) \
+ ASN1_digest((int (*)())i2d_ASN1_BIT_STRING,type,(char *)data,md,len)
+
+#define OCSP_CERTID_dup(cid) (OCSP_CERTID*)ASN1_dup((int(*)())i2d_OCSP_CERTID,\
+ (char *(*)())d2i_OCSP_CERTID,(char *)(cid))
+
+#define OCSP_CERTSTATUS_dup(cs)\
+ (OCSP_CERTSTATUS*)ASN1_dup((int(*)())i2d_OCSP_CERTSTATUS,\
+ (char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
+
+OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst,
+ X509_NAME *issuerName,
+ ASN1_BIT_STRING* issuerKey,
+ ASN1_INTEGER *serialNumber);
+
+OCSP_CERTSTATUS *OCSP_cert_status_new(int status, int reason, char *tim);
+
+OCSP_REQUEST *OCSP_request_new(X509_NAME* name,
+ STACK_OF(X509_EXTENSION) *extensions);
+
+int OCSP_request_add(OCSP_REQUEST *req,
+ OCSP_CERTID *cid,
+ STACK_OF(X509_EXTENSION) *extensions);
+
+int OCSP_request_sign(OCSP_REQUEST *req,
+ EVP_PKEY *key,
+ const EVP_MD *dgst,
+ STACK_OF(X509) *certs);
+
+int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey);
+
+OCSP_BASICRESP *OCSP_basic_response_new(int tag,
+ X509* cert,
+ STACK_OF(X509_EXTENSION) *extensions);
+
+int OCSP_basic_response_add(OCSP_BASICRESP *rsp,
+ OCSP_CERTID *cid,
+ OCSP_CERTSTATUS *cst,
+ char *thisUpdate,
+ char *nextUpdate,
+ STACK_OF(X509_EXTENSION) *extensions);
+
+int OCSP_basic_response_sign(OCSP_BASICRESP *brsp,
+ EVP_PKEY *key,
+ const EVP_MD *dgst,
+ STACK_OF(X509) *certs);
+
+int OCSP_response_verify(OCSP_RESPONSE *rsp, EVP_PKEY *pkey);
+
+int OCSP_basic_response_verify(OCSP_BASICRESP *rsp, EVP_PKEY *pkey);
+
+
+OCSP_RESPONSE *OCSP_response_new(int status,
+ int nid,
+ int (*i2d)(),
+ char *data);
+
+ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, int (*i2d)(),
+ char *data, STACK_OF(ASN1_OBJECT) *sk);
+
+X509_EXTENSION *OCSP_nonce_new(void *p, unsigned int len);
+
+X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim);
+
+X509_EXTENSION *OCSP_accept_responses_new(char **oids);
+
+X509_EXTENSION *OCSP_archive_cutoff_new(char* tim);
+
+X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls);
+
+OCSP_SINGLERESP *OCSP_SINGLERESP_new(void);
+void OCSP_SINGLERESP_free(OCSP_SINGLERESP *a);
+int i2d_OCSP_SINGLERESP(OCSP_SINGLERESP *a, unsigned char **pp);
+OCSP_SINGLERESP *d2i_OCSP_SINGLERESP(OCSP_SINGLERESP **a, unsigned char **pp, long length);
+int i2a_OCSP_SINGLERESP(BIO *bp, OCSP_SINGLERESP* a);
+
+OCSP_CERTSTATUS *OCSP_CERTSTATUS_new(void);
+void OCSP_CERTSTATUS_free(OCSP_CERTSTATUS *a);
+int i2d_OCSP_CERTSTATUS(OCSP_CERTSTATUS *a, unsigned char **pp);
+OCSP_CERTSTATUS *d2i_OCSP_CERTSTATUS(OCSP_CERTSTATUS **a, unsigned char **pp, long length);
+int i2a_OCSP_CERTSTATUS(BIO *bp, OCSP_CERTSTATUS* a);
+
+OCSP_REVOKEDINFO *OCSP_REVOKEDINFO_new(void);
+void OCSP_REVOKEDINFO_free(OCSP_REVOKEDINFO *a);
+int i2d_OCSP_REVOKEDINFO(OCSP_REVOKEDINFO *a, unsigned char **pp);
+OCSP_REVOKEDINFO *d2i_OCSP_REVOKEDINFO(OCSP_REVOKEDINFO **a, unsigned char **pp, long length);
+int i2a_OCSP_REVOKEDINFO(BIO *bp, OCSP_REVOKEDINFO* a);
+
+OCSP_BASICRESP *OCSP_BASICRESP_new(void);
+void OCSP_BASICRESP_free(OCSP_BASICRESP *a);
+int i2d_OCSP_BASICRESP(OCSP_BASICRESP *a, unsigned char **pp);
+OCSP_BASICRESP *d2i_OCSP_BASICRESP(OCSP_BASICRESP **a, unsigned char **pp, long length);
+int i2a_OCSP_BASICRESP(BIO *bp, OCSP_BASICRESP* a);
+
+OCSP_RESPDATA *OCSP_RESPDATA_new(void);
+void OCSP_RESPDATA_free(OCSP_RESPDATA *a);
+int i2d_OCSP_RESPDATA(OCSP_RESPDATA *a, unsigned char **pp);
+OCSP_RESPDATA *d2i_OCSP_RESPDATA(OCSP_RESPDATA **a, unsigned char **pp, long length);
+int i2a_OCSP_RESPDATA(BIO *bp, OCSP_RESPDATA* a);
+
+OCSP_RESPID *OCSP_RESPID_new(void);
+void OCSP_RESPID_free(OCSP_RESPID *a);
+int i2d_OCSP_RESPID(OCSP_RESPID *a, unsigned char **pp);
+OCSP_RESPID *d2i_OCSP_RESPID(OCSP_RESPID **a, unsigned char **pp, long length);
+int i2a_OCSP_RESPID(BIO *bp, OCSP_RESPID* a);
+
+OCSP_RESPONSE *OCSP_RESPONSE_new(void);
+void OCSP_RESPONSE_free(OCSP_RESPONSE *a);
+int i2d_OCSP_RESPONSE(OCSP_RESPONSE *a, unsigned char **pp);
+OCSP_RESPONSE *d2i_OCSP_RESPONSE(OCSP_RESPONSE **a, unsigned char **pp, long length);
+int i2a_OCSP_RESPONSE(BIO *bp, OCSP_RESPONSE* a);
+int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* a);
+
+OCSP_RESPBYTES *OCSP_RESPBYTES_new(void);
+void OCSP_RESPBYTES_free(OCSP_RESPBYTES *a);
+int i2d_OCSP_RESPBYTES(OCSP_RESPBYTES *a, unsigned char **pp);
+OCSP_RESPBYTES *d2i_OCSP_RESPBYTES(OCSP_RESPBYTES **a, unsigned char **pp, long length);
+int i2a_OCSP_RESPBYTES(BIO *bp, OCSP_RESPBYTES* a);
+
+OCSP_ONEREQ *OCSP_ONEREQ_new(void);
+void OCSP_ONEREQ_free(OCSP_ONEREQ *a);
+int i2d_OCSP_ONEREQ(OCSP_ONEREQ *a, unsigned char **pp);
+OCSP_ONEREQ *d2i_OCSP_ONEREQ(OCSP_ONEREQ **a, unsigned char **pp, long length);
+int i2a_OCSP_ONEREQ(BIO *bp, OCSP_ONEREQ* a);
+
+OCSP_CERTID *OCSP_CERTID_new(void);
+void OCSP_CERTID_free(OCSP_CERTID *a);
+int i2d_OCSP_CERTID(OCSP_CERTID *a, unsigned char **pp);
+OCSP_CERTID *d2i_OCSP_CERTID(OCSP_CERTID **a, unsigned char **pp, long length);
+int i2a_OCSP_CERTID(BIO *bp, OCSP_CERTID* a);
+
+OCSP_REQUEST *OCSP_REQUEST_new(void);
+void OCSP_REQUEST_free(OCSP_REQUEST *a);
+int i2d_OCSP_REQUEST(OCSP_REQUEST *a, unsigned char **pp);
+OCSP_REQUEST *d2i_OCSP_REQUEST(OCSP_REQUEST **a, unsigned char **pp, long length);
+int i2a_OCSP_REQUEST(BIO *bp, OCSP_REQUEST* a);
+int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST* a);
+
+OCSP_SIGNATURE *OCSP_SIGNATURE_new(void);
+void OCSP_SIGNATURE_free(OCSP_SIGNATURE *a);
+int i2d_OCSP_SIGNATURE(OCSP_SIGNATURE *a, unsigned char **pp);
+OCSP_SIGNATURE *d2i_OCSP_SIGNATURE(OCSP_SIGNATURE **a, unsigned char **pp, long length);
+int i2a_OCSP_SIGNATURE(BIO *bp, OCSP_SIGNATURE* a);
+
+OCSP_REQINFO *OCSP_REQINFO_new(void);
+void OCSP_REQINFO_free(OCSP_REQINFO *a);
+int i2d_OCSP_REQINFO(OCSP_REQINFO *a, unsigned char **pp);
+OCSP_REQINFO *d2i_OCSP_REQINFO(OCSP_REQINFO **a, unsigned char **pp, long length);
+int i2a_OCSP_REQINFO(BIO *bp, OCSP_REQINFO* a);
+
+OCSP_CRLID *OCSP_CRLID_new(void);
+void OCSP_CRLID_free(OCSP_CRLID *a);
+int i2d_OCSP_CRLID(OCSP_CRLID *a, unsigned char **pp);
+OCSP_CRLID *d2i_OCSP_CRLID(OCSP_CRLID **a, unsigned char **pp, long length);
+int i2a_OCSP_CRLID(BIO *bp, OCSP_CRLID* a);
+int OCSP_CRLID_print(BIO *bp, OCSP_CRLID *a, int ind);
+
+OCSP_SERVICELOC *OCSP_SERVICELOC_new(void);
+void OCSP_SERVICELOC_free(OCSP_SERVICELOC *a);
+int i2d_OCSP_SERVICELOC(OCSP_SERVICELOC *a, unsigned char **pp);
+OCSP_SERVICELOC *d2i_OCSP_SERVICELOC(OCSP_SERVICELOC **a, unsigned char **pp, long length);
+int i2a_OCSP_SERVICELOC(BIO *bp, OCSP_SERVICELOC* a);
+int OCSP_SERVICELOC_print(BIO *bp, OCSP_SERVICELOC* a, int ind);
+
+int OCSP_extensions_print(BIO *bp, STACK_OF(X509_EXTENSION) *sk, char *title);
+int OCSP_extension_print(BIO *bp, X509_EXTENSION *x, int ind);
+
+void ERR_load_OCSP_strings(void);
+
+#if 0 /* Not yet implemented */
+X509_EXTENSION *OCSP_nochain_new(void);
+#endif
+
+char* ocspResponseStatus2string(long s);
+char* ocspCertStatus2string(long s);
+char * cRLReason2string(long s);
+
+#if 0 /* Not yet implemented */
+void OCSP_add_standard_extension(void);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+
+/* Error codes for the OCSP functions. */
+
+/* Function codes. */
+#define OCSP_F_ASN1_STRING_ENCODE 106
+#define OCSP_F_BASIC_RESPONSE_NEW 100
+#define OCSP_F_BASIC_RESPONSE_VERIFY 101
+#define OCSP_F_CERT_ID_NEW 102
+#define OCSP_F_CERT_STATUS_NEW 103
+#define OCSP_F_REQUEST_VERIFY 104
+#define OCSP_F_RESPONSE_VERIFY 105
+#define OCSP_F_S2I_OCSP_NONCE 107
+#define OCSP_F_V2I_OCSP_CRLID 108
+
+/* Reason codes. */
+#define OCSP_R_BAD_DATA 108
+#define OCSP_R_BAD_TAG 100
+#define OCSP_R_DIGEST_ERR 101
+#define OCSP_R_FAILED_TO_OPEN 109
+#define OCSP_R_FAILED_TO_READ 110
+#define OCSP_R_FAILED_TO_STAT 111
+#define OCSP_R_MISSING_VALUE 112
+#define OCSP_R_NO_CERTIFICATE 102
+#define OCSP_R_NO_PUBLIC_KEY 103
+#define OCSP_R_NO_RESPONSE_DATA 104
+#define OCSP_R_NO_SIGNATURE 105
+#define OCSP_R_REVOKED_NO_TIME 106
+#define OCSP_R_UNKNOWN_NID 107
+#define OCSP_R_UNSUPPORTED_OPTION 113
+#define OCSP_R_VALUE_ALREADY 114
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/crypto/ocsp/ocsp_ext.c b/crypto/ocsp/ocsp_ext.c
new file mode 100644
index 0000000000..aac4edb1e5
--- /dev/null
+++ b/crypto/ocsp/ocsp_ext.c
@@ -0,0 +1,349 @@
+/* ocsp_ext.c */
+/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
+ * project. */
+
+/* History:
+ This file was transfered to Richard Levitte from CertCo by Kathy
+ Weinhold in mid-spring 2000 to be included in OpenSSL or released
+ as a patch kit. */
+
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <cryptlib.h>
+#include <openssl/objects.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/x509.h>
+#include <openssl/ocsp.h>
+#include <openssl/x509v3.h>
+
+/* Make sure we work well with older variants of OpenSSL */
+#ifndef OPENSSL_malloc
+#define OPENSSL_malloc Malloc
+#endif
+#ifndef OPENSSL_realloc
+#define OPENSSL_realloc Realloc
+#endif
+#ifndef OPENSSL_free
+#define OPENSSL_free Free
+#endif
+
+/* also CRL Entry Extensions */
+
+ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, int (*i2d)(),
+ char *data, STACK_OF(ASN1_OBJECT) *sk)
+ {
+ int i;
+ unsigned char *p, *b = NULL;
+
+ if (data)
+ {
+ if ((i=i2d(data,NULL)) <= 0) goto err;
+ if (!(b=p=(unsigned char*)OPENSSL_malloc((unsigned int)i)))
+ goto err;
+ if (i2d(data, &p) <= 0) goto err;
+ }
+ else if (sk)
+ {
+ if ((i=i2d_ASN1_SET_OF_ASN1_OBJECT(sk,NULL,i2d,V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL,IS_SEQUENCE))<=0) goto err;
+ if (!(b=p=(unsigned char*)OPENSSL_malloc((unsigned int)i)))
+ goto err;
+ if (i2d_ASN1_SET_OF_ASN1_OBJECT(sk,&p,i2d,V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL,IS_SEQUENCE)<=0) goto err;
+ }
+ else
+ {
+ OCSPerr(OCSP_F_ASN1_STRING_ENCODE,OCSP_R_BAD_DATA);
+ goto err;
+ }
+ if (!s && !(s = ASN1_STRING_new())) goto err;
+ if (!(ASN1_STRING_set(s, b, i))) goto err;
+ OPENSSL_free(b);
+ return s;
+err:
+ if (b) OPENSSL_free(b);
+ return NULL;
+ }
+
+X509_EXTENSION *OCSP_nonce_new(void *p, unsigned int len)
+ {
+ X509_EXTENSION *x=NULL;
+ if (!(x = X509_EXTENSION_new())) goto err;
+ if (!(x->object = OBJ_nid2obj(NID_id_pkix_OCSP_Nonce))) goto err;
+ if (!(ASN1_OCTET_STRING_set(x->value, p, len))) goto err;
+ return x;
+err:
+ if (x) X509_EXTENSION_free(x);
+ return NULL;
+ }
+
+X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim)
+ {
+ X509_EXTENSION *x = NULL;
+ OCSP_CRLID *cid = NULL;
+
+ if (!(cid = OCSP_CRLID_new())) goto err;
+ if (url)
+ {
+ if (!(cid->crlUrl = ASN1_IA5STRING_new())) goto err;
+ if (!(ASN1_STRING_set(cid->crlUrl, url, -1))) goto err;
+ }
+ if (n)
+ {
+ if (!(cid->crlNum = ASN1_INTEGER_new())) goto err;
+ if (!(ASN1_INTEGER_set(cid->crlNum, *n))) goto err;
+ }
+ if (tim)
+ {
+ if (!(cid->crlTime = ASN1_GENERALIZEDTIME_new())) goto err;
+ if (!(ASN1_GENERALIZEDTIME_set_string(cid->crlTime, tim)))
+ goto err;
+ }
+ if (!(x = X509_EXTENSION_new())) goto err;
+ if (!(x->object = OBJ_nid2obj(NID_id_pkix_OCSP_CrlID))) goto err;
+ if (!(ASN1_STRING_encode(x->value,i2d_OCSP_CRLID,(char*)cid,NULL)))
+ goto err;
+ OCSP_CRLID_free(cid);
+ return x;
+err:
+ if (x) X509_EXTENSION_free(x);
+ if (cid) OCSP_CRLID_free(cid);
+ return NULL;
+ }
+
+/* AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER */
+X509_EXTENSION *OCSP_accept_responses_new(char **oids)
+ {
+ int nid;
+ STACK_OF(ASN1_OBJECT) *sk = NULL;
+ ASN1_OBJECT *o = NULL;
+ X509_EXTENSION *x = NULL;
+
+ if (!(sk = sk_ASN1_OBJECT_new(NULL))) goto err;
+ while (oids && *oids)
+ {
+ if ((nid=OBJ_txt2nid(*oids))!=NID_undef&&(o=OBJ_nid2obj(nid)))
+ sk_ASN1_OBJECT_push(sk, o);
+ oids++;
+ }
+ if (!(x = X509_EXTENSION_new())) goto err;
+ if (!(x->object = OBJ_nid2obj(NID_id_pkix_OCSP_acceptableResponses)))
+ goto err;
+ if (!(ASN1_STRING_encode(x->value,i2d_ASN1_OBJECT,NULL,sk)))
+ goto err;
+ sk_ASN1_OBJECT_pop_free(sk, ASN1_OBJECT_free);
+ return x;
+err:
+ if (x) X509_EXTENSION_free(x);
+ if (sk) sk_ASN1_OBJECT_pop_free(sk, ASN1_OBJECT_free);
+ return NULL;
+ }
+
+/* ArchiveCutoff ::= GeneralizedTime */
+X509_EXTENSION *OCSP_archive_cutoff_new(char* tim)
+ {
+ X509_EXTENSION *x=NULL;
+ ASN1_GENERALIZEDTIME *gt = NULL;
+
+ if (!(gt = ASN1_GENERALIZEDTIME_new())) goto err;
+ if (!(ASN1_GENERALIZEDTIME_set_string(gt, tim))) goto err;
+ if (!(x = X509_EXTENSION_new())) goto err;
+ if (!(x->object=OBJ_nid2obj(NID_id_pkix_OCSP_archiveCutoff)))goto err;
+ if (!(ASN1_STRING_encode(x->value,i2d_ASN1_GENERALIZEDTIME,
+ (char*)gt,NULL))) goto err;
+ ASN1_GENERALIZEDTIME_free(gt);
+ return x;
+err:
+ if (gt) ASN1_GENERALIZEDTIME_free(gt);
+ if (x) X509_EXTENSION_free(x);
+ return NULL;
+ }
+
+/* per ACCESS_DESCRIPTION parameter are oids, of which there are currently
+ * two--NID_ad_ocsp, NID_id_ad_caIssuers--and GeneralName value. This
+ * method forces NID_ad_ocsp and uniformResourceLocator [6] IA5String.
+ */
+X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls)
+ {
+ X509_EXTENSION *x = NULL;
+ ASN1_IA5STRING *ia5 = NULL;
+ OCSP_SERVICELOC *sloc = NULL;
+ ACCESS_DESCRIPTION *ad = NULL;
+
+ if (!(sloc = OCSP_SERVICELOC_new())) goto err;
+ if (!(sloc->issuer = X509_NAME_dup(issuer))) goto err;
+ if (urls && *urls && !(sloc->locator = sk_ACCESS_DESCRIPTION_new(NULL))) goto err;
+ while (urls && *urls)
+ {
+ if (!(ad = ACCESS_DESCRIPTION_new())) goto err;
+ if (!(ad->method=OBJ_nid2obj(NID_ad_OCSP))) goto err;
+ if (!(ad->location = GENERAL_NAME_new())) goto err;
+ if (!(ia5 = ASN1_IA5STRING_new())) goto err;
+ if (!ASN1_STRING_set((ASN1_STRING*)ia5, *urls, -1)) goto err;
+ ad->location->type = GEN_URI;
+ ad->location->d.ia5 = ia5;
+ if (!sk_ACCESS_DESCRIPTION_push(sloc->locator, ad)) goto err;
+ urls++;
+ }
+ if (!(x = X509_EXTENSION_new())) goto err;
+ if (!(x->object = OBJ_nid2obj(NID_id_pkix_OCSP_serviceLocator)))
+ goto err;
+ if (!(ASN1_STRING_encode(x->value, i2d_OCSP_SERVICELOC,
+ (char*)sloc, NULL))) goto err;
+ OCSP_SERVICELOC_free(sloc);
+ return x;
+err:
+ if (x) X509_EXTENSION_free(x);
+ if (sloc) OCSP_SERVICELOC_free(sloc);
+ return NULL;
+ }
+
+int OCSP_extensions_print(BIO *bp,
+ STACK_OF(X509_EXTENSION) *sk,
+ char *title)
+ {
+ int i;
+ if (!sk) return 1;
+ if (BIO_printf(bp, "%s:\n", title) <= 0) return 0;
+ for (i=0; i<sk_X509_EXTENSION_num(sk); i++)
+ OCSP_extension_print(bp, sk_X509_EXTENSION_value(sk,i), 4);
+ return sk_X509_EXTENSION_num(sk);
+ }
+
+int OCSP_extension_print(BIO *bp,
+ X509_EXTENSION *x,
+ int ind)
+ {
+ int i, j;
+ STACK_OF(ASN1_OBJECT) *sk = NULL;
+ unsigned char *p;
+ OCSP_CRLID *crlid = NULL;
+ OCSP_SERVICELOC *sloc = NULL;
+ ASN1_GENERALIZEDTIME *gt = NULL;
+
+ if (!x) return 1;
+ switch (OBJ_obj2nid(x->object))
+ {
+ case NID_id_pkix_OCSP_Nonce:
+ if (BIO_printf(bp, "%*snonce: ", ind, "") <= 0)
+ goto err;
+ if (M_ASN1_OCTET_STRING_print(bp, x->value) <= 0)
+ goto err;
+ if (BIO_write(bp, "\n", 1) <= 0) goto err;
+ break;
+ case NID_id_pkix_OCSP_CrlID:
+ if (BIO_printf(bp, "%*scrlId:\n", ind, "") <= 0)
+ goto err;
+ p = x->value->data;
+ if (!(d2i_OCSP_CRLID(&crlid, &p, x->value->length)))
+ goto err;
+ if (!OCSP_CRLID_print(bp, crlid, (2*ind))) goto err;
+ OCSP_CRLID_free(crlid);
+ break;
+ case NID_id_pkix_OCSP_acceptableResponses:
+ if (BIO_printf(bp,
+ "%*sacceptable responses: ",
+ ind, "") <= 0)
+ goto err;
+ p = x->value->data;
+ if (!(d2i_ASN1_SET_OF_ASN1_OBJECT(&sk, &p, x->value->length,
+ d2i_ASN1_OBJECT,
+ ASN1_OBJECT_free,
+ V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL)))
+ goto err;
+ for (i = 0; i < sk_ASN1_OBJECT_num(sk); i++)
+ {
+ j=OBJ_obj2nid(sk_ASN1_OBJECT_value(sk,i));
+ if (BIO_printf(bp," %s ",
+ (j == NID_undef)?"UNKNOWN":
+ OBJ_nid2ln(j)) <= 0)
+ goto err;
+ }
+ if (BIO_write(bp, "\n", 1) <= 0) goto err;
+ sk_ASN1_OBJECT_pop_free(sk, ASN1_OBJECT_free);
+ break;
+ case NID_id_pkix_OCSP_archiveCutoff:
+ if (BIO_printf(bp, "%*sarchive cutoff: ", ind, "")<=0)
+ goto err;
+ p = x->value->data;
+ if (!d2i_ASN1_GENERALIZEDTIME(&gt, &p,
+ x->value->length))
+ goto err;
+ if (!ASN1_GENERALIZEDTIME_print(bp, gt)) goto err;
+ if (BIO_write(bp, "\n", 1) <= 0) goto err;
+ ASN1_GENERALIZEDTIME_free(gt);
+ break;
+ case NID_id_pkix_OCSP_serviceLocator:
+ if (BIO_printf(bp, "%*sservice locator:\n", ind, "") <= 0)
+ goto err;
+ p = x->value->data;
+ if (!d2i_OCSP_SERVICELOC(&sloc, &p,
+ x->value->length))
+ goto err;
+ if (!OCSP_SERVICELOC_print(bp,sloc,(2*ind))) goto err;
+ OCSP_SERVICELOC_free(sloc);
+ break;
+ case NID_undef:
+ default:
+ if (BIO_printf(bp,"%*sunrecognized oid: ",ind,"") <= 0)
+ goto err;
+ break;
+ }
+ return 1;
+err:
+ return 0;
+ }
diff --git a/crypto/rijndael/.cvsignore b/crypto/rijndael/.cvsignore
new file mode 100644
index 0000000000..c6d03a9dbc
--- /dev/null
+++ b/crypto/rijndael/.cvsignore
@@ -0,0 +1,2 @@
+lib
+Makefile.save
diff --git a/crypto/rijndael/rd_fst.c b/crypto/rijndael/rd_fst.c
new file mode 100755
index 0000000000..f856cee3a8
--- /dev/null
+++ b/crypto/rijndael/rd_fst.c
@@ -0,0 +1,476 @@
+/*
+ * rijndael-alg-fst.c v2.4 April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * authors: v1.0: Antoon Bosselaers
+ * v2.0: Vincent Rijmen
+ * v2.3: Paulo Barreto
+ * v2.4: Vincent Rijmen
+ *
+ * This code is placed in the public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rd_fst.h"
+
+#include "boxes-fst-corrected.dat"
+
+int rijndaelKeySched(const word8 k[RIJNDAEL_MAXKC][4],
+ word8 W[RIJNDAEL_MAXROUNDS+1][4][4],int ROUNDS)
+ {
+ /* Calculate the necessary round keys
+ * The number of calculations depends on keyBits and blockBits
+ */
+ int j, r, t, rconpointer = 0;
+ word8 tk[RIJNDAEL_MAXKC][4];
+ int KC = ROUNDS - 6;
+
+ for (j = KC-1; j >= 0; j--)
+ *((word32*)tk[j]) = *((word32*)k[j]);
+ r = 0;
+ t = 0;
+ /* copy values into round key array */
+ for (j = 0; (j < KC) && (r < ROUNDS + 1); )
+ {
+ for (; (j < KC) && (t < 4); j++, t++)
+ *((word32*)W[r][t]) = *((word32*)tk[j]);
+ if (t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+
+ while (r < ROUNDS + 1)
+ { /* while not enough round key material calculated */
+ /* calculate new values */
+ tk[0][0] ^= S[tk[KC-1][1]];
+ tk[0][1] ^= S[tk[KC-1][2]];
+ tk[0][2] ^= S[tk[KC-1][3]];
+ tk[0][3] ^= S[tk[KC-1][0]];
+ tk[0][0] ^= rcon[rconpointer++];
+
+ if (KC != 8)
+ {
+ for (j = 1; j < KC; j++)
+ {
+ *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+ }
+ }
+ else
+ {
+ for (j = 1; j < KC/2; j++)
+ {
+ *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+ }
+ tk[KC/2][0] ^= S[tk[KC/2 - 1][0]];
+ tk[KC/2][1] ^= S[tk[KC/2 - 1][1]];
+ tk[KC/2][2] ^= S[tk[KC/2 - 1][2]];
+ tk[KC/2][3] ^= S[tk[KC/2 - 1][3]];
+ for (j = KC/2 + 1; j < KC; j++)
+ {
+ *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+ }
+ }
+ /* copy values into round key array */
+ for (j = 0; (j < KC) && (r < ROUNDS + 1); )
+ {
+ for (; (j < KC) && (t < 4); j++, t++)
+ {
+ *((word32*)W[r][t]) = *((word32*)tk[j]);
+ }
+ if (t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+ }
+ return 0;
+ }
+
+int rijndaelKeyEncToDec(word8 W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS)
+ {
+ int r;
+ word8 *w;
+
+ for (r = 1; r < ROUNDS; r++)
+ {
+ w = W[r][0];
+ *((word32*)w) =
+ *((word32*)U1[w[0]])
+ ^ *((word32*)U2[w[1]])
+ ^ *((word32*)U3[w[2]])
+ ^ *((word32*)U4[w[3]]);
+
+ w = W[r][1];
+ *((word32*)w) =
+ *((word32*)U1[w[0]])
+ ^ *((word32*)U2[w[1]])
+ ^ *((word32*)U3[w[2]])
+ ^ *((word32*)U4[w[3]]);
+
+ w = W[r][2];
+ *((word32*)w) =
+ *((word32*)U1[w[0]])
+ ^ *((word32*)U2[w[1]])
+ ^ *((word32*)U3[w[2]])
+ ^ *((word32*)U4[w[3]]);
+
+ w = W[r][3];
+ *((word32*)w) =
+ *((word32*)U1[w[0]])
+ ^ *((word32*)U2[w[1]])
+ ^ *((word32*)U3[w[2]])
+ ^ *((word32*)U4[w[3]]);
+ }
+ return 0;
+ }
+
+/**
+ * Encrypt a single block.
+ */
+int rijndaelEncrypt(const word8 a[16],word8 b[16],
+ word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS)
+ {
+ int r;
+ word8 temp[4][4];
+
+ *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]);
+ *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]);
+ *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]);
+ *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]);
+ *((word32*)(b )) = *((word32*)T1[temp[0][0]])
+ ^ *((word32*)T2[temp[1][1]])
+ ^ *((word32*)T3[temp[2][2]])
+ ^ *((word32*)T4[temp[3][3]]);
+ *((word32*)(b + 4)) = *((word32*)T1[temp[1][0]])
+ ^ *((word32*)T2[temp[2][1]])
+ ^ *((word32*)T3[temp[3][2]])
+ ^ *((word32*)T4[temp[0][3]]);
+ *((word32*)(b + 8)) = *((word32*)T1[temp[2][0]])
+ ^ *((word32*)T2[temp[3][1]])
+ ^ *((word32*)T3[temp[0][2]])
+ ^ *((word32*)T4[temp[1][3]]);
+ *((word32*)(b +12)) = *((word32*)T1[temp[3][0]])
+ ^ *((word32*)T2[temp[0][1]])
+ ^ *((word32*)T3[temp[1][2]])
+ ^ *((word32*)T4[temp[2][3]]);
+ for (r = 1; r < ROUNDS-1; r++)
+ {
+ *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]);
+ *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
+ *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
+ *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
+
+ *((word32*)(b )) = *((word32*)T1[temp[0][0]])
+ ^ *((word32*)T2[temp[1][1]])
+ ^ *((word32*)T3[temp[2][2]])
+ ^ *((word32*)T4[temp[3][3]]);
+ *((word32*)(b + 4)) = *((word32*)T1[temp[1][0]])
+ ^ *((word32*)T2[temp[2][1]])
+ ^ *((word32*)T3[temp[3][2]])
+ ^ *((word32*)T4[temp[0][3]]);
+ *((word32*)(b + 8)) = *((word32*)T1[temp[2][0]])
+ ^ *((word32*)T2[temp[3][1]])
+ ^ *((word32*)T3[temp[0][2]])
+ ^ *((word32*)T4[temp[1][3]]);
+ *((word32*)(b +12)) = *((word32*)T1[temp[3][0]])
+ ^ *((word32*)T2[temp[0][1]])
+ ^ *((word32*)T3[temp[1][2]])
+ ^ *((word32*)T4[temp[2][3]]);
+ }
+ /* last round is special */
+ *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[ROUNDS-1][0]);
+ *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]);
+ *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]);
+ *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]);
+ b[ 0] = T1[temp[0][0]][1];
+ b[ 1] = T1[temp[1][1]][1];
+ b[ 2] = T1[temp[2][2]][1];
+ b[ 3] = T1[temp[3][3]][1];
+ b[ 4] = T1[temp[1][0]][1];
+ b[ 5] = T1[temp[2][1]][1];
+ b[ 6] = T1[temp[3][2]][1];
+ b[ 7] = T1[temp[0][3]][1];
+ b[ 8] = T1[temp[2][0]][1];
+ b[ 9] = T1[temp[3][1]][1];
+ b[10] = T1[temp[0][2]][1];
+ b[11] = T1[temp[1][3]][1];
+ b[12] = T1[temp[3][0]][1];
+ b[13] = T1[temp[0][1]][1];
+ b[14] = T1[temp[1][2]][1];
+ b[15] = T1[temp[2][3]][1];
+ *((word32*)(b )) ^= *((word32*)rk[ROUNDS][0]);
+ *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]);
+ *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]);
+ *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]);
+
+ return 0;
+ }
+
+#ifdef INTERMEDIATE_VALUE_KAT
+/**
+ * Encrypt only a certain number of rounds.
+ * Only used in the Intermediate Value Known Answer Test.
+ */
+int rijndaelEncryptRound(word8 a[4][4],word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS, int rounds)
+ {
+ int r;
+ word8 temp[4][4];
+
+ /* make number of rounds sane */
+ if (rounds > ROUNDS)
+ {
+ rounds = ROUNDS;
+ }
+
+ *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]);
+ *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]);
+ *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]);
+ *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]);
+
+ for (r = 1; (r <= rounds) && (r < ROUNDS); r++) {
+ *((word32*)temp[0]) = *((word32*)T1[a[0][0]])
+ ^ *((word32*)T2[a[1][1]])
+ ^ *((word32*)T3[a[2][2]])
+ ^ *((word32*)T4[a[3][3]]);
+ *((word32*)temp[1]) = *((word32*)T1[a[1][0]])
+ ^ *((word32*)T2[a[2][1]])
+ ^ *((word32*)T3[a[3][2]])
+ ^ *((word32*)T4[a[0][3]]);
+ *((word32*)temp[2]) = *((word32*)T1[a[2][0]])
+ ^ *((word32*)T2[a[3][1]])
+ ^ *((word32*)T3[a[0][2]])
+ ^ *((word32*)T4[a[1][3]]);
+ *((word32*)temp[3]) = *((word32*)T1[a[3][0]])
+ ^ *((word32*)T2[a[0][1]])
+ ^ *((word32*)T3[a[1][2]])
+ ^ *((word32*)T4[a[2][3]]);
+ *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]);
+ *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]);
+ *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]);
+ *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]);
+ }
+ if (rounds == ROUNDS)
+ {
+ /* last round is special */
+ temp[0][0] = T1[a[0][0]][1];
+ temp[0][1] = T1[a[1][1]][1];
+ temp[0][2] = T1[a[2][2]][1];
+ temp[0][3] = T1[a[3][3]][1];
+ temp[1][0] = T1[a[1][0]][1];
+ temp[1][1] = T1[a[2][1]][1];
+ temp[1][2] = T1[a[3][2]][1];
+ temp[1][3] = T1[a[0][3]][1];
+ temp[2][0] = T1[a[2][0]][1];
+ temp[2][1] = T1[a[3][1]][1];
+ temp[2][2] = T1[a[0][2]][1];
+ temp[2][3] = T1[a[1][3]][1];
+ temp[3][0] = T1[a[3][0]][1];
+ temp[3][1] = T1[a[0][1]][1];
+ temp[3][2] = T1[a[1][2]][1];
+ temp[3][3] = T1[a[2][3]][1];
+ *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]);
+ *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]);
+ *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]);
+ *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]);
+ }
+
+ return 0;
+ }
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+/**
+ * Decrypt a single block.
+ */
+int rijndaelDecrypt(const word8 a[16],word8 b[16],
+ word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],int ROUNDS)
+ {
+ int r;
+ word8 temp[4][4];
+
+ *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]);
+ *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]);
+ *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]);
+ *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]);
+
+ *((word32*)(b )) = *((word32*)T5[temp[0][0]])
+ ^ *((word32*)T6[temp[3][1]])
+ ^ *((word32*)T7[temp[2][2]])
+ ^ *((word32*)T8[temp[1][3]]);
+ *((word32*)(b+ 4)) = *((word32*)T5[temp[1][0]])
+ ^ *((word32*)T6[temp[0][1]])
+ ^ *((word32*)T7[temp[3][2]])
+ ^ *((word32*)T8[temp[2][3]]);
+ *((word32*)(b+ 8)) = *((word32*)T5[temp[2][0]])
+ ^ *((word32*)T6[temp[1][1]])
+ ^ *((word32*)T7[temp[0][2]])
+ ^ *((word32*)T8[temp[3][3]]);
+ *((word32*)(b+12)) = *((word32*)T5[temp[3][0]])
+ ^ *((word32*)T6[temp[2][1]])
+ ^ *((word32*)T7[temp[1][2]])
+ ^ *((word32*)T8[temp[0][3]]);
+ for (r = ROUNDS-1; r > 1; r--)
+ {
+ *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]);
+ *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
+ *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
+ *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
+ *((word32*)(b )) = *((word32*)T5[temp[0][0]])
+ ^ *((word32*)T6[temp[3][1]])
+ ^ *((word32*)T7[temp[2][2]])
+ ^ *((word32*)T8[temp[1][3]]);
+ *((word32*)(b+ 4)) = *((word32*)T5[temp[1][0]])
+ ^ *((word32*)T6[temp[0][1]])
+ ^ *((word32*)T7[temp[3][2]])
+ ^ *((word32*)T8[temp[2][3]]);
+ *((word32*)(b+ 8)) = *((word32*)T5[temp[2][0]])
+ ^ *((word32*)T6[temp[1][1]])
+ ^ *((word32*)T7[temp[0][2]])
+ ^ *((word32*)T8[temp[3][3]]);
+ *((word32*)(b+12)) = *((word32*)T5[temp[3][0]])
+ ^ *((word32*)T6[temp[2][1]])
+ ^ *((word32*)T7[temp[1][2]])
+ ^ *((word32*)T8[temp[0][3]]);
+ }
+ /* last round is special */
+ *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[1][0]);
+ *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]);
+ *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]);
+ *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]);
+ b[ 0] = S5[temp[0][0]];
+ b[ 1] = S5[temp[3][1]];
+ b[ 2] = S5[temp[2][2]];
+ b[ 3] = S5[temp[1][3]];
+ b[ 4] = S5[temp[1][0]];
+ b[ 5] = S5[temp[0][1]];
+ b[ 6] = S5[temp[3][2]];
+ b[ 7] = S5[temp[2][3]];
+ b[ 8] = S5[temp[2][0]];
+ b[ 9] = S5[temp[1][1]];
+ b[10] = S5[temp[0][2]];
+ b[11] = S5[temp[3][3]];
+ b[12] = S5[temp[3][0]];
+ b[13] = S5[temp[2][1]];
+ b[14] = S5[temp[1][2]];
+ b[15] = S5[temp[0][3]];
+ *((word32*)(b )) ^= *((word32*)rk[0][0]);
+ *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]);
+ *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]);
+ *((word32*)(b+12)) ^= *((word32*)rk[0][3]);
+
+ return 0;
+ }
+
+#ifdef INTERMEDIATE_VALUE_KAT
+/**
+ * Decrypt only a certain number of rounds.
+ * Only used in the Intermediate Value Known Answer Test.
+ * Operations rearranged such that the intermediate values
+ * of decryption correspond with the intermediate values
+ * of encryption.
+ */
+int rijndaelDecryptRound(word8 a[4][4], word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS, int rounds)
+ {
+ int r, i;
+ word8 temp[4], shift;
+
+ /* make number of rounds sane */
+ if (rounds > ROUNDS)
+ {
+ rounds = ROUNDS;
+ }
+ /* first round is special: */
+ *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0];
+ *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1];
+ *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2];
+ *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3];
+ for (i = 0; i < 4; i++)
+ {
+ a[i][0] = Si[a[i][0]];
+ a[i][1] = Si[a[i][1]];
+ a[i][2] = Si[a[i][2]];
+ a[i][3] = Si[a[i][3]];
+ }
+ for (i = 1; i < 4; i++)
+ {
+ shift = (4 - i) & 3;
+ temp[0] = a[(0 + shift) & 3][i];
+ temp[1] = a[(1 + shift) & 3][i];
+ temp[2] = a[(2 + shift) & 3][i];
+ temp[3] = a[(3 + shift) & 3][i];
+ a[0][i] = temp[0];
+ a[1][i] = temp[1];
+ a[2][i] = temp[2];
+ a[3][i] = temp[3];
+ }
+ /* ROUNDS-1 ordinary rounds */
+ for (r = ROUNDS-1; r > rounds; r--)
+ {
+ *(word32 *)a[0] ^= *(word32 *)rk[r][0];
+ *(word32 *)a[1] ^= *(word32 *)rk[r][1];
+ *(word32 *)a[2] ^= *(word32 *)rk[r][2];
+ *(word32 *)a[3] ^= *(word32 *)rk[r][3];
+
+ *((word32*)a[0]) =
+ *((word32*)U1[a[0][0]])
+ ^ *((word32*)U2[a[0][1]])
+ ^ *((word32*)U3[a[0][2]])
+ ^ *((word32*)U4[a[0][3]]);
+
+ *((word32*)a[1]) =
+ *((word32*)U1[a[1][0]])
+ ^ *((word32*)U2[a[1][1]])
+ ^ *((word32*)U3[a[1][2]])
+ ^ *((word32*)U4[a[1][3]]);
+
+ *((word32*)a[2]) =
+ *((word32*)U1[a[2][0]])
+ ^ *((word32*)U2[a[2][1]])
+ ^ *((word32*)U3[a[2][2]])
+ ^ *((word32*)U4[a[2][3]]);
+
+ *((word32*)a[3]) =
+ *((word32*)U1[a[3][0]])
+ ^ *((word32*)U2[a[3][1]])
+ ^ *((word32*)U3[a[3][2]])
+ ^ *((word32*)U4[a[3][3]]);
+ for (i = 0; i < 4; i++)
+ {
+ a[i][0] = Si[a[i][0]];
+ a[i][1] = Si[a[i][1]];
+ a[i][2] = Si[a[i][2]];
+ a[i][3] = Si[a[i][3]];
+ }
+ for (i = 1; i < 4; i++)
+ {
+ shift = (4 - i) & 3;
+ temp[0] = a[(0 + shift) & 3][i];
+ temp[1] = a[(1 + shift) & 3][i];
+ temp[2] = a[(2 + shift) & 3][i];
+ temp[3] = a[(3 + shift) & 3][i];
+ a[0][i] = temp[0];
+ a[1][i] = temp[1];
+ a[2][i] = temp[2];
+ a[3][i] = temp[3];
+ }
+ }
+ if (rounds == 0)
+ {
+ /* End with the extra key addition */
+ *(word32 *)a[0] ^= *(word32 *)rk[0][0];
+ *(word32 *)a[1] ^= *(word32 *)rk[0][1];
+ *(word32 *)a[2] ^= *(word32 *)rk[0][2];
+ *(word32 *)a[3] ^= *(word32 *)rk[0][3];
+ }
+ return 0;
+ }
+
+#endif /* INTERMEDIATE_VALUE_KAT */
diff --git a/crypto/rijndael/rd_fst.h b/crypto/rijndael/rd_fst.h
new file mode 100755
index 0000000000..9a86e25cf7
--- /dev/null
+++ b/crypto/rijndael/rd_fst.h
@@ -0,0 +1,46 @@
+/*
+ * rijndael-alg-fst.h v2.4 April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test.
+ */
+
+#ifndef __RIJNDAEL_ALG_FST_H
+#define __RIJNDAEL_ALG_FST_H
+
+#define RIJNDAEL_MAXKC (256/32)
+#define RIJNDAEL_MAXROUNDS 14
+
+#ifndef USUAL_TYPES
+#define USUAL_TYPES
+typedef unsigned char byte;
+typedef unsigned char word8;
+typedef unsigned short word16;
+typedef unsigned int word32;
+#endif /* USUAL_TYPES */
+
+int rijndaelKeySched(const word8 k[RIJNDAEL_MAXKC][4],
+ word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS);
+
+int rijndaelKeyEncToDec(word8 W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+int rijndaelEncrypt(const word8 a[16],word8 b[16],
+ word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int rijndaelEncryptRound(word8 a[4][4],word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS, int rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+int rijndaelDecrypt(const word8 a[16], word8 b[16],
+ word8 rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int rijndaelDecryptRound(word8 a[4][4], word8 rk[RIJNDAEL_MAXROUNDS+1][4][4],
+ int ROUNDS, int rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+#endif /* __RIJNDAEL_ALG_FST_H */
diff --git a/demos/tunala/.cvsignore b/demos/tunala/.cvsignore
new file mode 100644
index 0000000000..1254a1ee29
--- /dev/null
+++ b/demos/tunala/.cvsignore
@@ -0,0 +1,2 @@
+tunala
+
diff --git a/demos/tunala/Makefile b/demos/tunala/Makefile
new file mode 100644
index 0000000000..a68db7a39d
--- /dev/null
+++ b/demos/tunala/Makefile
@@ -0,0 +1,41 @@
+# Edit these to suit
+#
+# Oh yeah, and please read the README too.
+
+
+SSL_HOMEDIR=../..
+SSL_INCLUDEDIR=$(SSL_HOMEDIR)/include
+SSL_LIBDIR=$(SSL_HOMEDIR)
+
+RM=rm -f
+CC=gcc
+DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow
+INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR)
+CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS)
+COMPILE=$(CC) $(CFLAGS) -c
+
+# Edit, particularly the "-ldl" if not building with "dlfcn" support
+LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl
+
+SRCS=buffer.c cb.c ip.c sm.c tunala.c
+OBJS=buffer.o cb.o ip.o sm.o tunala.o
+
+TARGETS=tunala
+
+default: $(TARGETS)
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) *.bak core
+
+.c.o:
+ $(COMPILE) $<
+
+tunala: $(OBJS)
+ $(CC) -o tunala $(OBJS) $(LINK_FLAGS)
+
+# Extra dependencies, should really use makedepend
+buffer.o: buffer.c tunala.h
+cb.o: cb.c tunala.h
+ip.o: ip.c tunala.h
+sm.o: sm.c tunala.h
+tunala.o: tunala.c tunala.h
diff --git a/demos/tunala/buffer.c b/demos/tunala/buffer.c
new file mode 100644
index 0000000000..2915f2c67b
--- /dev/null
+++ b/demos/tunala/buffer.c
@@ -0,0 +1,181 @@
+#include "tunala.h"
+
+#ifndef NO_BUFFER
+
+void buffer_init(buffer_t *buf)
+{
+ buf->used = 0;
+}
+
+void buffer_close(buffer_t *buf)
+{
+ /* Our data is static - nothing needs "release", just reset */
+ buffer_init(buf);
+}
+
+/* Code these simple ones in compact form */
+unsigned int buffer_used(buffer_t *buf) {
+ return buf->used; }
+unsigned int buffer_unused(buffer_t *buf) {
+ return (MAX_DATA_SIZE - buf->used); }
+int buffer_full(buffer_t *buf) {
+ return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
+int buffer_notfull(buffer_t *buf) {
+ return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
+int buffer_empty(buffer_t *buf) {
+ return (buf->used == 0 ? 1 : 0); }
+int buffer_notempty(buffer_t *buf) {
+ return (buf->used > 0 ? 1 : 0); }
+
+unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
+ unsigned int size)
+{
+ unsigned int added = MAX_DATA_SIZE - buf->used;
+ if(added > size)
+ added = size;
+ if(added == 0)
+ return 0;
+ memcpy(buf->data + buf->used, ptr, added);
+ buf->used += added;
+ return added;
+}
+
+unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
+ unsigned int size)
+{
+ unsigned int taken = buf->used;
+ if(taken > size)
+ taken = size;
+ if(taken == 0)
+ return 0;
+ if(ptr)
+ memcpy(ptr, buf->data, taken);
+ buf->used -= taken;
+ /* Do we have to scroll? */
+ if(buf->used > 0)
+ memmove(buf->data, buf->data + taken, buf->used);
+ return taken;
+}
+
+unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
+{
+ unsigned int moved, tomove = from->used;
+ if((int)tomove > cap)
+ tomove = cap;
+ if(tomove == 0)
+ return 0;
+ moved = buffer_adddata(to, from->data, tomove);
+ if(moved == 0)
+ return 0;
+ buffer_takedata(from, NULL, moved);
+ return moved;
+}
+
+#ifndef NO_IP
+
+int buffer_from_fd(buffer_t *buf, int fd)
+{
+ unsigned int toread = buffer_unused(buf);
+ if(toread == 0)
+ /* Shouldn't be called in this case! */
+ abort();
+ toread = read(fd, buf->data + buf->used, toread);
+ if(toread > 0)
+ buf->used += toread;
+ return toread;
+}
+
+int buffer_to_fd(buffer_t *buf, int fd)
+{
+ unsigned int towrite = buffer_used(buf);
+ if(towrite == 0)
+ /* Shouldn't be called in this case! */
+ abort();
+ towrite = write(fd, buf->data, towrite);
+ if(towrite > 0)
+ buffer_takedata(buf, NULL, towrite);
+ return towrite;
+}
+
+#endif /* !defined(NO_IP) */
+
+#ifndef NO_OPENSSL
+
+static void int_ssl_check(SSL *s, int ret)
+{
+ int e = SSL_get_error(s, ret);
+ switch(e) {
+ /* These seem to be harmless and already "dealt with" by our
+ * non-blocking environment. NB: "ZERO_RETURN" is the clean
+ * "error" indicating a successfully closed SSL tunnel. We let
+ * this happen because our IO loop should not appear to have
+ * broken on this condition - and outside the IO loop, the
+ * "shutdown" state is checked. */
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_ZERO_RETURN:
+ return;
+ /* These seem to be indications of a genuine error that should
+ * result in the SSL tunnel being regarded as "dead". */
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ SSL_set_app_data(s, (char *)1);
+ return;
+ default:
+ break;
+ }
+ /* For any other errors that (a) exist, and (b) crop up - we need to
+ * interpret what to do with them - so "politely inform" the caller that
+ * the code needs updating here. */
+ abort();
+}
+
+void buffer_from_SSL(buffer_t *buf, SSL *ssl)
+{
+ int ret;
+ if(!ssl || buffer_full(buf))
+ return;
+ ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
+ if(ret > 0)
+ buf->used += ret;
+ if(ret < 0)
+ int_ssl_check(ssl, ret);
+}
+
+void buffer_to_SSL(buffer_t *buf, SSL *ssl)
+{
+ int ret;
+ if(!ssl || buffer_empty(buf))
+ return;
+ ret = SSL_write(ssl, buf->data, buf->used);
+ if(ret > 0)
+ buffer_takedata(buf, NULL, ret);
+ if(ret < 0)
+ int_ssl_check(ssl, ret);
+}
+
+void buffer_from_BIO(buffer_t *buf, BIO *bio)
+{
+ int ret;
+ if(!bio || buffer_full(buf))
+ return;
+ ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
+ if(ret > 0)
+ buf->used += ret;
+}
+
+void buffer_to_BIO(buffer_t *buf, BIO *bio)
+{
+ int ret;
+ if(!bio || buffer_empty(buf))
+ return;
+ ret = BIO_write(bio, buf->data, buf->used);
+ if(ret > 0)
+ buffer_takedata(buf, NULL, ret);
+}
+
+#endif /* !defined(NO_OPENSSL) */
+
+#endif /* !defined(NO_BUFFER) */
diff --git a/demos/tunala/cb.c b/demos/tunala/cb.c
new file mode 100644
index 0000000000..ac7122da4f
--- /dev/null
+++ b/demos/tunala/cb.c
@@ -0,0 +1,133 @@
+#include "tunala.h"
+
+#ifndef NO_OPENSSL
+
+/* For callbacks generating output, here are their file-descriptors. */
+static FILE *fp_cb_ssl_info = NULL;
+static FILE *fp_cb_ssl_verify = NULL;
+/* Output level:
+ * 0 = nothing,
+ * 1 = minimal, just errors,
+ * 2 = minimal, all steps,
+ * 3 = detail, all steps */
+static unsigned int cb_ssl_verify_level = 1;
+
+/* Other static rubbish (to mirror s_cb.c where required) */
+static int int_verify_depth = 10;
+
+/* This function is largely borrowed from the one used in OpenSSL's "s_client"
+ * and "s_server" utilities. */
+void cb_ssl_info(SSL *s, int where, int ret)
+{
+ char *str1, *str2;
+ int w;
+
+ if(!fp_cb_ssl_info)
+ return;
+
+ w = where & ~SSL_ST_MASK;
+ str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
+ "SSL_accept" : "undefined")),
+ str2 = SSL_state_string_long(s);
+
+ if (where & SSL_CB_LOOP)
+ fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
+ else if (where & SSL_CB_EXIT) {
+ if (ret == 0)
+ fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
+/* In a non-blocking model, we get a few of these "error"s simply because we're
+ * calling "reads" and "writes" on the state-machine that are virtual NOPs
+ * simply to avoid wasting the time seeing if we *should* call them. Removing
+ * this case makes the "-out_state" output a lot easier on the eye. */
+#if 0
+ else if (ret < 0)
+ fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
+#endif
+ }
+}
+
+void cb_ssl_info_set_output(FILE *fp)
+{
+ fp_cb_ssl_info = fp;
+}
+
+static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
+static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
+static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
+static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
+static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
+
+/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
+int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
+{
+ char buf1[256]; /* Used for the subject name */
+ char buf2[256]; /* Used for the issuer name */
+ const char *reason = NULL; /* Error reason (if any) */
+ X509 *err_cert;
+ int err, depth;
+
+ if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
+ return ok;
+ err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ err = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ buf1[0] = buf2[0] = '\0';
+ /* Fill buf1 */
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
+ /* Fill buf2 */
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ reason = int_reason_no_issuer;
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ reason = int_reason_not_yet;
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ reason = int_reason_before;
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ reason = int_reason_expired;
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ reason = int_reason_after;
+ break;
+ }
+
+ if((cb_ssl_verify_level == 1) && ok)
+ return ok;
+ fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
+ if(reason)
+ fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
+ else
+ fprintf(fp_cb_ssl_verify, "error=%d\n", err);
+ if(cb_ssl_verify_level < 3)
+ return ok;
+ fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
+ fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2);
+ if(!ok)
+ fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err,
+ X509_verify_cert_error_string(err));
+ fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok);
+ return ok;
+}
+
+void cb_ssl_verify_set_output(FILE *fp)
+{
+ fp_cb_ssl_verify = fp;
+}
+
+void cb_ssl_verify_set_depth(unsigned int verify_depth)
+{
+ int_verify_depth = verify_depth;
+}
+
+void cb_ssl_verify_set_level(unsigned int level)
+{
+ if(level < 4)
+ cb_ssl_verify_level = level;
+}
+
+#endif /* !defined(NO_OPENSSL) */
+
diff --git a/demos/tunala/sm.c b/demos/tunala/sm.c
new file mode 100644
index 0000000000..c213d110d5
--- /dev/null
+++ b/demos/tunala/sm.c
@@ -0,0 +1,151 @@
+#include "tunala.h"
+
+#ifndef NO_TUNALA
+
+void state_machine_init(state_machine_t *machine)
+{
+ machine->ssl = NULL;
+ machine->bio_intossl = machine->bio_fromssl = NULL;
+ buffer_init(&machine->clean_in);
+ buffer_init(&machine->clean_out);
+ buffer_init(&machine->dirty_in);
+ buffer_init(&machine->dirty_out);
+}
+
+void state_machine_close(state_machine_t *machine)
+{
+ if(machine->ssl)
+ SSL_free(machine->ssl);
+/* SSL_free seems to decrement the reference counts already so doing this goes
+ * kaboom. */
+#if 0
+ if(machine->bio_intossl)
+ BIO_free(machine->bio_intossl);
+ if(machine->bio_fromssl)
+ BIO_free(machine->bio_fromssl);
+#endif
+ buffer_close(&machine->clean_in);
+ buffer_close(&machine->clean_out);
+ buffer_close(&machine->dirty_in);
+ buffer_close(&machine->dirty_out);
+ state_machine_init(machine);
+}
+
+buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
+{
+ switch(type) {
+ case SM_CLEAN_IN:
+ return &machine->clean_in;
+ case SM_CLEAN_OUT:
+ return &machine->clean_out;
+ case SM_DIRTY_IN:
+ return &machine->dirty_in;
+ case SM_DIRTY_OUT:
+ return &machine->dirty_out;
+ default:
+ break;
+ }
+ /* Should never get here */
+ abort();
+ return NULL;
+}
+
+SSL *state_machine_get_SSL(state_machine_t *machine)
+{
+ return machine->ssl;
+}
+
+int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
+{
+ if(machine->ssl)
+ /* Shouldn't ever be set twice */
+ abort();
+ machine->ssl = ssl;
+ /* Create the BIOs to handle the dirty side of the SSL */
+ if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
+ abort();
+ if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
+ abort();
+ /* Hook up the BIOs on the dirty side of the SSL */
+ SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
+ if(is_server)
+ SSL_set_accept_state(machine->ssl);
+ else
+ SSL_set_connect_state(machine->ssl);
+ /* If we're the first one to generate traffic - do it now otherwise we
+ * go into the next select empty-handed and our peer will not send data
+ * but will similarly wait for us. */
+ return state_machine_churn(machine);
+}
+
+/* Performs the data-IO loop and returns zero if the machine should close */
+int state_machine_churn(state_machine_t *machine)
+{
+ unsigned int loop;
+ /* Do this loop twice to cover any dependencies about which precise
+ * order of reads and writes is required. */
+ for(loop = 0; loop < 2; loop++) {
+ buffer_to_SSL(&machine->clean_in, machine->ssl);
+ buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
+ buffer_from_SSL(&machine->clean_out, machine->ssl);
+ buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
+ }
+ if(machine->ssl == NULL) {
+ if(buffer_empty(&machine->clean_out))
+ /* Time to close this state-machine altogether */
+ return 0;
+ else
+ /* Still buffered data on the clean side to go out */
+ return 1;
+ }
+ /* We close on the SSL side if the info callback noticed some problems
+ * or an SSL shutdown was underway and shutdown traffic had all been
+ * sent. */
+ if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
+ buffer_empty(&machine->dirty_out))) {
+ /* Great, we can seal off the dirty side completely */
+ if(!state_machine_close_dirty(machine))
+ return 0;
+ }
+ /* Either the SSL is alive and well, or the closing process still has
+ * outgoing data waiting to be sent */
+ return 1;
+}
+
+/* Called when the clean side of the SSL has lost its connection */
+int state_machine_close_clean(state_machine_t *machine)
+{
+ /* Well, first thing to do is null out the clean-side buffers - they're
+ * no use any more. */
+ buffer_close(&machine->clean_in);
+ buffer_close(&machine->clean_out);
+ /* And start an SSL shutdown */
+ if(machine->ssl)
+ SSL_shutdown(machine->ssl);
+ /* This is an "event", so flush the SSL of any generated traffic */
+ state_machine_churn(machine);
+ if(buffer_empty(&machine->dirty_in) &&
+ buffer_empty(&machine->dirty_out))
+ return 0;
+ return 1;
+}
+
+/* Called when the dirty side of the SSL has lost its connection. This is pretty
+ * terminal as all that can be left to do is send any buffered output on the
+ * clean side - after that, we're done. */
+int state_machine_close_dirty(state_machine_t *machine)
+{
+ buffer_close(&machine->dirty_in);
+ buffer_close(&machine->dirty_out);
+ buffer_close(&machine->clean_in);
+ if(machine->ssl)
+ SSL_free(machine->ssl);
+ machine->ssl = NULL;
+ machine->bio_intossl = machine->bio_fromssl = NULL;
+ if(buffer_empty(&machine->clean_out))
+ return 0;
+ return 1;
+}
+
+#endif /* !defined(NO_TUNALA) */
+
diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c
new file mode 100644
index 0000000000..2b3d65d98c
--- /dev/null
+++ b/demos/tunala/tunala.c
@@ -0,0 +1,885 @@
+#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
+#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
+#endif
+
+/* Include our bits'n'pieces */
+#include "tunala.h"
+
+
+/********************************************/
+/* Our local types that specify our "world" */
+/********************************************/
+
+/* These represent running "tunnels". Eg. if you wanted to do SSL in a
+ * "message-passing" scanario, the "int" file-descriptors might be replaced by
+ * thread or process IDs, and the "select" code might be replaced by message
+ * handling code. Whatever. */
+typedef struct _tunala_item_t {
+ /* The underlying SSL state machine. This is a data-only processing unit
+ * and we communicate with it by talking to its four "buffers". */
+ state_machine_t sm;
+ /* The file-descriptors for the "dirty" (encrypted) side of the SSL
+ * setup. In actuality, this is typically a socket and both values are
+ * identical. */
+ int dirty_read, dirty_send;
+ /* The file-descriptors for the "clean" (unencrypted) side of the SSL
+ * setup. These could be stdin/stdout, a socket (both values the same),
+ * or whatever you like. */
+ int clean_read, clean_send;
+} tunala_item_t;
+
+/* This structure is used as the data for running the main loop. Namely, in a
+ * network format such as this, it is stuff for select() - but as pointed out,
+ * when moving the real-world to somewhere else, this might be replaced by
+ * something entirely different. It's basically the stuff that controls when
+ * it's time to do some "work". */
+typedef struct _select_sets_t {
+ int max; /* As required as the first argument to select() */
+ fd_set reads, sends, excepts; /* As passed to select() */
+} select_sets_t;
+typedef struct _tunala_selector_t {
+ select_sets_t last_selected; /* Results of the last select() */
+ select_sets_t next_select; /* What we'll next select on */
+} tunala_selector_t;
+
+/* This structure is *everything*. We do it to avoid the use of globals so that,
+ * for example, it would be easier to shift things around between async-IO,
+ * thread-based, or multi-fork()ed (or combinations thereof). */
+typedef struct _tunala_world_t {
+ /* The file-descriptor we "listen" on for new connections */
+ int listen_fd;
+ /* The array of tunnels */
+ tunala_item_t *tunnels;
+ /* the number of tunnels in use and allocated, respectively */
+ unsigned int tunnels_used, tunnels_size;
+ /* Our outside "loop" context stuff */
+ tunala_selector_t selector;
+ /* Our SSL_CTX, which is configured as the SSL client or server and has
+ * the various cert-settings and callbacks configured. */
+ SSL_CTX *ssl_ctx;
+ /* Simple flag with complex logic :-) Indicates whether we're an SSL
+ * server or an SSL client. */
+ int server_mode;
+} tunala_world_t;
+
+/*****************************/
+/* Internal static functions */
+/*****************************/
+
+static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
+ const char *CAfile, const char *cert, const char *key,
+ const char *dcert, const char *dkey, const char *cipher_list,
+ int out_state, int out_verify, int verify_mode,
+ unsigned int verify_depth);
+static void selector_init(tunala_selector_t *selector);
+static void selector_add_listener(tunala_selector_t *selector, int fd);
+static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t);
+static int selector_select(tunala_selector_t *selector);
+/* This returns -1 for error, 0 for no new connections, or 1 for success, in
+ * which case *newfd is populated. */
+static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd);
+static int tunala_world_new_item(tunala_world_t *world, int fd,
+ const unsigned char *ip, unsigned short port);
+static void tunala_world_del_item(tunala_world_t *world, unsigned int idx);
+static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item);
+
+/*********************************************/
+/* MAIN FUNCTION (and its utility functions) */
+/*********************************************/
+
+static const char *def_proxyhost = "127.0.0.1:443";
+static const char *def_listenhost = "127.0.0.1:8080";
+static int def_max_tunnels = 50;
+static const char *def_cacert = NULL;
+static const char *def_cert = NULL;
+static const char *def_key = NULL;
+static const char *def_dcert = NULL;
+static const char *def_dkey = NULL;
+static const char *def_engine_id = NULL;
+static int def_server_mode = 0;
+static const char *def_cipher_list = NULL;
+static int def_out_state = 0;
+static unsigned int def_out_verify = 0;
+static int def_verify_mode = 0;
+static unsigned int def_verify_depth = 10;
+
+static const char *helpstring =
+"\n'Tunala' (A tunneler with a New Zealand accent)\n"
+"Usage: tunala [options], where options are from;\n"
+" -listen [host:]<port> (default = 127.0.0.1:8080)\n"
+" -proxy <host>:<port> (default = 127.0.0.1:443)\n"
+" -maxtunnels <num> (default = 50)\n"
+" -cacert <path|NULL> (default = NULL)\n"
+" -cert <path|NULL> (default = NULL)\n"
+" -key <path|NULL> (default = whatever '-cert' is)\n"
+" -dcert <path|NULL> (usually for DSA, default = NULL)\n"
+" -dkey <path|NULL> (usually for DSA, default = whatever '-dcert' is)\n"
+" -engine <id|NULL> (default = NULL)\n"
+" -server <0|1> (default = 0, ie. an SSL client)\n"
+" -cipher <list> (specifies cipher list to use)\n"
+" -out_state (prints SSL handshake states)\n"
+" -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n"
+" -v_peer (verify the peer certificate)\n"
+" -v_strict (do not continue if peer doesn't authenticate)\n"
+" -v_once (no verification in renegotiates)\n"
+" -v_depth <num> (limit certificate chain depth, default = 10)\n"
+" -<h|help|?> (displays this help screen)\n"
+"NB: It is recommended to specify a cert+key when operating as an\n"
+"SSL server. If you only specify '-cert', the same file must\n"
+"contain a matching private key.\n";
+
+static int usage(const char *errstr, int isunknownarg)
+{
+ if(isunknownarg)
+ fprintf(stderr, "Error: unknown argument '%s'\n", errstr);
+ else
+ fprintf(stderr, "Error: %s\n", errstr);
+ fprintf(stderr, "%s\n", helpstring);
+ return 1;
+}
+
+static int err_str0(const char *str0)
+{
+ fprintf(stderr, str0);
+ fprintf(stderr, "\n");
+ return 1;
+}
+
+static int err_str1(const char *str0, const char *str1)
+{
+ fprintf(stderr, str0, str1);
+ fprintf(stderr, "\n");
+ return 1;
+}
+
+static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
+{
+ unsigned long l;
+ char *temp;
+ l = strtoul(s, &temp, 10);
+ if((temp == s) || (*temp != '\0') || (l < 1) || (l > 1024)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "maxtunnels\n", s);
+ return 0;
+ }
+ *maxtunnels = (unsigned int)l;
+ return 1;
+}
+
+static int parse_server_mode(const char *s, int *servermode)
+{
+ unsigned long l;
+ char *temp;
+ l = strtoul(s, &temp, 10);
+ if((temp == s) || (*temp != '\0') || (l > 1)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for the "
+ "server mode\n", s);
+ return 0;
+ }
+ *servermode = (int)l;
+ return 1;
+}
+
+static int parse_verify_level(const char *s, unsigned int *verify_level)
+{
+ unsigned long l;
+ char *temp;
+ l = strtoul(s, &temp, 10);
+ if((temp == s) || (*temp != '\0') || (l > 3)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "out_verify\n", s);
+ return 0;
+ }
+ *verify_level = (unsigned int)l;
+ return 1;
+}
+
+static int parse_verify_depth(const char *s, unsigned int *verify_depth)
+{
+ unsigned long l;
+ char *temp;
+ l = strtoul(s, &temp, 10);
+ if((temp == s) || (*temp != '\0') || (l < 1) || (l > 50)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "verify_depth\n", s);
+ return 0;
+ }
+ *verify_depth = (unsigned int)l;
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int loop;
+ int newfd;
+ tunala_world_t world;
+ tunala_item_t *t_item;
+ unsigned char *proxy_ip;
+ unsigned short proxy_port;
+ /* Overridables */
+ const char *proxyhost = def_proxyhost;
+ const char *listenhost = def_listenhost;
+ unsigned int max_tunnels = def_max_tunnels;
+ const char *cacert = def_cacert;
+ const char *cert = def_cert;
+ const char *key = def_key;
+ const char *dcert = def_dcert;
+ const char *dkey = def_dkey;
+ const char *engine_id = def_engine_id;
+ int server_mode = def_server_mode;
+ const char *cipher_list = def_cipher_list;
+ int out_state = def_out_state;
+ unsigned int out_verify = def_out_verify;
+ int verify_mode = def_verify_mode;
+ unsigned int verify_depth = def_verify_depth;
+
+/* Parse command-line arguments */
+next_arg:
+ argc--; argv++;
+ if(argc > 0) {
+ if(strcmp(*argv, "-listen") == 0) {
+ if(argc < 2)
+ return usage("-listen requires an argument", 0);
+ argc--; argv++;
+ listenhost = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-proxy") == 0) {
+ if(argc < 2)
+ return usage("-proxy requires an argument", 0);
+ argc--; argv++;
+ proxyhost = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-maxtunnels") == 0) {
+ if(argc < 2)
+ return usage("-maxtunnels requires an argument", 0);
+ argc--; argv++;
+ if(!parse_max_tunnels(*argv, &max_tunnels))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cacert") == 0) {
+ if(argc < 2)
+ return usage("-cacert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ cacert = NULL;
+ else
+ cacert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cert") == 0) {
+ if(argc < 2)
+ return usage("-cert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ cert = NULL;
+ else
+ cert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-key") == 0) {
+ if(argc < 2)
+ return usage("-key requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ key = NULL;
+ else
+ key = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dcert") == 0) {
+ if(argc < 2)
+ return usage("-dcert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ dcert = NULL;
+ else
+ dcert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dkey") == 0) {
+ if(argc < 2)
+ return usage("-dkey requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ dkey = NULL;
+ else
+ dkey = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-engine") == 0) {
+ if(argc < 2)
+ return usage("-engine requires an argument", 0);
+ argc--; argv++;
+ engine_id = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-server") == 0) {
+ if(argc < 2)
+ return usage("-server requires an argument", 0);
+ argc--; argv++;
+ if(!parse_server_mode(*argv, &server_mode))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cipher") == 0) {
+ if(argc < 2)
+ return usage("-cipher requires an argument", 0);
+ argc--; argv++;
+ cipher_list = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_state") == 0) {
+ out_state = 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_verify") == 0) {
+ if(argc < 2)
+ return usage("-out_verify requires an argument", 0);
+ argc--; argv++;
+ if(!parse_verify_level(*argv, &out_verify))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_peer") == 0) {
+ verify_mode |= SSL_VERIFY_PEER;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_strict") == 0) {
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_once") == 0) {
+ verify_mode |= SSL_VERIFY_CLIENT_ONCE;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_depth") == 0) {
+ if(argc < 2)
+ return usage("-v_depth requires an argument", 0);
+ argc--; argv++;
+ if(!parse_verify_depth(*argv, &verify_depth))
+ return 1;
+ goto next_arg;
+ } else if((strcmp(*argv, "-h") == 0) ||
+ (strcmp(*argv, "-help") == 0) ||
+ (strcmp(*argv, "-?") == 0)) {
+ fprintf(stderr, "%s\n", helpstring);
+ return 0;
+ } else
+ return usage(*argv, 1);
+ }
+
+ /* Initialise network stuff */
+ if(!ip_initialise())
+ return err_str0("ip_initialise failed");
+ err_str0("ip_initialise succeeded");
+ /* Create the SSL_CTX */
+ if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
+ cacert, cert, key, dcert, dkey, cipher_list, out_state,
+ out_verify, verify_mode, verify_depth)) == NULL)
+ return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
+ (engine_id == NULL) ? "NULL" : engine_id);
+ err_str1("initialise_ssl_ctx(engine_id=%s) succeeded",
+ (engine_id == NULL) ? "NULL" : engine_id);
+ /* Create the listener */
+ if((world.listen_fd = ip_create_listener(listenhost)) == -1)
+ return err_str1("ip_create_listener(%s) failed", listenhost);
+ err_str1("ip_create_listener(%s) succeeded", listenhost);
+ if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
+ return err_str1("ip_parse_address(%s) failed", proxyhost);
+ err_str1("ip_parse_address(%s) succeeded", proxyhost);
+ fprintf(stderr, "Info - proxying to %d.%d.%d.%d:%d\n",
+ (int)proxy_ip[0], (int)proxy_ip[1],
+ (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
+ fprintf(stderr, "Info - set maxtunnels to %d\n", (int)max_tunnels);
+ fprintf(stderr, "Info - set to operate as an SSL %s\n",
+ (server_mode ? "server" : "client"));
+ /* Initialise the rest of the stuff */
+ world.tunnels_used = world.tunnels_size = 0;
+ world.tunnels = NULL;
+ world.server_mode = server_mode;
+ selector_init(&world.selector);
+
+/* We're ready to loop */
+main_loop:
+ /* Should we listen for *new* tunnels? */
+ if(world.tunnels_used < max_tunnels)
+ selector_add_listener(&world.selector, world.listen_fd);
+ /* We should add in our existing tunnels */
+ for(loop = 0; loop < world.tunnels_used; loop++)
+ selector_add_tunala(&world.selector, world.tunnels + loop);
+ /* Now do the select */
+ switch(selector_select(&world.selector)) {
+ case -1:
+ fprintf(stderr, "selector_select returned a badness error.\n");
+ abort();
+ case 0:
+ fprintf(stderr, "Warn, selector_select returned 0 - signal??\n");
+ goto main_loop;
+ default:
+ break;
+ }
+ /* Accept new connection if we should and can */
+ if((world.tunnels_used < max_tunnels) && (selector_get_listener(
+ &world.selector, world.listen_fd,
+ &newfd) == 1)) {
+ /* We have a new connection */
+ if(!tunala_world_new_item(&world, newfd,
+ proxy_ip, proxy_port))
+ fprintf(stderr, "tunala_world_new_item failed\n");
+ else
+ fprintf(stderr, "Info, new tunnel opened, now up to "
+ "%d\n", world.tunnels_used);
+ }
+ /* Give each tunnel its moment, note the while loop is because it makes
+ * the logic easier than with "for" to deal with an array that may shift
+ * because of deletes. */
+ loop = 0;
+ t_item = world.tunnels;
+ while(loop < world.tunnels_used) {
+ if(!tunala_item_io(&world.selector, t_item)) {
+ /* We're closing whether for reasons of an error or a
+ * natural close. Don't increment loop or t_item because
+ * the next item is moving to us! */
+ tunala_world_del_item(&world, loop);
+ fprintf(stderr, "Info, tunnel closed, down to %d\n",
+ world.tunnels_used);
+ }
+ else {
+ /* Move to the next item */
+ loop++;
+ t_item++;
+ }
+ }
+ goto main_loop;
+ /* Should never get here */
+ abort();
+ return 1;
+}
+
+/****************/
+/* OpenSSL bits */
+/****************/
+
+static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
+{
+ FILE *fp = NULL;
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int toret = 0; /* Assume an error */
+
+ /* cert */
+ if(cert) {
+ if((fp = fopen(cert, "r")) == NULL) {
+ fprintf(stderr, "Error opening cert file '%s'\n", cert);
+ goto err;
+ }
+ if(!PEM_read_X509(fp, &x509, NULL, NULL)) {
+ fprintf(stderr, "Error reading PEM cert from '%s'\n",
+ cert);
+ goto err;
+ }
+ if(!SSL_CTX_use_certificate(ctx, x509)) {
+ fprintf(stderr, "Error, cert in '%s' can not be used\n",
+ cert);
+ goto err;
+ }
+ /* Clear the FILE* for reuse in the "key" code */
+ fclose(fp);
+ fp = NULL;
+ fprintf(stderr, "Info, operating with cert in '%s'\n", cert);
+ /* If a cert was given without matching key, we assume the same
+ * file contains the required key. */
+ if(!key)
+ key = cert;
+ } else {
+ if(key)
+ fprintf(stderr, "Error, can't specify a key without a "
+ "corresponding certificate\n");
+ else
+ fprintf(stderr, "Error, ctx_set_cert called with "
+ "NULLs!\n");
+ goto err;
+ }
+ /* key */
+ if(key) {
+ if((fp = fopen(key, "r")) == NULL) {
+ fprintf(stderr, "Error opening key file '%s'\n", key);
+ goto err;
+ }
+ if(!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
+ fprintf(stderr, "Error reading PEM key from '%s'\n",
+ key);
+ goto err;
+ }
+ if(!SSL_CTX_use_PrivateKey(ctx, pkey)) {
+ fprintf(stderr, "Error, key in '%s' can not be used\n",
+ key);
+ goto err;
+ }
+ fprintf(stderr, "Info, operating with key in '%s'\n", key);
+ } else
+ fprintf(stderr, "Info, operating without a cert or key\n");
+ /* Success */
+ toret = 1; err:
+ if(x509)
+ X509_free(x509);
+ if(pkey)
+ EVP_PKEY_free(pkey);
+ if(fp)
+ fclose(fp);
+ return toret;
+}
+
+static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
+ const char *CAfile, const char *cert, const char *key,
+ const char *dcert, const char *dkey, const char *cipher_list,
+ int out_state, int out_verify, int verify_mode,
+ unsigned int verify_depth)
+{
+ SSL_CTX *ctx, *ret = NULL;
+ SSL_METHOD *meth;
+ ENGINE *e = NULL;
+
+ OpenSSL_add_ssl_algorithms();
+ SSL_load_error_strings();
+
+ meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method());
+ if(meth == NULL)
+ goto err;
+ if(engine_id) {
+ if((e = ENGINE_by_id(engine_id)) == NULL) {
+ fprintf(stderr, "Error obtaining '%s' engine, openssl "
+ "errors follow\n", engine_id);
+ goto err;
+ }
+ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
+ fprintf(stderr, "Error assigning '%s' engine, openssl "
+ "errors follow\n", engine_id);
+ goto err;
+ }
+ ENGINE_free(e);
+ }
+ if((ctx = SSL_CTX_new(meth)) == NULL)
+ goto err;
+ /* cacert */
+ if(CAfile) {
+ if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx),
+ CAfile, NULL)) {
+ fprintf(stderr, "Error loading CA cert(s) in '%s'\n",
+ CAfile);
+ goto err;
+ }
+ fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n",
+ CAfile);
+ } else
+ fprintf(stderr, "Info, operating without a CA cert(-list)\n");
+ if(!SSL_CTX_set_default_verify_paths(ctx)) {
+ fprintf(stderr, "Error setting default verify paths\n");
+ goto err;
+ }
+
+ /* cert and key */
+ if((cert || key) && !ctx_set_cert(ctx, cert, key))
+ goto err;
+ /* dcert and dkey */
+ if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
+ goto err;
+
+ /* cipher_list */
+ if(cipher_list) {
+ if(!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
+ fprintf(stderr, "Error setting cipher list '%s'\n",
+ cipher_list);
+ goto err;
+ }
+ fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
+ } else
+ fprintf(stderr, "Info, operating with default cipher list\n");
+
+ /* out_state (output of SSL handshake states to screen). */
+ if(out_state)
+ cb_ssl_info_set_output(stderr);
+
+ /* out_verify */
+ if(out_verify > 0) {
+ cb_ssl_verify_set_output(stderr);
+ cb_ssl_verify_set_level(out_verify);
+ }
+
+ /* verify_depth */
+ cb_ssl_verify_set_depth(verify_depth);
+
+ /* Success! (includes setting verify_mode) */
+ SSL_CTX_set_info_callback(ctx, cb_ssl_info);
+ SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify);
+ ret = ctx;
+err:
+ if(!ret) {
+ ERR_print_errors_fp(stderr);
+ if(ctx)
+ SSL_CTX_free(ctx);
+ }
+ return ret;
+}
+
+/*****************/
+/* Selector bits */
+/*****************/
+
+static void selector_sets_init(select_sets_t *s)
+{
+ s->max = 0;
+ FD_ZERO(&s->reads);
+ FD_ZERO(&s->sends);
+ FD_ZERO(&s->excepts);
+}
+static void selector_init(tunala_selector_t *selector)
+{
+ selector_sets_init(&selector->last_selected);
+ selector_sets_init(&selector->next_select);
+}
+
+#define SEL_EXCEPTS 0x00
+#define SEL_READS 0x01
+#define SEL_SENDS 0x02
+static void selector_add_raw_fd(tunala_selector_t *s, int fd, int flags)
+{
+ FD_SET(fd, &s->next_select.excepts);
+ if(flags & SEL_READS)
+ FD_SET(fd, &s->next_select.reads);
+ if(flags & SEL_SENDS)
+ FD_SET(fd, &s->next_select.sends);
+ /* Adjust "max" */
+ if(s->next_select.max < (fd + 1))
+ s->next_select.max = fd + 1;
+}
+
+static void selector_add_listener(tunala_selector_t *selector, int fd)
+{
+ selector_add_raw_fd(selector, fd, SEL_READS);
+}
+
+static void selector_add_tunala(tunala_selector_t *s, tunala_item_t *t)
+{
+ /* Set clean read if sm.clean_in is not full */
+ if(t->clean_read != -1) {
+ selector_add_raw_fd(s, t->clean_read,
+ (buffer_full(state_machine_get_buffer(&t->sm,
+ SM_CLEAN_IN)) ? SEL_EXCEPTS : SEL_READS));
+ }
+ /* Set clean send if sm.clean_out is not empty */
+ if(t->clean_send != -1) {
+ selector_add_raw_fd(s, t->clean_send,
+ (buffer_empty(state_machine_get_buffer(&t->sm,
+ SM_CLEAN_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
+ }
+ /* Set dirty read if sm.dirty_in is not full */
+ if(t->dirty_read != -1) {
+ selector_add_raw_fd(s, t->dirty_read,
+ (buffer_full(state_machine_get_buffer(&t->sm,
+ SM_DIRTY_IN)) ? SEL_EXCEPTS : SEL_READS));
+ }
+ /* Set dirty send if sm.dirty_out is not empty */
+ if(t->dirty_send != -1) {
+ selector_add_raw_fd(s, t->dirty_send,
+ (buffer_empty(state_machine_get_buffer(&t->sm,
+ SM_DIRTY_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
+ }
+}
+
+static int selector_select(tunala_selector_t *selector)
+{
+ memcpy(&selector->last_selected, &selector->next_select,
+ sizeof(select_sets_t));
+ selector_sets_init(&selector->next_select);
+ return select(selector->last_selected.max,
+ &selector->last_selected.reads,
+ &selector->last_selected.sends,
+ &selector->last_selected.excepts, NULL);
+}
+
+/* This returns -1 for error, 0 for no new connections, or 1 for success, in
+ * which case *newfd is populated. */
+static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd)
+{
+ if(FD_ISSET(fd, &selector->last_selected.excepts))
+ return -1;
+ if(!FD_ISSET(fd, &selector->last_selected.reads))
+ return 0;
+ if((*newfd = ip_accept_connection(fd)) == -1)
+ return -1;
+ return 1;
+}
+
+/************************/
+/* "Tunala" world stuff */
+/************************/
+
+static int tunala_world_make_room(tunala_world_t *world)
+{
+ unsigned int newsize;
+ tunala_item_t *newarray;
+
+ if(world->tunnels_used < world->tunnels_size)
+ return 1;
+ newsize = (world->tunnels_size == 0 ? 16 :
+ ((world->tunnels_size * 3) / 2));
+ if((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL)
+ return 0;
+ memset(newarray, 0, newsize * sizeof(tunala_item_t));
+ if(world->tunnels_used > 0)
+ memcpy(newarray, world->tunnels,
+ world->tunnels_used * sizeof(tunala_item_t));
+ if(world->tunnels_size > 0)
+ free(world->tunnels);
+ /* migrate */
+ world->tunnels = newarray;
+ world->tunnels_size = newsize;
+ return 1;
+}
+
+static int tunala_world_new_item(tunala_world_t *world, int fd,
+ const unsigned char *ip, unsigned short port)
+{
+ tunala_item_t *item;
+ int newfd;
+ SSL *new_ssl = NULL;
+
+ if(!tunala_world_make_room(world))
+ return 0;
+ if((new_ssl = SSL_new(world->ssl_ctx)) == NULL) {
+ fprintf(stderr, "Error creating new SSL\n");
+ ERR_print_errors_fp(stderr);
+ return 0;
+ }
+ item = world->tunnels + (world->tunnels_used++);
+ state_machine_init(&item->sm);
+ item->clean_read = item->clean_send =
+ item->dirty_read = item->dirty_send = -1;
+ if((newfd = ip_create_connection_split(ip, port)) == -1)
+ goto err;
+ /* Which way round? If we're a server, "fd" is the dirty side and the
+ * connection we open is the clean one. For a client, it's the other way
+ * around. */
+ if(world->server_mode) {
+ item->dirty_read = item->dirty_send = fd;
+ item->clean_read = item->clean_send = newfd;
+ } else {
+ item->clean_read = item->clean_send = fd;
+ item->dirty_read = item->dirty_send = newfd;
+ }
+ /* We use the SSL's "app_data" to indicate a call-back induced "kill" */
+ SSL_set_app_data(new_ssl, NULL);
+ if(!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode))
+ goto err;
+ return 1;
+err:
+ tunala_world_del_item(world, world->tunnels_used - 1);
+ return 0;
+
+}
+
+static void tunala_world_del_item(tunala_world_t *world, unsigned int idx)
+{
+ tunala_item_t *item = world->tunnels + idx;
+ if(item->clean_read != -1)
+ close(item->clean_read);
+ if(item->clean_send != item->clean_read)
+ close(item->clean_send);
+ item->clean_read = item->clean_send = -1;
+ if(item->dirty_read != -1)
+ close(item->dirty_read);
+ if(item->dirty_send != item->dirty_read)
+ close(item->dirty_send);
+ item->dirty_read = item->dirty_send = -1;
+ state_machine_close(&item->sm);
+ /* OK, now we fix the item array */
+ if(idx + 1 < world->tunnels_used)
+ /* We need to scroll entries to the left */
+ memmove(world->tunnels + idx,
+ world->tunnels + (idx + 1),
+ (world->tunnels_used - (idx + 1)) *
+ sizeof(tunala_item_t));
+ world->tunnels_used--;
+}
+
+static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item)
+{
+ int c_r, c_s, d_r, d_s; /* Four boolean flags */
+
+ /* Take ourselves out of the gene-pool if there was an except */
+ if((item->clean_read != -1) && FD_ISSET(item->clean_read,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->clean_send != -1) && FD_ISSET(item->clean_send,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
+ &selector->last_selected.excepts))
+ return 0;
+ /* Grab our 4 IO flags */
+ c_r = c_s = d_r = d_s = 0;
+ if(item->clean_read != -1)
+ c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
+ if(item->clean_send != -1)
+ c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
+ if(item->dirty_read != -1)
+ d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
+ if(item->dirty_send != -1)
+ d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
+ /* If no IO has happened for us, skip needless data looping */
+ if(!c_r && !c_s && !d_r && !d_s)
+ return 1;
+ if(c_r)
+ c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
+ SM_CLEAN_IN), item->clean_read) <= 0);
+ if(c_s)
+ c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
+ SM_CLEAN_OUT), item->clean_send) <= 0);
+ if(d_r)
+ d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
+ SM_DIRTY_IN), item->dirty_read) <= 0);
+ if(d_s)
+ d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
+ SM_DIRTY_OUT), item->dirty_send) <= 0);
+ /* If any of the flags is non-zero, that means they need closing */
+ if(c_r) {
+ close(item->clean_read);
+ if(item->clean_send == item->clean_read)
+ item->clean_send = -1;
+ item->clean_read = -1;
+ }
+ if(c_s && (item->clean_send != -1)) {
+ close(item->clean_send);
+ if(item->clean_send == item->clean_read)
+ item->clean_read = -1;
+ item->clean_send = -1;
+ }
+ if(d_r) {
+ close(item->dirty_read);
+ if(item->dirty_send == item->dirty_read)
+ item->dirty_send = -1;
+ item->dirty_read = -1;
+ }
+ if(d_s && (item->dirty_send != -1)) {
+ close(item->dirty_send);
+ if(item->dirty_send == item->dirty_read)
+ item->dirty_read = -1;
+ item->dirty_send = -1;
+ }
+ /* This function name is attributed to the term donated by David
+ * Schwartz on openssl-dev, message-ID:
+ * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-) */
+ if(!state_machine_churn(&item->sm))
+ /* If the SSL closes, it will also zero-out the _in buffers
+ * and will in future process just outgoing data. As and
+ * when the outgoing data has gone, it will return zero
+ * here to tell us to bail out. */
+ return 0;
+ /* Otherwise, we return zero if both sides are dead. */
+ if(((item->clean_read == -1) || (item->clean_send == -1)) &&
+ ((item->dirty_read == -1) || (item->dirty_send == -1)))
+ return 0;
+ /* If only one side closed, notify the SSL of this so it can take
+ * appropriate action. */
+ if((item->clean_read == -1) || (item->clean_send == -1)) {
+ if(!state_machine_close_clean(&item->sm))
+ return 0;
+ }
+ if((item->dirty_read == -1) || (item->dirty_send == -1)) {
+ if(!state_machine_close_dirty(&item->sm))
+ return 0;
+ }
+ return 1;
+}
+
diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h
new file mode 100644
index 0000000000..7d4e35dc9c
--- /dev/null
+++ b/demos/tunala/tunala.h
@@ -0,0 +1,154 @@
+/* Tunala ("Tunneler with a New Zealand accent")
+ *
+ * Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is
+ * if it's useful or informative to you, but it's only here as a scratchpad for
+ * ideas about how you might (or might not) program with OpenSSL. If you deploy
+ * this is in a mission-critical environment, and have not read, understood,
+ * audited, and modified this code to your satisfaction, and the result is that
+ * all hell breaks loose and you are looking for a new employer, then it proves
+ * nothing except perhaps that Darwinism is alive and well. Let's just say, *I*
+ * don't use this in a mission-critical environment, so it would be stupid for
+ * anyone to assume that it is solid and/or tested enough when even its author
+ * doesn't place that much trust in it. You have been warned.
+ *
+ * With thanks to Cryptographic Appliances, Inc.
+ */
+
+#ifndef _TUNALA_H
+#define _TUNALA_H
+
+#ifndef NO_SYSTEM_H
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif /* !defined(NO_SYSTEM_H) */
+
+#ifndef NO_OPENSSL
+#include <openssl/err.h>
+#include <openssl/engine.h>
+#include <openssl/ssl.h>
+#endif /* !defined(NO_OPENSSL) */
+
+#ifndef NO_BUFFER
+/* This is the generic "buffer" type that is used when feeding the
+ * state-machine. It's basically a FIFO with respect to the "adddata" &
+ * "takedata" type functions that operate on it. */
+#define MAX_DATA_SIZE 16384
+typedef struct _buffer_t {
+ unsigned char data[MAX_DATA_SIZE];
+ unsigned int used;
+} buffer_t;
+
+/* Initialise a buffer structure before use */
+void buffer_init(buffer_t *buf);
+/* Cleanup a buffer structure - presently not needed, but if buffer_t is
+ * converted to using dynamic allocation, this would be required - so should be
+ * called to protect against an explosion of memory leaks later if the change is
+ * made. */
+void buffer_close(buffer_t *buf);
+
+/* Basic functions to manipulate buffers */
+
+unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */
+unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */
+int buffer_full(buffer_t *buf); /* Boolean, is it full? */
+int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */
+int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */
+int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */
+
+/* Add data to the tail of the buffer, returns the amount that was actually
+ * added (so, you need to check if return value is less than size) */
+unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
+ unsigned int size);
+
+/* Take data from the front of the buffer (and scroll the rest forward). If
+ * "ptr" is NULL, this just removes data off the front of the buffer. Return
+ * value is the amount actually removed (can be less than size if the buffer has
+ * too little data). */
+unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
+ unsigned int size);
+
+/* Flushes as much data as possible out of the "from" buffer into the "to"
+ * buffer. Return value is the amount moved. The amount moved can be restricted
+ * to a maximum by specifying "cap" - setting it to -1 means no limit. */
+unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap);
+
+#ifndef NO_IP
+/* Read or write between a file-descriptor and a buffer */
+int buffer_from_fd(buffer_t *buf, int fd);
+int buffer_to_fd(buffer_t *buf, int fd);
+#endif /* !defined(NO_IP) */
+
+#ifndef NO_OPENSSL
+/* Read or write between an SSL or BIO and a buffer */
+void buffer_from_SSL(buffer_t *buf, SSL *ssl);
+void buffer_to_SSL(buffer_t *buf, SSL *ssl);
+void buffer_from_BIO(buffer_t *buf, BIO *bio);
+void buffer_to_BIO(buffer_t *buf, BIO *bio);
+
+/* Callbacks */
+void cb_ssl_info(SSL *s, int where, int ret);
+void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */
+int cb_ssl_verify(int ok, X509_STORE_CTX *ctx);
+void cb_ssl_verify_set_output(FILE *fp);
+void cb_ssl_verify_set_depth(unsigned int verify_depth);
+void cb_ssl_verify_set_level(unsigned int level);
+#endif /* !defined(NO_OPENSSL) */
+#endif /* !defined(NO_BUFFER) */
+
+#ifndef NO_TUNALA
+#ifdef NO_BUFFER
+#error "TUNALA section of tunala.h requires BUFFER support"
+#endif
+typedef struct _state_machine_t {
+ SSL *ssl;
+ BIO *bio_intossl;
+ BIO *bio_fromssl;
+ buffer_t clean_in, clean_out;
+ buffer_t dirty_in, dirty_out;
+} state_machine_t;
+typedef enum {
+ SM_CLEAN_IN, SM_CLEAN_OUT,
+ SM_DIRTY_IN, SM_DIRTY_OUT
+} sm_buffer_t;
+void state_machine_init(state_machine_t *machine);
+void state_machine_close(state_machine_t *machine);
+buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type);
+SSL *state_machine_get_SSL(state_machine_t *machine);
+int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server);
+/* Performs the data-IO loop and returns zero if the machine should close */
+int state_machine_churn(state_machine_t *machine);
+/* Is used to handle closing conditions - namely when one side of the tunnel has
+ * closed but the other should finish flushing. */
+int state_machine_close_clean(state_machine_t *machine);
+int state_machine_close_dirty(state_machine_t *machine);
+#endif /* !defined(NO_TUNALA) */
+
+#ifndef NO_IP
+/* Initialise anything related to the networking. This includes blocking pesky
+ * SIGPIPE signals. */
+int ip_initialise(void);
+/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
+ * the port to listen on (host byte order), and the return value is the
+ * file-descriptor or -1 on error. */
+int ip_create_listener_split(const unsigned char *ip, unsigned short port);
+/* Same semantics as above. */
+int ip_create_connection_split(const unsigned char *ip, unsigned short port);
+/* Converts a string into the ip/port before calling the above */
+int ip_create_listener(const char *address);
+int ip_create_connection(const char *address);
+/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
+ * then the address string could be just a port. Ie. it's suitable for a
+ * listening address but not a connecting address. */
+int ip_parse_address(const char *address, unsigned char **parsed_ip,
+ unsigned short *port, int accept_all_ip);
+/* Accepts an incoming connection through the listener. Assumes selects and
+ * what-not have deemed it an appropriate thing to do. */
+int ip_accept_connection(int listen_fd);
+#endif /* !defined(NO_IP) */
+
+#endif /* !defined(_TUNALA_H) */
diff --git a/doc/HOWTO/certificates.txt b/doc/HOWTO/certificates.txt
new file mode 100644
index 0000000000..74fe84b487
--- /dev/null
+++ b/doc/HOWTO/certificates.txt
@@ -0,0 +1,85 @@
+[DRAFT!]
+ HOWTO certificates
+
+How you handle certificates depend a great deal on what your role is.
+Your role can be one or several of:
+
+ - User of some client software
+ - User of some server software
+ - Certificate authority
+
+This file is for users who wish to get a certificate of their own.
+Certificate authorities should read ca.txt.
+
+In all the cases shown below, the standard configuration file, as
+compiled into openssl, will be used. You may find it in /etc/,
+/usr/local/ssr/ or somewhere else. The name is openssl.cnf, and
+is better described in another HOWTO [config.txt?]. If you want to
+use a different configuration file, use the argument '-config {file}'
+with the command shown below.
+
+
+Certificates are related to public key cryptography by containing a
+public key. To be useful, there must be a corresponding private key
+somewhere. With OpenSSL, public keys are easily derived from private
+keys, so before you create a certificate or a certificate request, you
+need to create a private key.
+
+Private keys are generated with 'openssl genrsa' if you want a RSA
+private key, or 'openssl gendsa' if you want a DSA private key. More
+info on how to handle these commands are found in the manual pages for
+those commands or by running them with the argument '-h'. For the
+sake of the description in this file, let's assume that the private
+key ended up in the file privkey.pem (which is the default in some
+cases).
+
+
+Let's start with the most normal way of getting a certificate. Most
+often, you want or need to get a certificate from a certificate
+authority. To handle that, the certificate authority needs a
+certificate request (or, as some certificate authorities like to put
+it, "certificate signing request", since that's exactly what they do,
+they sign it and give you the result back, thus making it authentic
+according to their policies) from you. To generate a request, use the
+command 'openssl req' like this:
+
+ openssl req -new -key privkey.pem -out cert.csr
+
+Now, cert.csr can be sent to the certificate authority, if they can
+handle files in PEM format. If not, use the extra argument '-outform'
+followed by the keyword for the format to use (see another HOWTO
+[formats.txt?]). In some cases, that isn't sufficient and you will
+have to be more creative.
+
+When the certificate authority has then done the checks the need to
+do (and probably gotten payment from you), they will hand over your
+new certificate to you.
+
+
+[fill in on how to create a self-signed certificate]
+
+
+If you created everything yourself, or if the certificate authority
+was kind enough, your certificate is a raw DER thing in PEM format.
+Your key most definitely is if you have followed the examples above.
+However, some (most?) certificate authorities will encode them with
+things like PKCS7 or PKCS12, or something else. Depending on your
+applications, this may be perfectly OK, it all depends on what they
+know how to decode. If not, There are a number of OpenSSL tools to
+convert between some (most?) formats.
+
+So, depending on your application, you may have to convert your
+certificate and your key to various formats, most often also putting
+them together into one file. The ways to do this is described in
+another HOWTO [formats.txt?], I will just mention the simplest case.
+In the case of a raw DER thing in PEM format, and assuming that's all
+right for yor applications, simply concatenating the certificate and
+the key into a new file and using that one should be enough. With
+some applications, you don't even have to do that.
+
+
+By now, you have your cetificate and your private key and can start
+using the software that depend on it.
+
+--
+Richard Levitte
diff --git a/doc/crypto/BN_swap.pod b/doc/crypto/BN_swap.pod
new file mode 100644
index 0000000000..79efaa1446
--- /dev/null
+++ b/doc/crypto/BN_swap.pod
@@ -0,0 +1,23 @@
+=pod
+
+=head1 NAME
+
+BN_swap - exchange BIGNUMs
+
+=head1 SYNOPSIS
+
+ #include <openssl/bn.h>
+
+ void BN_swap(BIGNUM *a, BIGNUM *b);
+
+=head1 DESCRIPTION
+
+BN_swap() exchanges the values of I<a> and I<b>.
+
+L<bn(3)|bn(3)>
+
+=head1 HISTORY
+
+BN_swap was added in OpenSSL 0.9.7.
+
+=cut
diff --git a/ssl/kssl.c b/ssl/kssl.c
new file mode 100644
index 0000000000..fe7f4ebe5e
--- /dev/null
+++ b/ssl/kssl.c
@@ -0,0 +1,1040 @@
+/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
+/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+
+/* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
+**
+** 19990701 VRS Started.
+*/
+
+#ifndef NO_KRB5
+#include <string.h>
+#include <openssl/ssl.h>
+
+/*
+ * When OpenSSL is built on Windows, we do not want to require that
+ * the Kerberos DLLs be available in order for the OpenSSL DLLs to
+ * work. Therefore, all Kerberos routines are loaded at run time
+ * and we do not link to a .LIB file.
+ */
+
+#if defined(WINDOWS) || defined(WIN32)
+/*
+ * The purpose of the following pre-processor statements is to provide
+ * compatibility with different releases of MIT Kerberos for Windows.
+ * All versions up to 1.2 used macros. But macros do not allow for
+ * a binary compatible interface for DLLs. Therefore, all macros are
+ * being replaced by function calls. The following code will allow
+ * an OpenSSL DLL built on Windows to work whether or not the macro
+ * or function form of the routines are utilized.
+ */
+#ifdef krb5_cc_get_principal
+#define NO_DEF_KRB5_CCACHE
+#undef krb5_cc_get_principal
+#endif
+#define krb5_cc_get_principal kssl_krb5_cc_get_principal
+
+#define krb5_free_data_contents kssl_krb5_free_data_contents
+#define krb5_free_context kssl_krb5_free_context
+#define krb5_auth_con_free kssl_krb5_auth_con_free
+#define krb5_free_principal kssl_krb5_free_principal
+#define krb5_mk_req_extended kssl_krb5_mk_req_extended
+#define krb5_get_credentials kssl_krb5_get_credentials
+#define krb5_cc_default kssl_krb5_cc_default
+#define krb5_sname_to_principal kssl_krb5_sname_to_principal
+#define krb5_init_context kssl_krb5_init_context
+#define krb5_free_ticket kssl_krb5_free_ticket
+#define krb5_rd_req kssl_krb5_rd_req
+#define krb5_kt_default kssl_krb5_kt_default
+#define krb5_kt_resolve kssl_krb5_kt_resolve
+#define krb5_auth_con_init kssl_krb5_auth_con_init
+
+/* Prototypes for built in stubs */
+void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
+void kssl_krb5_free_principal(krb5_context, krb5_principal );
+krb5_error_code kssl_krb5_kt_resolve(krb5_context,
+ krb5_const char *,
+ krb5_keytab *);
+krb5_error_code kssl_krb5_kt_default(krb5_context,
+ krb5_keytab *);
+krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
+krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
+ krb5_const krb5_data *,
+ krb5_const_principal, krb5_keytab,
+ krb5_flags *,krb5_ticket **);
+krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
+ krb5_auth_context *,
+ krb5_const krb5_flags,
+ krb5_data *,
+ krb5_creds *,
+ krb5_data * );
+krb5_error_code kssl_krb5_init_context(krb5_context *);
+void kssl_krb5_free_context(krb5_context);
+krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache *);
+krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
+ krb5_const char *,
+ krb5_const char *,
+ krb5_int32,
+ krb5_principal *);
+krb5_error_code kssl_krb5_get_credentials(krb5_context,
+ krb5_const krb5_flags,
+ krb5_ccache,
+ krb5_creds *,
+ krb5_creds * *);
+krb5_error_code kssl_krb5_auth_con_init(krb5_context,
+ krb5_auth_context *);
+krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
+ krb5_ccache cache,
+ krb5_principal *principal);
+krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
+
+/* Function pointers (almost all Kerberos functions are _stdcall) */
+static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)=NULL;
+static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )=NULL;
+static krb5_error_code(_stdcall *p_krb5_kt_resolve)(krb5_context, krb5_const char *,
+ krb5_keytab *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
+ krb5_keytab *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
+ krb5_ticket *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
+ krb5_auth_context *,
+ krb5_const krb5_data *,
+ krb5_const_principal,
+ krb5_keytab, krb5_flags *,
+ krb5_ticket **)=NULL;
+static krb5_error_code (_stdcall *p_krb5_mk_req_extended) (krb5_context,
+ krb5_auth_context *,
+ krb5_const krb5_flags,
+ krb5_data *,
+ krb5_creds *,
+ krb5_data * )=NULL;
+static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
+static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
+static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
+ krb5_ccache *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_sname_to_principal)(krb5_context,
+ krb5_const char *,
+ krb5_const char *,
+ krb5_int32,
+ krb5_principal *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_get_credentials)(krb5_context,
+ krb5_const krb5_flags,
+ krb5_ccache,
+ krb5_creds *,
+ krb5_creds * *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_auth_con_init)(krb5_context,
+ krb5_auth_context *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_cc_get_principal)(krb5_context context,
+ krb5_ccache cache,
+ krb5_principal *principal)=NULL;
+static krb5_error_code (_stdcall *p_krb5_auth_con_free)(krb5_context,
+ krb5_auth_context)=NULL;
+static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */
+
+/* Function to Load the Kerberos 5 DLL and initialize function pointers */
+void
+load_krb5_dll(void)
+ {
+ HANDLE hKRB5_32;
+
+ krb5_loaded++;
+ hKRB5_32 = LoadLibrary("KRB5_32");
+ if (!hKRB5_32)
+ return;
+
+ (FARPROC) p_krb5_free_data_contents =
+ GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
+ (FARPROC) p_krb5_free_context =
+ GetProcAddress( hKRB5_32, "krb5_free_context" );
+ (FARPROC) p_krb5_auth_con_free =
+ GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
+ (FARPROC) p_krb5_free_principal =
+ GetProcAddress( hKRB5_32, "krb5_free_principal" );
+ (FARPROC) p_krb5_mk_req_extended =
+ GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
+ (FARPROC) p_krb5_get_credentials =
+ GetProcAddress( hKRB5_32, "krb5_get_credentials" );
+ (FARPROC) p_krb5_cc_get_principal =
+ GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
+ (FARPROC) p_krb5_cc_default =
+ GetProcAddress( hKRB5_32, "krb5_cc_default" );
+ (FARPROC) p_krb5_sname_to_principal =
+ GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
+ (FARPROC) p_krb5_init_context =
+ GetProcAddress( hKRB5_32, "krb5_init_context" );
+ (FARPROC) p_krb5_free_ticket =
+ GetProcAddress( hKRB5_32, "krb5_free_ticket" );
+ (FARPROC) p_krb5_rd_req =
+ GetProcAddress( hKRB5_32, "krb5_rd_req" );
+ (FARPROC) p_krb5_kt_default =
+ GetProcAddress( hKRB5_32, "krb5_kt_default" );
+ (FARPROC) p_krb5_kt_resolve =
+ GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
+ (FARPROC) p_krb5_auth_con_init =
+ GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
+ }
+
+/* Stubs for each function to be dynamicly loaded */
+void
+kssl_krb5_free_data_contents(krb5_context CO, krb5_data * data)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_free_data_contents )
+ p_krb5_free_data_contents(CO,data);
+ }
+
+krb5_error_code
+kssl_krb5_mk_req_extended (krb5_context CO,
+ krb5_auth_context * pACO,
+ krb5_const krb5_flags F,
+ krb5_data * pD1,
+ krb5_creds * pC,
+ krb5_data * pD2)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_mk_req_extended )
+ return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+krb5_error_code
+kssl_krb5_auth_con_init(krb5_context CO,
+ krb5_auth_context * pACO)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_auth_con_init )
+ return(p_krb5_auth_con_init(CO,pACO));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+krb5_error_code
+kssl_krb5_auth_con_free (krb5_context CO,
+ krb5_auth_context ACO)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_auth_con_free )
+ return(p_krb5_auth_con_free(CO,ACO));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+krb5_error_code
+kssl_krb5_get_credentials(krb5_context CO,
+ krb5_const krb5_flags F,
+ krb5_ccache CC,
+ krb5_creds * pCR,
+ krb5_creds ** ppCR)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_get_credentials )
+ return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+krb5_error_code
+kssl_krb5_sname_to_principal(krb5_context CO,
+ krb5_const char * pC1,
+ krb5_const char * pC2,
+ krb5_int32 I,
+ krb5_principal * pPR)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_sname_to_principal )
+ return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_cc_default(krb5_context CO,
+ krb5_ccache * pCC)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_cc_default )
+ return(p_krb5_cc_default(CO,pCC));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_init_context(krb5_context * pCO)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_init_context )
+ return(p_krb5_init_context(pCO));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+void
+kssl_krb5_free_context(krb5_context CO)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_free_context )
+ p_krb5_free_context(CO);
+ }
+
+void
+kssl_krb5_free_principal(krb5_context c, krb5_principal p)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_free_principal )
+ p_krb5_free_principal(c,p);
+ }
+
+krb5_error_code
+kssl_krb5_kt_resolve(krb5_context con,
+ krb5_const char * sz,
+ krb5_keytab * kt)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_kt_resolve )
+ return(p_krb5_kt_resolve(con,sz,kt));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_kt_default(krb5_context con,
+ krb5_keytab * kt)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_kt_default )
+ return(p_krb5_kt_default(con,kt));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_free_ticket(krb5_context con,
+ krb5_ticket * kt)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_free_ticket )
+ return(p_krb5_free_ticket(con,kt));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
+ krb5_const krb5_data * data,
+ krb5_const_principal princ, krb5_keytab keytab,
+ krb5_flags * flags, krb5_ticket ** pptkt)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_rd_req )
+ return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+/* Structure definitions */
+#ifndef NO_DEF_KRB5_CCACHE
+#ifndef krb5_x
+#define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
+#define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
+#endif
+
+typedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */
+
+typedef struct _krb5_ccache
+ {
+ krb5_magic magic;
+ struct _krb5_cc_ops FAR *ops;
+ krb5_pointer data;
+ } *krb5_ccache;
+
+typedef struct _krb5_cc_ops
+ {
+ krb5_magic magic;
+ char *prefix;
+ char * (KRB5_CALLCONV *get_name) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ krb5_error_code (KRB5_CALLCONV *resolve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *,
+ const char *));
+ krb5_error_code (KRB5_CALLCONV *gen_new) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
+ krb5_error_code (KRB5_CALLCONV *init) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_principal));
+ krb5_error_code (KRB5_CALLCONV *destroy) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ krb5_error_code (KRB5_CALLCONV *close) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ krb5_error_code (KRB5_CALLCONV *store) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_creds *));
+ krb5_error_code (KRB5_CALLCONV *retrieve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_flags, krb5_creds *,
+ krb5_creds *));
+ krb5_error_code (KRB5_CALLCONV *get_princ) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_principal *));
+ krb5_error_code (KRB5_CALLCONV *get_first) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_cc_cursor *));
+ krb5_error_code (KRB5_CALLCONV *get_next) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_cc_cursor *, krb5_creds *));
+ krb5_error_code (KRB5_CALLCONV *end_get) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_cc_cursor *));
+ krb5_error_code (KRB5_CALLCONV *remove_cred) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_flags, krb5_creds *));
+ krb5_error_code (KRB5_CALLCONV *set_flags) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
+ krb5_flags));
+ } krb5_cc_ops;
+#endif /* NO_DEF_KRB5_CCACHE */
+
+krb5_error_code
+kssl_krb5_cc_get_principal
+ (krb5_context context, krb5_ccache cache,
+ krb5_principal *principal)
+ {
+ if ( p_krb5_cc_get_principal )
+ return(p_krb5_cc_get_principal(context,cache,principal));
+ else
+ return(krb5_x ((cache)->ops->get_princ,(context, cache, principal)));
+ }
+#endif /* WINDOWS || WIN32 */
+
+char
+*kstring(char *string)
+ {
+ static char *null = "[NULL]";
+
+ return ((string == NULL)? null: string);
+ }
+
+#define MAXKNUM 255
+char
+*knumber(int len, krb5_octet *contents)
+ {
+ static char buf[MAXKNUM+1];
+ int i;
+
+ BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
+
+ for (i=0; i < len && MAXKNUM > strlen(buf)+3; i++)
+ {
+ BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
+ }
+
+ return (buf);
+ }
+
+
+/* Set kssl_err error info when reason text is a simple string
+** kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
+*/
+void
+kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
+ {
+ if (kssl_err == NULL) return;
+
+ kssl_err->reason = reason;
+ BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
+ return;
+ }
+
+
+/* Display contents of krb5_data struct, for debugging
+*/
+void
+print_krb5_data(char *label, krb5_data *kdata)
+ {
+ int i;
+
+ printf("%s[%d] ", label, kdata->length);
+ for (i=0; i < kdata->length; i++)
+ {
+ if (isprint((int) kdata->data[i]))
+ printf( "%c ", kdata->data[i]);
+ else
+ printf( "%02x", kdata->data[i]);
+ }
+ printf("\n");
+ }
+
+
+/* Display contents of krb5_authdata struct, for debugging
+*/
+void
+print_krb5_authdata(char *label, krb5_authdata **adata)
+ {
+ if (adata == NULL)
+ {
+ printf("%s, authdata==0\n", label);
+ return;
+ }
+ printf("%s [%p]\n", label, adata);
+#if 0
+ {
+ int i;
+ printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
+ for (i=0; i < adata->length; i++)
+ {
+ printf((isprint(adata->contents[i]))? "%c ": "%02x",
+ adata->contents[i]);
+ }
+ printf("\n");
+ }
+#endif
+ }
+
+
+/* Display contents of krb5_keyblock struct, for debugging
+*/
+void
+print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
+ {
+ int i;
+
+ if (keyblk == NULL)
+ {
+ printf("%s, keyblk==0\n", label);
+ return;
+ }
+#ifdef KRB5_HEIMDAL
+ printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, keyblk->keyvalue->length);
+ for (i=0; i < keyblk->keyvalue->length; i++)
+ {
+ printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
+ }
+ printf("\n");
+#else
+ printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
+ for (i=0; i < keyblk->length; i++)
+ {
+ printf("%02x",keyblk->contents[i]);
+ }
+ printf("\n");
+#endif
+ }
+
+
+/* Given krb5 service (typically "kssl") and hostname in kssl_ctx,
+** Create Kerberos AP_REQ message for SSL Client.
+**
+** 19990628 VRS Started.
+*/
+krb5_error_code
+kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
+ /* OUT */ krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
+ {
+ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
+ krb5_context krb5context = NULL;
+ krb5_auth_context krb5auth_context = NULL;
+ krb5_ccache krb5ccdef = NULL;
+ krb5_creds krb5creds, *krb5credsp = NULL;
+ krb5_data krb5in_data;
+
+ kssl_err_set(kssl_err, 0, "");
+ memset((char *)&krb5creds, 0, sizeof(krb5creds));
+
+ if (!kssl_ctx)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "No kssl_ctx defined.\n");
+ goto err;
+ }
+ else if (!kssl_ctx->service_host)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "kssl_ctx service_host undefined.\n");
+ goto err;
+ }
+
+ if ((krb5rc = krb5_init_context(&krb5context)) != 0)
+ {
+ BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
+ "krb5_init_context() fails: %d\n", krb5rc);
+ kssl_err->reason = SSL_R_KRB5_C_INIT;
+ goto err;
+ }
+
+ if ((krb5rc = krb5_sname_to_principal(krb5context,
+ kssl_ctx->service_host,
+ (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
+ KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
+ {
+ BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
+ "krb5_sname_to_principal() fails for %s/%s\n",
+ kssl_ctx->service_host,
+ (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
+ kssl_err->reason = SSL_R_KRB5_C_INIT;
+ goto err;
+ }
+
+ if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
+ "krb5_cc_default fails.\n");
+ goto err;
+ }
+
+ if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
+ &krb5creds.client)) != 0)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
+ "krb5_cc_get_principal() fails.\n");
+ goto err;
+ }
+
+ if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
+ &krb5creds, &krb5credsp)) != 0)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
+ "krb5_get_credentials() fails.\n");
+ goto err;
+ }
+
+ krb5in_data.data = NULL;
+ krb5in_data.length = 0;
+
+ krb5rc = KRB5KRB_ERR_GENERIC;
+ /* caller should free data of krb5_app_req */
+ if ((krb5rc = krb5_mk_req_extended(krb5context, &krb5auth_context,
+ 0, &krb5in_data, krb5credsp, krb5_app_req)) != 0)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
+ "krb5_mk_req_extended() fails.\n");
+ goto err;
+ }
+#ifdef KRB5_HEIMDAL
+ else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
+ "kssl_ctx_setkey() fails.\n");
+ }
+#else
+ else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
+ "kssl_ctx_setkey() fails.\n");
+ }
+#endif
+ else krb5rc = 0;
+
+ err:
+#ifdef KSSL_DEBUG
+ kssl_ctx_show(kssl_ctx);
+#endif /* KSSL_DEBUG */
+
+ if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client);
+ if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server);
+ if (krb5auth_context) krb5_auth_con_free(krb5context, krb5auth_context);
+ if (krb5context) krb5_free_context(krb5context);
+ return (krb5rc);
+ }
+
+
+/* Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
+** and krb5 AP_REQ message & message length,
+** Return Kerberos session key and client principle
+** to SSL Server in KSSL_CTX *kssl_ctx.
+**
+** 19990702 VRS Started.
+*/
+krb5_error_code
+kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
+ /* IN */ char *msg, int msglen,
+ /* OUT */ KSSL_ERR *kssl_err )
+ {
+ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
+ static krb5_context krb5context = NULL;
+ static krb5_auth_context krb5auth_context = NULL;
+ krb5_ticket *krb5ticket = NULL;
+ krb5_keytab krb5keytab = NULL;
+ krb5_principal krb5server;
+ krb5_data krb5in_data;
+ krb5_flags ap_option;
+
+ kssl_err_set(kssl_err, 0, "");
+
+ if (!kssl_ctx)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
+ goto err;
+ }
+
+#ifdef KSSL_DEBUG
+ printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
+#endif /* KSSL_DEBUG */
+
+ if (!krb5context && (krb5rc = krb5_init_context(&krb5context)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_init_context() fails.\n");
+ goto err;
+ }
+ if (krb5auth_context &&
+ (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_auth_con_free() fails.\n");
+ goto err;
+ }
+ else krb5auth_context = NULL;
+ if (!krb5auth_context &&
+ (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_auth_con_init() fails.\n");
+ goto err;
+ }
+
+ if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
+ (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
+ KRB5_NT_SRV_HST, &krb5server)) != 0)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_sname_to_principal() fails.\n");
+ goto err;
+ }
+
+ /* kssl_ctx->keytab_file == NULL ==> use Kerberos default
+ */
+ if (kssl_ctx->keytab_file)
+ {
+ krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
+ &krb5keytab);
+ if (krb5rc)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_kt_resolve() fails.\n");
+ goto err;
+ }
+ }
+ else
+ {
+ krb5rc = krb5_kt_default(krb5context,&krb5keytab);
+ if (krb5rc)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_kt_default() fails.\n");
+ goto err;
+ }
+ }
+
+ /* Actual Kerberos5 krb5_recvauth() has initial conversation here
+ ** o check KRB5_SENDAUTH_BADAUTHVERS unless KRB5_RECVAUTH_SKIP_VERSION
+ ** o check KRB5_SENDAUTH_BADAPPLVERS
+ ** o send "0" msg if all OK
+ */
+
+ krb5in_data.data = msg;
+ krb5in_data.length = msglen;
+ if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, &krb5in_data,
+ krb5server, krb5keytab, &ap_option, &krb5ticket)) != 0)
+ {
+ BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
+ "krb5_rd_req() fails with %x.\n", krb5rc);
+ kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
+ goto err;
+ }
+
+ krb5rc = KRB5_NO_TKT_SUPPLIED;
+ if (!krb5ticket || !krb5ticket->enc_part2 ||
+ !krb5ticket->enc_part2->client ||
+ !krb5ticket->enc_part2->client->data ||
+ !krb5ticket->enc_part2->session)
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
+ "bad ticket from krb5_rd_req.\n");
+ }
+ else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
+ &krb5ticket->enc_part2->client->realm,
+ krb5ticket->enc_part2->client->data))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
+ "kssl_ctx_setprinc() fails.\n");
+ }
+ else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
+ "kssl_ctx_setkey() fails.\n");
+ }
+ else krb5rc = 0;
+
+ err:
+#ifdef KSSL_DEBUG
+ kssl_ctx_show(kssl_ctx);
+#endif /* KSSL_DEBUG */
+
+ if (krb5keytab) krb5_kt_close(krb5context, krb5keytab);
+ if (krb5ticket) krb5_free_ticket(krb5context, krb5ticket);
+ if (krb5server) krb5_free_principal(krb5context, krb5server);
+ return (krb5rc);
+ }
+
+
+/* Allocate & return a new kssl_ctx struct.
+*/
+KSSL_CTX *
+kssl_ctx_new(void)
+ {
+ return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
+ }
+
+
+/* Frees a kssl_ctx struct and any allocated memory it holds.
+** Returns NULL.
+*/
+KSSL_CTX *
+kssl_ctx_free(KSSL_CTX *kssl_ctx)
+ {
+ if (kssl_ctx == NULL) return kssl_ctx;
+
+ if (kssl_ctx->key) memset(kssl_ctx->key, 0, kssl_ctx->length);
+ if (kssl_ctx->key) free(kssl_ctx->key);
+ if (kssl_ctx->client_princ) free(kssl_ctx->client_princ);
+ if (kssl_ctx->service_host) free(kssl_ctx->service_host);
+ if (kssl_ctx->service_name) free(kssl_ctx->service_name);
+ if (kssl_ctx->keytab_file) free(kssl_ctx->keytab_file);
+
+ free(kssl_ctx);
+ return (KSSL_CTX *) NULL;
+ }
+
+
+/* Given a (krb5_data *) entity (and optional realm),
+** set the plain (char *) client_princ or service_host member
+** of the kssl_ctx struct.
+*/
+krb5_error_code
+kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
+ krb5_data *realm, krb5_data *entity)
+ {
+ char **princ;
+ int length;
+
+ if (kssl_ctx == NULL || entity == NULL) return KSSL_CTX_ERR;
+
+ switch (which)
+ {
+ case KSSL_CLIENT: princ = &kssl_ctx->client_princ; break;
+ case KSSL_SERVER: princ = &kssl_ctx->service_host; break;
+ default: return KSSL_CTX_ERR; break;
+ }
+ if (*princ) free(*princ);
+
+ length = entity->length + ((realm)? realm->length + 2: 1);
+ if ((*princ = calloc(1, length)) == NULL)
+ return KSSL_CTX_ERR;
+ else
+ {
+ strncpy(*princ, entity->data, entity->length);
+ if (realm)
+ {
+ strcat (*princ, "@");
+ (void) strncat(*princ, realm->data, realm->length);
+ }
+ }
+
+ return KSSL_CTX_OK;
+ }
+
+
+/* Set one of the plain (char *) string members of the kssl_ctx struct.
+** Default values should be:
+** which == KSSL_SERVICE => "khost" (KRB5SVC)
+** which == KSSL_KEYTAB => "/etc/krb5.keytab" (KRB5KEYTAB)
+*/
+krb5_error_code
+kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
+ {
+ char **string;
+
+ if (!kssl_ctx) return KSSL_CTX_ERR;
+
+ switch (which)
+ {
+ case KSSL_SERVICE: string = &kssl_ctx->service_name; break;
+ case KSSL_SERVER: string = &kssl_ctx->service_host; break;
+ case KSSL_CLIENT: string = &kssl_ctx->client_princ; break;
+ case KSSL_KEYTAB: string = &kssl_ctx->keytab_file; break;
+ default: return KSSL_CTX_ERR; break;
+ }
+ if (*string) free(*string);
+
+ if (!text)
+ {
+ *string = '\0';
+ return KSSL_CTX_OK;
+ }
+
+ if ((*string = calloc(1, strlen(text) + 1)) == NULL)
+ return KSSL_CTX_ERR;
+ else
+ strcpy(*string, text);
+
+ return KSSL_CTX_OK;
+ }
+
+
+/* Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
+** struct. Clear kssl_ctx->key if Kerberos session key is NULL.
+*/
+krb5_error_code
+kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
+ {
+ if (!kssl_ctx) return KSSL_CTX_ERR;
+
+ if (kssl_ctx->key)
+ {
+ memset(kssl_ctx->key, 0, kssl_ctx->length);
+ free(kssl_ctx->key);
+ }
+
+ if (session)
+ {
+ kssl_ctx->enctype = session->enctype;
+ kssl_ctx->length = session->length;
+ }
+ else
+ {
+ kssl_ctx->enctype = ENCTYPE_UNKNOWN;
+ kssl_ctx->length = 0;
+ return KSSL_CTX_OK;
+ }
+
+ if ((kssl_ctx->key =
+ (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
+ {
+ kssl_ctx->length = 0;
+ return KSSL_CTX_ERR;
+ }
+ else
+ memcpy(kssl_ctx->key, session->contents, session->length);
+
+ return KSSL_CTX_OK;
+ }
+
+
+/* Display contents of kssl_ctx struct
+*/
+void
+kssl_ctx_show(KSSL_CTX *kssl_ctx)
+ {
+ int i;
+
+ printf("kssl_ctx: ");
+ if (kssl_ctx == NULL)
+ {
+ printf("NULL\n");
+ return;
+ }
+ else
+ printf("%p\n", kssl_ctx);
+
+ printf("\tservice:\t%s\n",
+ (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
+ printf("\tclient:\t%s\n",
+ (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
+ printf("\tserver:\t%s\n",
+ (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
+ printf("\tkeytab:\t%s\n",
+ (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
+ printf("\tkey [%d:%d]:\t",
+ kssl_ctx->enctype, kssl_ctx->length);
+
+ for (i=0; i < kssl_ctx->length && kssl_ctx->key; i++)
+ {
+ printf("%02x", kssl_ctx->key[i]);
+ }
+ printf("\n");
+ return;
+ }
+
+void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
+ {
+#ifdef KRB5_HEIMDAL
+ data->length = 0;
+ free(data->if (data->data) data);
+#else
+ krb5_free_data_contents(NULL, data);
+#endif
+ }
+
+#else /* !NO_KRB5 */
+
+#ifdef PEDANTIC
+static int dummy=(int)&dummy;
+#endif
+
+#endif /* !NO_KRB5 */
+
diff --git a/ssl/kssl.h b/ssl/kssl.h
new file mode 100644
index 0000000000..8f46e66f25
--- /dev/null
+++ b/ssl/kssl.h
@@ -0,0 +1,162 @@
+/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */
+/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+** 19990701 VRS Started.
+*/
+
+#ifndef KSSL_H
+#define KSSL_H
+
+#ifndef NO_KRB5
+
+#include <stdio.h>
+#include <ctype.h>
+#include <krb5.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Depending on which KRB5 implementation used, some types from
+** the other may be missing. Resolve that here and now
+*/
+#ifdef KRB5_HEIMDAL
+typedef unsigned char krb5_octet;
+#define FAR
+#endif
+
+/* Uncomment this to debug kssl problems or
+** to trace usage of the Kerberos session key
+**
+** #define KSSL_DEBUG
+*/
+
+#ifndef KRB5SVC
+#define KRB5SVC "host"
+#endif
+
+#ifndef KRB5KEYTAB
+#define KRB5KEYTAB "/etc/krb5.keytab"
+#endif
+
+
+#define KSSL_ERR_MAX 255
+typedef struct kssl_err_st {
+ int reason;
+ char text[KSSL_ERR_MAX+1];
+ } KSSL_ERR;
+
+
+/* Context for passing
+** (1) Kerberos session key to SSL, and
+** (2) Config data between application and SSL lib
+*/
+typedef struct kssl_ctx_st
+ {
+ /* used by: disposition: */
+ char *service_name; /* C,S default ok (kssl) */
+ char *service_host; /* C input, REQUIRED */
+ char *client_princ; /* S output from krb5 ticket */
+ char *keytab_file; /* S NULL (/etc/krb5.keytab) */
+ char *cred_cache; /* C NULL (default) */
+ krb5_enctype enctype;
+ int length;
+ krb5_octet FAR *key;
+ } KSSL_CTX;
+
+#define KSSL_CLIENT 1
+#define KSSL_SERVER 2
+#define KSSL_SERVICE 3
+#define KSSL_KEYTAB 4
+
+#define KSSL_CTX_OK 0
+#define KSSL_CTX_ERR 1
+#define KSSL_NOMEM 2
+
+
+/* Private (internal to OpenSSL) */
+void print_krb5_data(char *label, krb5_data *kdata);
+void print_krb5_authdata(char *label, krb5_authdata **adata);
+void print_krb5_keyblock(char *label, krb5_keyblock *keyblk);
+
+char *kstring(char *string);
+char *knumber(int len, krb5_octet *contents);
+
+
+/* Public (for use by applications that use OpenSSL with Kerberos 5 support */
+krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text);
+KSSL_CTX *kssl_ctx_new(void);
+KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx);
+void kssl_ctx_show(KSSL_CTX *kssl_ctx);
+krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
+ krb5_data *realm, krb5_data *entity);
+krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data *ap_req,
+ KSSL_ERR *kssl_err);
+krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, char *msg, int msglen,
+ KSSL_ERR *kssl_err);
+krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session);
+void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text);
+void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* NO_KRB5 */
+#endif /* KSSL_H */