passing chunks, not prf+, to kernel interface
authorMartin Willi <martin@strongswan.org>
Tue, 14 Oct 2008 15:17:44 +0000 (15:17 -0000)
committerMartin Willi <martin@strongswan.org>
Tue, 14 Oct 2008 15:17:44 +0000 (15:17 -0000)
gives us better control of keymat in CHILD_SA

src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/kernel/kernel_ipsec.h
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/charon/sa/child_sa.c
src/charon/sa/ike_sa.c

index e2d508d..f71e3c5 100644 (file)
@@ -85,14 +85,13 @@ static status_t get_cpi(private_kernel_interface_t *this, host_t *src, host_t *d
 static status_t add_sa(private_kernel_interface_t *this, host_t *src, host_t *dst,
                                u_int32_t spi, protocol_id_t protocol, u_int32_t reqid,
                                u_int64_t expire_soft, u_int64_t expire_hard,
-                               u_int16_t enc_alg, u_int16_t enc_size,
-                               u_int16_t int_alg, u_int16_t int_size,
-                               prf_plus_t *prf_plus, ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
-                               bool update)
+                               u_int16_t enc_alg, chunk_t enc_key,
+                               u_int16_t int_alg, chunk_t int_key,
+                               ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool update)
 {
        return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
-                       expire_soft, expire_hard, enc_alg, enc_size, int_alg, int_size,
-                       prf_plus, mode, ipcomp, encap, update);
+                       expire_soft, expire_hard, enc_alg, enc_key, int_alg, int_key,
+                       mode, ipcomp, encap, update);
 }
 
 /**
@@ -371,7 +370,7 @@ kernel_interface_t *kernel_interface_create()
        
        this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.get_cpi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
+       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
        this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
        this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy;
index a2a83b6..aec4924 100644 (file)
@@ -101,10 +101,9 @@ struct kernel_interface_t {
         * @param expire_soft   lifetime in seconds before rekeying
         * @param expire_hard   lifetime in seconds before delete
         * @param enc_alg               Algorithm to use for encryption (ESP only)
-        * @param enc_size              key length of encryption algorithm, if dynamic
+        * @param enc_key               key to use for encryption
         * @param int_alg               Algorithm to use for integrity protection
-        * @param int_size              key length of integrity algorithm, if dynamic
-        * @param prf_plus              PRF to derive keys from
+        * @param int_key               key to use for integrity protection
         * @param mode                  mode of the SA (tunnel, transport)
         * @param ipcomp                IPComp transform to use
         * @param encap                 enable UDP encapsulation for NAT traversal
@@ -115,10 +114,9 @@ struct kernel_interface_t {
                                                host_t *src, host_t *dst, u_int32_t spi,
                                                protocol_id_t protocol, u_int32_t reqid,
                                                u_int64_t expire_soft, u_int64_t expire_hard,
-                                           u_int16_t enc_alg, u_int16_t enc_size,
-                                           u_int16_t int_alg, u_int16_t int_size,
-                                               prf_plus_t *prf_plus, ipsec_mode_t mode,
-                                               u_int16_t ipcomp, bool encap,
+                                           u_int16_t enc_alg, chunk_t enc_key,
+                                           u_int16_t int_alg, chunk_t int_key,
+                                               ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
                                                bool update);
        
        /**
index 8fa5fb0..bef496a 100644 (file)
@@ -133,10 +133,9 @@ struct kernel_ipsec_t {
         * @param expire_soft   lifetime in seconds before rekeying
         * @param expire_hard   lifetime in seconds before delete
         * @param enc_alg               Algorithm to use for encryption (ESP only)
-        * @param enc_size              key length of encryption algorithm, if dynamic
+        * @param enc_key               key to use for encryption
         * @param int_alg               Algorithm to use for integrity protection
-        * @param int_size              key length of integrity algorithm, if dynamic
-        * @param prf_plus              PRF to derive keys from
+        * @param int_key               key to use for integrity protection
         * @param mode                  mode of the SA (tunnel, transport)
         * @param ipcomp                IPComp transform to use
         * @param encap                 enable UDP encapsulation for NAT traversal
@@ -147,10 +146,9 @@ struct kernel_ipsec_t {
                                                host_t *src, host_t *dst, u_int32_t spi,
                                                protocol_id_t protocol, u_int32_t reqid,
                                                u_int64_t expire_soft, u_int64_t expire_hard,
-                                           u_int16_t enc_alg, u_int16_t enc_size,
-                                           u_int16_t int_alg, u_int16_t int_size,
-                                               prf_plus_t *prf_plus, ipsec_mode_t mode,
-                                               u_int16_t ipcomp, bool encap,
+                                           u_int16_t enc_alg, chunk_t enc_key,
+                                           u_int16_t int_alg, chunk_t int_key,
+                                               ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
                                                bool update);
        
        /**
index 7fb6a26..1b526e6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2006-2008 Tobias Brunner
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005 Jan Hutter
 typedef struct kernel_algorithm_t kernel_algorithm_t;
 
 /**
- * Mapping from the algorithms defined in IKEv2 to
- * kernel level algorithm names and their key length
+ * Mapping of IKEv2 kernel identifier to linux crypto API names
  */
 struct kernel_algorithm_t {
        /**
         * Identifier specified in IKEv2
         */
-       int ikev2_id;
+       int ikev2;
        
        /**
-        * Name of the algorithm, as used as kernel identifier
+        * Name of the algorithm in linux crypto API
         */
        char *name;
-       
-       /**
-        * Key length in bits, if fixed size
-        */
-       u_int key_size;
 };
 
 #define END_OF_LIST -1
@@ -102,71 +96,65 @@ struct kernel_algorithm_t {
  * Algorithms for encryption
  */
 static kernel_algorithm_t encryption_algs[] = {
-/*     {ENCR_DES_IV64,                 "***",                                  0}, */
-       {ENCR_DES,                              "des",                                  64},
-       {ENCR_3DES,                     "des3_ede",                             192},
-/*     {ENCR_RC5,                              "***",                                  0}, */
-/*     {ENCR_IDEA,                     "***",                                  0}, */
-       {ENCR_CAST,                     "cast128",                              0},
-       {ENCR_BLOWFISH,                 "blowfish",                             0},
-/*     {ENCR_3IDEA,                    "***",                                  0}, */
-/*     {ENCR_DES_IV32,                 "***",                                  0}, */
-       {ENCR_NULL,                     "cipher_null",                  0},
-       {ENCR_AES_CBC,                  "aes",                                  0},
-/*     {ENCR_AES_CTR,                  "***",                                  0}, */
-       {ENCR_AES_CCM_ICV8,             "rfc4309(ccm(aes))",    64},    /* key_size = ICV size */
-       {ENCR_AES_CCM_ICV12,    "rfc4309(ccm(aes))",    96},    /* key_size = ICV size */
-       {ENCR_AES_CCM_ICV16,    "rfc4309(ccm(aes))",    128},   /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV8,             "rfc4106(gcm(aes))",    64},    /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV12,    "rfc4106(gcm(aes))",    96},    /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV16,    "rfc4106(gcm(aes))",    128},   /* key_size = ICV size */
-       {END_OF_LIST,           NULL,                   0},
+/*     {ENCR_DES_IV64,                         "***"                           }, */
+       {ENCR_DES,                                      "des"                           },
+       {ENCR_3DES,                             "des3_ede"                      },
+/*     {ENCR_RC5,                                      "***"                           }, */
+/*     {ENCR_IDEA,                             "***"                           }, */
+       {ENCR_CAST,                             "cast128"                       },
+       {ENCR_BLOWFISH,                         "blowfish"                      },
+/*     {ENCR_3IDEA,                            "***"                           }, */
+/*     {ENCR_DES_IV32,                         "***"                           }, */
+       {ENCR_NULL,                             "cipher_null"           },
+       {ENCR_AES_CBC,                          "aes"                           },
+/*     {ENCR_AES_CTR,                          "***"                           }, */
+       {ENCR_AES_CCM_ICV8,                     "rfc4309(ccm(aes))"     },
+       {ENCR_AES_CCM_ICV12,            "rfc4309(ccm(aes))"     },
+       {ENCR_AES_CCM_ICV16,            "rfc4309(ccm(aes))"     },
+       {ENCR_AES_GCM_ICV8,                     "rfc4106(gcm(aes))"     },
+       {ENCR_AES_GCM_ICV12,            "rfc4106(gcm(aes))"     },
+       {ENCR_AES_GCM_ICV16,            "rfc4106(gcm(aes))"     },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Algorithms for integrity protection
  */
 static kernel_algorithm_t integrity_algs[] = {
-       {AUTH_HMAC_MD5_96,                      "md5",                  128},
-       {AUTH_HMAC_SHA1_96,                     "sha1",                 160},
-       {AUTH_HMAC_SHA2_256_128,        "sha256",               256},
-       {AUTH_HMAC_SHA2_384_192,        "sha384",               384},
-       {AUTH_HMAC_SHA2_512_256,        "sha512",               512},
-/*     {AUTH_DES_MAC,                          "***",                  0}, */
-/*     {AUTH_KPDK_MD5,                         "***",                  0}, */
-       {AUTH_AES_XCBC_96,                      "xcbc(aes)",    128},
-       {END_OF_LIST,                           NULL,                   0},
+       {AUTH_HMAC_MD5_96,                      "md5"                           },
+       {AUTH_HMAC_SHA1_96,                     "sha1"                          },
+       {AUTH_HMAC_SHA2_256_128,        "sha256"                        },
+       {AUTH_HMAC_SHA2_384_192,        "sha384"                        },
+       {AUTH_HMAC_SHA2_512_256,        "sha512"                        },
+/*     {AUTH_DES_MAC,                          "***"                           }, */
+/*     {AUTH_KPDK_MD5,                         "***"                           }, */
+       {AUTH_AES_XCBC_96,                      "xcbc(aes)"                     },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Algorithms for IPComp
  */
 static kernel_algorithm_t compression_algs[] = {
-/*     {IPCOMP_OUI,                    "***",                  0}, */
-       {IPCOMP_DEFLATE,                "deflate",              0},
-       {IPCOMP_LZS,                    "lzs",                  0},
-       {IPCOMP_LZJH,                   "lzjh",                 0},
-       {END_OF_LIST,                   NULL,                   0},
+/*     {IPCOMP_OUI,                            "***"                           }, */
+       {IPCOMP_DEFLATE,                        "deflate"                       },
+       {IPCOMP_LZS,                            "lzs"                           },
+       {IPCOMP_LZJH,                           "lzjh"                          },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Look up a kernel algorithm name and its key size
  */
-static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, 
-                                          u_int16_t ikev2_algo, u_int16_t *key_size)
+static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2)
 {
-       while (kernel_algo->ikev2_id != END_OF_LIST)
+       while (list->ikev2 != END_OF_LIST)
        {
-               if (ikev2_algo == kernel_algo->ikev2_id)
+               if (list->ikev2 == ikev2)
                {
-                       /* match, evaluate key length */
-                       if (key_size && *key_size == 0)
-                       {       /* update key size if not set */
-                               *key_size = kernel_algo->key_size;
-                       }
-                       return kernel_algo->name;
+                       return list->name;
                }
-               kernel_algo++;
+               list++;
        }
        return NULL;
 }
@@ -688,23 +676,22 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                           host_t *src, host_t *dst, u_int32_t spi,
                                           protocol_id_t protocol, u_int32_t reqid,
                                           u_int64_t expire_soft, u_int64_t expire_hard,
-                                          u_int16_t enc_alg, u_int16_t enc_size,
-                                          u_int16_t int_alg, u_int16_t int_size,
-                                          prf_plus_t *prf_plus, ipsec_mode_t mode,
-                                          u_int16_t ipcomp, bool encap,
+                                          u_int16_t enc_alg, chunk_t enc_key,
+                                          u_int16_t int_alg, chunk_t int_key,
+                                          ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
                                           bool replace)
 {
        unsigned char request[NETLINK_BUFFER_SIZE];
        char *alg_name;
-       /* additional 4 octets KEYMAT required for AES-GCM as of RFC4106 8.1. */
-       u_int16_t add_keymat = 32; 
        struct nlmsghdr *hdr;
        struct xfrm_usersa_info *sa;
+       u_int16_t icv_size = 64;        
        
        memset(&request, 0, sizeof(request));
        
-       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
-
+       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}",
+                ntohl(spi), reqid);
+       
        hdr = (struct nlmsghdr*)request;
        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
@@ -741,19 +728,19 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                case ENCR_UNDEFINED:
                        /* no encryption */
                        break;
-               case ENCR_AES_CCM_ICV8:
-               case ENCR_AES_CCM_ICV12:
                case ENCR_AES_CCM_ICV16:
-                       /* AES-CCM needs only 3 additional octets KEYMAT as of RFC 4309 7.1. */
-                       add_keymat = 24;
-                       /* fall-through */
-               case ENCR_AES_GCM_ICV8:
-               case ENCR_AES_GCM_ICV12:
                case ENCR_AES_GCM_ICV16:
+                       icv_size += 32;
+                       /* FALL */
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_GCM_ICV12:
+                       icv_size += 32;
+                       /* FALL */
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_GCM_ICV8:
                {
-                       u_int16_t icv_size = 0;
                        rthdr->rta_type = XFRMA_ALG_AEAD;
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg, &icv_size);
+                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
                        if (alg_name == NULL)
                        {
                                DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
@@ -761,12 +748,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                return FAILED;
                        }
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_size);
-                       
-                       /* additional KEYMAT required */
-                       enc_size += add_keymat;
+                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
                        
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_size / 8);
+                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len);
                        hdr->nlmsg_len += rthdr->rta_len;
                        if (hdr->nlmsg_len > sizeof(request))
                        {
@@ -774,10 +758,10 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        }
                        
                        struct xfrm_algo_aead* algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_size;
+                       algo->alg_key_len = enc_key.len * 8;
                        algo->alg_icv_len = icv_size;
                        strcpy(algo->alg_name, alg_name);
-                       prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key);
+                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
                        
                        rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
@@ -785,7 +769,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                default:
                {
                        rthdr->rta_type = XFRMA_ALG_CRYPT;
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg, &enc_size);
+                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
                        if (alg_name == NULL)
                        {
                                DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
@@ -793,9 +777,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                return FAILED;
                        }
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_size);
+                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
                        
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_size / 8);
+                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len);
                        hdr->nlmsg_len += rthdr->rta_len;
                        if (hdr->nlmsg_len > sizeof(request))
                        {
@@ -803,9 +787,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        }
                        
                        struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_size;
+                       algo->alg_key_len = enc_key.len * 8;
                        strcpy(algo->alg_name, alg_name);
-                       prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key);
+                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
                        
                        rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
@@ -815,7 +799,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        if (int_alg  != AUTH_UNDEFINED)
        {
                rthdr->rta_type = XFRMA_ALG_AUTH;
-               alg_name = lookup_algorithm(integrity_algs, int_alg, &int_size);
+               alg_name = lookup_algorithm(integrity_algs, int_alg);
                if (alg_name == NULL)
                {
                        DBG1(DBG_KNL, "algorithm %N not supported by kernel!", 
@@ -823,9 +807,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        return FAILED;
                }
                DBG2(DBG_KNL, "  using integrity algorithm %N with key size %d",
-                        integrity_algorithm_names, int_alg, int_size);
+                        integrity_algorithm_names, int_alg, int_key.len * 8);
                
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_size / 8);
+               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len);
                hdr->nlmsg_len += rthdr->rta_len;
                if (hdr->nlmsg_len > sizeof(request))
                {
@@ -833,9 +817,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                }
                
                struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-               algo->alg_key_len = int_size;
+               algo->alg_key_len = int_key.len * 8;
                strcpy(algo->alg_name, alg_name);
-               prf_plus->get_bytes(prf_plus, int_size / 8, algo->alg_key);
+               memcpy(algo->alg_key, int_key.ptr, int_key.len);
                
                rthdr = XFRM_RTA_NEXT(rthdr);
        }
@@ -843,7 +827,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        if (ipcomp != IPCOMP_NONE)
        {
                rthdr->rta_type = XFRMA_ALG_COMP;
-               alg_name = lookup_algorithm(compression_algs, ipcomp, NULL);
+               alg_name = lookup_algorithm(compression_algs, ipcomp);
                if (alg_name == NULL)
                {
                        DBG1(DBG_KNL, "algorithm %N not supported by kernel!", 
@@ -1559,7 +1543,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
+       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
        this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy;
index dec43e2..50d6322 100644 (file)
@@ -384,24 +384,18 @@ static u_int8_t dir2kernel(policy_dir_t dir)
 typedef struct kernel_algorithm_t kernel_algorithm_t;
 
 /**
- * Mapping from the algorithms defined in IKEv2 to
- * kernel level algorithm identifiers and their key length
+ * Mapping of IKEv2 algorithms to PF_KEY algorithms
  */
 struct kernel_algorithm_t {
        /**
         * Identifier specified in IKEv2
         */
-       int ikev2_id;
+       int ikev2;
        
        /**
         * Identifier as defined in pfkeyv2.h
         */
-       int kernel_id;
-       
-       /**
-        * Key length in bits, if fixed size
-        */
-       u_int key_size;
+       int kernel;
 };
 
 #define END_OF_LIST -1
@@ -410,71 +404,65 @@ struct kernel_algorithm_t {
  * Algorithms for encryption
  */
 static kernel_algorithm_t encryption_algs[] = {
-/*     {ENCR_DES_IV64,                 0,                                                      0},  */
-       {ENCR_DES,                              SADB_EALG_DESCBC,                       64},
-       {ENCR_3DES,                     SADB_EALG_3DESCBC,                      192},
-/*     {ENCR_RC5,                              0,                                                      0},  */
-/*     {ENCR_IDEA,                     0,                                                      0},  */
-       {ENCR_CAST,                     SADB_X_EALG_CASTCBC,            0},
-       {ENCR_BLOWFISH,                 SADB_X_EALG_BLOWFISHCBC,        0},
-/*     {ENCR_3IDEA,                    0,                                                      0},  */
-/*     {ENCR_DES_IV32,                 0,                                                      0},  */
-       {ENCR_NULL,                     SADB_EALG_NULL,                         0},
-       {ENCR_AES_CBC,                  SADB_X_EALG_AESCBC,                     0},
-/*     {ENCR_AES_CTR,                  0,                                                      0},  */
-/*     {ENCR_AES_CCM_ICV8,             0,                                                      64}, */ /* key_size = ICV size */
-/*     {ENCR_AES_CCM_ICV12,    0,                                                      96}, */ /* key_size = ICV size */
-/*     {ENCR_AES_CCM_ICV16,    0,                                                      128},*/ /* key_size = ICV size */
-/*     {ENCR_AES_GCM_ICV8,             0,                                                      64}, */ /* key_size = ICV size */
-/*     {ENCR_AES_GCM_ICV12,    0,                                                      96}, */ /* key_size = ICV size */
-/*     {ENCR_AES_GCM_ICV16,    0,                                                      128},*/ /* key_size = ICV size */
-       {END_OF_LIST,                   0,                                                      0},
+/*     {ENCR_DES_IV64,                         0                                                       }, */
+       {ENCR_DES,                                      SADB_EALG_DESCBC                        },
+       {ENCR_3DES,                             SADB_EALG_3DESCBC                       },
+/*     {ENCR_RC5,                                      0                                                       }, */
+/*     {ENCR_IDEA,                             0                                                       }, */
+       {ENCR_CAST,                             SADB_X_EALG_CASTCBC                     },
+       {ENCR_BLOWFISH,                         SADB_X_EALG_BLOWFISHCBC         },
+/*     {ENCR_3IDEA,                            0                                                       }, */
+/*     {ENCR_DES_IV32,                         0                                                       }, */
+       {ENCR_NULL,                             SADB_EALG_NULL                          },
+       {ENCR_AES_CBC,                          SADB_X_EALG_AESCBC                      },
+/*     {ENCR_AES_CTR,                          0                                                       }, */
+/*     {ENCR_AES_CCM_ICV8,                     0                                                       }, */
+/*     {ENCR_AES_CCM_ICV12,            0                                                       }, */
+/*     {ENCR_AES_CCM_ICV16,            0                                                       }, */
+/*     {ENCR_AES_GCM_ICV8,                     0                                                       }, */
+/*     {ENCR_AES_GCM_ICV12,            0                                                       }, */
+/*     {ENCR_AES_GCM_ICV16,            0                                                       }, */
+       {END_OF_LIST,                           0                                                       },
 };
 
 /**
  * Algorithms for integrity protection
  */
 static kernel_algorithm_t integrity_algs[] = {
-       {AUTH_HMAC_MD5_96,                      SADB_AALG_MD5HMAC,                      128},
-       {AUTH_HMAC_SHA1_96,                     SADB_AALG_SHA1HMAC,                     160},
-       {AUTH_HMAC_SHA2_256_128,        SADB_X_AALG_SHA2_256HMAC,       256},
-       {AUTH_HMAC_SHA2_384_192,        SADB_X_AALG_SHA2_384HMAC,       384},
-       {AUTH_HMAC_SHA2_512_256,        SADB_X_AALG_SHA2_512HMAC,       512},
-/*     {AUTH_DES_MAC,                          0,                                                      0}, */
-/*     {AUTH_KPDK_MD5,                         0,                                                      0}, */
-       {AUTH_AES_XCBC_96,                      SADB_X_AALG_AES_XCBC_MAC,       128},
-       {END_OF_LIST,                           0,                                                      0},
+       {AUTH_HMAC_MD5_96,                      SADB_AALG_MD5HMAC                       },
+       {AUTH_HMAC_SHA1_96,                     SADB_AALG_SHA1HMAC                      },
+       {AUTH_HMAC_SHA2_256_128,        SADB_X_AALG_SHA2_256HMAC        },
+       {AUTH_HMAC_SHA2_384_192,        SADB_X_AALG_SHA2_384HMAC        },
+       {AUTH_HMAC_SHA2_512_256,        SADB_X_AALG_SHA2_512HMAC        },
+/*     {AUTH_DES_MAC,                          0,                                                      }, */
+/*     {AUTH_KPDK_MD5,                         0,                                                      }, */
+       {AUTH_AES_XCBC_96,                      SADB_X_AALG_AES_XCBC_MAC,       },
+       {END_OF_LIST,                           0,                                                      },
 };
 
 /**
  * Algorithms for IPComp
  */
 static kernel_algorithm_t compression_algs[] = {
-/*     {IPCOMP_OUI,                    0,                                                      0}, */
-       {IPCOMP_DEFLATE,                SADB_X_CALG_DEFLATE,            0},
-       {IPCOMP_LZS,                    SADB_X_CALG_LZS,                        0},
-       {IPCOMP_LZJH,                   SADB_X_CALG_LZJH,                       0},
-       {END_OF_LIST,                   0,                                                      0},
+/*     {IPCOMP_OUI,                            0                                                       }, */
+       {IPCOMP_DEFLATE,                        SADB_X_CALG_DEFLATE                     },
+       {IPCOMP_LZS,                            SADB_X_CALG_LZS                         },
+       {IPCOMP_LZJH,                           SADB_X_CALG_LZJH                        },
+       {END_OF_LIST,                           0                                                       },
 };
 
 /**
  * Look up a kernel algorithm ID and its key size
  */
-static int lookup_algorithm(kernel_algorithm_t *kernel_algo, 
-                                          u_int16_t ikev2_algo, u_int16_t *key_size)
+static int lookup_algorithm(kernel_algorithm_t *list, int ikev2)
 {
-       while (kernel_algo->ikev2_id != END_OF_LIST)
+       while (list->ikev2 != END_OF_LIST)
        {
-               if (ikev2_algo == kernel_algo->ikev2_id)
+               if (ikev2 == list->ikev2)
                {
-                       /* match, evaluate key length */
-                       if (key_size && *key_size == 0)
-                       {       /* update key size if not set */
-                               *key_size = kernel_algo->key_size;
-                       }
-                       return kernel_algo->kernel_id;
+                       return list->kernel;
                }
-               kernel_algo++;
+               list++;
        }
        return 0;
 }
@@ -977,10 +965,9 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
                                           host_t *src, host_t *dst, u_int32_t spi,
                                           protocol_id_t protocol, u_int32_t reqid,
                                           u_int64_t expire_soft, u_int64_t expire_hard,
-                                          u_int16_t enc_alg, u_int16_t enc_size,
-                                          u_int16_t int_alg, u_int16_t int_size,
-                                          prf_plus_t *prf_plus, ipsec_mode_t mode,
-                                          u_int16_t ipcomp, bool encap,
+                                          u_int16_t enc_alg, chunk_t enc_key,
+                                          u_int16_t int_alg, chunk_t int_key,
+                                          ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
                                           bool replace)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
@@ -1007,10 +994,8 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
        sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
        sa->sadb_sa_spi = spi;
        sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32;
-       sa->sadb_sa_auth = lookup_algorithm(integrity_algs, 
-                                                               int_alg, &int_size);
-       sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, 
-                                                               enc_alg, &enc_size);
+       sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg);
+       sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg);
        PFKEY_EXT_ADD(msg, sa);
        
        sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
@@ -1047,17 +1032,17 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
                if (!sa->sadb_sa_encrypt)
                {
                        DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                        encryption_algorithm_names, enc_alg);
+                                encryption_algorithm_names, enc_alg);
                        return FAILED;
                }
                DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                               encryption_algorithm_names, enc_alg, enc_size);
+                        encryption_algorithm_names, enc_alg, enc_key.len * 8);
                
                key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
                key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
-               key->sadb_key_bits = enc_size;
-               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_size / 8);
-               prf_plus->get_bytes(prf_plus, enc_size / 8, (void*)(key + 1));
+               key->sadb_key_bits = enc_key.len * 8;
+               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_key.len);
+               memcpy(key + 1, enc_key.ptr, enc_key.len);
                
                PFKEY_EXT_ADD(msg, key);
        }
@@ -1071,13 +1056,13 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
                        return FAILED;
                }
                DBG2(DBG_KNL, "  using integrity algorithm %N with key size %d",
-                        integrity_algorithm_names, int_alg, int_size);
+                        integrity_algorithm_names, int_alg, int_key.len * 8);
                
                key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
                key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
-               key->sadb_key_bits = int_size;
-               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_size / 8);
-               prf_plus->get_bytes(prf_plus, int_size / 8, (void*)(key + 1));
+               key->sadb_key_bits = int_key.len * 8;
+               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_key.len);
+               memcpy(key + 1, int_key.ptr, int_key.len);
                
                PFKEY_EXT_ADD(msg, key);
        }
@@ -1765,7 +1750,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
+       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
        this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy;
index 2dc2ec5..4b56d55 100644 (file)
@@ -182,6 +182,58 @@ struct private_child_sa_t {
        char *iface;
 };
 
+typedef struct keylen_entry_t keylen_entry_t;
+
+/**
+ * Implicit key length for an algorithm
+ */
+struct keylen_entry_t {
+       /** IKEv2 algorithm identifier */
+       int algo;
+       /** key length in bits */
+       int len;
+};
+
+#define END_OF_LIST -1
+
+/**
+ * Keylen for encryption algos
+ */
+keylen_entry_t keylen_enc[] = {
+       {ENCR_DES,                                       64},
+       {ENCR_3DES,                             192},
+       {END_OF_LIST,                             0}
+};
+
+/**
+ * Keylen for integrity algos
+ */
+keylen_entry_t keylen_int[] = {
+       {AUTH_HMAC_MD5_96,                      128},
+       {AUTH_HMAC_SHA1_96,                     160},
+       {AUTH_HMAC_SHA2_256_128,        256},
+       {AUTH_HMAC_SHA2_384_192,        384},
+       {AUTH_HMAC_SHA2_512_256,        512},
+       {AUTH_AES_XCBC_96,                      128},
+       {END_OF_LIST,                             0}
+};
+
+/**
+ * Lookup key length of an algorithm
+ */
+static int lookup_keylen(keylen_entry_t *list, int algo)
+{
+       while (list->algo != END_OF_LIST)
+       {
+               if (algo == list->algo)
+               {
+                       return list->len;
+               }
+               list++;
+       }
+       return 0;
+}
+
 /**
  * Implementation of child_sa_t.get_name.
  */
@@ -530,10 +582,11 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
 static status_t install(private_child_sa_t *this, proposal_t *proposal,
                                                ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine)
 {
-       u_int32_t spi, soft, hard;
-       host_t *src;
-       host_t *dst;
+       u_int32_t spi, cpi, soft, hard;
+       host_t *src, *dst;
        status_t status;
+       chunk_t enc_key = chunk_empty, int_key = chunk_empty;
+       int add_keymat;
        
        this->protocol = proposal->get_protocol(proposal);
        
@@ -549,8 +602,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                        this->me.spi = this->alloc_esp_spi;
                        if (this->alloc_ah_spi)
                        {
-                               charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, 
-                                               this->alloc_ah_spi, PROTO_AH);
+                               charon->kernel_interface->del_sa(charon->kernel_interface,
+                                                               this->me.addr, this->alloc_ah_spi, PROTO_AH);
                        }
                }
                else
@@ -558,8 +611,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                        this->me.spi = this->alloc_ah_spi;
                        if (this->alloc_esp_spi)
                        {
-                               charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, 
-                                               this->alloc_esp_spi, PROTO_ESP);
+                               charon->kernel_interface->del_sa(charon->kernel_interface,
+                                                               this->me.addr, this->alloc_esp_spi, PROTO_ESP);
                        }
                }
                spi = this->me.spi;
@@ -577,23 +630,55 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
        DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound",
                 protocol_id_names, this->protocol);
        
-       /* select encryption algo */
+       /* select encryption algo, derive key */
        if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
                                                                &this->enc_alg, &this->enc_size))
        {
                DBG2(DBG_CHD, "  using %N for encryption", 
                         encryption_algorithm_names, this->enc_alg);
        }
+       if (!this->enc_size)
+       {
+               this->enc_size = lookup_keylen(keylen_enc, this->enc_alg);
+       }
+       if (this->enc_size && this->enc_alg != ENCR_UNDEFINED)
+       {
+               /* CCM/GCM needs additional keymat */
+               switch (this->enc_alg)
+               {
+                       case ENCR_AES_CCM_ICV8:
+                       case ENCR_AES_CCM_ICV12:
+                       case ENCR_AES_CCM_ICV16:
+                               add_keymat = 3;
+                               break;          
+                       case ENCR_AES_GCM_ICV8:
+                       case ENCR_AES_GCM_ICV12:
+                       case ENCR_AES_GCM_ICV16:
+                               add_keymat = 4;
+                               break;
+                       default:
+                               add_keymat = 0;
+                               break;
+               }
+               prf_plus->allocate_bytes(prf_plus, this->enc_size / 8 + add_keymat,
+                                                                &enc_key);
+       }
        
-       /* select integrity algo */
+       /* select integrity algo, derive key */
        if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
                                                                &this->int_alg, &this->int_size))
        {
                DBG2(DBG_CHD, "  using %N for integrity",
                         integrity_algorithm_names, this->int_alg);
        }
-       soft = this->config->get_lifetime(this->config, TRUE);
-       hard = this->config->get_lifetime(this->config, FALSE);
+       if (!this->int_size)
+       {
+               this->int_size = lookup_keylen(keylen_int, this->int_alg);
+       }
+       if (this->int_size && this->int_alg != AUTH_UNDEFINED)
+       {
+               prf_plus->allocate_bytes(prf_plus, this->int_size / 8, &int_key);
+       }
        
        /* send SA down to the kernel */
        DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
@@ -601,18 +686,22 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
        if (this->ipcomp != IPCOMP_NONE)
        {
                /* we install an additional IPComp SA */
-               u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi));
-               status = charon->kernel_interface->add_sa(charon->kernel_interface,
+               cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi));
+               charon->kernel_interface->add_sa(charon->kernel_interface,
                                src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0,
-                               ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode,
-                               this->ipcomp, FALSE, mine);
+                               ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
+                               mode, this->ipcomp, FALSE, mine);
        }
        
+       soft = this->config->get_lifetime(this->config, TRUE);
+       hard = this->config->get_lifetime(this->config, FALSE);
        status = charon->kernel_interface->add_sa(charon->kernel_interface,
                                src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, 
-                               this->enc_alg, this->enc_size, this->int_alg, this->int_size,
-                               prf_plus, mode, IPCOMP_NONE, this->encap, mine);
-                                       
+                               this->enc_alg, enc_key, this->int_alg, int_key,
+                               mode, IPCOMP_NONE, this->encap, mine);
+       
+       chunk_clear(&enc_key);
+       chunk_clear(&int_key);
        this->install_time = time(NULL);
        this->rekey_time = this->install_time + soft;
        return status;
index 5dd522d..28241cf 100644 (file)
@@ -1658,8 +1658,8 @@ static status_t derive_keys(private_ike_sa_t *this,
                this->prf->allocate_bytes(this->prf, secret, &skeyseed);
                DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
                this->prf->set_key(this->prf, skeyseed);
-               chunk_free(&skeyseed);
-               chunk_free(&secret);
+               chunk_clear(&skeyseed);
+               chunk_clear(&secret);
                prf_plus = prf_plus_create(this->prf, prf_plus_seed);
        }
        else
@@ -1670,13 +1670,13 @@ static status_t derive_keys(private_ike_sa_t *this,
                child_prf->allocate_bytes(child_prf, secret, &skeyseed);
                DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
                old_prf->set_key(old_prf, skeyseed);
-               chunk_free(&skeyseed);
-               chunk_free(&secret);
+               chunk_clear(&skeyseed);
+               chunk_clear(&secret);
                prf_plus = prf_plus_create(old_prf, prf_plus_seed);
        }
        chunk_free(&full_nonce);
        chunk_free(&fixed_nonce);
-       chunk_free(&prf_plus_seed);
+       chunk_clear(&prf_plus_seed);
        
        /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
        
@@ -1687,7 +1687,7 @@ static status_t derive_keys(private_ike_sa_t *this,
        prf_plus->allocate_bytes(prf_plus, key_size, &key);
        DBG4(DBG_IKE, "Sk_d secret %B", &key);
        this->child_prf->set_key(this->child_prf, key);
-       chunk_free(&key);
+       chunk_clear(&key);
        
        /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
        if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
@@ -1711,12 +1711,12 @@ static status_t derive_keys(private_ike_sa_t *this,
        prf_plus->allocate_bytes(prf_plus, key_size, &key);
        DBG4(DBG_IKE, "Sk_ai secret %B", &key);
        signer_i->set_key(signer_i, key);
-       chunk_free(&key);
+       chunk_clear(&key);
        
        prf_plus->allocate_bytes(prf_plus, key_size, &key);
        DBG4(DBG_IKE, "Sk_ar secret %B", &key);
        signer_r->set_key(signer_r, key);
-       chunk_free(&key);
+       chunk_clear(&key);
        
        if (initiator)
        {
@@ -1752,12 +1752,12 @@ static status_t derive_keys(private_ike_sa_t *this,
        prf_plus->allocate_bytes(prf_plus, key_size, &key);
        DBG4(DBG_IKE, "Sk_ei secret %B", &key);
        crypter_i->set_key(crypter_i, key);
-       chunk_free(&key);
+       chunk_clear(&key);
        
        prf_plus->allocate_bytes(prf_plus, key_size, &key);
        DBG4(DBG_IKE, "Sk_er secret %B", &key);
        crypter_r->set_key(crypter_r, key);
-       chunk_free(&key);
+       chunk_clear(&key);
        
        if (initiator)
        {