~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/hcrypto/dh.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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$");
 
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