kdc: Provide extended error information in AS-REP error replies.
[tprouty/samba.git] / source4 / heimdal / lib / hcrypto / dh.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
38 RCSID("$Id: dh.c 18618 2006-10-19 17:31:51Z lha $");
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <dh.h>
43
44 #include <roken.h>
45
46 /*
47  *
48  */
49
50 DH *
51 DH_new(void)
52 {
53     return DH_new_method(NULL);
54 }
55
56 DH *
57 DH_new_method(ENGINE *engine)
58 {
59     DH *dh;
60
61     dh = calloc(1, sizeof(*dh));
62     if (dh == NULL)
63         return NULL;
64
65     dh->references = 1;
66
67     if (engine) {
68         ENGINE_up_ref(engine);
69         dh->engine = engine;
70     } else {
71         dh->engine = ENGINE_get_default_DH();
72     }
73
74     if (dh->engine) {
75         dh->meth = ENGINE_get_DH(dh->engine);
76         if (dh->meth == NULL) {
77             ENGINE_finish(engine);
78             free(dh);
79             return 0;
80         }
81     }
82
83     if (dh->meth == NULL)
84         dh->meth = DH_get_default_method();
85
86     (*dh->meth->init)(dh);
87
88     return dh;
89 }
90
91 void
92 DH_free(DH *dh)
93 {
94     if (dh->references <= 0)
95         abort();
96
97     if (--dh->references > 0)
98         return;
99
100     (*dh->meth->finish)(dh);
101
102     if (dh->engine)
103         ENGINE_finish(dh->engine);
104
105 #define free_if(f) if (f) { BN_free(f); }
106     free_if(dh->p);
107     free_if(dh->g);
108     free_if(dh->pub_key);
109     free_if(dh->priv_key);
110     free_if(dh->q);
111     free_if(dh->j);
112     free_if(dh->counter);
113 #undef free_if
114
115     memset(dh, 0, sizeof(*dh));
116     free(dh);
117 }    
118
119 int
120 DH_up_ref(DH *dh)
121 {
122     return ++dh->references;
123 }
124
125 int
126 DH_size(const DH *dh)
127 {
128     return BN_num_bytes(dh->p);
129 }
130
131 int
132 DH_set_ex_data(DH *dh, int idx, void *data)
133 {
134     dh->ex_data.sk = data;
135     return 1;
136 }
137
138 void *
139 DH_get_ex_data(DH *dh, int idx)
140 {
141     return dh->ex_data.sk;
142 }
143
144 int
145 DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb)
146 {
147     if (dh->meth->generate_params)
148         return dh->meth->generate_params(dh, prime_len, generator, cb);
149     return 0;
150 }
151
152 /*
153  * Check that
154  *
155  *      pub_key > 1    and    pub_key < p - 1
156  *
157  * to avoid small subgroups attack.
158  */
159
160 int
161 DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes)
162 {
163     BIGNUM *bn = NULL, *sum = NULL;
164     int ret = 0;
165
166     *codes = 0;
167
168     bn = BN_new();
169     if (bn == NULL)
170         goto out;
171
172     if (!BN_set_word(bn, 1))
173         goto out;
174
175     if (BN_cmp(bn, pub_key) >= 0)
176         *codes |= DH_CHECK_PUBKEY_TOO_SMALL;
177
178     sum = BN_new();
179     if (sum == NULL)
180         goto out;
181
182     BN_uadd(sum, pub_key, bn);
183
184     if (BN_cmp(sum, dh->p) >= 0)
185         *codes |= DH_CHECK_PUBKEY_TOO_LARGE;
186
187     ret = 1;
188 out:
189     if (bn)
190         BN_free(bn);
191     if (sum)
192         BN_free(sum);
193
194     return ret;
195 }
196
197 int
198 DH_generate_key(DH *dh)
199 {
200     return dh->meth->generate_key(dh);
201 }
202
203 int
204 DH_compute_key(unsigned char *shared_key,
205                const BIGNUM *peer_pub_key, DH *dh)
206 {
207     int codes;
208
209     if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0)
210         return -1;
211
212     return dh->meth->compute_key(shared_key, peer_pub_key, dh);
213 }
214
215 int
216 DH_set_method(DH *dh, const DH_METHOD *method)
217 {
218     (*dh->meth->finish)(dh);
219     if (dh->engine) {
220         ENGINE_finish(dh->engine);
221         dh->engine = NULL;
222     }
223     dh->meth = method;
224     (*dh->meth->init)(dh);
225     return 1;
226 }
227
228 /*
229  *
230  */
231
232 static int
233 dh_null_generate_key(DH *dh)
234 {
235     return 0;
236 }
237
238 static int
239 dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh)
240 {
241     return 0;
242 }
243
244 static int
245 dh_null_init(DH *dh)
246 {
247     return 1;
248 }
249
250 static int
251 dh_null_finish(DH *dh)
252 {
253     return 1;
254 }
255
256 static int
257 dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb)
258 {
259     return 0;
260 }
261
262 static const DH_METHOD dh_null_method = {
263     "hcrypto null DH",
264     dh_null_generate_key,
265     dh_null_compute_key,
266     NULL,
267     dh_null_init,
268     dh_null_finish,
269     0,
270     NULL,
271     dh_null_generate_params
272 };
273
274 extern const DH_METHOD hc_dh_imath_method;
275 static const DH_METHOD *dh_default_method = &hc_dh_imath_method;
276
277 const DH_METHOD *
278 DH_null_method(void)
279 {
280     return &dh_null_method;
281 }
282
283 void
284 DH_set_default_method(const DH_METHOD *meth)
285 {
286     dh_default_method = meth;
287 }
288
289 const DH_METHOD *
290 DH_get_default_method(void)
291 {
292     return dh_default_method;
293 }
294