- unsigned int extend)
- {
- int i,off,newb;
-
- /* if there is stuff still in the buffer from a previous read,
- * and there is more than we want, take some. */
- if (s->s2->rbuf_left >= (int)n)
- {
- if (extend)
- s->packet_length+=n;
- else
- {
- s->packet= &(s->s2->rbuf[s->s2->rbuf_offs]);
- s->packet_length=n;
- }
- s->s2->rbuf_left-=n;
- s->s2->rbuf_offs+=n;
- return(n);
- }
-
- if (!s->read_ahead) max=n;
- if (max > (unsigned int)(SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2))
- max=SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2;
-
-
- /* Else we want more than we have.
- * First, if there is some left or we want to extend */
- off=0;
- if ((s->s2->rbuf_left != 0) || ((s->packet_length != 0) && extend))
- {
- newb=s->s2->rbuf_left;
- if (extend)
- {
- off=s->packet_length;
- if (s->packet != s->s2->rbuf)
- memcpy(s->s2->rbuf,s->packet,
- (unsigned int)newb+off);
- }
- else if (s->s2->rbuf_offs != 0)
- {
- memcpy(s->s2->rbuf,&(s->s2->rbuf[s->s2->rbuf_offs]),
- (unsigned int)newb);
- s->s2->rbuf_offs=0;
- }
- s->s2->rbuf_left=0;
- }
- else
- newb=0;
-
- /* off is the offset to start writing too.
- * r->s2->rbuf_offs is the 'unread data', now 0.
- * newb is the number of new bytes so far
- */
- s->packet=s->s2->rbuf;
- while (newb < (int)n)
- {
- clear_sys_error();
- if (s->rbio != NULL)
- {
- s->rwstate=SSL_READING;
- i=BIO_read(s->rbio,(char *)&(s->s2->rbuf[off+newb]),
- max-newb);
- }
- else
- {
- SSLerr(SSL_F_READ_N,SSL_R_READ_BIO_NOT_SET);
- i= -1;
- }
-#ifdef PKT_DEBUG
- if (s->debug & 0x01) sleep(1);
-#endif
- if (i <= 0)
- {
- s->s2->rbuf_left+=newb;
- return(i);
- }
- newb+=i;
- }
-
- /* record unread data */
- if (newb > (int)n)
- {
- s->s2->rbuf_offs=n+off;
- s->s2->rbuf_left=newb-n;
- }
- else
- {
- s->s2->rbuf_offs=0;
- s->s2->rbuf_left=0;
- }
- if (extend)
- s->packet_length+=n;
- else
- s->packet_length=n;
- s->rwstate=SSL_NOTHING;
- return(n);
- }
-
-int ssl2_write(SSL *s, const char *buf, int len)
- {
- unsigned int n,tot;
- int i;
-
- if (SSL_in_init(s) && !s->in_handshake)
- {
- i=s->handshake_func(s);
- if (i < 0) return(i);
- if (i == 0)
- {
- SSLerr(SSL_F_SSL2_WRITE,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
- }
- }
-
- if (s->error)
- {
- ssl2_write_error(s);
- if (s->error)
- return(-1);
- }
-
- clear_sys_error();
- s->rwstate=SSL_NOTHING;
- if (len <= 0) return(len);
-
- tot=s->s2->wnum;
- s->s2->wnum=0;
-
- n=(len-tot);
- for (;;)
- {
- i=do_ssl_write(s,&(buf[tot]),n);
- if (i <= 0)
- {
- s->s2->wnum=tot;
- return(i);
- }
- if (i == (int)n) return(tot+i);
-
- n-=i;
- tot+=i;
- }
- }
-
-static int write_pending(SSL *s, const char *buf, unsigned int len)
- {
- int i;
-
- /* s->s2->wpend_len != 0 MUST be true. */
-
- /* check that they have given us the same buffer to
- * write */
- if ((s->s2->wpend_tot > (int)len) || (s->s2->wpend_buf != buf))
- {
- SSLerr(SSL_F_WRITE_PENDING,SSL_R_BAD_WRITE_RETRY);
- return(-1);
- }
-
- for (;;)
- {
- clear_sys_error();
- if (s->wbio != NULL)
- {
- s->rwstate=SSL_WRITING;
- i=BIO_write(s->wbio,
- (char *)&(s->s2->write_ptr[s->s2->wpend_off]),
- (unsigned int)s->s2->wpend_len);
- }
- else
- {
- SSLerr(SSL_F_WRITE_PENDING,SSL_R_WRITE_BIO_NOT_SET);
- i= -1;
- }
-#ifdef PKT_DEBUG
- if (s->debug & 0x01) sleep(1);
-#endif
- if (i == s->s2->wpend_len)
- {
- s->s2->wpend_len=0;
- s->rwstate=SSL_NOTHING;
- return(s->s2->wpend_ret);
- }
- else if (i <= 0)
- return(i);
- s->s2->wpend_off+=i;
- s->s2->wpend_len-=i;
- }
- }
-
-static int do_ssl_write(SSL *s, const char *buf, unsigned int len)
- {
- unsigned int j,k,olen,p,mac_size,bs;
- register unsigned char *pp;
-
- olen=len;
-
- /* first check if there is data from an encryption waiting to
- * be sent - it must be sent because the other end is waiting.
- * This will happen with non-blocking IO. We print it and then
- * return.
- */
- if (s->s2->wpend_len != 0) return(write_pending(s,buf,len));
-
- /* set mac_size to mac size */
- if (s->s2->clear_text)
- mac_size=0;
- else
- mac_size=EVP_MD_size(s->write_hash);
-
- /* lets set the pad p */
- if (s->s2->clear_text)
- {
- if (len > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER)
- len=SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER;
- p=0;
- s->s2->three_byte_header=0;
- /* len=len; */
- }
- else
- {
- bs=EVP_CIPHER_CTX_block_size(s->enc_read_ctx);
- j=len+mac_size;
- if ((j > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) &&
- (!s->s2->escape))
- {
- if (j > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER)
- j=SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER;
- /* set k to the max number of bytes with 2
- * byte header */
- k=j-(j%bs);
- /* how many data bytes? */
- len=k-mac_size;
- s->s2->three_byte_header=0;
- p=0;
- }
- else if ((bs <= 1) && (!s->s2->escape))
- {
- /* len=len; */
- s->s2->three_byte_header=0;
- p=0;
- }
- else /* 3 byte header */
- {
- /*len=len; */
- p=(j%bs);
- p=(p == 0)?0:(bs-p);
- if (s->s2->escape)
- s->s2->three_byte_header=1;
- else
- s->s2->three_byte_header=(p == 0)?0:1;
- }
- }
- /* mac_size is the number of MAC bytes
- * len is the number of data bytes we are going to send
- * p is the number of padding bytes
- * if p == 0, it is a 2 byte header */
-
- s->s2->wlength=len;
- s->s2->padding=p;
- s->s2->mac_data= &(s->s2->wbuf[3]);
- s->s2->wact_data= &(s->s2->wbuf[3+mac_size]);
- /* we copy the data into s->s2->wbuf */
- memcpy(s->s2->wact_data,buf,len);
-#ifdef PURIFY
- if (p)
- memset(&(s->s2->wact_data[len]),0,p);
-#endif
-
- if (!s->s2->clear_text)
- {
- s->s2->wact_data_length=len+p;
- ssl2_mac(s,s->s2->mac_data,1);
- s->s2->wlength+=p+mac_size;
- ssl2_enc(s,1);
- }
-
- /* package up the header */
- s->s2->wpend_len=s->s2->wlength;
- if (s->s2->three_byte_header) /* 3 byte header */
- {
- pp=s->s2->mac_data;
- pp-=3;
- pp[0]=(s->s2->wlength>>8)&(THREE_BYTE_MASK>>8);
- if (s->s2->escape) pp[0]|=SEC_ESC_BIT;
- pp[1]=s->s2->wlength&0xff;
- pp[2]=s->s2->padding;
- s->s2->wpend_len+=3;
- }
- else
- {
- pp=s->s2->mac_data;
- pp-=2;
- pp[0]=((s->s2->wlength>>8)&(TWO_BYTE_MASK>>8))|TWO_BYTE_BIT;
- pp[1]=s->s2->wlength&0xff;
- s->s2->wpend_len+=2;
- }
- s->s2->write_ptr=pp;
-
- INC32(s->s2->write_sequence); /* expect next number */
-
- /* lets try to actually write the data */
- s->s2->wpend_tot=olen;
- s->s2->wpend_buf=buf;
-
- s->s2->wpend_ret=len;
-
- s->s2->wpend_off=0;
- return(write_pending(s,buf,olen));
- }
+ unsigned int extend)
+{
+ int i, off, newb;
+
+ /*
+ * if there is stuff still in the buffer from a previous read, and there
+ * is more than we want, take some.
+ */
+ if (s->s2->rbuf_left >= (int)n) {
+ if (extend)
+ s->packet_length += n;
+ else {
+ s->packet = &(s->s2->rbuf[s->s2->rbuf_offs]);
+ s->packet_length = n;
+ }
+ s->s2->rbuf_left -= n;
+ s->s2->rbuf_offs += n;
+ return (n);
+ }
+
+ if (!s->read_ahead)
+ max = n;
+ if (max > (unsigned int)(SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2))
+ max = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2;
+
+ /*
+ * Else we want more than we have. First, if there is some left or we
+ * want to extend
+ */
+ off = 0;
+ if ((s->s2->rbuf_left != 0) || ((s->packet_length != 0) && extend)) {
+ newb = s->s2->rbuf_left;
+ if (extend) {
+ off = s->packet_length;
+ if (s->packet != s->s2->rbuf)
+ memcpy(s->s2->rbuf, s->packet, (unsigned int)newb + off);
+ } else if (s->s2->rbuf_offs != 0) {
+ memcpy(s->s2->rbuf, &(s->s2->rbuf[s->s2->rbuf_offs]),
+ (unsigned int)newb);
+ s->s2->rbuf_offs = 0;
+ }
+ s->s2->rbuf_left = 0;
+ } else
+ newb = 0;
+
+ /*
+ * off is the offset to start writing too. r->s2->rbuf_offs is the
+ * 'unread data', now 0. newb is the number of new bytes so far
+ */
+ s->packet = s->s2->rbuf;
+ while (newb < (int)n) {
+ clear_sys_error();
+ if (s->rbio != NULL) {
+ s->rwstate = SSL_READING;
+ i = BIO_read(s->rbio, (char *)&(s->s2->rbuf[off + newb]),
+ max - newb);
+ } else {
+ SSLerr(SSL_F_READ_N, SSL_R_READ_BIO_NOT_SET);
+ i = -1;
+ }
+# ifdef PKT_DEBUG
+ if (s->debug & 0x01)
+ sleep(1);
+# endif
+ if (i <= 0) {
+ s->s2->rbuf_left += newb;
+ return i;
+ }
+ newb += i;
+ }
+
+ /* record unread data */
+ if (newb > (int)n) {
+ s->s2->rbuf_offs = n + off;
+ s->s2->rbuf_left = newb - n;
+ } else {
+ s->s2->rbuf_offs = 0;
+ s->s2->rbuf_left = 0;
+ }
+ if (extend)
+ s->packet_length += n;
+ else
+ s->packet_length = n;
+ s->rwstate = SSL_NOTHING;
+ return (n);
+}
+
+int ssl2_write(SSL *s, const void *_buf, int len)
+{
+ const unsigned char *buf = _buf;
+ unsigned int n, tot;
+ int i;
+
+ if (SSL_in_init(s) && !s->in_handshake) {
+ i = s->handshake_func(s);
+ if (i < 0)
+ return (i);
+ if (i == 0) {
+ SSLerr(SSL_F_SSL2_WRITE, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return (-1);
+ }
+ }
+
+ if (s->error) {
+ ssl2_write_error(s);
+ if (s->error)
+ return (-1);
+ }
+
+ clear_sys_error();
+ s->rwstate = SSL_NOTHING;
+ if (len <= 0)
+ return (len);
+
+ tot = s->s2->wnum;
+ s->s2->wnum = 0;
+
+ n = (len - tot);
+ for (;;) {
+ i = n_do_ssl_write(s, &(buf[tot]), n);
+ if (i <= 0) {
+ s->s2->wnum = tot;
+ return (i);
+ }
+ if ((i == (int)n) || (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)) {
+ return (tot + i);
+ }
+
+ n -= i;
+ tot += i;
+ }
+}
+
+/*
+ * Return values are as per SSL_write()
+ */
+static int write_pending(SSL *s, const unsigned char *buf, unsigned int len)
+{
+ int i;
+
+ /* s->s2->wpend_len != 0 MUST be true. */
+
+ /*
+ * check that they have given us the same buffer to write
+ */
+ if ((s->s2->wpend_tot > (int)len) ||
+ ((s->s2->wpend_buf != buf) &&
+ !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))) {
+ SSLerr(SSL_F_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY);
+ return (-1);
+ }
+
+ for (;;) {
+ clear_sys_error();
+ if (s->wbio != NULL) {
+ s->rwstate = SSL_WRITING;
+ i = BIO_write(s->wbio,
+ (char *)&(s->s2->write_ptr[s->s2->wpend_off]),
+ (unsigned int)s->s2->wpend_len);
+ } else {
+ SSLerr(SSL_F_WRITE_PENDING, SSL_R_WRITE_BIO_NOT_SET);
+ i = -1;
+ }
+# ifdef PKT_DEBUG
+ if (s->debug & 0x01)
+ sleep(1);
+# endif
+ if (i == s->s2->wpend_len) {
+ s->s2->wpend_len = 0;
+ s->rwstate = SSL_NOTHING;
+ return (s->s2->wpend_ret);
+ } else if (i <= 0)
+ return i;
+ s->s2->wpend_off += i;
+ s->s2->wpend_len -= i;
+ }
+}
+
+static int n_do_ssl_write(SSL *s, const unsigned char *buf, unsigned int len)
+{
+ unsigned int j, k, olen, p, bs;
+ int mac_size;
+ register unsigned char *pp;
+
+ olen = len;
+
+ /*
+ * first check if there is data from an encryption waiting to be sent -
+ * it must be sent because the other end is waiting. This will happen
+ * with non-blocking IO. We print it and then return.
+ */
+ if (s->s2->wpend_len != 0)
+ return (write_pending(s, buf, len));
+
+ /* set mac_size to mac size */
+ if (s->s2->clear_text)
+ mac_size = 0;
+ else {
+ mac_size = EVP_MD_CTX_size(s->write_hash);
+ if (mac_size < 0)
+ return -1;
+ }
+
+ /* lets set the pad p */
+ if (s->s2->clear_text) {
+ if (len > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER)
+ len = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER;
+ p = 0;
+ s->s2->three_byte_header = 0;
+ /* len=len; */
+ } else {
+ bs = EVP_CIPHER_CTX_block_size(s->enc_read_ctx);
+ j = len + mac_size;
+ /*
+ * Two-byte headers allow for a larger record length than three-byte
+ * headers, but we can't use them if we need padding or if we have to
+ * set the escape bit.
+ */
+ if ((j > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) && (!s->s2->escape)) {
+ if (j > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER)
+ j = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER;
+ /*
+ * set k to the max number of bytes with 2 byte header
+ */
+ k = j - (j % bs);
+ /* how many data bytes? */
+ len = k - mac_size;
+ s->s2->three_byte_header = 0;
+ p = 0;
+ } else if ((bs <= 1) && (!s->s2->escape)) {
+ /*-
+ * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER, thus
+ * j < SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER
+ */
+ s->s2->three_byte_header = 0;
+ p = 0;
+ } else { /* we may have to use a 3 byte header */
+
+ /*-
+ * If s->s2->escape is not set, then
+ * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER, and thus
+ * j < SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER.
+ */
+ p = (j % bs);
+ p = (p == 0) ? 0 : (bs - p);
+ if (s->s2->escape) {
+ s->s2->three_byte_header = 1;
+ if (j > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+ j = SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER;
+ } else
+ s->s2->three_byte_header = (p == 0) ? 0 : 1;
+ }
+ }
+
+ /*-
+ * Now
+ * j <= SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER
+ * holds, and if s->s2->three_byte_header is set, then even
+ * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER.
+ */
+
+ /*
+ * mac_size is the number of MAC bytes len is the number of data bytes we
+ * are going to send p is the number of padding bytes (if it is a
+ * two-byte header, then p == 0)
+ */
+
+ s->s2->wlength = len;
+ s->s2->padding = p;
+ s->s2->mac_data = &(s->s2->wbuf[3]);
+ s->s2->wact_data = &(s->s2->wbuf[3 + mac_size]);
+
+ /*
+ * It would be clearer to write this as follows:
+ * if (mac_size + len + p > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER)
+ * However |len| is user input that could in theory be very large. We
+ * know |mac_size| and |p| are small, so to avoid any possibility of
+ * overflow we write it like this.
+ *
+ * In theory this should never fail because the logic above should have
+ * modified |len| if it is too big. But we are being cautious.
+ */
+ if (len > (SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER - (mac_size + p))) {
+ return -1;
+ }
+ /* we copy the data into s->s2->wbuf */
+ memcpy(s->s2->wact_data, buf, len);
+ if (p)
+ memset(&(s->s2->wact_data[len]), 0, p); /* arbitrary padding */
+
+ if (!s->s2->clear_text) {
+ s->s2->wact_data_length = len + p;
+ ssl2_mac(s, s->s2->mac_data, 1);
+ s->s2->wlength += p + mac_size;
+ if (ssl2_enc(s, 1) < 1)
+ return -1;
+ }
+
+ /* package up the header */
+ s->s2->wpend_len = s->s2->wlength;
+ if (s->s2->three_byte_header) { /* 3 byte header */
+ pp = s->s2->mac_data;
+ pp -= 3;
+ pp[0] = (s->s2->wlength >> 8) & (THREE_BYTE_MASK >> 8);
+ if (s->s2->escape)
+ pp[0] |= SEC_ESC_BIT;
+ pp[1] = s->s2->wlength & 0xff;
+ pp[2] = s->s2->padding;
+ s->s2->wpend_len += 3;
+ } else {
+ pp = s->s2->mac_data;
+ pp -= 2;
+ pp[0] = ((s->s2->wlength >> 8) & (TWO_BYTE_MASK >> 8)) | TWO_BYTE_BIT;
+ pp[1] = s->s2->wlength & 0xff;
+ s->s2->wpend_len += 2;
+ }
+ s->s2->write_ptr = pp;
+
+ INC32(s->s2->write_sequence); /* expect next number */
+
+ /* lets try to actually write the data */
+ s->s2->wpend_tot = olen;
+ s->s2->wpend_buf = buf;
+
+ s->s2->wpend_ret = len;
+
+ s->s2->wpend_off = 0;
+ return (write_pending(s, buf, olen));
+}