int sadb_msg_send_acquire(struct ipsec_sa *sa) { int i=0, error = 0; uint comb_num = 0; struct sadb_comb combs[4]; struct digest_implementation *di = NULL; struct cipher_implementation *ci = NULL; struct sadb_msg *msg = NULL; struct sadb_ext *ext_msgs[SADB_EXT_MAX+1]; struct socket_list *pfkey_socketsp = NULL; memset(ext_msgs, 0, sizeof(ext_msgs)); memset(combs, 0, sizeof(combs)); if (sa->ipsec_proto == SADB_SATYPE_AH || sa->ipsec_proto == SADB_SATYPE_ESP) { di = find_digest_by_name("md5", 0 /* atomic */); if (di) { combs[comb_num].sadb_comb_auth = SADB_AALG_MD5HMAC; combs[comb_num].sadb_comb_auth_minbits = AUTH_MD5HMAC_KEY_BITS; combs[comb_num].sadb_comb_auth_maxbits = AUTH_MD5HMAC_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; di = NULL; } di = find_digest_by_name("sha1", 0 /* atomic */); if (di) { combs[comb_num].sadb_comb_auth = SADB_AALG_SHA1HMAC; combs[comb_num].sadb_comb_auth_minbits = AUTH_SHA1HMAC_KEY_BITS; combs[comb_num].sadb_comb_auth_maxbits = AUTH_SHA1HMAC_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; di = NULL; } } if (sa->ipsec_proto == SADB_SATYPE_ESP) { ci = find_cipher_by_name("des-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_DESCBC; combs[comb_num].sadb_comb_encrypt_minbits = ESP_DES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_DES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_3DESCBC; combs[comb_num].sadb_comb_encrypt_minbits = ESP_3DES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_3DES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } ci = find_cipher_by_name("aes-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_AES; combs[comb_num].sadb_comb_encrypt_minbits = ESP_AES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_AES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } } error = pfkey_msg_hdr_build(&ext_msgs[0], SADB_ACQUIRE, sa->ipsec_proto, 0, 0, 0); if (error) { PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n"); goto free_ext_finish; } error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC], SADB_EXT_ADDRESS_SRC, sa->proto, sa->prefixlen_s, (struct sockaddr*)&sa->src); if (error) goto free_ext_finish; error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST], SADB_EXT_ADDRESS_DST, sa->proto, sa->prefixlen_d, (struct sockaddr*)&sa->dst); if (error) goto free_ext_finish; error = pfkey_prop_build(&ext_msgs[SADB_EXT_PROPOSAL], 64, comb_num, combs); if (error) goto free_ext_finish; error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT); write_lock(&pfkey_sk_lock); for (pfkey_socketsp = pfkey_registered_sockets[sa->ipsec_proto]; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, msg); } write_unlock(&pfkey_sk_lock); kfree(msg); free_ext_finish: for(i=0; i<SADB_MAX+1; i++) { if (ext_msgs[i]) { kfree(ext_msgs[i]); } } return 0; }
int sadb_key_to_esp(const __u8 esp_algo, const struct sadb_key* ext_msg, struct ipsec_sa* sa_entry) { int error = 0; char *algoname = NULL; struct cipher_implementation *ci=NULL; if (!sa_entry) { PFKEY_DEBUG("sa_entry is null\n"); error = -EINVAL; goto err; } if (esp_algo != SADB_EALG_NULL && !ext_msg) { PFKEY_DEBUG("ext_msg is null\n"); error = -EINVAL; goto err; } switch (esp_algo) { case SADB_EALG_DESCBC: algoname = "des-cbc"; PFKEY_DEBUG("esp algorithm is DES-CBC\n"); if(ext_msg->sadb_key_bits != ESP_DES_KEY_BITS){ PFKEY_DEBUG("the key length is not match\n"); error = -EINVAL; goto err; } break; case SADB_EALG_3DESCBC: algoname = "des_ede3-cbc"; PFKEY_DEBUG("esp algorithm is 3DES-CBC\n"); if(ext_msg->sadb_key_bits != ESP_3DES_KEY_BITS){ PFKEY_DEBUG("the key length is not match\n"); error = -EINVAL; goto err; } break; case SADB_EALG_NULL: algoname = "null-algo"; PFKEY_DEBUG("esp algorithm is NULL\n"); break; case SADB_EALG_AES: algoname = "aes-cbc"; PFKEY_DEBUG("esp algorithm is AES(128-bit)\n"); if (ext_msg->sadb_key_bits != ESP_AES_KEY_BITS) { PFKEY_DEBUG("the key length is no match\n"); error = -EINVAL; goto err; } break; case SADB_EALG_NONE: /* currently not enter */ default: PFKEY_DEBUG("esp_algo is NONE or not supported one\n"); error = -EINVAL; goto err; } ci = find_cipher_by_name(algoname, 1); if(!ci){ PFKEY_DEBUG("algorithm %u:%s is not supported\n", esp_algo, algoname); error = -EINVAL; goto err; } ci->lock(); sa_entry->esp_algo.algo = esp_algo; if (esp_algo != SADB_EALG_NULL) { sa_entry->esp_algo.key_len = (ext_msg->sadb_key_bits)/OCTETBITS; } else { sa_entry->esp_algo.key_len = 0; } sa_entry->esp_algo.cx = ci->realloc_context (NULL, ci, sa_entry->esp_algo.key_len); if (!sa_entry->esp_algo.cx) { ci->unlock(); error = -EINVAL; goto err; } sa_entry->esp_algo.cx->ci = ci; if (esp_algo != SADB_EALG_NULL) { sa_entry->esp_algo.key = kmalloc(sa_entry->esp_algo.key_len, GFP_KERNEL); if (!sa_entry->esp_algo.key) { PFKEY_DEBUG("could not allocate memory for key\n"); ci->wipe_context(sa_entry->esp_algo.cx); ci->free_context(sa_entry->esp_algo.cx); ci->unlock(); error = -ENOMEM; goto err; } memset(sa_entry->esp_algo.key, 0, sa_entry->esp_algo.key_len); memcpy(sa_entry->esp_algo.key, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len); sa_entry->esp_algo.cx->keyinfo = (u32*)kmalloc(ci->key_schedule_size, GFP_KERNEL); if (!sa_entry->esp_algo.cx->keyinfo) { PFKEY_DEBUG("could not allocate memory for keyinfo\n"); ci->unlock(); error = -ENOMEM; goto err; } memset(sa_entry->esp_algo.cx->keyinfo, 0, ci->key_schedule_size); error = ci->set_key(sa_entry->esp_algo.cx, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len); if (error < 0) { PFKEY_DEBUG("set_key failed, key is wondered weak \n"); ci->wipe_context(sa_entry->esp_algo.cx); ci->free_context(sa_entry->esp_algo.cx); ci->unlock(); goto err; } } err: return error; }
int sadb_msg_register_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply) { int error = 0; uint alg_num = 0; struct sadb_alg algs[5]; struct digest_implementation *di = NULL; struct cipher_implementation *ci = NULL; struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1]; if (!(sk&&msg)) { PFKEY_DEBUG("msg or sk is null\n"); error = -EINVAL; PFKEY_DEBUG("msg or *reply is null\n"); goto err; } error = sadb_msg_sanity_check(msg); if (error) { goto err; } memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs)); memset(algs, 0, sizeof(algs)); switch (msg->sadb_msg_satype) { case SADB_SATYPE_AH: case SADB_SATYPE_ESP: break; case SADB_SATYPE_RSVP: case SADB_SATYPE_OSPFV2: case SADB_SATYPE_RIPV2: case SADB_SATYPE_MIP: case SADB_X_SATYPE_IPIP: case SADB_X_SATYPE_COMP: case SADB_X_SATYPE_INT: default: error = -EINVAL; goto err; } write_lock(&pfkey_sk_lock); /* register a socket with the proper SA type's socket list it will be release in pfkey_release process (file:pfkey_v2.c). */ error = pfkey_list_insert_socket(sk->socket, &pfkey_registered_sockets[msg->sadb_msg_satype]); if (error) { goto err; } write_unlock(&pfkey_sk_lock); PFKEY_DEBUG("socket=%p registered, SA type is %d\n", sk->socket, msg->sadb_msg_satype); reply_ext_msgs[0] = (struct sadb_ext*)msg; if (msg->sadb_msg_satype == SADB_SATYPE_AH || msg->sadb_msg_satype == SADB_SATYPE_ESP) { di = find_digest_by_name("md5", 0 /* atomic */); if (di) { algs[alg_num].sadb_alg_id = SADB_AALG_MD5HMAC; algs[alg_num].sadb_alg_ivlen = 0; algs[alg_num].sadb_alg_minbits = AUTH_MD5HMAC_KEY_BITS; algs[alg_num].sadb_alg_maxbits = AUTH_MD5HMAC_KEY_BITS; algs[alg_num].sadb_alg_reserved = 0; alg_num++; di = NULL; } di = find_digest_by_name("sha1", 0 /* atomic */); if (di) { algs[alg_num].sadb_alg_id = SADB_AALG_SHA1HMAC; algs[alg_num].sadb_alg_ivlen = 0; algs[alg_num].sadb_alg_minbits = AUTH_SHA1HMAC_KEY_BITS; algs[alg_num].sadb_alg_maxbits = AUTH_SHA1HMAC_KEY_BITS; algs[alg_num].sadb_alg_reserved = 0; alg_num++; di = NULL; } if (msg->sadb_msg_satype == SADB_SATYPE_AH) { error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH], SADB_EXT_SUPPORTED_AUTH, alg_num, algs); if (error) goto free_ext_finish; } } if (msg->sadb_msg_satype == SADB_SATYPE_ESP) { ci = find_cipher_by_name("des-cbc", 1 /* atomic */); if (ci) { ci->lock(); algs[alg_num].sadb_alg_id = SADB_EALG_DESCBC; algs[alg_num].sadb_alg_ivlen = ci->ivsize; algs[alg_num].sadb_alg_minbits = ESP_DES_KEY_BITS; algs[alg_num].sadb_alg_maxbits = ESP_DES_KEY_BITS; algs[alg_num].sadb_alg_reserved = 0; alg_num++; ci->unlock(); ci = NULL; } ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */); if (ci) { ci->lock(); algs[alg_num].sadb_alg_id = SADB_EALG_3DESCBC; algs[alg_num].sadb_alg_ivlen = ci->ivsize; algs[alg_num].sadb_alg_minbits = ESP_3DES_KEY_BITS; algs[alg_num].sadb_alg_maxbits = ESP_3DES_KEY_BITS; algs[alg_num].sadb_alg_reserved = 0; alg_num++; ci->unlock(); ci = NULL; } ci = find_cipher_by_name("aes-cbc", 1 /* atomic */); if (ci) { ci->lock(); algs[alg_num].sadb_alg_id = SADB_EALG_AES; algs[alg_num].sadb_alg_ivlen = ci->ivsize; algs[alg_num].sadb_alg_minbits = ESP_AES_KEY_BITS; algs[alg_num].sadb_alg_maxbits = ESP_AES_KEY_BITS; algs[alg_num].sadb_alg_reserved = 0; alg_num++; ci->unlock(); ci = NULL; } error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT], SADB_EXT_SUPPORTED_ENCRYPT, alg_num, algs); if (error) goto free_ext_finish; } pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT); free_ext_finish: if (reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH]) kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH]); if (reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT]) kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT]); err: return error; }
static int cryptoloop_init (struct loop_device *lo, struct loop_info *info) { struct cryptoloop_context *lx = (struct cryptoloop_context *) lo->key_reserved; int err = -EINVAL; char cipher[LO_NAME_SIZE]; struct cipher_implementation *ci; struct cipher_context *cx; /* encryption breaks for non sector aligned offsets */ if (info->lo_offset % LOOP_IV_SECTOR_SIZE) goto out; lx->blocksize = LOOP_IV_SECTOR_SIZE; lx->debug = 0; strncpy (cipher, info->lo_name, LO_NAME_SIZE); cipher[LO_NAME_SIZE - 1] = 0; ci = find_cipher_by_name (cipher, 1); if (!ci) goto out; ci->lock (); err = -ENOMEM; cx = ci->realloc_context (NULL, ci, info->lo_encrypt_key_size); if (!cx) goto out_ci; cx->ci = ci; ci->wipe_context (cx); #if defined(CONFIG_CRYPTOLOOP_ATOMIC) if (ci->set_key_atomic (cx, info->lo_encrypt_key, info->lo_encrypt_key_size)) { #else if (ci->set_key (cx, info->lo_encrypt_key, info->lo_encrypt_key_size)) { #endif err = -EINVAL; goto out_key; } lo->key_data = cx; err = 0; goto out; out_key: ci->wipe_context (cx); ci->free_context (cx); out_ci: ci->unlock (); out: if (!err) { MOD_INC_USE_COUNT; } return err; } static int cryptoloop_transfer (struct loop_device *lo, int cmd, char *raw_buf, char *loop_buf, int size, loop_iv_t IV) { const struct cryptoloop_context *lx = (struct cryptoloop_context *) lo->key_reserved; struct cipher_context *cx = (struct cipher_context *) lo->key_data; struct cipher_implementation *ci = cx->ci; cipher_trans_proc_iv encdecfunc; const int blocksize = lx->blocksize ? lx->blocksize : size; char const *in; char *out; if (cmd == READ) { #if defined(CONFIG_CRYPTOLOOP_ATOMIC) encdecfunc = ci->decrypt_atomic_iv; #else encdecfunc = ci->decrypt_iv; #endif in = raw_buf; out = loop_buf; } else { #if defined(CONFIG_CRYPTOLOOP_ATOMIC) encdecfunc = ci->encrypt_atomic_iv; #else encdecfunc = ci->encrypt_iv; #endif in = loop_buf; out = raw_buf; } #if defined(CONFIG_CRYPTOLOOP_IV_HACK) /* contributed by Clemens Fruhwirth * * Expand IV to 512 byte metric */ IV *= loop_get_bs(lo) >> LOOP_IV_SECTOR_BITS; /* * Too bad offset information is lost, but we use a dirty * trick to recover it from the raw_buf address (ab)using the * page alignments and the blocksize alignments */ IV += ((unsigned long) raw_buf & (loop_get_bs (lo)-1)) >> LOOP_IV_SECTOR_BITS; #endif /* CONFIG_CRYPTOLOOP_IV_HACK */ /* * scale IV back to custom (iv_)blocksize units */ IV /= blocksize / LOOP_IV_SECTOR_SIZE; #if defined(CONFIG_CRYPTOLOOP_DEBUG) if (lx->debug) printk (KERN_DEBUG "cryptoloop_transfer: cmd=%d size=%d iv=%ld blksize=%d iv_blksize=%d\n", cmd, size, (unsigned long) IV, loop_get_bs (lo), blocksize); #endif /* CONFIG_CRYPTOLOOP_DEBUG */ /* split up transfer request into blocksize (default = 512) byte data blocks */ while (size > 0) { const int _size = (size > blocksize) ? blocksize : size; u32 iv[4] = { 0, }; if (size < blocksize) printk (KERN_WARNING "cryptoloop_transfer: block (IV = %ld) smaller than blocksize! (%d < %d)\n", (unsigned long) IV, size, blocksize); iv[0] = cpu_to_le32 (IV & 0xffffffff); encdecfunc (cx, in, out, _size, (u8 *) iv); IV++; size -= _size; in += _size; out += _size; } return 0; } static int cryptoloop_ioctl (struct loop_device *lo, int cmd, unsigned long arg) { struct cryptoloop_context *lx = (struct cryptoloop_context *) lo->key_reserved; int err = -EINVAL; int arg_int = 0; if (get_user (arg_int, (int *) arg)) return -EFAULT; switch (cmd) { case CRYPTOLOOP_SET_BLKSIZE: printk (KERN_DEBUG "cryptoloop: switch to blocksize %d requested\n", arg_int); if (arg_int >= 0 && (arg_int % LOOP_IV_SECTOR_SIZE == 0)) { lx->blocksize = arg_int; err = 0; } break; case CRYPTOLOOP_SET_DEBUG: printk (KERN_DEBUG "cryptoloop: set debug = %d requested\n", arg_int); lx->debug = arg_int; err = 0; break; default: err = -EINVAL; break; } return err; } static int cryptoloop_release (struct loop_device *lo) { struct cipher_context *cx = (struct cipher_context *) lo->key_data; if (cx != NULL) { cx->ci->wipe_context (cx); cx->ci->unlock (); cx->ci->free_context (cx); lo->key_data = NULL; MOD_DEC_USE_COUNT; return 0; } printk (KERN_ERR "cryptoloop_release(): cx == NULL ????\n"); return -EINVAL; } struct loop_func_table cryptoloop_funcs = { number:LO_CRYPT_CRYPTOAPI, init:cryptoloop_init, ioctl:cryptoloop_ioctl, transfer:cryptoloop_transfer, release:cryptoloop_release };