Merge in my S/MIME library and utility.
[openssl.git] / 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 #define BER_BUF_SIZE    (32)
73
74 /* This is used to hold the state of the BER objects being read. */
75 typedef struct ber_struct
76         {
77         int tag;
78         int class;
79         long length;
80         int inf;
81         int num_left;
82         int depth;
83         } BER_CTX;
84
85 typedef struct bio_ber_struct
86         {
87         int tag;
88         int class;
89         long length;
90         int inf;
91
92         /* most of the following are used when doing non-blocking IO */
93         /* reading */
94         long num_left;  /* number of bytes still to read/write in block */
95         int depth;      /* used with idefinite encoding. */
96         int finished;   /* No more read data */
97
98         /* writting */ 
99         char *w_addr;
100         int w_offset;
101         int w_left;
102
103         int buf_len;
104         int buf_off;
105         unsigned char buf[BER_BUF_SIZE];
106         } BIO_BER_CTX;
107
108 static BIO_METHOD methods_ber=
109         {
110         BIO_TYPE_CIPHER,"cipher",
111         ber_write,
112         ber_read,
113         NULL, /* ber_puts, */
114         NULL, /* ber_gets, */
115         ber_ctrl,
116         ber_new,
117         ber_free,
118         };
119
120 BIO_METHOD *BIO_f_ber(void)
121         {
122         return(&methods_ber);
123         }
124
125 static int ber_new(BIO *bi)
126         {
127         BIO_BER_CTX *ctx;
128
129         ctx=(BIO_BER_CTX *)Malloc(sizeof(BIO_BER_CTX));
130         if (ctx == NULL) return(0);
131
132         memset((char *)ctx,0,sizeof(BIO_BER_CTX));
133
134         bi->init=0;
135         bi->ptr=(char *)ctx;
136         bi->flags=0;
137         return(1);
138         }
139
140 static int ber_free(BIO *a)
141         {
142         BIO_BER_CTX *b;
143
144         if (a == NULL) return(0);
145         b=(BIO_BER_CTX *)a->ptr;
146         memset(a->ptr,0,sizeof(BIO_BER_CTX));
147         Free(a->ptr);
148         a->ptr=NULL;
149         a->init=0;
150         a->flags=0;
151         return(1);
152         }
153
154 int bio_ber_get_header(BIO *bio, BIO_BER_CTX *ctx)
155         {
156         char buf[64];
157         int i,j,n;
158         int ret;
159         unsigned char *p;
160         unsigned long length
161         int tag;
162         int class;
163         long max;
164
165         BIO_clear_retry_flags(b);
166
167         /* Pack the buffer down if there is a hole at the front */
168         if (ctx->buf_off != 0)
169                 {
170                 p=ctx->buf;
171                 j=ctx->buf_off;
172                 n=ctx->buf_len-j;
173                 for (i=0; i<n; i++)
174                         {
175                         p[0]=p[j];
176                         p++;
177                         }
178                 ctx->buf_len-j;
179                 ctx->buf_off=0;
180                 }
181
182         /* If there is more room, read some more data */
183         i=BER_BUF_SIZE-ctx->buf_len;
184         if (i)
185                 {
186                 i=BIO_read(bio->next_bio,&(ctx->buf[ctx->buf_len]),i);
187                 if (i <= 0)
188                         {
189                         BIO_copy_next_retry(b);
190                         return(i);
191                         }
192                 else
193                         ctx->buf_len+=i;
194                 }
195
196         max=ctx->buf_len;
197         p=ctx->buf;
198         ret=ASN1_get_object(&p,&length,&tag,&class,max);
199
200         if (ret & 0x80)
201                 {
202                 if ((ctx->buf_len < BER_BUF_SIZE) &&
203                         (ERR_GET_REASON(ERR_peek_error()) == ASN1_R_TOO_LONG))
204                         {
205                         ERR_get_error(); /* clear the error */
206                         BIO_set_retry_read(b);
207                         }
208                 return(-1);
209                 }
210
211         /* We have no error, we have a header, so make use of it */
212
213         if ((ctx->tag  >= 0) && (ctx->tag != tag))
214                 {
215                 BIOerr(BIO_F_BIO_BER_GET_HEADER,BIO_R_TAG_MISMATCH);
216                 sprintf(buf,"tag=%d, got %d",ctx->tag,tag);
217                 ERR_add_error_data(1,buf);
218                 return(-1);
219                 }
220         if (ret & 0x01)
221         if (ret & V_ASN1_CONSTRUCTED)
222         }
223         
224 static int ber_read(BIO *b, char *out, int outl)
225         {
226         int ret=0,i,n;
227         BIO_BER_CTX *ctx;
228
229         BIO_clear_retry_flags(b);
230
231         if (out == NULL) return(0);
232         ctx=(BIO_BER_CTX *)b->ptr;
233
234         if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
235
236         if (ctx->finished) return(0);
237
238 again:
239         /* First see if we are half way through reading a block */
240         if (ctx->num_left > 0)
241                 {
242                 if (ctx->num_left < outl)
243                         n=ctx->num_left;
244                 else
245                         n=outl;
246                 i=BIO_read(b->next_bio,out,n);
247                 if (i <= 0)
248                         {
249                         BIO_copy_next_retry(b);
250                         return(i);
251                         }
252                 ctx->num_left-=i;
253                 outl-=i;
254                 ret+=i;
255                 if (ctx->num_left <= 0)
256                         {
257                         ctx->depth--;
258                         if (ctx->depth <= 0)
259                                 ctx->finished=1;
260                         }
261                 if (outl <= 0)
262                         return(ret);
263                 else
264                         goto again;
265                 }
266         else    /* we need to read another BER header */
267                 {
268                 }
269         }
270
271 static int ber_write(BIO *b, char *in, int inl)
272         {
273         int ret=0,n,i;
274         BIO_ENC_CTX *ctx;
275
276         ctx=(BIO_ENC_CTX *)b->ptr;
277         ret=inl;
278
279         BIO_clear_retry_flags(b);
280         n=ctx->buf_len-ctx->buf_off;
281         while (n > 0)
282                 {
283                 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
284                 if (i <= 0)
285                         {
286                         BIO_copy_next_retry(b);
287                         return(i);
288                         }
289                 ctx->buf_off+=i;
290                 n-=i;
291                 }
292         /* at this point all pending data has been written */
293
294         if ((in == NULL) || (inl <= 0)) return(0);
295
296         ctx->buf_off=0;
297         while (inl > 0)
298                 {
299                 n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl;
300                 EVP_CipherUpdate(&(ctx->cipher),
301                         (unsigned char *)ctx->buf,&ctx->buf_len,
302                         (unsigned char *)in,n);
303                 inl-=n;
304                 in+=n;
305
306                 ctx->buf_off=0;
307                 n=ctx->buf_len;
308                 while (n > 0)
309                         {
310                         i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
311                         if (i <= 0)
312                                 {
313                                 BIO_copy_next_retry(b);
314                                 return(i);
315                                 }
316                         n-=i;
317                         ctx->buf_off+=i;
318                         }
319                 ctx->buf_len=0;
320                 ctx->buf_off=0;
321                 }
322         BIO_copy_next_retry(b);
323         return(ret);
324         }
325
326 static long ber_ctrl(BIO *b, int cmd, long num, char *ptr)
327         {
328         BIO *dbio;
329         BIO_ENC_CTX *ctx,*dctx;
330         long ret=1;
331         int i;
332
333         ctx=(BIO_ENC_CTX *)b->ptr;
334
335         switch (cmd)
336                 {
337         case BIO_CTRL_RESET:
338                 ctx->ok=1;
339                 ctx->finished=0;
340                 EVP_CipherInit(&(ctx->cipher),NULL,NULL,NULL,
341                         ctx->cipher.berrypt);
342                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
343                 break;
344         case BIO_CTRL_EOF:      /* More to read */
345                 if (ctx->cont <= 0)
346                         ret=1;
347                 else
348                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
349                 break;
350         case BIO_CTRL_WPENDING:
351                 ret=ctx->buf_len-ctx->buf_off;
352                 if (ret <= 0)
353                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
354                 break;
355         case BIO_CTRL_PENDING: /* More to read in buffer */
356                 ret=ctx->buf_len-ctx->buf_off;
357                 if (ret <= 0)
358                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
359                 break;
360         case BIO_CTRL_FLUSH:
361                 /* do a final write */
362 again:
363                 while (ctx->buf_len != ctx->buf_off)
364                         {
365                         i=ber_write(b,NULL,0);
366                         if (i < 0)
367                                 {
368                                 ret=i;
369                                 break;
370                                 }
371                         }
372
373                 if (!ctx->finished)
374                         {
375                         ctx->finished=1;
376                         ctx->buf_off=0;
377                         ret=EVP_CipherFinal(&(ctx->cipher),
378                                 (unsigned char *)ctx->buf,
379                                 &(ctx->buf_len));
380                         ctx->ok=(int)ret;
381                         if (ret <= 0) break;
382
383                         /* push out the bytes */
384                         goto again;
385                         }
386                 
387                 /* Finally flush the underlying BIO */
388                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
389                 break;
390         case BIO_C_GET_CIPHER_STATUS:
391                 ret=(long)ctx->ok;
392                 break;
393         case BIO_C_DO_STATE_MACHINE:
394                 BIO_clear_retry_flags(b);
395                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
396                 BIO_copy_next_retry(b);
397                 break;
398
399         case BIO_CTRL_DUP:
400                 dbio=(BIO *)ptr;
401                 dctx=(BIO_ENC_CTX *)dbio->ptr;
402                 memcpy(&(dctx->cipher),&(ctx->cipher),sizeof(ctx->cipher));
403                 dbio->init=1;
404                 break;
405         default:
406                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
407                 break;
408                 }
409         return(ret);
410         }
411
412 /*
413 void BIO_set_cipher_ctx(b,c)
414 BIO *b;
415 EVP_CIPHER_ctx *c;
416         {
417         if (b == NULL) return;
418
419         if ((b->callback != NULL) &&
420                 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
421                 return;
422
423         b->init=1;
424         ctx=(BIO_ENC_CTX *)b->ptr;
425         memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
426         
427         if (b->callback != NULL)
428                 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
429         }
430 */
431
432 void BIO_set_cipher(BIO *b, EVP_CIPHER *c, unsigned char *k, unsigned char *i,
433              int e)
434         {
435         BIO_ENC_CTX *ctx;
436
437         if (b == NULL) return;
438
439         if ((b->callback != NULL) &&
440                 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
441                 return;
442
443         b->init=1;
444         ctx=(BIO_ENC_CTX *)b->ptr;
445         EVP_CipherInit(&(ctx->cipher),c,k,i,e);
446         
447         if (b->callback != NULL)
448                 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
449         }
450