Add SSL_FIPS flag for FIPS 140-2 approved ciphersuites and add a new
[openssl.git] / ssl / ssl_ciph.c
index a9d11ca47481d72b28fb57c97255d80796a4343a..c31d6e0c782f7545364b11da4f8981a071d60240 100644 (file)
 #include <stdio.h>
 #include <openssl/objects.h>
 #include <openssl/comp.h>
+#include <openssl/engine.h>
 #include "ssl_locl.h"
 
 #define SSL_ENC_DES_IDX                0
 #define SSL_ENC_AES256_IDX     7
 #define SSL_ENC_CAMELLIA128_IDX        8
 #define SSL_ENC_CAMELLIA256_IDX        9
-#define SSL_ENC_NUM_IDX                10
+#define SSL_ENC_GOST89_IDX     10
+#define SSL_ENC_SEED_IDX       11
+#define SSL_ENC_NUM_IDX                12
 
 
 static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]={
-       NULL,NULL,NULL,NULL,NULL,NULL,
+       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
        };
 
 #define SSL_COMP_NULL_IDX      0
@@ -170,9 +173,30 @@ static STACK_OF(SSL_COMP) *ssl_comp_methods=NULL;
 
 #define SSL_MD_MD5_IDX 0
 #define SSL_MD_SHA1_IDX        1
-#define SSL_MD_NUM_IDX 2
+#define SSL_MD_GOST94_IDX 2
+#define SSL_MD_GOST89MAC_IDX 3
+/*Constant SSL_MAX_DIGEST equal to size of digests array should be 
+ * defined in the
+ * ssl_locl.h */
+#define SSL_MD_NUM_IDX SSL_MAX_DIGEST 
 static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX]={
-       NULL,NULL,
+       NULL,NULL,NULL,NULL
+       };
+/* PKEY_TYPE for GOST89MAC is known in advance, but, because
+ * implementation is engine-provided, we'll fill it only if
+ * corresponding EVP_PKEY_METHOD is found 
+ */
+static int  ssl_mac_pkey_id[SSL_MD_NUM_IDX]={
+       EVP_PKEY_HMAC,EVP_PKEY_HMAC,EVP_PKEY_HMAC,NID_undef
+       };
+
+static int ssl_mac_secret_size[SSL_MD_NUM_IDX]={
+       0,0,0,0
+       };
+
+static int ssl_handshake_digest_flag[SSL_MD_NUM_IDX]={
+       SSL_HANDSHAKE_MAC_MD5,SSL_HANDSHAKE_MAC_SHA,
+       SSL_HANDSHAKE_MAC_GOST94,0
        };
 
 #define CIPHER_ADD     1
@@ -219,7 +243,7 @@ static const SSL_CIPHER cipher_aliases[]={
        {0,SSL_TXT_ECDH,0,    SSL_kECDHr|SSL_kECDHe|SSL_kEECDH,0,0,0,0,0,0,0,0},
 
         {0,SSL_TXT_kPSK,0,    SSL_kPSK,  0,0,0,0,0,0,0,0},
-
+       {0,SSL_TXT_kGOST,0, SSL_kGOST,0,0,0,0,0,0,0,0},
 
        /* server authentication aliases */
        {0,SSL_TXT_aRSA,0,    0,SSL_aRSA,  0,0,0,0,0,0,0},
@@ -232,7 +256,9 @@ static const SSL_CIPHER cipher_aliases[]={
        {0,SSL_TXT_aECDSA,0,  0,SSL_aECDSA,0,0,0,0,0,0,0},
        {0,SSL_TXT_ECDSA,0,   0,SSL_aECDSA, 0,0,0,0,0,0,0},
         {0,SSL_TXT_aPSK,0,    0,SSL_aPSK,  0,0,0,0,0,0,0},
-
+       {0,SSL_TXT_aGOST94,0,0,SSL_aGOST94,0,0,0,0,0,0,0},
+       {0,SSL_TXT_aGOST01,0,0,SSL_aGOST01,0,0,0,0,0,0,0},
+       {0,SSL_TXT_aGOST,0,0,SSL_aGOST94|SSL_aGOST01,0,0,0,0,0,0,0},
 
        /* aliases combining key exchange and server authentication */
        {0,SSL_TXT_EDH,0,     SSL_kEDH,~SSL_aNULL,0,0,0,0,0,0,0},
@@ -251,6 +277,7 @@ static const SSL_CIPHER cipher_aliases[]={
        {0,SSL_TXT_RC4,0,     0,0,SSL_RC4,   0,0,0,0,0,0},
        {0,SSL_TXT_RC2,0,     0,0,SSL_RC2,   0,0,0,0,0,0},
        {0,SSL_TXT_IDEA,0,    0,0,SSL_IDEA,  0,0,0,0,0,0},
+       {0,SSL_TXT_SEED,0,    0,0,SSL_SEED,  0,0,0,0,0,0},
        {0,SSL_TXT_eNULL,0,   0,0,SSL_eNULL, 0,0,0,0,0,0},
        {0,SSL_TXT_AES128,0,  0,0,SSL_AES128,0,0,0,0,0,0},
        {0,SSL_TXT_AES256,0,  0,0,SSL_AES256,0,0,0,0,0,0},
@@ -263,6 +290,8 @@ static const SSL_CIPHER cipher_aliases[]={
        {0,SSL_TXT_MD5,0,     0,0,0,SSL_MD5,   0,0,0,0,0},
        {0,SSL_TXT_SHA1,0,    0,0,0,SSL_SHA1,  0,0,0,0,0},
        {0,SSL_TXT_SHA,0,     0,0,0,SSL_SHA1,  0,0,0,0,0},
+       {0,SSL_TXT_GOST94,0,     0,0,0,SSL_GOST94,  0,0,0,0,0},
+       {0,SSL_TXT_GOST89MAC,0,     0,0,0,SSL_GOST89MAC,  0,0,0,0,0},
 
        /* protocol version aliases */
        {0,SSL_TXT_SSLV2,0,   0,0,0,0,SSL_SSLV2, 0,0,0,0},
@@ -279,7 +308,25 @@ static const SSL_CIPHER cipher_aliases[]={
        {0,SSL_TXT_LOW,0,     0,0,0,0,0,SSL_LOW,   0,0,0},
        {0,SSL_TXT_MEDIUM,0,  0,0,0,0,0,SSL_MEDIUM,0,0,0},
        {0,SSL_TXT_HIGH,0,    0,0,0,0,0,SSL_HIGH,  0,0,0},
+       /* FIPS 140-2 approved ciphersuite */
+       {0,SSL_TXT_FIPS,0,    0,0,~SSL_eNULL,0,0,SSL_FIPS,  0,0,0},
        };
+/* Search for public key algorithm with given name and 
+ * return its pkey_id if it is available. Otherwise return 0
+ */
+static int get_optional_pkey_id(const char *pkey_name)
+       {
+       const EVP_PKEY_ASN1_METHOD *ameth;
+       ENGINE *tmpeng = NULL;
+       int pkey_id=0;
+       ameth = EVP_PKEY_asn1_find_str(&tmpeng,pkey_name,-1);
+       if (ameth) 
+               {
+               EVP_PKEY_asn1_get0_info(&pkey_id, NULL,NULL,NULL,NULL,ameth);
+               }               
+       if (tmpeng) ENGINE_finish(tmpeng);      
+       return pkey_id;
+       }
 
 void ssl_load_ciphers(void)
        {
@@ -305,14 +352,34 @@ void ssl_load_ciphers(void)
          EVP_get_cipherbyname(SN_camellia_128_cbc);
        ssl_cipher_methods[SSL_ENC_CAMELLIA256_IDX]=
          EVP_get_cipherbyname(SN_camellia_256_cbc);
+       ssl_cipher_methods[SSL_ENC_GOST89_IDX]=
+         EVP_get_cipherbyname(SN_gost89_cnt);
+       ssl_cipher_methods[SSL_ENC_SEED_IDX]=
+         EVP_get_cipherbyname(SN_seed_cbc);
 
        ssl_digest_methods[SSL_MD_MD5_IDX]=
                EVP_get_digestbyname(SN_md5);
+       ssl_mac_secret_size[SSL_MD_MD5_IDX]=
+               EVP_MD_size(ssl_digest_methods[SSL_MD_MD5_IDX]);
        ssl_digest_methods[SSL_MD_SHA1_IDX]=
                EVP_get_digestbyname(SN_sha1);
-       }
-
+       ssl_mac_secret_size[SSL_MD_SHA1_IDX]=
+               EVP_MD_size(ssl_digest_methods[SSL_MD_SHA1_IDX]);
+       ssl_digest_methods[SSL_MD_GOST94_IDX]=
+               EVP_get_digestbyname(SN_id_GostR3411_94);
+       if (ssl_digest_methods[SSL_MD_GOST94_IDX])
+               {       
+               ssl_mac_secret_size[SSL_MD_GOST94_IDX]=
+                       EVP_MD_size(ssl_digest_methods[SSL_MD_GOST94_IDX]);
+               }
+       ssl_digest_methods[SSL_MD_GOST89MAC_IDX]=
+               EVP_get_digestbyname(SN_id_Gost28147_89_MAC);
+               ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] = get_optional_pkey_id("gost-mac");
+               if (ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]) {
+                       ssl_mac_secret_size[SSL_MD_GOST89MAC_IDX]=32;
+               }               
 
+       }
 #ifndef OPENSSL_NO_COMP
 
 static int sk_comp_cmp(const SSL_COMP * const *a,
@@ -367,7 +434,7 @@ static void load_builtin_compressions(void)
 #endif
 
 int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
-            const EVP_MD **md, SSL_COMP **comp)
+            const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size,SSL_COMP **comp)
        {
        int i;
        SSL_CIPHER *c;
@@ -427,6 +494,12 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
        case SSL_CAMELLIA256:
                i=SSL_ENC_CAMELLIA256_IDX;
                break;
+       case SSL_eGOST2814789CNT:
+               i=SSL_ENC_GOST89_IDX;
+               break;
+       case SSL_SEED:
+               i=SSL_ENC_SEED_IDX;
+               break;
        default:
                i= -1;
                break;
@@ -450,21 +523,48 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
        case SSL_SHA1:
                i=SSL_MD_SHA1_IDX;
                break;
+       case SSL_GOST94:
+               i = SSL_MD_GOST94_IDX;
+               break;
+       case SSL_GOST89MAC:
+               i = SSL_MD_GOST89MAC_IDX;
+               break;
        default:
                i= -1;
                break;
                }
        if ((i < 0) || (i > SSL_MD_NUM_IDX))
-               *md=NULL;
+       {
+               *md=NULL; 
+               if (mac_pkey_type!=NULL) *mac_pkey_type = NID_undef;
+               if (mac_secret_size!=NULL) *mac_secret_size = 0;
+
+       }
        else
+       {
                *md=ssl_digest_methods[i];
+               if (mac_pkey_type!=NULL) *mac_pkey_type = ssl_mac_pkey_id[i];
+               if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i];
+       }       
 
-       if ((*enc != NULL) && (*md != NULL))
+       if ((*enc != NULL) && (*md != NULL) && (!mac_pkey_type||*mac_pkey_type != NID_undef))
                return(1);
        else
                return(0);
        }
 
+int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md) 
+{
+       if (idx <0||idx>=SSL_MD_NUM_IDX) 
+               {
+               return 0;
+               }
+       if (ssl_handshake_digest_flag[idx]==0) return 0;
+       *mask = ssl_handshake_digest_flag[idx];
+       *md = ssl_digest_methods[idx];
+       return 1;
+}
+
 #define ITEM_SEP(a) \
        (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
 
@@ -476,7 +576,7 @@ static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr,
                *head=curr->next;
        if (curr->prev != NULL)
                curr->prev->next=curr->next;
-       if (curr->next != NULL) /* should always be true */
+       if (curr->next != NULL)
                curr->next->prev=curr->prev;
        (*tail)->next=curr;
        curr->prev= *tail;
@@ -484,6 +584,22 @@ static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr,
        *tail=curr;
        }
 
+static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+            CIPHER_ORDER **tail)
+       {
+       if (curr == *head) return;
+       if (curr == *tail)
+               *tail=curr->prev;
+       if (curr->next != NULL)
+               curr->next->prev=curr->prev;
+       if (curr->prev != NULL)
+               curr->prev->next=curr->next;
+       (*head)->prev=curr;
+       curr->next= *head;
+       curr->prev=NULL;
+       *head=curr;
+       }
+
 static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *enc, unsigned long *mac, unsigned long *ssl)
        {
        *mkey = 0;
@@ -520,9 +636,23 @@ static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, un
        *mkey |= SSL_kPSK;
        *auth |= SSL_aPSK;
 #endif
+       /* Check for presence of GOST 34.10 algorithms, and if they
+        * do not present, disable  appropriate auth and key exchange */
+       if (!get_optional_pkey_id("gost94")) {
+               *auth |= SSL_aGOST94;
+       }
+       if (!get_optional_pkey_id("gost2001")) {
+               *auth |= SSL_aGOST01;
+       }
+       /* Disable GOST key exchange if no GOST signature algs are available * */
+       if ((*auth & (SSL_aGOST94|SSL_aGOST01)) == (SSL_aGOST94|SSL_aGOST01)) {
+               *mkey |= SSL_kGOST;
+       }       
 #ifdef SSL_FORBID_ENULL
        *enc |= SSL_eNULL;
 #endif
+               
+
 
        *enc |= (ssl_cipher_methods[SSL_ENC_DES_IDX ] == NULL) ? SSL_DES :0;
        *enc |= (ssl_cipher_methods[SSL_ENC_3DES_IDX] == NULL) ? SSL_3DES:0;
@@ -533,9 +663,14 @@ static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, un
        *enc |= (ssl_cipher_methods[SSL_ENC_AES256_IDX] == NULL) ? SSL_AES256:0;
        *enc |= (ssl_cipher_methods[SSL_ENC_CAMELLIA128_IDX] == NULL) ? SSL_CAMELLIA128:0;
        *enc |= (ssl_cipher_methods[SSL_ENC_CAMELLIA256_IDX] == NULL) ? SSL_CAMELLIA256:0;
+       *enc |= (ssl_cipher_methods[SSL_ENC_GOST89_IDX] == NULL) ? SSL_eGOST2814789CNT:0;
+       *enc |= (ssl_cipher_methods[SSL_ENC_SEED_IDX] == NULL) ? SSL_SEED:0;
 
        *mac |= (ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL) ? SSL_MD5 :0;
        *mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1:0;
+       *mac |= (ssl_digest_methods[SSL_MD_GOST94_IDX] == NULL) ? SSL_GOST94:0;
+       *mac |= (ssl_digest_methods[SSL_MD_GOST89MAC_IDX] == NULL || ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]==NID_undef)? SSL_GOST89MAC:0;
+
        }
 
 static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
@@ -586,19 +721,27 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
        /*
         * Prepare linked list from list entries
         */     
-       for (i = 1; i < co_list_num - 1; i++)
-               {
-               co_list[i].prev = &(co_list[i-1]);
-               co_list[i].next = &(co_list[i+1]);
-               }
        if (co_list_num > 0)
                {
-               (*head_p) = &(co_list[0]);
-               (*head_p)->prev = NULL;
-               (*head_p)->next = &(co_list[1]);
-               (*tail_p) = &(co_list[co_list_num - 1]);
-               (*tail_p)->prev = &(co_list[co_list_num - 2]);
-               (*tail_p)->next = NULL;
+               co_list[0].prev = NULL;
+
+               if (co_list_num > 1)
+                       {
+                       co_list[0].next = &co_list[1];
+                       
+                       for (i = 1; i < co_list_num - 1; i++)
+                               {
+                               co_list[i].prev = &co_list[i - 1];
+                               co_list[i].next = &co_list[i + 1];
+                               }
+
+                       co_list[co_list_num - 1].prev = &co_list[co_list_num - 2];
+                       }
+               
+               co_list[co_list_num - 1].next = NULL;
+
+               *head_p = &co_list[0];
+               *tail_p = &co_list[co_list_num - 1];
                }
        }
 
@@ -679,22 +822,38 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
                int rule, int strength_bits,
                CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p)
        {
-       CIPHER_ORDER *head, *tail, *curr, *curr2, *tail2;
+       CIPHER_ORDER *head, *tail, *curr, *curr2, *last;
        SSL_CIPHER *cp;
+       int reverse = 0;
 
 #ifdef CIPHER_DEBUG
        printf("Applying rule %d with %08lx/%08lx/%08lx/%08lx/%08lx %08lx (%d)\n",
                rule, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, strength_bits);
 #endif
 
-       curr = head = *head_p;
-       curr2 = head;
-       tail2 = tail = *tail_p;
+       if (rule == CIPHER_DEL)
+               reverse = 1; /* needed to maintain sorting between currently deleted ciphers */
+
+       head = *head_p;
+       tail = *tail_p;
+
+       if (reverse)
+               {
+               curr = tail;
+               last = head;
+               }
+       else
+               {
+               curr = head;
+               last = tail;
+               }
+
+       curr2 = curr;
        for (;;)
                {
-               if ((curr == NULL) || (curr == tail2)) break;
+               if ((curr == NULL) || (curr == last)) break;
                curr = curr2;
-               curr2 = curr->next;
+               curr2 = reverse ? curr->prev : curr->next;
 
                cp = curr->cipher;
 
@@ -736,6 +895,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
                /* add the cipher if it has not been added yet. */
                if (rule == CIPHER_ADD)
                        {
+                       /* reverse == 0 */
                        if (!curr->active)
                                {
                                ll_append_tail(&head, curr, &tail);
@@ -745,15 +905,27 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
                /* Move the added cipher to this location */
                else if (rule == CIPHER_ORD)
                        {
+                       /* reverse == 0 */
                        if (curr->active)
                                {
                                ll_append_tail(&head, curr, &tail);
                                }
                        }
                else if (rule == CIPHER_DEL)
-                       curr->active = 0;
+                       {
+                       /* reverse == 1 */
+                       if (curr->active)
+                               {
+                               /* most recently deleted ciphersuites get best positions
+                                * for any future CIPHER_ADD (note that the CIPHER_DEL loop
+                                * works in reverse to maintain the order) */
+                               ll_append_head(&head, curr, &tail);
+                               curr->active = 0;
+                               }
+                       }
                else if (rule == CIPHER_KILL)
                        {
+                       /* reverse == 0 */
                        if (head == curr)
                                head = curr->next;
                        else
@@ -1123,12 +1295,19 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
 
        /* Now arrange all ciphers by preference: */
 
-       /* Temporarily enabled AES first (preferred cipher) */
+       /* Everything else being equal, prefer ephemeral ECDH over other key exchange mechanisms */
+       ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
+       ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
+
+       /* AES is our preferred symmetric cipher */
        ssl_cipher_apply_rule(0, 0, 0, SSL_AES, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
 
-       /* Temporarily enable everything else */
+       /* Temporarily enable everything else for sorting */
        ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
 
+       /* Low priority for MD5 */
+       ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head, &tail);
+
        /* Move anonymous ciphers to the end.  Usually, these will remain disabled.
         * (For applications that allow them, they aren't too bad, but we prefer
         * authenticated ciphers.) */
@@ -1139,6 +1318,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
        /* ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail); */
        ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
        ssl_cipher_apply_rule(0, SSL_kPSK, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+       ssl_cipher_apply_rule(0, SSL_kKRB5, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
 
        /* RC4 is sort-of broken -- move the the end */
        ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
@@ -1241,7 +1421,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
        if (*cipher_list_by_id != NULL)
                sk_SSL_CIPHER_free(*cipher_list_by_id);
        *cipher_list_by_id = tmp_cipher_list;
-       sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
+       (void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
 
        return(cipherstack);
        }
@@ -1376,6 +1556,9 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len)
        case SSL_CAMELLIA256:
                enc="Camellia(256)";
                break;
+       case SSL_SEED:
+               enc="SEED(128)";
+               break;
        default:
                enc="unknown";
                break;