~ubuntu-branches/ubuntu/hardy/openssl/hardy-security

« back to all changes in this revision

Viewing changes to crypto/pkcs7/bio_ber.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Martin
  • Date: 2004-05-24 17:02:29 UTC
  • Revision ID: james.westby@ubuntu.com-20040524170229-ixlo08bbbly0xied
Tags: upstream-0.9.7d
ImportĀ upstreamĀ versionĀ 0.9.7d

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* crypto/evp/bio_ber.c */
 
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 
3
 * All rights reserved.
 
4
 *
 
5
 * This package is an SSL implementation written
 
6
 * by Eric Young (eay@cryptsoft.com).
 
7
 * The implementation was written so as to conform with Netscapes SSL.
 
8
 * 
 
9
 * This library is free for commercial and non-commercial use as long as
 
10
 * the following conditions are aheared to.  The following conditions
 
11
 * apply to all code found in this distribution, be it the RC4, RSA,
 
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 
13
 * included with this distribution is covered by the same copyright terms
 
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 
15
 * 
 
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
 
17
 * the code are not to be removed.
 
18
 * If this package is used in a product, Eric Young should be given attribution
 
19
 * as the author of the parts of the library used.
 
20
 * This can be in the form of a textual message at program startup or
 
21
 * in documentation (online or textual) provided with the package.
 
22
 * 
 
23
 * Redistribution and use in source and binary forms, with or without
 
24
 * modification, are permitted provided that the following conditions
 
25
 * are met:
 
26
 * 1. Redistributions of source code must retain the copyright
 
27
 *    notice, this list of conditions and the following disclaimer.
 
28
 * 2. Redistributions in binary form must reproduce the above copyright
 
29
 *    notice, this list of conditions and the following disclaimer in the
 
30
 *    documentation and/or other materials provided with the distribution.
 
31
 * 3. All advertising materials mentioning features or use of this software
 
32
 *    must display the following acknowledgement:
 
33
 *    "This product includes cryptographic software written by
 
34
 *     Eric Young (eay@cryptsoft.com)"
 
35
 *    The word 'cryptographic' can be left out if the rouines from the library
 
36
 *    being used are not cryptographic related :-).
 
37
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 
38
 *    the apps directory (application code) you must include an acknowledgement:
 
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 
40
 * 
 
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
51
 * SUCH DAMAGE.
 
52
 * 
 
53
 * The licence and distribution terms for any publically available version or
 
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 
55
 * copied and put under another distribution licence
 
56
 * [including the GNU Public Licence.]
 
57
 */
 
58
 
 
59
#include <stdio.h>
 
60
#include <errno.h>
 
61
#include "cryptlib.h"
 
62
#include <openssl/buffer.h>
 
63
#include <openssl/evp.h>
 
64
 
 
65
static int ber_write(BIO *h,char *buf,int num);
 
66
static int ber_read(BIO *h,char *buf,int size);
 
67
/*static int ber_puts(BIO *h,char *str); */
 
68
/*static int ber_gets(BIO *h,char *str,int size); */
 
69
static long ber_ctrl(BIO *h,int cmd,long arg1,char *arg2);
 
70
static int ber_new(BIO *h);
 
71
static int ber_free(BIO *data);
 
72
static long ber_callback_ctrl(BIO *h,int cmd,void *(*fp)());
 
73
#define BER_BUF_SIZE    (32)
 
74
 
 
75
/* This is used to hold the state of the BER objects being read. */
 
76
typedef struct ber_struct
 
77
        {
 
78
        int tag;
 
79
        int class;
 
80
        long length;
 
81
        int inf;
 
82
        int num_left;
 
83
        int depth;
 
84
        } BER_CTX;
 
85
 
 
86
typedef struct bio_ber_struct
 
87
        {
 
88
        int tag;
 
89
        int class;
 
90
        long length;
 
91
        int inf;
 
92
 
 
93
        /* most of the following are used when doing non-blocking IO */
 
94
        /* reading */
 
95
        long num_left;  /* number of bytes still to read/write in block */
 
96
        int depth;      /* used with indefinite encoding. */
 
97
        int finished;   /* No more read data */
 
98
 
 
99
        /* writting */ 
 
100
        char *w_addr;
 
101
        int w_offset;
 
102
        int w_left;
 
103
 
 
104
        int buf_len;
 
105
        int buf_off;
 
106
        unsigned char buf[BER_BUF_SIZE];
 
107
        } BIO_BER_CTX;
 
108
 
 
109
static BIO_METHOD methods_ber=
 
110
        {
 
111
        BIO_TYPE_CIPHER,"cipher",
 
112
        ber_write,
 
113
        ber_read,
 
114
        NULL, /* ber_puts, */
 
115
        NULL, /* ber_gets, */
 
116
        ber_ctrl,
 
117
        ber_new,
 
118
        ber_free,
 
119
        ber_callback_ctrl,
 
120
        };
 
121
 
 
122
BIO_METHOD *BIO_f_ber(void)
 
123
        {
 
124
        return(&methods_ber);
 
125
        }
 
126
 
 
127
static int ber_new(BIO *bi)
 
128
        {
 
129
        BIO_BER_CTX *ctx;
 
130
 
 
131
        ctx=(BIO_BER_CTX *)OPENSSL_malloc(sizeof(BIO_BER_CTX));
 
132
        if (ctx == NULL) return(0);
 
133
 
 
134
        memset((char *)ctx,0,sizeof(BIO_BER_CTX));
 
135
 
 
136
        bi->init=0;
 
137
        bi->ptr=(char *)ctx;
 
138
        bi->flags=0;
 
139
        return(1);
 
140
        }
 
141
 
 
142
static int ber_free(BIO *a)
 
143
        {
 
144
        BIO_BER_CTX *b;
 
145
 
 
146
        if (a == NULL) return(0);
 
147
        b=(BIO_BER_CTX *)a->ptr;
 
148
        OPENSSL_cleanse(a->ptr,sizeof(BIO_BER_CTX));
 
149
        OPENSSL_free(a->ptr);
 
150
        a->ptr=NULL;
 
151
        a->init=0;
 
152
        a->flags=0;
 
153
        return(1);
 
154
        }
 
155
 
 
156
int bio_ber_get_header(BIO *bio, BIO_BER_CTX *ctx)
 
157
        {
 
158
        char buf[64];
 
159
        int i,j,n;
 
160
        int ret;
 
161
        unsigned char *p;
 
162
        unsigned long length
 
163
        int tag;
 
164
        int class;
 
165
        long max;
 
166
 
 
167
        BIO_clear_retry_flags(b);
 
168
 
 
169
        /* Pack the buffer down if there is a hole at the front */
 
170
        if (ctx->buf_off != 0)
 
171
                {
 
172
                p=ctx->buf;
 
173
                j=ctx->buf_off;
 
174
                n=ctx->buf_len-j;
 
175
                for (i=0; i<n; i++)
 
176
                        {
 
177
                        p[0]=p[j];
 
178
                        p++;
 
179
                        }
 
180
                ctx->buf_len-j;
 
181
                ctx->buf_off=0;
 
182
                }
 
183
 
 
184
        /* If there is more room, read some more data */
 
185
        i=BER_BUF_SIZE-ctx->buf_len;
 
186
        if (i)
 
187
                {
 
188
                i=BIO_read(bio->next_bio,&(ctx->buf[ctx->buf_len]),i);
 
189
                if (i <= 0)
 
190
                        {
 
191
                        BIO_copy_next_retry(b);
 
192
                        return(i);
 
193
                        }
 
194
                else
 
195
                        ctx->buf_len+=i;
 
196
                }
 
197
 
 
198
        max=ctx->buf_len;
 
199
        p=ctx->buf;
 
200
        ret=ASN1_get_object(&p,&length,&tag,&class,max);
 
201
 
 
202
        if (ret & 0x80)
 
203
                {
 
204
                if ((ctx->buf_len < BER_BUF_SIZE) &&
 
205
                        (ERR_GET_REASON(ERR_peek_error()) == ASN1_R_TOO_LONG))
 
206
                        {
 
207
                        ERR_get_error(); /* clear the error */
 
208
                        BIO_set_retry_read(b);
 
209
                        }
 
210
                return(-1);
 
211
                }
 
212
 
 
213
        /* We have no error, we have a header, so make use of it */
 
214
 
 
215
        if ((ctx->tag  >= 0) && (ctx->tag != tag))
 
216
                {
 
217
                BIOerr(BIO_F_BIO_BER_GET_HEADER,BIO_R_TAG_MISMATCH);
 
218
                sprintf(buf,"tag=%d, got %d",ctx->tag,tag);
 
219
                ERR_add_error_data(1,buf);
 
220
                return(-1);
 
221
                }
 
222
        if (ret & 0x01)
 
223
        if (ret & V_ASN1_CONSTRUCTED)
 
224
        }
 
225
        
 
226
static int ber_read(BIO *b, char *out, int outl)
 
227
        {
 
228
        int ret=0,i,n;
 
229
        BIO_BER_CTX *ctx;
 
230
 
 
231
        BIO_clear_retry_flags(b);
 
232
 
 
233
        if (out == NULL) return(0);
 
234
        ctx=(BIO_BER_CTX *)b->ptr;
 
235
 
 
236
        if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
 
237
 
 
238
        if (ctx->finished) return(0);
 
239
 
 
240
again:
 
241
        /* First see if we are half way through reading a block */
 
242
        if (ctx->num_left > 0)
 
243
                {
 
244
                if (ctx->num_left < outl)
 
245
                        n=ctx->num_left;
 
246
                else
 
247
                        n=outl;
 
248
                i=BIO_read(b->next_bio,out,n);
 
249
                if (i <= 0)
 
250
                        {
 
251
                        BIO_copy_next_retry(b);
 
252
                        return(i);
 
253
                        }
 
254
                ctx->num_left-=i;
 
255
                outl-=i;
 
256
                ret+=i;
 
257
                if (ctx->num_left <= 0)
 
258
                        {
 
259
                        ctx->depth--;
 
260
                        if (ctx->depth <= 0)
 
261
                                ctx->finished=1;
 
262
                        }
 
263
                if (outl <= 0)
 
264
                        return(ret);
 
265
                else
 
266
                        goto again;
 
267
                }
 
268
        else    /* we need to read another BER header */
 
269
                {
 
270
                }
 
271
        }
 
272
 
 
273
static int ber_write(BIO *b, char *in, int inl)
 
274
        {
 
275
        int ret=0,n,i;
 
276
        BIO_ENC_CTX *ctx;
 
277
 
 
278
        ctx=(BIO_ENC_CTX *)b->ptr;
 
279
        ret=inl;
 
280
 
 
281
        BIO_clear_retry_flags(b);
 
282
        n=ctx->buf_len-ctx->buf_off;
 
283
        while (n > 0)
 
284
                {
 
285
                i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
 
286
                if (i <= 0)
 
287
                        {
 
288
                        BIO_copy_next_retry(b);
 
289
                        return(i);
 
290
                        }
 
291
                ctx->buf_off+=i;
 
292
                n-=i;
 
293
                }
 
294
        /* at this point all pending data has been written */
 
295
 
 
296
        if ((in == NULL) || (inl <= 0)) return(0);
 
297
 
 
298
        ctx->buf_off=0;
 
299
        while (inl > 0)
 
300
                {
 
301
                n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl;
 
302
                EVP_CipherUpdate(&(ctx->cipher),
 
303
                        (unsigned char *)ctx->buf,&ctx->buf_len,
 
304
                        (unsigned char *)in,n);
 
305
                inl-=n;
 
306
                in+=n;
 
307
 
 
308
                ctx->buf_off=0;
 
309
                n=ctx->buf_len;
 
310
                while (n > 0)
 
311
                        {
 
312
                        i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
 
313
                        if (i <= 0)
 
314
                                {
 
315
                                BIO_copy_next_retry(b);
 
316
                                return(i);
 
317
                                }
 
318
                        n-=i;
 
319
                        ctx->buf_off+=i;
 
320
                        }
 
321
                ctx->buf_len=0;
 
322
                ctx->buf_off=0;
 
323
                }
 
324
        BIO_copy_next_retry(b);
 
325
        return(ret);
 
326
        }
 
327
 
 
328
static long ber_ctrl(BIO *b, int cmd, long num, char *ptr)
 
329
        {
 
330
        BIO *dbio;
 
331
        BIO_ENC_CTX *ctx,*dctx;
 
332
        long ret=1;
 
333
        int i;
 
334
 
 
335
        ctx=(BIO_ENC_CTX *)b->ptr;
 
336
 
 
337
        switch (cmd)
 
338
                {
 
339
        case BIO_CTRL_RESET:
 
340
                ctx->ok=1;
 
341
                ctx->finished=0;
 
342
                EVP_CipherInit_ex(&(ctx->cipher),NULL,NULL,NULL,NULL,
 
343
                        ctx->cipher.berrypt);
 
344
                ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
345
                break;
 
346
        case BIO_CTRL_EOF:      /* More to read */
 
347
                if (ctx->cont <= 0)
 
348
                        ret=1;
 
349
                else
 
350
                        ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
351
                break;
 
352
        case BIO_CTRL_WPENDING:
 
353
                ret=ctx->buf_len-ctx->buf_off;
 
354
                if (ret <= 0)
 
355
                        ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
356
                break;
 
357
        case BIO_CTRL_PENDING: /* More to read in buffer */
 
358
                ret=ctx->buf_len-ctx->buf_off;
 
359
                if (ret <= 0)
 
360
                        ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
361
                break;
 
362
        case BIO_CTRL_FLUSH:
 
363
                /* do a final write */
 
364
again:
 
365
                while (ctx->buf_len != ctx->buf_off)
 
366
                        {
 
367
                        i=ber_write(b,NULL,0);
 
368
                        if (i < 0)
 
369
                                {
 
370
                                ret=i;
 
371
                                break;
 
372
                                }
 
373
                        }
 
374
 
 
375
                if (!ctx->finished)
 
376
                        {
 
377
                        ctx->finished=1;
 
378
                        ctx->buf_off=0;
 
379
                        ret=EVP_CipherFinal_ex(&(ctx->cipher),
 
380
                                (unsigned char *)ctx->buf,
 
381
                                &(ctx->buf_len));
 
382
                        ctx->ok=(int)ret;
 
383
                        if (ret <= 0) break;
 
384
 
 
385
                        /* push out the bytes */
 
386
                        goto again;
 
387
                        }
 
388
                
 
389
                /* Finally flush the underlying BIO */
 
390
                ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
391
                break;
 
392
        case BIO_C_GET_CIPHER_STATUS:
 
393
                ret=(long)ctx->ok;
 
394
                break;
 
395
        case BIO_C_DO_STATE_MACHINE:
 
396
                BIO_clear_retry_flags(b);
 
397
                ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
398
                BIO_copy_next_retry(b);
 
399
                break;
 
400
 
 
401
        case BIO_CTRL_DUP:
 
402
                dbio=(BIO *)ptr;
 
403
                dctx=(BIO_ENC_CTX *)dbio->ptr;
 
404
                memcpy(&(dctx->cipher),&(ctx->cipher),sizeof(ctx->cipher));
 
405
                dbio->init=1;
 
406
                break;
 
407
        default:
 
408
                ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
 
409
                break;
 
410
                }
 
411
        return(ret);
 
412
        }
 
413
 
 
414
static long ber_callback_ctrl(BIO *b, int cmd, void *(*fp)())
 
415
        {
 
416
        long ret=1;
 
417
 
 
418
        if (b->next_bio == NULL) return(0);
 
419
        switch (cmd)
 
420
                {
 
421
        default:
 
422
                ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
 
423
                break;
 
424
                }
 
425
        return(ret);
 
426
        }
 
427
 
 
428
/*
 
429
void BIO_set_cipher_ctx(b,c)
 
430
BIO *b;
 
431
EVP_CIPHER_ctx *c;
 
432
        {
 
433
        if (b == NULL) return;
 
434
 
 
435
        if ((b->callback != NULL) &&
 
436
                (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
 
437
                return;
 
438
 
 
439
        b->init=1;
 
440
        ctx=(BIO_ENC_CTX *)b->ptr;
 
441
        memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
 
442
        
 
443
        if (b->callback != NULL)
 
444
                b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
 
445
        }
 
446
*/
 
447
 
 
448
void BIO_set_cipher(BIO *b, EVP_CIPHER *c, unsigned char *k, unsigned char *i,
 
449
             int e)
 
450
        {
 
451
        BIO_ENC_CTX *ctx;
 
452
 
 
453
        if (b == NULL) return;
 
454
 
 
455
        if ((b->callback != NULL) &&
 
456
                (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
 
457
                return;
 
458
 
 
459
        b->init=1;
 
460
        ctx=(BIO_ENC_CTX *)b->ptr;
 
461
        EVP_CipherInit_ex(&(ctx->cipher),c,NULL,k,i,e);
 
462
        
 
463
        if (b->callback != NULL)
 
464
                b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
 
465
        }
 
466