/* ssl/ssl_ciph.c */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
#include <stdio.h>
#include "objects.h"
+#include "comp.h"
#include "ssl_locl.h"
#define SSL_ENC_DES_IDX 0
NULL,NULL,NULL,NULL,NULL,NULL,
};
+static STACK_OF(SSL_COMP) *ssl_comp_methods=NULL;
+
#define SSL_MD_MD5_IDX 0
-#define SSL_MD_SHA0_IDX 1
-#define SSL_MD_SHA1_IDX 2
-#define SSL_MD_NUM_IDX 3
+#define SSL_MD_SHA1_IDX 1
+#define SSL_MD_NUM_IDX 2
static EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX]={
- NULL,NULL,NULL,
+ NULL,NULL,
};
typedef struct cipher_sort_st
#define CIPHER_ADD 1
#define CIPHER_KILL 2
#define CIPHER_DEL 3
-#define CIPHER_ORDER 4
+#define CIPHER_ORD 4
typedef struct cipher_choice_st
{
int type;
unsigned long algorithms;
unsigned long mask;
- STACK *order;
+ long top;
} CIPHER_CHOICE;
+typedef struct cipher_order_st
+ {
+ SSL_CIPHER *cipher;
+ int active;
+ int dead;
+ struct cipher_order_st *next,*prev;
+ } CIPHER_ORDER;
+
static SSL_CIPHER cipher_aliases[]={
- {0,SSL_TXT_ALL, 0,SSL_ALL, 0,SSL_ALL}, /* must be first */
+ /* Don't include eNULL unless specifically enabled */
+ {0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL, 0,SSL_ALL}, /* must be first */
{0,SSL_TXT_kRSA,0,SSL_kRSA, 0,SSL_MKEY_MASK},
{0,SSL_TXT_kDHr,0,SSL_kDHr, 0,SSL_MKEY_MASK},
{0,SSL_TXT_kDHd,0,SSL_kDHd, 0,SSL_MKEY_MASK},
{0,SSL_TXT_eFZA,0,SSL_eFZA, 0,SSL_ENC_MASK},
{0,SSL_TXT_MD5, 0,SSL_MD5, 0,SSL_MAC_MASK},
- {0,SSL_TXT_SHA0,0,SSL_SHA0, 0,SSL_MAC_MASK},
{0,SSL_TXT_SHA1,0,SSL_SHA1, 0,SSL_MAC_MASK},
{0,SSL_TXT_SHA, 0,SSL_SHA, 0,SSL_MAC_MASK},
{0,SSL_TXT_ADH, 0,SSL_ADH, 0,SSL_AUTH_MASK|SSL_MKEY_MASK},
{0,SSL_TXT_FZA, 0,SSL_FZA, 0,SSL_AUTH_MASK|SSL_MKEY_MASK|SSL_ENC_MASK},
- {0,SSL_TXT_EXP, 0,SSL_EXP, 0,SSL_EXP_MASK},
- {0,SSL_TXT_EXPORT,0,SSL_EXPORT,0,SSL_EXP_MASK},
- {0,SSL_TXT_SSLV2,0,SSL_SSLV2,0,SSL_SSL_MASK},
- {0,SSL_TXT_SSLV3,0,SSL_SSLV3,0,SSL_SSL_MASK},
- {0,SSL_TXT_LOW, 0,SSL_LOW,0,SSL_STRONG_MASK},
+ {0,SSL_TXT_EXP40, 0,SSL_EXP40, 0,SSL_EXP_MASK},
+ {0,SSL_TXT_EXPORT,0,SSL_EXP40, 0,SSL_EXP_MASK},
+ {0,SSL_TXT_EXP56, 0,SSL_EXP56, 0,SSL_EXP_MASK},
+ {0,SSL_TXT_SSLV2, 0,SSL_SSLV2, 0,SSL_SSL_MASK},
+ {0,SSL_TXT_SSLV3, 0,SSL_SSLV3, 0,SSL_SSL_MASK},
+ {0,SSL_TXT_TLSV1, 0,SSL_TLSV1, 0,SSL_SSL_MASK},
+ {0,SSL_TXT_LOW, 0,SSL_LOW, 0,SSL_STRONG_MASK},
{0,SSL_TXT_MEDIUM,0,SSL_MEDIUM,0,SSL_STRONG_MASK},
- {0,SSL_TXT_HIGH, 0,SSL_HIGH,0,SSL_STRONG_MASK},
+ {0,SSL_TXT_HIGH, 0,SSL_HIGH, 0,SSL_STRONG_MASK},
};
static int init_ciphers=1;
ssl_digest_methods[SSL_MD_MD5_IDX]=
EVP_get_digestbyname(SN_md5);
- ssl_digest_methods[SSL_MD_SHA0_IDX]=
- EVP_get_digestbyname(SN_sha);
ssl_digest_methods[SSL_MD_SHA1_IDX]=
EVP_get_digestbyname(SN_sha1);
}
-int ssl_cipher_get_evp(c,enc,md)
-SSL_CIPHER *c;
+int ssl_cipher_get_evp(s,enc,md,comp)
+SSL_SESSION *s;
EVP_CIPHER **enc;
EVP_MD **md;
+SSL_COMP **comp;
{
int i;
+ SSL_CIPHER *c;
+ c=s->cipher;
if (c == NULL) return(0);
+ if (comp != NULL)
+ {
+ SSL_COMP ctmp;
+
+ if (s->compress_meth == 0)
+ *comp=NULL;
+ else if (ssl_comp_methods == NULL)
+ {
+ /* bad */
+ *comp=NULL;
+ }
+ else
+ {
+
+ ctmp.id=s->compress_meth;
+ i=sk_SSL_COMP_find(ssl_comp_methods,&ctmp);
+ if (i >= 0)
+ *comp=sk_SSL_COMP_value(ssl_comp_methods,i);
+ else
+ *comp=NULL;
+ }
+ }
+
+ if ((enc == NULL) || (md == NULL)) return(0);
switch (c->algorithms & SSL_ENC_MASK)
{
case SSL_eNULL:
i=SSL_ENC_NULL_IDX;
break;
- break;
default:
i= -1;
break;
case SSL_MD5:
i=SSL_MD_MD5_IDX;
break;
- case SSL_SHA0:
- i=SSL_MD_SHA0_IDX;
- break;
case SSL_SHA1:
i=SSL_MD_SHA1_IDX;
break;
return(0);
}
-STACK *ssl_create_cipher_list(ssl_method,cipher_list,cipher_list_by_id,str)
+#define ITEM_SEP(a) \
+ (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
+
+static void ll_append_tail(head,curr,tail)
+CIPHER_ORDER **head,*curr,**tail;
+ {
+ if (curr == *tail) return;
+ if (curr == *head)
+ *head=curr->next;
+ if (curr->prev != NULL)
+ curr->prev->next=curr->next;
+ if (curr->next != NULL) /* should always be true */
+ curr->next->prev=curr->prev;
+ (*tail)->next=curr;
+ curr->prev= *tail;
+ curr->next=NULL;
+ *tail=curr;
+ }
+
+STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(ssl_method,cipher_list,
+ cipher_list_by_id,str)
SSL_METHOD *ssl_method;
-STACK **cipher_list,**cipher_list_by_id;
+STACK_OF(SSL_CIPHER) **cipher_list,**cipher_list_by_id;
char *str;
{
SSL_CIPHER *c;
char *l;
- STACK *ret=NULL,*ok=NULL;
+ STACK_OF(SSL_CIPHER) *ret=NULL,*ok=NULL;
#define CL_BUF 40
char buf[CL_BUF];
char *tmp_str=NULL;
int i,j,k,num=0,ch,multi;
unsigned long al;
STACK *ca_list=NULL;
- STACK *c_list=NULL;
- int old_x,old_y,current_x,num_x;
+ int current_x,num_x;
CIPHER_CHOICE *ops=NULL;
+ CIPHER_ORDER *list=NULL,*head=NULL,*tail=NULL,*curr,*tail2,*curr2;
+ int list_num;
+ int type;
SSL_CIPHER c_tmp,*cp;
if (str == NULL) return(NULL);
goto err;
}
strcpy(tmp_str,SSL_DEFAULT_CIPHER_LIST);
+ strcat(tmp_str,":");
strcat(tmp_str,&(str[7]));
str=tmp_str;
}
num=ssl_method->num_ciphers();
- if ((ret=(STACK *)sk_new(NULL)) == NULL) goto err;
- if ((c_list=(STACK *)sk_new(NULL)) == NULL) goto err;
+ if ((ret=sk_SSL_CIPHER_new(NULL)) == NULL) goto err;
if ((ca_list=(STACK *)sk_new(cmp_by_name)) == NULL) goto err;
mask =SSL_kFZA;
mask|=SSL_kDHr|SSL_kDHd|SSL_kEDH|SSL_aDH;
#endif
-#ifndef SSL_ALLOW_ENULL
+#ifdef SSL_FORBID_ENULL
mask|=SSL_eNULL;
#endif
mask|=(ssl_cipher_methods[SSL_ENC_eFZA_IDX] == NULL)?SSL_eFZA:0;
mask|=(ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL)?SSL_MD5 :0;
- mask|=(ssl_digest_methods[SSL_MD_SHA0_IDX] == NULL)?SSL_SHA0:0;
mask|=(ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL)?SSL_SHA1:0;
+ if ((list=(CIPHER_ORDER *)Malloc(sizeof(CIPHER_ORDER)*num)) == NULL)
+ goto err;
+
/* Get the initial list of ciphers */
+ list_num=0;
for (i=0; i<num; i++)
{
c=ssl_method->get_cipher((unsigned int)i);
/* drop those that use any of that is not available */
if ((c != NULL) && c->valid && !(c->algorithms & mask))
{
- if (!sk_push(c_list,(char *)c)) goto err;
+ list[list_num].cipher=c;
+ list[list_num].next=NULL;
+ list[list_num].prev=NULL;
+ list[list_num].active=0;
+ list_num++;
if (!sk_push(ca_list,(char *)c)) goto err;
}
}
+
+ for (i=1; i<list_num-1; i++)
+ {
+ list[i].prev= &(list[i-1]);
+ list[i].next= &(list[i+1]);
+ }
+ if (list_num > 0)
+ {
+ head= &(list[0]);
+ head->prev=NULL;
+ head->next= &(list[1]);
+ tail= &(list[list_num-1]);
+ tail->prev= &(list[list_num-2]);
+ tail->next=NULL;
+ }
/* special case */
- cipher_aliases[0].algorithms= ~mask;
+ cipher_aliases[0].algorithms &= ~mask;
/* get the aliases */
k=sizeof(cipher_aliases)/sizeof(SSL_CIPHER);
/* how many parameters are there? */
num=1;
for (l=str; *l; l++)
- if (*l == ':') num++;
+ if (ITEM_SEP(*l))
+ num++;
ops=(CIPHER_CHOICE *)Malloc(sizeof(CIPHER_CHOICE)*num);
if (ops == NULL) goto err;
memset(ops,0,sizeof(CIPHER_CHOICE)*num);
- for (i=0; i<num; i++)
- if ((ops[i].order=sk_new_null()) == NULL) goto err;
/* we now parse the input string and create our operations */
l=str;
for (;;)
{
ch= *l;
+
+ if (ch == '\0') break;
+
if (ch == '-')
{ j=CIPHER_DEL; l++; }
else if (ch == '+')
- { j=CIPHER_ORDER; l++; }
+ { j=CIPHER_ORD; l++; }
else if (ch == '!')
{ j=CIPHER_KILL; l++; }
else
{ j=CIPHER_ADD; }
- if (*l == ':')
+ if (ITEM_SEP(ch))
{
l++;
continue;
if (i >= (CL_BUF-2)) break;
}
buf[i]='\0';
- if (ch != '\0') l++;
/* check for multi-part specification */
- multi=(ch == '+')?1:0;
+ if (ch == '+')
+ {
+ multi=1;
+ l++;
+ }
+ else
+ multi=0;
c_tmp.name=buf;
j=sk_find(ca_list,(char *)&c_tmp);
if (j < 0)
- {
- if (ch == '\0')
- break;
- else
- continue;
- }
+ goto end_loop;
cp=(SSL_CIPHER *)sk_value(ca_list,j);
ops[current_x].algorithms|=cp->algorithms;
}
current_x++;
if (ch == '\0') break;
+end_loop:
+ /* Make sure we scan until the next valid start point */
+ while ((*l != '\0') && ITEM_SEP(*l))
+ l++;
}
num_x=current_x;
current_x=0;
-#ifdef CIPHER_DEBUG
- printf("<--->\n");
-#endif
-
- for (i=0; i<sk_num(c_list); i++)
+ /* We will now process the list of ciphers, once for each category, to
+ * decide what we should do with it. */
+ for (j=0; j<num_x; j++)
{
- old_x= -1;
- old_y= -1;
- cp=(SSL_CIPHER *)sk_value(c_list,i);
-#ifdef CIPHER_DEBUG
- printf("[%s]\n",cp->name);
-#endif
- for (j=0; j<num_x; j++)
+ algorithms=ops[j].algorithms;
+ type=ops[j].type;
+ mask=ops[j].mask;
+
+ curr=head;
+ curr2=head;
+ tail2=tail;
+ for (;;)
{
- algorithms=ops[j].algorithms;
- ma=ops[j].mask & cp->algorithms;
-#ifdef CIPHER_DEBUG
- printf(" %s %08lX&%08lX==0 || %08lX != %08lX \n",
- cp->name,ops[j].mask,cp->algorithms,ma,algorithms);
-#endif
+ if ((curr == NULL) || (curr == tail2)) break;
+ curr=curr2;
+ curr2=curr->next;
+
+ cp=curr->cipher;
+ ma=mask & cp->algorithms;
if ((ma == 0) || ((ma & algorithms) != ma))
{
+ /* does not apply */
continue;
}
- k=ops[j].type;
-#ifdef CIPHER_DEBUG
- printf(">>%s\n",cp->name);
-#endif
/* add the cipher if it has not been added yet. */
- if (k == CIPHER_ADD)
+ if (type == CIPHER_ADD)
{
- if (old_x < 0)
+ if (!curr->active)
{
- old_x=j;
- old_y=sk_num(ops[j].order);
- sk_push(ops[j].order,(char *)cp);
+ ll_append_tail(&head,curr,&tail);
+ curr->active=1;
}
}
/* Move the added cipher to this location */
- else if (k == CIPHER_ORDER)
+ else if (type == CIPHER_ORD)
{
- if (old_x >= 0)
+ if (curr->active)
{
- sk_value(ops[old_x].order,old_y)=NULL;
- old_y=sk_num(ops[j].order);
- sk_push(ops[j].order,(char *)cp);
- old_x=j;
+ ll_append_tail(&head,curr,&tail);
}
}
- /* Remove added cipher */
- else if ((k == CIPHER_DEL) || (k == CIPHER_KILL))
+ else if (type == CIPHER_DEL)
+ curr->active=0;
+ if (type == CIPHER_KILL)
{
- if (old_x >= 0)
- {
- sk_value(ops[old_x].order,old_y)=NULL;
- old_x= -1;
- }
- if (k == CIPHER_KILL)
- break;
+ if (head == curr)
+ head=curr->next;
+ else
+ curr->prev->next=curr->next;
+ if (tail == curr)
+ tail=curr->prev;
+ curr->active=0;
+ if (curr->next != NULL)
+ curr->next->prev=curr->prev;
+ if (curr->prev != NULL)
+ curr->prev->next=curr->next;
+ curr->next=NULL;
+ curr->prev=NULL;
}
}
}
- for (i=0; i<num_x; i++)
+ for (curr=head; curr != NULL; curr=curr->next)
{
- for (j=0; j<sk_num(ops[i].order); j++)
+ if (curr->active)
{
- cp=(SSL_CIPHER *)sk_value(ops[i].order,j);
- if (cp != NULL)
- {
- sk_push(ret,(char *)cp);
+ sk_SSL_CIPHER_push(ret,curr->cipher);
#ifdef CIPHER_DEBUG
- printf("<%s>\n",cp->name);
+ printf("<%s>\n",curr->cipher->name);
#endif
- }
}
}
if (cipher_list != NULL)
{
if (*cipher_list != NULL)
- sk_free(*cipher_list);
+ sk_SSL_CIPHER_free(*cipher_list);
*cipher_list=ret;
}
if (cipher_list_by_id != NULL)
{
if (*cipher_list_by_id != NULL)
- sk_free(*cipher_list_by_id);
- *cipher_list_by_id=sk_dup(ret);
+ sk_SSL_CIPHER_free(*cipher_list_by_id);
+ *cipher_list_by_id=sk_SSL_CIPHER_dup(ret);
}
if ( (cipher_list_by_id == NULL) ||
(cipher_list == NULL) ||
(*cipher_list == NULL))
goto err;
- sk_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
+ sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
ok=ret;
ret=NULL;
err:
if (tmp_str) Free(tmp_str);
- if (ops != NULL)
- {
- for (i=0; i<num; i++)
- if (ops[i].order != NULL)
- sk_free(ops[i].order);
- Free(ops);
- }
- if (ret != NULL) sk_free(ret);
- if (c_list != NULL) sk_free(c_list);
+ if (ops != NULL) Free(ops);
+ if (ret != NULL) sk_SSL_CIPHER_free(ret);
if (ca_list != NULL) sk_free(ca_list);
+ if (list != NULL) Free(list);
return(ok);
}
char *buf;
int len;
{
- int export;
+ int is_export,pkl,kl;
char *ver,*exp;
char *kx,*au,*enc,*mac;
unsigned long alg,alg2;
alg=cipher->algorithms;
alg2=cipher->algorithm2;
- export=(alg&SSL_EXP)?1:0;
- exp=(export)?" export":"";
+ is_export=SSL_IS_EXPORT(alg);
+ pkl=SSL_EXPORT_PKEYLENGTH(alg);
+ kl=SSL_EXPORT_KEYLENGTH(alg);
+ exp=is_export?" export":"";
if (alg & SSL_SSLV2)
ver="SSLv2";
switch (alg&SSL_MKEY_MASK)
{
case SSL_kRSA:
- kx=(export)?"RSA(512)":"RSA";
+ kx=is_export?(pkl == 512 ? "RSA(512)" : "RSA(1024)"):"RSA";
break;
case SSL_kDHr:
kx="DH/RSA";
kx="Fortezza";
break;
case SSL_kEDH:
- kx=(export)?"DH(512)":"DH";
+ kx=is_export?(pkl == 512 ? "DH(512)" : "DH(1024)"):"DH";
break;
default:
kx="unknown";
switch (alg&SSL_ENC_MASK)
{
case SSL_DES:
- enc=export?"DES(40)":"DES(56)";
+ enc=(is_export && kl == 5)?"DES(40)":"DES(56)";
break;
case SSL_3DES:
enc="3DES(168)";
break;
case SSL_RC4:
- enc=export?"RC4(40)":((alg2&SSL2_CF_8_BYTE_ENC)?"RC4(64)":"RC4(128)");
+ enc=is_export?(kl == 5 ? "RC4(40)" : "RC4(56)")
+ :((alg2&SSL2_CF_8_BYTE_ENC)?"RC4(64)":"RC4(128)");
break;
case SSL_RC2:
- enc=export?"RC2(40)":"RC2(128)";
+ enc=is_export?(kl == 5 ? "RC2(40)" : "RC2(56)"):"RC2(128)";
break;
case SSL_IDEA:
enc="IDEA(128)";
case SSL_MD5:
mac="MD5";
break;
- case SSL_SHA0:
- mac="SHA0";
- break;
case SSL_SHA1:
mac="SHA1";
break;
{
int i;
+ if (c == NULL) return("(NONE)");
i=(int)(c->id>>24L);
if (i == 3)
- return("SSLv3");
+ return("TLSv1/SSLv3");
else if (i == 2)
return("SSLv2");
else
int ret=0,a=0;
EVP_CIPHER *enc;
EVP_MD *md;
+ SSL_SESSION ss;
if (c != NULL)
{
- if (!ssl_cipher_get_evp(c,&enc,&md))
+ ss.cipher=c;
+ if (!ssl_cipher_get_evp(&ss,&enc,&md,NULL))
return(0);
a=EVP_CIPHER_key_length(enc)*8;
- if (c->algorithms & SSL_EXP)
+ if (SSL_C_IS_EXPORT(c))
{
- ret=40;
+ ret=SSL_C_EXPORT_KEYLENGTH(c)*8;
}
else
{
return(ret);
}
+SSL_COMP *ssl3_comp_find(sk,n)
+STACK_OF(SSL_COMP) *sk;
+int n;
+ {
+ SSL_COMP *ctmp;
+ int i,nn;
+
+ if ((n == 0) || (sk == NULL)) return(NULL);
+ nn=sk_SSL_COMP_num(sk);
+ for (i=0; i<nn; i++)
+ {
+ ctmp=sk_SSL_COMP_value(sk,i);
+ if (ctmp->id == n)
+ return(ctmp);
+ }
+ return(NULL);
+ }
+
+static int sk_comp_cmp(SSL_COMP **a,SSL_COMP **b)
+ {
+ return((*a)->id-(*b)->id);
+ }
+
+STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods()
+ {
+ return(ssl_comp_methods);
+ }
+
+int SSL_COMP_add_compression_method(id,cm)
+int id;
+COMP_METHOD *cm;
+ {
+ SSL_COMP *comp;
+ STACK_OF(SSL_COMP) *sk;
+
+ comp=(SSL_COMP *)Malloc(sizeof(SSL_COMP));
+ comp->id=id;
+ comp->method=cm;
+ if (ssl_comp_methods == NULL)
+ sk=ssl_comp_methods=sk_SSL_COMP_new(sk_comp_cmp);
+ else
+ sk=ssl_comp_methods;
+ if ((sk == NULL) || !sk_SSL_COMP_push(sk,comp))
+ {
+ SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD,ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ else
+ return(1);
+ }
+