/* validation for registering (auth) module */ static int check_auth(struct ipsec_alg_auth *ixt) { int ret=-EINVAL; if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX) barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX); if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2) barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize); if (ixt->ixt_blocksize>AH_BLKLEN_MAX) barf_out(KERN_ERR "sorry blocksize=%d > %d. " "Please increase AH_BLKLEN_MAX and recompile\n", ixt->ixt_blocksize, AH_BLKLEN_MAX); if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0) goto zero_key_ok; if (ixt->ixt_keyminbits==0) barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits); if (ixt->ixt_keymaxbits==0) barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits); if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits) barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n"); if (ixt->ixt_a_keylen==0) barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen); zero_key_ok: if (ixt->ixt_a_ctx_size==0) barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size); if (ixt->ixt_a_hmac_set_key==NULL) barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n"); if (ixt->ixt_a_hmac_hash==NULL) barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n"); ret=0; out: return ret; }
/* * Generic (enc, auth) registration entry point */ int register_ipsec_alg(struct ipsec_alg *ixt) { int ret=-EINVAL; /* Validation */ if (ixt==NULL) barf_out("NULL ipsec_alg object passed\n"); if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00)) barf_out("incorrect version: %d.%d.%d-%d, " "must be %d.%d.%d[-%d]\n", IPSEC_ALG_VERSION_QUAD(ixt->ixt_version), IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION)); switch(ixt->ixt_alg_type) { case IPSEC_ALG_TYPE_AUTH: if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0)) goto out; break; case IPSEC_ALG_TYPE_ENCRYPT: if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0)) goto out; /* * Adapted two lines below: * ivlen == 0 is possible (NULL enc has blocksize==1) * * fixed NULL support by David De Reu <*****@*****.**> */ if (ixt->ixt_support.ias_ivlen == 0 && ixt->ixt_blocksize > 1) { ixt->ixt_support.ias_ivlen = ixt->ixt_blocksize*8; } break; default: barf_out("alg_type=%d not supported\n", ixt->ixt_alg_type); } INIT_LIST_HEAD(&ixt->ixt_list); ret = ipsec_alg_insert(ixt); if (ret<0) barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed." "Not loaded (ret=%d).\n", ixt->ixt_support.ias_id, ret); ret = pfkey_list_insert_supported((struct ipsec_alg_supported *)&ixt->ixt_support , &(pfkey_supported_list[K_SADB_SATYPE_ESP])); if (ret==0) { ixt->ixt_state |= IPSEC_ALG_ST_SUPP; /* send register event to userspace */ pfkey_register_reply(K_SADB_SATYPE_ESP, NULL); } else printk(KERN_ERR "pfkey_list_insert_supported returned %d. " "Loading anyway.\n", ret); ret=0; out: return ret; }
/* * unregister ipsec_alg object from own tables, if * success => calls pfkey_list_remove_supported() */ int unregister_ipsec_alg(struct ipsec_alg *ixt) { int ret= -EINVAL; switch(ixt->ixt_alg_type) { case IPSEC_ALG_TYPE_AUTH: case IPSEC_ALG_TYPE_ENCRYPT: break; default: /* this is not a typo :) */ barf_out("frog found in list (\"%s\"): ixt_p=NULL\n", ixt->ixt_name); } ret=ipsec_alg_delete(ixt); if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) { ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP; pfkey_list_remove_supported((struct ipsec_alg_supported *)&ixt->ixt_support , &(pfkey_supported_list[K_SADB_SATYPE_ESP])); /* send register event to userspace */ pfkey_register_reply(K_SADB_SATYPE_ESP, NULL); } out: return ret; }
/* * inserts (in front) a new entry in hash table, * called from ipsec_alg_register() when new algorithm is registered. */ static int ipsec_alg_insert(struct ipsec_alg *ixt) { int ret=-EINVAL; unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id); struct list_head *head= ipsec_alg_hash_table + hashval; struct ipsec_alg *ixt_cur; /* new element must be virgin ... */ if (ixt->ixt_list.next != &ixt->ixt_list || ixt->ixt_list.prev != &ixt->ixt_list) { printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" " "list head not initialized\n", ixt->ixt_name); return ret; } write_lock_bh(&ipsec_alg_lock); ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head); /* if previous (current) ipsec_alg found check excl flag of _anyone_ */ if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL)) { barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. " "Not loaded (ret=%d).\n", ixt->ixt_alg_type, ixt->ixt_alg_id, ret=-EEXIST); } list_add(&ixt->ixt_list, head); ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED; ret=0; out: write_unlock_bh(&ipsec_alg_lock); return ret; }
/* validation for registering (enc) module */ static int check_enc(struct ipsec_alg_enc *ixt) { int ret=-EINVAL; if (ixt->ixt_common.ixt_blocksize==0) /* || ixt->ixt_common.ixt_blocksize%2) need for ESP_NULL */ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_common.ixt_blocksize); if (ixt->ixt_common.ixt_support.ias_keyminbits==0 && ixt->ixt_common.ixt_support.ias_keymaxbits==0 && ixt->ixt_e_keylen==0) goto zero_key_ok; if (ixt->ixt_common.ixt_support.ias_keyminbits==0) barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_common.ixt_support.ias_keyminbits); if (ixt->ixt_common.ixt_support.ias_keymaxbits==0) barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_common.ixt_support.ias_keymaxbits); if (ixt->ixt_e_keylen==0) barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen); zero_key_ok: if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL) barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size); if (ixt->ixt_e_cbc_encrypt==NULL) barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n"); ret=0; out: return ret; }
/* * inserts (in front) a new entry in hash table, * called from ipsec_alg_register() when new algorithm is registered. */ static int ipsec_alg_insert(struct ipsec_alg *ixt) { int ret=-EINVAL; unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id); struct list_head *head= ipsec_alg_hash_table + hashval; /* new element must be virgin ... */ if (ixt->ixt_list.next != &ixt->ixt_list || ixt->ixt_list.prev != &ixt->ixt_list) { printk(KERN_ERR "%s: ixt object \"%s\" " "list head not initialized\n", __FUNCTION__, ixt->ixt_name); return ret; } write_lock_bh(&ipsec_alg_lock); if (__ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head)) barf_out(KERN_WARNING "ipsec_alg for alg_type=%d, alg_id=%d already exist." "Not loaded (ret=%d).\n", ixt->ixt_alg_type, ixt->ixt_alg_id, ret=-EEXIST); list_add(&ixt->ixt_list, head); ret=0; out: write_unlock_bh(&ipsec_alg_lock); return ret; }
/* validation for registering (enc) module */ static int check_enc(struct ipsec_alg_enc *ixt) { int ret=-EINVAL; if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_EALG_MAX) barf_out("invalid alg_id=%d >= %d\n", ixt->ixt_alg_id, SADB_EALG_MAX); if (ixt->ixt_blocksize==0) /* || ixt->ixt_blocksize%2) need for ESP_NULL */ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize); if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0) goto zero_key_ok; if (ixt->ixt_keyminbits==0) barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits); if (ixt->ixt_keymaxbits==0) barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits); if (ixt->ixt_e_keylen==0) barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen); zero_key_ok: if (ixt->ixt_e_ctx_size==0) barf_out(KERN_ERR "invalid key_e_size=%d\n", ixt->ixt_e_ctx_size); if (ixt->ixt_e_cbc_encrypt==NULL) barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n"); ret=0; out: return ret; }