BUG REPORT: base64 encoding does not work correctly for
BIO_FLAGS_BASE64_NO_NL bios



please see comments starting on the line // BUGGY SEGMENT BEGINS and
how I PROPOSE to fix it. If someone could take a look at it and see whether
that's fine I'd appreciate it. 

basically the cause of this problem is that we the function messes up its
input parameters
and also writes incorrect data to the output stream by copying what's left
in the temporary
buffer of the bio

PLEASE NOTE: I did not prepare a build with these changes but I did test the
solution by
             setting n to a correct value and zeroing ctx->tmp_len=0; in the
debugger - you'll
             know what I mean when you see the code and comments below

Thanks!







======   The Culprit ============

static int b64_write(BIO *b, char *in, int inl)
        {
        int ret=inl,n,i;
        BIO_B64_CTX *ctx;

        ctx=(BIO_B64_CTX *)b->ptr;
        BIO_clear_retry_flags(b);

        if (ctx->encode != B64_ENCODE)
                {
                ctx->encode=B64_ENCODE;
                ctx->buf_len=0;
                ctx->buf_off=0;
                ctx->tmp_len=0;
                EVP_EncodeInit(&(ctx->base64));
                }

        n=ctx->buf_len-ctx->buf_off;
        while (n > 0)
                {
                i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
                if (i <= 0)
                        {
                        BIO_copy_next_retry(b);
                        return(i);
                        }
                ctx->buf_off+=i;
                n-=i;
                }
        /* at this point all pending data has been written */

        if ((in == NULL) || (inl <= 0)) return(0);

        ctx->buf_off=0;
        while (inl > 0)
                {
                n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl;

                if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
                        {
                        if (ctx->tmp_len > 0)
                                {

            
           // *** HERE WE HAVE A BUG - see the next block on how I propose
to fix it ***

          // BUGGY SEGMENT BEGINS

                                n=3-ctx->tmp_len;
                                memcpy(&(ctx->tmp[ctx->tmp_len]),in,n);
                                ctx->tmp_len+=n;
                                n=ctx->tmp_len;
                                if (n < 3)
                                        break;
                                ctx->buf_len=EVP_EncodeBlock(
                                        (unsigned char *)ctx->buf,
                                        (unsigned char *)ctx->tmp,n);
           
           // BUGGY SEGMENT ENDS

           // corrected code segment begins

                n=3-ctx->tmp_len; // correct - figure out how many
characters we need to form a triplet

                                memcpy(&(ctx->tmp[ctx->tmp_len]),in,n); //
correct - form a triplet for b64 encoding
                                
                ctx->tmp_len+=n;  // fine too

                // we should not do that because this totally messes up
statements marked as // (***) below (about 40 lines down from here)
                                //n=ctx->tmp_len; 

                // we don't need this because we don't have n=ctx->tmp_len;
anymore in any case this could be substituted
                // with "if( ctx->tmp_len < 3) break;" but that should never
happen 
                //
                                //if (n < 3) 
                                //      break;

                                ctx->buf_len=EVP_EncodeBlock(
                                        (unsigned char *)ctx->buf,
                                        (unsigned char *)ctx->tmp, /* n
replace with 3 or to be more honest ctx->tmp_len */ 3);

                ctx->tmp_len=0; // clear the temporary buffer so that on
subsequent reads we did not copy
                                // its content to the out stream again and
again

            // corrected code segment begins

                                }
                        else
                                {
                                if (n < 3)
                                        {
                                        memcpy(&(ctx->tmp[0]),in,n);
                                        ctx->tmp_len=n;
                                        break;
                                        }
                                n-=n%3;
                                ctx->buf_len=EVP_EncodeBlock(
                                        (unsigned char *)ctx->buf,
                                        (unsigned char *)in,n);
                                }
                        }
                else
                        {
                        EVP_EncodeUpdate(&(ctx->base64),
                                (unsigned char *)ctx->buf,&ctx->buf_len,
                                (unsigned char *)in,n);
                        }
                inl-=n; // (***)
                in+=n;  // (***)

                ctx->buf_off=0;
                n=ctx->buf_len;
                while (n > 0)
                        {
        
i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
                        if (i <= 0)
                                {
                                BIO_copy_next_retry(b);
                                return((ret == 0)?i:ret);
                                }
                        n-=i;
                        ctx->buf_off+=i;
                        }
                ctx->buf_len=0;
                ctx->buf_off=0;
                }
        return(ret);
        }
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to