Skip to content

Commit f1774cb

Browse files
vt-altherbertx
authored andcommitted
X.509: parse public key parameters from x509 for akcipher
Some public key algorithms (like EC-DSA) keep in parameters field important data such as digest and curve OIDs (possibly more for different EC-DSA variants). Thus, just setting a public key (as for RSA) is not enough. Append parameters into the key stream for akcipher_set_{pub,priv}_key. Appended data is: (u32) algo OID, (u32) parameters length, parameters data. This does not affect current akcipher API nor RSA ciphers (they could ignore it). Idea of appending parameters to the key stream is by Herbert Xu. Cc: David Howells <dhowells@redhat.com> Cc: Denis Kenzior <denkenz@gmail.com> Cc: keyrings@vger.kernel.org Signed-off-by: Vitaly Chikunov <vt@altlinux.org> Reviewed-by: Denis Kenzior <denkenz@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 83bc029 commit f1774cb

File tree

8 files changed

+136
-29
lines changed

8 files changed

+136
-29
lines changed

crypto/asymmetric_keys/asym_tpm.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ static int tpm_sign(struct tpm_buf *tb,
276276

277277
return datalen;
278278
}
279+
280+
/* Room to fit two u32 zeros for algo id and parameters length. */
281+
#define SETKEY_PARAMS_SIZE (sizeof(u32) * 2)
282+
279283
/*
280284
* Maximum buffer size for the BER/DER encoded public key. The public key
281285
* is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048
@@ -286,8 +290,9 @@ static int tpm_sign(struct tpm_buf *tb,
286290
* - 257 bytes of n
287291
* - max 2 bytes for INTEGER e type/length
288292
* - 3 bytes of e
293+
* - 4+4 of zeros for set_pub_key parameters (SETKEY_PARAMS_SIZE)
289294
*/
290-
#define PUB_KEY_BUF_SIZE (4 + 4 + 257 + 2 + 3)
295+
#define PUB_KEY_BUF_SIZE (4 + 4 + 257 + 2 + 3 + SETKEY_PARAMS_SIZE)
291296

292297
/*
293298
* Provide a part of a description of the key for /proc/keys.
@@ -364,6 +369,8 @@ static uint32_t derive_pub_key(const void *pub_key, uint32_t len, uint8_t *buf)
364369
cur = encode_tag_length(cur, 0x02, sizeof(e));
365370
memcpy(cur, e, sizeof(e));
366371
cur += sizeof(e);
372+
/* Zero parameters to satisfy set_pub_key ABI. */
373+
memset(cur, 0, SETKEY_PARAMS_SIZE);
367374

368375
return cur - buf;
369376
}

crypto/asymmetric_keys/public_key.c

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ void public_key_free(struct public_key *key)
4545
{
4646
if (key) {
4747
kfree(key->key);
48+
kfree(key->params);
4849
kfree(key);
4950
}
5051
}
@@ -94,6 +95,12 @@ int software_key_determine_akcipher(const char *encoding,
9495
return -ENOPKG;
9596
}
9697

98+
static u8 *pkey_pack_u32(u8 *dst, u32 val)
99+
{
100+
memcpy(dst, &val, sizeof(val));
101+
return dst + sizeof(val);
102+
}
103+
97104
/*
98105
* Query information about a key.
99106
*/
@@ -103,6 +110,7 @@ static int software_key_query(const struct kernel_pkey_params *params,
103110
struct crypto_akcipher *tfm;
104111
struct public_key *pkey = params->key->payload.data[asym_crypto];
105112
char alg_name[CRYPTO_MAX_ALG_NAME];
113+
u8 *key, *ptr;
106114
int ret, len;
107115

108116
ret = software_key_determine_akcipher(params->encoding,
@@ -115,14 +123,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
115123
if (IS_ERR(tfm))
116124
return PTR_ERR(tfm);
117125

126+
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
127+
GFP_KERNEL);
128+
if (!key)
129+
goto error_free_tfm;
130+
memcpy(key, pkey->key, pkey->keylen);
131+
ptr = key + pkey->keylen;
132+
ptr = pkey_pack_u32(ptr, pkey->algo);
133+
ptr = pkey_pack_u32(ptr, pkey->paramlen);
134+
memcpy(ptr, pkey->params, pkey->paramlen);
135+
118136
if (pkey->key_is_private)
119-
ret = crypto_akcipher_set_priv_key(tfm,
120-
pkey->key, pkey->keylen);
137+
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
121138
else
122-
ret = crypto_akcipher_set_pub_key(tfm,
123-
pkey->key, pkey->keylen);
139+
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
124140
if (ret < 0)
125-
goto error_free_tfm;
141+
goto error_free_key;
126142

127143
len = crypto_akcipher_maxsize(tfm);
128144
info->key_size = len * 8;
@@ -137,6 +153,8 @@ static int software_key_query(const struct kernel_pkey_params *params,
137153
KEYCTL_SUPPORTS_SIGN);
138154
ret = 0;
139155

156+
error_free_key:
157+
kfree(key);
140158
error_free_tfm:
141159
crypto_free_akcipher(tfm);
142160
pr_devel("<==%s() = %d\n", __func__, ret);
@@ -155,6 +173,7 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
155173
struct crypto_wait cwait;
156174
struct scatterlist in_sg, out_sg;
157175
char alg_name[CRYPTO_MAX_ALG_NAME];
176+
char *key, *ptr;
158177
int ret;
159178

160179
pr_devel("==>%s()\n", __func__);
@@ -173,14 +192,23 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
173192
if (!req)
174193
goto error_free_tfm;
175194

195+
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
196+
GFP_KERNEL);
197+
if (!key)
198+
goto error_free_req;
199+
200+
memcpy(key, pkey->key, pkey->keylen);
201+
ptr = key + pkey->keylen;
202+
ptr = pkey_pack_u32(ptr, pkey->algo);
203+
ptr = pkey_pack_u32(ptr, pkey->paramlen);
204+
memcpy(ptr, pkey->params, pkey->paramlen);
205+
176206
if (pkey->key_is_private)
177-
ret = crypto_akcipher_set_priv_key(tfm,
178-
pkey->key, pkey->keylen);
207+
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
179208
else
180-
ret = crypto_akcipher_set_pub_key(tfm,
181-
pkey->key, pkey->keylen);
209+
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
182210
if (ret)
183-
goto error_free_req;
211+
goto error_free_key;
184212

185213
sg_init_one(&in_sg, in, params->in_len);
186214
sg_init_one(&out_sg, out, params->out_len);
@@ -210,6 +238,8 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
210238
if (ret == 0)
211239
ret = req->dst_len;
212240

241+
error_free_key:
242+
kfree(key);
213243
error_free_req:
214244
akcipher_request_free(req);
215245
error_free_tfm:
@@ -229,6 +259,7 @@ int public_key_verify_signature(const struct public_key *pkey,
229259
struct akcipher_request *req;
230260
struct scatterlist src_sg[2];
231261
char alg_name[CRYPTO_MAX_ALG_NAME];
262+
char *key, *ptr;
232263
int ret;
233264

234265
pr_devel("==>%s()\n", __func__);
@@ -252,14 +283,23 @@ int public_key_verify_signature(const struct public_key *pkey,
252283
if (!req)
253284
goto error_free_tfm;
254285

286+
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
287+
GFP_KERNEL);
288+
if (!key)
289+
goto error_free_req;
290+
291+
memcpy(key, pkey->key, pkey->keylen);
292+
ptr = key + pkey->keylen;
293+
ptr = pkey_pack_u32(ptr, pkey->algo);
294+
ptr = pkey_pack_u32(ptr, pkey->paramlen);
295+
memcpy(ptr, pkey->params, pkey->paramlen);
296+
255297
if (pkey->key_is_private)
256-
ret = crypto_akcipher_set_priv_key(tfm,
257-
pkey->key, pkey->keylen);
298+
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
258299
else
259-
ret = crypto_akcipher_set_pub_key(tfm,
260-
pkey->key, pkey->keylen);
300+
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
261301
if (ret)
262-
goto error_free_req;
302+
goto error_free_key;
263303

264304
sg_init_table(src_sg, 2);
265305
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
@@ -272,6 +312,8 @@ int public_key_verify_signature(const struct public_key *pkey,
272312
crypto_req_done, &cwait);
273313
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
274314

315+
error_free_key:
316+
kfree(key);
275317
error_free_req:
276318
akcipher_request_free(req);
277319
error_free_tfm:

crypto/asymmetric_keys/x509.asn1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ CertificateSerialNumber ::= INTEGER
2222

2323
AlgorithmIdentifier ::= SEQUENCE {
2424
algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
25-
parameters ANY OPTIONAL
25+
parameters ANY OPTIONAL ({ x509_note_params })
2626
}
2727

2828
Name ::= SEQUENCE OF RelativeDistinguishedName

crypto/asymmetric_keys/x509_cert_parser.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ struct x509_parse_context {
2626
const void *cert_start; /* Start of cert content */
2727
const void *key; /* Key data */
2828
size_t key_size; /* Size of key data */
29+
const void *params; /* Key parameters */
30+
size_t params_size; /* Size of key parameters */
31+
enum OID key_algo; /* Public key algorithm */
2932
enum OID last_oid; /* Last OID encountered */
3033
enum OID algo_oid; /* Algorithm OID */
3134
unsigned char nr_mpi; /* Number of MPIs stored */
@@ -109,6 +112,13 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
109112

110113
cert->pub->keylen = ctx->key_size;
111114

115+
cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
116+
if (!cert->pub->params)
117+
goto error_decode;
118+
119+
cert->pub->paramlen = ctx->params_size;
120+
cert->pub->algo = ctx->key_algo;
121+
112122
/* Grab the signature bits */
113123
ret = x509_get_sig_params(cert);
114124
if (ret < 0)
@@ -400,6 +410,27 @@ int x509_note_subject(void *context, size_t hdrlen,
400410
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
401411
}
402412

413+
/*
414+
* Extract the parameters for the public key
415+
*/
416+
int x509_note_params(void *context, size_t hdrlen,
417+
unsigned char tag,
418+
const void *value, size_t vlen)
419+
{
420+
struct x509_parse_context *ctx = context;
421+
422+
/*
423+
* AlgorithmIdentifier is used three times in the x509, we should skip
424+
* first and ignore third, using second one which is after subject and
425+
* before subjectPublicKey.
426+
*/
427+
if (!ctx->cert->raw_subject || ctx->key)
428+
return 0;
429+
ctx->params = value - hdrlen;
430+
ctx->params_size = vlen + hdrlen;
431+
return 0;
432+
}
433+
403434
/*
404435
* Extract the data for the public key algorithm
405436
*/

crypto/testmgr.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2585,6 +2585,12 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
25852585
return err;
25862586
}
25872587

2588+
static u8 *test_pack_u32(u8 *dst, u32 val)
2589+
{
2590+
memcpy(dst, &val, sizeof(val));
2591+
return dst + sizeof(val);
2592+
}
2593+
25882594
static int test_akcipher_one(struct crypto_akcipher *tfm,
25892595
const struct akcipher_testvec *vecs)
25902596
{
@@ -2599,6 +2605,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
25992605
const char *m, *c;
26002606
unsigned int m_size, c_size;
26012607
const char *op;
2608+
u8 *key, *ptr;
26022609

26032610
if (testmgr_alloc_buf(xbuf))
26042611
return err;
@@ -2609,12 +2616,20 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
26092616

26102617
crypto_init_wait(&wait);
26112618

2619+
key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len,
2620+
GFP_KERNEL);
2621+
if (!key)
2622+
goto free_xbuf;
2623+
memcpy(key, vecs->key, vecs->key_len);
2624+
ptr = key + vecs->key_len;
2625+
ptr = test_pack_u32(ptr, vecs->algo);
2626+
ptr = test_pack_u32(ptr, vecs->param_len);
2627+
memcpy(ptr, vecs->params, vecs->param_len);
2628+
26122629
if (vecs->public_key_vec)
2613-
err = crypto_akcipher_set_pub_key(tfm, vecs->key,
2614-
vecs->key_len);
2630+
err = crypto_akcipher_set_pub_key(tfm, key, vecs->key_len);
26152631
else
2616-
err = crypto_akcipher_set_priv_key(tfm, vecs->key,
2617-
vecs->key_len);
2632+
err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len);
26182633
if (err)
26192634
goto free_req;
26202635

@@ -2744,6 +2759,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
27442759
kfree(outbuf_enc);
27452760
free_req:
27462761
akcipher_request_free(req);
2762+
kfree(key);
27472763
free_xbuf:
27482764
testmgr_free_buf(xbuf);
27492765
return err;

crypto/testmgr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#ifndef _CRYPTO_TESTMGR_H
2626
#define _CRYPTO_TESTMGR_H
2727

28+
#include <linux/oid_registry.h>
29+
2830
#define MAX_IVLEN 32
2931

3032
/*
@@ -135,13 +137,16 @@ struct drbg_testvec {
135137

136138
struct akcipher_testvec {
137139
const unsigned char *key;
140+
const unsigned char *params;
138141
const unsigned char *m;
139142
const unsigned char *c;
140143
unsigned int key_len;
144+
unsigned int param_len;
141145
unsigned int m_size;
142146
unsigned int c_size;
143147
bool public_key_vec;
144148
bool siggen_sigver_test;
149+
enum OID algo;
145150
};
146151

147152
struct kpp_testvec {

include/crypto/akcipher.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ struct crypto_akcipher {
7474
* operation
7575
* @set_pub_key: Function invokes the algorithm specific set public key
7676
* function, which knows how to decode and interpret
77-
* the BER encoded public key
77+
* the BER encoded public key and parameters
7878
* @set_priv_key: Function invokes the algorithm specific set private key
7979
* function, which knows how to decode and interpret
80-
* the BER encoded private key
80+
* the BER encoded private key and parameters
8181
* @max_size: Function returns dest buffer size required for a given key.
8282
* @init: Initialize the cryptographic transformation object.
8383
* This function is used to initialize the cryptographic
@@ -379,11 +379,12 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
379379
* crypto_akcipher_set_pub_key() - Invoke set public key operation
380380
*
381381
* Function invokes the algorithm specific set key function, which knows
382-
* how to decode and interpret the encoded key
382+
* how to decode and interpret the encoded key and parameters
383383
*
384384
* @tfm: tfm handle
385-
* @key: BER encoded public key
386-
* @keylen: length of the key
385+
* @key: BER encoded public key, algo OID, paramlen, BER encoded
386+
* parameters
387+
* @keylen: length of the key (not including other data)
387388
*
388389
* Return: zero on success; error code in case of error
389390
*/
@@ -400,11 +401,12 @@ static inline int crypto_akcipher_set_pub_key(struct crypto_akcipher *tfm,
400401
* crypto_akcipher_set_priv_key() - Invoke set private key operation
401402
*
402403
* Function invokes the algorithm specific set key function, which knows
403-
* how to decode and interpret the encoded key
404+
* how to decode and interpret the encoded key and parameters
404405
*
405406
* @tfm: tfm handle
406-
* @key: BER encoded private key
407-
* @keylen: length of the key
407+
* @key: BER encoded private key, algo OID, paramlen, BER encoded
408+
* parameters
409+
* @keylen: length of the key (not including other data)
408410
*
409411
* Return: zero on success; error code in case of error
410412
*/

include/crypto/public_key.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define _LINUX_PUBLIC_KEY_H
1616

1717
#include <linux/keyctl.h>
18+
#include <linux/oid_registry.h>
1819

1920
/*
2021
* Cryptographic data for the public-key subtype of the asymmetric key type.
@@ -25,6 +26,9 @@
2526
struct public_key {
2627
void *key;
2728
u32 keylen;
29+
enum OID algo;
30+
void *params;
31+
u32 paramlen;
2832
bool key_is_private;
2933
const char *id_type;
3034
const char *pkey_algo;

0 commit comments

Comments
 (0)