diff options
author | cvs2svn <cvs2svn> | 2000-12-06 12:25:34 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn> | 2000-12-06 12:25:34 +0000 |
commit | f8a5c03cdf952c047f4f76ccb3d2cf12f4704a1b (patch) | |
tree | 4146d8b72ff2f0be194b607bffe3101c329096f9 | |
parent | d0905a24988257be3458689f8793a86d2b05ecb0 (diff) | |
parent | bac685417a0890642bada45bfaf1e44de9c92beb (diff) | |
download | openssl-new-f8a5c03cdf952c047f4f76ccb3d2cf12f4704a1b.tar.gz |
This commit was manufactured by cvs2svn to create branch 'BRANCH_ASN1'.
-rw-r--r-- | crypto/bn/bn_kron.c | 182 | ||||
-rw-r--r-- | crypto/bn/bn_mod.c | 296 | ||||
-rw-r--r-- | crypto/bn/bn_mont2.c | 349 | ||||
-rw-r--r-- | crypto/bn/bn_mont2.h | 36 | ||||
-rw-r--r-- | crypto/bn/bn_sqrt.c | 382 | ||||
-rw-r--r-- | crypto/ec/ec.c | 120 | ||||
-rw-r--r-- | crypto/ec/ec.h | 86 | ||||
-rw-r--r-- | crypto/ec/ec_point.c | 1477 | ||||
-rw-r--r-- | crypto/ocsp/.cvsignore | 2 | ||||
-rw-r--r-- | crypto/ocsp/Makefile.ssl | 236 | ||||
-rw-r--r-- | crypto/ocsp/ocsp.h | 595 | ||||
-rw-r--r-- | crypto/ocsp/ocsp_ext.c | 349 | ||||
-rw-r--r-- | crypto/rijndael/.cvsignore | 2 | ||||
-rwxr-xr-x | crypto/rijndael/rd_fst.c | 476 | ||||
-rwxr-xr-x | crypto/rijndael/rd_fst.h | 46 | ||||
-rw-r--r-- | demos/tunala/.cvsignore | 2 | ||||
-rw-r--r-- | demos/tunala/Makefile | 41 | ||||
-rw-r--r-- | demos/tunala/buffer.c | 181 | ||||
-rw-r--r-- | demos/tunala/cb.c | 133 | ||||
-rw-r--r-- | demos/tunala/sm.c | 151 | ||||
-rw-r--r-- | demos/tunala/tunala.c | 885 | ||||
-rw-r--r-- | demos/tunala/tunala.h | 154 | ||||
-rw-r--r-- | doc/HOWTO/certificates.txt | 85 | ||||
-rw-r--r-- | doc/crypto/BN_swap.pod | 23 | ||||
-rw-r--r-- | ssl/kssl.c | 1040 | ||||
-rw-r--r-- | ssl/kssl.h | 162 |
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(>, &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 */ |