From: Tadeusz Struk <hidden> Date: 2016-06-23 22:55:29
First four patches are a resend algif_akcipher from
Stephan Mueller, with minor changes after rebase on top of 4.7-rc1.
The next three patches add support for keys stored in system
keyring subsystem.
First patch adds algif_akcipher nokey hadlers.
Second patch adds generic sign, verify, encrypt, decrypt accessors
functions to the asymmetric key type. These will be defined by
asymmetric subtypes, similarly to how public_key currently defines
the verify_signature function.
Third patch adds support for ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID
commands to AF_ALG and setkeyid operation to the af_alg_type struct.
If the keyid is used then the afalg layer acquires the key for the
keyring subsystem and uses the new asymmetric accessor functions
instead of akcipher api. The asymmetric subtypes can use akcipher
api internally.
Patches are generate against:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-next
v8 hanges:
- copy the result to user for verify after the signature_verify
operation. Before only the return code was checked, but not the
actual data. Reported by Mat Martineau
- remove the constrain on the output buffer size as requested by
Mat Martineau
- ifx uninitialize variable issue, reported by Mat Martineau
v7 changes:
- update to reflect changes in kernel_pkey_params struct
v6 changes:
- rabased on top of
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-asym-keyctl
v5 changes:
- drop public key changes and use new version provided by David
v4 changes:
- don't use internal public_key struct in af_alg.
- add generic accessor functions to asymmetric key type, which take
the generic struct key type and resolve the specific subtype internally
v3 changes:
- include Stephan's patches (rebased on 4.6-rc1)
- add algif_akcipher nokey hadlers
- add public_key info struct to public_key and helper query functions
- add a check if a key is a software accessible key on af_alg, and
return -ENOKEY if it isn't
v2 changes:
- pass the original skcipher request in ablkcipher.base.data instead of
casting it back from the ablkcipher request.
- rename _req to base_req
- dropped 3/3
---
Stephan Mueller (4):
crypto: AF_ALG -- add sign/verify API
crypto: AF_ALG -- add setpubkey setsockopt call
crypto: AF_ALG -- add asymmetric cipher interface
crypto: algif_akcipher - enable compilation
Tadeusz Struk (2):
crypto: algif_akcipher - add ops_nokey
crypto: AF_ALG - add support for key_id
crypto/Kconfig | 9
crypto/Makefile | 1
crypto/af_alg.c | 28 +
crypto/algif_akcipher.c | 878 +++++++++++++++++++++++++++++++++++++++++++
include/crypto/if_alg.h | 2
include/uapi/linux/if_alg.h | 5
6 files changed, 918 insertions(+), 5 deletions(-)
create mode 100644 crypto/algif_akcipher.c
--
TS
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:55:34
From: Stephan Mueller <redacted>
Add the flags for handling signature generation and signature
verification.
Also, the patch adds the interface for setting a public key.
Signed-off-by: Stephan Mueller <redacted>
Signed-off-by: Tadeusz Struk <redacted>
---
include/uapi/linux/if_alg.h | 3 +++
1 file changed, 3 insertions(+)
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:55:56
Similar to algif_skcipher and algif_hash, algif_akcipher needs
to prevent user space from using the interface in an improper way.
This patch adds nokey ops handlers, which do just that.
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/algif_akcipher.c | 159 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 152 insertions(+), 7 deletions(-)
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:56:03
This patch adds support for asymmetric key type to AF_ALG.
It will work as follows: A new PF_ALG socket options are
added on top of existing ALG_SET_KEY and ALG_SET_PUBKEY, namely
ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID for setting public and
private keys respectively. When these new options will be used
the user, instead of providing the key material, will provide a
key id and the key itself will be obtained from kernel keyring
subsystem. The user will use the standard tools (keyctl tool
or the keyctl syscall) for key instantiation and to obtain the
key id. The key id can also be obtained by reading the
/proc/keys file.
When a key corresponding to the given keyid is found, it is stored
in the socket context and subsequent crypto operation invoked by the
user will use the new asymmetric accessor functions instead of akcipher
api. The asymmetric subtype can internally use akcipher api or
invoke operations defined by a given subtype, depending on the
key type.
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/af_alg.c | 10 ++
crypto/algif_akcipher.c | 212 ++++++++++++++++++++++++++++++++++++++++++-
include/crypto/if_alg.h | 1
include/uapi/linux/if_alg.h | 2
4 files changed, 220 insertions(+), 5 deletions(-)
@@ -260,6 +260,16 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,err=alg_setkey(sk,optval,optlen,type->setpubkey);break;++caseALG_SET_KEY_ID:+caseALG_SET_PUBKEY_ID:+/* ALG_SET_KEY_ID is only for akcipher */+if(!strcmp(type->name,"akcipher")||+sock->state==SS_CONNECTED)+gotounlock;++err=alg_setkey(sk,optval,optlen,type->setkeyid);+break;caseALG_SET_AEAD_AUTHSIZE:if(sock->state==SS_CONNECTED)gotounlock;
@@ -317,6 +321,158 @@ unlock:returnerr?err:size;}+staticintasym_key_encrypt(conststructkey*key,structakcipher_request*req)+{+structkernel_pkey_paramsparams={0};+char*src=NULL,*dst=NULL,*in,*out;+intret;++if(!sg_is_last(req->src)){+src=kmalloc(req->src_len,GFP_KERNEL);+if(!src)+return-ENOMEM;+scatterwalk_map_and_copy(src,req->src,0,req->src_len,0);+in=src;+}else{+in=sg_virt(req->src);+}+if(!sg_is_last(req->dst)){+dst=kmalloc(req->dst_len,GFP_KERNEL);+if(!dst){+kfree(src);+return-ENOMEM;+}+out=dst;+}else{+out=sg_virt(req->dst);+}+params.key=(structkey*)key;+params.in_len=req->src_len;+params.out_len=req->dst_len;+ret=encrypt_blob(¶ms,in,out);+if(ret)+gotofree;++if(dst)+scatterwalk_map_and_copy(dst,req->dst,0,req->dst_len,1);+free:+kfree(src);+kfree(dst);+returnret;+}++staticintasym_key_decrypt(conststructkey*key,structakcipher_request*req)+{+structkernel_pkey_paramsparams={0};+char*src=NULL,*dst=NULL,*in,*out;+intret;++if(!sg_is_last(req->src)){+src=kmalloc(req->src_len,GFP_KERNEL);+if(!src)+return-ENOMEM;+scatterwalk_map_and_copy(src,req->src,0,req->src_len,0);+in=src;+}else{+in=sg_virt(req->src);+}+if(!sg_is_last(req->dst)){+dst=kmalloc(req->dst_len,GFP_KERNEL);+if(!dst){+kfree(src);+return-ENOMEM;+}+out=dst;+}else{+out=sg_virt(req->dst);+}+params.key=(structkey*)key;+params.in_len=req->src_len;+params.out_len=req->dst_len;+ret=decrypt_blob(¶ms,in,out);+if(ret)+gotofree;++if(dst)+scatterwalk_map_and_copy(dst,req->dst,0,req->dst_len,1);+free:+kfree(src);+kfree(dst);+returnret;+}++staticintasym_key_sign(conststructkey*key,structakcipher_request*req)+{+structkernel_pkey_paramsparams={0};+char*src=NULL,*dst=NULL,*in,*out;+intret;++if(!sg_is_last(req->src)){+src=kmalloc(req->src_len,GFP_KERNEL);+if(!src)+return-ENOMEM;+scatterwalk_map_and_copy(src,req->src,0,req->src_len,0);+in=src;+}else{+in=sg_virt(req->src);+}+if(!sg_is_last(req->dst)){+dst=kmalloc(req->dst_len,GFP_KERNEL);+if(!dst){+kfree(src);+return-ENOMEM;+}+out=dst;+}else{+out=sg_virt(req->dst);+}+params.key=(structkey*)key;+params.in_len=req->src_len;+params.out_len=req->dst_len;+ret=create_signature(¶ms,in,out);+if(ret)+gotofree;++if(dst)+scatterwalk_map_and_copy(dst,req->dst,0,req->dst_len,1);+free:+kfree(src);+kfree(dst);+returnret;+}++staticintasym_key_verify(conststructkey*key,structakcipher_request*req)+{+structpublic_key_signaturesig;+char*src=NULL,*in,digest[20];+intret;++if(!sg_is_last(req->src)){+src=kmalloc(req->src_len,GFP_KERNEL);+if(!src)+return-ENOMEM;+scatterwalk_map_and_copy(src,req->src,0,req->src_len,0);+in=src;+}else{+in=sg_virt(req->src);+}+sig.pkey_algo="rsa";+sig.encoding="pkcs1";+/* Need to find a way to pass the hash param */+sig.hash_algo="sha1";+sig.digest_size=sizeof(digest);+sig.digest=digest;+sig.s_size=req->src_len;+sig.s=src;+ret=verify_signature(key,&sig);+if(!ret){+req->dst_len=sizeof(digest);+scatterwalk_map_and_copy(digest,req->dst,0,req->dst_len,1);+}+kfree(src);+returnret;+}+staticintakcipher_recvmsg(structsocket*sock,structmsghdr*msg,size_tignored,intflags){
@@ -568,6 +736,27 @@ static void akcipher_release(void *private)kfree(tfm);}+staticintakcipher_setkeyid(void*private,constu8*key,unsignedintkeylen)+{+structakcipher_tfm*tfm=private;+structkey*akey;+u32keyid=*((u32*)key);+interr=-ENOKEY;++/* Store the key id and verify that a key with the given id is present.+*Theactualkeywillbeacquiredintheaccept_parentfunction+*/+sprintf(tfm->keyid,"id:%08x",keyid);+akey=request_key(&key_type_asymmetric,tfm->keyid,NULL);+if(IS_ERR(key))+gotoout;++tfm->has_key=true;+key_put(akey);+out:+returnerr;+}+staticintakcipher_setprivkey(void*private,constu8*key,unsignedintkeylen){
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:56:07
From: Stephan Mueller <redacted>
Add the Makefile and Kconfig updates to allow algif_akcipher to be
compiled.
Signed-off-by: Stephan Mueller <redacted>
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/Kconfig | 9 +++++++++
crypto/Makefile | 1 +
2 files changed, 10 insertions(+)
@@ -121,6 +121,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.oobj-$(CONFIG_CRYPTO_USER_API_SKCIPHER)+=algif_skcipher.oobj-$(CONFIG_CRYPTO_USER_API_RNG)+=algif_rng.oobj-$(CONFIG_CRYPTO_USER_API_AEAD)+=algif_aead.o+obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER)+=algif_akcipher.o## generic algorithms and the async_tx api
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:56:36
From: Stephan Mueller <redacted>
This patch adds the user space interface for asymmetric ciphers. The
interface allows the use of sendmsg as well as vmsplice to provide data.
This version has been rebased on top of 4.7 and a few chackpatch issues
have been fixed. This version also removes the constrain on the output
buffer size.
Signed-off-by: Stephan Mueller <redacted>
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/algif_akcipher.c | 531 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 531 insertions(+)
create mode 100644 crypto/algif_akcipher.c
@@ -0,0 +1,531 @@+/*+*algif_akcipher:User-spaceinterfaceforasymmetriccipheralgorithms+*+*Copyright(C)2015,StephanMueller<smueller@chronox.de>+*+*Thisfileprovidestheuser-spaceAPIforasymmetricciphers.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseaspublishedbytheFree+*SoftwareFoundation;eitherversion2oftheLicense,or(atyouroption)+*anylaterversion.+*/++#include<crypto/akcipher.h>+#include<crypto/scatterwalk.h>+#include<crypto/if_alg.h>+#include<linux/init.h>+#include<linux/list.h>+#include<linux/kernel.h>+#include<linux/mm.h>+#include<linux/module.h>+#include<linux/net.h>+#include<net/sock.h>++structakcipher_sg_list{+unsignedintcur;+structscatterlistsg[ALG_MAX_PAGES];+};++structakcipher_ctx{+structakcipher_sg_listtsgl;+structaf_alg_sglrsgl[ALG_MAX_PAGES];++structaf_alg_completioncompletion;++unsignedlongused;++unsignedintlen;+boolmore;+boolmerge;+intop;++structakcipher_requestreq;+};++staticinlineintakcipher_sndbuf(structsock*sk)+{+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;++returnmax_t(int,max_t(int,sk->sk_sndbuf&PAGE_MASK,PAGE_SIZE)-+ctx->used,0);+}++staticinlineboolakcipher_writable(structsock*sk)+{+returnakcipher_sndbuf(sk)>=PAGE_SIZE;+}++staticvoidakcipher_put_sgl(structsock*sk)+{+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+structakcipher_sg_list*sgl=&ctx->tsgl;+structscatterlist*sg=sgl->sg;+unsignedinti;++for(i=0;i<sgl->cur;i++){+if(!sg_page(sg+i))+continue;++put_page(sg_page(sg+i));+sg_assign_page(sg+i,NULL);+}+sg_init_table(sg,ALG_MAX_PAGES);+sgl->cur=0;+ctx->used=0;+ctx->more=0;+ctx->merge=0;+}++staticvoidakcipher_wmem_wakeup(structsock*sk)+{+structsocket_wq*wq;++if(!akcipher_writable(sk))+return;++rcu_read_lock();+wq=rcu_dereference(sk->sk_wq);+if(wq_has_sleeper(&wq->wait))+wake_up_interruptible_sync_poll(&wq->wait,POLLIN|+POLLRDNORM|+POLLRDBAND);+sk_wake_async(sk,SOCK_WAKE_WAITD,POLL_IN);+rcu_read_unlock();+}++staticintakcipher_wait_for_data(structsock*sk,unsignedintflags)+{+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+longtimeout;+DEFINE_WAIT(wait);+interr=-ERESTARTSYS;++if(flags&MSG_DONTWAIT)+return-EAGAIN;++set_bit(SOCKWQ_ASYNC_WAITDATA,&sk->sk_socket->flags);++for(;;){+if(signal_pending(current))+break;+prepare_to_wait(sk_sleep(sk),&wait,TASK_INTERRUPTIBLE);+timeout=MAX_SCHEDULE_TIMEOUT;+if(sk_wait_event(sk,&timeout,!ctx->more)){+err=0;+break;+}+}+finish_wait(sk_sleep(sk),&wait);++clear_bit(SOCKWQ_ASYNC_WAITDATA,&sk->sk_socket->flags);++returnerr;+}++staticvoidakcipher_data_wakeup(structsock*sk)+{+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+structsocket_wq*wq;++if(ctx->more)+return;+if(!ctx->used)+return;++rcu_read_lock();+wq=rcu_dereference(sk->sk_wq);+if(wq_has_sleeper(&wq->wait))+wake_up_interruptible_sync_poll(&wq->wait,POLLOUT|+POLLRDNORM|+POLLRDBAND);+sk_wake_async(sk,SOCK_WAKE_SPACE,POLL_OUT);+rcu_read_unlock();+}++staticintakcipher_sendmsg(structsocket*sock,structmsghdr*msg,+size_tsize)+{+structsock*sk=sock->sk;+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+structakcipher_sg_list*sgl=&ctx->tsgl;+structaf_alg_controlcon={};+longcopied=0;+intop=0;+boolinit=0;+interr=-EINVAL;++if(msg->msg_controllen){+err=af_alg_cmsg_send(msg,&con);+if(err)+returnerr;++init=1;+switch(con.op){+caseALG_OP_VERIFY:+caseALG_OP_SIGN:+caseALG_OP_ENCRYPT:+caseALG_OP_DECRYPT:+op=con.op;+break;+default:+return-EINVAL;+}+}++lock_sock(sk);+if(!ctx->more&&ctx->used)+gotounlock;++if(init)+ctx->op=op;++while(size){+unsignedlonglen=size;+structscatterlist*sg=NULL;++/* use the existing memory in an allocated page */+if(ctx->merge){+sg=sgl->sg+sgl->cur-1;+len=min_t(unsignedlong,len,+PAGE_SIZE-sg->offset-sg->length);+err=memcpy_from_msg(page_address(sg_page(sg))++sg->offset+sg->length,+msg,len);+if(err)+gotounlock;++sg->length+=len;+ctx->merge=(sg->offset+sg->length)&+(PAGE_SIZE-1);++ctx->used+=len;+copied+=len;+size-=len;+continue;+}++if(!akcipher_writable(sk)){+/* user space sent too much data */+akcipher_put_sgl(sk);+err=-EMSGSIZE;+gotounlock;+}++/* allocate a new page */+len=min_t(unsignedlong,size,akcipher_sndbuf(sk));+while(len){+intplen=0;++if(sgl->cur>=ALG_MAX_PAGES){+akcipher_put_sgl(sk);+err=-E2BIG;+gotounlock;+}++sg=sgl->sg+sgl->cur;+plen=min_t(int,len,PAGE_SIZE);++sg_assign_page(sg,alloc_page(GFP_KERNEL));+if(!sg_page(sg)){+err=-ENOMEM;+gotounlock;+}++err=memcpy_from_msg(page_address(sg_page(sg)),+msg,plen);+if(err){+__free_page(sg_page(sg));+sg_assign_page(sg,NULL);+gotounlock;+}++sg->offset=0;+sg->length=plen;+len-=plen;+ctx->used+=plen;+copied+=plen;+sgl->cur++;+size-=plen;+ctx->merge=plen&(PAGE_SIZE-1);+}+}++err=0;++ctx->more=msg->msg_flags&MSG_MORE;++unlock:+akcipher_data_wakeup(sk);+release_sock(sk);++returnerr?:copied;+}++staticssize_takcipher_sendpage(structsocket*sock,structpage*page,+intoffset,size_tsize,intflags)+{+structsock*sk=sock->sk;+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+structakcipher_sg_list*sgl=&ctx->tsgl;+interr=0;++if(flags&MSG_SENDPAGE_NOTLAST)+flags|=MSG_MORE;++if(sgl->cur>=ALG_MAX_PAGES)+return-E2BIG;++lock_sock(sk);+if(!ctx->more&&ctx->used)+gotounlock;++if(!size)+gotodone;++if(!akcipher_writable(sk)){+/* user space sent too much data */+akcipher_put_sgl(sk);+err=-EMSGSIZE;+gotounlock;+}++ctx->merge=0;++get_page(page);+sg_set_page(sgl->sg+sgl->cur,page,size,offset);+sgl->cur++;+ctx->used+=size;++done:+ctx->more=flags&MSG_MORE;+unlock:+akcipher_data_wakeup(sk);+release_sock(sk);++returnerr?err:size;+}++staticintakcipher_recvmsg(structsocket*sock,structmsghdr*msg,+size_tignored,intflags)+{+structsock*sk=sock->sk;+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+structakcipher_sg_list*sgl=&ctx->tsgl;+unsignedinti=0;+interr;+unsignedlongused=0;+size_tusedpages=0;+unsignedintcnt=0;++/* Limit number of IOV blocks to be accessed below */+if(msg->msg_iter.nr_segs>ALG_MAX_PAGES)+return-ENOMSG;++lock_sock(sk);++if(ctx->more){+err=akcipher_wait_for_data(sk,flags);+if(err)+gotounlock;+}++used=ctx->used;++/* convert iovecs of output buffers into scatterlists */+while(iov_iter_count(&msg->msg_iter)){+/* make one iovec available as scatterlist */+err=af_alg_make_sg(&ctx->rsgl[cnt],&msg->msg_iter,+iov_iter_count(&msg->msg_iter));+if(err<0)+gotounlock;+usedpages+=err;+/* chain the new scatterlist with previous one */+if(cnt)+af_alg_link_sg(&ctx->rsgl[cnt-1],&ctx->rsgl[cnt]);++iov_iter_advance(&msg->msg_iter,err);+cnt++;+}++sg_mark_end(sgl->sg+sgl->cur-1);++akcipher_request_set_crypt(&ctx->req,sgl->sg,ctx->rsgl[0].sg,used,+usedpages);+switch(ctx->op){+caseALG_OP_VERIFY:+err=crypto_akcipher_verify(&ctx->req);+break;+caseALG_OP_SIGN:+err=crypto_akcipher_sign(&ctx->req);+break;+caseALG_OP_ENCRYPT:+err=crypto_akcipher_encrypt(&ctx->req);+break;+caseALG_OP_DECRYPT:+err=crypto_akcipher_decrypt(&ctx->req);+break;+default:+err=-EFAULT;+gotounlock;+}++err=af_alg_wait_for_completion(err,&ctx->completion);++if(err){+/* EBADMSG implies a valid cipher operation took place */+if(err==-EBADMSG)+akcipher_put_sgl(sk);+gotounlock;+}++akcipher_put_sgl(sk);++unlock:+for(i=0;i<cnt;i++)+af_alg_free_sg(&ctx->rsgl[i]);++akcipher_wmem_wakeup(sk);+release_sock(sk);++returnerr?err:ctx->req.dst_len;+}++staticunsignedintakcipher_poll(structfile*file,structsocket*sock,+poll_table*wait)+{+structsock*sk=sock->sk;+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;+unsignedintmask=0;++sock_poll_wait(file,sk_sleep(sk),wait);++if(!ctx->more)+mask|=POLLIN|POLLRDNORM;++if(akcipher_writable(sk))+mask|=POLLOUT|POLLWRNORM|POLLWRBAND;++returnmask;+}++staticstructproto_opsalgif_akcipher_ops={+.family=PF_ALG,++.connect=sock_no_connect,+.socketpair=sock_no_socketpair,+.getname=sock_no_getname,+.ioctl=sock_no_ioctl,+.listen=sock_no_listen,+.shutdown=sock_no_shutdown,+.getsockopt=sock_no_getsockopt,+.mmap=sock_no_mmap,+.bind=sock_no_bind,+.accept=sock_no_accept,+.setsockopt=sock_no_setsockopt,++.release=af_alg_release,+.sendmsg=akcipher_sendmsg,+.sendpage=akcipher_sendpage,+.recvmsg=akcipher_recvmsg,+.poll=akcipher_poll,+};++staticvoid*akcipher_bind(constchar*name,u32type,u32mask)+{+returncrypto_alloc_akcipher(name,type,mask);+}++staticvoidakcipher_release(void*private)+{+crypto_free_akcipher(private);+}++staticintakcipher_setprivkey(void*private,constu8*key,+unsignedintkeylen)+{+returncrypto_akcipher_set_priv_key(private,key,keylen);+}++staticintakcipher_setpubkey(void*private,constu8*key,unsignedintkeylen)+{+returncrypto_akcipher_set_pub_key(private,key,keylen);+}++staticvoidakcipher_sock_destruct(structsock*sk)+{+structalg_sock*ask=alg_sk(sk);+structakcipher_ctx*ctx=ask->private;++akcipher_put_sgl(sk);+sock_kfree_s(sk,ctx,ctx->len);+af_alg_release_parent(sk);+}++staticintakcipher_accept_parent(void*private,structsock*sk)+{+structakcipher_ctx*ctx;+structalg_sock*ask=alg_sk(sk);+unsignedintlen=sizeof(*ctx)+crypto_akcipher_reqsize(private);++ctx=sock_kmalloc(sk,len,GFP_KERNEL);+if(!ctx)+return-ENOMEM;+memset(ctx,0,len);++ctx->len=len;+ctx->used=0;+ctx->more=0;+ctx->merge=0;+ctx->op=0;+ctx->tsgl.cur=0;+af_alg_init_completion(&ctx->completion);+sg_init_table(ctx->tsgl.sg,ALG_MAX_PAGES);++ask->private=ctx;++akcipher_request_set_tfm(&ctx->req,private);+akcipher_request_set_callback(&ctx->req,CRYPTO_TFM_REQ_MAY_BACKLOG,+af_alg_complete,&ctx->completion);++sk->sk_destruct=akcipher_sock_destruct;++return0;+}++staticconststructaf_alg_typealgif_type_akcipher={+.bind=akcipher_bind,+.release=akcipher_release,+.setkey=akcipher_setprivkey,+.setpubkey=akcipher_setpubkey,+.accept=akcipher_accept_parent,+.ops=&algif_akcipher_ops,+.name="akcipher",+.owner=THIS_MODULE+};++staticint__initalgif_akcipher_init(void)+{+returnaf_alg_register_type(&algif_type_akcipher);+}++staticvoid__exitalgif_akcipher_exit(void)+{+interr=af_alg_unregister_type(&algif_type_akcipher);++WARN_ON(err);+}++module_init(algif_akcipher_init);+module_exit(algif_akcipher_exit);+MODULE_LICENSE("GPL");+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");+MODULE_DESCRIPTION("Asymmetric kernel crypto API user space interface");
From: Tadeusz Struk <hidden> Date: 2016-06-23 22:56:53
From: Stephan Mueller <redacted>
For supporting asymmetric ciphers, user space must be able to set the
public key. The patch adds a new setsockopt call for setting the public
key.
Signed-off-by: Stephan Mueller <redacted>
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/af_alg.c | 18 +++++++++++++-----
include/crypto/if_alg.h | 1 +
2 files changed, 14 insertions(+), 5 deletions(-)
@@ -247,10 +251,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,caseALG_SET_KEY:if(sock->state==SS_CONNECTED)gotounlock;-if(!type->setkey)++err=alg_setkey(sk,optval,optlen,type->setkey);+break;+caseALG_SET_PUBKEY:+if(sock->state==SS_CONNECTED)gotounlock;-err=alg_setkey(sk,optval,optlen);+err=alg_setkey(sk,optval,optlen,type->setpubkey);break;caseALG_SET_AEAD_AUTHSIZE:if(sock->state==SS_CONNECTED)
From: Mat Martineau <hidden> Date: 2016-06-29 18:43:24
Tadeusz,
On Thu, 23 Jun 2016, Tadeusz Struk wrote:
quoted hunk
This patch adds support for asymmetric key type to AF_ALG.
It will work as follows: A new PF_ALG socket options are
added on top of existing ALG_SET_KEY and ALG_SET_PUBKEY, namely
ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID for setting public and
private keys respectively. When these new options will be used
the user, instead of providing the key material, will provide a
key id and the key itself will be obtained from kernel keyring
subsystem. The user will use the standard tools (keyctl tool
or the keyctl syscall) for key instantiation and to obtain the
key id. The key id can also be obtained by reading the
/proc/keys file.
When a key corresponding to the given keyid is found, it is stored
in the socket context and subsequent crypto operation invoked by the
user will use the new asymmetric accessor functions instead of akcipher
api. The asymmetric subtype can internally use akcipher api or
invoke operations defined by a given subtype, depending on the
key type.
Signed-off-by: Tadeusz Struk <redacted>
---
crypto/af_alg.c | 10 ++
crypto/algif_akcipher.c | 212 ++++++++++++++++++++++++++++++++++++++++++-
include/crypto/if_alg.h | 1
include/uapi/linux/if_alg.h | 2
4 files changed, 220 insertions(+), 5 deletions(-)
diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.cindex 2b8d37e..106f715 100644--- a/crypto/algif_akcipher.c+++ b/crypto/algif_akcipher.c
+static int asym_key_verify(const struct key *key, struct akcipher_request *req)
+{
+ struct public_key_signature sig;
+ char *src = NULL, *in, digest[20];
+ int ret;
+
+ if (!sg_is_last(req->src)) {
+ src = kmalloc(req->src_len, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+ in = src;
+ } else {
+ in = sg_virt(req->src);
+ }
+ sig.pkey_algo = "rsa";
+ sig.encoding = "pkcs1";
+ /* Need to find a way to pass the hash param */
I think you fixed the BUG_ON() problem but there's still an issue with the
handling of the digest. Check the use of sig->digest in
public_key_verify_signature(), it's an input not an output. Right now it
looks like 20 uninitialized bytes are compared with the computed digest
within verify_signature, and then the unintialized bytes are copied to
req->dst here.
With some modifications to public_key_verify_signature you could get the
digest you need, but I'm not sure if verification with a hardware key
(like a key in a TPM) can or can not provide the digest needed. Maybe this
is why the verify_signature hook in struct asymmetric_key_subtype is
optional.
From: Tadeusz Struk <hidden> Date: 2016-07-05 20:27:09
Hi Mat,
On 06/29/2016 11:43 AM, Mat Martineau wrote:
quoted
+ ret = verify_signature(key, &sig);
+ if (!ret) {
+ req->dst_len = sizeof(digest);
I think you fixed the BUG_ON() problem but there's still an issue with
the handling of the digest. Check the use of sig->digest in
public_key_verify_signature(), it's an input not an output. Right now it
looks like 20 uninitialized bytes are compared with the computed digest
within verify_signature, and then the unintialized bytes are copied to
req->dst here.
With some modifications to public_key_verify_signature you could get the
digest you need, but I'm not sure if verification with a hardware key
(like a key in a TPM) can or can not provide the digest needed. Maybe
this is why the verify_signature hook in struct asymmetric_key_subtype
is optional.
From: Mat Martineau <hidden> Date: 2016-07-06 19:39:00
On Tue, 5 Jul 2016, Tadeusz Struk wrote:
Hi Mat,
On 06/29/2016 11:43 AM, Mat Martineau wrote:
quoted
quoted
+ ret = verify_signature(key, &sig);
+ if (!ret) {
+ req->dst_len = sizeof(digest);
I think you fixed the BUG_ON() problem but there's still an issue with
the handling of the digest. Check the use of sig->digest in
public_key_verify_signature(), it's an input not an output. Right now it
looks like 20 uninitialized bytes are compared with the computed digest
within verify_signature, and then the unintialized bytes are copied to
req->dst here.
With some modifications to public_key_verify_signature you could get the
digest you need, but I'm not sure if verification with a hardware key
(like a key in a TPM) can or can not provide the digest needed. Maybe
this is why the verify_signature hook in struct asymmetric_key_subtype
is optional.
So it looks like the only thing that we need to return to the user in
this case is the return code. Do you agree?
The way verify_signature is implemented today, the only output is the
return code. For verify, maybe no read is required (just sendmsg() and
check the return code).
But this isn't the extent of the problem: verify_signature needs both the
signature to be verified and the expected hash as inputs. How is the
expected hash provided? Would you include it as a cmsg header?
ALG_OP_VERIFY should have consistent inputs and outputs whether the key
was set with ALG_SET_KEY_ID or ALG_SET_KEY.
--
Mat Martineau
Intel OTC
From: Tadeusz Struk <hidden> Date: 2016-07-08 15:22:13
Hi Mat,
On 07/06/2016 12:38 PM, Mat Martineau wrote:
quoted
So it looks like the only thing that we need to return to the user in
this case is the return code. Do you agree?
The way verify_signature is implemented today, the only output is the
return code. For verify, maybe no read is required (just sendmsg() and
check the return code).
But this isn't the extent of the problem: verify_signature needs both
the signature to be verified and the expected hash as inputs. How is the
expected hash provided? Would you include it as a cmsg header?
ALG_OP_VERIFY should have consistent inputs and outputs whether the key
was set with ALG_SET_KEY_ID or ALG_SET_KEY.
The signature of verify_signature() is quite different from the other
new public key handlers, i.e. create_signature(), encrypt_blob(), and
decrypt_blob(). For verify_signature() we need the following parameters:
encrypted src, hash function to use, expected digest.
The expected digest could be optional if we would modify the
verify_signature() to return the decrypted buffer.
I think the best solution for now would be to just return -ENOPROTOOPT
for verify_signature in SET_KEY_ID mode.
All the four operations will be supported in the SET_KEY mode and
all but verify_signature() will be supported in the SET_KEY_ID mode.
This can added later if we will find a way to pass all parameters in a
consistent way. What do you think? If you are ok with that I will send a
new version soon.
Thanks,
--
TS
From: Mat Martineau <hidden> Date: 2016-07-08 16:44:26
On Fri, 8 Jul 2016, Tadeusz Struk wrote:
Hi Mat,
On 07/06/2016 12:38 PM, Mat Martineau wrote:
quoted
quoted
So it looks like the only thing that we need to return to the user in
this case is the return code. Do you agree?
The way verify_signature is implemented today, the only output is the
return code. For verify, maybe no read is required (just sendmsg() and
check the return code).
But this isn't the extent of the problem: verify_signature needs both
the signature to be verified and the expected hash as inputs. How is the
expected hash provided? Would you include it as a cmsg header?
ALG_OP_VERIFY should have consistent inputs and outputs whether the key
was set with ALG_SET_KEY_ID or ALG_SET_KEY.
The signature of verify_signature() is quite different from the other
new public key handlers, i.e. create_signature(), encrypt_blob(), and
decrypt_blob(). For verify_signature() we need the following parameters:
encrypted src, hash function to use, expected digest.
The expected digest could be optional if we would modify the
verify_signature() to return the decrypted buffer.
I think the best solution for now would be to just return -ENOPROTOOPT
for verify_signature in SET_KEY_ID mode.
All the four operations will be supported in the SET_KEY mode and
all but verify_signature() will be supported in the SET_KEY_ID mode.
This can added later if we will find a way to pass all parameters in a
consistent way. What do you think? If you are ok with that I will send a
new version soon.
Are the inputs and outputs defined for ALG_OP_VERIFY in SET_KEY mode going
to work for hardware keys (like TPM) in SET_KEY_ID mode? That's needed if
the verify SET_KEY_ID mode is to be added later.
--
Mat Martineau
Intel OTC
From: Tadeusz Struk <hidden> Date: 2016-07-08 17:27:08
On 07/08/2016 09:38 AM, Mat Martineau wrote:
Are the inputs and outputs defined for ALG_OP_VERIFY in SET_KEY mode
going to work for hardware keys (like TPM) in SET_KEY_ID mode? That's
needed if the verify SET_KEY_ID mode is to be added later.
Yes, we will just need to change the verify_signature() in public_key.c
to be consistent with the rest of handlers. What we need really is the
src (encrypted input), key (or key id), and an output buffer where we
can copy the result to.
Thanks,
--
TS