source: trunk/library/md5.c @ 1159

Revision 1159, 15.5 KB checked in by paul, 5 months ago (diff)
  • Changed the behaviour of x509parse_parse_crt for permissive parsing. Now returns the number of 'failed certificates' instead of having a switch to enable it.
  • As a consequence all error code that were positive were changed. A lot of MALLOC_FAILED and FILE_IO_ERROR error codes added for different modules.
  • Programs and tests were adapted accordingly
Line 
1/*
2 *  RFC 1321 compliant MD5 implementation
3 *
4 *  Copyright (C) 2006-2010, Brainspark B.V.
5 *
6 *  This file is part of PolarSSL (http://www.polarssl.org)
7 *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 *  All rights reserved.
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License along
22 *  with this program; if not, write to the Free Software Foundation, Inc.,
23 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25/*
26 *  The MD5 algorithm was designed by Ron Rivest in 1991.
27 *
28 *  http://www.ietf.org/rfc/rfc1321.txt
29 */
30
31#include "polarssl/config.h"
32
33#if defined(POLARSSL_MD5_C)
34
35#include "polarssl/md5.h"
36
37#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
38#include <stdio.h>
39#endif
40
41/*
42 * 32-bit integer manipulation macros (little endian)
43 */
44#ifndef GET_ULONG_LE
45#define GET_ULONG_LE(n,b,i)                             \
46{                                                       \
47    (n) = ( (unsigned long) (b)[(i)    ]       )        \
48        | ( (unsigned long) (b)[(i) + 1] <<  8 )        \
49        | ( (unsigned long) (b)[(i) + 2] << 16 )        \
50        | ( (unsigned long) (b)[(i) + 3] << 24 );       \
51}
52#endif
53
54#ifndef PUT_ULONG_LE
55#define PUT_ULONG_LE(n,b,i)                             \
56{                                                       \
57    (b)[(i)    ] = (unsigned char) ( (n)       );       \
58    (b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
59    (b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
60    (b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
61}
62#endif
63
64/*
65 * MD5 context setup
66 */
67void md5_starts( md5_context *ctx )
68{
69    ctx->total[0] = 0;
70    ctx->total[1] = 0;
71
72    ctx->state[0] = 0x67452301;
73    ctx->state[1] = 0xEFCDAB89;
74    ctx->state[2] = 0x98BADCFE;
75    ctx->state[3] = 0x10325476;
76}
77
78static void md5_process( md5_context *ctx, const unsigned char data[64] )
79{
80    unsigned long X[16], A, B, C, D;
81
82    GET_ULONG_LE( X[ 0], data,  0 );
83    GET_ULONG_LE( X[ 1], data,  4 );
84    GET_ULONG_LE( X[ 2], data,  8 );
85    GET_ULONG_LE( X[ 3], data, 12 );
86    GET_ULONG_LE( X[ 4], data, 16 );
87    GET_ULONG_LE( X[ 5], data, 20 );
88    GET_ULONG_LE( X[ 6], data, 24 );
89    GET_ULONG_LE( X[ 7], data, 28 );
90    GET_ULONG_LE( X[ 8], data, 32 );
91    GET_ULONG_LE( X[ 9], data, 36 );
92    GET_ULONG_LE( X[10], data, 40 );
93    GET_ULONG_LE( X[11], data, 44 );
94    GET_ULONG_LE( X[12], data, 48 );
95    GET_ULONG_LE( X[13], data, 52 );
96    GET_ULONG_LE( X[14], data, 56 );
97    GET_ULONG_LE( X[15], data, 60 );
98
99#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
100
101#define P(a,b,c,d,k,s,t)                                \
102{                                                       \
103    a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
104}
105
106    A = ctx->state[0];
107    B = ctx->state[1];
108    C = ctx->state[2];
109    D = ctx->state[3];
110
111#define F(x,y,z) (z ^ (x & (y ^ z)))
112
113    P( A, B, C, D,  0,  7, 0xD76AA478 );
114    P( D, A, B, C,  1, 12, 0xE8C7B756 );
115    P( C, D, A, B,  2, 17, 0x242070DB );
116    P( B, C, D, A,  3, 22, 0xC1BDCEEE );
117    P( A, B, C, D,  4,  7, 0xF57C0FAF );
118    P( D, A, B, C,  5, 12, 0x4787C62A );
119    P( C, D, A, B,  6, 17, 0xA8304613 );
120    P( B, C, D, A,  7, 22, 0xFD469501 );
121    P( A, B, C, D,  8,  7, 0x698098D8 );
122    P( D, A, B, C,  9, 12, 0x8B44F7AF );
123    P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
124    P( B, C, D, A, 11, 22, 0x895CD7BE );
125    P( A, B, C, D, 12,  7, 0x6B901122 );
126    P( D, A, B, C, 13, 12, 0xFD987193 );
127    P( C, D, A, B, 14, 17, 0xA679438E );
128    P( B, C, D, A, 15, 22, 0x49B40821 );
129
130#undef F
131
132#define F(x,y,z) (y ^ (z & (x ^ y)))
133
134    P( A, B, C, D,  1,  5, 0xF61E2562 );
135    P( D, A, B, C,  6,  9, 0xC040B340 );
136    P( C, D, A, B, 11, 14, 0x265E5A51 );
137    P( B, C, D, A,  0, 20, 0xE9B6C7AA );
138    P( A, B, C, D,  5,  5, 0xD62F105D );
139    P( D, A, B, C, 10,  9, 0x02441453 );
140    P( C, D, A, B, 15, 14, 0xD8A1E681 );
141    P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
142    P( A, B, C, D,  9,  5, 0x21E1CDE6 );
143    P( D, A, B, C, 14,  9, 0xC33707D6 );
144    P( C, D, A, B,  3, 14, 0xF4D50D87 );
145    P( B, C, D, A,  8, 20, 0x455A14ED );
146    P( A, B, C, D, 13,  5, 0xA9E3E905 );
147    P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
148    P( C, D, A, B,  7, 14, 0x676F02D9 );
149    P( B, C, D, A, 12, 20, 0x8D2A4C8A );
150
151#undef F
152   
153#define F(x,y,z) (x ^ y ^ z)
154
155    P( A, B, C, D,  5,  4, 0xFFFA3942 );
156    P( D, A, B, C,  8, 11, 0x8771F681 );
157    P( C, D, A, B, 11, 16, 0x6D9D6122 );
158    P( B, C, D, A, 14, 23, 0xFDE5380C );
159    P( A, B, C, D,  1,  4, 0xA4BEEA44 );
160    P( D, A, B, C,  4, 11, 0x4BDECFA9 );
161    P( C, D, A, B,  7, 16, 0xF6BB4B60 );
162    P( B, C, D, A, 10, 23, 0xBEBFBC70 );
163    P( A, B, C, D, 13,  4, 0x289B7EC6 );
164    P( D, A, B, C,  0, 11, 0xEAA127FA );
165    P( C, D, A, B,  3, 16, 0xD4EF3085 );
166    P( B, C, D, A,  6, 23, 0x04881D05 );
167    P( A, B, C, D,  9,  4, 0xD9D4D039 );
168    P( D, A, B, C, 12, 11, 0xE6DB99E5 );
169    P( C, D, A, B, 15, 16, 0x1FA27CF8 );
170    P( B, C, D, A,  2, 23, 0xC4AC5665 );
171
172#undef F
173
174#define F(x,y,z) (y ^ (x | ~z))
175
176    P( A, B, C, D,  0,  6, 0xF4292244 );
177    P( D, A, B, C,  7, 10, 0x432AFF97 );
178    P( C, D, A, B, 14, 15, 0xAB9423A7 );
179    P( B, C, D, A,  5, 21, 0xFC93A039 );
180    P( A, B, C, D, 12,  6, 0x655B59C3 );
181    P( D, A, B, C,  3, 10, 0x8F0CCC92 );
182    P( C, D, A, B, 10, 15, 0xFFEFF47D );
183    P( B, C, D, A,  1, 21, 0x85845DD1 );
184    P( A, B, C, D,  8,  6, 0x6FA87E4F );
185    P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
186    P( C, D, A, B,  6, 15, 0xA3014314 );
187    P( B, C, D, A, 13, 21, 0x4E0811A1 );
188    P( A, B, C, D,  4,  6, 0xF7537E82 );
189    P( D, A, B, C, 11, 10, 0xBD3AF235 );
190    P( C, D, A, B,  2, 15, 0x2AD7D2BB );
191    P( B, C, D, A,  9, 21, 0xEB86D391 );
192
193#undef F
194
195    ctx->state[0] += A;
196    ctx->state[1] += B;
197    ctx->state[2] += C;
198    ctx->state[3] += D;
199}
200
201/*
202 * MD5 process buffer
203 */
204void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen )
205{
206    size_t fill;
207    unsigned long left;
208
209    if( ilen <= 0 )
210        return;
211
212    left = ctx->total[0] & 0x3F;
213    fill = 64 - left;
214
215    ctx->total[0] += (unsigned long) ilen;
216    ctx->total[0] &= 0xFFFFFFFF;
217
218    if( ctx->total[0] < (unsigned long) ilen )
219        ctx->total[1]++;
220
221    if( left && ilen >= fill )
222    {
223        memcpy( (void *) (ctx->buffer + left),
224                (void *) input, fill );
225        md5_process( ctx, ctx->buffer );
226        input += fill;
227        ilen  -= fill;
228        left = 0;
229    }
230
231    while( ilen >= 64 )
232    {
233        md5_process( ctx, input );
234        input += 64;
235        ilen  -= 64;
236    }
237
238    if( ilen > 0 )
239    {
240        memcpy( (void *) (ctx->buffer + left),
241                (void *) input, ilen );
242    }
243}
244
245static const unsigned char md5_padding[64] =
246{
247 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
248    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
249    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
251};
252
253/*
254 * MD5 final digest
255 */
256void md5_finish( md5_context *ctx, unsigned char output[16] )
257{
258    unsigned long last, padn;
259    unsigned long high, low;
260    unsigned char msglen[8];
261
262    high = ( ctx->total[0] >> 29 )
263         | ( ctx->total[1] <<  3 );
264    low  = ( ctx->total[0] <<  3 );
265
266    PUT_ULONG_LE( low,  msglen, 0 );
267    PUT_ULONG_LE( high, msglen, 4 );
268
269    last = ctx->total[0] & 0x3F;
270    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
271
272    md5_update( ctx, (unsigned char *) md5_padding, padn );
273    md5_update( ctx, msglen, 8 );
274
275    PUT_ULONG_LE( ctx->state[0], output,  0 );
276    PUT_ULONG_LE( ctx->state[1], output,  4 );
277    PUT_ULONG_LE( ctx->state[2], output,  8 );
278    PUT_ULONG_LE( ctx->state[3], output, 12 );
279}
280
281/*
282 * output = MD5( input buffer )
283 */
284void md5( const unsigned char *input, size_t ilen, unsigned char output[16] )
285{
286    md5_context ctx;
287
288    md5_starts( &ctx );
289    md5_update( &ctx, input, ilen );
290    md5_finish( &ctx, output );
291
292    memset( &ctx, 0, sizeof( md5_context ) );
293}
294
295#if defined(POLARSSL_FS_IO)
296/*
297 * output = MD5( file contents )
298 */
299int md5_file( const char *path, unsigned char output[16] )
300{
301    FILE *f;
302    size_t n;
303    md5_context ctx;
304    unsigned char buf[1024];
305
306    if( ( f = fopen( path, "rb" ) ) == NULL )
307        return( POLARSSL_ERR_MD5_FILE_IO_ERROR );
308
309    md5_starts( &ctx );
310
311    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
312        md5_update( &ctx, buf, n );
313
314    md5_finish( &ctx, output );
315
316    memset( &ctx, 0, sizeof( md5_context ) );
317
318    if( ferror( f ) != 0 )
319    {
320        fclose( f );
321        return( POLARSSL_ERR_MD5_FILE_IO_ERROR );
322    }
323
324    fclose( f );
325    return( 0 );
326}
327#endif /* POLARSSL_FS_IO */
328
329/*
330 * MD5 HMAC context setup
331 */
332void md5_hmac_starts( md5_context *ctx, const unsigned char *key, size_t keylen )
333{
334    size_t i;
335    unsigned char sum[16];
336
337    if( keylen > 64 )
338    {
339        md5( key, keylen, sum );
340        keylen = 16;
341        key = sum;
342    }
343
344    memset( ctx->ipad, 0x36, 64 );
345    memset( ctx->opad, 0x5C, 64 );
346
347    for( i = 0; i < keylen; i++ )
348    {
349        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
350        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
351    }
352
353    md5_starts( ctx );
354    md5_update( ctx, ctx->ipad, 64 );
355
356    memset( sum, 0, sizeof( sum ) );
357}
358
359/*
360 * MD5 HMAC process buffer
361 */
362void md5_hmac_update( md5_context *ctx, const unsigned char *input, size_t ilen )
363{
364    md5_update( ctx, input, ilen );
365}
366
367/*
368 * MD5 HMAC final digest
369 */
370void md5_hmac_finish( md5_context *ctx, unsigned char output[16] )
371{
372    unsigned char tmpbuf[16];
373
374    md5_finish( ctx, tmpbuf );
375    md5_starts( ctx );
376    md5_update( ctx, ctx->opad, 64 );
377    md5_update( ctx, tmpbuf, 16 );
378    md5_finish( ctx, output );
379
380    memset( tmpbuf, 0, sizeof( tmpbuf ) );
381}
382
383/*
384 * MD5 HMAC context reset
385 */
386void md5_hmac_reset( md5_context *ctx )
387{
388    md5_starts( ctx );
389    md5_update( ctx, ctx->ipad, 64 );
390}
391
392/*
393 * output = HMAC-MD5( hmac key, input buffer )
394 */
395void md5_hmac( const unsigned char *key, size_t keylen,
396               const unsigned char *input, size_t ilen,
397               unsigned char output[16] )
398{
399    md5_context ctx;
400
401    md5_hmac_starts( &ctx, key, keylen );
402    md5_hmac_update( &ctx, input, ilen );
403    md5_hmac_finish( &ctx, output );
404
405    memset( &ctx, 0, sizeof( md5_context ) );
406}
407
408#if defined(POLARSSL_SELF_TEST)
409/*
410 * RFC 1321 test vectors
411 */
412static unsigned char md5_test_buf[7][81] =
413{
414    { "" }, 
415    { "a" },
416    { "abc" },
417    { "message digest" },
418    { "abcdefghijklmnopqrstuvwxyz" },
419    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
420    { "12345678901234567890123456789012345678901234567890123456789012" \
421      "345678901234567890" }
422};
423
424static const int md5_test_buflen[7] =
425{
426    0, 1, 3, 14, 26, 62, 80
427};
428
429static const unsigned char md5_test_sum[7][16] =
430{
431    { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
432      0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
433    { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
434      0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
435    { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
436      0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
437    { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
438      0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
439    { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
440      0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
441    { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
442      0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
443    { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
444      0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
445};
446
447/*
448 * RFC 2202 test vectors
449 */
450static unsigned char md5_hmac_test_key[7][26] =
451{
452    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" },
453    { "Jefe" },
454    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" },
455    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
456      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
457    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" },
458    { "" }, /* 0xAA 80 times */
459    { "" }
460};
461
462static const int md5_hmac_test_keylen[7] =
463{
464    16, 4, 16, 25, 16, 80, 80
465};
466
467static unsigned char md5_hmac_test_buf[7][74] =
468{
469    { "Hi There" },
470    { "what do ya want for nothing?" },
471    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
472      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
473      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
474      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
475      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
476    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
477      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
478      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
479      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
480      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
481    { "Test With Truncation" },
482    { "Test Using Larger Than Block-Size Key - Hash Key First" },
483    { "Test Using Larger Than Block-Size Key and Larger"
484      " Than One Block-Size Data" }
485};
486
487static const int md5_hmac_test_buflen[7] =
488{
489    8, 28, 50, 50, 20, 54, 73
490};
491
492static const unsigned char md5_hmac_test_sum[7][16] =
493{
494    { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
495      0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D },
496    { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
497      0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 },
498    { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
499      0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 },
500    { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
501      0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 },
502    { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
503      0xF9, 0xBA, 0xB9, 0x95 },
504    { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
505      0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD },
506    { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
507      0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E }
508};
509
510/*
511 * Checkup routine
512 */
513int md5_self_test( int verbose )
514{
515    int i, buflen;
516    unsigned char buf[1024];
517    unsigned char md5sum[16];
518    md5_context ctx;
519
520    for( i = 0; i < 7; i++ )
521    {
522        if( verbose != 0 )
523            printf( "  MD5 test #%d: ", i + 1 );
524
525        md5( md5_test_buf[i], md5_test_buflen[i], md5sum );
526
527        if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
528        {
529            if( verbose != 0 )
530                printf( "failed\n" );
531
532            return( 1 );
533        }
534
535        if( verbose != 0 )
536            printf( "passed\n" );
537    }
538
539    if( verbose != 0 )
540        printf( "\n" );
541
542    for( i = 0; i < 7; i++ )
543    {
544        if( verbose != 0 )
545            printf( "  HMAC-MD5 test #%d: ", i + 1 );
546
547        if( i == 5 || i == 6 )
548        {
549            memset( buf, '\xAA', buflen = 80 );
550            md5_hmac_starts( &ctx, buf, buflen );
551        }
552        else
553            md5_hmac_starts( &ctx, md5_hmac_test_key[i],
554                                   md5_hmac_test_keylen[i] );
555
556        md5_hmac_update( &ctx, md5_hmac_test_buf[i],
557                               md5_hmac_test_buflen[i] );
558
559        md5_hmac_finish( &ctx, md5sum );
560
561        buflen = ( i == 4 ) ? 12 : 16;
562
563        if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 )
564        {
565            if( verbose != 0 )
566                printf( "failed\n" );
567
568            return( 1 );
569        }
570
571        if( verbose != 0 )
572            printf( "passed\n" );
573    }
574
575    if( verbose != 0 )
576        printf( "\n" );
577
578    return( 0 );
579}
580
581#endif
582
583#endif
Note: See TracBrowser for help on using the repository browser.

What are you looking for?