~ubuntu-branches/ubuntu/karmic/gnupg2/karmic-updates

« back to all changes in this revision

Viewing changes to cipher/md.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* md.c  -  message digest dispatcher
2
 
 *      Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
3
 
 *
4
 
 * This file is part of GnuPG.
5
 
 *
6
 
 * GnuPG is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * GnuPG is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19
 
 */
20
 
 
21
 
#include <config.h>
22
 
#include <stdio.h>
23
 
#include <stdlib.h>
24
 
#include <string.h>
25
 
#include <errno.h>
26
 
#include <assert.h>
27
 
#include "util.h"
28
 
#include "cipher.h"
29
 
#include "errors.h"
30
 
#include "algorithms.h"
31
 
#include "i18n.h"
32
 
 
33
 
/****************
34
 
 * This structure is used for the list of available algorithms
35
 
 * and for the list of algorithms in MD_HANDLE.
36
 
 */
37
 
struct md_digest_list_s {
38
 
    struct md_digest_list_s *next;
39
 
    const char *name;
40
 
    int algo;
41
 
    byte *asnoid;
42
 
    int asnlen;
43
 
    int mdlen;
44
 
    void (*init)( void *c );
45
 
    void (*write)( void *c, byte *buf, size_t nbytes );
46
 
    void (*final)( void *c );
47
 
    byte *(*read)( void *c );
48
 
    size_t contextsize; /* allocate this amount of context */
49
 
    PROPERLY_ALIGNED_TYPE context;
50
 
};
51
 
 
52
 
static struct md_digest_list_s *digest_list;
53
 
 
54
 
 
55
 
static struct md_digest_list_s *
56
 
new_list_item (int algo,
57
 
               const char *(*get_info)( int, size_t*,byte**, int*, int*,
58
 
                                       void (**)(void*),
59
 
                                       void (**)(void*,byte*,size_t),
60
 
                                       void (**)(void*),byte *(**)(void*)))
61
 
{
62
 
  struct md_digest_list_s *r;
63
 
 
64
 
  r = m_alloc_clear (sizeof *r );
65
 
  r->algo = algo;
66
 
  r->name = (*get_info)( algo, &r->contextsize,
67
 
                         &r->asnoid, &r->asnlen, &r->mdlen,
68
 
                         &r->init, &r->write, &r->final, &r->read );
69
 
  if (!r->name ) 
70
 
    {
71
 
      m_free(r);
72
 
      r = NULL;
73
 
    }
74
 
  if (r)
75
 
    {
76
 
      r->next = digest_list;
77
 
      digest_list = r;
78
 
    }
79
 
  return r;
80
 
}
81
 
 
82
 
 
83
 
 
84
 
/*
85
 
  Load all available hash algorithms and return true.  Subsequent
86
 
  calls will return 0.  
87
 
 */
88
 
static int
89
 
load_digest_module (void)
90
 
{
91
 
  static int initialized = 0;
92
 
 
93
 
  if (initialized)
94
 
    return 0;
95
 
  initialized = 1;
96
 
 
97
 
  /* We load them in reverse order so that the most
98
 
     frequently used are the first in the list. */
99
 
#ifdef USE_SHA512
100
 
  if (!new_list_item (DIGEST_ALGO_SHA512, sha512_get_info)) 
101
 
    BUG ();
102
 
  if (!new_list_item (DIGEST_ALGO_SHA384, sha384_get_info)) 
103
 
    BUG ();
104
 
#endif
105
 
#ifdef USE_SHA256
106
 
  if (!new_list_item (DIGEST_ALGO_SHA256, sha256_get_info)) 
107
 
    BUG ();
108
 
#endif
109
 
  if (!new_list_item (DIGEST_ALGO_MD5, md5_get_info)) 
110
 
    BUG ();
111
 
  if (!new_list_item (DIGEST_ALGO_RMD160, rmd160_get_info)) 
112
 
    BUG ();
113
 
  if (!new_list_item (DIGEST_ALGO_SHA1, sha1_get_info)) 
114
 
    BUG ();
115
 
 
116
 
  return 1;
117
 
}      
118
 
 
119
 
 
120
 
/****************
121
 
 * Map a string to the digest algo */
122
 
int
123
 
string_to_digest_algo( const char *string )
124
 
{
125
 
    struct md_digest_list_s *r;
126
 
 
127
 
    do {
128
 
        for(r = digest_list; r; r = r->next )
129
 
            if( !ascii_strcasecmp( r->name, string ) )
130
 
                return r->algo;
131
 
    } while( !r && load_digest_module () );
132
 
 
133
 
    /* Didn't find it, so try the Hx format */
134
 
    if(string[0]=='H' || string[0]=='h')
135
 
      {
136
 
        long val;
137
 
        char *endptr;
138
 
 
139
 
        string++;
140
 
 
141
 
        val=strtol(string,&endptr,10);
142
 
        if(*string!='\0' && *endptr=='\0' && check_digest_algo(val)==0)
143
 
          return val;
144
 
      }
145
 
 
146
 
    return 0;
147
 
}
148
 
 
149
 
/****************
150
 
 * Map a digest algo to a string
151
 
 */
152
 
const char *
153
 
digest_algo_to_string( int algo )
154
 
{
155
 
    struct md_digest_list_s *r;
156
 
 
157
 
    do {
158
 
        for(r = digest_list; r; r = r->next )
159
 
            if( r->algo == algo )
160
 
                return r->name;
161
 
    } while( !r && load_digest_module () );
162
 
    return NULL;
163
 
}
164
 
 
165
 
 
166
 
int
167
 
check_digest_algo( int algo )
168
 
{
169
 
    struct md_digest_list_s *r;
170
 
 
171
 
    do {
172
 
        for(r = digest_list; r; r = r->next )
173
 
            if( r->algo == algo )
174
 
                return 0;
175
 
    } while( !r && load_digest_module () );
176
 
    return G10ERR_DIGEST_ALGO;
177
 
}
178
 
 
179
 
 
180
 
 
181
 
/****************
182
 
 * Open a message digest handle for use with algorithm ALGO.
183
 
 * More algorithms may be added by md_enable(). The initial algorithm
184
 
 * may be 0.
185
 
 */
186
 
MD_HANDLE
187
 
md_open( int algo, int secure )
188
 
{
189
 
    MD_HANDLE hd;
190
 
    int bufsize;
191
 
 
192
 
    if( secure ) {
193
 
        bufsize = 512 - sizeof( *hd );
194
 
        hd = m_alloc_secure_clear( sizeof *hd + bufsize );
195
 
    }
196
 
    else {
197
 
        bufsize = 1024 - sizeof( *hd );
198
 
        hd = m_alloc_clear( sizeof *hd + bufsize );
199
 
    }
200
 
 
201
 
    hd->bufsize = bufsize+1; /* hd has already one byte allocated */
202
 
    hd->secure = secure;
203
 
    if( algo )
204
 
        md_enable( hd, algo );
205
 
    fast_random_poll();
206
 
    return hd;
207
 
}
208
 
 
209
 
void
210
 
md_enable( MD_HANDLE h, int algo )
211
 
{
212
 
    struct md_digest_list_s *r, *ac;
213
 
 
214
 
    for( ac=h->list; ac; ac = ac->next )
215
 
        if( ac->algo == algo )
216
 
            return ; /* already enabled */
217
 
    /* find the algorithm */
218
 
    do {
219
 
        for(r = digest_list; r; r = r->next )
220
 
            if( r->algo == algo )
221
 
                break;
222
 
    } while( !r && load_digest_module () );
223
 
    if( !r ) {
224
 
        log_error("md_enable: algorithm %d not available\n", algo );
225
 
        return;
226
 
    }
227
 
    /* and allocate a new list entry */
228
 
    ac = h->secure? m_alloc_secure( sizeof *ac + r->contextsize
229
 
                                               - sizeof(r->context) )
230
 
                  : m_alloc( sizeof *ac + r->contextsize
231
 
                                               - sizeof(r->context) );
232
 
    *ac = *r;
233
 
    ac->next = h->list;
234
 
    h->list = ac;
235
 
    /* and init this instance */
236
 
    (*ac->init)( &ac->context.c );
237
 
}
238
 
 
239
 
 
240
 
MD_HANDLE
241
 
md_copy( MD_HANDLE a )
242
 
{
243
 
    MD_HANDLE b;
244
 
    struct md_digest_list_s *ar, *br;
245
 
 
246
 
    if( a->bufcount )
247
 
        md_write( a, NULL, 0 );
248
 
    b = a->secure ? m_alloc_secure( sizeof *b + a->bufsize - 1 )
249
 
                  : m_alloc( sizeof *b + a->bufsize - 1 );
250
 
    memcpy( b, a, sizeof *a + a->bufsize - 1 );
251
 
    b->list = NULL;
252
 
    b->debug = NULL;
253
 
    /* and now copy the complete list of algorithms */
254
 
    /* I know that the copied list is reversed, but that doesn't matter */
255
 
    for( ar=a->list; ar; ar = ar->next ) {
256
 
        br = a->secure ? m_alloc_secure( sizeof *br + ar->contextsize
257
 
                                               - sizeof(ar->context) )
258
 
                       : m_alloc( sizeof *br + ar->contextsize
259
 
                                               - sizeof(ar->context) );
260
 
        memcpy( br, ar, sizeof(*br) + ar->contextsize
261
 
                                    - sizeof(ar->context) );
262
 
        br->next = b->list;
263
 
        b->list = br;
264
 
    }
265
 
 
266
 
    if( a->debug )
267
 
        md_start_debug( b, "unknown" );
268
 
    return b;
269
 
}
270
 
 
271
 
 
272
 
/****************
273
 
 * Reset all contexts and discard any buffered stuff.  This may be used
274
 
 * instead of a md_close(); md_open().
275
 
 */
276
 
void
277
 
md_reset( MD_HANDLE a )
278
 
{
279
 
    struct md_digest_list_s *r;
280
 
 
281
 
    a->bufcount = a->finalized = 0;
282
 
    for( r=a->list; r; r = r->next ) {
283
 
        memset( r->context.c, 0, r->contextsize );
284
 
        (*r->init)( &r->context.c );
285
 
    }
286
 
}
287
 
 
288
 
 
289
 
void
290
 
md_close(MD_HANDLE a)
291
 
{
292
 
    struct md_digest_list_s *r, *r2;
293
 
 
294
 
    if( !a )
295
 
        return;
296
 
    if( a->debug )
297
 
        md_stop_debug(a);
298
 
    for(r=a->list; r; r = r2 ) {
299
 
        r2 = r->next;
300
 
        m_free(r);
301
 
    }
302
 
    m_free(a);
303
 
}
304
 
 
305
 
 
306
 
void
307
 
md_write( MD_HANDLE a, const byte *inbuf, size_t inlen)
308
 
{
309
 
    struct md_digest_list_s *r;
310
 
 
311
 
    if( a->debug ) {
312
 
        if( a->bufcount && fwrite(a->buffer, a->bufcount, 1, a->debug ) != 1 )
313
 
            BUG();
314
 
        if( inlen && fwrite(inbuf, inlen, 1, a->debug ) != 1 )
315
 
            BUG();
316
 
    }
317
 
    for(r=a->list; r; r = r->next ) {
318
 
        (*r->write)( &r->context.c, a->buffer, a->bufcount );
319
 
        /* Fixme: all ->write fnc should take a const byte* */ 
320
 
        (*r->write)( &r->context.c, (byte*)inbuf, inlen );
321
 
    }
322
 
    a->bufcount = 0;
323
 
}
324
 
 
325
 
 
326
 
 
327
 
void
328
 
md_final(MD_HANDLE a)
329
 
{
330
 
    struct md_digest_list_s *r;
331
 
 
332
 
    if( a->finalized )
333
 
        return;
334
 
 
335
 
    if( a->bufcount )
336
 
        md_write( a, NULL, 0 );
337
 
 
338
 
    for(r=a->list; r; r = r->next ) {
339
 
        (*r->final)( &r->context.c );
340
 
    }
341
 
    a->finalized = 1;
342
 
}
343
 
 
344
 
 
345
 
/****************
346
 
 * if ALGO is null get the digest for the used algo (which should be only one)
347
 
 */
348
 
byte *
349
 
md_read( MD_HANDLE a, int algo )
350
 
{
351
 
    struct md_digest_list_s *r;
352
 
 
353
 
    if( !algo ) {  /* return the first algorithm */
354
 
        if( (r=a->list) ) {
355
 
            if( r->next )
356
 
                log_debug("more than algorithm in md_read(0)\n");
357
 
            return (*r->read)( &r->context.c );
358
 
        }
359
 
    }
360
 
    else {
361
 
        for(r=a->list; r; r = r->next )
362
 
            if( r->algo == algo )
363
 
                return (*r->read)( &r->context.c );
364
 
    }
365
 
    BUG();
366
 
    return NULL;
367
 
}
368
 
 
369
 
 
370
 
/****************
371
 
 * This function combines md_final and md_read but keeps the context
372
 
 * intact.  This function can be used to calculate intermediate
373
 
 * digests.  The digest is copied into buffer and the digestlength is
374
 
 * returned.  If buffer is NULL only the needed size for buffer is returned.
375
 
 * buflen gives the max size of buffer. If the buffer is too shourt to
376
 
 * hold the complete digest, the buffer is filled with as many bytes are
377
 
 * possible and this value is returned.
378
 
 */
379
 
int
380
 
md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen )
381
 
{
382
 
    struct md_digest_list_s *r = NULL;
383
 
    char *context;
384
 
    char *digest;
385
 
 
386
 
    if( a->bufcount )
387
 
        md_write( a, NULL, 0 );
388
 
 
389
 
    if( !algo ) {  /* return digest for the first algorithm */
390
 
        if( (r=a->list) && r->next )
391
 
            log_debug("more than algorithm in md_digest(0)\n");
392
 
    }
393
 
    else {
394
 
        for(r=a->list; r; r = r->next )
395
 
            if( r->algo == algo )
396
 
                break;
397
 
    }
398
 
    if( !r )
399
 
        BUG();
400
 
 
401
 
    if( !buffer )
402
 
        return r->mdlen;
403
 
 
404
 
    /* I don't want to change the interface, so I simply work on a copy
405
 
     * the context (extra overhead - should be fixed)*/
406
 
    context = a->secure ? m_alloc_secure( r->contextsize )
407
 
                        : m_alloc( r->contextsize );
408
 
    memcpy( context, r->context.c, r->contextsize );
409
 
    (*r->final)( context );
410
 
    digest = (*r->read)( context );
411
 
 
412
 
    if( buflen > r->mdlen )
413
 
        buflen = r->mdlen;
414
 
    memcpy( buffer, digest, buflen );
415
 
 
416
 
    m_free(context);
417
 
    return buflen;
418
 
}
419
 
 
420
 
 
421
 
int
422
 
md_get_algo( MD_HANDLE a )
423
 
{
424
 
    struct md_digest_list_s *r;
425
 
 
426
 
    if( (r=a->list) ) {
427
 
        if( r->next )
428
 
            log_error("WARNING: more than algorithm in md_get_algo()\n");
429
 
        return r->algo;
430
 
    }
431
 
    return 0;
432
 
}
433
 
 
434
 
/* Returns true if a given algo is in use in a md */
435
 
int
436
 
md_algo_present( MD_HANDLE a, int algo )
437
 
{
438
 
  struct md_digest_list_s *r=a->list;
439
 
 
440
 
  while(r)
441
 
    {
442
 
      if(r->algo==algo)
443
 
        return 1;
444
 
 
445
 
      r=r->next;
446
 
    }
447
 
 
448
 
  return 0;
449
 
}
450
 
 
451
 
/****************
452
 
 * Return the length of the digest
453
 
 */
454
 
int
455
 
md_digest_length( int algo )
456
 
{
457
 
    struct md_digest_list_s *r;
458
 
 
459
 
    do {
460
 
        for(r = digest_list; r; r = r->next ) {
461
 
            if( r->algo == algo )
462
 
                return r->mdlen;
463
 
        }
464
 
    } while( !r && load_digest_module () );
465
 
    log_error("WARNING: no length for md algo %d\n", algo);
466
 
    return 0;
467
 
}
468
 
 
469
 
 
470
 
/* Hmmm: add a mode to enumerate the OIDs
471
 
 *      to make g10/sig-check.c more portable */
472
 
const byte *
473
 
md_asn_oid( int algo, size_t *asnlen, size_t *mdlen )
474
 
{
475
 
    struct md_digest_list_s *r;
476
 
 
477
 
    do {
478
 
        for(r = digest_list; r; r = r->next ) {
479
 
            if( r->algo == algo ) {
480
 
                if( asnlen )
481
 
                    *asnlen = r->asnlen;
482
 
                if( mdlen )
483
 
                    *mdlen = r->mdlen;
484
 
                return r->asnoid;
485
 
            }
486
 
        }
487
 
    } while( !r && load_digest_module () );
488
 
    log_bug("no asn for md algo %d\n", algo);
489
 
    return NULL;
490
 
}
491
 
 
492
 
 
493
 
void
494
 
md_start_debug( MD_HANDLE md, const char *suffix )
495
 
{
496
 
    static int idx=0;
497
 
    char buf[25];
498
 
 
499
 
    if( md->debug ) {
500
 
        log_debug("Oops: md debug already started\n");
501
 
        return;
502
 
    }
503
 
    idx++;
504
 
    sprintf(buf, "dbgmd-%05d" EXTSEP_S "%.10s", idx, suffix );
505
 
    md->debug = fopen(buf, "wb");
506
 
    if( !md->debug )
507
 
        log_debug("md debug: can't open %s\n", buf );
508
 
}
509
 
 
510
 
void
511
 
md_stop_debug( MD_HANDLE md )
512
 
{
513
 
    if( md->debug ) {
514
 
        if( md->bufcount )
515
 
            md_write( md, NULL, 0 );
516
 
        fclose(md->debug);
517
 
        md->debug = NULL;
518
 
    }
519
 
#ifdef HAVE_U64_TYPEDEF
520
 
    {  /* a kludge to pull in the __muldi3 for Solaris */
521
 
       volatile u32 a = (u32)(ulong)md;
522
 
       volatile u64 b = 42;
523
 
       volatile u64 c;
524
 
       c = a * b;
525
 
    }
526
 
#endif
527
 
}