Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-local
[kai/samba.git] / source4 / heimdal / lib / hcrypto / dh.c
1 /*
2  * Copyright (c) 2006 - 2007 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 22397 2008-01-01 20:20:31Z lha $");
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <dh.h>
43
44 #include <roken.h>
45
46 /**
47  * @page page_dh DH - Diffie-Hellman key exchange
48  *
49  * Diffie-Hellman key exchange is a protocol that allows two parties
50  * to establish a shared secret key.
51  *
52  * Include and example how to use DH_new() and friends here.
53  *
54  * See the library functions here: @ref hcrypto_dh
55  */
56
57 /**
58  * Create a new DH object using DH_new_method(NULL), see DH_new_method().
59  *
60  * @return a newly allocated DH object.
61  *
62  * @ingroup hcrypto_dh
63  */
64
65 DH *
66 DH_new(void)
67 {
68     return DH_new_method(NULL);
69 }
70
71 /**
72  * Create a new DH object from the given engine, if the NULL is used,
73  * the default engine is used. Free the DH object with DH_free().
74  *
75  * @param engine The engine to use to allocate the DH object. 
76  *
77  * @return a newly allocated DH object.
78  *
79  * @ingroup hcrypto_dh
80  */
81
82 DH *
83 DH_new_method(ENGINE *engine)
84 {
85     DH *dh;
86
87     dh = calloc(1, sizeof(*dh));
88     if (dh == NULL)
89         return NULL;
90
91     dh->references = 1;
92
93     if (engine) {
94         ENGINE_up_ref(engine);
95         dh->engine = engine;
96     } else {
97         dh->engine = ENGINE_get_default_DH();
98     }
99
100     if (dh->engine) {
101         dh->meth = ENGINE_get_DH(dh->engine);
102         if (dh->meth == NULL) {
103             ENGINE_finish(engine);
104             free(dh);
105             return 0;
106         }
107     }
108
109     if (dh->meth == NULL)
110         dh->meth = DH_get_default_method();
111
112     (*dh->meth->init)(dh);
113
114     return dh;
115 }
116
117 /**
118  * Free a DH object and release related resources, like ENGINE, that
119  * the object was using.
120  *
121  * @param dh object to be freed.
122  *
123  * @ingroup hcrypto_dh
124  */
125
126 void
127 DH_free(DH *dh)
128 {
129     if (dh->references <= 0)
130         abort();
131
132     if (--dh->references > 0)
133         return;
134
135     (*dh->meth->finish)(dh);
136
137     if (dh->engine)
138         ENGINE_finish(dh->engine);
139
140 #define free_if(f) if (f) { BN_free(f); }
141     free_if(dh->p);
142     free_if(dh->g);
143     free_if(dh->pub_key);
144     free_if(dh->priv_key);
145     free_if(dh->q);
146     free_if(dh->j);
147     free_if(dh->counter);
148 #undef free_if
149
150     memset(dh, 0, sizeof(*dh));
151     free(dh);
152 }    
153
154 /**
155  * Add a reference to the DH object. The object should be free with
156  * DH_free() to drop the reference.
157  *
158  * @param dh the object to increase the reference count too.
159  *
160  * @return the updated reference count, can't safely be used except
161  * for debug printing.
162  * 
163  * @ingroup hcrypto_dh
164  */
165
166 int
167 DH_up_ref(DH *dh)
168 {
169     return ++dh->references;
170 }
171
172 /**
173  * The maximum output size of the DH_compute_key() function.
174  *
175  * @param dh The DH object to get the size from.
176  *
177  * @return the maximum size in bytes of the out data.
178  *
179  * @ingroup hcrypto_dh
180  */
181
182 int
183 DH_size(const DH *dh)
184 {
185     return BN_num_bytes(dh->p);
186 }
187
188 /**
189  * Set the data index idx in the DH object to data.
190  *
191  * @param dh DH object.
192  * @param idx index to set the data for.
193  * @param data data to store for the index idx.
194  *
195  * @return 1 on success.
196  *
197  * @ingroup hcrypto_dh
198  */
199
200 int
201 DH_set_ex_data(DH *dh, int idx, void *data)
202 {
203     dh->ex_data.sk = data;
204     return 1;
205 }
206
207 /**
208  * Get the data for index idx in the DH object.
209  *
210  * @param dh DH object.
211  * @param idx index to get the data for.
212  *
213  * @return the object store in index idx
214  *
215  * @ingroup hcrypto_dh
216  */
217
218 void *
219 DH_get_ex_data(DH *dh, int idx)
220 {
221     return dh->ex_data.sk;
222 }
223
224 /**
225  * Generate DH parameters for the DH object give parameters.
226  *
227  * @param dh The DH object to generate parameters for.
228  * @param prime_len length of the prime
229  * @param generator generator, g
230  * @param cb Callback parameters to show progress, can be NULL.
231  *
232  * @return the maximum size in bytes of the out data.
233  *
234  * @ingroup hcrypto_dh
235  */
236
237 int
238 DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb)
239 {
240     if (dh->meth->generate_params)
241         return dh->meth->generate_params(dh, prime_len, generator, cb);
242     return 0;
243 }
244
245 /**
246  * Check that the public key is sane.
247  *
248  * @param dh the local peer DH parameters.
249  * @param pub_key the remote peer public key parameters.
250  * @param codes return that the failures of the pub_key are.
251  *
252  * @return 1 on success, 0 on failure and *codes is set the the
253  * combined fail check for the public key
254  *
255  * @ingroup hcrypto_dh
256  */
257
258 int
259 DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes)
260 {
261     BIGNUM *bn = NULL, *sum = NULL;
262     int ret = 0;
263
264     *codes = 0;
265
266     /**
267      * Checks that the function performs are:
268      * - pub_key is not negative 
269      */
270
271     if (BN_is_negative(pub_key))
272         goto out;
273
274     /**
275      * - pub_key > 1    and    pub_key < p - 1,
276      *    to avoid small subgroups attack.
277      */
278
279     bn = BN_new();
280     if (bn == NULL)
281         goto out;
282
283     if (!BN_set_word(bn, 1))
284         goto out;
285
286     if (BN_cmp(bn, pub_key) >= 0)
287         *codes |= DH_CHECK_PUBKEY_TOO_SMALL;
288
289     sum = BN_new();
290     if (sum == NULL)
291         goto out;
292
293     BN_uadd(sum, pub_key, bn);
294
295     if (BN_cmp(sum, dh->p) >= 0)
296         *codes |= DH_CHECK_PUBKEY_TOO_LARGE;
297
298     /**
299      * - if g == 2, pub_key have more then one bit set,
300      *   if bits set is 1, log_2(pub_key) is trival
301      */
302
303     if (!BN_set_word(bn, 2))
304         goto out;
305
306     if (BN_cmp(bn, pub_key) == 0) {
307         unsigned i, n = BN_num_bits(pub_key);
308         unsigned bits = 0;
309
310         for (i = 0; i <= n; i++)
311             if (BN_is_bit_set(pub_key, i))
312                 bits++;
313
314         if (bits > 1) {
315             *codes |= DH_CHECK_PUBKEY_TOO_SMALL;
316             goto out;
317         }
318     }
319
320     ret = 1;
321 out:
322     if (bn)
323         BN_free(bn);
324     if (sum)
325         BN_free(sum);
326
327     return ret;
328 }
329
330 /**
331  * Generate a new DH private-public key pair. The dh parameter must be
332  * allocted first with DH_new(). dh->p and dp->g must be set.
333  *
334  * @param dh dh parameter.
335  *
336  * @return 1 on success.
337  *
338  * @ingroup hcrypto_dh
339  */
340
341 int
342 DH_generate_key(DH *dh)
343 {
344     return dh->meth->generate_key(dh);
345 }
346
347 /**
348  * Complute the shared secret key.
349  *
350  * @param shared_key the resulting shared key, need to be at least
351  * DH_size() large.
352  * @param peer_pub_key the peer's public key.
353  * @param dh the dh key pair.
354  *
355  * @return 1 on success.
356  *
357  * @ingroup hcrypto_dh
358  */
359
360 int
361 DH_compute_key(unsigned char *shared_key,
362                const BIGNUM *peer_pub_key, DH *dh)
363 {
364     int codes;
365
366     /**
367      * Checks that the pubkey passed in is valid using
368      * DH_check_pubkey().
369      */
370
371     if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0)
372         return -1;
373
374     return dh->meth->compute_key(shared_key, peer_pub_key, dh);
375 }
376
377 /**
378  * Set a new method for the DH keypair.
379  *
380  * @param dh dh parameter.
381  * @param method the new method for the DH parameter.
382  *
383  * @return 1 on success.
384  *
385  * @ingroup hcrypto_dh
386  */
387
388 int
389 DH_set_method(DH *dh, const DH_METHOD *method)
390 {
391     (*dh->meth->finish)(dh);
392     if (dh->engine) {
393         ENGINE_finish(dh->engine);
394         dh->engine = NULL;
395     }
396     dh->meth = method;
397     (*dh->meth->init)(dh);
398     return 1;
399 }
400
401 /*
402  *
403  */
404
405 static int
406 dh_null_generate_key(DH *dh)
407 {
408     return 0;
409 }
410
411 static int
412 dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh)
413 {
414     return 0;
415 }
416
417 static int
418 dh_null_init(DH *dh)
419 {
420     return 1;
421 }
422
423 static int
424 dh_null_finish(DH *dh)
425 {
426     return 1;
427 }
428
429 static int
430 dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb)
431 {
432     return 0;
433 }
434
435 static const DH_METHOD dh_null_method = {
436     "hcrypto null DH",
437     dh_null_generate_key,
438     dh_null_compute_key,
439     NULL,
440     dh_null_init,
441     dh_null_finish,
442     0,
443     NULL,
444     dh_null_generate_params
445 };
446
447 extern const DH_METHOD _hc_dh_imath_method;
448 static const DH_METHOD *dh_default_method = &_hc_dh_imath_method;
449
450 /**
451  * Return the dummy DH implementation.
452  *
453  * @return pointer to a DH_METHOD.
454  *
455  * @ingroup hcrypto_dh
456  */
457
458 const DH_METHOD *
459 DH_null_method(void)
460 {
461     return &dh_null_method;
462 }
463
464 /**
465  * Set the default DH implementation.
466  *
467  * @param meth pointer to a DH_METHOD.
468  *
469  * @ingroup hcrypto_dh
470  */
471
472 void
473 DH_set_default_method(const DH_METHOD *meth)
474 {
475     dh_default_method = meth;
476 }
477
478 /**
479  * Return the default DH implementation.
480  *
481  * @return pointer to a DH_METHOD.
482  *
483  * @ingroup hcrypto_dh
484  */
485
486 const DH_METHOD *
487 DH_get_default_method(void)
488 {
489     return dh_default_method;
490 }
491