Fix BIO_f_buffer().

Submitted by: Adam Langley
Reviewed by: Bodo Moeller
diff --git a/CHANGES b/CHANGES
index 142dc80..753492b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -490,6 +490,10 @@
 
  Changes between 1.0.0e and 1.0.0f [xx XXX xxxx]
 
+  *) Fix the BIO_f_buffer() implementation (which was mixing different
+     interpretations of the '..._len' fields).
+     [Adam Langley (Google)]
+
   *) Fix handling of BN_BLINDING: now BN_BLINDING_invert_ex (rather than
      BN_BLINDING_invert_ex) calls BN_BLINDING_update, ensuring that concurrent
      threads won't reuse the same blinding coefficients.
@@ -1410,6 +1414,10 @@
   
  Changes between 0.9.8r and 0.9.8s [xx XXX xxxx]
 
+  *) Fix the BIO_f_buffer() implementation (which was mixing different
+     interpretations of the '..._len' fields).
+     [Adam Langley (Google)]
+
   *) Fix handling of BN_BLINDING: now BN_BLINDING_invert_ex (rather than
      BN_BLINDING_invert_ex) calls BN_BLINDING_update, ensuring that concurrent
      threads won't reuse the same blinding coefficients.
diff --git a/crypto/bio/bf_buff.c b/crypto/bio/bf_buff.c
index c1fd75a..4b5a132 100644
--- a/crypto/bio/bf_buff.c
+++ b/crypto/bio/bf_buff.c
@@ -209,7 +209,7 @@
 	/* add to buffer and return */
 	if (i >= inl)
 		{
-		memcpy(&(ctx->obuf[ctx->obuf_len]),in,inl);
+		memcpy(&(ctx->obuf[ctx->obuf_off+ctx->obuf_len]),in,inl);
 		ctx->obuf_len+=inl;
 		return(num+inl);
 		}
@@ -219,7 +219,7 @@
 		{
 		if (i > 0) /* lets fill it up if we can */
 			{
-			memcpy(&(ctx->obuf[ctx->obuf_len]),in,i);
+			memcpy(&(ctx->obuf[ctx->obuf_off+ctx->obuf_len]),in,i);
 			in+=i;
 			inl-=i;
 			num+=i;
@@ -294,9 +294,9 @@
 	case BIO_C_GET_BUFF_NUM_LINES:
 		ret=0;
 		p1=ctx->ibuf;
-		for (i=ctx->ibuf_off; i<ctx->ibuf_len; i++)
+		for (i=0; i<ctx->ibuf_len; i++)
 			{
-			if (p1[i] == '\n') ret++;
+			if (p1[ctx->ibuf_off + i] == '\n') ret++;
 			}
 		break;
 	case BIO_CTRL_WPENDING:
@@ -399,17 +399,18 @@
 		for (;;)
 			{
 			BIO_clear_retry_flags(b);
-			if (ctx->obuf_len > ctx->obuf_off)
+			if (ctx->obuf_len > 0)
 				{
 				r=BIO_write(b->next_bio,
 					&(ctx->obuf[ctx->obuf_off]),
-					ctx->obuf_len-ctx->obuf_off);
+					ctx->obuf_len);
 #if 0
-fprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len-ctx->obuf_off,r);
+fprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len,r);
 #endif
 				BIO_copy_next_retry(b);
 				if (r <= 0) return((long)r);
 				ctx->obuf_off+=r;
+				ctx->obuf_len-=r;
 				}
 			else
 				{
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
index 152802f..ab47abc 100644
--- a/crypto/bio/bio.h
+++ b/crypto/bio/bio.h
@@ -306,6 +306,15 @@
 
 typedef struct bio_f_buffer_ctx_struct
 	{
+	/* Buffers are setup like this:
+	 *
+	 * <---------------------- size ----------------------->
+	 * +---------------------------------------------------+
+	 * | consumed | remaining          | free space        |
+	 * +---------------------------------------------------+
+	 * <-- off --><------- len ------->
+	 */
+
 	/* BIO *bio; */ /* this is now in the BIO struct */
 	int ibuf_size;	/* how big is the input buffer */
 	int obuf_size;	/* how big is the output buffer */