2019-05-20 19:08:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-09-21 23:24:55 +01:00
/* In-software asymmetric public-key crypto subtype
*
2020-06-15 08:50:08 +02:00
* See Documentation / crypto / asymmetric - keys . rst
2012-09-21 23:24:55 +01:00
*
* Copyright ( C ) 2012 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*/
# define pr_fmt(fmt) "PKEY: "fmt
2023-06-15 18:28:55 +08:00
# include <crypto/akcipher.h>
# include <crypto/public_key.h>
# include <crypto/sig.h>
# include <keys/asymmetric-subtype.h>
# include <linux/asn1.h>
# include <linux/err.h>
2012-09-21 23:24:55 +01:00
# include <linux/kernel.h>
2023-06-15 18:28:55 +08:00
# include <linux/module.h>
2012-09-21 23:24:55 +01:00
# include <linux/seq_file.h>
2023-06-15 18:28:55 +08:00
# include <linux/slab.h>
# include <linux/string.h>
2012-09-21 23:24:55 +01:00
2017-11-15 16:38:45 +00:00
MODULE_DESCRIPTION ( " In-software asymmetric public-key subtype " ) ;
MODULE_AUTHOR ( " Red Hat, Inc. " ) ;
2012-09-21 23:24:55 +01:00
MODULE_LICENSE ( " GPL " ) ;
/*
* Provide a part of a description of the key for / proc / keys .
*/
static void public_key_describe ( const struct key * asymmetric_key ,
struct seq_file * m )
{
2015-10-21 14:04:48 +01:00
struct public_key * key = asymmetric_key - > payload . data [ asym_crypto ] ;
2012-09-21 23:24:55 +01:00
if ( key )
2016-03-03 21:49:27 +00:00
seq_printf ( m , " %s.%s " , key - > id_type , key - > pkey_algo ) ;
2012-09-21 23:24:55 +01:00
}
/*
* Destroy a public key algorithm key .
*/
2016-04-06 16:13:33 +01:00
void public_key_free ( struct public_key * key )
2012-09-21 23:24:55 +01:00
{
2016-04-06 16:13:33 +01:00
if ( key ) {
2023-07-17 12:55:09 +00:00
kfree_sensitive ( key - > key ) ;
2019-04-11 18:51:17 +03:00
kfree ( key - > params ) ;
2016-04-06 16:13:33 +01:00
kfree ( key ) ;
}
}
EXPORT_SYMBOL_GPL ( public_key_free ) ;
/*
* Destroy a public key algorithm key .
*/
static void public_key_destroy ( void * payload0 , void * payload3 )
{
public_key_free ( payload0 ) ;
public_key_signature_free ( payload3 ) ;
2012-09-21 23:24:55 +01:00
}
2018-10-09 17:47:23 +01:00
/*
2022-02-07 21:24:48 -08:00
* Given a public_key , and an encoding and hash_algo to be used for signing
* and / or verification with that key , determine the name of the corresponding
* akcipher algorithm . Also check that encoding and hash_algo are allowed .
2018-10-09 17:47:23 +01:00
*/
2022-02-07 21:24:48 -08:00
static int
software_key_determine_akcipher ( const struct public_key * pkey ,
const char * encoding , const char * hash_algo ,
2023-06-15 18:28:55 +08:00
char alg_name [ CRYPTO_MAX_ALG_NAME ] , bool * sig ,
enum kernel_pkey_operation op )
2018-10-09 17:47:23 +01:00
{
int n ;
2023-06-15 18:28:55 +08:00
* sig = true ;
2022-02-07 21:24:48 -08:00
if ( ! encoding )
return - EINVAL ;
if ( strcmp ( pkey - > pkey_algo , " rsa " ) = = 0 ) {
/*
* RSA signatures usually use EMSA - PKCS1 - 1 _5 [ RFC3447 sec 8.2 ] .
*/
if ( strcmp ( encoding , " pkcs1 " ) = = 0 ) {
2023-10-16 16:35:36 +08:00
* sig = op = = kernel_pkey_sign | |
op = = kernel_pkey_verify ;
2023-06-15 18:28:55 +08:00
if ( ! hash_algo ) {
2022-02-07 21:24:48 -08:00
n = snprintf ( alg_name , CRYPTO_MAX_ALG_NAME ,
" pkcs1pad(%s) " ,
pkey - > pkey_algo ) ;
2023-06-15 18:28:55 +08:00
} else {
2022-02-07 21:24:48 -08:00
n = snprintf ( alg_name , CRYPTO_MAX_ALG_NAME ,
" pkcs1pad(%s,%s) " ,
pkey - > pkey_algo , hash_algo ) ;
2023-06-15 18:28:55 +08:00
}
2022-02-07 21:24:48 -08:00
return n > = CRYPTO_MAX_ALG_NAME ? - EINVAL : 0 ;
}
if ( strcmp ( encoding , " raw " ) ! = 0 )
return - EINVAL ;
/*
* Raw RSA cannot differentiate between different hash
* algorithms .
*/
if ( hash_algo )
return - EINVAL ;
2023-06-15 18:28:55 +08:00
* sig = false ;
2022-02-07 21:24:48 -08:00
} else if ( strncmp ( pkey - > pkey_algo , " ecdsa " , 5 ) = = 0 ) {
if ( strcmp ( encoding , " x962 " ) ! = 0 )
return - EINVAL ;
/*
* ECDSA signatures are taken over a raw hash , so they don ' t
* differentiate between different hash algorithms . That means
* that the verifier should hard - code a specific hash algorithm .
* Unfortunately , in practice ECDSA is used with multiple SHAs ,
* so we have to allow all of them and not just one .
2018-10-09 17:47:23 +01:00
*/
if ( ! hash_algo )
2022-02-07 21:24:48 -08:00
return - EINVAL ;
2024-03-13 16:32:27 -07:00
if ( strcmp ( hash_algo , " sha1 " ) ! = 0 & &
strcmp ( hash_algo , " sha224 " ) ! = 0 & &
2022-02-07 21:24:48 -08:00
strcmp ( hash_algo , " sha256 " ) ! = 0 & &
strcmp ( hash_algo , " sha384 " ) ! = 0 & &
2023-10-22 19:22:06 +01:00
strcmp ( hash_algo , " sha512 " ) ! = 0 & &
strcmp ( hash_algo , " sha3-256 " ) ! = 0 & &
strcmp ( hash_algo , " sha3-384 " ) ! = 0 & &
strcmp ( hash_algo , " sha3-512 " ) ! = 0 )
2022-02-07 21:24:48 -08:00
return - EINVAL ;
} else if ( strcmp ( pkey - > pkey_algo , " sm2 " ) = = 0 ) {
if ( strcmp ( encoding , " raw " ) ! = 0 )
return - EINVAL ;
if ( ! hash_algo )
return - EINVAL ;
if ( strcmp ( hash_algo , " sm3 " ) ! = 0 )
return - EINVAL ;
} else if ( strcmp ( pkey - > pkey_algo , " ecrdsa " ) = = 0 ) {
if ( strcmp ( encoding , " raw " ) ! = 0 )
return - EINVAL ;
if ( ! hash_algo )
return - EINVAL ;
if ( strcmp ( hash_algo , " streebog256 " ) ! = 0 & &
strcmp ( hash_algo , " streebog512 " ) ! = 0 )
return - EINVAL ;
} else {
/* Unknown public key algorithm */
return - ENOPKG ;
2018-10-09 17:47:23 +01:00
}
2022-02-07 21:24:48 -08:00
if ( strscpy ( alg_name , pkey - > pkey_algo , CRYPTO_MAX_ALG_NAME ) < 0 )
return - EINVAL ;
return 0 ;
2018-10-09 17:47:23 +01:00
}
2019-04-11 18:51:17 +03:00
static u8 * pkey_pack_u32 ( u8 * dst , u32 val )
{
memcpy ( dst , & val , sizeof ( val ) ) ;
return dst + sizeof ( val ) ;
}
2018-10-09 17:47:23 +01:00
/*
* Query information about a key .
*/
static int software_key_query ( const struct kernel_pkey_params * params ,
struct kernel_pkey_query * info )
{
struct crypto_akcipher * tfm ;
struct public_key * pkey = params - > key - > payload . data [ asym_crypto ] ;
char alg_name [ CRYPTO_MAX_ALG_NAME ] ;
2023-06-15 18:28:55 +08:00
struct crypto_sig * sig ;
2019-04-11 18:51:17 +03:00
u8 * key , * ptr ;
2018-10-09 17:47:23 +01:00
int ret , len ;
2023-06-15 18:28:55 +08:00
bool issig ;
2018-10-09 17:47:23 +01:00
2022-02-07 21:24:48 -08:00
ret = software_key_determine_akcipher ( pkey , params - > encoding ,
2023-06-15 18:28:55 +08:00
params - > hash_algo , alg_name ,
& issig , kernel_pkey_sign ) ;
2018-10-09 17:47:23 +01:00
if ( ret < 0 )
return ret ;
2019-04-11 18:51:17 +03:00
key = kmalloc ( pkey - > keylen + sizeof ( u32 ) * 2 + pkey - > paramlen ,
GFP_KERNEL ) ;
if ( ! key )
2023-06-15 18:28:55 +08:00
return - ENOMEM ;
2019-04-11 18:51:17 +03:00
memcpy ( key , pkey - > key , pkey - > keylen ) ;
ptr = key + pkey - > keylen ;
ptr = pkey_pack_u32 ( ptr , pkey - > algo ) ;
ptr = pkey_pack_u32 ( ptr , pkey - > paramlen ) ;
memcpy ( ptr , pkey - > params , pkey - > paramlen ) ;
2023-06-15 18:28:55 +08:00
if ( issig ) {
sig = crypto_alloc_sig ( alg_name , 0 , 0 ) ;
2023-07-03 17:18:08 +03:00
if ( IS_ERR ( sig ) ) {
ret = PTR_ERR ( sig ) ;
2023-06-15 18:28:55 +08:00
goto error_free_key ;
2023-07-03 17:18:08 +03:00
}
2023-06-15 18:28:55 +08:00
if ( pkey - > key_is_private )
ret = crypto_sig_set_privkey ( sig , key , pkey - > keylen ) ;
else
ret = crypto_sig_set_pubkey ( sig , key , pkey - > keylen ) ;
if ( ret < 0 )
goto error_free_tfm ;
len = crypto_sig_maxsize ( sig ) ;
info - > supported_ops = KEYCTL_SUPPORTS_VERIFY ;
if ( pkey - > key_is_private )
info - > supported_ops | = KEYCTL_SUPPORTS_SIGN ;
if ( strcmp ( params - > encoding , " pkcs1 " ) = = 0 ) {
info - > supported_ops | = KEYCTL_SUPPORTS_ENCRYPT ;
if ( pkey - > key_is_private )
info - > supported_ops | = KEYCTL_SUPPORTS_DECRYPT ;
}
} else {
tfm = crypto_alloc_akcipher ( alg_name , 0 , 0 ) ;
2023-07-03 17:18:08 +03:00
if ( IS_ERR ( tfm ) ) {
ret = PTR_ERR ( tfm ) ;
2023-06-15 18:28:55 +08:00
goto error_free_key ;
2023-07-03 17:18:08 +03:00
}
2023-06-15 18:28:55 +08:00
if ( pkey - > key_is_private )
ret = crypto_akcipher_set_priv_key ( tfm , key , pkey - > keylen ) ;
else
ret = crypto_akcipher_set_pub_key ( tfm , key , pkey - > keylen ) ;
if ( ret < 0 )
goto error_free_tfm ;
len = crypto_akcipher_maxsize ( tfm ) ;
info - > supported_ops = KEYCTL_SUPPORTS_ENCRYPT ;
if ( pkey - > key_is_private )
info - > supported_ops | = KEYCTL_SUPPORTS_DECRYPT ;
}
2018-10-09 17:47:23 +01:00
info - > key_size = len * 8 ;
2022-08-26 09:51:19 -05:00
if ( strncmp ( pkey - > pkey_algo , " ecdsa " , 5 ) = = 0 ) {
/*
* ECDSA key sizes are much smaller than RSA , and thus could
* operate on ( hashed ) inputs that are larger than key size .
* For example SHA384 - hashed input used with secp256r1
* based keys . Set max_data_size to be at least as large as
* the largest supported hash size ( SHA512 )
*/
info - > max_data_size = 64 ;
/*
* Verify takes ECDSA - Sig ( described in RFC 5480 ) as input ,
* which is actually 2 ' key_size ' - bit integers encoded in
* ASN .1 . Account for the ASN .1 encoding overhead here .
*/
info - > max_sig_size = 2 * ( len + 3 ) + 2 ;
} else {
info - > max_data_size = len ;
info - > max_sig_size = len ;
}
2018-10-09 17:47:23 +01:00
info - > max_enc_size = len ;
info - > max_dec_size = len ;
2023-06-15 18:28:55 +08:00
2018-10-09 17:47:23 +01:00
ret = 0 ;
2023-06-15 18:28:55 +08:00
error_free_tfm :
if ( issig )
crypto_free_sig ( sig ) ;
else
crypto_free_akcipher ( tfm ) ;
2019-04-11 18:51:17 +03:00
error_free_key :
2023-07-17 12:55:09 +00:00
kfree_sensitive ( key ) ;
2018-10-09 17:47:23 +01:00
pr_devel ( " <==%s() = %d \n " , __func__ , ret ) ;
return ret ;
}
2018-10-09 17:47:38 +01:00
/*
* Do encryption , decryption and signing ops .
*/
static int software_key_eds_op ( struct kernel_pkey_params * params ,
const void * in , void * out )
{
const struct public_key * pkey = params - > key - > payload . data [ asym_crypto ] ;
char alg_name [ CRYPTO_MAX_ALG_NAME ] ;
2023-06-15 18:28:55 +08:00
struct crypto_akcipher * tfm ;
struct crypto_sig * sig ;
2019-04-11 18:51:17 +03:00
char * key , * ptr ;
2023-06-15 18:28:55 +08:00
bool issig ;
int ksz ;
2018-10-09 17:47:38 +01:00
int ret ;
pr_devel ( " ==>%s() \n " , __func__ ) ;
2022-02-07 21:24:48 -08:00
ret = software_key_determine_akcipher ( pkey , params - > encoding ,
2023-06-15 18:28:55 +08:00
params - > hash_algo , alg_name ,
& issig , params - > op ) ;
2018-10-09 17:47:38 +01:00
if ( ret < 0 )
return ret ;
2019-04-11 18:51:17 +03:00
key = kmalloc ( pkey - > keylen + sizeof ( u32 ) * 2 + pkey - > paramlen ,
GFP_KERNEL ) ;
if ( ! key )
2023-06-15 18:28:55 +08:00
return - ENOMEM ;
2019-04-11 18:51:17 +03:00
memcpy ( key , pkey - > key , pkey - > keylen ) ;
ptr = key + pkey - > keylen ;
ptr = pkey_pack_u32 ( ptr , pkey - > algo ) ;
ptr = pkey_pack_u32 ( ptr , pkey - > paramlen ) ;
memcpy ( ptr , pkey - > params , pkey - > paramlen ) ;
2023-06-15 18:28:55 +08:00
if ( issig ) {
sig = crypto_alloc_sig ( alg_name , 0 , 0 ) ;
2023-07-03 17:18:08 +03:00
if ( IS_ERR ( sig ) ) {
ret = PTR_ERR ( sig ) ;
2023-06-15 18:28:55 +08:00
goto error_free_key ;
2023-07-03 17:18:08 +03:00
}
2023-06-15 18:28:55 +08:00
if ( pkey - > key_is_private )
ret = crypto_sig_set_privkey ( sig , key , pkey - > keylen ) ;
else
ret = crypto_sig_set_pubkey ( sig , key , pkey - > keylen ) ;
if ( ret )
goto error_free_tfm ;
ksz = crypto_sig_maxsize ( sig ) ;
} else {
tfm = crypto_alloc_akcipher ( alg_name , 0 , 0 ) ;
2023-07-03 17:18:08 +03:00
if ( IS_ERR ( tfm ) ) {
ret = PTR_ERR ( tfm ) ;
2023-06-15 18:28:55 +08:00
goto error_free_key ;
2023-07-03 17:18:08 +03:00
}
2023-06-15 18:28:55 +08:00
if ( pkey - > key_is_private )
ret = crypto_akcipher_set_priv_key ( tfm , key , pkey - > keylen ) ;
else
ret = crypto_akcipher_set_pub_key ( tfm , key , pkey - > keylen ) ;
if ( ret )
goto error_free_tfm ;
ksz = crypto_akcipher_maxsize ( tfm ) ;
}
2018-10-09 17:47:38 +01:00
2023-06-15 18:28:55 +08:00
ret = - EINVAL ;
2018-10-09 17:47:38 +01:00
/* Perform the encryption calculation. */
switch ( params - > op ) {
case kernel_pkey_encrypt :
2023-06-15 18:28:55 +08:00
if ( issig )
break ;
ret = crypto_akcipher_sync_encrypt ( tfm , in , params - > in_len ,
out , params - > out_len ) ;
2018-10-09 17:47:38 +01:00
break ;
case kernel_pkey_decrypt :
2023-06-15 18:28:55 +08:00
if ( issig )
break ;
ret = crypto_akcipher_sync_decrypt ( tfm , in , params - > in_len ,
out , params - > out_len ) ;
2018-10-09 17:47:38 +01:00
break ;
case kernel_pkey_sign :
2023-06-15 18:28:55 +08:00
if ( ! issig )
break ;
ret = crypto_sig_sign ( sig , in , params - > in_len ,
out , params - > out_len ) ;
2018-10-09 17:47:38 +01:00
break ;
default :
BUG ( ) ;
}
if ( ret = = 0 )
2023-06-15 18:28:55 +08:00
ret = ksz ;
2018-10-09 17:47:38 +01:00
2023-06-15 18:28:55 +08:00
error_free_tfm :
if ( issig )
crypto_free_sig ( sig ) ;
else
crypto_free_akcipher ( tfm ) ;
2019-04-11 18:51:17 +03:00
error_free_key :
2023-07-17 12:55:09 +00:00
kfree_sensitive ( key ) ;
2018-10-09 17:47:38 +01:00
pr_devel ( " <==%s() = %d \n " , __func__ , ret ) ;
return ret ;
}
2012-09-21 23:24:55 +01:00
/*
* Verify a signature using a public key .
*/
2016-02-02 10:08:53 -08:00
int public_key_verify_signature ( const struct public_key * pkey ,
2013-08-30 16:15:30 +01:00
const struct public_key_signature * sig )
2012-09-21 23:24:55 +01:00
{
2018-10-09 17:47:23 +01:00
char alg_name [ CRYPTO_MAX_ALG_NAME ] ;
2023-06-15 18:28:55 +08:00
struct crypto_sig * tfm ;
2019-04-11 18:51:17 +03:00
char * key , * ptr ;
2023-06-15 18:28:55 +08:00
bool issig ;
2017-12-08 15:13:29 +00:00
int ret ;
2016-03-03 21:49:27 +00:00
pr_devel ( " ==>%s() \n " , __func__ ) ;
2016-02-02 10:08:53 -08:00
BUG_ON ( ! pkey ) ;
2013-08-30 16:15:30 +01:00
BUG_ON ( ! sig ) ;
2016-02-02 10:08:53 -08:00
BUG_ON ( ! sig - > s ) ;
2012-09-21 23:24:55 +01:00
2022-02-07 21:24:47 -08:00
/*
* If the signature specifies a public key algorithm , it * must * match
* the key ' s actual public key algorithm .
*
* Small exception : ECDSA signatures don ' t specify the curve , but ECDSA
* keys do . So the strings can mismatch slightly in that case :
* " ecdsa-nist-* " for the key , but " ecdsa " for the signature .
*/
if ( sig - > pkey_algo ) {
if ( strcmp ( pkey - > pkey_algo , sig - > pkey_algo ) ! = 0 & &
( strncmp ( pkey - > pkey_algo , " ecdsa- " , 6 ) ! = 0 | |
strcmp ( sig - > pkey_algo , " ecdsa " ) ! = 0 ) )
return - EKEYREJECTED ;
}
2022-02-07 21:24:48 -08:00
ret = software_key_determine_akcipher ( pkey , sig - > encoding ,
2023-06-15 18:28:55 +08:00
sig - > hash_algo , alg_name ,
& issig , kernel_pkey_verify ) ;
2018-10-09 17:47:23 +01:00
if ( ret < 0 )
return ret ;
2016-03-03 21:49:27 +00:00
2023-06-15 18:28:55 +08:00
tfm = crypto_alloc_sig ( alg_name , 0 , 0 ) ;
2016-03-03 21:49:27 +00:00
if ( IS_ERR ( tfm ) )
return PTR_ERR ( tfm ) ;
2019-04-11 18:51:17 +03:00
key = kmalloc ( pkey - > keylen + sizeof ( u32 ) * 2 + pkey - > paramlen ,
GFP_KERNEL ) ;
2023-07-03 17:18:08 +03:00
if ( ! key ) {
ret = - ENOMEM ;
2023-06-15 18:28:55 +08:00
goto error_free_tfm ;
2023-07-03 17:18:08 +03:00
}
2019-04-11 18:51:17 +03:00
memcpy ( key , pkey - > key , pkey - > keylen ) ;
ptr = key + pkey - > keylen ;
ptr = pkey_pack_u32 ( ptr , pkey - > algo ) ;
ptr = pkey_pack_u32 ( ptr , pkey - > paramlen ) ;
memcpy ( ptr , pkey - > params , pkey - > paramlen ) ;
2018-10-09 17:47:31 +01:00
if ( pkey - > key_is_private )
2023-06-15 18:28:55 +08:00
ret = crypto_sig_set_privkey ( tfm , key , pkey - > keylen ) ;
2018-10-09 17:47:31 +01:00
else
2023-06-15 18:28:55 +08:00
ret = crypto_sig_set_pubkey ( tfm , key , pkey - > keylen ) ;
2016-03-03 21:49:27 +00:00
if ( ret )
2019-04-11 18:51:17 +03:00
goto error_free_key ;
2016-03-03 21:49:27 +00:00
2023-06-15 18:28:55 +08:00
ret = crypto_sig_verify ( tfm , sig - > s , sig - > s_size ,
sig - > digest , sig - > digest_size ) ;
2012-09-21 23:24:55 +01:00
2019-04-11 18:51:17 +03:00
error_free_key :
2023-07-17 12:55:09 +00:00
kfree_sensitive ( key ) ;
2016-03-03 21:49:27 +00:00
error_free_tfm :
2023-06-15 18:28:55 +08:00
crypto_free_sig ( tfm ) ;
2016-03-03 21:49:27 +00:00
pr_devel ( " <==%s() = %d \n " , __func__ , ret ) ;
2017-12-08 15:13:29 +00:00
if ( WARN_ON_ONCE ( ret > 0 ) )
ret = - EINVAL ;
2016-03-03 21:49:27 +00:00
return ret ;
2013-08-30 16:15:30 +01:00
}
EXPORT_SYMBOL_GPL ( public_key_verify_signature ) ;
static int public_key_verify_signature_2 ( const struct key * key ,
const struct public_key_signature * sig )
{
2015-10-21 14:04:48 +01:00
const struct public_key * pk = key - > payload . data [ asym_crypto ] ;
2013-08-30 16:15:30 +01:00
return public_key_verify_signature ( pk , sig ) ;
2012-09-21 23:24:55 +01:00
}
/*
* Public key algorithm asymmetric key subtype
*/
struct asymmetric_key_subtype public_key_subtype = {
. owner = THIS_MODULE ,
. name = " public_key " ,
2014-09-02 13:52:10 +01:00
. name_len = sizeof ( " public_key " ) - 1 ,
2012-09-21 23:24:55 +01:00
. describe = public_key_describe ,
. destroy = public_key_destroy ,
2018-10-09 17:47:23 +01:00
. query = software_key_query ,
2018-10-09 17:47:38 +01:00
. eds_op = software_key_eds_op ,
2013-08-30 16:15:30 +01:00
. verify_signature = public_key_verify_signature_2 ,
2012-09-21 23:24:55 +01:00
} ;
EXPORT_SYMBOL_GPL ( public_key_subtype ) ;