diff options
author | marha <marha@users.sourceforge.net> | 2011-04-13 08:10:11 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-04-13 08:10:11 +0000 |
commit | c1e91b66cbcf91645f65b9d63f115dcb5a441406 (patch) | |
tree | 67be8fec5fa39c8febbd86416aeb9ef09053d1d4 /openssl/ssl | |
parent | d92d86b5e751381366dcde13cf983e041e300ee2 (diff) | |
parent | 7bcdd32ccff794b9a83a88ff9bc2d0b7b088bd06 (diff) | |
download | vcxsrv-c1e91b66cbcf91645f65b9d63f115dcb5a441406.tar.gz vcxsrv-c1e91b66cbcf91645f65b9d63f115dcb5a441406.tar.bz2 vcxsrv-c1e91b66cbcf91645f65b9d63f115dcb5a441406.zip |
svn merge ^/branches/released .
Diffstat (limited to 'openssl/ssl')
-rw-r--r-- | openssl/ssl/d1_enc.c | 582 | ||||
-rw-r--r-- | openssl/ssl/d1_pkt.c | 3537 | ||||
-rw-r--r-- | openssl/ssl/install.com | 180 | ||||
-rw-r--r-- | openssl/ssl/s2_srvr.c | 2283 | ||||
-rw-r--r-- | openssl/ssl/ssl-lib.com | 2173 | ||||
-rw-r--r-- | openssl/ssl/t1_lib.c | 3488 |
6 files changed, 6153 insertions, 6090 deletions
diff --git a/openssl/ssl/d1_enc.c b/openssl/ssl/d1_enc.c index 8fa57347a..d762dc5c5 100644 --- a/openssl/ssl/d1_enc.c +++ b/openssl/ssl/d1_enc.c @@ -1,293 +1,289 @@ -/* ssl/d1_enc.c */ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1998-2005 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). - * - */ -/* 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.] - */ - -#include <stdio.h> -#include "ssl_locl.h" -#ifndef OPENSSL_NO_COMP -#include <openssl/comp.h> -#endif -#include <openssl/evp.h> -#include <openssl/hmac.h> -#include <openssl/md5.h> -#include <openssl/rand.h> -#ifdef KSSL_DEBUG -#include <openssl/des.h> -#endif - -int dtls1_enc(SSL *s, int send) - { - SSL3_RECORD *rec; - EVP_CIPHER_CTX *ds; - unsigned long l; - int bs,i,ii,j,k,n=0; - const EVP_CIPHER *enc; - - if (send) - { - if (EVP_MD_CTX_md(s->write_hash)) - { - n=EVP_MD_CTX_size(s->write_hash); - if (n < 0) - return -1; - } - ds=s->enc_write_ctx; - rec= &(s->s3->wrec); - if (s->enc_write_ctx == NULL) - enc=NULL; - else - { - enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); - if ( rec->data != rec->input) - /* we can't write into the input stream */ - fprintf(stderr, "%s:%d: rec->data != rec->input\n", - __FILE__, __LINE__); - else if ( EVP_CIPHER_block_size(ds->cipher) > 1) - { - if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0) - return -1; - } - } - } - else - { - if (EVP_MD_CTX_md(s->read_hash)) - { - n=EVP_MD_CTX_size(s->read_hash); - if (n < 0) - return -1; - } - ds=s->enc_read_ctx; - rec= &(s->s3->rrec); - if (s->enc_read_ctx == NULL) - enc=NULL; - else - enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); - } - -#ifdef KSSL_DEBUG - printf("dtls1_enc(%d)\n", send); -#endif /* KSSL_DEBUG */ - - if ((s->session == NULL) || (ds == NULL) || - (enc == NULL)) - { - memmove(rec->data,rec->input,rec->length); - rec->input=rec->data; - } - else - { - l=rec->length; - bs=EVP_CIPHER_block_size(ds->cipher); - - if ((bs != 1) && send) - { - i=bs-((int)l%bs); - - /* Add weird padding of upto 256 bytes */ - - /* we need to add 'i' padding bytes of value j */ - j=i-1; - if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG) - { - if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) - j++; - } - for (k=(int)l; k<(int)(l+i); k++) - rec->input[k]=j; - l+=i; - rec->length+=i; - } - -#ifdef KSSL_DEBUG - { - unsigned long ui; - printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", - ds,rec->data,rec->input,l); - printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", - ds->buf_len, ds->cipher->key_len, - DES_KEY_SZ, DES_SCHEDULE_SZ, - ds->cipher->iv_len); - printf("\t\tIV: "); - for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); - printf("\n"); - printf("\trec->input="); - for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]); - printf("\n"); - } -#endif /* KSSL_DEBUG */ - - if (!send) - { - if (l == 0 || l%bs != 0) - { - SSLerr(SSL_F_DTLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); - ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED); - return 0; - } - } - - EVP_Cipher(ds,rec->data,rec->input,l); - -#ifdef KSSL_DEBUG - { - unsigned long i; - printf("\trec->data="); - for (i=0; i<l; i++) - printf(" %02x", rec->data[i]); printf("\n"); - } -#endif /* KSSL_DEBUG */ - - if ((bs != 1) && !send) - { - ii=i=rec->data[l-1]; /* padding_length */ - i++; - if (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG) - { - /* First packet is even in size, so check */ - if ((memcmp(s->s3->read_sequence, - "\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1)) - s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG; - if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) - i--; - } - /* TLS 1.0 does not bound the number of padding bytes by the block size. - * All of them must have value 'padding_length'. */ - if (i > (int)rec->length) - { - /* Incorrect padding. SSLerr() and ssl3_alert are done - * by caller: we don't want to reveal whether this is - * a decryption error or a MAC verification failure - * (see http://www.openssl.org/~bodo/tls-cbc.txt) - */ - return -1; - } - for (j=(int)(l-i); j<(int)l; j++) - { - if (rec->data[j] != ii) - { - /* Incorrect padding */ - return -1; - } - } - rec->length-=i; - - rec->data += bs; /* skip the implicit IV */ - rec->input += bs; - rec->length -= bs; - } - } - return(1); - } - +/* ssl/d1_enc.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* 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.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+#ifdef KSSL_DEBUG
+#include <openssl/des.h>
+#endif
+
+int dtls1_enc(SSL *s, int send)
+ {
+ SSL3_RECORD *rec;
+ EVP_CIPHER_CTX *ds;
+ unsigned long l;
+ int bs,i,ii,j,k,n=0;
+ const EVP_CIPHER *enc;
+
+ if (send)
+ {
+ if (EVP_MD_CTX_md(s->write_hash))
+ {
+ n=EVP_MD_CTX_size(s->write_hash);
+ if (n < 0)
+ return -1;
+ }
+ ds=s->enc_write_ctx;
+ rec= &(s->s3->wrec);
+ if (s->enc_write_ctx == NULL)
+ enc=NULL;
+ else
+ {
+ enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+ if ( rec->data != rec->input)
+ /* we can't write into the input stream */
+ fprintf(stderr, "%s:%d: rec->data != rec->input\n",
+ __FILE__, __LINE__);
+ else if ( EVP_CIPHER_block_size(ds->cipher) > 1)
+ {
+ if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0)
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ if (EVP_MD_CTX_md(s->read_hash))
+ {
+ n=EVP_MD_CTX_size(s->read_hash);
+ if (n < 0)
+ return -1;
+ }
+ ds=s->enc_read_ctx;
+ rec= &(s->s3->rrec);
+ if (s->enc_read_ctx == NULL)
+ enc=NULL;
+ else
+ enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+ }
+
+#ifdef KSSL_DEBUG
+ printf("dtls1_enc(%d)\n", send);
+#endif /* KSSL_DEBUG */
+
+ if ((s->session == NULL) || (ds == NULL) ||
+ (enc == NULL))
+ {
+ memmove(rec->data,rec->input,rec->length);
+ rec->input=rec->data;
+ }
+ else
+ {
+ l=rec->length;
+ bs=EVP_CIPHER_block_size(ds->cipher);
+
+ if ((bs != 1) && send)
+ {
+ i=bs-((int)l%bs);
+
+ /* Add weird padding of upto 256 bytes */
+
+ /* we need to add 'i' padding bytes of value j */
+ j=i-1;
+ if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
+ {
+ if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+ j++;
+ }
+ for (k=(int)l; k<(int)(l+i); k++)
+ rec->input[k]=j;
+ l+=i;
+ rec->length+=i;
+ }
+
+#ifdef KSSL_DEBUG
+ {
+ unsigned long ui;
+ printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
+ ds,rec->data,rec->input,l);
+ printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
+ ds->buf_len, ds->cipher->key_len,
+ DES_KEY_SZ, DES_SCHEDULE_SZ,
+ ds->cipher->iv_len);
+ printf("\t\tIV: ");
+ for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
+ printf("\n");
+ printf("\trec->input=");
+ for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
+ printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ if (!send)
+ {
+ if (l == 0 || l%bs != 0)
+ return -1;
+ }
+
+ EVP_Cipher(ds,rec->data,rec->input,l);
+
+#ifdef KSSL_DEBUG
+ {
+ unsigned long i;
+ printf("\trec->data=");
+ for (i=0; i<l; i++)
+ printf(" %02x", rec->data[i]); printf("\n");
+ }
+#endif /* KSSL_DEBUG */
+
+ if ((bs != 1) && !send)
+ {
+ ii=i=rec->data[l-1]; /* padding_length */
+ i++;
+ if (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG)
+ {
+ /* First packet is even in size, so check */
+ if ((memcmp(s->s3->read_sequence,
+ "\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1))
+ s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
+ if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+ i--;
+ }
+ /* TLS 1.0 does not bound the number of padding bytes by the block size.
+ * All of them must have value 'padding_length'. */
+ if (i > (int)rec->length)
+ {
+ /* Incorrect padding. SSLerr() and ssl3_alert are done
+ * by caller: we don't want to reveal whether this is
+ * a decryption error or a MAC verification failure
+ * (see http://www.openssl.org/~bodo/tls-cbc.txt)
+ */
+ return -1;
+ }
+ for (j=(int)(l-i); j<(int)l; j++)
+ {
+ if (rec->data[j] != ii)
+ {
+ /* Incorrect padding */
+ return -1;
+ }
+ }
+ rec->length-=i;
+
+ rec->data += bs; /* skip the implicit IV */
+ rec->input += bs;
+ rec->length -= bs;
+ }
+ }
+ return(1);
+ }
+
diff --git a/openssl/ssl/d1_pkt.c b/openssl/ssl/d1_pkt.c index 1fd58bf59..79b723a5e 100644 --- a/openssl/ssl/d1_pkt.c +++ b/openssl/ssl/d1_pkt.c @@ -1,1768 +1,1769 @@ -/* ssl/d1_pkt.c */ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1998-2005 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). - * - */ -/* 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.] - */ - -#include <stdio.h> -#include <errno.h> -#define USE_SOCKETS -#include "ssl_locl.h" -#include <openssl/evp.h> -#include <openssl/buffer.h> -#include <openssl/pqueue.h> -#include <openssl/rand.h> - -/* mod 128 saturating subtract of two 64-bit values in big-endian order */ -static int satsub64be(const unsigned char *v1,const unsigned char *v2) -{ int ret,sat,brw,i; - - if (sizeof(long) == 8) do - { const union { long one; char little; } is_endian = {1}; - long l; - - if (is_endian.little) break; - /* not reached on little-endians */ - /* following test is redundant, because input is - * always aligned, but I take no chances... */ - if (((size_t)v1|(size_t)v2)&0x7) break; - - l = *((long *)v1); - l -= *((long *)v2); - if (l>128) return 128; - else if (l<-128) return -128; - else return (int)l; - } while (0); - - ret = (int)v1[7]-(int)v2[7]; - sat = 0; - brw = ret>>8; /* brw is either 0 or -1 */ - if (ret & 0x80) - { for (i=6;i>=0;i--) - { brw += (int)v1[i]-(int)v2[i]; - sat |= ~brw; - brw >>= 8; - } - } - else - { for (i=6;i>=0;i--) - { brw += (int)v1[i]-(int)v2[i]; - sat |= brw; - brw >>= 8; - } - } - brw <<= 8; /* brw is either 0 or -256 */ - - if (sat&0xff) return brw | 0x80; - else return brw + (ret&0xFF); -} - -static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, - int len, int peek); -static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); -static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); -static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch); -#if 0 -static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, - unsigned short *priority, unsigned long *offset); -#endif -static int dtls1_buffer_record(SSL *s, record_pqueue *q, - unsigned char *priority); -static int dtls1_process_record(SSL *s); -static void dtls1_clear_timeouts(SSL *s); - -/* copy buffered record into SSL structure */ -static int -dtls1_copy_record(SSL *s, pitem *item) - { - DTLS1_RECORD_DATA *rdata; - - rdata = (DTLS1_RECORD_DATA *)item->data; - - if (s->s3->rbuf.buf != NULL) - OPENSSL_free(s->s3->rbuf.buf); - - s->packet = rdata->packet; - s->packet_length = rdata->packet_length; - memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); - - /* Set proper sequence number for mac calculation */ - memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6); - - return(1); - } - - -static int -dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority) - { - DTLS1_RECORD_DATA *rdata; - pitem *item; - - /* Limit the size of the queue to prevent DOS attacks */ - if (pqueue_size(queue->q) >= 100) - return 0; - - rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA)); - item = pitem_new(priority, rdata); - if (rdata == NULL || item == NULL) - { - if (rdata != NULL) OPENSSL_free(rdata); - if (item != NULL) pitem_free(item); - - SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); - return(0); - } - - rdata->packet = s->packet; - rdata->packet_length = s->packet_length; - memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD)); - - item->data = rdata; - - /* insert should not fail, since duplicates are dropped */ - if (pqueue_insert(queue->q, item) == NULL) - { - OPENSSL_free(rdata); - pitem_free(item); - return(0); - } - - s->packet = NULL; - s->packet_length = 0; - memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER)); - memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD)); - - if (!ssl3_setup_buffers(s)) - { - SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); - OPENSSL_free(rdata); - pitem_free(item); - return(0); - } - - return(1); - } - - -static int -dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) - { - pitem *item; - - item = pqueue_pop(queue->q); - if (item) - { - dtls1_copy_record(s, item); - - OPENSSL_free(item->data); - pitem_free(item); - - return(1); - } - - return(0); - } - - -/* retrieve a buffered record that belongs to the new epoch, i.e., not processed - * yet */ -#define dtls1_get_unprocessed_record(s) \ - dtls1_retrieve_buffered_record((s), \ - &((s)->d1->unprocessed_rcds)) - -/* retrieve a buffered record that belongs to the current epoch, ie, processed */ -#define dtls1_get_processed_record(s) \ - dtls1_retrieve_buffered_record((s), \ - &((s)->d1->processed_rcds)) - -static int -dtls1_process_buffered_records(SSL *s) - { - pitem *item; - - item = pqueue_peek(s->d1->unprocessed_rcds.q); - if (item) - { - /* Check if epoch is current. */ - if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch) - return(1); /* Nothing to do. */ - - /* Process all the records. */ - while (pqueue_peek(s->d1->unprocessed_rcds.q)) - { - dtls1_get_unprocessed_record(s); - if ( ! dtls1_process_record(s)) - return(0); - dtls1_buffer_record(s, &(s->d1->processed_rcds), - s->s3->rrec.seq_num); - } - } - - /* sync epoch numbers once all the unprocessed records - * have been processed */ - s->d1->processed_rcds.epoch = s->d1->r_epoch; - s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1; - - return(1); - } - - -#if 0 - -static int -dtls1_get_buffered_record(SSL *s) - { - pitem *item; - PQ_64BIT priority = - (((PQ_64BIT)s->d1->handshake_read_seq) << 32) | - ((PQ_64BIT)s->d1->r_msg_hdr.frag_off); - - if ( ! SSL_in_init(s)) /* if we're not (re)negotiating, - nothing buffered */ - return 0; - - - item = pqueue_peek(s->d1->rcvd_records); - if (item && item->priority == priority) - { - /* Check if we've received the record of interest. It must be - * a handshake record, since data records as passed up without - * buffering */ - DTLS1_RECORD_DATA *rdata; - item = pqueue_pop(s->d1->rcvd_records); - rdata = (DTLS1_RECORD_DATA *)item->data; - - if (s->s3->rbuf.buf != NULL) - OPENSSL_free(s->s3->rbuf.buf); - - s->packet = rdata->packet; - s->packet_length = rdata->packet_length; - memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); - - OPENSSL_free(item->data); - pitem_free(item); - - /* s->d1->next_expected_seq_num++; */ - return(1); - } - - return 0; - } - -#endif - -static int -dtls1_process_record(SSL *s) -{ - int i,al; - int clear=0; - int enc_err; - SSL_SESSION *sess; - SSL3_RECORD *rr; - unsigned int mac_size; - unsigned char md[EVP_MAX_MD_SIZE]; - - - rr= &(s->s3->rrec); - sess = s->session; - - /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, - * and we have that many bytes in s->packet - */ - rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]); - - /* ok, we can now read from 's->packet' data into 'rr' - * rr->input points at rr->length bytes, which - * need to be copied into rr->data by either - * the decryption or by the decompression - * When the data is 'copied' into the rr->data buffer, - * rr->input will be pointed at the new buffer */ - - /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] - * rr->length bytes of encrypted compressed stuff. */ - - /* check is not needed I believe */ - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) - { - al=SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG); - goto f_err; - } - - /* decrypt in place in 'rr->input' */ - rr->data=rr->input; - - enc_err = s->method->ssl3_enc->enc(s,0); - if (enc_err <= 0) - { - if (enc_err == 0) - /* SSLerr() and ssl3_send_alert() have been called */ - goto err; - - /* otherwise enc_err == -1 */ - goto err; - } - -#ifdef TLS_DEBUG -printf("dec %d\n",rr->length); -{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); } -printf("\n"); -#endif - - /* r->length is now the compressed data plus mac */ - if ( (sess == NULL) || - (s->enc_read_ctx == NULL) || - (s->read_hash == NULL)) - clear=1; - - if (!clear) - { - /* !clear => s->read_hash != NULL => mac_size != -1 */ - int t; - t=EVP_MD_CTX_size(s->read_hash); - OPENSSL_assert(t >= 0); - mac_size=t; - - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size) - { -#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */ - al=SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG); - goto f_err; -#else - goto err; -#endif - } - /* check the MAC for rr->input (it's in mac_size bytes at the tail) */ - if (rr->length < mac_size) - { -#if 0 /* OK only for stream ciphers */ - al=SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT); - goto f_err; -#else - goto err; -#endif - } - rr->length-=mac_size; - i=s->method->ssl3_enc->mac(s,md,0); - if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 0) - { - goto err; - } - } - - /* r->length is now just compressed */ - if (s->expand != NULL) - { - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) - { - al=SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG); - goto f_err; - } - if (!ssl3_do_uncompress(s)) - { - al=SSL_AD_DECOMPRESSION_FAILURE; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_BAD_DECOMPRESSION); - goto f_err; - } - } - - if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) - { - al=SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DATA_LENGTH_TOO_LONG); - goto f_err; - } - - rr->off=0; - /* So at this point the following is true - * ssl->s3->rrec.type is the type of record - * ssl->s3->rrec.length == number of bytes in record - * ssl->s3->rrec.off == offset to first valid byte - * ssl->s3->rrec.data == where to take bytes from, increment - * after use :-). - */ - - /* we have pulled in a full packet so zero things */ - s->packet_length=0; - dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */ - return(1); - -f_err: - ssl3_send_alert(s,SSL3_AL_FATAL,al); -err: - return(0); -} - - -/* Call this to get a new input record. - * It will return <= 0 if more data is needed, normally due to an error - * or non-blocking IO. - * When it finishes, one packet has been decoded and can be found in - * ssl->s3->rrec.type - is the type of record - * ssl->s3->rrec.data, - data - * ssl->s3->rrec.length, - number of bytes - */ -/* used only by dtls1_read_bytes */ -int dtls1_get_record(SSL *s) - { - int ssl_major,ssl_minor; - int i,n; - SSL3_RECORD *rr; - unsigned char *p = NULL; - unsigned short version; - DTLS1_BITMAP *bitmap; - unsigned int is_next_epoch; - - rr= &(s->s3->rrec); - - /* The epoch may have changed. If so, process all the - * pending records. This is a non-blocking operation. */ - dtls1_process_buffered_records(s); - - /* if we're renegotiating, then there may be buffered records */ - if (dtls1_get_processed_record(s)) - return 1; - - /* get something from the wire */ -again: - /* check if we have the header */ - if ( (s->rstate != SSL_ST_READ_BODY) || - (s->packet_length < DTLS1_RT_HEADER_LENGTH)) - { - n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0); - /* read timeout is handled by dtls1_read_bytes */ - if (n <= 0) return(n); /* error or non-blocking */ - - /* this packet contained a partial record, dump it */ - if (s->packet_length != DTLS1_RT_HEADER_LENGTH) - { - s->packet_length = 0; - goto again; - } - - s->rstate=SSL_ST_READ_BODY; - - p=s->packet; - - /* Pull apart the header into the DTLS1_RECORD */ - rr->type= *(p++); - ssl_major= *(p++); - ssl_minor= *(p++); - version=(ssl_major<<8)|ssl_minor; - - /* sequence number is 64 bits, with top 2 bytes = epoch */ - n2s(p,rr->epoch); - - memcpy(&(s->s3->read_sequence[2]), p, 6); - p+=6; - - n2s(p,rr->length); - - /* Lets check version */ - if (!s->first_packet) - { - if (version != s->version) - { - /* unexpected version, silently discard */ - rr->length = 0; - s->packet_length = 0; - goto again; - } - } - - if ((version & 0xff00) != (s->version & 0xff00)) - { - /* wrong version, silently discard record */ - rr->length = 0; - s->packet_length = 0; - goto again; - } - - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) - { - /* record too long, silently discard it */ - rr->length = 0; - s->packet_length = 0; - goto again; - } - - /* now s->rstate == SSL_ST_READ_BODY */ - } - - /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ - - if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH) - { - /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ - i=rr->length; - n=ssl3_read_n(s,i,i,1); - if (n <= 0) return(n); /* error or non-blocking io */ - - /* this packet contained a partial record, dump it */ - if ( n != i) - { - rr->length = 0; - s->packet_length = 0; - goto again; - } - - /* now n == rr->length, - * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */ - } - s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */ - - /* match epochs. NULL means the packet is dropped on the floor */ - bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); - if ( bitmap == NULL) - { - rr->length = 0; - s->packet_length = 0; /* dump this record */ - goto again; /* get another record */ - } - - /* Check whether this is a repeat, or aged record. - * Don't check if we're listening and this message is - * a ClientHello. They can look as if they're replayed, - * since they arrive from different connections and - * would be dropped unnecessarily. - */ - if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE && - *p == SSL3_MT_CLIENT_HELLO) && - !dtls1_record_replay_check(s, bitmap)) - { - rr->length = 0; - s->packet_length=0; /* dump this record */ - goto again; /* get another record */ - } - - /* just read a 0 length packet */ - if (rr->length == 0) goto again; - - /* If this record is from the next epoch (either HM or ALERT), - * and a handshake is currently in progress, buffer it since it - * cannot be processed at this time. */ - if (is_next_epoch) - { - if (SSL_in_init(s) || s->in_handshake) - { - dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num); - } - rr->length = 0; - s->packet_length = 0; - goto again; - } - - if (!dtls1_process_record(s)) - { - rr->length = 0; - s->packet_length = 0; /* dump this record */ - goto again; /* get another record */ - } - - dtls1_clear_timeouts(s); /* done waiting */ - return(1); - - } - -/* Return up to 'len' payload bytes received in 'type' records. - * 'type' is one of the following: - * - * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) - * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) - * - 0 (during a shutdown, no data has to be returned) - * - * If we don't have stored data to work from, read a SSL/TLS record first - * (possibly multiple records if we still don't have anything to return). - * - * This function must handle any surprises the peer may have for us, such as - * Alert records (e.g. close_notify), ChangeCipherSpec records (not really - * a surprise, but handled as if it were), or renegotiation requests. - * Also if record payloads contain fragments too small to process, we store - * them until there is enough for the respective protocol (the record protocol - * may use arbitrary fragmentation and even interleaving): - * Change cipher spec protocol - * just 1 byte needed, no need for keeping anything stored - * Alert protocol - * 2 bytes needed (AlertLevel, AlertDescription) - * Handshake protocol - * 4 bytes needed (HandshakeType, uint24 length) -- we just have - * to detect unexpected Client Hello and Hello Request messages - * here, anything else is handled by higher layers - * Application data protocol - * none of our business - */ -int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) - { - int al,i,j,ret; - unsigned int n; - SSL3_RECORD *rr; - void (*cb)(const SSL *ssl,int type2,int val)=NULL; - - if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ - if (!ssl3_setup_buffers(s)) - return(-1); - - /* XXX: check what the second '&& type' is about */ - if ((type && (type != SSL3_RT_APPLICATION_DATA) && - (type != SSL3_RT_HANDSHAKE) && type) || - (peek && (type != SSL3_RT_APPLICATION_DATA))) - { - SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); - return -1; - } - - /* check whether there's a handshake message (client hello?) waiting */ - if ( (ret = have_handshake_fragment(s, type, buf, len, peek))) - return ret; - - /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ - - if (!s->in_handshake && SSL_in_init(s)) - { - /* type == SSL3_RT_APPLICATION_DATA */ - i=s->handshake_func(s); - if (i < 0) return(i); - if (i == 0) - { - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); - return(-1); - } - } - -start: - s->rwstate=SSL_NOTHING; - - /* s->s3->rrec.type - is the type of record - * s->s3->rrec.data, - data - * s->s3->rrec.off, - offset into 'data' for next read - * s->s3->rrec.length, - number of bytes. */ - rr = &(s->s3->rrec); - - /* We are not handshaking and have no data yet, - * so process data buffered during the last handshake - * in advance, if any. - */ - if (s->state == SSL_ST_OK && rr->length == 0) - { - pitem *item; - item = pqueue_pop(s->d1->buffered_app_data.q); - if (item) - { - dtls1_copy_record(s, item); - - OPENSSL_free(item->data); - pitem_free(item); - } - } - - /* Check for timeout */ - if (dtls1_handle_timeout(s) > 0) - goto start; - - /* get new packet if necessary */ - if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) - { - ret=dtls1_get_record(s); - if (ret <= 0) - { - ret = dtls1_read_failed(s, ret); - /* anything other than a timeout is an error */ - if (ret <= 0) - return(ret); - else - goto start; - } - } - - /* we now have a packet which can be read and processed */ - - if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, - * reset by ssl3_get_finished */ - && (rr->type != SSL3_RT_HANDSHAKE)) - { - /* We now have application data between CCS and Finished. - * Most likely the packets were reordered on their way, so - * buffer the application data for later processing rather - * than dropping the connection. - */ - dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num); - rr->length = 0; - goto start; - } - - /* If the other end has shut down, throw anything we read away - * (even in 'peek' mode) */ - if (s->shutdown & SSL_RECEIVED_SHUTDOWN) - { - rr->length=0; - s->rwstate=SSL_NOTHING; - return(0); - } - - - if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */ - { - /* make sure that we are not getting application data when we - * are doing a handshake for the first time */ - if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && - (s->enc_read_ctx == NULL)) - { - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE); - goto f_err; - } - - if (len <= 0) return(len); - - if ((unsigned int)len > rr->length) - n = rr->length; - else - n = (unsigned int)len; - - memcpy(buf,&(rr->data[rr->off]),n); - if (!peek) - { - rr->length-=n; - rr->off+=n; - if (rr->length == 0) - { - s->rstate=SSL_ST_READ_HEADER; - rr->off=0; - } - } - return(n); - } - - - /* If we get here, then type != rr->type; if we have a handshake - * message, then it was unexpected (Hello Request or Client Hello). */ - - /* In case of record types for which we have 'fragment' storage, - * fill that so that we can process the data at a fixed place. - */ - { - unsigned int k, dest_maxlen = 0; - unsigned char *dest = NULL; - unsigned int *dest_len = NULL; - - if (rr->type == SSL3_RT_HANDSHAKE) - { - dest_maxlen = sizeof s->d1->handshake_fragment; - dest = s->d1->handshake_fragment; - dest_len = &s->d1->handshake_fragment_len; - } - else if (rr->type == SSL3_RT_ALERT) - { - dest_maxlen = sizeof(s->d1->alert_fragment); - dest = s->d1->alert_fragment; - dest_len = &s->d1->alert_fragment_len; - } - /* else it's a CCS message, or application data or wrong */ - else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) - { - /* Application data while renegotiating - * is allowed. Try again reading. - */ - if (rr->type == SSL3_RT_APPLICATION_DATA) - { - BIO *bio; - s->s3->in_read_app_data=2; - bio=SSL_get_rbio(s); - s->rwstate=SSL_READING; - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - - /* Not certain if this is the right error handling */ - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - - if (dest_maxlen > 0) - { - /* XDTLS: In a pathalogical case, the Client Hello - * may be fragmented--don't always expect dest_maxlen bytes */ - if ( rr->length < dest_maxlen) - { -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - /* - * for normal alerts rr->length is 2, while - * dest_maxlen is 7 if we were to handle this - * non-existing alert... - */ - FIX ME -#endif - s->rstate=SSL_ST_READ_HEADER; - rr->length = 0; - goto start; - } - - /* now move 'n' bytes: */ - for ( k = 0; k < dest_maxlen; k++) - { - dest[k] = rr->data[rr->off++]; - rr->length--; - } - *dest_len = dest_maxlen; - } - } - - /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; - * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT. - * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ - - /* If we are a client, check for an incoming 'Hello Request': */ - if ((!s->server) && - (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && - (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && - (s->session != NULL) && (s->session->cipher != NULL)) - { - s->d1->handshake_fragment_len = 0; - - if ((s->d1->handshake_fragment[1] != 0) || - (s->d1->handshake_fragment[2] != 0) || - (s->d1->handshake_fragment[3] != 0)) - { - al=SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_HELLO_REQUEST); - goto err; - } - - /* no need to check sequence number on HELLO REQUEST messages */ - - if (s->msg_callback) - s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, - s->d1->handshake_fragment, 4, s, s->msg_callback_arg); - - if (SSL_is_init_finished(s) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && - !s->s3->renegotiate) - { - ssl3_renegotiate(s); - if (ssl3_renegotiate_check(s)) - { - i=s->handshake_func(s); - if (i < 0) return(i); - if (i == 0) - { - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); - return(-1); - } - - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } - } - } - /* we either finished a handshake or ignored the request, - * now try again to obtain the (application) data we were asked for */ - goto start; - } - - if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) - { - int alert_level = s->d1->alert_fragment[0]; - int alert_descr = s->d1->alert_fragment[1]; - - s->d1->alert_fragment_len = 0; - - if (s->msg_callback) - s->msg_callback(0, s->version, SSL3_RT_ALERT, - s->d1->alert_fragment, 2, s, s->msg_callback_arg); - - if (s->info_callback != NULL) - cb=s->info_callback; - else if (s->ctx->info_callback != NULL) - cb=s->ctx->info_callback; - - if (cb != NULL) - { - j = (alert_level << 8) | alert_descr; - cb(s, SSL_CB_READ_ALERT, j); - } - - if (alert_level == 1) /* warning */ - { - s->s3->warn_alert = alert_descr; - if (alert_descr == SSL_AD_CLOSE_NOTIFY) - { - s->shutdown |= SSL_RECEIVED_SHUTDOWN; - return(0); - } -#if 0 - /* XXX: this is a possible improvement in the future */ - /* now check if it's a missing record */ - if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) - { - unsigned short seq; - unsigned int frag_off; - unsigned char *p = &(s->d1->alert_fragment[2]); - - n2s(p, seq); - n2l3(p, frag_off); - - dtls1_retransmit_message(s, - dtls1_get_queue_priority(frag->msg_header.seq, 0), - frag_off, &found); - if ( ! found && SSL_in_init(s)) - { - /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */ - /* requested a message not yet sent, - send an alert ourselves */ - ssl3_send_alert(s,SSL3_AL_WARNING, - DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); - } - } -#endif - } - else if (alert_level == 2) /* fatal */ - { - char tmp[16]; - - s->rwstate=SSL_NOTHING; - s->s3->fatal_alert = alert_descr; - SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); - BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr); - ERR_add_error_data(2,"SSL alert number ",tmp); - s->shutdown|=SSL_RECEIVED_SHUTDOWN; - SSL_CTX_remove_session(s->ctx,s->session); - return(0); - } - else - { - al=SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE); - goto f_err; - } - - goto start; - } - - if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */ - { - s->rwstate=SSL_NOTHING; - rr->length=0; - return(0); - } - - if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) - { - struct ccs_header_st ccs_hdr; - unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH; - - dtls1_get_ccs_header(rr->data, &ccs_hdr); - - if (s->version == DTLS1_BAD_VER) - ccs_hdr_len = 3; - - /* 'Change Cipher Spec' is just a single byte, so we know - * exactly what the record payload has to look like */ - /* XDTLS: check that epoch is consistent */ - if ( (rr->length != ccs_hdr_len) || - (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS)) - { - i=SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC); - goto err; - } - - rr->length=0; - - if (s->msg_callback) - s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, - rr->data, 1, s, s->msg_callback_arg); - - /* We can't process a CCS now, because previous handshake - * messages are still missing, so just drop it. - */ - if (!s->d1->change_cipher_spec_ok) - { - goto start; - } - - s->d1->change_cipher_spec_ok = 0; - - s->s3->change_cipher_spec=1; - if (!ssl3_do_change_cipher_spec(s)) - goto err; - - /* do this whenever CCS is processed */ - dtls1_reset_seq_numbers(s, SSL3_CC_READ); - - if (s->version == DTLS1_BAD_VER) - s->d1->handshake_read_seq++; - - goto start; - } - - /* Unexpected handshake message (Client Hello, or protocol violation) */ - if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && - !s->in_handshake) - { - struct hm_header_st msg_hdr; - - /* this may just be a stale retransmit */ - dtls1_get_message_header(rr->data, &msg_hdr); - if( rr->epoch != s->d1->r_epoch) - { - rr->length = 0; - goto start; - } - - /* If we are server, we may have a repeated FINISHED of the - * client here, then retransmit our CCS and FINISHED. - */ - if (msg_hdr.type == SSL3_MT_FINISHED) - { - dtls1_retransmit_buffered_messages(s); - rr->length = 0; - goto start; - } - - if (((s->state&SSL_ST_MASK) == SSL_ST_OK) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) - { -#if 0 /* worked only because C operator preferences are not as expected (and - * because this is not really needed for clients except for detecting - * protocol violations): */ - s->state=SSL_ST_BEFORE|(s->server) - ?SSL_ST_ACCEPT - :SSL_ST_CONNECT; -#else - s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; -#endif - s->new_session=1; - } - i=s->handshake_func(s); - if (i < 0) return(i); - if (i == 0) - { - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); - return(-1); - } - - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } - goto start; - } - - switch (rr->type) - { - default: -#ifndef OPENSSL_NO_TLS - /* TLS just ignores unknown message types */ - if (s->version == TLS1_VERSION) - { - rr->length = 0; - goto start; - } -#endif - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD); - goto f_err; - case SSL3_RT_CHANGE_CIPHER_SPEC: - case SSL3_RT_ALERT: - case SSL3_RT_HANDSHAKE: - /* we already handled all of these, with the possible exception - * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that - * should not happen when type != rr->type */ - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,ERR_R_INTERNAL_ERROR); - goto f_err; - case SSL3_RT_APPLICATION_DATA: - /* At this point, we were expecting handshake data, - * but have application data. If the library was - * running inside ssl3_read() (i.e. in_read_app_data - * is set) and it makes sense to read application data - * at this point (session renegotiation not yet started), - * we will indulge it. - */ - if (s->s3->in_read_app_data && - (s->s3->total_renegotiations != 0) && - (( - (s->state & SSL_ST_CONNECT) && - (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && - (s->state <= SSL3_ST_CR_SRVR_HELLO_A) - ) || ( - (s->state & SSL_ST_ACCEPT) && - (s->state <= SSL3_ST_SW_HELLO_REQ_A) && - (s->state >= SSL3_ST_SR_CLNT_HELLO_A) - ) - )) - { - s->s3->in_read_app_data=2; - return(-1); - } - else - { - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - } - /* not reached */ - -f_err: - ssl3_send_alert(s,SSL3_AL_FATAL,al); -err: - return(-1); - } - -int -dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) - { - 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_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } - - if (len > SSL3_RT_MAX_PLAIN_LENGTH) - { - SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_DTLS_MESSAGE_TOO_BIG); - return -1; - } - - i = dtls1_write_bytes(s, type, buf_, len); - return i; - } - - - /* this only happens when a client hello is received and a handshake - * is started. */ -static int -have_handshake_fragment(SSL *s, int type, unsigned char *buf, - int len, int peek) - { - - if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0)) - /* (partially) satisfy request from storage */ - { - unsigned char *src = s->d1->handshake_fragment; - unsigned char *dst = buf; - unsigned int k,n; - - /* peek == 0 */ - n = 0; - while ((len > 0) && (s->d1->handshake_fragment_len > 0)) - { - *dst++ = *src++; - len--; s->d1->handshake_fragment_len--; - n++; - } - /* move any remaining fragment bytes: */ - for (k = 0; k < s->d1->handshake_fragment_len; k++) - s->d1->handshake_fragment[k] = *src++; - return n; - } - - return 0; - } - - - - -/* Call this to write data in records of type 'type' - * It will return <= 0 if not all data has been sent or non-blocking IO. - */ -int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) - { - int i; - - OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); - s->rwstate=SSL_NOTHING; - i=do_dtls1_write(s, type, buf, len, 0); - return i; - } - -int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment) - { - unsigned char *p,*pseq; - int i,mac_size,clear=0; - int prefix_len = 0; - SSL3_RECORD *wr; - SSL3_BUFFER *wb; - SSL_SESSION *sess; - int bs; - - /* first check if there is a SSL3_BUFFER still being written - * out. This will happen with non blocking IO */ - if (s->s3->wbuf.left != 0) - { - OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */ - return(ssl3_write_pending(s,type,buf,len)); - } - - /* If we have an alert to send, lets send it */ - if (s->s3->alert_dispatch) - { - i=s->method->ssl_dispatch_alert(s); - if (i <= 0) - return(i); - /* if it went, fall through and send more stuff */ - } - - if (len == 0 && !create_empty_fragment) - return 0; - - wr= &(s->s3->wrec); - wb= &(s->s3->wbuf); - sess=s->session; - - if ( (sess == NULL) || - (s->enc_write_ctx == NULL) || - (EVP_MD_CTX_md(s->write_hash) == NULL)) - clear=1; - - if (clear) - mac_size=0; - else - { - mac_size=EVP_MD_CTX_size(s->write_hash); - if (mac_size < 0) - goto err; - } - - /* DTLS implements explicit IV, so no need for empty fragments */ -#if 0 - /* 'create_empty_fragment' is true only when this function calls itself */ - if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done - && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) - { - /* countermeasure against known-IV weakness in CBC ciphersuites - * (see http://www.openssl.org/~bodo/tls-cbc.txt) - */ - - if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) - { - /* recursive function call with 'create_empty_fragment' set; - * this prepares and buffers the data for an empty fragment - * (these 'prefix_len' bytes are sent out later - * together with the actual payload) */ - prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1); - if (prefix_len <= 0) - goto err; - - if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) - { - /* insufficient space */ - SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR); - goto err; - } - } - - s->s3->empty_fragment_done = 1; - } -#endif - p = wb->buf + prefix_len; - - /* write the header */ - - *(p++)=type&0xff; - wr->type=type; - - *(p++)=(s->version>>8); - *(p++)=s->version&0xff; - - /* field where we are to write out packet epoch, seq num and len */ - pseq=p; - p+=10; - - /* lets setup the record stuff. */ - - /* Make space for the explicit IV in case of CBC. - * (this is a bit of a boundary violation, but what the heck). - */ - if ( s->enc_write_ctx && - (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE)) - bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher); - else - bs = 0; - - wr->data=p + bs; /* make room for IV in case of CBC */ - wr->length=(int)len; - wr->input=(unsigned char *)buf; - - /* we now 'read' from wr->input, wr->length bytes into - * wr->data */ - - /* first we compress */ - if (s->compress != NULL) - { - if (!ssl3_do_compress(s)) - { - SSLerr(SSL_F_DO_DTLS1_WRITE,SSL_R_COMPRESSION_FAILURE); - goto err; - } - } - else - { - memcpy(wr->data,wr->input,wr->length); - wr->input=wr->data; - } - - /* we should still have the output to wr->data and the input - * from wr->input. Length should be wr->length. - * wr->data still points in the wb->buf */ - - if (mac_size != 0) - { - if(s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1) < 0) - goto err; - wr->length+=mac_size; - } - - /* this is true regardless of mac size */ - wr->input=p; - wr->data=p; - - - /* ssl3_enc can only have an error on read */ - if (bs) /* bs != 0 in case of CBC */ - { - RAND_pseudo_bytes(p,bs); - /* master IV and last CBC residue stand for - * the rest of randomness */ - wr->length += bs; - } - - s->method->ssl3_enc->enc(s,1); - - /* record length after mac and block padding */ -/* if (type == SSL3_RT_APPLICATION_DATA || - (type == SSL3_RT_ALERT && ! SSL_in_init(s))) */ - - /* there's only one epoch between handshake and app data */ - - s2n(s->d1->w_epoch, pseq); - - /* XDTLS: ?? */ -/* else - s2n(s->d1->handshake_epoch, pseq); */ - - memcpy(pseq, &(s->s3->write_sequence[2]), 6); - pseq+=6; - s2n(wr->length,pseq); - - /* we should now have - * wr->data pointing to the encrypted data, which is - * wr->length long */ - wr->type=type; /* not needed but helps for debugging */ - wr->length+=DTLS1_RT_HEADER_LENGTH; - -#if 0 /* this is now done at the message layer */ - /* buffer the record, making it easy to handle retransmits */ - if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC) - dtls1_buffer_record(s, wr->data, wr->length, - *((PQ_64BIT *)&(s->s3->write_sequence[0]))); -#endif - - ssl3_record_sequence_update(&(s->s3->write_sequence[0])); - - if (create_empty_fragment) - { - /* we are in a recursive call; - * just return the length, don't write out anything here - */ - return wr->length; - } - - /* now let's set up wb */ - wb->left = prefix_len + wr->length; - wb->offset = 0; - - /* memorize arguments so that ssl3_write_pending can detect bad write retries later */ - s->s3->wpend_tot=len; - s->s3->wpend_buf=buf; - s->s3->wpend_type=type; - s->s3->wpend_ret=len; - - /* we now just need to write the buffer */ - return ssl3_write_pending(s,type,buf,len); -err: - return -1; - } - - - -static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) - { - int cmp; - unsigned int shift; - const unsigned char *seq = s->s3->read_sequence; - - cmp = satsub64be(seq,bitmap->max_seq_num); - if (cmp > 0) - { - memcpy (s->s3->rrec.seq_num,seq,8); - return 1; /* this record in new */ - } - shift = -cmp; - if (shift >= sizeof(bitmap->map)*8) - return 0; /* stale, outside the window */ - else if (bitmap->map & (1UL<<shift)) - return 0; /* record previously received */ - - memcpy (s->s3->rrec.seq_num,seq,8); - return 1; - } - - -static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap) - { - int cmp; - unsigned int shift; - const unsigned char *seq = s->s3->read_sequence; - - cmp = satsub64be(seq,bitmap->max_seq_num); - if (cmp > 0) - { - shift = cmp; - if (shift < sizeof(bitmap->map)*8) - bitmap->map <<= shift, bitmap->map |= 1UL; - else - bitmap->map = 1UL; - memcpy(bitmap->max_seq_num,seq,8); - } - else { - shift = -cmp; - if (shift < sizeof(bitmap->map)*8) - bitmap->map |= 1UL<<shift; - } - } - - -int dtls1_dispatch_alert(SSL *s) - { - int i,j; - void (*cb)(const SSL *ssl,int type,int val)=NULL; - unsigned char buf[DTLS1_AL_HEADER_LENGTH]; - unsigned char *ptr = &buf[0]; - - s->s3->alert_dispatch=0; - - memset(buf, 0x00, sizeof(buf)); - *ptr++ = s->s3->send_alert[0]; - *ptr++ = s->s3->send_alert[1]; - -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) - { - s2n(s->d1->handshake_read_seq, ptr); -#if 0 - if ( s->d1->r_msg_hdr.frag_off == 0) /* waiting for a new msg */ - - else - s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */ -#endif - -#if 0 - fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq); -#endif - l2n3(s->d1->r_msg_hdr.frag_off, ptr); - } -#endif - - i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0); - if (i <= 0) - { - s->s3->alert_dispatch=1; - /* fprintf( stderr, "not done with alert\n" ); */ - } - else - { - if (s->s3->send_alert[0] == SSL3_AL_FATAL -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE -#endif - ) - (void)BIO_flush(s->wbio); - - if (s->msg_callback) - s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, - 2, s, s->msg_callback_arg); - - if (s->info_callback != NULL) - cb=s->info_callback; - else if (s->ctx->info_callback != NULL) - cb=s->ctx->info_callback; - - if (cb != NULL) - { - j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1]; - cb(s,SSL_CB_WRITE_ALERT,j); - } - } - return(i); - } - - -static DTLS1_BITMAP * -dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch) - { - - *is_next_epoch = 0; - - /* In current epoch, accept HM, CCS, DATA, & ALERT */ - if (rr->epoch == s->d1->r_epoch) - return &s->d1->bitmap; - - /* Only HM and ALERT messages can be from the next epoch */ - else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) && - (rr->type == SSL3_RT_HANDSHAKE || - rr->type == SSL3_RT_ALERT)) - { - *is_next_epoch = 1; - return &s->d1->next_bitmap; - } - - return NULL; - } - -#if 0 -static int -dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority, - unsigned long *offset) - { - - /* alerts are passed up immediately */ - if ( rr->type == SSL3_RT_APPLICATION_DATA || - rr->type == SSL3_RT_ALERT) - return 0; - - /* Only need to buffer if a handshake is underway. - * (this implies that Hello Request and Client Hello are passed up - * immediately) */ - if ( SSL_in_init(s)) - { - unsigned char *data = rr->data; - /* need to extract the HM/CCS sequence number here */ - if ( rr->type == SSL3_RT_HANDSHAKE || - rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) - { - unsigned short seq_num; - struct hm_header_st msg_hdr; - struct ccs_header_st ccs_hdr; - - if ( rr->type == SSL3_RT_HANDSHAKE) - { - dtls1_get_message_header(data, &msg_hdr); - seq_num = msg_hdr.seq; - *offset = msg_hdr.frag_off; - } - else - { - dtls1_get_ccs_header(data, &ccs_hdr); - seq_num = ccs_hdr.seq; - *offset = 0; - } - - /* this is either a record we're waiting for, or a - * retransmit of something we happened to previously - * receive (higher layers will drop the repeat silently */ - if ( seq_num < s->d1->handshake_read_seq) - return 0; - if (rr->type == SSL3_RT_HANDSHAKE && - seq_num == s->d1->handshake_read_seq && - msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off) - return 0; - else if ( seq_num == s->d1->handshake_read_seq && - (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC || - msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off)) - return 0; - else - { - *priority = seq_num; - return 1; - } - } - else /* unknown record type */ - return 0; - } - - return 0; - } -#endif - -void -dtls1_reset_seq_numbers(SSL *s, int rw) - { - unsigned char *seq; - unsigned int seq_bytes = sizeof(s->s3->read_sequence); - - if ( rw & SSL3_CC_READ) - { - seq = s->s3->read_sequence; - s->d1->r_epoch++; - memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP)); - memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP)); - } - else - { - seq = s->s3->write_sequence; - memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence)); - s->d1->w_epoch++; - } - - memset(seq, 0x00, seq_bytes); - } - - -static void -dtls1_clear_timeouts(SSL *s) - { - memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st)); - } +/* ssl/d1_pkt.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* 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.]
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "ssl_locl.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+#include <openssl/rand.h>
+
+/* mod 128 saturating subtract of two 64-bit values in big-endian order */
+static int satsub64be(const unsigned char *v1,const unsigned char *v2)
+{ int ret,sat,brw,i;
+
+ if (sizeof(long) == 8) do
+ { const union { long one; char little; } is_endian = {1};
+ long l;
+
+ if (is_endian.little) break;
+ /* not reached on little-endians */
+ /* following test is redundant, because input is
+ * always aligned, but I take no chances... */
+ if (((size_t)v1|(size_t)v2)&0x7) break;
+
+ l = *((long *)v1);
+ l -= *((long *)v2);
+ if (l>128) return 128;
+ else if (l<-128) return -128;
+ else return (int)l;
+ } while (0);
+
+ ret = (int)v1[7]-(int)v2[7];
+ sat = 0;
+ brw = ret>>8; /* brw is either 0 or -1 */
+ if (ret & 0x80)
+ { for (i=6;i>=0;i--)
+ { brw += (int)v1[i]-(int)v2[i];
+ sat |= ~brw;
+ brw >>= 8;
+ }
+ }
+ else
+ { for (i=6;i>=0;i--)
+ { brw += (int)v1[i]-(int)v2[i];
+ sat |= brw;
+ brw >>= 8;
+ }
+ }
+ brw <<= 8; /* brw is either 0 or -256 */
+
+ if (sat&0xff) return brw | 0x80;
+ else return brw + (ret&0xFF);
+}
+
+static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
+ int len, int peek);
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
+ unsigned int *is_next_epoch);
+#if 0
+static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
+ unsigned short *priority, unsigned long *offset);
+#endif
+static int dtls1_buffer_record(SSL *s, record_pqueue *q,
+ unsigned char *priority);
+static int dtls1_process_record(SSL *s);
+static void dtls1_clear_timeouts(SSL *s);
+
+/* copy buffered record into SSL structure */
+static int
+dtls1_copy_record(SSL *s, pitem *item)
+ {
+ DTLS1_RECORD_DATA *rdata;
+
+ rdata = (DTLS1_RECORD_DATA *)item->data;
+
+ if (s->s3->rbuf.buf != NULL)
+ OPENSSL_free(s->s3->rbuf.buf);
+
+ s->packet = rdata->packet;
+ s->packet_length = rdata->packet_length;
+ memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+
+ /* Set proper sequence number for mac calculation */
+ memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
+
+ return(1);
+ }
+
+
+static int
+dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
+ {
+ DTLS1_RECORD_DATA *rdata;
+ pitem *item;
+
+ /* Limit the size of the queue to prevent DOS attacks */
+ if (pqueue_size(queue->q) >= 100)
+ return 0;
+
+ rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
+ item = pitem_new(priority, rdata);
+ if (rdata == NULL || item == NULL)
+ {
+ if (rdata != NULL) OPENSSL_free(rdata);
+ if (item != NULL) pitem_free(item);
+
+ SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+ return(0);
+ }
+
+ rdata->packet = s->packet;
+ rdata->packet_length = s->packet_length;
+ memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
+
+ item->data = rdata;
+
+ /* insert should not fail, since duplicates are dropped */
+ if (pqueue_insert(queue->q, item) == NULL)
+ {
+ OPENSSL_free(rdata);
+ pitem_free(item);
+ return(0);
+ }
+
+ s->packet = NULL;
+ s->packet_length = 0;
+ memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
+ memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
+
+ if (!ssl3_setup_buffers(s))
+ {
+ SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(rdata);
+ pitem_free(item);
+ return(0);
+ }
+
+ return(1);
+ }
+
+
+static int
+dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
+ {
+ pitem *item;
+
+ item = pqueue_pop(queue->q);
+ if (item)
+ {
+ dtls1_copy_record(s, item);
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+
+ return(1);
+ }
+
+ return(0);
+ }
+
+
+/* retrieve a buffered record that belongs to the new epoch, i.e., not processed
+ * yet */
+#define dtls1_get_unprocessed_record(s) \
+ dtls1_retrieve_buffered_record((s), \
+ &((s)->d1->unprocessed_rcds))
+
+/* retrieve a buffered record that belongs to the current epoch, ie, processed */
+#define dtls1_get_processed_record(s) \
+ dtls1_retrieve_buffered_record((s), \
+ &((s)->d1->processed_rcds))
+
+static int
+dtls1_process_buffered_records(SSL *s)
+ {
+ pitem *item;
+
+ item = pqueue_peek(s->d1->unprocessed_rcds.q);
+ if (item)
+ {
+ /* Check if epoch is current. */
+ if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
+ return(1); /* Nothing to do. */
+
+ /* Process all the records. */
+ while (pqueue_peek(s->d1->unprocessed_rcds.q))
+ {
+ dtls1_get_unprocessed_record(s);
+ if ( ! dtls1_process_record(s))
+ return(0);
+ dtls1_buffer_record(s, &(s->d1->processed_rcds),
+ s->s3->rrec.seq_num);
+ }
+ }
+
+ /* sync epoch numbers once all the unprocessed records
+ * have been processed */
+ s->d1->processed_rcds.epoch = s->d1->r_epoch;
+ s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
+
+ return(1);
+ }
+
+
+#if 0
+
+static int
+dtls1_get_buffered_record(SSL *s)
+ {
+ pitem *item;
+ PQ_64BIT priority =
+ (((PQ_64BIT)s->d1->handshake_read_seq) << 32) |
+ ((PQ_64BIT)s->d1->r_msg_hdr.frag_off);
+
+ if ( ! SSL_in_init(s)) /* if we're not (re)negotiating,
+ nothing buffered */
+ return 0;
+
+
+ item = pqueue_peek(s->d1->rcvd_records);
+ if (item && item->priority == priority)
+ {
+ /* Check if we've received the record of interest. It must be
+ * a handshake record, since data records as passed up without
+ * buffering */
+ DTLS1_RECORD_DATA *rdata;
+ item = pqueue_pop(s->d1->rcvd_records);
+ rdata = (DTLS1_RECORD_DATA *)item->data;
+
+ if (s->s3->rbuf.buf != NULL)
+ OPENSSL_free(s->s3->rbuf.buf);
+
+ s->packet = rdata->packet;
+ s->packet_length = rdata->packet_length;
+ memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+ memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+
+ /* s->d1->next_expected_seq_num++; */
+ return(1);
+ }
+
+ return 0;
+ }
+
+#endif
+
+static int
+dtls1_process_record(SSL *s)
+{
+ int i,al;
+ int clear=0;
+ int enc_err;
+ SSL_SESSION *sess;
+ SSL3_RECORD *rr;
+ unsigned int mac_size;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+
+ rr= &(s->s3->rrec);
+ sess = s->session;
+
+ /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+ * and we have that many bytes in s->packet
+ */
+ rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
+
+ /* ok, we can now read from 's->packet' data into 'rr'
+ * rr->input points at rr->length bytes, which
+ * need to be copied into rr->data by either
+ * the decryption or by the decompression
+ * When the data is 'copied' into the rr->data buffer,
+ * rr->input will be pointed at the new buffer */
+
+ /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+ * rr->length bytes of encrypted compressed stuff. */
+
+ /* check is not needed I believe */
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ /* decrypt in place in 'rr->input' */
+ rr->data=rr->input;
+
+ enc_err = s->method->ssl3_enc->enc(s,0);
+ if (enc_err <= 0)
+ {
+ if (enc_err == 0)
+ /* SSLerr() and ssl3_send_alert() have been called */
+ goto err;
+
+ /* otherwise enc_err == -1 */
+ al=SSL_AD_BAD_RECORD_MAC;
+ goto f_err;
+ }
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+ /* r->length is now the compressed data plus mac */
+ if ( (sess == NULL) ||
+ (s->enc_read_ctx == NULL) ||
+ (s->read_hash == NULL))
+ clear=1;
+
+ if (!clear)
+ {
+ /* !clear => s->read_hash != NULL => mac_size != -1 */
+ int t;
+ t=EVP_MD_CTX_size(s->read_hash);
+ OPENSSL_assert(t >= 0);
+ mac_size=t;
+
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
+ {
+#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
+ goto f_err;
+#else
+ goto err;
+#endif
+ }
+ /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
+ if (rr->length < mac_size)
+ {
+#if 0 /* OK only for stream ciphers */
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
+ goto f_err;
+#else
+ goto err;
+#endif
+ }
+ rr->length-=mac_size;
+ i=s->method->ssl3_enc->mac(s,md,0);
+ if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+ {
+ goto err;
+ }
+ }
+
+ /* r->length is now just compressed */
+ if (s->expand != NULL)
+ {
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+ if (!ssl3_do_uncompress(s))
+ {
+ al=SSL_AD_DECOMPRESSION_FAILURE;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_BAD_DECOMPRESSION);
+ goto f_err;
+ }
+ }
+
+ if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH)
+ {
+ al=SSL_AD_RECORD_OVERFLOW;
+ SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ rr->off=0;
+ /* So at this point the following is true
+ * ssl->s3->rrec.type is the type of record
+ * ssl->s3->rrec.length == number of bytes in record
+ * ssl->s3->rrec.off == offset to first valid byte
+ * ssl->s3->rrec.data == where to take bytes from, increment
+ * after use :-).
+ */
+
+ /* we have pulled in a full packet so zero things */
+ s->packet_length=0;
+ dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
+ return(1);
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(0);
+}
+
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type - is the type of record
+ * ssl->s3->rrec.data, - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by dtls1_read_bytes */
+int dtls1_get_record(SSL *s)
+ {
+ int ssl_major,ssl_minor;
+ int i,n;
+ SSL3_RECORD *rr;
+ unsigned char *p = NULL;
+ unsigned short version;
+ DTLS1_BITMAP *bitmap;
+ unsigned int is_next_epoch;
+
+ rr= &(s->s3->rrec);
+
+ /* The epoch may have changed. If so, process all the
+ * pending records. This is a non-blocking operation. */
+ dtls1_process_buffered_records(s);
+
+ /* if we're renegotiating, then there may be buffered records */
+ if (dtls1_get_processed_record(s))
+ return 1;
+
+ /* get something from the wire */
+again:
+ /* check if we have the header */
+ if ( (s->rstate != SSL_ST_READ_BODY) ||
+ (s->packet_length < DTLS1_RT_HEADER_LENGTH))
+ {
+ n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+ /* read timeout is handled by dtls1_read_bytes */
+ if (n <= 0) return(n); /* error or non-blocking */
+
+ /* this packet contained a partial record, dump it */
+ if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
+ {
+ s->packet_length = 0;
+ goto again;
+ }
+
+ s->rstate=SSL_ST_READ_BODY;
+
+ p=s->packet;
+
+ /* Pull apart the header into the DTLS1_RECORD */
+ rr->type= *(p++);
+ ssl_major= *(p++);
+ ssl_minor= *(p++);
+ version=(ssl_major<<8)|ssl_minor;
+
+ /* sequence number is 64 bits, with top 2 bytes = epoch */
+ n2s(p,rr->epoch);
+
+ memcpy(&(s->s3->read_sequence[2]), p, 6);
+ p+=6;
+
+ n2s(p,rr->length);
+
+ /* Lets check version */
+ if (!s->first_packet)
+ {
+ if (version != s->version)
+ {
+ /* unexpected version, silently discard */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+ }
+
+ if ((version & 0xff00) != (s->version & 0xff00))
+ {
+ /* wrong version, silently discard record */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+ {
+ /* record too long, silently discard it */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ /* now s->rstate == SSL_ST_READ_BODY */
+ }
+
+ /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+ if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
+ {
+ /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
+ i=rr->length;
+ n=ssl3_read_n(s,i,i,1);
+ if (n <= 0) return(n); /* error or non-blocking io */
+
+ /* this packet contained a partial record, dump it */
+ if ( n != i)
+ {
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ /* now n == rr->length,
+ * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
+ }
+ s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+ /* match epochs. NULL means the packet is dropped on the floor */
+ bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+ if ( bitmap == NULL)
+ {
+ rr->length = 0;
+ s->packet_length = 0; /* dump this record */
+ goto again; /* get another record */
+ }
+
+ /* Check whether this is a repeat, or aged record.
+ * Don't check if we're listening and this message is
+ * a ClientHello. They can look as if they're replayed,
+ * since they arrive from different connections and
+ * would be dropped unnecessarily.
+ */
+ if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+ *p == SSL3_MT_CLIENT_HELLO) &&
+ !dtls1_record_replay_check(s, bitmap))
+ {
+ rr->length = 0;
+ s->packet_length=0; /* dump this record */
+ goto again; /* get another record */
+ }
+
+ /* just read a 0 length packet */
+ if (rr->length == 0) goto again;
+
+ /* If this record is from the next epoch (either HM or ALERT),
+ * and a handshake is currently in progress, buffer it since it
+ * cannot be processed at this time. */
+ if (is_next_epoch)
+ {
+ if (SSL_in_init(s) || s->in_handshake)
+ {
+ dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+ }
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
+ }
+
+ if (!dtls1_process_record(s))
+ {
+ rr->length = 0;
+ s->packet_length = 0; /* dump this record */
+ goto again; /* get another record */
+ }
+
+ dtls1_clear_timeouts(s); /* done waiting */
+ return(1);
+
+ }
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ * - 0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ * Change cipher spec protocol
+ * just 1 byte needed, no need for keeping anything stored
+ * Alert protocol
+ * 2 bytes needed (AlertLevel, AlertDescription)
+ * Handshake protocol
+ * 4 bytes needed (HandshakeType, uint24 length) -- we just have
+ * to detect unexpected Client Hello and Hello Request messages
+ * here, anything else is handled by higher layers
+ * Application data protocol
+ * none of our business
+ */
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+ {
+ int al,i,j,ret;
+ unsigned int n;
+ SSL3_RECORD *rr;
+ void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+ if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+ if (!ssl3_setup_buffers(s))
+ return(-1);
+
+ /* XXX: check what the second '&& type' is about */
+ if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
+ (type != SSL3_RT_HANDSHAKE) && type) ||
+ (peek && (type != SSL3_RT_APPLICATION_DATA)))
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* check whether there's a handshake message (client hello?) waiting */
+ if ( (ret = have_handshake_fragment(s, type, buf, len, peek)))
+ return ret;
+
+ /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+ if (!s->in_handshake && SSL_in_init(s))
+ {
+ /* type == SSL3_RT_APPLICATION_DATA */
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+ }
+
+start:
+ s->rwstate=SSL_NOTHING;
+
+ /* s->s3->rrec.type - is the type of record
+ * s->s3->rrec.data, - data
+ * s->s3->rrec.off, - offset into 'data' for next read
+ * s->s3->rrec.length, - number of bytes. */
+ rr = &(s->s3->rrec);
+
+ /* We are not handshaking and have no data yet,
+ * so process data buffered during the last handshake
+ * in advance, if any.
+ */
+ if (s->state == SSL_ST_OK && rr->length == 0)
+ {
+ pitem *item;
+ item = pqueue_pop(s->d1->buffered_app_data.q);
+ if (item)
+ {
+ dtls1_copy_record(s, item);
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+ }
+
+ /* Check for timeout */
+ if (dtls1_handle_timeout(s) > 0)
+ goto start;
+
+ /* get new packet if necessary */
+ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+ {
+ ret=dtls1_get_record(s);
+ if (ret <= 0)
+ {
+ ret = dtls1_read_failed(s, ret);
+ /* anything other than a timeout is an error */
+ if (ret <= 0)
+ return(ret);
+ else
+ goto start;
+ }
+ }
+
+ /* we now have a packet which can be read and processed */
+
+ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+ * reset by ssl3_get_finished */
+ && (rr->type != SSL3_RT_HANDSHAKE))
+ {
+ /* We now have application data between CCS and Finished.
+ * Most likely the packets were reordered on their way, so
+ * buffer the application data for later processing rather
+ * than dropping the connection.
+ */
+ dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
+ rr->length = 0;
+ goto start;
+ }
+
+ /* If the other end has shut down, throw anything we read away
+ * (even in 'peek' mode) */
+ if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+ {
+ rr->length=0;
+ s->rwstate=SSL_NOTHING;
+ return(0);
+ }
+
+
+ if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+ {
+ /* make sure that we are not getting application data when we
+ * are doing a handshake for the first time */
+ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+ (s->enc_read_ctx == NULL))
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
+ goto f_err;
+ }
+
+ if (len <= 0) return(len);
+
+ if ((unsigned int)len > rr->length)
+ n = rr->length;
+ else
+ n = (unsigned int)len;
+
+ memcpy(buf,&(rr->data[rr->off]),n);
+ if (!peek)
+ {
+ rr->length-=n;
+ rr->off+=n;
+ if (rr->length == 0)
+ {
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->off=0;
+ }
+ }
+ return(n);
+ }
+
+
+ /* If we get here, then type != rr->type; if we have a handshake
+ * message, then it was unexpected (Hello Request or Client Hello). */
+
+ /* In case of record types for which we have 'fragment' storage,
+ * fill that so that we can process the data at a fixed place.
+ */
+ {
+ unsigned int k, dest_maxlen = 0;
+ unsigned char *dest = NULL;
+ unsigned int *dest_len = NULL;
+
+ if (rr->type == SSL3_RT_HANDSHAKE)
+ {
+ dest_maxlen = sizeof s->d1->handshake_fragment;
+ dest = s->d1->handshake_fragment;
+ dest_len = &s->d1->handshake_fragment_len;
+ }
+ else if (rr->type == SSL3_RT_ALERT)
+ {
+ dest_maxlen = sizeof(s->d1->alert_fragment);
+ dest = s->d1->alert_fragment;
+ dest_len = &s->d1->alert_fragment_len;
+ }
+ /* else it's a CCS message, or application data or wrong */
+ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ /* Application data while renegotiating
+ * is allowed. Try again reading.
+ */
+ if (rr->type == SSL3_RT_APPLICATION_DATA)
+ {
+ BIO *bio;
+ s->s3->in_read_app_data=2;
+ bio=SSL_get_rbio(s);
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+
+ /* Not certain if this is the right error handling */
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ }
+
+ if (dest_maxlen > 0)
+ {
+ /* XDTLS: In a pathalogical case, the Client Hello
+ * may be fragmented--don't always expect dest_maxlen bytes */
+ if ( rr->length < dest_maxlen)
+ {
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ /*
+ * for normal alerts rr->length is 2, while
+ * dest_maxlen is 7 if we were to handle this
+ * non-existing alert...
+ */
+ FIX ME
+#endif
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->length = 0;
+ goto start;
+ }
+
+ /* now move 'n' bytes: */
+ for ( k = 0; k < dest_maxlen; k++)
+ {
+ dest[k] = rr->data[rr->off++];
+ rr->length--;
+ }
+ *dest_len = dest_maxlen;
+ }
+ }
+
+ /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
+ * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
+ * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+ /* If we are a client, check for an incoming 'Hello Request': */
+ if ((!s->server) &&
+ (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+ (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+ (s->session != NULL) && (s->session->cipher != NULL))
+ {
+ s->d1->handshake_fragment_len = 0;
+
+ if ((s->d1->handshake_fragment[1] != 0) ||
+ (s->d1->handshake_fragment[2] != 0) ||
+ (s->d1->handshake_fragment[3] != 0))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
+ goto err;
+ }
+
+ /* no need to check sequence number on HELLO REQUEST messages */
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
+
+ if (SSL_is_init_finished(s) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+ !s->s3->renegotiate)
+ {
+ ssl3_renegotiate(s);
+ if (ssl3_renegotiate_check(s))
+ {
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ }
+ }
+ /* we either finished a handshake or ignored the request,
+ * now try again to obtain the (application) data we were asked for */
+ goto start;
+ }
+
+ if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH)
+ {
+ int alert_level = s->d1->alert_fragment[0];
+ int alert_descr = s->d1->alert_fragment[1];
+
+ s->d1->alert_fragment_len = 0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_ALERT,
+ s->d1->alert_fragment, 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j = (alert_level << 8) | alert_descr;
+ cb(s, SSL_CB_READ_ALERT, j);
+ }
+
+ if (alert_level == 1) /* warning */
+ {
+ s->s3->warn_alert = alert_descr;
+ if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+ {
+ s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ return(0);
+ }
+#if 0
+ /* XXX: this is a possible improvement in the future */
+ /* now check if it's a missing record */
+ if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+ {
+ unsigned short seq;
+ unsigned int frag_off;
+ unsigned char *p = &(s->d1->alert_fragment[2]);
+
+ n2s(p, seq);
+ n2l3(p, frag_off);
+
+ dtls1_retransmit_message(s,
+ dtls1_get_queue_priority(frag->msg_header.seq, 0),
+ frag_off, &found);
+ if ( ! found && SSL_in_init(s))
+ {
+ /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
+ /* requested a message not yet sent,
+ send an alert ourselves */
+ ssl3_send_alert(s,SSL3_AL_WARNING,
+ DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+ }
+ }
+#endif
+ }
+ else if (alert_level == 2) /* fatal */
+ {
+ char tmp[16];
+
+ s->rwstate=SSL_NOTHING;
+ s->s3->fatal_alert = alert_descr;
+ SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
+ BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+ ERR_add_error_data(2,"SSL alert number ",tmp);
+ s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+ SSL_CTX_remove_session(s->ctx,s->session);
+ return(0);
+ }
+ else
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
+ goto f_err;
+ }
+
+ goto start;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+ {
+ s->rwstate=SSL_NOTHING;
+ rr->length=0;
+ return(0);
+ }
+
+ if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ struct ccs_header_st ccs_hdr;
+ unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
+
+ dtls1_get_ccs_header(rr->data, &ccs_hdr);
+
+ if (s->version == DTLS1_BAD_VER)
+ ccs_hdr_len = 3;
+
+ /* 'Change Cipher Spec' is just a single byte, so we know
+ * exactly what the record payload has to look like */
+ /* XDTLS: check that epoch is consistent */
+ if ( (rr->length != ccs_hdr_len) ||
+ (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
+ {
+ i=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ goto err;
+ }
+
+ rr->length=0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+ rr->data, 1, s, s->msg_callback_arg);
+
+ /* We can't process a CCS now, because previous handshake
+ * messages are still missing, so just drop it.
+ */
+ if (!s->d1->change_cipher_spec_ok)
+ {
+ goto start;
+ }
+
+ s->d1->change_cipher_spec_ok = 0;
+
+ s->s3->change_cipher_spec=1;
+ if (!ssl3_do_change_cipher_spec(s))
+ goto err;
+
+ /* do this whenever CCS is processed */
+ dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+ if (s->version == DTLS1_BAD_VER)
+ s->d1->handshake_read_seq++;
+
+ goto start;
+ }
+
+ /* Unexpected handshake message (Client Hello, or protocol violation) */
+ if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+ !s->in_handshake)
+ {
+ struct hm_header_st msg_hdr;
+
+ /* this may just be a stale retransmit */
+ dtls1_get_message_header(rr->data, &msg_hdr);
+ if( rr->epoch != s->d1->r_epoch)
+ {
+ rr->length = 0;
+ goto start;
+ }
+
+ /* If we are server, we may have a repeated FINISHED of the
+ * client here, then retransmit our CCS and FINISHED.
+ */
+ if (msg_hdr.type == SSL3_MT_FINISHED)
+ {
+ dtls1_retransmit_buffered_messages(s);
+ rr->length = 0;
+ goto start;
+ }
+
+ if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+ !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+ {
+#if 0 /* worked only because C operator preferences are not as expected (and
+ * because this is not really needed for clients except for detecting
+ * protocol violations): */
+ s->state=SSL_ST_BEFORE|(s->server)
+ ?SSL_ST_ACCEPT
+ :SSL_ST_CONNECT;
+#else
+ s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+ s->new_session=1;
+ }
+ i=s->handshake_func(s);
+ if (i < 0) return(i);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return(-1);
+ }
+
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
+ {
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ }
+ goto start;
+ }
+
+ switch (rr->type)
+ {
+ default:
+#ifndef OPENSSL_NO_TLS
+ /* TLS just ignores unknown message types */
+ if (s->version == TLS1_VERSION)
+ {
+ rr->length = 0;
+ goto start;
+ }
+#endif
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ case SSL3_RT_ALERT:
+ case SSL3_RT_HANDSHAKE:
+ /* we already handled all of these, with the possible exception
+ * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
+ * should not happen when type != rr->type */
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ case SSL3_RT_APPLICATION_DATA:
+ /* At this point, we were expecting handshake data,
+ * but have application data. If the library was
+ * running inside ssl3_read() (i.e. in_read_app_data
+ * is set) and it makes sense to read application data
+ * at this point (session renegotiation not yet started),
+ * we will indulge it.
+ */
+ if (s->s3->in_read_app_data &&
+ (s->s3->total_renegotiations != 0) &&
+ ((
+ (s->state & SSL_ST_CONNECT) &&
+ (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
+ (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
+ ) || (
+ (s->state & SSL_ST_ACCEPT) &&
+ (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
+ (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
+ )
+ ))
+ {
+ s->s3->in_read_app_data=2;
+ return(-1);
+ }
+ else
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+ goto f_err;
+ }
+ }
+ /* not reached */
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int
+dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
+ {
+ 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_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH)
+ {
+ SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_DTLS_MESSAGE_TOO_BIG);
+ return -1;
+ }
+
+ i = dtls1_write_bytes(s, type, buf_, len);
+ return i;
+ }
+
+
+ /* this only happens when a client hello is received and a handshake
+ * is started. */
+static int
+have_handshake_fragment(SSL *s, int type, unsigned char *buf,
+ int len, int peek)
+ {
+
+ if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0))
+ /* (partially) satisfy request from storage */
+ {
+ unsigned char *src = s->d1->handshake_fragment;
+ unsigned char *dst = buf;
+ unsigned int k,n;
+
+ /* peek == 0 */
+ n = 0;
+ while ((len > 0) && (s->d1->handshake_fragment_len > 0))
+ {
+ *dst++ = *src++;
+ len--; s->d1->handshake_fragment_len--;
+ n++;
+ }
+ /* move any remaining fragment bytes: */
+ for (k = 0; k < s->d1->handshake_fragment_len; k++)
+ s->d1->handshake_fragment[k] = *src++;
+ return n;
+ }
+
+ return 0;
+ }
+
+
+
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len)
+ {
+ int i;
+
+ OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
+ s->rwstate=SSL_NOTHING;
+ i=do_dtls1_write(s, type, buf, len, 0);
+ return i;
+ }
+
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment)
+ {
+ unsigned char *p,*pseq;
+ int i,mac_size,clear=0;
+ int prefix_len = 0;
+ SSL3_RECORD *wr;
+ SSL3_BUFFER *wb;
+ SSL_SESSION *sess;
+ int bs;
+
+ /* first check if there is a SSL3_BUFFER still being written
+ * out. This will happen with non blocking IO */
+ if (s->s3->wbuf.left != 0)
+ {
+ OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */
+ return(ssl3_write_pending(s,type,buf,len));
+ }
+
+ /* If we have an alert to send, lets send it */
+ if (s->s3->alert_dispatch)
+ {
+ i=s->method->ssl_dispatch_alert(s);
+ if (i <= 0)
+ return(i);
+ /* if it went, fall through and send more stuff */
+ }
+
+ if (len == 0 && !create_empty_fragment)
+ return 0;
+
+ wr= &(s->s3->wrec);
+ wb= &(s->s3->wbuf);
+ sess=s->session;
+
+ if ( (sess == NULL) ||
+ (s->enc_write_ctx == NULL) ||
+ (EVP_MD_CTX_md(s->write_hash) == NULL))
+ clear=1;
+
+ if (clear)
+ mac_size=0;
+ else
+ {
+ mac_size=EVP_MD_CTX_size(s->write_hash);
+ if (mac_size < 0)
+ goto err;
+ }
+
+ /* DTLS implements explicit IV, so no need for empty fragments */
+#if 0
+ /* 'create_empty_fragment' is true only when this function calls itself */
+ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
+ && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
+ {
+ /* countermeasure against known-IV weakness in CBC ciphersuites
+ * (see http://www.openssl.org/~bodo/tls-cbc.txt)
+ */
+
+ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+ {
+ /* recursive function call with 'create_empty_fragment' set;
+ * this prepares and buffers the data for an empty fragment
+ * (these 'prefix_len' bytes are sent out later
+ * together with the actual payload) */
+ prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1);
+ if (prefix_len <= 0)
+ goto err;
+
+ if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ s->s3->empty_fragment_done = 1;
+ }
+#endif
+ p = wb->buf + prefix_len;
+
+ /* write the header */
+
+ *(p++)=type&0xff;
+ wr->type=type;
+
+ *(p++)=(s->version>>8);
+ *(p++)=s->version&0xff;
+
+ /* field where we are to write out packet epoch, seq num and len */
+ pseq=p;
+ p+=10;
+
+ /* lets setup the record stuff. */
+
+ /* Make space for the explicit IV in case of CBC.
+ * (this is a bit of a boundary violation, but what the heck).
+ */
+ if ( s->enc_write_ctx &&
+ (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE))
+ bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+ else
+ bs = 0;
+
+ wr->data=p + bs; /* make room for IV in case of CBC */
+ wr->length=(int)len;
+ wr->input=(unsigned char *)buf;
+
+ /* we now 'read' from wr->input, wr->length bytes into
+ * wr->data */
+
+ /* first we compress */
+ if (s->compress != NULL)
+ {
+ if (!ssl3_do_compress(s))
+ {
+ SSLerr(SSL_F_DO_DTLS1_WRITE,SSL_R_COMPRESSION_FAILURE);
+ goto err;
+ }
+ }
+ else
+ {
+ memcpy(wr->data,wr->input,wr->length);
+ wr->input=wr->data;
+ }
+
+ /* we should still have the output to wr->data and the input
+ * from wr->input. Length should be wr->length.
+ * wr->data still points in the wb->buf */
+
+ if (mac_size != 0)
+ {
+ if(s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1) < 0)
+ goto err;
+ wr->length+=mac_size;
+ }
+
+ /* this is true regardless of mac size */
+ wr->input=p;
+ wr->data=p;
+
+
+ /* ssl3_enc can only have an error on read */
+ if (bs) /* bs != 0 in case of CBC */
+ {
+ RAND_pseudo_bytes(p,bs);
+ /* master IV and last CBC residue stand for
+ * the rest of randomness */
+ wr->length += bs;
+ }
+
+ s->method->ssl3_enc->enc(s,1);
+
+ /* record length after mac and block padding */
+/* if (type == SSL3_RT_APPLICATION_DATA ||
+ (type == SSL3_RT_ALERT && ! SSL_in_init(s))) */
+
+ /* there's only one epoch between handshake and app data */
+
+ s2n(s->d1->w_epoch, pseq);
+
+ /* XDTLS: ?? */
+/* else
+ s2n(s->d1->handshake_epoch, pseq); */
+
+ memcpy(pseq, &(s->s3->write_sequence[2]), 6);
+ pseq+=6;
+ s2n(wr->length,pseq);
+
+ /* we should now have
+ * wr->data pointing to the encrypted data, which is
+ * wr->length long */
+ wr->type=type; /* not needed but helps for debugging */
+ wr->length+=DTLS1_RT_HEADER_LENGTH;
+
+#if 0 /* this is now done at the message layer */
+ /* buffer the record, making it easy to handle retransmits */
+ if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ dtls1_buffer_record(s, wr->data, wr->length,
+ *((PQ_64BIT *)&(s->s3->write_sequence[0])));
+#endif
+
+ ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
+
+ if (create_empty_fragment)
+ {
+ /* we are in a recursive call;
+ * just return the length, don't write out anything here
+ */
+ return wr->length;
+ }
+
+ /* now let's set up wb */
+ wb->left = prefix_len + wr->length;
+ wb->offset = 0;
+
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+ s->s3->wpend_tot=len;
+ s->s3->wpend_buf=buf;
+ s->s3->wpend_type=type;
+ s->s3->wpend_ret=len;
+
+ /* we now just need to write the buffer */
+ return ssl3_write_pending(s,type,buf,len);
+err:
+ return -1;
+ }
+
+
+
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
+ {
+ int cmp;
+ unsigned int shift;
+ const unsigned char *seq = s->s3->read_sequence;
+
+ cmp = satsub64be(seq,bitmap->max_seq_num);
+ if (cmp > 0)
+ {
+ memcpy (s->s3->rrec.seq_num,seq,8);
+ return 1; /* this record in new */
+ }
+ shift = -cmp;
+ if (shift >= sizeof(bitmap->map)*8)
+ return 0; /* stale, outside the window */
+ else if (bitmap->map & (1UL<<shift))
+ return 0; /* record previously received */
+
+ memcpy (s->s3->rrec.seq_num,seq,8);
+ return 1;
+ }
+
+
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
+ {
+ int cmp;
+ unsigned int shift;
+ const unsigned char *seq = s->s3->read_sequence;
+
+ cmp = satsub64be(seq,bitmap->max_seq_num);
+ if (cmp > 0)
+ {
+ shift = cmp;
+ if (shift < sizeof(bitmap->map)*8)
+ bitmap->map <<= shift, bitmap->map |= 1UL;
+ else
+ bitmap->map = 1UL;
+ memcpy(bitmap->max_seq_num,seq,8);
+ }
+ else {
+ shift = -cmp;
+ if (shift < sizeof(bitmap->map)*8)
+ bitmap->map |= 1UL<<shift;
+ }
+ }
+
+
+int dtls1_dispatch_alert(SSL *s)
+ {
+ int i,j;
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ unsigned char buf[DTLS1_AL_HEADER_LENGTH];
+ unsigned char *ptr = &buf[0];
+
+ s->s3->alert_dispatch=0;
+
+ memset(buf, 0x00, sizeof(buf));
+ *ptr++ = s->s3->send_alert[0];
+ *ptr++ = s->s3->send_alert[1];
+
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+ {
+ s2n(s->d1->handshake_read_seq, ptr);
+#if 0
+ if ( s->d1->r_msg_hdr.frag_off == 0) /* waiting for a new msg */
+
+ else
+ s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
+#endif
+
+#if 0
+ fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
+#endif
+ l2n3(s->d1->r_msg_hdr.frag_off, ptr);
+ }
+#endif
+
+ i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0);
+ if (i <= 0)
+ {
+ s->s3->alert_dispatch=1;
+ /* fprintf( stderr, "not done with alert\n" ); */
+ }
+ else
+ {
+ if (s->s3->send_alert[0] == SSL3_AL_FATAL
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+ || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+#endif
+ )
+ (void)BIO_flush(s->wbio);
+
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert,
+ 2, s, s->msg_callback_arg);
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ if (cb != NULL)
+ {
+ j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+ cb(s,SSL_CB_WRITE_ALERT,j);
+ }
+ }
+ return(i);
+ }
+
+
+static DTLS1_BITMAP *
+dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch)
+ {
+
+ *is_next_epoch = 0;
+
+ /* In current epoch, accept HM, CCS, DATA, & ALERT */
+ if (rr->epoch == s->d1->r_epoch)
+ return &s->d1->bitmap;
+
+ /* Only HM and ALERT messages can be from the next epoch */
+ else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
+ (rr->type == SSL3_RT_HANDSHAKE ||
+ rr->type == SSL3_RT_ALERT))
+ {
+ *is_next_epoch = 1;
+ return &s->d1->next_bitmap;
+ }
+
+ return NULL;
+ }
+
+#if 0
+static int
+dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority,
+ unsigned long *offset)
+ {
+
+ /* alerts are passed up immediately */
+ if ( rr->type == SSL3_RT_APPLICATION_DATA ||
+ rr->type == SSL3_RT_ALERT)
+ return 0;
+
+ /* Only need to buffer if a handshake is underway.
+ * (this implies that Hello Request and Client Hello are passed up
+ * immediately) */
+ if ( SSL_in_init(s))
+ {
+ unsigned char *data = rr->data;
+ /* need to extract the HM/CCS sequence number here */
+ if ( rr->type == SSL3_RT_HANDSHAKE ||
+ rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ unsigned short seq_num;
+ struct hm_header_st msg_hdr;
+ struct ccs_header_st ccs_hdr;
+
+ if ( rr->type == SSL3_RT_HANDSHAKE)
+ {
+ dtls1_get_message_header(data, &msg_hdr);
+ seq_num = msg_hdr.seq;
+ *offset = msg_hdr.frag_off;
+ }
+ else
+ {
+ dtls1_get_ccs_header(data, &ccs_hdr);
+ seq_num = ccs_hdr.seq;
+ *offset = 0;
+ }
+
+ /* this is either a record we're waiting for, or a
+ * retransmit of something we happened to previously
+ * receive (higher layers will drop the repeat silently */
+ if ( seq_num < s->d1->handshake_read_seq)
+ return 0;
+ if (rr->type == SSL3_RT_HANDSHAKE &&
+ seq_num == s->d1->handshake_read_seq &&
+ msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off)
+ return 0;
+ else if ( seq_num == s->d1->handshake_read_seq &&
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC ||
+ msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off))
+ return 0;
+ else
+ {
+ *priority = seq_num;
+ return 1;
+ }
+ }
+ else /* unknown record type */
+ return 0;
+ }
+
+ return 0;
+ }
+#endif
+
+void
+dtls1_reset_seq_numbers(SSL *s, int rw)
+ {
+ unsigned char *seq;
+ unsigned int seq_bytes = sizeof(s->s3->read_sequence);
+
+ if ( rw & SSL3_CC_READ)
+ {
+ seq = s->s3->read_sequence;
+ s->d1->r_epoch++;
+ memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
+ memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
+ }
+ else
+ {
+ seq = s->s3->write_sequence;
+ memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));
+ s->d1->w_epoch++;
+ }
+
+ memset(seq, 0x00, seq_bytes);
+ }
+
+
+static void
+dtls1_clear_timeouts(SSL *s)
+ {
+ memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st));
+ }
diff --git a/openssl/ssl/install.com b/openssl/ssl/install.com index 7f5606759..c79f76ef9 100644 --- a/openssl/ssl/install.com +++ b/openssl/ssl/install.com @@ -1,90 +1,90 @@ -$! INSTALL.COM -- Installs the files in a given directory tree -$! -$! Author: Richard Levitte <richard@levitte.org> -$! Time of creation: 22-MAY-1998 10:13 -$! -$! P1 root of the directory tree -$! -$ IF P1 .EQS. "" -$ THEN -$ WRITE SYS$OUTPUT "First argument missing." -$ WRITE SYS$OUTPUT - - "It should be the directory where you want things installed." -$ EXIT -$ ENDIF -$ -$ IF (F$GETSYI("CPU").LT.128) -$ THEN -$ ARCH := VAX -$ ELSE -$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE") -$ IF (ARCH .EQS. "") THEN ARCH = "UNK" -$ ENDIF -$ -$ ROOT = F$PARSE(P1,"[]A.;0",,,"SYNTAX_ONLY,NO_CONCEAL") - "A.;0" -$ ROOT_DEV = F$PARSE(ROOT,,,"DEVICE","SYNTAX_ONLY") -$ ROOT_DIR = F$PARSE(ROOT,,,"DIRECTORY","SYNTAX_ONLY") - - - "[000000." - "][" - "[" - "]" -$ ROOT = ROOT_DEV + "[" + ROOT_DIR -$ -$ DEFINE/NOLOG WRK_SSLROOT 'ROOT'.] /TRANS=CONC -$ DEFINE/NOLOG WRK_SSLXLIB WRK_SSLROOT:['ARCH'_LIB] -$ DEFINE/NOLOG WRK_SSLINCLUDE WRK_SSLROOT:[INCLUDE] -$ DEFINE/NOLOG WRK_SSLXEXE WRK_SSLROOT:['ARCH'_EXE] -$ -$ IF F$PARSE("WRK_SSLROOT:[000000]") .EQS. "" THEN - - CREATE/DIR/LOG WRK_SSLROOT:[000000] -$ IF F$PARSE("WRK_SSLXLIB:") .EQS. "" THEN - - CREATE/DIR/LOG WRK_SSLXLIB: -$ IF F$PARSE("WRK_SSLINCLUDE:") .EQS. "" THEN - - CREATE/DIR/LOG WRK_SSLINCLUDE: -$ IF F$PARSE("WRK_SSLXEXE:") .EQS. "" THEN - - CREATE/DIR/LOG WRK_SSLXEXE: -$ -$ EXHEADER := ssl.h,ssl2.h,ssl3.h,ssl23.h,tls1.h,dtls1.h,kssl.h -$ E_EXE := ssl_task -$ LIBS := LIBSSL -$ -$ XEXE_DIR := [-.'ARCH'.EXE.SSL] -$ -$ COPY 'EXHEADER' WRK_SSLINCLUDE:/LOG -$ SET FILE/PROT=WORLD:RE WRK_SSLINCLUDE:'EXHEADER' -$ -$ I = 0 -$ LOOP_EXE: -$ E = F$EDIT(F$ELEMENT(I, ",", E_EXE),"TRIM") -$ I = I + 1 -$ IF E .EQS. "," THEN GOTO LOOP_EXE_END -$ SET NOON -$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. "" -$ THEN -$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXEXE:'E'.EXE/log -$ SET FILE/PROT=W:RE WRK_SSLXEXE:'E'.EXE -$ ENDIF -$ SET ON -$ GOTO LOOP_EXE -$ LOOP_EXE_END: -$ -$ I = 0 -$ LOOP_LIB: -$ E = F$EDIT(F$ELEMENT(I, ",", LIBS),"TRIM") -$ I = I + 1 -$ IF E .EQS. "," THEN GOTO LOOP_LIB_END -$ SET NOON -$! Object library. -$ IF F$SEARCH(XEXE_DIR+E+".OLB") .NES. "" -$ THEN -$ COPY 'XEXE_DIR''E'.OLB WRK_SSLXLIB:'E'.OLB/log -$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.OLB -$ ENDIF -$! Shareable image. -$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. "" -$ THEN -$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXLIB:'E'.EXE/log -$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.EXE -$ ENDIF -$ SET ON -$ GOTO LOOP_LIB -$ LOOP_LIB_END: -$ -$ EXIT +$! INSTALL.COM -- Installs the files in a given directory tree
+$!
+$! Author: Richard Levitte <richard@levitte.org>
+$! Time of creation: 22-MAY-1998 10:13
+$!
+$! P1 root of the directory tree
+$!
+$ IF P1 .EQS. ""
+$ THEN
+$ WRITE SYS$OUTPUT "First argument missing."
+$ WRITE SYS$OUTPUT -
+ "It should be the directory where you want things installed."
+$ EXIT
+$ ENDIF
+$
+$ IF (F$GETSYI("CPU").LT.128)
+$ THEN
+$ ARCH := VAX
+$ ELSE
+$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
+$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
+$ ENDIF
+$
+$ ROOT = F$PARSE(P1,"[]A.;0",,,"SYNTAX_ONLY,NO_CONCEAL") - "A.;0"
+$ ROOT_DEV = F$PARSE(ROOT,,,"DEVICE","SYNTAX_ONLY")
+$ ROOT_DIR = F$PARSE(ROOT,,,"DIRECTORY","SYNTAX_ONLY") -
+ - "[000000." - "][" - "[" - "]"
+$ ROOT = ROOT_DEV + "[" + ROOT_DIR
+$
+$ DEFINE/NOLOG WRK_SSLROOT 'ROOT'.] /TRANS=CONC
+$ DEFINE/NOLOG WRK_SSLXLIB WRK_SSLROOT:['ARCH'_LIB]
+$ DEFINE/NOLOG WRK_SSLINCLUDE WRK_SSLROOT:[INCLUDE]
+$ DEFINE/NOLOG WRK_SSLXEXE WRK_SSLROOT:['ARCH'_EXE]
+$
+$ IF F$PARSE("WRK_SSLROOT:[000000]") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLROOT:[000000]
+$ IF F$PARSE("WRK_SSLXLIB:") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLXLIB:
+$ IF F$PARSE("WRK_SSLINCLUDE:") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLINCLUDE:
+$ IF F$PARSE("WRK_SSLXEXE:") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLXEXE:
+$
+$ EXHEADER := ssl.h,ssl2.h,ssl3.h,ssl23.h,tls1.h,dtls1.h,kssl.h
+$ E_EXE := ssl_task
+$ LIBS := LIBSSL,LIBSSL32
+$
+$ XEXE_DIR := [-.'ARCH'.EXE.SSL]
+$
+$ COPY 'EXHEADER' WRK_SSLINCLUDE:/LOG
+$ SET FILE/PROT=WORLD:RE WRK_SSLINCLUDE:'EXHEADER'
+$
+$ I = 0
+$ LOOP_EXE:
+$ E = F$EDIT(F$ELEMENT(I, ",", E_EXE),"TRIM")
+$ I = I + 1
+$ IF E .EQS. "," THEN GOTO LOOP_EXE_END
+$ SET NOON
+$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. ""
+$ THEN
+$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXEXE:'E'.EXE/log
+$ SET FILE/PROT=W:RE WRK_SSLXEXE:'E'.EXE
+$ ENDIF
+$ SET ON
+$ GOTO LOOP_EXE
+$ LOOP_EXE_END:
+$
+$ I = 0
+$ LOOP_LIB:
+$ E = F$EDIT(F$ELEMENT(I, ",", LIBS),"TRIM")
+$ I = I + 1
+$ IF E .EQS. "," THEN GOTO LOOP_LIB_END
+$ SET NOON
+$! Object library.
+$ IF F$SEARCH(XEXE_DIR+E+".OLB") .NES. ""
+$ THEN
+$ COPY 'XEXE_DIR''E'.OLB WRK_SSLXLIB:'E'.OLB/log
+$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.OLB
+$ ENDIF
+$! Shareable image.
+$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. ""
+$ THEN
+$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXLIB:'E'.EXE/log
+$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.EXE
+$ ENDIF
+$ SET ON
+$ GOTO LOOP_LIB
+$ LOOP_LIB_END:
+$
+$ EXIT
diff --git a/openssl/ssl/s2_srvr.c b/openssl/ssl/s2_srvr.c index 947167687..6643c787c 100644 --- a/openssl/ssl/s2_srvr.c +++ b/openssl/ssl/s2_srvr.c @@ -1,1141 +1,1142 @@ -/* ssl/s2_srvr.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 <openssl/bio.h> -#include <openssl/rand.h> -#include <openssl/objects.h> -#include <openssl/evp.h> - -static const SSL_METHOD *ssl2_get_server_method(int ver); -static int get_client_master_key(SSL *s); -static int get_client_hello(SSL *s); -static int server_hello(SSL *s); -static int get_client_finished(SSL *s); -static int server_verify(SSL *s); -static int server_finish(SSL *s); -static int request_certificate(SSL *s); -static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, - unsigned char *to,int padding); -#define BREAK break - -static const SSL_METHOD *ssl2_get_server_method(int ver) - { - if (ver == SSL2_VERSION) - return(SSLv2_server_method()); - else - return(NULL); - } - -IMPLEMENT_ssl2_meth_func(SSLv2_server_method, - ssl2_accept, - ssl_undefined_function, - ssl2_get_server_method) - -int ssl2_accept(SSL *s) - { - unsigned long l=(unsigned long)time(NULL); - BUF_MEM *buf=NULL; - int ret= -1; - long num1; - void (*cb)(const SSL *ssl,int type,int val)=NULL; - int new_state,state; - - RAND_add(&l,sizeof(l),0); - ERR_clear_error(); - clear_sys_error(); - - if (s->info_callback != NULL) - cb=s->info_callback; - else if (s->ctx->info_callback != NULL) - cb=s->ctx->info_callback; - - /* init things to blank */ - s->in_handshake++; - if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); - - if (s->cert == NULL) - { - SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET); - return(-1); - } - - clear_sys_error(); - for (;;) - { - state=s->state; - - switch (s->state) - { - case SSL_ST_BEFORE: - case SSL_ST_ACCEPT: - case SSL_ST_BEFORE|SSL_ST_ACCEPT: - case SSL_ST_OK|SSL_ST_ACCEPT: - - s->server=1; - if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); - - s->version=SSL2_VERSION; - s->type=SSL_ST_ACCEPT; - - buf=s->init_buf; - if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL)) - { ret= -1; goto end; } - if (!BUF_MEM_grow(buf,(int) - SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) - { ret= -1; goto end; } - s->init_buf=buf; - s->init_num=0; - s->ctx->stats.sess_accept++; - s->handshake_func=ssl2_accept; - s->state=SSL2_ST_GET_CLIENT_HELLO_A; - BREAK; - - case SSL2_ST_GET_CLIENT_HELLO_A: - case SSL2_ST_GET_CLIENT_HELLO_B: - case SSL2_ST_GET_CLIENT_HELLO_C: - s->shutdown=0; - ret=get_client_hello(s); - if (ret <= 0) goto end; - s->init_num=0; - s->state=SSL2_ST_SEND_SERVER_HELLO_A; - BREAK; - - case SSL2_ST_SEND_SERVER_HELLO_A: - case SSL2_ST_SEND_SERVER_HELLO_B: - ret=server_hello(s); - if (ret <= 0) goto end; - s->init_num=0; - if (!s->hit) - { - s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A; - BREAK; - } - else - { - s->state=SSL2_ST_SERVER_START_ENCRYPTION; - BREAK; - } - case SSL2_ST_GET_CLIENT_MASTER_KEY_A: - case SSL2_ST_GET_CLIENT_MASTER_KEY_B: - ret=get_client_master_key(s); - if (ret <= 0) goto end; - s->init_num=0; - s->state=SSL2_ST_SERVER_START_ENCRYPTION; - BREAK; - - case SSL2_ST_SERVER_START_ENCRYPTION: - /* Ok we how have sent all the stuff needed to - * start encrypting, the next packet back will - * be encrypted. */ - if (!ssl2_enc_init(s,0)) - { ret= -1; goto end; } - s->s2->clear_text=0; - s->state=SSL2_ST_SEND_SERVER_VERIFY_A; - BREAK; - - case SSL2_ST_SEND_SERVER_VERIFY_A: - case SSL2_ST_SEND_SERVER_VERIFY_B: - ret=server_verify(s); - if (ret <= 0) goto end; - s->init_num=0; - if (s->hit) - { - /* If we are in here, we have been - * buffering the output, so we need to - * flush it and remove buffering from - * future traffic */ - s->state=SSL2_ST_SEND_SERVER_VERIFY_C; - BREAK; - } - else - { - s->state=SSL2_ST_GET_CLIENT_FINISHED_A; - break; - } - - case SSL2_ST_SEND_SERVER_VERIFY_C: - /* get the number of bytes to write */ - num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); - if (num1 > 0) - { - s->rwstate=SSL_WRITING; - num1=BIO_flush(s->wbio); - if (num1 <= 0) { ret= -1; goto end; } - s->rwstate=SSL_NOTHING; - } - - /* flushed and now remove buffering */ - s->wbio=BIO_pop(s->wbio); - - s->state=SSL2_ST_GET_CLIENT_FINISHED_A; - BREAK; - - case SSL2_ST_GET_CLIENT_FINISHED_A: - case SSL2_ST_GET_CLIENT_FINISHED_B: - ret=get_client_finished(s); - if (ret <= 0) - goto end; - s->init_num=0; - s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A; - BREAK; - - case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: - case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: - case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: - case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: - /* don't do a 'request certificate' if we - * don't want to, or we already have one, and - * we only want to do it once. */ - if (!(s->verify_mode & SSL_VERIFY_PEER) || - ((s->session->peer != NULL) && - (s->verify_mode & SSL_VERIFY_CLIENT_ONCE))) - { - s->state=SSL2_ST_SEND_SERVER_FINISHED_A; - break; - } - else - { - ret=request_certificate(s); - if (ret <= 0) goto end; - s->init_num=0; - s->state=SSL2_ST_SEND_SERVER_FINISHED_A; - } - BREAK; - - case SSL2_ST_SEND_SERVER_FINISHED_A: - case SSL2_ST_SEND_SERVER_FINISHED_B: - ret=server_finish(s); - if (ret <= 0) goto end; - s->init_num=0; - s->state=SSL_ST_OK; - break; - - case SSL_ST_OK: - BUF_MEM_free(s->init_buf); - ssl_free_wbio_buffer(s); - s->init_buf=NULL; - s->init_num=0; - /* ERR_clear_error();*/ - - ssl_update_cache(s,SSL_SESS_CACHE_SERVER); - - s->ctx->stats.sess_accept_good++; - /* s->server=1; */ - ret=1; - - if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); - - goto end; - /* BREAK; */ - - default: - SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE); - ret= -1; - goto end; - /* BREAK; */ - } - - if ((cb != NULL) && (s->state != state)) - { - new_state=s->state; - s->state=state; - cb(s,SSL_CB_ACCEPT_LOOP,1); - s->state=new_state; - } - } -end: - s->in_handshake--; - if (cb != NULL) - cb(s,SSL_CB_ACCEPT_EXIT,ret); - return(ret); - } - -static int get_client_master_key(SSL *s) - { - int is_export,i,n,keya,ek; - unsigned long len; - unsigned char *p; - const SSL_CIPHER *cp; - const EVP_CIPHER *c; - const EVP_MD *md; - - p=(unsigned char *)s->init_buf->data; - if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A) - { - i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num); - - if (i < (10-s->init_num)) - return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); - s->init_num = 10; - - if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY) - { - if (p[-1] != SSL2_MT_ERROR) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE); - } - else - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR); - return(-1); - } - - cp=ssl2_get_cipher_by_char(p); - if (cp == NULL) - { - ssl2_return_error(s,SSL2_PE_NO_CIPHER); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH); - return(-1); - } - s->session->cipher= cp; - - p+=3; - n2s(p,i); s->s2->tmp.clear=i; - n2s(p,i); s->s2->tmp.enc=i; - n2s(p,i); s->session->key_arg_length=i; - if(s->session->key_arg_length > SSL_MAX_KEY_ARG_LENGTH) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG); - return -1; - } - s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B; - } - - /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */ - p=(unsigned char *)s->init_buf->data; - if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); - return -1; - } - keya=s->session->key_arg_length; - len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya; - if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG); - return -1; - } - n = (int)len - s->init_num; - i = ssl2_read(s,(char *)&(p[s->init_num]),n); - if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i)); - if (s->msg_callback) - s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */ - p += 10; - - memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]), - (unsigned int)keya); - - if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY); - return(-1); - } - i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc, - &(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]), - (s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING); - - is_export=SSL_C_IS_EXPORT(s->session->cipher); - - if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL)) - { - ssl2_return_error(s,SSL2_PE_NO_CIPHER); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); - return(0); - } - - if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) - { - is_export=1; - ek=8; - } - else - ek=5; - - /* bad decrypt */ -#if 1 - /* If a bad decrypt, continue with protocol but with a - * random master secret (Bleichenbacher attack) */ - if ((i < 0) || - ((!is_export && (i != EVP_CIPHER_key_length(c))) - || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i != - (unsigned int)EVP_CIPHER_key_length(c)))))) - { - ERR_clear_error(); - if (is_export) - i=ek; - else - i=EVP_CIPHER_key_length(c); - if (RAND_pseudo_bytes(p,i) <= 0) - return 0; - } -#else - if (i < 0) - { - error=1; - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT); - } - /* incorrect number of key bytes for non export cipher */ - else if ((!is_export && (i != EVP_CIPHER_key_length(c))) - || (is_export && ((i != ek) || (s->s2->tmp.clear+i != - EVP_CIPHER_key_length(c))))) - { - error=1; - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS); - } - if (error) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - return(-1); - } -#endif - - if (is_export) i+=s->s2->tmp.clear; - - if (i > SSL_MAX_MASTER_KEY_LENGTH) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); - return -1; - } - s->session->master_key_length=i; - memcpy(s->session->master_key,p,(unsigned int)i); - return(1); - } - -static int get_client_hello(SSL *s) - { - int i,n; - unsigned long len; - unsigned char *p; - STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ - STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ - STACK_OF(SSL_CIPHER) *prio, *allow; - int z; - - /* This is a bit of a hack to check for the correct packet - * type the first time round. */ - if (s->state == SSL2_ST_GET_CLIENT_HELLO_A) - { - s->first_packet=1; - s->state=SSL2_ST_GET_CLIENT_HELLO_B; - } - - p=(unsigned char *)s->init_buf->data; - if (s->state == SSL2_ST_GET_CLIENT_HELLO_B) - { - i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num); - if (i < (9-s->init_num)) - return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); - s->init_num = 9; - - if (*(p++) != SSL2_MT_CLIENT_HELLO) - { - if (p[-1] != SSL2_MT_ERROR) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE); - } - else - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); - return(-1); - } - n2s(p,i); - if (i < s->version) s->version=i; - n2s(p,i); s->s2->tmp.cipher_spec_length=i; - n2s(p,i); s->s2->tmp.session_id_length=i; - n2s(p,i); s->s2->challenge_length=i; - if ( (i < SSL2_MIN_CHALLENGE_LENGTH) || - (i > SSL2_MAX_CHALLENGE_LENGTH)) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH); - return(-1); - } - s->state=SSL2_ST_GET_CLIENT_HELLO_C; - } - - /* SSL2_ST_GET_CLIENT_HELLO_C */ - p=(unsigned char *)s->init_buf->data; - len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length; - if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG); - return -1; - } - n = (int)len - s->init_num; - i = ssl2_read(s,(char *)&(p[s->init_num]),n); - if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i)); - if (s->msg_callback) - s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */ - p += 9; - - /* get session-id before cipher stuff so we can get out session - * structure if it is cached */ - /* session-id */ - if ((s->s2->tmp.session_id_length != 0) && - (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH)) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH); - return(-1); - } - - if (s->s2->tmp.session_id_length == 0) - { - if (!ssl_get_new_session(s,1)) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - return(-1); - } - } - else - { - i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]), - s->s2->tmp.session_id_length, NULL); - if (i == 1) - { /* previous session */ - s->hit=1; - } - else if (i == -1) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - return(-1); - } - else - { - if (s->cert == NULL) - { - ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); - SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET); - return(-1); - } - - if (!ssl_get_new_session(s,1)) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - return(-1); - } - } - } - - if (!s->hit) - { - cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length, - &s->session->ciphers); - if (cs == NULL) goto mem_err; - - cl=SSL_get_ciphers(s); - - if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) - { - prio=sk_SSL_CIPHER_dup(cl); - if (prio == NULL) goto mem_err; - allow = cs; - } - else - { - prio = cs; - allow = cl; - } - for (z=0; z<sk_SSL_CIPHER_num(prio); z++) - { - if (sk_SSL_CIPHER_find(allow,sk_SSL_CIPHER_value(prio,z)) < 0) - { - (void)sk_SSL_CIPHER_delete(prio,z); - z--; - } - } - if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) - { - sk_SSL_CIPHER_free(s->session->ciphers); - s->session->ciphers = prio; - } - /* s->session->ciphers should now have a list of - * ciphers that are on both the client and server. - * This list is ordered by the order the client sent - * the ciphers or in the order of the server's preference - * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. - */ - } - p+=s->s2->tmp.cipher_spec_length; - /* done cipher selection */ - - /* session id extracted already */ - p+=s->s2->tmp.session_id_length; - - /* challenge */ - if (s->s2->challenge_length > sizeof s->s2->challenge) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); - return -1; - } - memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length); - return(1); -mem_err: - SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE); - return(0); - } - -static int server_hello(SSL *s) - { - unsigned char *p,*d; - int n,hit; - - p=(unsigned char *)s->init_buf->data; - if (s->state == SSL2_ST_SEND_SERVER_HELLO_A) - { - d=p+11; - *(p++)=SSL2_MT_SERVER_HELLO; /* type */ - hit=s->hit; - *(p++)=(unsigned char)hit; -#if 1 - if (!hit) - { - if (s->session->sess_cert != NULL) - /* This can't really happen because get_client_hello - * has called ssl_get_new_session, which does not set - * sess_cert. */ - ssl_sess_cert_free(s->session->sess_cert); - s->session->sess_cert = ssl_sess_cert_new(); - if (s->session->sess_cert == NULL) - { - SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE); - return(-1); - } - } - /* If 'hit' is set, then s->sess_cert may be non-NULL or NULL, - * depending on whether it survived in the internal cache - * or was retrieved from an external cache. - * If it is NULL, we cannot put any useful data in it anyway, - * so we don't touch it. - */ - -#else /* That's what used to be done when cert_st and sess_cert_st were - * the same. */ - if (!hit) - { /* else add cert to session */ - CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT); - if (s->session->sess_cert != NULL) - ssl_cert_free(s->session->sess_cert); - s->session->sess_cert=s->cert; - } - else /* We have a session id-cache hit, if the - * session-id has no certificate listed against - * the 'cert' structure, grab the 'old' one - * listed against the SSL connection */ - { - if (s->session->sess_cert == NULL) - { - CRYPTO_add(&s->cert->references,1, - CRYPTO_LOCK_SSL_CERT); - s->session->sess_cert=s->cert; - } - } -#endif - - if (s->cert == NULL) - { - ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE); - SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED); - return(-1); - } - - if (hit) - { - *(p++)=0; /* no certificate type */ - s2n(s->version,p); /* version */ - s2n(0,p); /* cert len */ - s2n(0,p); /* ciphers len */ - } - else - { - /* EAY EAY */ - /* put certificate type */ - *(p++)=SSL2_CT_X509_CERTIFICATE; - s2n(s->version,p); /* version */ - n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); - s2n(n,p); /* certificate length */ - i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d); - n=0; - - /* lets send out the ciphers we like in the - * prefered order */ - n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0); - d+=n; - s2n(n,p); /* add cipher length */ - } - - /* make and send conn_id */ - s2n(SSL2_CONNECTION_ID_LENGTH,p); /* add conn_id length */ - s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH; - if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0) - return -1; - memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH); - d+=SSL2_CONNECTION_ID_LENGTH; - - s->state=SSL2_ST_SEND_SERVER_HELLO_B; - s->init_num=d-(unsigned char *)s->init_buf->data; - s->init_off=0; - } - /* SSL2_ST_SEND_SERVER_HELLO_B */ - /* If we are using TCP/IP, the performance is bad if we do 2 - * writes without a read between them. This occurs when - * Session-id reuse is used, so I will put in a buffering module - */ - if (s->hit) - { - if (!ssl_init_wbio_buffer(s,1)) return(-1); - } - - return(ssl2_do_write(s)); - } - -static int get_client_finished(SSL *s) - { - unsigned char *p; - int i, n; - unsigned long len; - - p=(unsigned char *)s->init_buf->data; - if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A) - { - i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num); - if (i < 1-s->init_num) - return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); - s->init_num += i; - - if (*p != SSL2_MT_CLIENT_FINISHED) - { - if (*p != SSL2_MT_ERROR) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE); - } - else - { - SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR); - /* try to read the error message */ - i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num); - return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i); - } - return(-1); - } - s->state=SSL2_ST_GET_CLIENT_FINISHED_B; - } - - /* SSL2_ST_GET_CLIENT_FINISHED_B */ - if (s->s2->conn_id_length > sizeof s->s2->conn_id) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); - return -1; - } - len = 1 + (unsigned long)s->s2->conn_id_length; - n = (int)len - s->init_num; - i = ssl2_read(s,(char *)&(p[s->init_num]),n); - if (i < n) - { - return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i)); - } - if (s->msg_callback) - s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */ - p += 1; - if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT); - return(-1); - } - return(1); - } - -static int server_verify(SSL *s) - { - unsigned char *p; - - if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A) - { - p=(unsigned char *)s->init_buf->data; - *(p++)=SSL2_MT_SERVER_VERIFY; - if (s->s2->challenge_length > sizeof s->s2->challenge) - { - SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR); - return -1; - } - memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length); - /* p+=s->s2->challenge_length; */ - - s->state=SSL2_ST_SEND_SERVER_VERIFY_B; - s->init_num=s->s2->challenge_length+1; - s->init_off=0; - } - return(ssl2_do_write(s)); - } - -static int server_finish(SSL *s) - { - unsigned char *p; - - if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A) - { - p=(unsigned char *)s->init_buf->data; - *(p++)=SSL2_MT_SERVER_FINISHED; - - if (s->session->session_id_length > sizeof s->session->session_id) - { - SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR); - return -1; - } - memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length); - /* p+=s->session->session_id_length; */ - - s->state=SSL2_ST_SEND_SERVER_FINISHED_B; - s->init_num=s->session->session_id_length+1; - s->init_off=0; - } - - /* SSL2_ST_SEND_SERVER_FINISHED_B */ - return(ssl2_do_write(s)); - } - -/* send the request and check the response */ -static int request_certificate(SSL *s) - { - const unsigned char *cp; - unsigned char *p,*p2,*buf2; - unsigned char *ccd; - int i,j,ctype,ret= -1; - unsigned long len; - X509 *x509=NULL; - STACK_OF(X509) *sk=NULL; - - ccd=s->s2->tmp.ccl; - if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A) - { - p=(unsigned char *)s->init_buf->data; - *(p++)=SSL2_MT_REQUEST_CERTIFICATE; - *(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION; - if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0) - return -1; - memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); - - s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B; - s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2; - s->init_off=0; - } - - if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B) - { - i=ssl2_do_write(s); - if (i <= 0) - { - ret=i; - goto end; - } - - s->init_num=0; - s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C; - } - - if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C) - { - p=(unsigned char *)s->init_buf->data; - i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */ - if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3 - * (probably NO-CERTIFICATE-ERROR) */ - { - ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); - goto end; - } - s->init_num += i; - - if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR)) - { - n2s(p,i); - if (i != SSL2_PE_NO_CERTIFICATE) - { - /* not the error message we expected -- let ssl2_part_read handle it */ - s->init_num -= 3; - ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3); - goto end; - } - - if (s->msg_callback) - s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */ - - /* this is the one place where we can recover from an SSL 2.0 error */ - - if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) - { - ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); - SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); - goto end; - } - ret=1; - goto end; - } - if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6)) - { - ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); - SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ); - goto end; - } - if (s->init_num != 6) - { - SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR); - goto end; - } - - /* ok we have a response */ - /* certificate type, there is only one right now. */ - ctype= *(p++); - if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) - { - ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); - SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT); - goto end; - } - n2s(p,i); s->s2->tmp.clen=i; - n2s(p,i); s->s2->tmp.rlen=i; - s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D; - } - - /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */ - p=(unsigned char *)s->init_buf->data; - len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen; - if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) - { - SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG); - goto end; - } - j = (int)len - s->init_num; - i = ssl2_read(s,(char *)&(p[s->init_num]),j); - if (i < j) - { - ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i); - goto end; - } - if (s->msg_callback) - s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */ - p += 6; - - cp = p; - x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen); - if (x509 == NULL) - { - SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB); - goto msg_end; - } - - if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509))) - { - SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); - goto msg_end; - } - - i=ssl_verify_cert_chain(s,sk); - - if (i > 0) /* we like the packet, now check the chksum */ - { - EVP_MD_CTX ctx; - EVP_PKEY *pkey=NULL; - - EVP_MD_CTX_init(&ctx); - EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL); - EVP_VerifyUpdate(&ctx,s->s2->key_material, - s->s2->key_material_length); - EVP_VerifyUpdate(&ctx,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH); - - i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL); - buf2=OPENSSL_malloc((unsigned int)i); - if (buf2 == NULL) - { - SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE); - goto msg_end; - } - p2=buf2; - i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2); - EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i); - OPENSSL_free(buf2); - - pkey=X509_get_pubkey(x509); - if (pkey == NULL) goto end; - i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey); - EVP_PKEY_free(pkey); - EVP_MD_CTX_cleanup(&ctx); - - if (i > 0) - { - if (s->session->peer != NULL) - X509_free(s->session->peer); - s->session->peer=x509; - CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); - s->session->verify_result = s->verify_result; - ret=1; - goto end; - } - else - { - SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM); - goto msg_end; - } - } - else - { -msg_end: - ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); - } -end: - sk_X509_free(sk); - X509_free(x509); - return(ret); - } - -static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, - unsigned char *to, int padding) - { - RSA *rsa; - int i; - - if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)) - { - SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY); - return(-1); - } - if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA) - { - SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA); - return(-1); - } - rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa; - - /* we have the public key */ - i=RSA_private_decrypt(len,from,to,rsa,padding); - if (i < 0) - SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB); - return(i); - } -#else /* !OPENSSL_NO_SSL2 */ - -# if PEDANTIC -static void *dummy=&dummy; -# endif - -#endif +/* ssl/s2_srvr.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 <openssl/bio.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+
+static const SSL_METHOD *ssl2_get_server_method(int ver);
+static int get_client_master_key(SSL *s);
+static int get_client_hello(SSL *s);
+static int server_hello(SSL *s);
+static int get_client_finished(SSL *s);
+static int server_verify(SSL *s);
+static int server_finish(SSL *s);
+static int request_certificate(SSL *s);
+static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from,
+ unsigned char *to,int padding);
+#define BREAK break
+
+static const SSL_METHOD *ssl2_get_server_method(int ver)
+ {
+ if (ver == SSL2_VERSION)
+ return(SSLv2_server_method());
+ else
+ return(NULL);
+ }
+
+IMPLEMENT_ssl2_meth_func(SSLv2_server_method,
+ ssl2_accept,
+ ssl_undefined_function,
+ ssl2_get_server_method)
+
+int ssl2_accept(SSL *s)
+ {
+ unsigned long l=(unsigned long)time(NULL);
+ BUF_MEM *buf=NULL;
+ int ret= -1;
+ long num1;
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ int new_state,state;
+
+ RAND_add(&l,sizeof(l),0);
+ ERR_clear_error();
+ clear_sys_error();
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ /* init things to blank */
+ s->in_handshake++;
+ if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+ if (s->cert == NULL)
+ {
+ SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+ return(-1);
+ }
+
+ clear_sys_error();
+ for (;;)
+ {
+ state=s->state;
+
+ switch (s->state)
+ {
+ case SSL_ST_BEFORE:
+ case SSL_ST_ACCEPT:
+ case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+ case SSL_ST_OK|SSL_ST_ACCEPT:
+
+ s->server=1;
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+ s->version=SSL2_VERSION;
+ s->type=SSL_ST_ACCEPT;
+
+ buf=s->init_buf;
+ if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL))
+ { ret= -1; goto end; }
+ if (!BUF_MEM_grow(buf,(int)
+ SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER))
+ { ret= -1; goto end; }
+ s->init_buf=buf;
+ s->init_num=0;
+ s->ctx->stats.sess_accept++;
+ s->handshake_func=ssl2_accept;
+ s->state=SSL2_ST_GET_CLIENT_HELLO_A;
+ BREAK;
+
+ case SSL2_ST_GET_CLIENT_HELLO_A:
+ case SSL2_ST_GET_CLIENT_HELLO_B:
+ case SSL2_ST_GET_CLIENT_HELLO_C:
+ s->shutdown=0;
+ ret=get_client_hello(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL2_ST_SEND_SERVER_HELLO_A;
+ BREAK;
+
+ case SSL2_ST_SEND_SERVER_HELLO_A:
+ case SSL2_ST_SEND_SERVER_HELLO_B:
+ ret=server_hello(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ if (!s->hit)
+ {
+ s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A;
+ BREAK;
+ }
+ else
+ {
+ s->state=SSL2_ST_SERVER_START_ENCRYPTION;
+ BREAK;
+ }
+ case SSL2_ST_GET_CLIENT_MASTER_KEY_A:
+ case SSL2_ST_GET_CLIENT_MASTER_KEY_B:
+ ret=get_client_master_key(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL2_ST_SERVER_START_ENCRYPTION;
+ BREAK;
+
+ case SSL2_ST_SERVER_START_ENCRYPTION:
+ /* Ok we how have sent all the stuff needed to
+ * start encrypting, the next packet back will
+ * be encrypted. */
+ if (!ssl2_enc_init(s,0))
+ { ret= -1; goto end; }
+ s->s2->clear_text=0;
+ s->state=SSL2_ST_SEND_SERVER_VERIFY_A;
+ BREAK;
+
+ case SSL2_ST_SEND_SERVER_VERIFY_A:
+ case SSL2_ST_SEND_SERVER_VERIFY_B:
+ ret=server_verify(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ if (s->hit)
+ {
+ /* If we are in here, we have been
+ * buffering the output, so we need to
+ * flush it and remove buffering from
+ * future traffic */
+ s->state=SSL2_ST_SEND_SERVER_VERIFY_C;
+ BREAK;
+ }
+ else
+ {
+ s->state=SSL2_ST_GET_CLIENT_FINISHED_A;
+ break;
+ }
+
+ case SSL2_ST_SEND_SERVER_VERIFY_C:
+ /* get the number of bytes to write */
+ num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
+ if (num1 > 0)
+ {
+ s->rwstate=SSL_WRITING;
+ num1=BIO_flush(s->wbio);
+ if (num1 <= 0) { ret= -1; goto end; }
+ s->rwstate=SSL_NOTHING;
+ }
+
+ /* flushed and now remove buffering */
+ s->wbio=BIO_pop(s->wbio);
+
+ s->state=SSL2_ST_GET_CLIENT_FINISHED_A;
+ BREAK;
+
+ case SSL2_ST_GET_CLIENT_FINISHED_A:
+ case SSL2_ST_GET_CLIENT_FINISHED_B:
+ ret=get_client_finished(s);
+ if (ret <= 0)
+ goto end;
+ s->init_num=0;
+ s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A;
+ BREAK;
+
+ case SSL2_ST_SEND_REQUEST_CERTIFICATE_A:
+ case SSL2_ST_SEND_REQUEST_CERTIFICATE_B:
+ case SSL2_ST_SEND_REQUEST_CERTIFICATE_C:
+ case SSL2_ST_SEND_REQUEST_CERTIFICATE_D:
+ /* don't do a 'request certificate' if we
+ * don't want to, or we already have one, and
+ * we only want to do it once. */
+ if (!(s->verify_mode & SSL_VERIFY_PEER) ||
+ ((s->session->peer != NULL) &&
+ (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)))
+ {
+ s->state=SSL2_ST_SEND_SERVER_FINISHED_A;
+ break;
+ }
+ else
+ {
+ ret=request_certificate(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL2_ST_SEND_SERVER_FINISHED_A;
+ }
+ BREAK;
+
+ case SSL2_ST_SEND_SERVER_FINISHED_A:
+ case SSL2_ST_SEND_SERVER_FINISHED_B:
+ ret=server_finish(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL_ST_OK;
+ break;
+
+ case SSL_ST_OK:
+ BUF_MEM_free(s->init_buf);
+ ssl_free_wbio_buffer(s);
+ s->init_buf=NULL;
+ s->init_num=0;
+ /* ERR_clear_error();*/
+
+ ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+
+ s->ctx->stats.sess_accept_good++;
+ /* s->server=1; */
+ ret=1;
+
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+ goto end;
+ /* BREAK; */
+
+ default:
+ SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE);
+ ret= -1;
+ goto end;
+ /* BREAK; */
+ }
+
+ if ((cb != NULL) && (s->state != state))
+ {
+ new_state=s->state;
+ s->state=state;
+ cb(s,SSL_CB_ACCEPT_LOOP,1);
+ s->state=new_state;
+ }
+ }
+end:
+ s->in_handshake--;
+ if (cb != NULL)
+ cb(s,SSL_CB_ACCEPT_EXIT,ret);
+ return(ret);
+ }
+
+static int get_client_master_key(SSL *s)
+ {
+ int is_export,i,n,keya,ek;
+ unsigned long len;
+ unsigned char *p;
+ const SSL_CIPHER *cp;
+ const EVP_CIPHER *c;
+ const EVP_MD *md;
+
+ p=(unsigned char *)s->init_buf->data;
+ if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A)
+ {
+ i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num);
+
+ if (i < (10-s->init_num))
+ return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i));
+ s->init_num = 10;
+
+ if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY)
+ {
+ if (p[-1] != SSL2_MT_ERROR)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE);
+ }
+ else
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR);
+ return(-1);
+ }
+
+ cp=ssl2_get_cipher_by_char(p);
+ if (cp == NULL)
+ {
+ ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH);
+ return(-1);
+ }
+ s->session->cipher= cp;
+
+ p+=3;
+ n2s(p,i); s->s2->tmp.clear=i;
+ n2s(p,i); s->s2->tmp.enc=i;
+ n2s(p,i);
+ if(i > SSL_MAX_KEY_ARG_LENGTH)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG);
+ return -1;
+ }
+ s->session->key_arg_length=i;
+ s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B;
+ }
+
+ /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */
+ p=(unsigned char *)s->init_buf->data;
+ if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ keya=s->session->key_arg_length;
+ len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya;
+ if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG);
+ return -1;
+ }
+ n = (int)len - s->init_num;
+ i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+ if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i));
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */
+ p += 10;
+
+ memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]),
+ (unsigned int)keya);
+
+ if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY);
+ return(-1);
+ }
+ i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc,
+ &(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]),
+ (s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING);
+
+ is_export=SSL_C_IS_EXPORT(s->session->cipher);
+
+ if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL))
+ {
+ ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
+ return(0);
+ }
+
+ if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC)
+ {
+ is_export=1;
+ ek=8;
+ }
+ else
+ ek=5;
+
+ /* bad decrypt */
+#if 1
+ /* If a bad decrypt, continue with protocol but with a
+ * random master secret (Bleichenbacher attack) */
+ if ((i < 0) ||
+ ((!is_export && (i != EVP_CIPHER_key_length(c)))
+ || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i !=
+ (unsigned int)EVP_CIPHER_key_length(c))))))
+ {
+ ERR_clear_error();
+ if (is_export)
+ i=ek;
+ else
+ i=EVP_CIPHER_key_length(c);
+ if (RAND_pseudo_bytes(p,i) <= 0)
+ return 0;
+ }
+#else
+ if (i < 0)
+ {
+ error=1;
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT);
+ }
+ /* incorrect number of key bytes for non export cipher */
+ else if ((!is_export && (i != EVP_CIPHER_key_length(c)))
+ || (is_export && ((i != ek) || (s->s2->tmp.clear+i !=
+ EVP_CIPHER_key_length(c)))))
+ {
+ error=1;
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS);
+ }
+ if (error)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ return(-1);
+ }
+#endif
+
+ if (is_export) i+=s->s2->tmp.clear;
+
+ if (i > SSL_MAX_MASTER_KEY_LENGTH)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->session->master_key_length=i;
+ memcpy(s->session->master_key,p,(unsigned int)i);
+ return(1);
+ }
+
+static int get_client_hello(SSL *s)
+ {
+ int i,n;
+ unsigned long len;
+ unsigned char *p;
+ STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */
+ STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */
+ STACK_OF(SSL_CIPHER) *prio, *allow;
+ int z;
+
+ /* This is a bit of a hack to check for the correct packet
+ * type the first time round. */
+ if (s->state == SSL2_ST_GET_CLIENT_HELLO_A)
+ {
+ s->first_packet=1;
+ s->state=SSL2_ST_GET_CLIENT_HELLO_B;
+ }
+
+ p=(unsigned char *)s->init_buf->data;
+ if (s->state == SSL2_ST_GET_CLIENT_HELLO_B)
+ {
+ i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num);
+ if (i < (9-s->init_num))
+ return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i));
+ s->init_num = 9;
+
+ if (*(p++) != SSL2_MT_CLIENT_HELLO)
+ {
+ if (p[-1] != SSL2_MT_ERROR)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE);
+ }
+ else
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ return(-1);
+ }
+ n2s(p,i);
+ if (i < s->version) s->version=i;
+ n2s(p,i); s->s2->tmp.cipher_spec_length=i;
+ n2s(p,i); s->s2->tmp.session_id_length=i;
+ n2s(p,i); s->s2->challenge_length=i;
+ if ( (i < SSL2_MIN_CHALLENGE_LENGTH) ||
+ (i > SSL2_MAX_CHALLENGE_LENGTH))
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH);
+ return(-1);
+ }
+ s->state=SSL2_ST_GET_CLIENT_HELLO_C;
+ }
+
+ /* SSL2_ST_GET_CLIENT_HELLO_C */
+ p=(unsigned char *)s->init_buf->data;
+ len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length;
+ if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG);
+ return -1;
+ }
+ n = (int)len - s->init_num;
+ i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+ if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i));
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */
+ p += 9;
+
+ /* get session-id before cipher stuff so we can get out session
+ * structure if it is cached */
+ /* session-id */
+ if ((s->s2->tmp.session_id_length != 0) &&
+ (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH))
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH);
+ return(-1);
+ }
+
+ if (s->s2->tmp.session_id_length == 0)
+ {
+ if (!ssl_get_new_session(s,1))
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ return(-1);
+ }
+ }
+ else
+ {
+ i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]),
+ s->s2->tmp.session_id_length, NULL);
+ if (i == 1)
+ { /* previous session */
+ s->hit=1;
+ }
+ else if (i == -1)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ return(-1);
+ }
+ else
+ {
+ if (s->cert == NULL)
+ {
+ ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE);
+ SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET);
+ return(-1);
+ }
+
+ if (!ssl_get_new_session(s,1))
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ return(-1);
+ }
+ }
+ }
+
+ if (!s->hit)
+ {
+ cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length,
+ &s->session->ciphers);
+ if (cs == NULL) goto mem_err;
+
+ cl=SSL_get_ciphers(s);
+
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+ {
+ prio=sk_SSL_CIPHER_dup(cl);
+ if (prio == NULL) goto mem_err;
+ allow = cs;
+ }
+ else
+ {
+ prio = cs;
+ allow = cl;
+ }
+ for (z=0; z<sk_SSL_CIPHER_num(prio); z++)
+ {
+ if (sk_SSL_CIPHER_find(allow,sk_SSL_CIPHER_value(prio,z)) < 0)
+ {
+ (void)sk_SSL_CIPHER_delete(prio,z);
+ z--;
+ }
+ }
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+ {
+ sk_SSL_CIPHER_free(s->session->ciphers);
+ s->session->ciphers = prio;
+ }
+ /* s->session->ciphers should now have a list of
+ * ciphers that are on both the client and server.
+ * This list is ordered by the order the client sent
+ * the ciphers or in the order of the server's preference
+ * if SSL_OP_CIPHER_SERVER_PREFERENCE was set.
+ */
+ }
+ p+=s->s2->tmp.cipher_spec_length;
+ /* done cipher selection */
+
+ /* session id extracted already */
+ p+=s->s2->tmp.session_id_length;
+
+ /* challenge */
+ if (s->s2->challenge_length > sizeof s->s2->challenge)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length);
+ return(1);
+mem_err:
+ SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+
+static int server_hello(SSL *s)
+ {
+ unsigned char *p,*d;
+ int n,hit;
+
+ p=(unsigned char *)s->init_buf->data;
+ if (s->state == SSL2_ST_SEND_SERVER_HELLO_A)
+ {
+ d=p+11;
+ *(p++)=SSL2_MT_SERVER_HELLO; /* type */
+ hit=s->hit;
+ *(p++)=(unsigned char)hit;
+#if 1
+ if (!hit)
+ {
+ if (s->session->sess_cert != NULL)
+ /* This can't really happen because get_client_hello
+ * has called ssl_get_new_session, which does not set
+ * sess_cert. */
+ ssl_sess_cert_free(s->session->sess_cert);
+ s->session->sess_cert = ssl_sess_cert_new();
+ if (s->session->sess_cert == NULL)
+ {
+ SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE);
+ return(-1);
+ }
+ }
+ /* If 'hit' is set, then s->sess_cert may be non-NULL or NULL,
+ * depending on whether it survived in the internal cache
+ * or was retrieved from an external cache.
+ * If it is NULL, we cannot put any useful data in it anyway,
+ * so we don't touch it.
+ */
+
+#else /* That's what used to be done when cert_st and sess_cert_st were
+ * the same. */
+ if (!hit)
+ { /* else add cert to session */
+ CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT);
+ if (s->session->sess_cert != NULL)
+ ssl_cert_free(s->session->sess_cert);
+ s->session->sess_cert=s->cert;
+ }
+ else /* We have a session id-cache hit, if the
+ * session-id has no certificate listed against
+ * the 'cert' structure, grab the 'old' one
+ * listed against the SSL connection */
+ {
+ if (s->session->sess_cert == NULL)
+ {
+ CRYPTO_add(&s->cert->references,1,
+ CRYPTO_LOCK_SSL_CERT);
+ s->session->sess_cert=s->cert;
+ }
+ }
+#endif
+
+ if (s->cert == NULL)
+ {
+ ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE);
+ SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED);
+ return(-1);
+ }
+
+ if (hit)
+ {
+ *(p++)=0; /* no certificate type */
+ s2n(s->version,p); /* version */
+ s2n(0,p); /* cert len */
+ s2n(0,p); /* ciphers len */
+ }
+ else
+ {
+ /* EAY EAY */
+ /* put certificate type */
+ *(p++)=SSL2_CT_X509_CERTIFICATE;
+ s2n(s->version,p); /* version */
+ n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL);
+ s2n(n,p); /* certificate length */
+ i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d);
+ n=0;
+
+ /* lets send out the ciphers we like in the
+ * prefered order */
+ n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0);
+ d+=n;
+ s2n(n,p); /* add cipher length */
+ }
+
+ /* make and send conn_id */
+ s2n(SSL2_CONNECTION_ID_LENGTH,p); /* add conn_id length */
+ s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH;
+ if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0)
+ return -1;
+ memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH);
+ d+=SSL2_CONNECTION_ID_LENGTH;
+
+ s->state=SSL2_ST_SEND_SERVER_HELLO_B;
+ s->init_num=d-(unsigned char *)s->init_buf->data;
+ s->init_off=0;
+ }
+ /* SSL2_ST_SEND_SERVER_HELLO_B */
+ /* If we are using TCP/IP, the performance is bad if we do 2
+ * writes without a read between them. This occurs when
+ * Session-id reuse is used, so I will put in a buffering module
+ */
+ if (s->hit)
+ {
+ if (!ssl_init_wbio_buffer(s,1)) return(-1);
+ }
+
+ return(ssl2_do_write(s));
+ }
+
+static int get_client_finished(SSL *s)
+ {
+ unsigned char *p;
+ int i, n;
+ unsigned long len;
+
+ p=(unsigned char *)s->init_buf->data;
+ if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A)
+ {
+ i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num);
+ if (i < 1-s->init_num)
+ return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i));
+ s->init_num += i;
+
+ if (*p != SSL2_MT_CLIENT_FINISHED)
+ {
+ if (*p != SSL2_MT_ERROR)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE);
+ }
+ else
+ {
+ SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR);
+ /* try to read the error message */
+ i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num);
+ return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i);
+ }
+ return(-1);
+ }
+ s->state=SSL2_ST_GET_CLIENT_FINISHED_B;
+ }
+
+ /* SSL2_ST_GET_CLIENT_FINISHED_B */
+ if (s->s2->conn_id_length > sizeof s->s2->conn_id)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ len = 1 + (unsigned long)s->s2->conn_id_length;
+ n = (int)len - s->init_num;
+ i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+ if (i < n)
+ {
+ return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i));
+ }
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */
+ p += 1;
+ if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0)
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT);
+ return(-1);
+ }
+ return(1);
+ }
+
+static int server_verify(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ *(p++)=SSL2_MT_SERVER_VERIFY;
+ if (s->s2->challenge_length > sizeof s->s2->challenge)
+ {
+ SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length);
+ /* p+=s->s2->challenge_length; */
+
+ s->state=SSL2_ST_SEND_SERVER_VERIFY_B;
+ s->init_num=s->s2->challenge_length+1;
+ s->init_off=0;
+ }
+ return(ssl2_do_write(s));
+ }
+
+static int server_finish(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ *(p++)=SSL2_MT_SERVER_FINISHED;
+
+ if (s->session->session_id_length > sizeof s->session->session_id)
+ {
+ SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length);
+ /* p+=s->session->session_id_length; */
+
+ s->state=SSL2_ST_SEND_SERVER_FINISHED_B;
+ s->init_num=s->session->session_id_length+1;
+ s->init_off=0;
+ }
+
+ /* SSL2_ST_SEND_SERVER_FINISHED_B */
+ return(ssl2_do_write(s));
+ }
+
+/* send the request and check the response */
+static int request_certificate(SSL *s)
+ {
+ const unsigned char *cp;
+ unsigned char *p,*p2,*buf2;
+ unsigned char *ccd;
+ int i,j,ctype,ret= -1;
+ unsigned long len;
+ X509 *x509=NULL;
+ STACK_OF(X509) *sk=NULL;
+
+ ccd=s->s2->tmp.ccl;
+ if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ *(p++)=SSL2_MT_REQUEST_CERTIFICATE;
+ *(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION;
+ if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0)
+ return -1;
+ memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH);
+
+ s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B;
+ s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2;
+ s->init_off=0;
+ }
+
+ if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B)
+ {
+ i=ssl2_do_write(s);
+ if (i <= 0)
+ {
+ ret=i;
+ goto end;
+ }
+
+ s->init_num=0;
+ s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C;
+ }
+
+ if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */
+ if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3
+ * (probably NO-CERTIFICATE-ERROR) */
+ {
+ ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i);
+ goto end;
+ }
+ s->init_num += i;
+
+ if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR))
+ {
+ n2s(p,i);
+ if (i != SSL2_PE_NO_CERTIFICATE)
+ {
+ /* not the error message we expected -- let ssl2_part_read handle it */
+ s->init_num -= 3;
+ ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3);
+ goto end;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */
+
+ /* this is the one place where we can recover from an SSL 2.0 error */
+
+ if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+ {
+ ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ goto end;
+ }
+ ret=1;
+ goto end;
+ }
+ if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6))
+ {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ);
+ goto end;
+ }
+ if (s->init_num != 6)
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ goto end;
+ }
+
+ /* ok we have a response */
+ /* certificate type, there is only one right now. */
+ ctype= *(p++);
+ if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION)
+ {
+ ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE);
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT);
+ goto end;
+ }
+ n2s(p,i); s->s2->tmp.clen=i;
+ n2s(p,i); s->s2->tmp.rlen=i;
+ s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D;
+ }
+
+ /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */
+ p=(unsigned char *)s->init_buf->data;
+ len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen;
+ if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG);
+ goto end;
+ }
+ j = (int)len - s->init_num;
+ i = ssl2_read(s,(char *)&(p[s->init_num]),j);
+ if (i < j)
+ {
+ ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i);
+ goto end;
+ }
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */
+ p += 6;
+
+ cp = p;
+ x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen);
+ if (x509 == NULL)
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB);
+ goto msg_end;
+ }
+
+ if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509)))
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto msg_end;
+ }
+
+ i=ssl_verify_cert_chain(s,sk);
+
+ if (i > 0) /* we like the packet, now check the chksum */
+ {
+ EVP_MD_CTX ctx;
+ EVP_PKEY *pkey=NULL;
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL);
+ EVP_VerifyUpdate(&ctx,s->s2->key_material,
+ s->s2->key_material_length);
+ EVP_VerifyUpdate(&ctx,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH);
+
+ i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL);
+ buf2=OPENSSL_malloc((unsigned int)i);
+ if (buf2 == NULL)
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+ goto msg_end;
+ }
+ p2=buf2;
+ i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2);
+ EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i);
+ OPENSSL_free(buf2);
+
+ pkey=X509_get_pubkey(x509);
+ if (pkey == NULL) goto end;
+ i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey);
+ EVP_PKEY_free(pkey);
+ EVP_MD_CTX_cleanup(&ctx);
+
+ if (i > 0)
+ {
+ if (s->session->peer != NULL)
+ X509_free(s->session->peer);
+ s->session->peer=x509;
+ CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
+ s->session->verify_result = s->verify_result;
+ ret=1;
+ goto end;
+ }
+ else
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM);
+ goto msg_end;
+ }
+ }
+ else
+ {
+msg_end:
+ ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
+ }
+end:
+ sk_X509_free(sk);
+ X509_free(x509);
+ return(ret);
+ }
+
+static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from,
+ unsigned char *to, int padding)
+ {
+ RSA *rsa;
+ int i;
+
+ if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL))
+ {
+ SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY);
+ return(-1);
+ }
+ if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA)
+ {
+ SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA);
+ return(-1);
+ }
+ rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa;
+
+ /* we have the public key */
+ i=RSA_private_decrypt(len,from,to,rsa,padding);
+ if (i < 0)
+ SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB);
+ return(i);
+ }
+#else /* !OPENSSL_NO_SSL2 */
+
+# if PEDANTIC
+static void *dummy=&dummy;
+# endif
+
+#endif
diff --git a/openssl/ssl/ssl-lib.com b/openssl/ssl/ssl-lib.com index c5ca9e1df..8847c9bd3 100644 --- a/openssl/ssl/ssl-lib.com +++ b/openssl/ssl/ssl-lib.com @@ -1,1057 +1,1116 @@ -$! -$! SSL-LIB.COM -$! Written By: Robert Byer -$! Vice-President -$! A-Com Computing, Inc. -$! byer@mail.all-net.net -$! -$! Changes by Richard Levitte <richard@levitte.org> -$! -$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB" -$! library for OpenSSL. The "xxx" denotes the machine architecture of -$! ALPHA, IA64 or VAX. -$! -$! It is written to detect what type of machine you are compiling on -$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC -$! or GNU C) or you can specify which compiler to use. -$! -$! Specify the following as P1 to build just that part or ALL to just -$! build everything. -$! -$! LIBRARY To just compile the [.xxx.EXE.SSL]LIBSSL.OLB Library. -$! SSL_TASK To just compile the [.xxx.EXE.SSL]SSL_TASK.EXE -$! -$! Specify DEBUG or NODEBUG as P2 to compile with or without debugger -$! information. -$! -$! Specify which compiler at P3 to try to compile under. -$! -$! VAXC For VAX C. -$! DECC For DEC C. -$! GNUC For GNU C. -$! -$! If you don't specify a compiler, it will try to determine which -$! "C" compiler to use. -$! -$! P4, if defined, sets a TCP/IP library to use, through one of the following -$! keywords: -$! -$! UCX for UCX -$! TCPIP for TCPIP (post UCX) -$! SOCKETSHR for SOCKETSHR+NETLIB -$! -$! P5, if defined, sets a compiler thread NOT needed on OpenVMS 7.1 (and up) -$! -$! -$! Define A TCP/IP Library That We Will Need To Link To. -$! (That Is, If We Need To Link To One.) -$! -$ TCPIP_LIB = "" -$! -$! Check What Architecture We Are Using. -$! -$ IF (F$GETSYI("CPU").LT.128) -$ THEN -$! -$! The Architecture Is VAX. -$! -$ ARCH = "VAX" -$! -$! Else... -$! -$ ELSE -$! -$! The Architecture Is Alpha, IA64 or whatever comes in the future. -$! -$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE") -$ IF (ARCH .EQS. "") THEN ARCH = "UNK" -$! -$! End The Architecture Check. -$! -$ ENDIF -$! -$! Define The OBJ Directory. -$! -$ OBJ_DIR := SYS$DISK:[-.'ARCH'.OBJ.SSL] -$! -$! Define The EXE Directory. -$! -$ EXE_DIR := SYS$DISK:[-.'ARCH'.EXE.SSL] -$! -$! Check To Make Sure We Have Valid Command Line Parameters. -$! -$ GOSUB CHECK_OPTIONS -$! -$! Initialise logical names and such -$! -$ GOSUB INITIALISE -$! -$! Tell The User What Kind of Machine We Run On. -$! -$ WRITE SYS$OUTPUT "Compiling On A ",ARCH," Machine." -$! -$! Check To See If The Architecture Specific OBJ Directory Exists. -$! -$ IF (F$PARSE(OBJ_DIR).EQS."") -$ THEN -$! -$! It Dosen't Exist, So Create It. -$! -$ CREATE/DIR 'OBJ_DIR' -$! -$! End The Architecture Specific OBJ Directory Check. -$! -$ ENDIF -$! -$! Check To See If The Architecture Specific Directory Exists. -$! -$ IF (F$PARSE(EXE_DIR).EQS."") -$ THEN -$! -$! It Dosen't Exist, So Create It. -$! -$ CREATE/DIR 'EXE_DIR' -$! -$! End The Architecture Specific Directory Check. -$! -$ ENDIF -$! -$! Define The Library Name. -$! -$ SSL_LIB := 'EXE_DIR'LIBSSL.OLB -$! -$! Define The CRYPTO-LIB We Are To Use. -$! -$ CRYPTO_LIB := SYS$DISK:[-.'ARCH'.EXE.CRYPTO]LIBCRYPTO.OLB -$! -$! Check To See What We Are To Do. -$! -$ IF (BUILDALL.EQS."TRUE") -$ THEN -$! -$! Since Nothing Special Was Specified, Do Everything. -$! -$ GOSUB LIBRARY -$ GOSUB SSL_TASK -$! -$! Else... -$! -$ ELSE -$! -$! Build Just What The User Wants Us To Build. -$! -$ GOSUB 'BUILDALL' -$! -$! End The BUILDALL Check. -$! -$ ENDIF -$! -$! Time To EXIT. -$! -$ EXIT: -$ GOSUB CLEANUP -$ EXIT -$! -$! Compile The Library. -$! -$ LIBRARY: -$! -$! Check To See If We Already Have A "[.xxx.EXE.SSL]LIBSSL.OLB" Library... -$! -$ IF (F$SEARCH(SSL_LIB).EQS."") -$ THEN -$! -$! Guess Not, Create The Library. -$! -$ LIBRARY/CREATE/OBJECT 'SSL_LIB' -$! -$! End The Library Exist Check. -$! -$ ENDIF -$! -$! Define The Different SSL "library" Files. -$! -$ LIB_SSL = "s2_meth,s2_srvr,s2_clnt,s2_lib,s2_enc,s2_pkt,"+ - - "s3_meth,s3_srvr,s3_clnt,s3_lib,s3_enc,s3_pkt,s3_both,"+ - - "s23_meth,s23_srvr,s23_clnt,s23_lib,s23_pkt,"+ - - "t1_meth,t1_srvr,t1_clnt,t1_lib,t1_enc,"+ - - "d1_meth,d1_srvr,d1_clnt,d1_lib,d1_pkt,"+ - - "d1_both,d1_enc,"+ - - "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ - - "ssl_ciph,ssl_stat,ssl_rsa,"+ - - "ssl_asn1,ssl_txt,ssl_algs,"+ - - "bio_ssl,ssl_err,kssl,t1_reneg" -$! -$! Tell The User That We Are Compiling The Library. -$! -$ WRITE SYS$OUTPUT "Building The ",SSL_LIB," Library." -$! -$! Define A File Counter And Set It To "0" -$! -$ FILE_COUNTER = 0 -$! -$! Top Of The File Loop. -$! -$ NEXT_FILE: -$! -$! O.K, Extract The File Name From The File List. -$! -$ FILE_NAME = F$ELEMENT(FILE_COUNTER,",",LIB_SSL) -$! -$! Check To See If We Are At The End Of The File List. -$! -$ IF (FILE_NAME.EQS.",") THEN GOTO FILE_DONE -$! -$! Increment The Counter. -$! -$ FILE_COUNTER = FILE_COUNTER + 1 -$! -$! Create The Source File Name. -$! -$ SOURCE_FILE = "SYS$DISK:[]" + FILE_NAME + ".C" -$! -$! Create The Object File Name. -$! -$ OBJECT_FILE = OBJ_DIR + FILE_NAME + ".OBJ" -$ ON WARNING THEN GOTO NEXT_FILE -$! -$! Check To See If The File We Want To Compile Is Actually There. -$! -$ IF (F$SEARCH(SOURCE_FILE).EQS."") -$ THEN -$! -$! Tell The User That The File Dosen't Exist. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The File ",SOURCE_FILE," Dosen't Exist." -$ WRITE SYS$OUTPUT "" -$! -$! Exit The Build. -$! -$ EXIT -$! -$! End The File Exists Check. -$! -$ ENDIF -$! -$! Tell The User What File We Are Compiling. -$! -$ WRITE SYS$OUTPUT " ",FILE_NAME,".c" -$! -$! Compile The File. -$! -$ ON ERROR THEN GOTO NEXT_FILE -$ CC/OBJECT='OBJECT_FILE' 'SOURCE_FILE' -$! -$! Add It To The Library. -$! -$ LIBRARY/REPLACE/OBJECT 'SSL_LIB' 'OBJECT_FILE' -$! -$! Time To Clean Up The Object File. -$! -$ DELETE 'OBJECT_FILE';* -$! -$! Go Back And Get The Next File Name. -$! -$ GOTO NEXT_FILE -$! -$! All Done With This Library. -$! -$ FILE_DONE: -$! -$! Tell The User That We Are All Done. -$! -$ WRITE SYS$OUTPUT "Library ",SSL_LIB," Compiled." -$! -$! Time To RETURN. -$! -$ RETURN -$ SSL_TASK: -$! -$! Check To See If We Have The Proper Libraries. -$! -$ GOSUB LIB_CHECK -$! -$! Check To See If We Have A Linker Option File. -$! -$ GOSUB CHECK_OPT_FILE -$! -$! Check To See If The File We Want To Compile Is Actually There. -$! -$ IF (F$SEARCH("SYS$DISK:[]SSL_TASK.C").EQS."") -$ THEN -$! -$! Tell The User That The File Dosen't Exist. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The File SSL_TASK.C Dosen't Exist." -$ WRITE SYS$OUTPUT "" -$! -$! Exit The Build. -$! -$ EXIT -$! -$! End The SSL_TASK.C File Check. -$! -$ ENDIF -$! -$! Tell The User We Are Creating The SSL_TASK. -$! -$ WRITE SYS$OUTPUT "Creating SSL_TASK OSU HTTP SSL Engine." -$! -$! Compile The File. -$! -$ ON ERROR THEN GOTO SSL_TASK_END -$ CC5/OBJECT='OBJ_DIR'SSL_TASK.OBJ SYS$DISK:[]SSL_TASK.C -$! -$! Link The Program. -$! Check To See If We Are To Link With A Specific TCP/IP Library. -$! -$ IF (TCPIP_LIB.NES."") -$ THEN -$! -$! Link With TCP/IP Library. -$! -$ LINK/'DEBUGGER'/'TRACEBACK'/EXE='EXE_DIR'SSL_TASK.EXE - - 'OBJ_DIR'SSL_TASK.OBJ, - - 'SSL_LIB'/LIBRARY,'CRYPTO_LIB'/LIBRARY, - - 'TCPIP_LIB','OPT_FILE'/OPTION -$! -$! Else... -$! -$ ELSE -$! -$! Don't Link With TCP/IP Library. -$! -$ LINK/'DEBUGGER'/'TRACEBACK'/EXE='EXE_DIR'SSL_TASK.EXE - - 'OBJ_DIR'SSL_TASK.OBJ,- - 'SSL_LIB'/LIBRARY,'CRYPTO_LIB'/LIBRARY, - - 'OPT_FILE'/OPTION -$! -$! End The TCP/IP Library Check. -$! -$ ENDIF -$! -$! Time To Return. -$! -$SSL_TASK_END: -$ RETURN -$! -$! Check For The Link Option FIle. -$! -$ CHECK_OPT_FILE: -$! -$! Check To See If We Need To Make A VAX C Option File. -$! -$ IF (COMPILER.EQS."VAXC") -$ THEN -$! -$! Check To See If We Already Have A VAX C Linker Option File. -$! -$ IF (F$SEARCH(OPT_FILE).EQS."") -$ THEN -$! -$! We Need A VAX C Linker Option File. -$! -$ CREATE 'OPT_FILE' -$DECK -! -! Default System Options File To Link Agianst -! The Sharable VAX C Runtime Library. -! -SYS$SHARE:VAXCRTL.EXE/SHARE -$EOD -$! -$! End The Option File Check. -$! -$ ENDIF -$! -$! End The VAXC Check. -$! -$ ENDIF -$! -$! Check To See If We Need A GNU C Option File. -$! -$ IF (COMPILER.EQS."GNUC") -$ THEN -$! -$! Check To See If We Already Have A GNU C Linker Option File. -$! -$ IF (F$SEARCH(OPT_FILE).EQS."") -$ THEN -$! -$! We Need A GNU C Linker Option File. -$! -$ CREATE 'OPT_FILE' -$DECK -! -! Default System Options File To Link Agianst -! The Sharable C Runtime Library. -! -GNU_CC:[000000]GCCLIB/LIBRARY -SYS$SHARE:VAXCRTL/SHARE -$EOD -$! -$! End The Option File Check. -$! -$ ENDIF -$! -$! End The GNU C Check. -$! -$ ENDIF -$! -$! Check To See If We Need A DEC C Option File. -$! -$ IF (COMPILER.EQS."DECC") -$ THEN -$! -$! Check To See If We Already Have A DEC C Linker Option File. -$! -$ IF (F$SEARCH(OPT_FILE).EQS."") -$ THEN -$! -$! Figure Out If We Need A non-VAX Or A VAX Linker Option File. -$! -$ IF (ARCH.EQS."VAX") -$ THEN -$! -$! We Need A DEC C Linker Option File For VAX. -$! -$ CREATE 'OPT_FILE' -$DECK -! -! Default System Options File To Link Agianst -! The Sharable DEC C Runtime Library. -! -SYS$SHARE:DECC$SHR.EXE/SHARE -$EOD -$! -$! Else... -$! -$ ELSE -$! -$! Create The non-VAX Linker Option File. -$! -$ CREATE 'OPT_FILE' -$DECK -! -! Default System Options File For non-VAX To Link Agianst -! The Sharable C Runtime Library. -! -SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE -SYS$SHARE:CMA$OPEN_RTL/SHARE -$EOD -$! -$! End The DEC C Option File Check. -$! -$ ENDIF -$! -$! End The Option File Search. -$! -$ ENDIF -$! -$! End The DEC C Check. -$! -$ ENDIF -$! -$! Tell The User What Linker Option File We Are Using. -$! -$ WRITE SYS$OUTPUT "Using Linker Option File ",OPT_FILE,"." -$! -$! Time To RETURN. -$! -$ RETURN -$ LIB_CHECK: -$! -$! Look For The VAX Library LIBSSL.OLB. -$! -$ IF (F$SEARCH(SSL_LIB).EQS."") -$ THEN -$! -$! Tell The User We Can't Find The LIBSSL.OLB Library. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Can't Find The Library ",SSL_LIB,"." -$ WRITE SYS$OUTPUT "We Can't Link Without It." -$ WRITE SYS$OUTPUT "" -$! -$! Since We Can't Link Without It, Exit. -$! -$ EXIT -$! -$! End The LIBSSL.OLB Library Check. -$! -$ ENDIF -$! -$! Look For The Library LIBCRYPTO.OLB. -$! -$ IF (F$SEARCH(CRYPTO_LIB).EQS."") -$ THEN -$! -$! Tell The User We Can't Find The LIBCRYPTO.OLB Library. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Can't Find The Library ",CRYPTO_LIB,"." -$ WRITE SYS$OUTPUT "We Can't Link Without It." -$ WRITE SYS$OUTPUT "" -$! -$! Since We Can't Link Without It, Exit. -$! -$ EXIT -$! -$! End The LIBCRYPTO.OLB Library Check. -$! -$ ENDIF -$! -$! Time To Return. -$! -$ RETURN -$! -$! Check The User's Options. -$! -$ CHECK_OPTIONS: -$! -$! Check To See If P1 Is Blank. -$! -$ IF (P1.EQS."ALL") -$ THEN -$! -$! P1 Is Blank, So Build Everything. -$! -$ BUILDALL = "TRUE" -$! -$! Else... -$! -$ ELSE -$! -$! Else, Check To See If P1 Has A Valid Argument. -$! -$ IF (P1.EQS."LIBRARY").OR.(P1.EQS."SSL_TASK") -$ THEN -$! -$! A Valid Argument. -$! -$ BUILDALL = P1 -$! -$! Else... -$! -$ ELSE -$! -$! Tell The User We Don't Know What They Want. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " ALL : Just Build Everything." -$ WRITE SYS$OUTPUT " LIBRARY : To Compile Just The [.xxx.EXE.SSL]LIBSSL.OLB Library." -$ WRITE SYS$OUTPUT " SSL_TASK : To Compile Just The [.xxx.EXE.SSL]SSL_TASK.EXE Program." -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " ALPHA : Alpha Architecture." -$ WRITE SYS$OUTPUT " IA64 : IA64 Architecture." -$ WRITE SYS$OUTPUT " VAX : VAX Architecture." -$ WRITE SYS$OUTPUT "" -$! -$! Time To EXIT. -$! -$ EXIT -$! -$! End The Valid Argument Check. -$! -$ ENDIF -$! -$! End The P1 Check. -$! -$ ENDIF -$! -$! Check To See If P2 Is Blank. -$! -$ IF (P2.EQS."NODEBUG") -$ THEN -$! -$! P2 Is NODEBUG, So Compile Without Debugger Information. -$! -$ DEBUGGER = "NODEBUG" -$ TRACEBACK = "NOTRACEBACK" -$ GCC_OPTIMIZE = "OPTIMIZE" -$ CC_OPTIMIZE = "OPTIMIZE" -$ WRITE SYS$OUTPUT "No Debugger Information Will Be Produced During Compile." -$ WRITE SYS$OUTPUT "Compiling With Compiler Optimization." -$! -$! Else... -$! -$ ELSE -$! -$! Check To See If We Are To Compile With Debugger Information. -$! -$ IF (P2.EQS."DEBUG") -$ THEN -$! -$! Compile With Debugger Information. -$! -$ DEBUGGER = "DEBUG" -$ TRACEBACK = "TRACEBACK" -$ GCC_OPTIMIZE = "NOOPTIMIZE" -$ CC_OPTIMIZE = "NOOPTIMIZE" -$ WRITE SYS$OUTPUT "Debugger Information Will Be Produced During Compile." -$ WRITE SYS$OUTPUT "Compiling Without Compiler Optimization." -$ ELSE -$! -$! Tell The User Entered An Invalid Option.. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " DEBUG : Compile With The Debugger Information." -$ WRITE SYS$OUTPUT " NODEBUG : Compile Without The Debugger Information." -$ WRITE SYS$OUTPUT "" -$! -$! Time To EXIT. -$! -$ EXIT -$! -$! End The Valid Argument Check. -$! -$ ENDIF -$! -$! End The P2 Check. -$! -$ ENDIF -$! -$! Special Threads For OpenVMS v7.1 Or Later -$! -$! Written By: Richard Levitte -$! richard@levitte.org -$! -$! -$! Check To See If We Have A Option For P5. -$! -$ IF (P5.EQS."") -$ THEN -$! -$! Get The Version Of VMS We Are Using. -$! -$ ISSEVEN := -$ TMP = F$ELEMENT(0,"-",F$EXTRACT(1,4,F$GETSYI("VERSION"))) -$ TMP = F$INTEGER(F$ELEMENT(0,".",TMP)+F$ELEMENT(1,".",TMP)) -$! -$! Check To See If The VMS Version Is v7.1 Or Later. -$! -$ IF (TMP.GE.71) -$ THEN -$! -$! We Have OpenVMS v7.1 Or Later, So Use The Special Threads. -$! -$ ISSEVEN := ,PTHREAD_USE_D4 -$! -$! End The VMS Version Check. -$! -$ ENDIF -$! -$! End The P5 Check. -$! -$ ENDIF -$! -$! Check To See If P3 Is Blank. -$! -$ IF (P3.EQS."") -$ THEN -$! -$! O.K., The User Didn't Specify A Compiler, Let's Try To -$! Find Out Which One To Use. -$! -$! Check To See If We Have GNU C. -$! -$ IF (F$TRNLNM("GNU_CC").NES."") -$ THEN -$! -$! Looks Like GNUC, Set To Use GNUC. -$! -$ P3 = "GNUC" -$! -$! End The GNU C Compiler Check. -$! -$ ELSE -$! -$! Check To See If We Have VAXC Or DECC. -$! -$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."") -$ THEN -$! -$! Looks Like DECC, Set To Use DECC. -$! -$ P3 = "DECC" -$! -$! Else... -$! -$ ELSE -$! -$! Looks Like VAXC, Set To Use VAXC. -$! -$ P3 = "VAXC" -$! -$! End The VAXC Compiler Check. -$! -$ ENDIF -$! -$! End The DECC & VAXC Compiler Check. -$! -$ ENDIF -$! -$! End The Compiler Check. -$! -$ ENDIF -$! -$! Check To See If We Have A Option For P4. -$! -$ IF (P4.EQS."") -$ THEN -$! -$! Find out what socket library we have available -$! -$ IF F$PARSE("SOCKETSHR:") .NES. "" -$ THEN -$! -$! We have SOCKETSHR, and it is my opinion that it's the best to use. -$! -$ P4 = "SOCKETSHR" -$! -$! Tell the user -$! -$ WRITE SYS$OUTPUT "Using SOCKETSHR for TCP/IP" -$! -$! Else, let's look for something else -$! -$ ELSE -$! -$! Like UCX (the reason to do this before Multinet is that the UCX -$! emulation is easier to use...) -$! -$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" - - .OR. F$PARSE("SYS$SHARE:UCX$IPC_SHR.EXE") .NES. "" - - .OR. F$PARSE("SYS$LIBRARY:UCX$IPC.OLB") .NES. "" -$ THEN -$! -$! Last resort: a UCX or UCX-compatible library -$! -$ P4 = "UCX" -$! -$! Tell the user -$! -$ WRITE SYS$OUTPUT "Using UCX or an emulation thereof for TCP/IP" -$! -$! That was all... -$! -$ ENDIF -$ ENDIF -$ ENDIF -$! -$! Set Up Initial CC Definitions, Possibly With User Ones -$! -$ CCDEFS = "TCPIP_TYPE_''P4'" -$ IF F$TYPE(USER_CCDEFS) .NES. "" THEN CCDEFS = CCDEFS + "," + USER_CCDEFS -$ CCEXTRAFLAGS = "" -$ IF F$TYPE(USER_CCFLAGS) .NES. "" THEN CCEXTRAFLAGS = USER_CCFLAGS -$ CCDISABLEWARNINGS = "LONGLONGTYPE,LONGLONGSUFX,FOUNDCR" -$ IF F$TYPE(USER_CCDISABLEWARNINGS) .NES. "" THEN - - CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," + USER_CCDISABLEWARNINGS -$! -$! Check To See If The User Entered A Valid Paramter. -$! -$ IF (P3.EQS."VAXC").OR.(P3.EQS."DECC").OR.(P3.EQS."GNUC") -$ THEN -$! -$! Check To See If The User Wanted DECC. -$! -$ IF (P3.EQS."DECC") -$ THEN -$! -$! Looks Like DECC, Set To Use DECC. -$! -$ COMPILER = "DECC" -$! -$! Tell The User We Are Using DECC. -$! -$ WRITE SYS$OUTPUT "Using DECC 'C' Compiler." -$! -$! Use DECC... -$! -$ CC = "CC" -$ IF ARCH.EQS."VAX" .AND. F$TRNLNM("DECC$CC_DEFAULT").NES."/DECC" - - THEN CC = "CC/DECC" -$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/STANDARD=ANSI89" + - - "/NOLIST/PREFIX=ALL" + - - "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS -$! -$! Define The Linker Options File Name. -$! -$ OPT_FILE = "''EXE_DIR'VAX_DECC_OPTIONS.OPT" -$! -$! End DECC Check. -$! -$ ENDIF -$! -$! Check To See If We Are To Use VAXC. -$! -$ IF (P3.EQS."VAXC") -$ THEN -$! -$! Looks Like VAXC, Set To Use VAXC. -$! -$ COMPILER = "VAXC" -$! -$! Tell The User We Are Using VAX C. -$! -$ WRITE SYS$OUTPUT "Using VAXC 'C' Compiler." -$! -$! Compile Using VAXC. -$! -$ CC = "CC" -$ IF ARCH.NES."VAX" -$ THEN -$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!" -$ EXIT -$ ENDIF -$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC" -$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/NOLIST" + - - "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS -$ CCDEFS = CCDEFS + ",""VAXC""" -$! -$! Define <sys> As SYS$COMMON:[SYSLIB] -$! -$ DEFINE/NOLOG SYS SYS$COMMON:[SYSLIB] -$! -$! Define The Linker Options File Name. -$! -$ OPT_FILE = "''EXE_DIR'VAX_VAXC_OPTIONS.OPT" -$! -$! End VAXC Check -$! -$ ENDIF -$! -$! Check To See If We Are To Use GNU C. -$! -$ IF (P3.EQS."GNUC") -$ THEN -$! -$! Looks Like GNUC, Set To Use GNUC. -$! -$ COMPILER = "GNUC" -$! -$! Tell The User We Are Using GNUC. -$! -$ WRITE SYS$OUTPUT "Using GNU 'C' Compiler." -$! -$! Use GNU C... -$! -$ IF F$TYPE(GCC) .EQS. "" THEN GCC := GCC -$ CC = GCC+"/NOCASE_HACK/''GCC_OPTIMIZE'/''DEBUGGER'/NOLIST" + - - "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS -$! -$! Define The Linker Options File Name. -$! -$ OPT_FILE = "''EXE_DIR'VAX_GNUC_OPTIONS.OPT" -$! -$! End The GNU C Check. -$! -$ ENDIF -$! -$! Set up default defines -$! -$ CCDEFS = """FLAT_INC=1""," + CCDEFS -$! -$! Finish up the definition of CC. -$! -$ IF COMPILER .EQS. "DECC" -$ THEN -$ IF CCDISABLEWARNINGS .EQS. "" -$ THEN -$ CC4DISABLEWARNINGS = "DOLLARID" -$ ELSE -$ CC4DISABLEWARNINGS = CCDISABLEWARNINGS + ",DOLLARID" -$ CCDISABLEWARNINGS = "/WARNING=(DISABLE=(" + CCDISABLEWARNINGS + "))" -$ ENDIF -$ CC4DISABLEWARNINGS = "/WARNING=(DISABLE=(" + CC4DISABLEWARNINGS + "))" -$ ELSE -$ CCDISABLEWARNINGS = "" -$ CC4DISABLEWARNINGS = "" -$ ENDIF -$ CC2 = CC + "/DEFINE=(" + CCDEFS + ",_POSIX_C_SOURCE)" + CCDISABLEWARNINGS -$ CC3 = CC + "/DEFINE=(" + CCDEFS + ISSEVEN + ")" + CCDISABLEWARNINGS -$ CC = CC + "/DEFINE=(" + CCDEFS + ")" + CCDISABLEWARNINGS -$ IF COMPILER .EQS. "DECC" -$ THEN -$ CC4 = CC - CCDISABLEWARNINGS + CC4DISABLEWARNINGS -$ CC5 = CC3 - CCDISABLEWARNINGS + CC4DISABLEWARNINGS -$ ELSE -$ CC4 = CC -$ CC5 = CC3 -$ ENDIF -$! -$! Show user the result -$! -$ WRITE/SYMBOL SYS$OUTPUT "Main Compiling Command: ",CC -$! -$! Else The User Entered An Invalid Argument. -$! -$ ELSE -$! -$! Tell The User We Don't Know What They Want. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P3," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " VAXC : To Compile With VAX C." -$ WRITE SYS$OUTPUT " DECC : To Compile With DEC C." -$ WRITE SYS$OUTPUT " GNUC : To Compile With GNU C." -$ WRITE SYS$OUTPUT "" -$! -$! Time To EXIT. -$! -$ EXIT -$ ENDIF -$! -$! Time to check the contents, and to make sure we get the correct library. -$! -$ IF P4.EQS."SOCKETSHR" .OR. P4.EQS."MULTINET" .OR. P4.EQS."UCX" - - .OR. P4.EQS."TCPIP" .OR. P4.EQS."NONE" -$ THEN -$! -$! Check to see if SOCKETSHR was chosen -$! -$ IF P4.EQS."SOCKETSHR" -$ THEN -$! -$! Set the library to use SOCKETSHR -$! -$ TCPIP_LIB = "SYS$DISK:[-.VMS]SOCKETSHR_SHR.OPT/OPT" -$! -$! Done with SOCKETSHR -$! -$ ENDIF -$! -$! Check to see if MULTINET was chosen -$! -$ IF P4.EQS."MULTINET" -$ THEN -$! -$! Set the library to use UCX emulation. -$! -$ P4 = "UCX" -$! -$! Done with MULTINET -$! -$ ENDIF -$! -$! Check to see if UCX was chosen -$! -$ IF P4.EQS."UCX" -$ THEN -$! -$! Set the library to use UCX. -$! -$ TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_DECC.OPT/OPT" -$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" -$ THEN -$ TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_DECC_LOG.OPT/OPT" -$ ELSE -$ IF COMPILER .NES. "DECC" .AND. ARCH .EQS. "VAX" THEN - - TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_VAXC.OPT/OPT" -$ ENDIF -$! -$! Done with UCX -$! -$ ENDIF -$! -$! Check to see if TCPIP was chosen -$! -$ IF P4.EQS."TCPIP" -$ THEN -$! -$! Set the library to use TCPIP (post UCX). -$! -$ TCPIP_LIB = "SYS$DISK:[-.VMS]TCPIP_SHR_DECC.OPT/OPT" -$! -$! Done with TCPIP -$! -$ ENDIF -$! -$! Check to see if NONE was chosen -$! -$ IF P4.EQS."NONE" -$ THEN -$! -$! Do not use a TCPIP library. -$! -$ TCPIP_LIB = "" -$! -$! Done with NONE -$! -$ ENDIF -$! -$! Print info -$! -$ WRITE SYS$OUTPUT "TCP/IP library spec: ", TCPIP_LIB -$! -$! Else The User Entered An Invalid Argument. -$! -$ ELSE -$! -$! Tell The User We Don't Know What They Want. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P4," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " SOCKETSHR : To link with SOCKETSHR TCP/IP library." -$ WRITE SYS$OUTPUT " UCX : To link with UCX TCP/IP library." -$ WRITE SYS$OUTPUT " TCPIP : To link with TCPIP (post UCX) TCP/IP library." -$ WRITE SYS$OUTPUT "" -$! -$! Time To EXIT. -$! -$ EXIT -$! -$! Done with TCP/IP libraries -$! -$ ENDIF -$! -$! Time To RETURN... -$! -$ RETURN -$! -$ INITIALISE: -$! -$! Save old value of the logical name OPENSSL -$! -$ __SAVE_OPENSSL = F$TRNLNM("OPENSSL","LNM$PROCESS_TABLE") -$! -$! Save directory information -$! -$ __HERE = F$PARSE(F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"))-"A.;","[]A.;") - "A.;" -$ __HERE = F$EDIT(__HERE,"UPCASE") -$ __TOP = __HERE - "SSL]" -$ __INCLUDE = __TOP + "INCLUDE.OPENSSL]" -$! -$! Set up the logical name OPENSSL to point at the include directory -$! -$ DEFINE OPENSSL/NOLOG '__INCLUDE' -$! -$! Done -$! -$ RETURN -$! -$ CLEANUP: -$! -$! Restore the logical name OPENSSL if it had a value -$! -$ IF __SAVE_OPENSSL .EQS. "" -$ THEN -$ DEASSIGN OPENSSL -$ ELSE -$ DEFINE/NOLOG OPENSSL '__SAVE_OPENSSL' -$ ENDIF -$! -$! Done -$! -$ RETURN +$!
+$! SSL-LIB.COM
+$! Written By: Robert Byer
+$! Vice-President
+$! A-Com Computing, Inc.
+$! byer@mail.all-net.net
+$!
+$! Changes by Richard Levitte <richard@levitte.org>
+$!
+$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB"
+$! library for OpenSSL. The "xxx" denotes the machine architecture of
+$! ALPHA, IA64 or VAX.
+$!
+$! It is written to detect what type of machine you are compiling on
+$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC
+$! or GNU C) or you can specify which compiler to use.
+$!
+$! Specify the following as P1 to build just that part or ALL to just
+$! build everything.
+$!
+$! LIBRARY To just compile the [.xxx.EXE.SSL]LIBSSL.OLB Library.
+$! SSL_TASK To just compile the [.xxx.EXE.SSL]SSL_TASK.EXE
+$!
+$! Specify DEBUG or NODEBUG as P2 to compile with or without debugger
+$! information.
+$!
+$! Specify which compiler at P3 to try to compile under.
+$!
+$! VAXC For VAX C.
+$! DECC For DEC C.
+$! GNUC For GNU C.
+$!
+$! If you don't specify a compiler, it will try to determine which
+$! "C" compiler to use.
+$!
+$! P4, if defined, sets a TCP/IP library to use, through one of the following
+$! keywords:
+$!
+$! UCX for UCX
+$! TCPIP for TCPIP (post UCX)
+$! SOCKETSHR for SOCKETSHR+NETLIB
+$!
+$! P5, if defined, sets a compiler thread NOT needed on OpenVMS 7.1 (and up)
+$!
+$! For 64 bit architectures (Alpha and IA64), specify the pointer size as P6.
+$! For 32 bit architectures (VAX), P6 is ignored.
+$! Currently supported values are:
+$!
+$! 32 To ge a library compiled with /POINTER_SIZE=32
+$! 64 To ge a library compiled with /POINTER_SIZE=64
+$!
+$!
+$! Define A TCP/IP Library That We Will Need To Link To.
+$! (That Is, If We Need To Link To One.)
+$!
+$ TCPIP_LIB = ""
+$!
+$! Check What Architecture We Are Using.
+$!
+$ IF (F$GETSYI("CPU").LT.128)
+$ THEN
+$!
+$! The Architecture Is VAX.
+$!
+$ ARCH = "VAX"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! The Architecture Is Alpha, IA64 or whatever comes in the future.
+$!
+$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
+$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
+$!
+$! End The Architecture Check.
+$!
+$ ENDIF
+$!
+$! Define The OBJ Directory.
+$!
+$ OBJ_DIR := SYS$DISK:[-.'ARCH'.OBJ.SSL]
+$!
+$! Define The EXE Directory.
+$!
+$ EXE_DIR := SYS$DISK:[-.'ARCH'.EXE.SSL]
+$!
+$! Check To Make Sure We Have Valid Command Line Parameters.
+$!
+$ GOSUB CHECK_OPTIONS
+$!
+$! Initialise logical names and such
+$!
+$ GOSUB INITIALISE
+$!
+$! Tell The User What Kind of Machine We Run On.
+$!
+$ WRITE SYS$OUTPUT "Compiling On A ",ARCH," Machine."
+$!
+$! Check To See If The Architecture Specific OBJ Directory Exists.
+$!
+$ IF (F$PARSE(OBJ_DIR).EQS."")
+$ THEN
+$!
+$! It Dosen't Exist, So Create It.
+$!
+$ CREATE/DIR 'OBJ_DIR'
+$!
+$! End The Architecture Specific OBJ Directory Check.
+$!
+$ ENDIF
+$!
+$! Check To See If The Architecture Specific Directory Exists.
+$!
+$ IF (F$PARSE(EXE_DIR).EQS."")
+$ THEN
+$!
+$! It Dosen't Exist, So Create It.
+$!
+$ CREATE/DIR 'EXE_DIR'
+$!
+$! End The Architecture Specific Directory Check.
+$!
+$ ENDIF
+$!
+$! Define The Library Name.
+$!
+$ SSL_LIB := 'EXE_DIR'LIBSSL'LIB32'.OLB
+$!
+$! Define The CRYPTO-LIB We Are To Use.
+$!
+$ CRYPTO_LIB := SYS$DISK:[-.'ARCH'.EXE.CRYPTO]LIBCRYPTO'LIB32'.OLB
+$!
+$! Check To See What We Are To Do.
+$!
+$ IF (BUILDALL.EQS."TRUE")
+$ THEN
+$!
+$! Since Nothing Special Was Specified, Do Everything.
+$!
+$ GOSUB LIBRARY
+$ GOSUB SSL_TASK
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Build Just What The User Wants Us To Build.
+$!
+$ GOSUB 'BUILDALL'
+$!
+$! End The BUILDALL Check.
+$!
+$ ENDIF
+$!
+$! Time To EXIT.
+$!
+$ EXIT:
+$ GOSUB CLEANUP
+$ EXIT
+$!
+$! Compile The Library.
+$!
+$ LIBRARY:
+$!
+$! Check To See If We Already Have A "[.xxx.EXE.SSL]LIBSSL''LIB32'.OLB" Library...
+$!
+$ IF (F$SEARCH(SSL_LIB).EQS."")
+$ THEN
+$!
+$! Guess Not, Create The Library.
+$!
+$ LIBRARY/CREATE/OBJECT 'SSL_LIB'
+$!
+$! End The Library Exist Check.
+$!
+$ ENDIF
+$!
+$! Define The Different SSL "library" Files.
+$!
+$ LIB_SSL = "s2_meth,s2_srvr,s2_clnt,s2_lib,s2_enc,s2_pkt,"+ -
+ "s3_meth,s3_srvr,s3_clnt,s3_lib,s3_enc,s3_pkt,s3_both,"+ -
+ "s23_meth,s23_srvr,s23_clnt,s23_lib,s23_pkt,"+ -
+ "t1_meth,t1_srvr,t1_clnt,t1_lib,t1_enc,"+ -
+ "d1_meth,d1_srvr,d1_clnt,d1_lib,d1_pkt,"+ -
+ "d1_both,d1_enc,"+ -
+ "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ -
+ "ssl_ciph,ssl_stat,ssl_rsa,"+ -
+ "ssl_asn1,ssl_txt,ssl_algs,"+ -
+ "bio_ssl,ssl_err,kssl,t1_reneg"
+$!
+$! Tell The User That We Are Compiling The Library.
+$!
+$ WRITE SYS$OUTPUT "Building The ",SSL_LIB," Library."
+$!
+$! Define A File Counter And Set It To "0"
+$!
+$ FILE_COUNTER = 0
+$!
+$! Top Of The File Loop.
+$!
+$ NEXT_FILE:
+$!
+$! O.K, Extract The File Name From The File List.
+$!
+$ FILE_NAME = F$ELEMENT(FILE_COUNTER,",",LIB_SSL)
+$!
+$! Check To See If We Are At The End Of The File List.
+$!
+$ IF (FILE_NAME.EQS.",") THEN GOTO FILE_DONE
+$!
+$! Increment The Counter.
+$!
+$ FILE_COUNTER = FILE_COUNTER + 1
+$!
+$! Create The Source File Name.
+$!
+$ SOURCE_FILE = "SYS$DISK:[]" + FILE_NAME + ".C"
+$!
+$! Create The Object File Name.
+$!
+$ OBJECT_FILE = OBJ_DIR + FILE_NAME + ".OBJ"
+$ ON WARNING THEN GOTO NEXT_FILE
+$!
+$! Check To See If The File We Want To Compile Is Actually There.
+$!
+$ IF (F$SEARCH(SOURCE_FILE).EQS."")
+$ THEN
+$!
+$! Tell The User That The File Dosen't Exist.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The File ",SOURCE_FILE," Dosen't Exist."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Exit The Build.
+$!
+$ EXIT
+$!
+$! End The File Exists Check.
+$!
+$ ENDIF
+$!
+$! Tell The User What File We Are Compiling.
+$!
+$ WRITE SYS$OUTPUT " ",FILE_NAME,".c"
+$!
+$! Compile The File.
+$!
+$ ON ERROR THEN GOTO NEXT_FILE
+$ CC/OBJECT='OBJECT_FILE' 'SOURCE_FILE'
+$!
+$! Add It To The Library.
+$!
+$ LIBRARY/REPLACE/OBJECT 'SSL_LIB' 'OBJECT_FILE'
+$!
+$! Time To Clean Up The Object File.
+$!
+$ DELETE 'OBJECT_FILE';*
+$!
+$! Go Back And Get The Next File Name.
+$!
+$ GOTO NEXT_FILE
+$!
+$! All Done With This Library.
+$!
+$ FILE_DONE:
+$!
+$! Tell The User That We Are All Done.
+$!
+$ WRITE SYS$OUTPUT "Library ",SSL_LIB," Compiled."
+$!
+$! Time To RETURN.
+$!
+$ RETURN
+$ SSL_TASK:
+$!
+$! Check To See If We Have The Proper Libraries.
+$!
+$ GOSUB LIB_CHECK
+$!
+$! Check To See If We Have A Linker Option File.
+$!
+$ GOSUB CHECK_OPT_FILE
+$!
+$! Check To See If The File We Want To Compile Is Actually There.
+$!
+$ IF (F$SEARCH("SYS$DISK:[]SSL_TASK.C").EQS."")
+$ THEN
+$!
+$! Tell The User That The File Dosen't Exist.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The File SSL_TASK.C Dosen't Exist."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Exit The Build.
+$!
+$ EXIT
+$!
+$! End The SSL_TASK.C File Check.
+$!
+$ ENDIF
+$!
+$! Tell The User We Are Creating The SSL_TASK.
+$!
+$ WRITE SYS$OUTPUT "Creating SSL_TASK OSU HTTP SSL Engine."
+$!
+$! Compile The File.
+$!
+$ ON ERROR THEN GOTO SSL_TASK_END
+$ CC5/OBJECT='OBJ_DIR'SSL_TASK.OBJ SYS$DISK:[]SSL_TASK.C
+$!
+$! Link The Program.
+$! Check To See If We Are To Link With A Specific TCP/IP Library.
+$!
+$ IF (TCPIP_LIB.NES."")
+$ THEN
+$!
+$! Link With TCP/IP Library.
+$!
+$ LINK/'DEBUGGER'/'TRACEBACK'/EXE='EXE_DIR'SSL_TASK.EXE -
+ 'OBJ_DIR'SSL_TASK.OBJ, -
+ 'SSL_LIB'/LIBRARY,'CRYPTO_LIB'/LIBRARY, -
+ 'TCPIP_LIB','OPT_FILE'/OPTION
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Don't Link With TCP/IP Library.
+$!
+$ LINK/'DEBUGGER'/'TRACEBACK'/EXE='EXE_DIR'SSL_TASK.EXE -
+ 'OBJ_DIR'SSL_TASK.OBJ,-
+ 'SSL_LIB'/LIBRARY,'CRYPTO_LIB'/LIBRARY, -
+ 'OPT_FILE'/OPTION
+$!
+$! End The TCP/IP Library Check.
+$!
+$ ENDIF
+$!
+$! Time To Return.
+$!
+$SSL_TASK_END:
+$ RETURN
+$!
+$! Check For The Link Option FIle.
+$!
+$ CHECK_OPT_FILE:
+$!
+$! Check To See If We Need To Make A VAX C Option File.
+$!
+$ IF (COMPILER.EQS."VAXC")
+$ THEN
+$!
+$! Check To See If We Already Have A VAX C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! We Need A VAX C Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Agianst
+! The Sharable VAX C Runtime Library.
+!
+SYS$SHARE:VAXCRTL.EXE/SHARE
+$EOD
+$!
+$! End The Option File Check.
+$!
+$ ENDIF
+$!
+$! End The VAXC Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Need A GNU C Option File.
+$!
+$ IF (COMPILER.EQS."GNUC")
+$ THEN
+$!
+$! Check To See If We Already Have A GNU C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! We Need A GNU C Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Agianst
+! The Sharable C Runtime Library.
+!
+GNU_CC:[000000]GCCLIB/LIBRARY
+SYS$SHARE:VAXCRTL/SHARE
+$EOD
+$!
+$! End The Option File Check.
+$!
+$ ENDIF
+$!
+$! End The GNU C Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Need A DEC C Option File.
+$!
+$ IF (COMPILER.EQS."DECC")
+$ THEN
+$!
+$! Check To See If We Already Have A DEC C Linker Option File.
+$!
+$ IF (F$SEARCH(OPT_FILE).EQS."")
+$ THEN
+$!
+$! Figure Out If We Need A non-VAX Or A VAX Linker Option File.
+$!
+$ IF (ARCH.EQS."VAX")
+$ THEN
+$!
+$! We Need A DEC C Linker Option File For VAX.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File To Link Agianst
+! The Sharable DEC C Runtime Library.
+!
+SYS$SHARE:DECC$SHR.EXE/SHARE
+$EOD
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Create The non-VAX Linker Option File.
+$!
+$ CREATE 'OPT_FILE'
+$DECK
+!
+! Default System Options File For non-VAX To Link Agianst
+! The Sharable C Runtime Library.
+!
+SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE
+SYS$SHARE:CMA$OPEN_RTL/SHARE
+$EOD
+$!
+$! End The DEC C Option File Check.
+$!
+$ ENDIF
+$!
+$! End The Option File Search.
+$!
+$ ENDIF
+$!
+$! End The DEC C Check.
+$!
+$ ENDIF
+$!
+$! Tell The User What Linker Option File We Are Using.
+$!
+$ WRITE SYS$OUTPUT "Using Linker Option File ",OPT_FILE,"."
+$!
+$! Time To RETURN.
+$!
+$ RETURN
+$ LIB_CHECK:
+$!
+$! Look For The VAX Library LIBSSL.OLB.
+$!
+$ IF (F$SEARCH(SSL_LIB).EQS."")
+$ THEN
+$!
+$! Tell The User We Can't Find The LIBSSL.OLB Library.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "Can't Find The Library ",SSL_LIB,"."
+$ WRITE SYS$OUTPUT "We Can't Link Without It."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Since We Can't Link Without It, Exit.
+$!
+$ EXIT
+$!
+$! End The LIBSSL.OLB Library Check.
+$!
+$ ENDIF
+$!
+$! Look For The Library LIBCRYPTO.OLB.
+$!
+$ IF (F$SEARCH(CRYPTO_LIB).EQS."")
+$ THEN
+$!
+$! Tell The User We Can't Find The LIBCRYPTO.OLB Library.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "Can't Find The Library ",CRYPTO_LIB,"."
+$ WRITE SYS$OUTPUT "We Can't Link Without It."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Since We Can't Link Without It, Exit.
+$!
+$ EXIT
+$!
+$! End The LIBCRYPTO.OLB Library Check.
+$!
+$ ENDIF
+$!
+$! Time To Return.
+$!
+$ RETURN
+$!
+$! Check The User's Options.
+$!
+$ CHECK_OPTIONS:
+$!
+$! Check To See If P1 Is Blank.
+$!
+$ IF (P1.EQS."ALL")
+$ THEN
+$!
+$! P1 Is Blank, So Build Everything.
+$!
+$ BUILDALL = "TRUE"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Else, Check To See If P1 Has A Valid Argument.
+$!
+$ IF (P1.EQS."LIBRARY").OR.(P1.EQS."SSL_TASK")
+$ THEN
+$!
+$! A Valid Argument.
+$!
+$ BUILDALL = P1
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " ALL : Just Build Everything."
+$ WRITE SYS$OUTPUT " LIBRARY : To Compile Just The [.xxx.EXE.SSL]LIBSSL.OLB Library."
+$ WRITE SYS$OUTPUT " SSL_TASK : To Compile Just The [.xxx.EXE.SSL]SSL_TASK.EXE Program."
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " ALPHA : Alpha Architecture."
+$ WRITE SYS$OUTPUT " IA64 : IA64 Architecture."
+$ WRITE SYS$OUTPUT " VAX : VAX Architecture."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! End The Valid Argument Check.
+$!
+$ ENDIF
+$!
+$! End The P1 Check.
+$!
+$ ENDIF
+$!
+$! Check To See If P2 Is Blank.
+$!
+$ IF (P2.EQS."NODEBUG")
+$ THEN
+$!
+$! P2 Is NODEBUG, So Compile Without Debugger Information.
+$!
+$ DEBUGGER = "NODEBUG"
+$ TRACEBACK = "NOTRACEBACK"
+$ GCC_OPTIMIZE = "OPTIMIZE"
+$ CC_OPTIMIZE = "OPTIMIZE"
+$ WRITE SYS$OUTPUT "No Debugger Information Will Be Produced During Compile."
+$ WRITE SYS$OUTPUT "Compiling With Compiler Optimization."
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Check To See If We Are To Compile With Debugger Information.
+$!
+$ IF (P2.EQS."DEBUG")
+$ THEN
+$!
+$! Compile With Debugger Information.
+$!
+$ DEBUGGER = "DEBUG"
+$ TRACEBACK = "TRACEBACK"
+$ GCC_OPTIMIZE = "NOOPTIMIZE"
+$ CC_OPTIMIZE = "NOOPTIMIZE"
+$ WRITE SYS$OUTPUT "Debugger Information Will Be Produced During Compile."
+$ WRITE SYS$OUTPUT "Compiling Without Compiler Optimization."
+$ ELSE
+$!
+$! Tell The User Entered An Invalid Option..
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " DEBUG : Compile With The Debugger Information."
+$ WRITE SYS$OUTPUT " NODEBUG : Compile Without The Debugger Information."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! End The Valid Argument Check.
+$!
+$ ENDIF
+$!
+$! End The P2 Check.
+$!
+$ ENDIF
+$!
+$! Special Threads For OpenVMS v7.1 Or Later
+$!
+$! Written By: Richard Levitte
+$! richard@levitte.org
+$!
+$!
+$! Check To See If We Have A Option For P5.
+$!
+$ IF (P5.EQS."")
+$ THEN
+$!
+$! Get The Version Of VMS We Are Using.
+$!
+$ ISSEVEN :=
+$ TMP = F$ELEMENT(0,"-",F$EXTRACT(1,4,F$GETSYI("VERSION")))
+$ TMP = F$INTEGER(F$ELEMENT(0,".",TMP)+F$ELEMENT(1,".",TMP))
+$!
+$! Check To See If The VMS Version Is v7.1 Or Later.
+$!
+$ IF (TMP.GE.71)
+$ THEN
+$!
+$! We Have OpenVMS v7.1 Or Later, So Use The Special Threads.
+$!
+$ ISSEVEN := ,PTHREAD_USE_D4
+$!
+$! End The VMS Version Check.
+$!
+$ ENDIF
+$!
+$! End The P5 Check.
+$!
+$ ENDIF
+$!
+$! Check To See If P6 Is Blank.
+$!
+$ IF (P6.EQS."")
+$ THEN
+$ POINTER_SIZE = ""
+$ ELSE
+$!
+$! Check is P6 Is Valid
+$!
+$ IF (P6.EQS."32")
+$ THEN
+$ POINTER_SIZE = "/POINTER_SIZE=32"
+$ IF ARCH .EQS. "VAX"
+$ THEN
+$ LIB32 = ""
+$ ELSE
+$ LIB32 = "32"
+$ ENDIF
+$ ELSE
+$ IF (P6.EQS."64")
+$ THEN
+$ LIB32 = ""
+$ IF ARCH .EQS. "VAX"
+$ THEN
+$ POINTER_SIZE = "/POINTER_SIZE=32"
+$ ELSE
+$ POINTER_SIZE = "/POINTER_SIZE=64"
+$ ENDIF
+$ ELSE
+$!
+$! Tell The User Entered An Invalid Option..
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P6," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " 32 : Compile with 32 bit pointer size"
+$ WRITE SYS$OUTPUT " 64 : Compile with 64 bit pointer size"
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ GOTO TIDY
+$!
+$! End The Valid Arguement Check.
+$!
+$ ENDIF
+$ ENDIF
+$!
+$! End The P6 Check.
+$!
+$ ENDIF
+$!
+$! Check To See If P3 Is Blank.
+$!
+$ IF (P3.EQS."")
+$ THEN
+$!
+$! O.K., The User Didn't Specify A Compiler, Let's Try To
+$! Find Out Which One To Use.
+$!
+$! Check To See If We Have GNU C.
+$!
+$ IF (F$TRNLNM("GNU_CC").NES."")
+$ THEN
+$!
+$! Looks Like GNUC, Set To Use GNUC.
+$!
+$ P3 = "GNUC"
+$!
+$! End The GNU C Compiler Check.
+$!
+$ ELSE
+$!
+$! Check To See If We Have VAXC Or DECC.
+$!
+$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."")
+$ THEN
+$!
+$! Looks Like DECC, Set To Use DECC.
+$!
+$ P3 = "DECC"
+$!
+$! Else...
+$!
+$ ELSE
+$!
+$! Looks Like VAXC, Set To Use VAXC.
+$!
+$ P3 = "VAXC"
+$!
+$! End The VAXC Compiler Check.
+$!
+$ ENDIF
+$!
+$! End The DECC & VAXC Compiler Check.
+$!
+$ ENDIF
+$!
+$! End The Compiler Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Have A Option For P4.
+$!
+$ IF (P4.EQS."")
+$ THEN
+$!
+$! Find out what socket library we have available
+$!
+$ IF F$PARSE("SOCKETSHR:") .NES. ""
+$ THEN
+$!
+$! We have SOCKETSHR, and it is my opinion that it's the best to use.
+$!
+$ P4 = "SOCKETSHR"
+$!
+$! Tell the user
+$!
+$ WRITE SYS$OUTPUT "Using SOCKETSHR for TCP/IP"
+$!
+$! Else, let's look for something else
+$!
+$ ELSE
+$!
+$! Like UCX (the reason to do this before Multinet is that the UCX
+$! emulation is easier to use...)
+$!
+$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" -
+ .OR. F$PARSE("SYS$SHARE:UCX$IPC_SHR.EXE") .NES. "" -
+ .OR. F$PARSE("SYS$LIBRARY:UCX$IPC.OLB") .NES. ""
+$ THEN
+$!
+$! Last resort: a UCX or UCX-compatible library
+$!
+$ P4 = "UCX"
+$!
+$! Tell the user
+$!
+$ WRITE SYS$OUTPUT "Using UCX or an emulation thereof for TCP/IP"
+$!
+$! That was all...
+$!
+$ ENDIF
+$ ENDIF
+$ ENDIF
+$!
+$! Set Up Initial CC Definitions, Possibly With User Ones
+$!
+$ CCDEFS = "TCPIP_TYPE_''P4'"
+$ IF F$TYPE(USER_CCDEFS) .NES. "" THEN CCDEFS = CCDEFS + "," + USER_CCDEFS
+$ CCEXTRAFLAGS = ""
+$ IF F$TYPE(USER_CCFLAGS) .NES. "" THEN CCEXTRAFLAGS = USER_CCFLAGS
+$ CCDISABLEWARNINGS = "LONGLONGTYPE,LONGLONGSUFX,FOUNDCR"
+$ IF F$TYPE(USER_CCDISABLEWARNINGS) .NES. "" THEN -
+ CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," + USER_CCDISABLEWARNINGS
+$!
+$! Check To See If The User Entered A Valid Paramter.
+$!
+$ IF (P3.EQS."VAXC").OR.(P3.EQS."DECC").OR.(P3.EQS."GNUC")
+$ THEN
+$!
+$! Check To See If The User Wanted DECC.
+$!
+$ IF (P3.EQS."DECC")
+$ THEN
+$!
+$! Looks Like DECC, Set To Use DECC.
+$!
+$ COMPILER = "DECC"
+$!
+$! Tell The User We Are Using DECC.
+$!
+$ WRITE SYS$OUTPUT "Using DECC 'C' Compiler."
+$!
+$! Use DECC...
+$!
+$ CC = "CC"
+$ IF ARCH.EQS."VAX" .AND. F$TRNLNM("DECC$CC_DEFAULT").NES."/DECC" -
+ THEN CC = "CC/DECC"
+$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/STANDARD=ANSI89''POINTER_SIZE'" + -
+ "/NOLIST/PREFIX=ALL" + -
+ "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "''EXE_DIR'VAX_DECC_OPTIONS.OPT"
+$!
+$! End DECC Check.
+$!
+$ ENDIF
+$!
+$! Check To See If We Are To Use VAXC.
+$!
+$ IF (P3.EQS."VAXC")
+$ THEN
+$!
+$! Looks Like VAXC, Set To Use VAXC.
+$!
+$ COMPILER = "VAXC"
+$!
+$! Tell The User We Are Using VAX C.
+$!
+$ WRITE SYS$OUTPUT "Using VAXC 'C' Compiler."
+$!
+$! Compile Using VAXC.
+$!
+$ CC = "CC"
+$ IF ARCH.NES."VAX"
+$ THEN
+$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!"
+$ EXIT
+$ ENDIF
+$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC"
+$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
+ "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS
+$ CCDEFS = CCDEFS + ",""VAXC"""
+$!
+$! Define <sys> As SYS$COMMON:[SYSLIB]
+$!
+$ DEFINE/NOLOG SYS SYS$COMMON:[SYSLIB]
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "''EXE_DIR'VAX_VAXC_OPTIONS.OPT"
+$!
+$! End VAXC Check
+$!
+$ ENDIF
+$!
+$! Check To See If We Are To Use GNU C.
+$!
+$ IF (P3.EQS."GNUC")
+$ THEN
+$!
+$! Looks Like GNUC, Set To Use GNUC.
+$!
+$ COMPILER = "GNUC"
+$!
+$! Tell The User We Are Using GNUC.
+$!
+$ WRITE SYS$OUTPUT "Using GNU 'C' Compiler."
+$!
+$! Use GNU C...
+$!
+$ IF F$TYPE(GCC) .EQS. "" THEN GCC := GCC
+$ CC = GCC+"/NOCASE_HACK/''GCC_OPTIMIZE'/''DEBUGGER'/NOLIST" + -
+ "/INCLUDE=(SYS$DISK:[-.CRYPTO],SYS$DISK:[-])" + CCEXTRAFLAGS
+$!
+$! Define The Linker Options File Name.
+$!
+$ OPT_FILE = "''EXE_DIR'VAX_GNUC_OPTIONS.OPT"
+$!
+$! End The GNU C Check.
+$!
+$ ENDIF
+$!
+$! Set up default defines
+$!
+$ CCDEFS = """FLAT_INC=1""," + CCDEFS
+$!
+$! Finish up the definition of CC.
+$!
+$ IF COMPILER .EQS. "DECC"
+$ THEN
+$ IF CCDISABLEWARNINGS .EQS. ""
+$ THEN
+$ CC4DISABLEWARNINGS = "DOLLARID"
+$ ELSE
+$ CC4DISABLEWARNINGS = CCDISABLEWARNINGS + ",DOLLARID"
+$ CCDISABLEWARNINGS = "/WARNING=(DISABLE=(" + CCDISABLEWARNINGS + "))"
+$ ENDIF
+$ CC4DISABLEWARNINGS = "/WARNING=(DISABLE=(" + CC4DISABLEWARNINGS + "))"
+$ ELSE
+$ CCDISABLEWARNINGS = ""
+$ CC4DISABLEWARNINGS = ""
+$ ENDIF
+$ CC2 = CC + "/DEFINE=(" + CCDEFS + ",_POSIX_C_SOURCE)" + CCDISABLEWARNINGS
+$ CC3 = CC + "/DEFINE=(" + CCDEFS + ISSEVEN + ")" + CCDISABLEWARNINGS
+$ CC = CC + "/DEFINE=(" + CCDEFS + ")" + CCDISABLEWARNINGS
+$ IF COMPILER .EQS. "DECC"
+$ THEN
+$ CC4 = CC - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
+$ CC5 = CC3 - CCDISABLEWARNINGS + CC4DISABLEWARNINGS
+$ ELSE
+$ CC4 = CC
+$ CC5 = CC3
+$ ENDIF
+$!
+$! Show user the result
+$!
+$ WRITE/SYMBOL SYS$OUTPUT "Main Compiling Command: ",CC
+$!
+$! Else The User Entered An Invalid Argument.
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P3," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " VAXC : To Compile With VAX C."
+$ WRITE SYS$OUTPUT " DECC : To Compile With DEC C."
+$ WRITE SYS$OUTPUT " GNUC : To Compile With GNU C."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$ ENDIF
+$!
+$! Time to check the contents, and to make sure we get the correct library.
+$!
+$ IF P4.EQS."SOCKETSHR" .OR. P4.EQS."MULTINET" .OR. P4.EQS."UCX" -
+ .OR. P4.EQS."TCPIP" .OR. P4.EQS."NONE"
+$ THEN
+$!
+$! Check to see if SOCKETSHR was chosen
+$!
+$ IF P4.EQS."SOCKETSHR"
+$ THEN
+$!
+$! Set the library to use SOCKETSHR
+$!
+$ TCPIP_LIB = "SYS$DISK:[-.VMS]SOCKETSHR_SHR.OPT/OPT"
+$!
+$! Done with SOCKETSHR
+$!
+$ ENDIF
+$!
+$! Check to see if MULTINET was chosen
+$!
+$ IF P4.EQS."MULTINET"
+$ THEN
+$!
+$! Set the library to use UCX emulation.
+$!
+$ P4 = "UCX"
+$!
+$! Done with MULTINET
+$!
+$ ENDIF
+$!
+$! Check to see if UCX was chosen
+$!
+$ IF P4.EQS."UCX"
+$ THEN
+$!
+$! Set the library to use UCX.
+$!
+$ TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_DECC.OPT/OPT"
+$ IF F$TRNLNM("UCX$IPC_SHR") .NES. ""
+$ THEN
+$ TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_DECC_LOG.OPT/OPT"
+$ ELSE
+$ IF COMPILER .NES. "DECC" .AND. ARCH .EQS. "VAX" THEN -
+ TCPIP_LIB = "SYS$DISK:[-.VMS]UCX_SHR_VAXC.OPT/OPT"
+$ ENDIF
+$!
+$! Done with UCX
+$!
+$ ENDIF
+$!
+$! Check to see if TCPIP was chosen
+$!
+$ IF P4.EQS."TCPIP"
+$ THEN
+$!
+$! Set the library to use TCPIP (post UCX).
+$!
+$ TCPIP_LIB = "SYS$DISK:[-.VMS]TCPIP_SHR_DECC.OPT/OPT"
+$!
+$! Done with TCPIP
+$!
+$ ENDIF
+$!
+$! Check to see if NONE was chosen
+$!
+$ IF P4.EQS."NONE"
+$ THEN
+$!
+$! Do not use a TCPIP library.
+$!
+$ TCPIP_LIB = ""
+$!
+$! Done with NONE
+$!
+$ ENDIF
+$!
+$! Print info
+$!
+$ WRITE SYS$OUTPUT "TCP/IP library spec: ", TCPIP_LIB
+$!
+$! Else The User Entered An Invalid Argument.
+$!
+$ ELSE
+$!
+$! Tell The User We Don't Know What They Want.
+$!
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT "The Option ",P4," Is Invalid. The Valid Options Are:"
+$ WRITE SYS$OUTPUT ""
+$ WRITE SYS$OUTPUT " SOCKETSHR : To link with SOCKETSHR TCP/IP library."
+$ WRITE SYS$OUTPUT " UCX : To link with UCX TCP/IP library."
+$ WRITE SYS$OUTPUT " TCPIP : To link with TCPIP (post UCX) TCP/IP library."
+$ WRITE SYS$OUTPUT ""
+$!
+$! Time To EXIT.
+$!
+$ EXIT
+$!
+$! Done with TCP/IP libraries
+$!
+$ ENDIF
+$!
+$! Time To RETURN...
+$!
+$ RETURN
+$!
+$ INITIALISE:
+$!
+$! Save old value of the logical name OPENSSL
+$!
+$ __SAVE_OPENSSL = F$TRNLNM("OPENSSL","LNM$PROCESS_TABLE")
+$!
+$! Save directory information
+$!
+$ __HERE = F$PARSE(F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"))-"A.;","[]A.;") - "A.;"
+$ __HERE = F$EDIT(__HERE,"UPCASE")
+$ __TOP = __HERE - "SSL]"
+$ __INCLUDE = __TOP + "INCLUDE.OPENSSL]"
+$!
+$! Set up the logical name OPENSSL to point at the include directory
+$!
+$ DEFINE OPENSSL/NOLOG '__INCLUDE'
+$!
+$! Done
+$!
+$ RETURN
+$!
+$ CLEANUP:
+$!
+$! Restore the logical name OPENSSL if it had a value
+$!
+$ IF __SAVE_OPENSSL .EQS. ""
+$ THEN
+$ DEASSIGN OPENSSL
+$ ELSE
+$ DEFINE/NOLOG OPENSSL '__SAVE_OPENSSL'
+$ ENDIF
+$!
+$! Done
+$!
+$ RETURN
diff --git a/openssl/ssl/t1_lib.c b/openssl/ssl/t1_lib.c index 5cdd7e572..1ebad6166 100644 --- a/openssl/ssl/t1_lib.c +++ b/openssl/ssl/t1_lib.c @@ -1,1741 +1,1747 @@ -/* ssl/t1_lib.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-2007 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 <stdio.h> -#include <openssl/objects.h> -#include <openssl/evp.h> -#include <openssl/hmac.h> -#include <openssl/ocsp.h> -#include "ssl_locl.h" - -const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; - -#ifndef OPENSSL_NO_TLSEXT -static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen, - const unsigned char *sess_id, int sesslen, - SSL_SESSION **psess); -#endif - -SSL3_ENC_METHOD TLSv1_enc_data={ - tls1_enc, - tls1_mac, - tls1_setup_key_block, - tls1_generate_master_secret, - tls1_change_cipher_state, - tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, - tls1_cert_verify_mac, - TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, - TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, - tls1_alert_code, - }; - -long tls1_default_timeout(void) - { - /* 2 hours, the 24 hours mentioned in the TLSv1 spec - * is way too long for http, the cache would over fill */ - return(60*60*2); - } - -int tls1_new(SSL *s) - { - if (!ssl3_new(s)) return(0); - s->method->ssl_clear(s); - return(1); - } - -void tls1_free(SSL *s) - { -#ifndef OPENSSL_NO_TLSEXT - if (s->tlsext_session_ticket) - { - OPENSSL_free(s->tlsext_session_ticket); - } -#endif /* OPENSSL_NO_TLSEXT */ - ssl3_free(s); - } - -void tls1_clear(SSL *s) - { - ssl3_clear(s); - s->version=TLS1_VERSION; - } - -#ifndef OPENSSL_NO_EC -static int nid_list[] = - { - NID_sect163k1, /* sect163k1 (1) */ - NID_sect163r1, /* sect163r1 (2) */ - NID_sect163r2, /* sect163r2 (3) */ - NID_sect193r1, /* sect193r1 (4) */ - NID_sect193r2, /* sect193r2 (5) */ - NID_sect233k1, /* sect233k1 (6) */ - NID_sect233r1, /* sect233r1 (7) */ - NID_sect239k1, /* sect239k1 (8) */ - NID_sect283k1, /* sect283k1 (9) */ - NID_sect283r1, /* sect283r1 (10) */ - NID_sect409k1, /* sect409k1 (11) */ - NID_sect409r1, /* sect409r1 (12) */ - NID_sect571k1, /* sect571k1 (13) */ - NID_sect571r1, /* sect571r1 (14) */ - NID_secp160k1, /* secp160k1 (15) */ - NID_secp160r1, /* secp160r1 (16) */ - NID_secp160r2, /* secp160r2 (17) */ - NID_secp192k1, /* secp192k1 (18) */ - NID_X9_62_prime192v1, /* secp192r1 (19) */ - NID_secp224k1, /* secp224k1 (20) */ - NID_secp224r1, /* secp224r1 (21) */ - NID_secp256k1, /* secp256k1 (22) */ - NID_X9_62_prime256v1, /* secp256r1 (23) */ - NID_secp384r1, /* secp384r1 (24) */ - NID_secp521r1 /* secp521r1 (25) */ - }; - -int tls1_ec_curve_id2nid(int curve_id) - { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ - if ((curve_id < 1) || ((unsigned int)curve_id > - sizeof(nid_list)/sizeof(nid_list[0]))) - return 0; - return nid_list[curve_id-1]; - } - -int tls1_ec_nid2curve_id(int nid) - { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ - switch (nid) - { - case NID_sect163k1: /* sect163k1 (1) */ - return 1; - case NID_sect163r1: /* sect163r1 (2) */ - return 2; - case NID_sect163r2: /* sect163r2 (3) */ - return 3; - case NID_sect193r1: /* sect193r1 (4) */ - return 4; - case NID_sect193r2: /* sect193r2 (5) */ - return 5; - case NID_sect233k1: /* sect233k1 (6) */ - return 6; - case NID_sect233r1: /* sect233r1 (7) */ - return 7; - case NID_sect239k1: /* sect239k1 (8) */ - return 8; - case NID_sect283k1: /* sect283k1 (9) */ - return 9; - case NID_sect283r1: /* sect283r1 (10) */ - return 10; - case NID_sect409k1: /* sect409k1 (11) */ - return 11; - case NID_sect409r1: /* sect409r1 (12) */ - return 12; - case NID_sect571k1: /* sect571k1 (13) */ - return 13; - case NID_sect571r1: /* sect571r1 (14) */ - return 14; - case NID_secp160k1: /* secp160k1 (15) */ - return 15; - case NID_secp160r1: /* secp160r1 (16) */ - return 16; - case NID_secp160r2: /* secp160r2 (17) */ - return 17; - case NID_secp192k1: /* secp192k1 (18) */ - return 18; - case NID_X9_62_prime192v1: /* secp192r1 (19) */ - return 19; - case NID_secp224k1: /* secp224k1 (20) */ - return 20; - case NID_secp224r1: /* secp224r1 (21) */ - return 21; - case NID_secp256k1: /* secp256k1 (22) */ - return 22; - case NID_X9_62_prime256v1: /* secp256r1 (23) */ - return 23; - case NID_secp384r1: /* secp384r1 (24) */ - return 24; - case NID_secp521r1: /* secp521r1 (25) */ - return 25; - default: - return 0; - } - } -#endif /* OPENSSL_NO_EC */ - -#ifndef OPENSSL_NO_TLSEXT -unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) - { - int extdatalen=0; - unsigned char *ret = p; - - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (s->client_version == SSL3_VERSION - && !s->s3->send_connection_binding) - return p; - - ret+=2; - - if (ret>=limit) return NULL; /* this really never occurs, but ... */ - - if (s->tlsext_hostname != NULL) - { - /* Add TLS extension servername to the Client Hello message */ - unsigned long size_str; - long lenmax; - - /* check for enough space. - 4 for the servername type and entension length - 2 for servernamelist length - 1 for the hostname type - 2 for hostname length - + hostname length - */ - - if ((lenmax = limit - ret - 9) < 0 - || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) - return NULL; - - /* extension type and length */ - s2n(TLSEXT_TYPE_server_name,ret); - s2n(size_str+5,ret); - - /* length of servername list */ - s2n(size_str+3,ret); - - /* hostname type, length and hostname */ - *(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name; - s2n(size_str,ret); - memcpy(ret, s->tlsext_hostname, size_str); - ret+=size_str; - } - - /* Add RI if renegotiating */ - if (s->new_session) - { - int el; - - if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) - { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - if((limit - p - 4 - el) < 0) return NULL; - - s2n(TLSEXT_TYPE_renegotiate,ret); - s2n(el,ret); - - if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) - { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - ret += el; - } - -#ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist != NULL && - s->version != DTLS1_VERSION) - { - /* Add TLS extension ECPointFormats to the ClientHello message */ - long lenmax; - - if ((lenmax = limit - ret - 5) < 0) return NULL; - if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; - if (s->tlsext_ecpointformatlist_length > 255) - { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - s2n(TLSEXT_TYPE_ec_point_formats,ret); - s2n(s->tlsext_ecpointformatlist_length + 1,ret); - *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length; - memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); - ret+=s->tlsext_ecpointformatlist_length; - } - if (s->tlsext_ellipticcurvelist != NULL && - s->version != DTLS1_VERSION) - { - /* Add TLS extension EllipticCurves to the ClientHello message */ - long lenmax; - - if ((lenmax = limit - ret - 6) < 0) return NULL; - if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; - if (s->tlsext_ellipticcurvelist_length > 65532) - { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - s2n(TLSEXT_TYPE_elliptic_curves,ret); - s2n(s->tlsext_ellipticcurvelist_length + 2, ret); - - /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for - * elliptic_curve_list, but the examples use two bytes. - * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html - * resolves this to two bytes. - */ - s2n(s->tlsext_ellipticcurvelist_length, ret); - memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); - ret+=s->tlsext_ellipticcurvelist_length; - } -#endif /* OPENSSL_NO_EC */ - - if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) - { - int ticklen; - if (!s->new_session && s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; - else if (s->session && s->tlsext_session_ticket && - s->tlsext_session_ticket->data) - { - ticklen = s->tlsext_session_ticket->length; - s->session->tlsext_tick = OPENSSL_malloc(ticklen); - if (!s->session->tlsext_tick) - return NULL; - memcpy(s->session->tlsext_tick, - s->tlsext_session_ticket->data, - ticklen); - s->session->tlsext_ticklen = ticklen; - } - else - ticklen = 0; - if (ticklen == 0 && s->tlsext_session_ticket && - s->tlsext_session_ticket->data == NULL) - goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ - if ((long)(limit - ret - 4 - ticklen) < 0) return NULL; - s2n(TLSEXT_TYPE_session_ticket,ret); - s2n(ticklen,ret); - if (ticklen) - { - memcpy(ret, s->session->tlsext_tick, ticklen); - ret += ticklen; - } - } - skip_ext: - -#ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->client_opaque_prf_input != NULL && - s->version != DTLS1_VERSION) - { - size_t col = s->s3->client_opaque_prf_input_len; - - if ((long)(limit - ret - 6 - col < 0)) - return NULL; - if (col > 0xFFFD) /* can't happen */ - return NULL; - - s2n(TLSEXT_TYPE_opaque_prf_input, ret); - s2n(col + 2, ret); - s2n(col, ret); - memcpy(ret, s->s3->client_opaque_prf_input, col); - ret += col; - } -#endif - - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp && - s->version != DTLS1_VERSION) - { - int i; - long extlen, idlen, itmp; - OCSP_RESPID *id; - - idlen = 0; - for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) - { - id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); - itmp = i2d_OCSP_RESPID(id, NULL); - if (itmp <= 0) - return NULL; - idlen += itmp + 2; - } - - if (s->tlsext_ocsp_exts) - { - extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); - if (extlen < 0) - return NULL; - } - else - extlen = 0; - - if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL; - s2n(TLSEXT_TYPE_status_request, ret); - if (extlen + idlen > 0xFFF0) - return NULL; - s2n(extlen + idlen + 5, ret); - *(ret++) = TLSEXT_STATUSTYPE_ocsp; - s2n(idlen, ret); - for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) - { - /* save position of id len */ - unsigned char *q = ret; - id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); - /* skip over id len */ - ret += 2; - itmp = i2d_OCSP_RESPID(id, &ret); - /* write id len */ - s2n(itmp, q); - } - s2n(extlen, ret); - if (extlen > 0) - i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); - } - - if ((extdatalen = ret-p-2)== 0) - return p; - - s2n(extdatalen,p); - return ret; - } - -unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) - { - int extdatalen=0; - unsigned char *ret = p; - - /* don't add extensions for SSLv3, unless doing secure renegotiation */ - if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) - return p; - - ret+=2; - if (ret>=limit) return NULL; /* this really never occurs, but ... */ - - if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL) - { - if ((long)(limit - ret - 4) < 0) return NULL; - - s2n(TLSEXT_TYPE_server_name,ret); - s2n(0,ret); - } - - if(s->s3->send_connection_binding) - { - int el; - - if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) - { - SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - if((limit - p - 4 - el) < 0) return NULL; - - s2n(TLSEXT_TYPE_renegotiate,ret); - s2n(el,ret); - - if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) - { - SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - ret += el; - } - -#ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist != NULL && - s->version != DTLS1_VERSION) - { - /* Add TLS extension ECPointFormats to the ServerHello message */ - long lenmax; - - if ((lenmax = limit - ret - 5) < 0) return NULL; - if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; - if (s->tlsext_ecpointformatlist_length > 255) - { - SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - s2n(TLSEXT_TYPE_ec_point_formats,ret); - s2n(s->tlsext_ecpointformatlist_length + 1,ret); - *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length; - memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); - ret+=s->tlsext_ecpointformatlist_length; - - } - /* Currently the server should not respond with a SupportedCurves extension */ -#endif /* OPENSSL_NO_EC */ - - if (s->tlsext_ticket_expected - && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) - { - if ((long)(limit - ret - 4) < 0) return NULL; - s2n(TLSEXT_TYPE_session_ticket,ret); - s2n(0,ret); - } - - if (s->tlsext_status_expected) - { - if ((long)(limit - ret - 4) < 0) return NULL; - s2n(TLSEXT_TYPE_status_request,ret); - s2n(0,ret); - } - -#ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->server_opaque_prf_input != NULL && - s->version != DTLS1_VERSION) - { - size_t sol = s->s3->server_opaque_prf_input_len; - - if ((long)(limit - ret - 6 - sol) < 0) - return NULL; - if (sol > 0xFFFD) /* can't happen */ - return NULL; - - s2n(TLSEXT_TYPE_opaque_prf_input, ret); - s2n(sol + 2, ret); - s2n(sol, ret); - memcpy(ret, s->s3->server_opaque_prf_input, sol); - ret += sol; - } -#endif - if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) - && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) - { const unsigned char cryptopro_ext[36] = { - 0xfd, 0xe8, /*65000*/ - 0x00, 0x20, /*32 bytes length*/ - 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, - 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06, - 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08, - 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17}; - if (limit-ret<36) return NULL; - memcpy(ret,cryptopro_ext,36); - ret+=36; - - } - - if ((extdatalen = ret-p-2)== 0) - return p; - - s2n(extdatalen,p); - return ret; - } - -int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) - { - unsigned short type; - unsigned short size; - unsigned short len; - unsigned char *data = *p; - int renegotiate_seen = 0; - - s->servername_done = 0; - s->tlsext_status_type = -1; - - if (data >= (d+n-2)) - goto ri_check; - n2s(data,len); - - if (data > (d+n-len)) - goto ri_check; - - while (data <= (d+n-4)) - { - n2s(data,type); - n2s(data,size); - - if (data+size > (d+n)) - goto ri_check; -#if 0 - fprintf(stderr,"Received extension type %d size %d\n",type,size); -#endif - if (s->tlsext_debug_cb) - s->tlsext_debug_cb(s, 0, type, data, size, - s->tlsext_debug_arg); -/* The servername extension is treated as follows: - - - Only the hostname type is supported with a maximum length of 255. - - The servername is rejected if too long or if it contains zeros, - in which case an fatal alert is generated. - - The servername field is maintained together with the session cache. - - When a session is resumed, the servername call back invoked in order - to allow the application to position itself to the right context. - - The servername is acknowledged if it is new for a session or when - it is identical to a previously used for the same session. - Applications can control the behaviour. They can at any time - set a 'desirable' servername for a new SSL object. This can be the - case for example with HTTPS when a Host: header field is received and - a renegotiation is requested. In this case, a possible servername - presented in the new client hello is only acknowledged if it matches - the value of the Host: field. - - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - if they provide for changing an explicit servername context for the session, - i.e. when the session has been established with a servername extension. - - On session reconnect, the servername extension may be absent. - -*/ - - if (type == TLSEXT_TYPE_server_name) - { - unsigned char *sdata; - int servname_type; - int dsize; - - if (size < 2) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - n2s(data,dsize); - size -= 2; - if (dsize > size ) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - sdata = data; - while (dsize > 3) - { - servname_type = *(sdata++); - n2s(sdata,len); - dsize -= 3; - - if (len > dsize) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - if (s->servername_done == 0) - switch (servname_type) - { - case TLSEXT_NAMETYPE_host_name: - if (!s->hit) - { - if(s->session->tlsext_hostname) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - if (len > TLSEXT_MAXLEN_host_name) - { - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - memcpy(s->session->tlsext_hostname, sdata, len); - s->session->tlsext_hostname[len]='\0'; - if (strlen(s->session->tlsext_hostname) != len) { - OPENSSL_free(s->session->tlsext_hostname); - s->session->tlsext_hostname = NULL; - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - s->servername_done = 1; - - } - else - s->servername_done = s->session->tlsext_hostname - && strlen(s->session->tlsext_hostname) == len - && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0; - - break; - - default: - break; - } - - dsize -= len; - } - if (dsize != 0) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - } - -#ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats && - s->version != DTLS1_VERSION) - { - unsigned char *sdata = data; - int ecpointformatlist_length = *(sdata++); - - if (ecpointformatlist_length != size - 1) - { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - if (!s->hit) - { - if(s->session->tlsext_ecpointformatlist) - { - OPENSSL_free(s->session->tlsext_ecpointformatlist); - s->session->tlsext_ecpointformatlist = NULL; - } - s->session->tlsext_ecpointformatlist_length = 0; - if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length; - memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length); - } -#if 0 - fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length); - sdata = s->session->tlsext_ecpointformatlist; - for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) - fprintf(stderr,"%i ",*(sdata++)); - fprintf(stderr,"\n"); -#endif - } - else if (type == TLSEXT_TYPE_elliptic_curves && - s->version != DTLS1_VERSION) - { - unsigned char *sdata = data; - int ellipticcurvelist_length = (*(sdata++) << 8); - ellipticcurvelist_length += (*(sdata++)); - - if (ellipticcurvelist_length != size - 2) - { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - if (!s->hit) - { - if(s->session->tlsext_ellipticcurvelist) - { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - s->session->tlsext_ellipticcurvelist_length = 0; - if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length; - memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length); - } -#if 0 - fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length); - sdata = s->session->tlsext_ellipticcurvelist; - for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++) - fprintf(stderr,"%i ",*(sdata++)); - fprintf(stderr,"\n"); -#endif - } -#endif /* OPENSSL_NO_EC */ -#ifdef TLSEXT_TYPE_opaque_prf_input - else if (type == TLSEXT_TYPE_opaque_prf_input && - s->version != DTLS1_VERSION) - { - unsigned char *sdata = data; - - if (size < 2) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - n2s(sdata, s->s3->client_opaque_prf_input_len); - if (s->s3->client_opaque_prf_input_len != size - 2) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ - OPENSSL_free(s->s3->client_opaque_prf_input); - if (s->s3->client_opaque_prf_input_len == 0) - s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ - else - s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len); - if (s->s3->client_opaque_prf_input == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - } -#endif - else if (type == TLSEXT_TYPE_session_ticket) - { - if (s->tls_session_ticket_ext_cb && - !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - } - else if (type == TLSEXT_TYPE_renegotiate) - { - if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) - return 0; - renegotiate_seen = 1; - } - else if (type == TLSEXT_TYPE_status_request && - s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) - { - - if (size < 5) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - s->tlsext_status_type = *data++; - size--; - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) - { - const unsigned char *sdata; - int dsize; - /* Read in responder_id_list */ - n2s(data,dsize); - size -= 2; - if (dsize > size ) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - while (dsize > 0) - { - OCSP_RESPID *id; - int idsize; - if (dsize < 4) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - n2s(data, idsize); - dsize -= 2 + idsize; - if (dsize < 0) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - sdata = data; - data += idsize; - id = d2i_OCSP_RESPID(NULL, - &sdata, idsize); - if (!id) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - if (data != sdata) - { - OCSP_RESPID_free(id); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - if (!s->tlsext_ocsp_ids - && !(s->tlsext_ocsp_ids = - sk_OCSP_RESPID_new_null())) - { - OCSP_RESPID_free(id); - *al = SSL_AD_INTERNAL_ERROR; - return 0; - } - if (!sk_OCSP_RESPID_push( - s->tlsext_ocsp_ids, id)) - { - OCSP_RESPID_free(id); - *al = SSL_AD_INTERNAL_ERROR; - return 0; - } - } - - /* Read in request_extensions */ - n2s(data,dsize); - size -= 2; - if (dsize > size) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - sdata = data; - if (dsize > 0) - { - s->tlsext_ocsp_exts = - d2i_X509_EXTENSIONS(NULL, - &sdata, dsize); - if (!s->tlsext_ocsp_exts - || (data + dsize != sdata)) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - } - } - /* We don't know what to do with any other type - * so ignore it. - */ - else - s->tlsext_status_type = -1; - } - - /* session ticket processed earlier */ - data+=size; - } - - *p = data; - - ri_check: - - /* Need RI if renegotiating */ - - if (!renegotiate_seen && s->new_session && - !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) - { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; - } - - return 1; - } - -int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) - { - unsigned short length; - unsigned short type; - unsigned short size; - unsigned char *data = *p; - int tlsext_servername = 0; - int renegotiate_seen = 0; - - if (data >= (d+n-2)) - goto ri_check; - - n2s(data,length); - if (data+length != d+n) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - while(data <= (d+n-4)) - { - n2s(data,type); - n2s(data,size); - - if (data+size > (d+n)) - goto ri_check; - - if (s->tlsext_debug_cb) - s->tlsext_debug_cb(s, 1, type, data, size, - s->tlsext_debug_arg); - - if (type == TLSEXT_TYPE_server_name) - { - if (s->tlsext_hostname == NULL || size > 0) - { - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - tlsext_servername = 1; - } - -#ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats && - s->version != DTLS1_VERSION) - { - unsigned char *sdata = data; - int ecpointformatlist_length = *(sdata++); - - if (ecpointformatlist_length != size - 1) - { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - s->session->tlsext_ecpointformatlist_length = 0; - if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); - if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length; - memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length); -#if 0 - fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist "); - sdata = s->session->tlsext_ecpointformatlist; - for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) - fprintf(stderr,"%i ",*(sdata++)); - fprintf(stderr,"\n"); -#endif - } -#endif /* OPENSSL_NO_EC */ - - else if (type == TLSEXT_TYPE_session_ticket) - { - if (s->tls_session_ticket_ext_cb && - !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - if ((SSL_get_options(s) & SSL_OP_NO_TICKET) - || (size > 0)) - { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - s->tlsext_ticket_expected = 1; - } -#ifdef TLSEXT_TYPE_opaque_prf_input - else if (type == TLSEXT_TYPE_opaque_prf_input && - s->version != DTLS1_VERSION) - { - unsigned char *sdata = data; - - if (size < 2) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - n2s(sdata, s->s3->server_opaque_prf_input_len); - if (s->s3->server_opaque_prf_input_len != size - 2) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */ - OPENSSL_free(s->s3->server_opaque_prf_input); - if (s->s3->server_opaque_prf_input_len == 0) - s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ - else - s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len); - - if (s->s3->server_opaque_prf_input == NULL) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - } -#endif - else if (type == TLSEXT_TYPE_status_request && - s->version != DTLS1_VERSION) - { - /* MUST be empty and only sent if we've requested - * a status request message. - */ - if ((s->tlsext_status_type == -1) || (size > 0)) - { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - /* Set flag to expect CertificateStatus message */ - s->tlsext_status_expected = 1; - } - else if (type == TLSEXT_TYPE_renegotiate) - { - if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) - return 0; - renegotiate_seen = 1; - } - data+=size; - } - - if (data != d+n) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit && tlsext_servername == 1) - { - if (s->tlsext_hostname) - { - if (s->session->tlsext_hostname == NULL) - { - s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname); - if (!s->session->tlsext_hostname) - { - *al = SSL_AD_UNRECOGNIZED_NAME; - return 0; - } - } - else - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - } - } - - *p = data; - - ri_check: - - /* Determine if we need to see RI. Strictly speaking if we want to - * avoid an attack we should *always* see RI even on initial server - * hello because the client doesn't see any renegotiation during an - * attack. However this would mean we could not connect to any server - * which doesn't support RI so for the immediate future tolerate RI - * absence on initial connect only. - */ - if (!renegotiate_seen - && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) - && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) - { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; - } - - return 1; - } - - -int ssl_prepare_clienthello_tlsext(SSL *s) - { -#ifndef OPENSSL_NO_EC - /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats - * and elliptic curves we support. - */ - int using_ecc = 0; - int i; - unsigned char *j; - unsigned long alg_k, alg_a; - STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); - - for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) - { - SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); - - alg_k = c->algorithm_mkey; - alg_a = c->algorithm_auth; - if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA))) - { - using_ecc = 1; - break; - } - } - using_ecc = using_ecc && (s->version == TLS1_VERSION); - if (using_ecc) - { - if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); - if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) - { - SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); - return -1; - } - s->tlsext_ecpointformatlist_length = 3; - s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; - s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; - s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; - - /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */ - if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist); - s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_list[0]) * 2; - if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) - { - s->tlsext_ellipticcurvelist_length = 0; - SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); - return -1; - } - for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= - sizeof(nid_list)/sizeof(nid_list[0]); i++) - s2n(i,j); - } -#endif /* OPENSSL_NO_EC */ - -#ifdef TLSEXT_TYPE_opaque_prf_input - { - int r = 1; - - if (s->ctx->tlsext_opaque_prf_input_callback != 0) - { - r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); - if (!r) - return -1; - } - - if (s->tlsext_opaque_prf_input != NULL) - { - if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ - OPENSSL_free(s->s3->client_opaque_prf_input); - - if (s->tlsext_opaque_prf_input_len == 0) - s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ - else - s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); - if (s->s3->client_opaque_prf_input == NULL) - { - SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); - return -1; - } - s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; - } - - if (r == 2) - /* at callback's request, insist on receiving an appropriate server opaque PRF input */ - s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; - } -#endif - - return 1; - } - -int ssl_prepare_serverhello_tlsext(SSL *s) - { -#ifndef OPENSSL_NO_EC - /* If we are server and using an ECC cipher suite, send the point formats we support - * if the client sent us an ECPointsFormat extension. Note that the server is not - * supposed to send an EllipticCurves extension. - */ - - unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA); - using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL); - - if (using_ecc) - { - if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); - if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) - { - SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); - return -1; - } - s->tlsext_ecpointformatlist_length = 3; - s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; - s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; - s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; - } -#endif /* OPENSSL_NO_EC */ - - return 1; - } - -int ssl_check_clienthello_tlsext(SSL *s) - { - int ret=SSL_TLSEXT_ERR_NOACK; - int al = SSL_AD_UNRECOGNIZED_NAME; - -#ifndef OPENSSL_NO_EC - /* The handling of the ECPointFormats extension is done elsewhere, namely in - * ssl3_choose_cipher in s3_lib.c. - */ - /* The handling of the EllipticCurves extension is done elsewhere, namely in - * ssl3_choose_cipher in s3_lib.c. - */ -#endif - - if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) - ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); - else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) - ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); - - /* If status request then ask callback what to do. - * Note: this must be called after servername callbacks in case - * the certificate has changed. - */ - if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) - { - int r; - r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); - switch (r) - { - /* We don't want to send a status request response */ - case SSL_TLSEXT_ERR_NOACK: - s->tlsext_status_expected = 0; - break; - /* status request response should be sent */ - case SSL_TLSEXT_ERR_OK: - if (s->tlsext_ocsp_resp) - s->tlsext_status_expected = 1; - else - s->tlsext_status_expected = 0; - break; - /* something bad happened */ - case SSL_TLSEXT_ERR_ALERT_FATAL: - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_INTERNAL_ERROR; - goto err; - } - } - else - s->tlsext_status_expected = 0; - -#ifdef TLSEXT_TYPE_opaque_prf_input - { - /* This sort of belongs into ssl_prepare_serverhello_tlsext(), - * but we might be sending an alert in response to the client hello, - * so this has to happen here in ssl_check_clienthello_tlsext(). */ - - int r = 1; - - if (s->ctx->tlsext_opaque_prf_input_callback != 0) - { - r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); - if (!r) - { - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_INTERNAL_ERROR; - goto err; - } - } - - if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */ - OPENSSL_free(s->s3->server_opaque_prf_input); - s->s3->server_opaque_prf_input = NULL; - - if (s->tlsext_opaque_prf_input != NULL) - { - if (s->s3->client_opaque_prf_input != NULL && - s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len) - { - /* can only use this extension if we have a server opaque PRF input - * of the same length as the client opaque PRF input! */ - - if (s->tlsext_opaque_prf_input_len == 0) - s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ - else - s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); - if (s->s3->server_opaque_prf_input == NULL) - { - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_INTERNAL_ERROR; - goto err; - } - s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; - } - } - - if (r == 2 && s->s3->server_opaque_prf_input == NULL) - { - /* The callback wants to enforce use of the extension, - * but we can't do that with the client opaque PRF input; - * abort the handshake. - */ - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_HANDSHAKE_FAILURE; - } - } - -#endif - err: - switch (ret) - { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(s,SSL3_AL_FATAL,al); - return -1; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(s,SSL3_AL_WARNING,al); - return 1; - - case SSL_TLSEXT_ERR_NOACK: - s->servername_done=0; - default: - return 1; - } - } - -int ssl_check_serverhello_tlsext(SSL *s) - { - int ret=SSL_TLSEXT_ERR_NOACK; - int al = SSL_AD_UNRECOGNIZED_NAME; - -#ifndef OPENSSL_NO_EC - /* If we are client and using an elliptic curve cryptography cipher - * suite, then if server returns an EC point formats lists extension - * it must contain uncompressed. - */ - unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && - (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && - ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA))) - { - /* we are using an ECC cipher */ - size_t i; - unsigned char *list; - int found_uncompressed = 0; - list = s->session->tlsext_ecpointformatlist; - for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) - { - if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed) - { - found_uncompressed = 1; - break; - } - } - if (!found_uncompressed) - { - SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); - return -1; - } - } - ret = SSL_TLSEXT_ERR_OK; -#endif /* OPENSSL_NO_EC */ - - if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) - ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); - else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) - ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); - -#ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->server_opaque_prf_input_len > 0) - { - /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs. - * So first verify that we really have a value from the server too. */ - - if (s->s3->server_opaque_prf_input == NULL) - { - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_HANDSHAKE_FAILURE; - } - - /* Anytime the server *has* sent an opaque PRF input, we need to check - * that we have a client opaque PRF input of the same size. */ - if (s->s3->client_opaque_prf_input == NULL || - s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len) - { - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_ILLEGAL_PARAMETER; - } - } -#endif - - /* If we've requested certificate status and we wont get one - * tell the callback - */ - if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) - && s->ctx && s->ctx->tlsext_status_cb) - { - int r; - /* Set resp to NULL, resplen to -1 so callback knows - * there is no response. - */ - if (s->tlsext_ocsp_resp) - { - OPENSSL_free(s->tlsext_ocsp_resp); - s->tlsext_ocsp_resp = NULL; - } - s->tlsext_ocsp_resplen = -1; - r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); - if (r == 0) - { - al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - } - if (r < 0) - { - al = SSL_AD_INTERNAL_ERROR; - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - } - } - - switch (ret) - { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(s,SSL3_AL_FATAL,al); - return -1; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(s,SSL3_AL_WARNING,al); - return 1; - - case SSL_TLSEXT_ERR_NOACK: - s->servername_done=0; - default: - return 1; - } - } - -/* Since the server cache lookup is done early on in the processing of client - * hello and other operations depend on the result we need to handle any TLS - * session ticket extension at the same time. - */ - -int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, - const unsigned char *limit, SSL_SESSION **ret) - { - /* Point after session ID in client hello */ - const unsigned char *p = session_id + len; - unsigned short i; - - /* If tickets disabled behave as if no ticket present - * to permit stateful resumption. - */ - if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 1; - - if ((s->version <= SSL3_VERSION) || !limit) - return 1; - if (p >= limit) - return -1; - /* Skip past DTLS cookie */ - if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) - { - i = *(p++); - p+= i; - if (p >= limit) - return -1; - } - /* Skip past cipher list */ - n2s(p, i); - p+= i; - if (p >= limit) - return -1; - /* Skip past compression algorithm list */ - i = *(p++); - p += i; - if (p > limit) - return -1; - /* Now at start of extensions */ - if ((p + 2) >= limit) - return 1; - n2s(p, i); - while ((p + 4) <= limit) - { - unsigned short type, size; - n2s(p, type); - n2s(p, size); - if (p + size > limit) - return 1; - if (type == TLSEXT_TYPE_session_ticket) - { - /* If tickets disabled indicate cache miss which will - * trigger a full handshake - */ - if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 1; - /* If zero length note client will accept a ticket - * and indicate cache miss to trigger full handshake - */ - if (size == 0) - { - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } - if (s->tls_session_secret_cb) - { - /* Indicate cache miss here and instead of - * generating the session from ticket now, - * trigger abbreviated handshake based on - * external mechanism to calculate the master - * secret later. */ - return 0; - } - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } - p += size; - } - return 1; - } - -static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, - const unsigned char *sess_id, int sesslen, - SSL_SESSION **psess) - { - SSL_SESSION *sess; - unsigned char *sdec; - const unsigned char *p; - int slen, mlen, renew_ticket = 0; - unsigned char tick_hmac[EVP_MAX_MD_SIZE]; - HMAC_CTX hctx; - EVP_CIPHER_CTX ctx; - SSL_CTX *tctx = s->initial_ctx; - /* Need at least keyname + iv + some encrypted data */ - if (eticklen < 48) - goto tickerr; - /* Initialize session ticket encryption and HMAC contexts */ - HMAC_CTX_init(&hctx); - EVP_CIPHER_CTX_init(&ctx); - if (tctx->tlsext_ticket_key_cb) - { - unsigned char *nctick = (unsigned char *)etick; - int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, - &ctx, &hctx, 0); - if (rv < 0) - return -1; - if (rv == 0) - goto tickerr; - if (rv == 2) - renew_ticket = 1; - } - else - { - /* Check key name matches */ - if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) - goto tickerr; - HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, - tlsext_tick_md(), NULL); - EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - tctx->tlsext_tick_aes_key, etick + 16); - } - /* Attempt to process session ticket, first conduct sanity and - * integrity checks on ticket. - */ - mlen = HMAC_size(&hctx); - if (mlen < 0) - { - EVP_CIPHER_CTX_cleanup(&ctx); - return -1; - } - eticklen -= mlen; - /* Check HMAC of encrypted ticket */ - HMAC_Update(&hctx, etick, eticklen); - HMAC_Final(&hctx, tick_hmac, NULL); - HMAC_CTX_cleanup(&hctx); - if (memcmp(tick_hmac, etick + eticklen, mlen)) - goto tickerr; - /* Attempt to decrypt session data */ - /* Move p after IV to start of encrypted ticket, update length */ - p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); - eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); - sdec = OPENSSL_malloc(eticklen); - if (!sdec) - { - EVP_CIPHER_CTX_cleanup(&ctx); - return -1; - } - EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); - if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) - goto tickerr; - slen += mlen; - EVP_CIPHER_CTX_cleanup(&ctx); - p = sdec; - - sess = d2i_SSL_SESSION(NULL, &p, slen); - OPENSSL_free(sdec); - if (sess) - { - /* The session ID if non-empty is used by some clients to - * detect that the ticket has been accepted. So we copy it to - * the session structure. If it is empty set length to zero - * as required by standard. - */ - if (sesslen) - memcpy(sess->session_id, sess_id, sesslen); - sess->session_id_length = sesslen; - *psess = sess; - s->tlsext_ticket_expected = renew_ticket; - return 1; - } - /* If session decrypt failure indicate a cache miss and set state to - * send a new ticket - */ - tickerr: - s->tlsext_ticket_expected = 1; - return 0; - } - -#endif +/* ssl/t1_lib.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-2007 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 <stdio.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/ocsp.h>
+#include "ssl_locl.h"
+
+const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
+
+#ifndef OPENSSL_NO_TLSEXT
+static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
+ const unsigned char *sess_id, int sesslen,
+ SSL_SESSION **psess);
+#endif
+
+SSL3_ENC_METHOD TLSv1_enc_data={
+ tls1_enc,
+ tls1_mac,
+ tls1_setup_key_block,
+ tls1_generate_master_secret,
+ tls1_change_cipher_state,
+ tls1_final_finish_mac,
+ TLS1_FINISH_MAC_LENGTH,
+ tls1_cert_verify_mac,
+ TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+ TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+ tls1_alert_code,
+ };
+
+long tls1_default_timeout(void)
+ {
+ /* 2 hours, the 24 hours mentioned in the TLSv1 spec
+ * is way too long for http, the cache would over fill */
+ return(60*60*2);
+ }
+
+int tls1_new(SSL *s)
+ {
+ if (!ssl3_new(s)) return(0);
+ s->method->ssl_clear(s);
+ return(1);
+ }
+
+void tls1_free(SSL *s)
+ {
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+ ssl3_free(s);
+ }
+
+void tls1_clear(SSL *s)
+ {
+ ssl3_clear(s);
+ s->version=TLS1_VERSION;
+ }
+
+#ifndef OPENSSL_NO_EC
+static int nid_list[] =
+ {
+ NID_sect163k1, /* sect163k1 (1) */
+ NID_sect163r1, /* sect163r1 (2) */
+ NID_sect163r2, /* sect163r2 (3) */
+ NID_sect193r1, /* sect193r1 (4) */
+ NID_sect193r2, /* sect193r2 (5) */
+ NID_sect233k1, /* sect233k1 (6) */
+ NID_sect233r1, /* sect233r1 (7) */
+ NID_sect239k1, /* sect239k1 (8) */
+ NID_sect283k1, /* sect283k1 (9) */
+ NID_sect283r1, /* sect283r1 (10) */
+ NID_sect409k1, /* sect409k1 (11) */
+ NID_sect409r1, /* sect409r1 (12) */
+ NID_sect571k1, /* sect571k1 (13) */
+ NID_sect571r1, /* sect571r1 (14) */
+ NID_secp160k1, /* secp160k1 (15) */
+ NID_secp160r1, /* secp160r1 (16) */
+ NID_secp160r2, /* secp160r2 (17) */
+ NID_secp192k1, /* secp192k1 (18) */
+ NID_X9_62_prime192v1, /* secp192r1 (19) */
+ NID_secp224k1, /* secp224k1 (20) */
+ NID_secp224r1, /* secp224r1 (21) */
+ NID_secp256k1, /* secp256k1 (22) */
+ NID_X9_62_prime256v1, /* secp256r1 (23) */
+ NID_secp384r1, /* secp384r1 (24) */
+ NID_secp521r1 /* secp521r1 (25) */
+ };
+
+int tls1_ec_curve_id2nid(int curve_id)
+ {
+ /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ if ((curve_id < 1) || ((unsigned int)curve_id >
+ sizeof(nid_list)/sizeof(nid_list[0])))
+ return 0;
+ return nid_list[curve_id-1];
+ }
+
+int tls1_ec_nid2curve_id(int nid)
+ {
+ /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ switch (nid)
+ {
+ case NID_sect163k1: /* sect163k1 (1) */
+ return 1;
+ case NID_sect163r1: /* sect163r1 (2) */
+ return 2;
+ case NID_sect163r2: /* sect163r2 (3) */
+ return 3;
+ case NID_sect193r1: /* sect193r1 (4) */
+ return 4;
+ case NID_sect193r2: /* sect193r2 (5) */
+ return 5;
+ case NID_sect233k1: /* sect233k1 (6) */
+ return 6;
+ case NID_sect233r1: /* sect233r1 (7) */
+ return 7;
+ case NID_sect239k1: /* sect239k1 (8) */
+ return 8;
+ case NID_sect283k1: /* sect283k1 (9) */
+ return 9;
+ case NID_sect283r1: /* sect283r1 (10) */
+ return 10;
+ case NID_sect409k1: /* sect409k1 (11) */
+ return 11;
+ case NID_sect409r1: /* sect409r1 (12) */
+ return 12;
+ case NID_sect571k1: /* sect571k1 (13) */
+ return 13;
+ case NID_sect571r1: /* sect571r1 (14) */
+ return 14;
+ case NID_secp160k1: /* secp160k1 (15) */
+ return 15;
+ case NID_secp160r1: /* secp160r1 (16) */
+ return 16;
+ case NID_secp160r2: /* secp160r2 (17) */
+ return 17;
+ case NID_secp192k1: /* secp192k1 (18) */
+ return 18;
+ case NID_X9_62_prime192v1: /* secp192r1 (19) */
+ return 19;
+ case NID_secp224k1: /* secp224k1 (20) */
+ return 20;
+ case NID_secp224r1: /* secp224r1 (21) */
+ return 21;
+ case NID_secp256k1: /* secp256k1 (22) */
+ return 22;
+ case NID_X9_62_prime256v1: /* secp256r1 (23) */
+ return 23;
+ case NID_secp384r1: /* secp384r1 (24) */
+ return 24;
+ case NID_secp521r1: /* secp521r1 (25) */
+ return 25;
+ default:
+ return 0;
+ }
+ }
+#endif /* OPENSSL_NO_EC */
+
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+ {
+ int extdatalen=0;
+ unsigned char *ret = p;
+
+ /* don't add extensions for SSLv3 unless doing secure renegotiation */
+ if (s->client_version == SSL3_VERSION
+ && !s->s3->send_connection_binding)
+ return p;
+
+ ret+=2;
+
+ if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+ if (s->tlsext_hostname != NULL)
+ {
+ /* Add TLS extension servername to the Client Hello message */
+ unsigned long size_str;
+ long lenmax;
+
+ /* check for enough space.
+ 4 for the servername type and entension length
+ 2 for servernamelist length
+ 1 for the hostname type
+ 2 for hostname length
+ + hostname length
+ */
+
+ if ((lenmax = limit - ret - 9) < 0
+ || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
+ return NULL;
+
+ /* extension type and length */
+ s2n(TLSEXT_TYPE_server_name,ret);
+ s2n(size_str+5,ret);
+
+ /* length of servername list */
+ s2n(size_str+3,ret);
+
+ /* hostname type, length and hostname */
+ *(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
+ s2n(size_str,ret);
+ memcpy(ret, s->tlsext_hostname, size_str);
+ ret+=size_str;
+ }
+
+ /* Add RI if renegotiating */
+ if (s->new_session)
+ {
+ int el;
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension ECPointFormats to the ClientHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 5) < 0) return NULL;
+ if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ecpointformatlist_length > 255)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats,ret);
+ s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+ *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+ memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+ ret+=s->tlsext_ecpointformatlist_length;
+ }
+ if (s->tlsext_ellipticcurvelist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension EllipticCurves to the ClientHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 6) < 0) return NULL;
+ if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ellipticcurvelist_length > 65532)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_elliptic_curves,ret);
+ s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+
+ /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
+ * elliptic_curve_list, but the examples use two bytes.
+ * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
+ * resolves this to two bytes.
+ */
+ s2n(s->tlsext_ellipticcurvelist_length, ret);
+ memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
+ ret+=s->tlsext_ellipticcurvelist_length;
+ }
+#endif /* OPENSSL_NO_EC */
+
+ if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ {
+ int ticklen;
+ if (!s->new_session && s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
+ else
+ ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
+ /* Check for enough room 2 for extension type, 2 for len
+ * rest for ticket
+ */
+ if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_session_ticket,ret);
+ s2n(ticklen,ret);
+ if (ticklen)
+ {
+ memcpy(ret, s->session->tlsext_tick, ticklen);
+ ret += ticklen;
+ }
+ }
+ skip_ext:
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->client_opaque_prf_input != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ size_t col = s->s3->client_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - col < 0))
+ return NULL;
+ if (col > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(col + 2, ret);
+ s2n(col, ret);
+ memcpy(ret, s->s3->client_opaque_prf_input, col);
+ ret += col;
+ }
+#endif
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION)
+ {
+ int i;
+ long extlen, idlen, itmp;
+ OCSP_RESPID *id;
+
+ idlen = 0;
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ itmp = i2d_OCSP_RESPID(id, NULL);
+ if (itmp <= 0)
+ return NULL;
+ idlen += itmp + 2;
+ }
+
+ if (s->tlsext_ocsp_exts)
+ {
+ extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+ if (extlen < 0)
+ return NULL;
+ }
+ else
+ extlen = 0;
+
+ if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request, ret);
+ if (extlen + idlen > 0xFFF0)
+ return NULL;
+ s2n(extlen + idlen + 5, ret);
+ *(ret++) = TLSEXT_STATUSTYPE_ocsp;
+ s2n(idlen, ret);
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ /* save position of id len */
+ unsigned char *q = ret;
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ /* skip over id len */
+ ret += 2;
+ itmp = i2d_OCSP_RESPID(id, &ret);
+ /* write id len */
+ s2n(itmp, q);
+ }
+ s2n(extlen, ret);
+ if (extlen > 0)
+ i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+ }
+
+ if ((extdatalen = ret-p-2)== 0)
+ return p;
+
+ s2n(extdatalen,p);
+ return ret;
+ }
+
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+ {
+ int extdatalen=0;
+ unsigned char *ret = p;
+
+ /* don't add extensions for SSLv3, unless doing secure renegotiation */
+ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
+ return p;
+
+ ret+=2;
+ if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+ if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_server_name,ret);
+ s2n(0,ret);
+ }
+
+ if(s->s3->send_connection_binding)
+ {
+ int el;
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ /* Add TLS extension ECPointFormats to the ServerHello message */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 5) < 0) return NULL;
+ if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+ if (s->tlsext_ecpointformatlist_length > 255)
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats,ret);
+ s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+ *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+ memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+ ret+=s->tlsext_ecpointformatlist_length;
+
+ }
+ /* Currently the server should not respond with a SupportedCurves extension */
+#endif /* OPENSSL_NO_EC */
+
+ if (s->tlsext_ticket_expected
+ && !(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+ s2n(TLSEXT_TYPE_session_ticket,ret);
+ s2n(0,ret);
+ }
+
+ if (s->tlsext_status_expected)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request,ret);
+ s2n(0,ret);
+ }
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input != NULL &&
+ s->version != DTLS1_VERSION)
+ {
+ size_t sol = s->s3->server_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - sol) < 0)
+ return NULL;
+ if (sol > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(sol + 2, ret);
+ s2n(sol, ret);
+ memcpy(ret, s->s3->server_opaque_prf_input, sol);
+ ret += sol;
+ }
+#endif
+ if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81)
+ && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
+ { const unsigned char cryptopro_ext[36] = {
+ 0xfd, 0xe8, /*65000*/
+ 0x00, 0x20, /*32 bytes length*/
+ 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+ 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+ 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
+ if (limit-ret<36) return NULL;
+ memcpy(ret,cryptopro_ext,36);
+ ret+=36;
+
+ }
+
+ if ((extdatalen = ret-p-2)== 0)
+ return p;
+
+ s2n(extdatalen,p);
+ return ret;
+ }
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+ {
+ unsigned short type;
+ unsigned short size;
+ unsigned short len;
+ unsigned char *data = *p;
+ int renegotiate_seen = 0;
+
+ s->servername_done = 0;
+ s->tlsext_status_type = -1;
+
+ if (data >= (d+n-2))
+ goto ri_check;
+ n2s(data,len);
+
+ if (data > (d+n-len))
+ goto ri_check;
+
+ while (data <= (d+n-4))
+ {
+ n2s(data,type);
+ n2s(data,size);
+
+ if (data+size > (d+n))
+ goto ri_check;
+#if 0
+ fprintf(stderr,"Received extension type %d size %d\n",type,size);
+#endif
+ if (s->tlsext_debug_cb)
+ s->tlsext_debug_cb(s, 0, type, data, size,
+ s->tlsext_debug_arg);
+/* The servername extension is treated as follows:
+
+ - Only the hostname type is supported with a maximum length of 255.
+ - The servername is rejected if too long or if it contains zeros,
+ in which case an fatal alert is generated.
+ - The servername field is maintained together with the session cache.
+ - When a session is resumed, the servername call back invoked in order
+ to allow the application to position itself to the right context.
+ - The servername is acknowledged if it is new for a session or when
+ it is identical to a previously used for the same session.
+ Applications can control the behaviour. They can at any time
+ set a 'desirable' servername for a new SSL object. This can be the
+ case for example with HTTPS when a Host: header field is received and
+ a renegotiation is requested. In this case, a possible servername
+ presented in the new client hello is only acknowledged if it matches
+ the value of the Host: field.
+ - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ if they provide for changing an explicit servername context for the session,
+ i.e. when the session has been established with a servername extension.
+ - On session reconnect, the servername extension may be absent.
+
+*/
+
+ if (type == TLSEXT_TYPE_server_name)
+ {
+ unsigned char *sdata;
+ int servname_type;
+ int dsize;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size )
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ sdata = data;
+ while (dsize > 3)
+ {
+ servname_type = *(sdata++);
+ n2s(sdata,len);
+ dsize -= 3;
+
+ if (len > dsize)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->servername_done == 0)
+ switch (servname_type)
+ {
+ case TLSEXT_NAMETYPE_host_name:
+ if (!s->hit)
+ {
+ if(s->session->tlsext_hostname)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (len > TLSEXT_MAXLEN_host_name)
+ {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->session->tlsext_hostname, sdata, len);
+ s->session->tlsext_hostname[len]='\0';
+ if (strlen(s->session->tlsext_hostname) != len) {
+ OPENSSL_free(s->session->tlsext_hostname);
+ s->session->tlsext_hostname = NULL;
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ s->servername_done = 1;
+
+ }
+ else
+ s->servername_done = s->session->tlsext_hostname
+ && strlen(s->session->tlsext_hostname) == len
+ && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
+
+ break;
+
+ default:
+ break;
+ }
+
+ dsize -= len;
+ }
+ if (dsize != 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ }
+
+#ifndef OPENSSL_NO_EC
+ else if (type == TLSEXT_TYPE_ec_point_formats &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit)
+ {
+ if(s->session->tlsext_ecpointformatlist)
+ {
+ OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ s->session->tlsext_ecpointformatlist = NULL;
+ }
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+ }
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+ else if (type == TLSEXT_TYPE_elliptic_curves &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ellipticcurvelist_length = (*(sdata++) << 8);
+ ellipticcurvelist_length += (*(sdata++));
+
+ if (ellipticcurvelist_length != size - 2)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit)
+ {
+ if(s->session->tlsext_ellipticcurvelist)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length = 0;
+ if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
+ memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
+ }
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
+ sdata = s->session->tlsext_ellipticcurvelist;
+ for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+#endif /* OPENSSL_NO_EC */
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input_len != size - 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+ if (s->s3->client_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+#endif
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+ {
+
+ if (size < 5)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->tlsext_status_type = *data++;
+ size--;
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ {
+ const unsigned char *sdata;
+ int dsize;
+ /* Read in responder_id_list */
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size )
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ while (dsize > 0)
+ {
+ OCSP_RESPID *id;
+ int idsize;
+ if (dsize < 4)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, idsize);
+ dsize -= 2 + idsize;
+ size -= 2 + idsize;
+ if (dsize < 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ data += idsize;
+ id = d2i_OCSP_RESPID(NULL,
+ &sdata, idsize);
+ if (!id)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (data != sdata)
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->tlsext_ocsp_ids
+ && !(s->tlsext_ocsp_ids =
+ sk_OCSP_RESPID_new_null()))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if (!sk_OCSP_RESPID_push(
+ s->tlsext_ocsp_ids, id))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
+ /* Read in request_extensions */
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize != size)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ if (dsize > 0)
+ {
+ s->tlsext_ocsp_exts =
+ d2i_X509_EXTENSIONS(NULL,
+ &sdata, dsize);
+ if (!s->tlsext_ocsp_exts
+ || (data + dsize != sdata))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+ /* We don't know what to do with any other type
+ * so ignore it.
+ */
+ else
+ s->tlsext_status_type = -1;
+ }
+
+ /* session ticket processed earlier */
+ data+=size;
+ }
+
+ *p = data;
+
+ ri_check:
+
+ /* Need RI if renegotiating */
+
+ if (!renegotiate_seen && s->new_session &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+ }
+
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+ {
+ unsigned short length;
+ unsigned short type;
+ unsigned short size;
+ unsigned char *data = *p;
+ int tlsext_servername = 0;
+ int renegotiate_seen = 0;
+
+ if (data >= (d+n-2))
+ goto ri_check;
+
+ n2s(data,length);
+ if (data+length != d+n)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ while(data <= (d+n-4))
+ {
+ n2s(data,type);
+ n2s(data,size);
+
+ if (data+size > (d+n))
+ goto ri_check;
+
+ if (s->tlsext_debug_cb)
+ s->tlsext_debug_cb(s, 1, type, data, size,
+ s->tlsext_debug_arg);
+
+ if (type == TLSEXT_TYPE_server_name)
+ {
+ if (s->tlsext_hostname == NULL || size > 0)
+ {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ tlsext_servername = 1;
+ }
+
+#ifndef OPENSSL_NO_EC
+ else if (type == TLSEXT_TYPE_ec_point_formats &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+ fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr,"%i ",*(sdata++));
+ fprintf(stderr,"\n");
+#endif
+ }
+#endif /* OPENSSL_NO_EC */
+
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ || (size > 0))
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ s->tlsext_ticket_expected = 1;
+ }
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION)
+ {
+ unsigned char *sdata = data;
+
+ if (size < 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->server_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input_len != size - 2)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ if (s->s3->server_opaque_prf_input_len == 0)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
+
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+#endif
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION)
+ {
+ /* MUST be empty and only sent if we've requested
+ * a status request message.
+ */
+ if ((s->tlsext_status_type == -1) || (size > 0))
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ /* Set flag to expect CertificateStatus message */
+ s->tlsext_status_expected = 1;
+ }
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+ data+=size;
+ }
+
+ if (data != d+n)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (!s->hit && tlsext_servername == 1)
+ {
+ if (s->tlsext_hostname)
+ {
+ if (s->session->tlsext_hostname == NULL)
+ {
+ s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
+ if (!s->session->tlsext_hostname)
+ {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ }
+ else
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ *p = data;
+
+ ri_check:
+
+ /* Determine if we need to see RI. Strictly speaking if we want to
+ * avoid an attack we should *always* see RI even on initial server
+ * hello because the client doesn't see any renegotiation during an
+ * attack. However this would mean we could not connect to any server
+ * which doesn't support RI so for the immediate future tolerate RI
+ * absence on initial connect only.
+ */
+ if (!renegotiate_seen
+ && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+ && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+ }
+
+
+int ssl_prepare_clienthello_tlsext(SSL *s)
+ {
+#ifndef OPENSSL_NO_EC
+ /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats
+ * and elliptic curves we support.
+ */
+ int using_ecc = 0;
+ int i;
+ unsigned char *j;
+ unsigned long alg_k, alg_a;
+ STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+ for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+ {
+ SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+ alg_k = c->algorithm_mkey;
+ alg_a = c->algorithm_auth;
+ if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA)))
+ {
+ using_ecc = 1;
+ break;
+ }
+ }
+ using_ecc = using_ecc && (s->version == TLS1_VERSION);
+ if (using_ecc)
+ {
+ if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->tlsext_ecpointformatlist_length = 3;
+ s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+
+ /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
+ if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
+ s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_list[0]) * 2;
+ if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
+ {
+ s->tlsext_ellipticcurvelist_length = 0;
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <=
+ sizeof(nid_list)/sizeof(nid_list[0]); i++)
+ s2n(i,j);
+ }
+#endif /* OPENSSL_NO_EC */
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ return -1;
+ }
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+
+ if (r == 2)
+ /* at callback's request, insist on receiving an appropriate server opaque PRF input */
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+#endif
+
+ return 1;
+ }
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+ {
+#ifndef OPENSSL_NO_EC
+ /* If we are server and using an ECC cipher suite, send the point formats we support
+ * if the client sent us an ECPointsFormat extension. Note that the server is not
+ * supposed to send an EllipticCurves extension.
+ */
+
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
+ using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+
+ if (using_ecc)
+ {
+ if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->tlsext_ecpointformatlist_length = 3;
+ s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ }
+#endif /* OPENSSL_NO_EC */
+
+ return 1;
+ }
+
+int ssl_check_clienthello_tlsext(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* The handling of the ECPointFormats extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+ /* The handling of the EllipticCurves extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+#endif
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed.
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
+ * but we might be sending an alert in response to the client hello,
+ * so this has to happen here in ssl_check_clienthello_tlsext(). */
+
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ s->s3->server_opaque_prf_input = NULL;
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL &&
+ s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
+ {
+ /* can only use this extension if we have a server opaque PRF input
+ * of the same length as the client opaque PRF input! */
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+ }
+
+ if (r == 2 && s->s3->server_opaque_prf_input == NULL)
+ {
+ /* The callback wants to enforce use of the extension,
+ * but we can't do that with the client opaque PRF input;
+ * abort the handshake.
+ */
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+ }
+
+#endif
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+int ssl_check_serverhello_tlsext(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* If we are client and using an elliptic curve cryptography cipher
+ * suite, then if server returns an EC point formats lists extension
+ * it must contain uncompressed.
+ */
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) &&
+ (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) &&
+ ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
+ {
+ /* we are using an ECC cipher */
+ size_t i;
+ unsigned char *list;
+ int found_uncompressed = 0;
+ list = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ {
+ if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+ {
+ found_uncompressed = 1;
+ break;
+ }
+ }
+ if (!found_uncompressed)
+ {
+ SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+ return -1;
+ }
+ }
+ ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input_len > 0)
+ {
+ /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
+ * So first verify that we really have a value from the server too. */
+
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+
+ /* Anytime the server *has* sent an opaque PRF input, we need to check
+ * that we have a client opaque PRF input of the same size. */
+ if (s->s3->client_opaque_prf_input == NULL ||
+ s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ }
+ }
+#endif
+
+ /* If we've requested certificate status and we wont get one
+ * tell the callback
+ */
+ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+ && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ /* Set resp to NULL, resplen to -1 so callback knows
+ * there is no response.
+ */
+ if (s->tlsext_ocsp_resp)
+ {
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = NULL;
+ }
+ s->tlsext_ocsp_resplen = -1;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (r == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ if (r < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
+
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+/* Since the server cache lookup is done early on in the processing of client
+ * hello and other operations depend on the result we need to handle any TLS
+ * session ticket extension at the same time.
+ */
+
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+ const unsigned char *limit, SSL_SESSION **ret)
+ {
+ /* Point after session ID in client hello */
+ const unsigned char *p = session_id + len;
+ unsigned short i;
+
+ /* If tickets disabled behave as if no ticket present
+ * to permit stateful resumption.
+ */
+ if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+ return 1;
+
+ if ((s->version <= SSL3_VERSION) || !limit)
+ return 1;
+ if (p >= limit)
+ return -1;
+ /* Skip past DTLS cookie */
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ {
+ i = *(p++);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ }
+ /* Skip past cipher list */
+ n2s(p, i);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ /* Skip past compression algorithm list */
+ i = *(p++);
+ p += i;
+ if (p > limit)
+ return -1;
+ /* Now at start of extensions */
+ if ((p + 2) >= limit)
+ return 1;
+ n2s(p, i);
+ while ((p + 4) <= limit)
+ {
+ unsigned short type, size;
+ n2s(p, type);
+ n2s(p, size);
+ if (p + size > limit)
+ return 1;
+ if (type == TLSEXT_TYPE_session_ticket)
+ {
+ /* If tickets disabled indicate cache miss which will
+ * trigger a full handshake
+ */
+ if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+ return 1;
+ /* If zero length note client will accept a ticket
+ * and indicate cache miss to trigger full handshake
+ */
+ if (size == 0)
+ {
+ s->tlsext_ticket_expected = 1;
+ return 0; /* Cache miss */
+ }
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
+ return tls_decrypt_ticket(s, p, size, session_id, len,
+ ret);
+ }
+ p += size;
+ }
+ return 1;
+ }
+
+static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
+ const unsigned char *sess_id, int sesslen,
+ SSL_SESSION **psess)
+ {
+ SSL_SESSION *sess;
+ unsigned char *sdec;
+ const unsigned char *p;
+ int slen, mlen, renew_ticket = 0;
+ unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+ HMAC_CTX hctx;
+ EVP_CIPHER_CTX ctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ /* Need at least keyname + iv + some encrypted data */
+ if (eticklen < 48)
+ goto tickerr;
+ /* Initialize session ticket encryption and HMAC contexts */
+ HMAC_CTX_init(&hctx);
+ EVP_CIPHER_CTX_init(&ctx);
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ unsigned char *nctick = (unsigned char *)etick;
+ int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+ &ctx, &hctx, 0);
+ if (rv < 0)
+ return -1;
+ if (rv == 0)
+ goto tickerr;
+ if (rv == 2)
+ renew_ticket = 1;
+ }
+ else
+ {
+ /* Check key name matches */
+ if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
+ goto tickerr;
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, etick + 16);
+ }
+ /* Attempt to process session ticket, first conduct sanity and
+ * integrity checks on ticket.
+ */
+ mlen = HMAC_size(&hctx);
+ if (mlen < 0)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ eticklen -= mlen;
+ /* Check HMAC of encrypted ticket */
+ HMAC_Update(&hctx, etick, eticklen);
+ HMAC_Final(&hctx, tick_hmac, NULL);
+ HMAC_CTX_cleanup(&hctx);
+ if (memcmp(tick_hmac, etick + eticklen, mlen))
+ goto tickerr;
+ /* Attempt to decrypt session data */
+ /* Move p after IV to start of encrypted ticket, update length */
+ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ sdec = OPENSSL_malloc(eticklen);
+ if (!sdec)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
+ if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+ goto tickerr;
+ slen += mlen;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ p = sdec;
+
+ sess = d2i_SSL_SESSION(NULL, &p, slen);
+ OPENSSL_free(sdec);
+ if (sess)
+ {
+ /* The session ID if non-empty is used by some clients to
+ * detect that the ticket has been accepted. So we copy it to
+ * the session structure. If it is empty set length to zero
+ * as required by standard.
+ */
+ if (sesslen)
+ memcpy(sess->session_id, sess_id, sesslen);
+ sess->session_id_length = sesslen;
+ *psess = sess;
+ s->tlsext_ticket_expected = renew_ticket;
+ return 1;
+ }
+ /* If session decrypt failure indicate a cache miss and set state to
+ * send a new ticket
+ */
+ tickerr:
+ s->tlsext_ticket_expected = 1;
+ return 0;
+ }
+
+#endif
|