diff options
Diffstat (limited to 'openssl/ssl')
-rw-r--r-- | openssl/ssl/d1_enc.c | 578 | ||||
-rw-r--r-- | openssl/ssl/d1_pkt.c | 3538 | ||||
-rw-r--r-- | openssl/ssl/install.com | 180 | ||||
-rw-r--r-- | openssl/ssl/s2_srvr.c | 2284 | ||||
-rw-r--r-- | openssl/ssl/ssl-lib.com | 2232 | ||||
-rw-r--r-- | openssl/ssl/t1_lib.c | 3494 |
6 files changed, 6153 insertions, 6153 deletions
diff --git a/openssl/ssl/d1_enc.c b/openssl/ssl/d1_enc.c index d762dc5c5..becbab91c 100644 --- a/openssl/ssl/d1_enc.c +++ b/openssl/ssl/d1_enc.c @@ -1,289 +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)
- 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);
- }
-
+/* 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 79b723a5e..c10514222 100644 --- a/openssl/ssl/d1_pkt.c +++ b/openssl/ssl/d1_pkt.c @@ -1,1769 +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 */
- 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));
- }
+/* 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 c79f76ef9..fe1d7268e 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,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
+$! 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 6643c787c..bc885e8e7 100644 --- a/openssl/ssl/s2_srvr.c +++ b/openssl/ssl/s2_srvr.c @@ -1,1142 +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);
- 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
+/* 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 8847c9bd3..35bdd34de 100644 --- a/openssl/ssl/ssl-lib.com +++ b/openssl/ssl/ssl-lib.com @@ -1,1116 +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)
-$!
-$! 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
+$! +$! 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 1ebad6166..85371c87b 100644 --- a/openssl/ssl/t1_lib.c +++ b/openssl/ssl/t1_lib.c @@ -1,1747 +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;
- 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
+/* 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 |