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