OpenSSL
1.0.1c
Main Page
Classes
Files
File List
File Members
All
Classes
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
crypto
evp
bio_ok.c
Go to the documentation of this file.
1
/* crypto/evp/bio_ok.c */
2
/* Copyright (C) 1995-1998 Eric Young (
[email protected]
)
3
* All rights reserved.
4
*
5
* This package is an SSL implementation written
6
* by Eric Young (
[email protected]
).
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 (
[email protected]
).
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 (
[email protected]
)"
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 (
[email protected]
)"
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
/*
60
From: Arne Ansper <
[email protected]
>
61
62
Why BIO_f_reliable?
63
64
I wrote function which took BIO* as argument, read data from it
65
and processed it. Then I wanted to store the input file in
66
encrypted form. OK I pushed BIO_f_cipher to the BIO stack
67
and everything was OK. BUT if user types wrong password
68
BIO_f_cipher outputs only garbage and my function crashes. Yes
69
I can and I should fix my function, but BIO_f_cipher is
70
easy way to add encryption support to many existing applications
71
and it's hard to debug and fix them all.
72
73
So I wanted another BIO which would catch the incorrect passwords and
74
file damages which cause garbage on BIO_f_cipher's output.
75
76
The easy way is to push the BIO_f_md and save the checksum at
77
the end of the file. However there are several problems with this
78
approach:
79
80
1) you must somehow separate checksum from actual data.
81
2) you need lot's of memory when reading the file, because you
82
must read to the end of the file and verify the checksum before
83
letting the application to read the data.
84
85
BIO_f_reliable tries to solve both problems, so that you can
86
read and write arbitrary long streams using only fixed amount
87
of memory.
88
89
BIO_f_reliable splits data stream into blocks. Each block is prefixed
90
with it's length and suffixed with it's digest. So you need only
91
several Kbytes of memory to buffer single block before verifying
92
it's digest.
93
94
BIO_f_reliable goes further and adds several important capabilities:
95
96
1) the digest of the block is computed over the whole stream
97
-- so nobody can rearrange the blocks or remove or replace them.
98
99
2) to detect invalid passwords right at the start BIO_f_reliable
100
adds special prefix to the stream. In order to avoid known plain-text
101
attacks this prefix is generated as follows:
102
103
*) digest is initialized with random seed instead of
104
standardized one.
105
*) same seed is written to output
106
*) well-known text is then hashed and the output
107
of the digest is also written to output.
108
109
reader can now read the seed from stream, hash the same string
110
and then compare the digest output.
111
112
Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
113
initially wrote and tested this code on x86 machine and wrote the
114
digests out in machine-dependent order :( There are people using
115
this code and I cannot change this easily without making existing
116
data files unreadable.
117
118
*/
119
120
#include <stdio.h>
121
#include <errno.h>
122
#include <assert.h>
123
#include "
cryptlib.h
"
124
#include <
openssl/buffer.h
>
125
#include <
openssl/bio.h
>
126
#include <
openssl/evp.h
>
127
#include <
openssl/rand.h
>
128
129
static
int
ok_write(
BIO
*
h
,
const
char
*buf,
int
num
);
130
static
int
ok_read(
BIO
*
h
,
char
*buf,
int
size);
131
static
long
ok_ctrl(
BIO
*
h
,
int
cmd,
long
arg1,
void
*arg2);
132
static
int
ok_new(
BIO
*
h
);
133
static
int
ok_free(
BIO
*
data
);
134
static
long
ok_callback_ctrl(
BIO
*
h
,
int
cmd,
bio_info_cb
*
fp
);
135
136
static
int
sig_out(
BIO
*
b
);
137
static
int
sig_in(
BIO
*
b
);
138
static
int
block_out(
BIO
*
b
);
139
static
int
block_in(
BIO
*
b
);
140
#define OK_BLOCK_SIZE (1024*4)
141
#define OK_BLOCK_BLOCK 4
142
#define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
143
#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
144
145
typedef
struct
ok_struct
146
{
147
size_t
buf_len
;
148
size_t
buf_off
;
149
size_t
buf_len_save
;
150
size_t
buf_off_save
;
151
int
cont
;
/* <= 0 when finished */
152
int
finished
;
153
EVP_MD_CTX
md
;
154
int
blockout
;
/* output block is ready */
155
int
sigio
;
/* must process signature */
156
unsigned
char
buf
[
IOBS
];
157
}
BIO_OK_CTX
;
158
159
static
BIO_METHOD
methods_ok=
160
{
161
BIO_TYPE_CIPHER
,
"reliable"
,
162
ok_write,
163
ok_read,
164
NULL,
/* ok_puts, */
165
NULL,
/* ok_gets, */
166
ok_ctrl,
167
ok_new,
168
ok_free,
169
ok_callback_ctrl,
170
};
171
172
BIO_METHOD
*
BIO_f_reliable
(
void
)
173
{
174
return
(&methods_ok);
175
}
176
177
static
int
ok_new(
BIO
*bi)
178
{
179
BIO_OK_CTX
*ctx;
180
181
ctx=(
BIO_OK_CTX
*)
OPENSSL_malloc
(
sizeof
(
BIO_OK_CTX
));
182
if
(ctx == NULL)
return
(0);
183
184
ctx->
buf_len
=0;
185
ctx->
buf_off
=0;
186
ctx->
buf_len_save
=0;
187
ctx->
buf_off_save
=0;
188
ctx->
cont
=1;
189
ctx->
finished
=0;
190
ctx->
blockout
= 0;
191
ctx->
sigio
=1;
192
193
EVP_MD_CTX_init
(&ctx->
md
);
194
195
bi->
init
=0;
196
bi->
ptr
=(
char
*)ctx;
197
bi->
flags
=0;
198
return
(1);
199
}
200
201
static
int
ok_free(
BIO
*
a
)
202
{
203
if
(a == NULL)
return
(0);
204
EVP_MD_CTX_cleanup
(&((
BIO_OK_CTX
*)a->
ptr
)->md);
205
OPENSSL_cleanse
(a->
ptr
,
sizeof
(
BIO_OK_CTX
));
206
OPENSSL_free
(a->
ptr
);
207
a->
ptr
=NULL;
208
a->
init
=0;
209
a->
flags
=0;
210
return
(1);
211
}
212
213
static
int
ok_read(
BIO
*
b
,
char
*out,
int
outl)
214
{
215
int
ret=0,i,n;
216
BIO_OK_CTX
*ctx;
217
218
if
(out == NULL)
return
(0);
219
ctx=(
BIO_OK_CTX
*)b->
ptr
;
220
221
if
((ctx == NULL) || (b->
next_bio
== NULL) || (b->
init
== 0))
return
(0);
222
223
while
(outl > 0)
224
{
225
226
/* copy clean bytes to output buffer */
227
if
(ctx->
blockout
)
228
{
229
i=ctx->
buf_len
-ctx->
buf_off
;
230
if
(i > outl) i=outl;
231
memcpy(out,&(ctx->
buf
[ctx->
buf_off
]),i);
232
ret+=i;
233
out+=i;
234
outl-=i;
235
ctx->
buf_off
+=i;
236
237
/* all clean bytes are out */
238
if
(ctx->
buf_len
== ctx->
buf_off
)
239
{
240
ctx->
buf_off
=0;
241
242
/* copy start of the next block into proper place */
243
if
(ctx->
buf_len_save
- ctx->
buf_off_save
> 0)
244
{
245
ctx->
buf_len
= ctx->
buf_len_save
- ctx->
buf_off_save
;
246
memmove(ctx->
buf
, &(ctx->
buf
[ctx->
buf_off_save
]),
247
ctx->
buf_len
);
248
}
249
else
250
{
251
ctx->
buf_len
=0;
252
}
253
ctx->
blockout
= 0;
254
}
255
}
256
257
/* output buffer full -- cancel */
258
if
(outl == 0)
break
;
259
260
/* no clean bytes in buffer -- fill it */
261
n=
IOBS
- ctx->
buf_len
;
262
i=
BIO_read
(b->
next_bio
,&(ctx->
buf
[ctx->
buf_len
]),n);
263
264
if
(i <= 0)
break
;
/* nothing new */
265
266
ctx->
buf_len
+= i;
267
268
/* no signature yet -- check if we got one */
269
if
(ctx->
sigio
== 1)
270
{
271
if
(!sig_in(b))
272
{
273
BIO_clear_retry_flags
(b);
274
return
0;
275
}
276
}
277
278
/* signature ok -- check if we got block */
279
if
(ctx->
sigio
== 0)
280
{
281
if
(!block_in(b))
282
{
283
BIO_clear_retry_flags
(b);
284
return
0;
285
}
286
}
287
288
/* invalid block -- cancel */
289
if
(ctx->
cont
<= 0)
break
;
290
291
}
292
293
BIO_clear_retry_flags
(b);
294
BIO_copy_next_retry
(b);
295
return
(ret);
296
}
297
298
static
int
ok_write(
BIO
*b,
const
char
*in,
int
inl)
299
{
300
int
ret=0,n,i;
301
BIO_OK_CTX
*ctx;
302
303
if
(inl <= 0)
return
inl;
304
305
ctx=(
BIO_OK_CTX
*)b->
ptr
;
306
ret=inl;
307
308
if
((ctx == NULL) || (b->
next_bio
== NULL) || (b->
init
== 0))
return
(0);
309
310
if
(ctx->
sigio
&& !sig_out(b))
311
return
0;
312
313
do
{
314
BIO_clear_retry_flags
(b);
315
n=ctx->
buf_len
-ctx->
buf_off
;
316
while
(ctx->
blockout
&& n > 0)
317
{
318
i=
BIO_write
(b->
next_bio
,&(ctx->
buf
[ctx->
buf_off
]),n);
319
if
(i <= 0)
320
{
321
BIO_copy_next_retry
(b);
322
if
(!
BIO_should_retry
(b))
323
ctx->
cont
= 0;
324
return
(i);
325
}
326
ctx->
buf_off
+=i;
327
n-=i;
328
}
329
330
/* at this point all pending data has been written */
331
ctx->
blockout
= 0;
332
if
(ctx->
buf_len
== ctx->
buf_off
)
333
{
334
ctx->
buf_len
=
OK_BLOCK_BLOCK
;
335
ctx->
buf_off
=0;
336
}
337
338
if
((in == NULL) || (inl <= 0))
return
(0);
339
340
n= (inl+ ctx->
buf_len
>
OK_BLOCK_SIZE
+
OK_BLOCK_BLOCK
) ?
341
(
int
)(
OK_BLOCK_SIZE
+
OK_BLOCK_BLOCK
-ctx->
buf_len
) : inl;
342
343
memcpy((
unsigned
char
*)(&(ctx->
buf
[ctx->
buf_len
])),(
unsigned
char
*)in,n);
344
ctx->
buf_len
+= n;
345
inl-=n;
346
in+=n;
347
348
if
(ctx->
buf_len
>=
OK_BLOCK_SIZE
+
OK_BLOCK_BLOCK
)
349
{
350
if
(!block_out(b))
351
{
352
BIO_clear_retry_flags
(b);
353
return
0;
354
}
355
}
356
}
while
(inl > 0);
357
358
BIO_clear_retry_flags
(b);
359
BIO_copy_next_retry
(b);
360
return
(ret);
361
}
362
363
static
long
ok_ctrl(
BIO
*b,
int
cmd,
long
num
,
void
*
ptr
)
364
{
365
BIO_OK_CTX
*ctx;
366
EVP_MD
*md;
367
const
EVP_MD
**ppmd;
368
long
ret=1;
369
int
i;
370
371
ctx=b->
ptr
;
372
373
switch
(cmd)
374
{
375
case
BIO_CTRL_RESET
:
376
ctx->
buf_len
=0;
377
ctx->
buf_off
=0;
378
ctx->
buf_len_save
=0;
379
ctx->
buf_off_save
=0;
380
ctx->
cont
=1;
381
ctx->
finished
=0;
382
ctx->
blockout
= 0;
383
ctx->
sigio
=1;
384
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
385
break
;
386
case
BIO_CTRL_EOF
:
/* More to read */
387
if
(ctx->
cont
<= 0)
388
ret=1;
389
else
390
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
391
break
;
392
case
BIO_CTRL_PENDING
:
/* More to read in buffer */
393
case
BIO_CTRL_WPENDING
:
/* More to read in buffer */
394
ret=ctx->
blockout
? ctx->
buf_len
-ctx->
buf_off
: 0;
395
if
(ret <= 0)
396
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
397
break
;
398
case
BIO_CTRL_FLUSH
:
399
/* do a final write */
400
if
(ctx->
blockout
== 0)
401
if
(!block_out(b))
402
return
0;
403
404
while
(ctx->
blockout
)
405
{
406
i=ok_write(b,NULL,0);
407
if
(i < 0)
408
{
409
ret=i;
410
break
;
411
}
412
}
413
414
ctx->
finished
=1;
415
ctx->
buf_off
=ctx->
buf_len
=0;
416
ctx->
cont
=(int)ret;
417
418
/* Finally flush the underlying BIO */
419
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
420
break
;
421
case
BIO_C_DO_STATE_MACHINE
:
422
BIO_clear_retry_flags
(b);
423
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
424
BIO_copy_next_retry
(b);
425
break
;
426
case
BIO_CTRL_INFO
:
427
ret=(long)ctx->
cont
;
428
break
;
429
case
BIO_C_SET_MD
:
430
md=ptr;
431
if
(!
EVP_DigestInit_ex
(&ctx->
md
, md, NULL))
432
return
0;
433
b->
init
=1;
434
break
;
435
case
BIO_C_GET_MD
:
436
if
(b->
init
)
437
{
438
ppmd=
ptr
;
439
*ppmd=ctx->
md
.
digest
;
440
}
441
else
442
ret=0;
443
break
;
444
default
:
445
ret=
BIO_ctrl
(b->
next_bio
,cmd,num,ptr);
446
break
;
447
}
448
return
(ret);
449
}
450
451
static
long
ok_callback_ctrl(
BIO
*b,
int
cmd,
bio_info_cb
*
fp
)
452
{
453
long
ret=1;
454
455
if
(b->
next_bio
== NULL)
return
(0);
456
switch
(cmd)
457
{
458
default
:
459
ret=
BIO_callback_ctrl
(b->
next_bio
,cmd,fp);
460
break
;
461
}
462
return
(ret);
463
}
464
465
static
void
longswap(
void
*_ptr,
size_t
len
)
466
{
const
union
{
long
one;
char
little; } is_endian = {1};
467
468
if
(is_endian.little) {
469
size_t
i;
470
unsigned
char
*
p
=_ptr,
c
;
471
472
for
(i= 0;i <
len
;i+= 4) {
473
c=p[0],p[0]=p[3],p[3]=c;
474
c=p[1],p[1]=p[2],p[2]=c;
475
}
476
}
477
}
478
479
static
int
sig_out(
BIO
* b)
480
{
481
BIO_OK_CTX
*ctx;
482
EVP_MD_CTX
*md;
483
484
ctx=b->
ptr
;
485
md=&ctx->
md
;
486
487
if
(ctx->
buf_len
+ 2* md->
digest
->
md_size
>
OK_BLOCK_SIZE
)
return
1;
488
489
if
(!
EVP_DigestInit_ex
(md, md->
digest
, NULL))
490
goto
berr;
491
/* FIXME: there's absolutely no guarantee this makes any sense at all,
492
* particularly now EVP_MD_CTX has been restructured.
493
*/
494
RAND_pseudo_bytes
(md->
md_data
, md->
digest
->
md_size
);
495
memcpy(&(ctx->
buf
[ctx->
buf_len
]), md->
md_data
, md->
digest
->
md_size
);
496
longswap(&(ctx->
buf
[ctx->
buf_len
]), md->
digest
->
md_size
);
497
ctx->
buf_len
+= md->
digest
->
md_size
;
498
499
if
(!
EVP_DigestUpdate
(md,
WELLKNOWN
, strlen(
WELLKNOWN
)))
500
goto
berr;
501
if
(!
EVP_DigestFinal_ex
(md, &(ctx->
buf
[ctx->
buf_len
]), NULL))
502
goto
berr;
503
ctx->
buf_len
+= md->
digest
->
md_size
;
504
ctx->
blockout
= 1;
505
ctx->
sigio
= 0;
506
return
1;
507
berr:
508
BIO_clear_retry_flags
(b);
509
return
0;
510
}
511
512
static
int
sig_in(
BIO
* b)
513
{
514
BIO_OK_CTX
*ctx;
515
EVP_MD_CTX
*md;
516
unsigned
char
tmp[
EVP_MAX_MD_SIZE
];
517
int
ret= 0;
518
519
ctx=b->
ptr
;
520
md=&ctx->
md
;
521
522
if
((
int
)(ctx->
buf_len
-ctx->
buf_off
) < 2*md->
digest
->
md_size
)
return
1;
523
524
if
(!
EVP_DigestInit_ex
(md, md->
digest
, NULL))
525
goto
berr;
526
memcpy(md->
md_data
, &(ctx->
buf
[ctx->
buf_off
]), md->
digest
->
md_size
);
527
longswap(md->
md_data
, md->
digest
->
md_size
);
528
ctx->
buf_off
+= md->
digest
->
md_size
;
529
530
if
(!
EVP_DigestUpdate
(md,
WELLKNOWN
, strlen(
WELLKNOWN
)))
531
goto
berr;
532
if
(!
EVP_DigestFinal_ex
(md, tmp, NULL))
533
goto
berr;
534
ret= memcmp(&(ctx->
buf
[ctx->
buf_off
]), tmp, md->
digest
->
md_size
) == 0;
535
ctx->
buf_off
+= md->
digest
->
md_size
;
536
if
(ret == 1)
537
{
538
ctx->
sigio
= 0;
539
if
(ctx->
buf_len
!= ctx->
buf_off
)
540
{
541
memmove(ctx->
buf
, &(ctx->
buf
[ctx->
buf_off
]), ctx->
buf_len
- ctx->
buf_off
);
542
}
543
ctx->
buf_len
-= ctx->
buf_off
;
544
ctx->
buf_off
= 0;
545
}
546
else
547
{
548
ctx->
cont
= 0;
549
}
550
return
1;
551
berr:
552
BIO_clear_retry_flags
(b);
553
return
0;
554
}
555
556
static
int
block_out(
BIO
* b)
557
{
558
BIO_OK_CTX
*ctx;
559
EVP_MD_CTX
*md;
560
unsigned
long
tl;
561
562
ctx=b->
ptr
;
563
md=&ctx->
md
;
564
565
tl= ctx->
buf_len
-
OK_BLOCK_BLOCK
;
566
ctx->
buf
[0]=(
unsigned
char)(tl>>24);
567
ctx->
buf
[1]=(
unsigned
char)(tl>>16);
568
ctx->
buf
[2]=(
unsigned
char)(tl>>8);
569
ctx->
buf
[3]=(
unsigned
char)(tl);
570
if
(!
EVP_DigestUpdate
(md,
571
(
unsigned
char
*) &(ctx->
buf
[
OK_BLOCK_BLOCK
]), tl))
572
goto
berr;
573
if
(!
EVP_DigestFinal_ex
(md, &(ctx->
buf
[ctx->
buf_len
]), NULL))
574
goto
berr;
575
ctx->
buf_len
+= md->
digest
->
md_size
;
576
ctx->
blockout
= 1;
577
return
1;
578
berr:
579
BIO_clear_retry_flags
(b);
580
return
0;
581
}
582
583
static
int
block_in(
BIO
* b)
584
{
585
BIO_OK_CTX
*ctx;
586
EVP_MD_CTX
*md;
587
unsigned
long
tl= 0;
588
unsigned
char
tmp[
EVP_MAX_MD_SIZE
];
589
590
ctx=b->
ptr
;
591
md=&ctx->
md
;
592
593
assert(
sizeof
(tl)>=
OK_BLOCK_BLOCK
);
/* always true */
594
tl =ctx->
buf
[0]; tl<<=8;
595
tl|=ctx->
buf
[1]; tl<<=8;
596
tl|=ctx->
buf
[2]; tl<<=8;
597
tl|=ctx->
buf
[3];
598
599
if
(ctx->
buf_len
< tl+
OK_BLOCK_BLOCK
+ md->
digest
->
md_size
)
return
1;
600
601
if
(!
EVP_DigestUpdate
(md,
602
(
unsigned
char
*) &(ctx->
buf
[
OK_BLOCK_BLOCK
]), tl))
603
goto
berr;
604
if
(!
EVP_DigestFinal_ex
(md, tmp, NULL))
605
goto
berr;
606
if
(memcmp(&(ctx->
buf
[tl+
OK_BLOCK_BLOCK
]), tmp, md->
digest
->
md_size
) == 0)
607
{
608
/* there might be parts from next block lurking around ! */
609
ctx->
buf_off_save
= tl+
OK_BLOCK_BLOCK
+ md->
digest
->
md_size
;
610
ctx->
buf_len_save
= ctx->
buf_len
;
611
ctx->
buf_off
=
OK_BLOCK_BLOCK
;
612
ctx->
buf_len
= tl+
OK_BLOCK_BLOCK
;
613
ctx->
blockout
= 1;
614
}
615
else
616
{
617
ctx->
cont
= 0;
618
}
619
return
1;
620
berr:
621
BIO_clear_retry_flags
(b);
622
return
0;
623
}
624
Generated on Thu Jan 10 2013 09:53:36 for OpenSSL by
1.8.2