s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / heimdal / lib / hcrypto / dh-ltm.c
1 /*
2  * Copyright (c) 2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 #include <roken.h>
38
39 #include <dh.h>
40
41 #include "tommath.h"
42
43 static void
44 BN2mpz(mp_int *s, const BIGNUM *bn)
45 {
46     size_t len;
47     void *p;
48
49     len = BN_num_bytes(bn);
50     p = malloc(len);
51     BN_bn2bin(bn, p);
52     mp_read_unsigned_bin(s, p, len);
53     free(p);
54 }
55
56
57 static BIGNUM *
58 mpz2BN(mp_int *s)
59 {
60     size_t size;
61     BIGNUM *bn;
62     void *p;
63
64     size = mp_unsigned_bin_size(s);
65     p = malloc(size);
66     if (p == NULL && size != 0)
67         return NULL;
68     mp_to_unsigned_bin(s, p);
69
70     bn = BN_bin2bn(p, size, NULL);
71     free(p);
72     return bn;
73 }
74
75 /*
76  *
77  */
78
79 #define DH_NUM_TRIES 10
80
81 static int
82 ltm_dh_generate_key(DH *dh)
83 {
84     mp_int pub, priv_key, g, p;
85     int have_private_key = (dh->priv_key != NULL);
86     int codes, times = 0;
87     int res;
88
89     if (dh->p == NULL || dh->g == NULL)
90         return 0;
91
92     while (times++ < DH_NUM_TRIES) {
93         if (!have_private_key) {
94             size_t bits = BN_num_bits(dh->p);
95
96             if (dh->priv_key)
97                 BN_free(dh->priv_key);
98
99             dh->priv_key = BN_new();
100             if (dh->priv_key == NULL)
101                 return 0;
102             if (!BN_rand(dh->priv_key, bits - 1, 0, 0)) {
103                 BN_clear_free(dh->priv_key);
104                 dh->priv_key = NULL;
105                 return 0;
106             }
107         }
108         if (dh->pub_key) {
109             BN_free(dh->pub_key);
110             dh->pub_key = NULL;
111         }
112
113         mp_init_multi(&pub, &priv_key, &g, &p, NULL);
114
115         BN2mpz(&priv_key, dh->priv_key);
116         BN2mpz(&g, dh->g);
117         BN2mpz(&p, dh->p);
118
119         res = mp_exptmod(&g, &priv_key, &p, &pub);
120
121         mp_clear_multi(&priv_key, &g, &p, NULL);
122         if (res != 0)
123             continue;
124
125         dh->pub_key = mpz2BN(&pub);
126         mp_clear(&pub);
127         if (dh->pub_key == NULL)
128             return 0;
129
130         if (DH_check_pubkey(dh, dh->pub_key, &codes) && codes == 0)
131             break;
132         if (have_private_key)
133             return 0;
134     }
135
136     if (times >= DH_NUM_TRIES) {
137         if (!have_private_key && dh->priv_key) {
138             BN_free(dh->priv_key);
139             dh->priv_key = NULL;
140         }
141         if (dh->pub_key) {
142             BN_free(dh->pub_key);
143             dh->pub_key = NULL;
144         }
145         return 0;
146     }
147
148     return 1;
149 }
150
151 static int
152 ltm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh)
153 {
154     mp_int s, priv_key, p, peer_pub;
155     int ret;
156
157     if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL)
158         return -1;
159
160     mp_init_multi(&s, &priv_key, &p, &peer_pub, NULL);
161     BN2mpz(&p, dh->p);
162     BN2mpz(&peer_pub, pub);
163
164     /* check if peers pubkey is reasonable */
165     if (mp_isneg(&peer_pub)
166         || mp_cmp(&peer_pub, &p) >= 0
167         || mp_cmp_d(&peer_pub, 1) <= 0)
168     {
169         ret = -1;
170         goto out;
171     }
172
173     BN2mpz(&priv_key, dh->priv_key);
174
175     ret = mp_exptmod(&peer_pub, &priv_key, &p, &s);
176
177     if (ret != 0) {
178         ret = -1;
179         goto out;
180     }
181
182     ret = mp_unsigned_bin_size(&s);
183     mp_to_unsigned_bin(&s, shared);
184
185  out:
186     mp_clear_multi(&s, &priv_key, &p, &peer_pub, NULL);
187
188     return ret;
189 }
190
191 static int
192 ltm_dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback)
193 {
194     /* groups should already be known, we don't care about this */
195     return 0;
196 }
197
198 static int
199 ltm_dh_init(DH *dh)
200 {
201     return 1;
202 }
203
204 static int
205 ltm_dh_finish(DH *dh)
206 {
207     return 1;
208 }
209
210
211 /*
212  *
213  */
214
215 const DH_METHOD _hc_dh_ltm_method = {
216     "hcrypto ltm DH",
217     ltm_dh_generate_key,
218     ltm_dh_compute_key,
219     NULL,
220     ltm_dh_init,
221     ltm_dh_finish,
222     0,
223     NULL,
224     ltm_dh_generate_params
225 };
226
227 /**
228  * DH implementation using libtommath.
229  *
230  * @return the DH_METHOD for the DH implementation using libtommath.
231  *
232  * @ingroup hcrypto_dh
233  */
234
235 const DH_METHOD *
236 DH_ltm_method(void)
237 {
238     return &_hc_dh_ltm_method;
239 }