]> WPIA git - cassiopeia.git/blobdiff - lib/openssl/ssl/s2_pkt.c
add: execute openssl fetcher to fetch openssl 1.0.1j
[cassiopeia.git] / lib / openssl / ssl / s2_pkt.c
diff --git a/lib/openssl/ssl/s2_pkt.c b/lib/openssl/ssl/s2_pkt.c
new file mode 100644 (file)
index 0000000..8bb6ab8
--- /dev/null
@@ -0,0 +1,743 @@
+/* ssl/s2_pkt.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "ssl_locl.h"
+#ifndef OPENSSL_NO_SSL2
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+
+static int read_n(SSL *s,unsigned int n,unsigned int max,unsigned int extend);
+static int n_do_ssl_write(SSL *s, const unsigned char *buf, unsigned int len);
+static int write_pending(SSL *s, const unsigned char *buf, unsigned int len);
+static int ssl_mt_error(int n);
+
+
+/* SSL 2.0 imlementation for SSL_read/SSL_peek -
+ * This routine will return 0 to len bytes, decrypted etc if required.
+ */
+static int ssl2_read_internal(SSL *s, void *buf, int len, int peek)
+       {
+       int n;
+       unsigned char mac[MAX_MAC_SIZE];
+       unsigned char *p;
+       int i;
+       int mac_size;
+
+ ssl2_read_again:
+       if (SSL_in_init(s) && !s->in_handshake)
+               {
+               n=s->handshake_func(s);
+               if (n < 0) return(n);
+               if (n == 0)
+                       {
+                       SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_SSL_HANDSHAKE_FAILURE);
+                       return(-1);
+                       }
+               }
+
+       clear_sys_error();
+       s->rwstate=SSL_NOTHING;
+       if (len <= 0) return(len);
+
+       if (s->s2->ract_data_length != 0) /* read from buffer */
+               {
+               if (len > s->s2->ract_data_length)
+                       n=s->s2->ract_data_length;
+               else
+                       n=len;
+
+               memcpy(buf,s->s2->ract_data,(unsigned int)n);
+               if (!peek)
+                       {
+                       s->s2->ract_data_length-=n;
+                       s->s2->ract_data+=n;
+                       if (s->s2->ract_data_length == 0)
+                               s->rstate=SSL_ST_READ_HEADER;
+                       }
+
+               return(n);
+               }
+
+       /* s->s2->ract_data_length == 0
+        * 
+        * Fill the buffer, then goto ssl2_read_again.
+        */
+
+       if (s->rstate == SSL_ST_READ_HEADER)
+               {
+               if (s->first_packet)
+                       {
+                       n=read_n(s,5,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0);
+                       if (n <= 0) return(n); /* error or non-blocking */
+                       s->first_packet=0;
+                       p=s->packet;
+                       if (!((p[0] & 0x80) && (
+                               (p[2] == SSL2_MT_CLIENT_HELLO) ||
+                               (p[2] == SSL2_MT_SERVER_HELLO))))
+                               {
+                               SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_NON_SSLV2_INITIAL_PACKET);
+                               return(-1);
+                               }
+                       }
+               else
+                       {
+                       n=read_n(s,2,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0);
+                       if (n <= 0) return(n); /* error or non-blocking */
+                       }
+               /* part read stuff */
+
+               s->rstate=SSL_ST_READ_BODY;
+               p=s->packet;
+               /* Do header */
+               /*s->s2->padding=0;*/
+               s->s2->escape=0;
+               s->s2->rlength=(((unsigned int)p[0])<<8)|((unsigned int)p[1]);
+               if ((p[0] & TWO_BYTE_BIT))              /* Two byte header? */
+                       {
+                       s->s2->three_byte_header=0;
+                       s->s2->rlength&=TWO_BYTE_MASK;  
+                       }
+               else
+                       {
+                       s->s2->three_byte_header=1;
+                       s->s2->rlength&=THREE_BYTE_MASK;
+
+                       /* security >s2->escape */
+                       s->s2->escape=((p[0] & SEC_ESC_BIT))?1:0;
+                       }
+               }
+
+       if (s->rstate == SSL_ST_READ_BODY)
+               {
+               n=s->s2->rlength+2+s->s2->three_byte_header;
+               if (n > (int)s->packet_length)
+                       {
+                       n-=s->packet_length;
+                       i=read_n(s,(unsigned int)n,(unsigned int)n,1);
+                       if (i <= 0) return(i); /* ERROR */
+                       }
+
+               p= &(s->packet[2]);
+               s->rstate=SSL_ST_READ_HEADER;
+               if (s->s2->three_byte_header)
+                       s->s2->padding= *(p++);
+               else    s->s2->padding=0;
+
+               /* Data portion */
+               if (s->s2->clear_text)
+                       {
+                       mac_size = 0;
+                       s->s2->mac_data=p;
+                       s->s2->ract_data=p;
+                       if (s->s2->padding)
+                               {
+                               SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING);
+                               return(-1);
+                               }
+                       }
+               else
+                       {
+                       mac_size=EVP_MD_CTX_size(s->read_hash);
+                       if (mac_size < 0)
+                               return -1;
+                       OPENSSL_assert(mac_size <= MAX_MAC_SIZE);
+                       s->s2->mac_data=p;
+                       s->s2->ract_data= &p[mac_size];
+                       if (s->s2->padding + mac_size > s->s2->rlength)
+                               {
+                               SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING);
+                               return(-1);
+                               }
+                       }
+
+               s->s2->ract_data_length=s->s2->rlength;
+               /* added a check for length > max_size in case
+                * encryption was not turned on yet due to an error */
+               if ((!s->s2->clear_text) &&
+                       (s->s2->rlength >= (unsigned int)mac_size))
+                       {
+                       ssl2_enc(s,0);
+                       s->s2->ract_data_length-=mac_size;
+                       ssl2_mac(s,mac,0);
+                       s->s2->ract_data_length-=s->s2->padding;
+                       if (    (CRYPTO_memcmp(mac,s->s2->mac_data,mac_size) != 0) ||
+                               (s->s2->rlength%EVP_CIPHER_CTX_block_size(s->enc_read_ctx) != 0))
+                               {
+                               SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_MAC_DECODE);
+                               return(-1);
+                               }
+                       }
+               INC32(s->s2->read_sequence); /* expect next number */
+               /* s->s2->ract_data is now available for processing */
+
+               /* Possibly the packet that we just read had 0 actual data bytes.
+                * (SSLeay/OpenSSL itself never sends such packets; see ssl2_write.)
+                * In this case, returning 0 would be interpreted by the caller
+                * as indicating EOF, so it's not a good idea.  Instead, we just
+                * continue reading; thus ssl2_read_internal may have to process
+                * multiple packets before it can return.
+                *
+                * [Note that using select() for blocking sockets *never* guarantees
+                * that the next SSL_read will not block -- the available
+                * data may contain incomplete packets, and except for SSL 2,
+                * renegotiation can confuse things even more.] */
+
+               goto ssl2_read_again; /* This should really be
+                                      * "return ssl2_read(s,buf,len)",
+                                      * but that would allow for
+                                      * denial-of-service attacks if a
+                                      * C compiler is used that does not
+                                      * recognize end-recursion. */
+               }
+       else
+               {
+               SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_STATE);
+                       return(-1);
+               }
+       }
+
+int ssl2_read(SSL *s, void *buf, int len)
+       {
+       return ssl2_read_internal(s, buf, len, 0);
+       }
+
+int ssl2_peek(SSL *s, void *buf, int len)
+       {
+       return ssl2_read_internal(s, buf, len, 1);
+       }
+
+static int read_n(SSL *s, unsigned int n, unsigned int max,
+            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;
+               }
+       }
+
+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]);
+       /* 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;
+               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));
+       }
+
+int ssl2_part_read(SSL *s, unsigned long f, int i)
+       {
+       unsigned char *p;
+       int j;
+
+       if (i < 0)
+               {
+               /* ssl2_return_error(s); */
+               /* for non-blocking io,
+                * this is not necessarily fatal */
+               return(i);
+               }
+       else
+               {
+               s->init_num+=i;
+
+               /* Check for error.  While there are recoverable errors,
+                * this function is not called when those must be expected;
+                * any error detected here is fatal. */
+               if (s->init_num >= 3)
+                       {
+                       p=(unsigned char *)s->init_buf->data;
+                       if (p[0] == SSL2_MT_ERROR)
+                               {
+                               j=(p[1]<<8)|p[2];
+                               SSLerr((int)f,ssl_mt_error(j));
+                               s->init_num -= 3;
+                               if (s->init_num > 0)
+                                       memmove(p, p+3, s->init_num);
+                               }
+                       }
+
+               /* If it's not an error message, we have some error anyway --
+                * the message was shorter than expected.  This too is treated
+                * as fatal (at least if SSL_get_error is asked for its opinion). */
+               return(0);
+               }
+       }
+
+int ssl2_do_write(SSL *s)
+       {
+       int ret;
+
+       ret=ssl2_write(s,&s->init_buf->data[s->init_off],s->init_num);
+       if (ret == s->init_num)
+               {
+               if (s->msg_callback)
+                       s->msg_callback(1, s->version, 0, s->init_buf->data, (size_t)(s->init_off + s->init_num), s, s->msg_callback_arg);
+               return(1);
+               }
+       if (ret < 0)
+               return(-1);
+       s->init_off+=ret;
+       s->init_num-=ret;
+       return(0);
+       }
+
+static int ssl_mt_error(int n)
+       {
+       int ret;
+
+       switch (n)
+               {
+       case SSL2_PE_NO_CIPHER:
+               ret=SSL_R_PEER_ERROR_NO_CIPHER;
+               break;
+       case SSL2_PE_NO_CERTIFICATE:
+               ret=SSL_R_PEER_ERROR_NO_CERTIFICATE;
+               break;
+       case SSL2_PE_BAD_CERTIFICATE:
+               ret=SSL_R_PEER_ERROR_CERTIFICATE;
+               break;
+       case SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
+               ret=SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE;
+               break;
+       default:
+               ret=SSL_R_UNKNOWN_REMOTE_ERROR_TYPE;
+               break;
+               }
+       return(ret);
+       }
+#else /* !OPENSSL_NO_SSL2 */
+
+# if PEDANTIC
+static void *dummy=&dummy;
+# endif
+
+#endif