ssl_ciph.c revision b6c3f7863936abeae522e48a13887dddeb691a45
/* ssl/ssl_ciph.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
* 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 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
* ECC cipher suite support in OpenSSL originally developed by
* SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
*/
#include <stdio.h>
#include "ssl_locl.h"
#define SSL_ENC_DES_IDX 0
#define SSL_ENC_3DES_IDX 1
#define SSL_ENC_RC4_IDX 2
#define SSL_ENC_RC2_IDX 3
#define SSL_ENC_IDEA_IDX 4
#define SSL_ENC_eFZA_IDX 5
#define SSL_ENC_NULL_IDX 6
#define SSL_ENC_AES128_IDX 7
#define SSL_ENC_AES256_IDX 8
#define SSL_ENC_NUM_IDX 9
};
#define SSL_COMP_NULL_IDX 0
#define SSL_COMP_ZLIB_IDX 1
#define SSL_COMP_NUM_IDX 2
#define SSL_MD_MD5_IDX 0
#define SSL_MD_SHA1_IDX 1
#define SSL_MD_NUM_IDX 2
};
#define CIPHER_ADD 1
#define CIPHER_KILL 2
#define CIPHER_DEL 3
#define CIPHER_ORD 4
#define CIPHER_SPECIAL 5
typedef struct cipher_order_st
{
int active;
int dead;
} CIPHER_ORDER;
static const SSL_CIPHER cipher_aliases[]={
/* Don't include eNULL unless specifically enabled. */
/* Don't include ECC in ALL because these ciphers are not yet official. */
{0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL & ~SSL_kECDH & ~SSL_kECDHE, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL}, /* must be first */
/* TODO: COMPLEMENT OF ALL and COMPLEMENT OF DEFAULT do not have ECC cipher suites handled properly. */
#ifndef OPENSSL_NO_IDEA
#endif
};
void ssl_load_ciphers(void)
{
#ifndef OPENSSL_NO_IDEA
#else
#endif
}
#ifndef OPENSSL_NO_COMP
static int sk_comp_cmp(const SSL_COMP * const *a,
const SSL_COMP * const *b)
{
}
static void load_builtin_compressions(void)
{
if (ssl_comp_methods != NULL)
return;
if (ssl_comp_methods == NULL)
{
MemCheck_off();
if (ssl_comp_methods != NULL)
{
{
else
{
}
}
}
MemCheck_on();
}
}
#endif
{
int i;
SSL_CIPHER *c;
c=s->cipher;
if (c == NULL) return(0);
{
#ifndef OPENSSL_NO_COMP
#endif
if (ssl_comp_methods != NULL)
{
if (i >= 0)
else
}
}
switch (c->algorithms & SSL_ENC_MASK)
{
case SSL_DES:
break;
case SSL_3DES:
break;
case SSL_RC4:
break;
case SSL_RC2:
break;
case SSL_IDEA:
break;
case SSL_eNULL:
break;
case SSL_AES:
switch(c->alg_bits)
{
case 128: i=SSL_ENC_AES128_IDX; break;
case 256: i=SSL_ENC_AES256_IDX; break;
default: i=-1; break;
}
break;
default:
i= -1;
break;
}
if ((i < 0) || (i > SSL_ENC_NUM_IDX))
else
{
if (i == SSL_ENC_NULL_IDX)
*enc=EVP_enc_null();
else
*enc=ssl_cipher_methods[i];
}
switch (c->algorithms & SSL_MAC_MASK)
{
case SSL_MD5:
break;
case SSL_SHA1:
break;
default:
i= -1;
break;
}
if ((i < 0) || (i > SSL_MD_NUM_IDX))
else
*md=ssl_digest_methods[i];
return(1);
else
return(0);
}
#define ITEM_SEP(a) \
(((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
CIPHER_ORDER **tail)
{
}
static unsigned long ssl_cipher_get_disabled(void)
{
unsigned long mask;
#ifdef OPENSSL_NO_RSA
#endif
#ifdef OPENSSL_NO_DSA
#endif
#ifdef OPENSSL_NO_DH
#endif
#ifdef OPENSSL_NO_KRB5
#endif
#ifdef OPENSSL_NO_ECDH
#endif
#ifdef SSL_FORBID_ENULL
#endif
return(mask);
}
{
int i, co_list_num;
SSL_CIPHER *c;
/*
* We have num_of_ciphers descriptions compiled in, depending on the
* These will later be sorted in a linked list with at most num
* entries.
*/
/* Get the initial list of ciphers */
co_list_num = 0; /* actual count of ciphers */
for (i = 0; i < num_of_ciphers; i++)
{
c = ssl_method->get_cipher(i);
/* drop those that use any of that is not available */
{
co_list_num++;
#ifdef KSSL_DEBUG
#endif /* KSSL_DEBUG */
/*
if (!sk_push(ca_list,(char *)c)) goto err;
*/
}
}
/*
* Prepare linked list from list entries
*/
{
}
if (co_list_num > 0)
{
}
}
int num_of_group_aliases, unsigned long mask,
{
int i;
/*
* First, add the real ciphers as already collected
*/
{
ca_curr++;
}
/*
* Now we add the available ones from the cipher_aliases[] table.
* They represent either an algorithm, that must be fully
* supported (not match any bit in mask) or represent a cipher
* strength value (will be added in any case because algorithms=0).
*/
for (i = 0; i < num_of_group_aliases; i++)
{
if ((i == 0) || /* always fetch "ALL" */
{
ca_curr++;
}
}
}
unsigned long algo_strength, unsigned long mask_strength,
{
SSL_CIPHER *cp;
#ifdef CIPHER_DEBUG
printf("Applying rule %d with %08lx %08lx %08lx %08lx (%d)\n",
#endif
for (;;)
{
/*
* Selection criteria is either the number of strength_bits
* or the algorithm used.
*/
if (strength_bits == -1)
{
#ifdef CIPHER_DEBUG
printf("\nName: %s:\nAlgo = %08lx Algo_strength = %08lx\nMask = %08lx Mask_strength %08lx\n", cp->name, cp->algorithms, cp->algo_strength, mask, mask_strength);
printf("ma = %08lx ma_s %08lx, ma&algo=%08lx, ma_s&algos=%08lx\n", ma, ma_s, ma&algorithms, ma_s&algo_strength);
#endif
/*
* Select: if none of the mask bit was met from the
* cipher or not all of the bits were met, the
* selection does not apply.
*/
continue; /* does not apply */
}
continue; /* does not apply */
#ifdef CIPHER_DEBUG
#endif
/* add the cipher if it has not been added yet. */
if (rule == CIPHER_ADD)
{
{
}
}
/* Move the added cipher to this location */
else if (rule == CIPHER_ORD)
{
{
}
}
else if (rule == CIPHER_DEL)
else if (rule == CIPHER_KILL)
{
else
}
}
}
{
int max_strength_bits, i, *number_uses;
/*
* This routine sorts the ciphers with descending strength. The sorting
* must keep the pre-sorted sequence, so we apply the normal sorting
* routine as '+' movement to the end of the list.
*/
max_strength_bits = 0;
{
}
if (!number_uses)
{
return(0);
}
/*
* Now find the strength_bits values actually used
*/
{
}
/*
* Go through the list of used strength_bits values in descending
* order.
*/
for (i = max_strength_bits; i >= 0; i--)
if (number_uses[i] > 0)
ssl_cipher_apply_rule(0, 0, 0, 0, CIPHER_ORD, i,
return(1);
}
static int ssl_cipher_process_rulestr(const char *rule_str,
{
char ch;
retval = 1;
l = rule_str;
for (;;)
{
ch = *l;
if (ch == '\0')
break; /* done */
if (ch == '-')
{ rule = CIPHER_DEL; l++; }
else if (ch == '+')
{ rule = CIPHER_ORD; l++; }
else if (ch == '!')
{ rule = CIPHER_KILL; l++; }
else if (ch == '@')
{ rule = CIPHER_SPECIAL; l++; }
else
{ rule = CIPHER_ADD; }
{
l++;
continue;
}
start=l;
for (;;)
{
ch = *l;
buf = l;
buflen = 0;
#ifndef CHARSET_EBCDIC
(ch == '-'))
#else
#endif
{
ch = *(++l);
buflen++;
}
if (buflen == 0)
{
/*
* We hit something we cannot deal with,
* it is no command or separator nor
* alphanumeric, so we call this an error.
*/
l++;
break;
}
if (rule == CIPHER_SPECIAL)
{
found = 0; /* unused -- avoid compiler warning */
break; /* special treatment */
}
/* check for multi-part specification */
if (ch == '+')
{
multi=1;
l++;
}
else
multi=0;
/*
* Now search for the cipher alias in the ca_list. Be careful
* with the strncmp, because the "buflen" limitation
* will make the rule "ADH:SOME" and the cipher
* "ADH-MY-CIPHER" look like a match for buflen=3.
* So additionally check whether the cipher name found
* has the correct length. We can save a strlen() call:
* just checking for the '\0' at the right place is
* sufficient, we have to strncmp() anyway. (We cannot
* use strcmp(), because buf is not '\0' terminated.)
*/
j = found = 0;
while (ca_list[j])
{
{
found = 1;
break;
}
else
j++;
}
if (!found)
break; /* ignore this entry */
/* New algorithms:
* 1 - any old restrictions apply outside new mask
* 2 - any new restrictions apply outside old mask
* 3 - enforce old & new where masks intersect
*/
if (!multi) break;
}
/*
* Ok, we have the rule, now apply it
*/
if (rule == CIPHER_SPECIAL)
{ /* special command */
ok = 0;
if ((buflen == 8) &&
else
if (ok == 0)
retval = 0;
/*
* We do not support any "multi" options
* together with "@", so throw away the
* rest of the command, if any left, until
* end or ':' is found.
*/
while ((*l != '\0') && ITEM_SEP(*l))
l++;
}
else if (found)
{
}
else
{
while ((*l != '\0') && ITEM_SEP(*l))
l++;
}
if (*l == '\0') break; /* done */
}
return(retval);
}
const char *rule_str)
{
unsigned long disabled_mask;
const char *rule_p;
/*
* Return with error if nothing to do.
*/
return NULL;
/*
* To reduce the work to do we only want to process the compiled
* in algorithms, so we first get the mask of disabled ciphers.
*/
/*
* Now we have to collect the available ciphers from the compiled
* in ciphers. We cannot get more than the number compiled in, so
* it is used for allocation.
*/
#ifdef KSSL_DEBUG
#endif /* KSSL_DEBUG */
{
return(NULL); /* Failure */
}
/*
* We also need cipher aliases for selecting based on the rule_str.
* There might be two types of entries in the rule_str: 1) names
* of ciphers themselves 2) aliases for groups of ciphers.
* For 1) we need the available ciphers and for 2) the cipher
* groups of cipher_aliases added together in one list (otherwise
* we would be happy with just the cipher_aliases table).
*/
ca_list =
{
return(NULL); /* Failure */
}
head);
/*
* If the rule_string begins with DEFAULT, apply the default rule
* before using the (possibly available) additional rules.
*/
ok = 1;
{
rule_p += 7;
if (*rule_p == ':')
rule_p++;
}
ca_list);
if (!ok)
{ /* Rule processing failure */
return(NULL);
}
/*
* Allocate new "cipherstack" for the result, return with error
* if we cannot get one.
*/
{
return(NULL);
}
/*
* The cipher selection for the list is done. The ciphers are added
* to the resulting precedence to the STACK_OF(SSL_CIPHER).
*/
{
{
#ifdef CIPHER_DEBUG
#endif
}
}
if (tmp_cipher_list == NULL)
{
return NULL;
}
if (*cipher_list != NULL)
if (*cipher_list_by_id != NULL)
return(cipherstack);
}
{
#ifdef KSSL_DEBUG
static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s AL=%lx\n";
#else
static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s\n";
#endif /* KSSL_DEBUG */
ver="SSLv2";
ver="SSLv3";
else
ver="unknown";
switch (alg&SSL_MKEY_MASK)
{
case SSL_kRSA:
break;
case SSL_kDHr:
break;
case SSL_kDHd:
break;
case SSL_kKRB5: /* VRS */
case SSL_KRB5: /* VRS */
kx="KRB5";
break;
case SSL_kFZA:
kx="Fortezza";
break;
case SSL_kEDH:
break;
case SSL_kECDH:
case SSL_kECDHE:
break;
default:
kx="unknown";
}
switch (alg&SSL_AUTH_MASK)
{
case SSL_aRSA:
au="RSA";
break;
case SSL_aDSS:
au="DSS";
break;
case SSL_aDH:
au="DH";
break;
case SSL_aKRB5: /* VRS */
case SSL_KRB5: /* VRS */
au="KRB5";
break;
case SSL_aFZA:
case SSL_aNULL:
au="None";
break;
case SSL_aECDSA:
au="ECDSA";
break;
default:
au="unknown";
break;
}
switch (alg&SSL_ENC_MASK)
{
case SSL_DES:
break;
case SSL_3DES:
enc="3DES(168)";
break;
case SSL_RC4:
break;
case SSL_RC2:
break;
case SSL_IDEA:
enc="IDEA(128)";
break;
case SSL_eFZA:
enc="Fortezza";
break;
case SSL_eNULL:
enc="None";
break;
case SSL_AES:
switch(cipher->strength_bits)
{
}
break;
default:
enc="unknown";
break;
}
switch (alg&SSL_MAC_MASK)
{
case SSL_MD5:
mac="MD5";
break;
case SSL_SHA1:
mac="SHA1";
break;
default:
mac="unknown";
break;
}
{
len=128;
}
else if (len < 128)
return("Buffer too small");
#ifdef KSSL_DEBUG
#else
#endif /* KSSL_DEBUG */
return(buf);
}
char *SSL_CIPHER_get_version(const SSL_CIPHER *c)
{
int i;
if (c == NULL) return("(NONE)");
i=(int)(c->id>>24L);
if (i == 3)
else if (i == 2)
return("SSLv2");
else
return("unknown");
}
/* return the actual cipher being used */
const char *SSL_CIPHER_get_name(const SSL_CIPHER *c)
{
if (c != NULL)
return(c->name);
return("(NONE)");
}
/* number of bits for symmetric cipher */
{
int ret=0;
if (c != NULL)
{
ret = c->strength_bits;
}
return(ret);
}
{
int i,nn;
for (i=0; i<nn; i++)
{
return(ctmp);
}
return(NULL);
}
#ifdef OPENSSL_NO_COMP
void *SSL_COMP_get_compression_methods(void)
{
return NULL;
}
{
return 1;
}
const char *SSL_COMP_get_name(const void *comp)
{
return NULL;
}
#else
{
return(ssl_comp_methods);
}
{
return 1;
/* According to draft-ietf-tls-compression-04.txt, the
compression number ranges should be the following:
0 to 63: methods defined by the IETF
64 to 192: external party methods assigned by IANA
193 to 255: reserved for private use */
{
return 0;
}
MemCheck_off();
if (ssl_comp_methods
{
MemCheck_on();
return(1);
}
else if ((ssl_comp_methods == NULL)
{
MemCheck_on();
return(1);
}
else
{
MemCheck_on();
return(0);
}
}
{
if (comp)
return NULL;
}
#endif