问题
I'm working on a kernel module which uses asymmetric cipher of kernel crypto api, kernel version 4.8.0. I generate asymmetric key pairs by openssl, convert them into DER format (which I knew was a subset of BER), and code into my module. Private key works just fine, but public key always fails at crypto_akcipher_set_pub_key, even if I try more other key pairs. dmesg just prints:
[16891.604718] next_op: pc=0/10 dp=0/161 C=0 J=0
[16891.604721] - match? 30 30 00
[16891.604724] - TAG: 30 158 CONS
[16891.604726] next_op: pc=2/10 dp=3/161 C=1 J=0
[16891.604727] - match? 30 02 32
[16891.604729]
ASN1: Unexpected tag [m=2 d=4 ot=02 t=30 l=158]
[16891.604730] set key error! -74,,,,,0
Here are my questions:
A) Does dmesg mean the public key is wrong? How to generate a kernel-crypto-compatible key pairs?
B) I cannot find a useable rsa key pairs for kernel asymmetric cipher, not even in Linux/crypto/testmgr.h or libkcapi/test/test.sh, can you help me out?
Thanks!
Here is my module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <crypto/skcipher.h>
#include <crypto/akcipher.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/highmem.h>
const char *priv_key =
"\x30\x82\x02\x5d\x02\x01\x00\x02\x81\x81\x00\xd0"
"\xb4\x5a\xc1\x9e\x2e\x4d\xae\xbd\x51\x39\xcc\x4b"
"\x12\xf5\x76\x30\xcf\x39\x97\xf1\xd3\x0d\xaa\x37"
"\x70\x2d\x2f\x01\xc9\x69\x09\xe3\x4e\xd5\x90\x68"
"\xfe\xbf\x7c\x8b\x86\xdf\xf3\x14\xb3\x96\xcf\x1b"
"\x39\xe3\xe6\x8a\x77\x6d\xe4\x89\xef\xdb\xba\x4a"
"\x40\x6d\xa9\xec\x21\x62\x00\xa4\xc3\x45\xcc\xdd"
"\x56\xb2\x77\x59\x46\x17\x27\x0e\x2c\xfe\x85\x53"
"\x72\x26\x9b\xdc\x24\x83\xd1\x67\xa7\x4c\x88\x70"
"\x78\x3f\x1c\x60\xd4\x95\x14\x57\xfc\xdb\x15\xaa"
"\xab\x31\x32\xb2\x44\x72\xdd\xb0\x0b\x13\x62\x03"
"\x50\x1d\xd4\x6a\xf6\xb2\x23\x02\x03\x01\x00\x01"
"\x02\x81\x80\x7b\x83\x10\xe6\xde\xf7\x26\x30\x10"
"\x88\x3e\x7d\x61\xbc\xa1\x99\xc5\xbf\x0d\xa5\x97"
"\x8e\xc0\xda\x88\x9e\x91\x8e\xed\x2e\xc6\x43\xfc"
"\xcb\x0d\xe6\xbd\xcc\x6d\x84\x86\x8a\x56\x84\xe4"
"\x2e\x78\x44\xaf\x27\x2e\x71\xa4\x66\x93\x99\x99"
"\xec\x62\x8c\x38\x1f\x33\x06\x37\xc1\x9d\x17\x6b"
"\xad\xfb\x8e\x44\xd3\x11\xcb\x74\xa4\x01\x78\xb0"
"\x9c\x64\xd3\x0d\x63\x99\x65\xe3\xca\xae\x11\xb2"
"\xc4\x00\x36\xc2\xfc\x4b\x7b\x6f\x9e\x84\xb6\x97"
"\x00\x56\x5b\x09\xa1\x28\xf5\x28\x8d\xc7\x93\x45"
"\xba\xc0\x6b\xa9\x2d\xeb\x02\xcd\xde\x1e\x29\x02"
"\x41\x00\xf6\x0e\x41\xbc\xfa\x40\x82\xba\xa0\x6a"
"\xa5\x75\x5c\xcd\xfe\xa8\x11\xa6\xef\xbc\xad\x5f"
"\x86\x40\xb4\x5a\x65\xc1\x7b\x5e\x89\xc2\x60\x38"
"\x0e\x8b\x7d\x7d\x99\x30\x01\xf1\xea\x1e\x3e\x46"
"\xf4\xd2\xd9\x80\xaf\x3a\x4b\x2f\xbb\x91\xbb\xb7"
"\x22\x2d\x6a\x0f\x4e\x6f\x02\x41\x00\xd9\x23\xa7"
"\x98\x0c\x58\xe1\x5d\xa7\x15\x05\xc6\xd9\x7b\xc5"
"\x7b\xd3\x01\x8b\x1e\xf1\x2e\x99\xc5\xac\x41\xf1"
"\x92\x88\xd9\x8e\x50\x86\xf9\x2f\x66\x42\xeb\xf9"
"\x80\x78\xfa\xc7\xea\x63\x35\x7e\x6f\xc5\x35\x36"
"\x6b\xa1\x8a\xa3\x49\x97\xbc\xa6\x9b\x5c\x6e\xf1"
"\x8d\x02\x40\x44\x70\xa0\xbe\x64\xc9\x4e\xd3\x84"
"\x4d\x45\xaa\x88\x5e\xcf\xe7\x85\xc9\x6e\x43\x87"
"\xe1\xdb\x20\xe2\x49\x86\xa6\x33\x9f\x8f\x27\xde"
"\xc5\x98\xde\x19\xd0\xb6\xac\x50\xce\x2e\x35\xad"
"\x52\xe5\x44\x44\xb5\x73\x87\xfe\x63\xcf\x83\x70"
"\xb8\x36\xac\x75\x24\xbe\xc7\x02\x41\x00\x87\xd2"
"\x97\xa8\xb2\x40\x7e\x67\xf8\x75\x5b\xf1\xb0\x64"
"\x8d\x79\x10\xd9\xec\x4d\xe4\x8b\x43\xc0\xb4\x29"
"\x63\x94\x47\x69\xde\x6d\x5c\xa0\x4e\x17\xe7\x50"
"\x77\xf6\xf6\xb5\xd7\x8b\x33\x97\x68\x89\x3d\x90"
"\x35\x84\x49\xbd\xd0\xb9\xdd\xe2\x31\x4d\x09\x1a"
"\x94\x99\x02\x41\x00\xc9\x12\xec\x64\xe9\x01\x27"
"\x10\x6c\xad\xc5\x83\x8a\x26\x39\xe0\x05\xde\xde"
"\xf9\x1a\x5d\xf6\xcb\xe8\xd2\x9b\x40\xd5\x11\xc8"
"\x9a\x6d\x29\xb6\x15\x36\x9a\xee\x45\xe2\x51\x14"
"\xa8\x2d\xab\x57\x86\x80\x87\x0a\x02\xaf\xfa\xda"
"\x5e\x7d\xfb\x84\xd1\x3a\xe0\xed\x57";
const int priv_key_len = 609;
const char *pub_key =
"\x30\x81\x9e\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7"
"\x0d\x01\x01\x01\x05\x00\x03\x81\x8c\x00\x30\x81"
"\x88\x02\x81\x80\x6d\x4d\xaf\xf5\x32\x98\xfa\x33"
"\xf2\x4a\xb0\x50\x27\x6f\x50\x0b\x28\xca\x5f\x6e"
"\xde\xec\x7b\xae\xeb\xd1\x89\xdf\xcf\x8d\x12\x6c"
"\x0d\xf2\x32\x65\xb7\x04\xf2\xb8\x76\x67\xe9\x28"
"\xc3\x12\x6b\x4a\x52\x09\xd6\x61\x9b\x21\x25\x04"
"\xe0\x9a\xec\xbc\x25\x3f\xfc\x6f\x1a\x98\xa8\x02"
"\xa8\x2e\x89\x91\x20\xcf\xf0\xd1\x9d\x09\x35\xac"
"\x95\xe2\xe4\x8e\x5b\x7c\x34\x93\x39\x4f\x33\xbd"
"\x6e\xe7\xc5\xbb\x2a\x28\x32\x13\x62\x39\x37\x87"
"\x40\xe7\x59\xf8\x94\xad\xc4\x2e\xaf\x23\xf4\x98"
"\xcd\x90\x27\x96\x41\xc6\x4a\xcd\x6d\x56\xfd\x5b"
"\x02\x03\x01\x00\x01";
const int pub_key_len = 161;
const char *msg = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
const int msg_len = 8;
char *crypted = NULL;
int crypted_len = 0;
struct tcrypt_result {
struct completion completion;
int err;
};
struct akcipher_testvec {
unsigned char *key;
unsigned char *msg;
unsigned int key_size;
unsigned int msg_size;
};
static inline void hexdump(unsigned char *buf,unsigned int len) {
while(len--)
printk("%02x",*buf++);
printk("\n");
}
static void tcrypt_complete(struct crypto_async_request *req, int err)
{
struct tcrypt_result *res = req->data;
if (err == -EINPROGRESS)
return;
res->err = err;
complete(&res->completion);
}
static int wait_async_op(struct tcrypt_result *tr, int ret)
{
if (ret == -EINPROGRESS || ret == -EBUSY) {
wait_for_completion(&tr->completion);
reinit_completion(&tr->completion);
ret = tr->err;
}
return ret;
}
static int uf_akcrypto(struct crypto_akcipher *tfm,
void *data, int datalen, int phase)
{
void *xbuf = NULL;
struct akcipher_request *req;
void *outbuf = NULL;
struct tcrypt_result result;
unsigned int out_len_max = 0;
struct scatterlist src, dst;
int err = -ENOMEM;
xbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!xbuf)
return err;
req = akcipher_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto free_xbuf;
init_completion(&result.completion);
if (!phase) //test
err = crypto_akcipher_set_pub_key(tfm, pub_key, pub_key_len);
else
err = crypto_akcipher_set_priv_key(tfm, priv_key, priv_key_len);
// err = crypto_akcipher_set_priv_key(tfm, priv_key, priv_key_len);
if (err){
printk("set key error! %d,,,,,%d\n", err,phase);
goto free_req;
}
err = -ENOMEM;
out_len_max = crypto_akcipher_maxsize(tfm);
outbuf = kzalloc(out_len_max, GFP_KERNEL);
if (!outbuf)
goto free_req;
if (WARN_ON(datalen > PAGE_SIZE))
goto free_all;
memcpy(xbuf, data, datalen);
sg_init_one(&src, xbuf, datalen);
sg_init_one(&dst, outbuf, out_len_max);
akcipher_request_set_crypt(req, &src, &dst, datalen, out_len_max);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
tcrypt_complete, &result);
if (phase){
err = wait_async_op(&result, crypto_akcipher_encrypt(req));
if (err) {
pr_err("alg: akcipher: encrypt test failed. err %d\n", err);
goto free_all;
}
memcpy(crypted,outbuf,out_len_max);
crypted_len = out_len_max;
hexdump(crypted, out_len_max);
}else{
err = wait_async_op(&result, crypto_akcipher_decrypt(req));
if (err) {
pr_err("alg: akcipher: decrypt test failed. err %d\n", err);
goto free_all;
}
hexdump(outbuf, out_len_max);
}
free_all:
kfree(outbuf);
free_req:
akcipher_request_free(req);
free_xbuf:
kfree(xbuf);
return err;
}
static int userfaultfd_akcrypto(void *data, int datalen, int phase)
{
struct crypto_akcipher *tfm;
int err = 0;
tfm = crypto_alloc_akcipher("rsa", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm)) {
pr_err("alg: akcipher: Failed to load tfm for rsa: %ld\n", PTR_ERR(tfm));
return PTR_ERR(tfm);
}
err = uf_akcrypto(tfm,data,datalen,phase);
crypto_free_akcipher(tfm);
return err;
}
static int __init test_init(void)
{
crypted = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!crypted){
printk("crypted kmalloc error\n");
return -1;
}
userfaultfd_akcrypto(msg,msg_len,1);
userfaultfd_akcrypto(crypted,crypted_len,0);
kfree(crypted);
}
static void __exit test_exit(void)
{
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
回答1:
I have figured this out myself.
The fact is the public key generate by openssl is correct, but it contains more information at its head, which is not required by kernel crypto api. With the extra data, kernel ctypto api cannot parse the public key structure correctly, that's why "ASN1: Unexpected tag".
Take a look at kernel-compatible public key here, it only contains the following elements:
{
total size
integer size and value
integer size and value
}
The following command will show you the structure of public key in der formate generate by openssl:
openssl asn1parse -in public_key.der -inform DER
The outputs are like these:
0:d=0 hl=3 l= 159 cons: SEQUENCE
3:d=1 hl=2 l= 13 cons: SEQUENCE
5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
16:d=2 hl=2 l= 0 prim: NULL
18:d=1 hl=3 l= 141 prim: BIT STRING
The real data is in BIT STRING. And it's offset is 18. So from offset 18 to end is the data you wanted.
You can read the BIT STRING inner structure by typing the command:
openssl asn1parse -in public_key.der -inform DER -strparse 18
The outputs like:
0:d=0 hl=3 l= 137 cons: SEQUENCE
3:d=1 hl=3 l= 129 prim: INTEGER :D0B45AC19E2E4DA ....
135:d=1 hl=2 l= 3 prim: INTEGER :010001
just as the same structure as kernel-compatible public key.
来源:https://stackoverflow.com/questions/41084118/crypto-akcipher-set-pub-key-in-kernel-asymmetric-crypto-always-returns-error