Add OpenSSL 0.9.7e.
[dragonfly.git] / crypto / openssl-0.9.7e / crypto / pkcs7 / bio_ber.c
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