Commit baa888d2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-keys2' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull keys updates from James Morris:
 "Provide five new operations in the key_type struct that can be used to
  provide access to asymmetric key operations. These will be implemented
  for the asymmetric key type in a later patch and may refer to a key
  retained in RAM by the kernel or a key retained in crypto hardware.

     int (*asym_query)(const struct kernel_pkey_params *params,
                       struct kernel_pkey_query *info);
     int (*asym_eds_op)(struct kernel_pkey_params *params,
                        const void *in, void *out);
     int (*asym_verify_signature)(struct kernel_pkey_params *params,
                                  const void *in, const void *in2);

  Since encrypt, decrypt and sign are identical in their interfaces,
  they're rolled together in the asym_eds_op() operation and there's an
  operation ID in the params argument to distinguish them.

  Verify is different in that we supply the data and the signature
  instead and get an error value (or 0) as the only result on the
  expectation that this may well be how a hardware crypto device may
  work"

* 'next-keys2' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (22 commits)
  KEYS: asym_tpm: Add support for the sign operation [ver #2]
  KEYS: asym_tpm: Implement tpm_sign [ver #2]
  KEYS: asym_tpm: Implement signature verification [ver #2]
  KEYS: asym_tpm: Implement the decrypt operation [ver #2]
  KEYS: asym_tpm: Implement tpm_unbind [ver #2]
  KEYS: asym_tpm: Add loadkey2 and flushspecific [ver #2]
  KEYS: Move trusted.h to include/keys [ver #2]
  KEYS: trusted: Expose common functionality [ver #2]
  KEYS: asym_tpm: Implement encryption operation [ver #2]
  KEYS: asym_tpm: Implement pkey_query [ver #2]
  KEYS: Add parser for TPM-based keys [ver #2]
  KEYS: asym_tpm: extract key size & public key [ver #2]
  KEYS: asym_tpm: add skeleton for asym_tpm [ver #2]
  crypto: rsa-pkcs1pad: Allow hash to be optional [ver #2]
  KEYS: Implement PKCS#8 RSA Private Key parser [ver #2]
  KEYS: Implement encrypt, decrypt and sign for software asymmetric key [ver #2]
  KEYS: Allow the public_key struct to hold a private key [ver #2]
  KEYS: Provide software public key query function [ver #2]
  KEYS: Make the X.509 and PKCS7 parsers supply the sig encoding type [ver #2]
  KEYS: Provide missing asymmetric key subops for new key type ops [ver #2]
  ...
parents 7260935d 64ae16df
...@@ -183,6 +183,10 @@ and looks like the following: ...@@ -183,6 +183,10 @@ and looks like the following:
void (*describe)(const struct key *key, struct seq_file *m); void (*describe)(const struct key *key, struct seq_file *m);
void (*destroy)(void *payload); void (*destroy)(void *payload);
int (*query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
int (*eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
int (*verify_signature)(const struct key *key, int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig); const struct public_key_signature *sig);
}; };
...@@ -207,12 +211,22 @@ There are a number of operations defined by the subtype: ...@@ -207,12 +211,22 @@ There are a number of operations defined by the subtype:
asymmetric key will look after freeing the fingerprint and releasing the asymmetric key will look after freeing the fingerprint and releasing the
reference on the subtype module. reference on the subtype module.
(3) verify_signature(). (3) query().
Optional. These are the entry points for the key usage operations. Mandatory. This is a function for querying the capabilities of a key.
Currently there is only the one defined. If not set, the caller will be
given -ENOTSUPP. The subtype may do anything it likes to implement an (4) eds_op().
operation, including offloading to hardware.
Optional. This is the entry point for the encryption, decryption and
signature creation operations (which are distinguished by the operation ID
in the parameter struct). The subtype may do anything it likes to
implement an operation, including offloading to hardware.
(5) verify_signature().
Optional. This is the entry point for signature verification. The
subtype may do anything it likes to implement an operation, including
offloading to hardware.
========================== ==========================
...@@ -234,6 +248,8 @@ Examples of blob formats for which parsers could be implemented include: ...@@ -234,6 +248,8 @@ Examples of blob formats for which parsers could be implemented include:
- X.509 ASN.1 stream. - X.509 ASN.1 stream.
- Pointer to TPM key. - Pointer to TPM key.
- Pointer to UEFI key. - Pointer to UEFI key.
- PKCS#8 private key [RFC 5208].
- PKCS#5 encrypted private key [RFC 2898].
During key instantiation each parser in the list is tried until one doesn't During key instantiation each parser in the list is tried until one doesn't
return -EBADMSG. return -EBADMSG.
......
...@@ -859,6 +859,7 @@ The keyctl syscall functions are: ...@@ -859,6 +859,7 @@ The keyctl syscall functions are:
and either the buffer length or the OtherInfo length exceeds the and either the buffer length or the OtherInfo length exceeds the
allowed length. allowed length.
* Restrict keyring linkage:: * Restrict keyring linkage::
long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring, long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring,
...@@ -890,6 +891,116 @@ The keyctl syscall functions are: ...@@ -890,6 +891,116 @@ The keyctl syscall functions are:
applicable to the asymmetric key type. applicable to the asymmetric key type.
* Query an asymmetric key::
long keyctl(KEYCTL_PKEY_QUERY,
key_serial_t key_id, unsigned long reserved,
struct keyctl_pkey_query *info);
Get information about an asymmetric key. The information is returned in
the keyctl_pkey_query struct::
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
__u32 __spare[10];
``supported_ops`` contains a bit mask of flags indicating which ops are
supported. This is constructed from a bitwise-OR of::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
``key_size`` indicated the size of the key in bits.
``max_*_size`` indicate the maximum sizes in bytes of a blob of data to be
signed, a signature blob, a blob to be encrypted and a blob to be
decrypted.
``__spare[]`` must be set to 0. This is intended for future use to hand
over one or more passphrases needed unlock a key.
If successful, 0 is returned. If the key is not an asymmetric key,
EOPNOTSUPP is returned.
* Encrypt, decrypt, sign or verify a blob using an asymmetric key::
long keyctl(KEYCTL_PKEY_ENCRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_DECRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_SIGN,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_VERIFY,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
const void *in2);
Use an asymmetric key to perform a public-key cryptographic operation a
blob of data. For encryption and verification, the asymmetric key may
only need the public parts to be available, but for decryption and signing
the private parts are required also.
The parameter block pointed to by params contains a number of integer
values::
__s32 key_id;
__u32 in_len;
__u32 out_len;
__u32 in2_len;
``key_id`` is the ID of the asymmetric key to be used. ``in_len`` and
``in2_len`` indicate the amount of data in the in and in2 buffers and
``out_len`` indicates the size of the out buffer as appropriate for the
above operations.
For a given operation, the in and out buffers are used as follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
KEYCTL_PKEY_ENCRYPT Raw data Encrypted data -
KEYCTL_PKEY_DECRYPT Encrypted data Raw data -
KEYCTL_PKEY_SIGN Raw data Signature -
KEYCTL_PKEY_VERIFY Raw data - Signature
``info`` is a string of key=value pairs that supply supplementary
information. These include:
``enc=<encoding>`` The encoding of the encrypted/signature blob. This
can be "pkcs1" for RSASSA-PKCS1-v1.5 or
RSAES-PKCS1-v1.5; "pss" for "RSASSA-PSS"; "oaep" for
"RSAES-OAEP". If omitted or is "raw", the raw output
of the encryption function is specified.
``hash=<algo>`` If the data buffer contains the output of a hash
function and the encoding includes some indication of
which hash function was used, the hash function can be
specified with this, eg. "hash=sha256".
The ``__spare[]`` space in the parameter block must be set to 0. This is
intended, amongst other things, to allow the passing of passphrases
required to unlock a key.
If successful, encrypt, decrypt and sign all return the amount of data
written into the output buffer. Verification returns 0 on success.
Kernel Services Kernel Services
=============== ===============
...@@ -1483,6 +1594,112 @@ The structure has a number of fields, some of which are mandatory: ...@@ -1483,6 +1594,112 @@ The structure has a number of fields, some of which are mandatory:
attempted key link operation. If there is no match, -EINVAL is returned. attempted key link operation. If there is no match, -EINVAL is returned.
* ``int (*asym_eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);``
``int (*asym_verify_signature)(struct kernel_pkey_params *params,
const void *in, const void *in2);``
These methods are optional. If provided the first allows a key to be
used to encrypt, decrypt or sign a blob of data, and the second allows a
key to verify a signature.
In all cases, the following information is provided in the params block::
struct kernel_pkey_params {
struct key *key;
const char *encoding;
const char *hash_algo;
char *info;
__u32 in_len;
union {
__u32 out_len;
__u32 in2_len;
};
enum kernel_pkey_operation op : 8;
};
This includes the key to be used; a string indicating the encoding to use
(for instance, "pkcs1" may be used with an RSA key to indicate
RSASSA-PKCS1-v1.5 or RSAES-PKCS1-v1.5 encoding or "raw" if no encoding);
the name of the hash algorithm used to generate the data for a signature
(if appropriate); the sizes of the input and output (or second input)
buffers; and the ID of the operation to be performed.
For a given operation ID, the input and output buffers are used as
follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
kernel_pkey_encrypt Raw data Encrypted data -
kernel_pkey_decrypt Encrypted data Raw data -
kernel_pkey_sign Raw data Signature -
kernel_pkey_verify Raw data - Signature
asym_eds_op() deals with encryption, decryption and signature creation as
specified by params->op. Note that params->op is also set for
asym_verify_signature().
Encrypting and signature creation both take raw data in the input buffer
and return the encrypted result in the output buffer. Padding may have
been added if an encoding was set. In the case of signature creation,
depending on the encoding, the padding created may need to indicate the
digest algorithm - the name of which should be supplied in hash_algo.
Decryption takes encrypted data in the input buffer and returns the raw
data in the output buffer. Padding will get checked and stripped off if
an encoding was set.
Verification takes raw data in the input buffer and the signature in the
second input buffer and checks that the one matches the other. Padding
will be validated. Depending on the encoding, the digest algorithm used
to generate the raw data may need to be indicated in hash_algo.
If successful, asym_eds_op() should return the number of bytes written
into the output buffer. asym_verify_signature() should return 0.
A variety of errors may be returned, including EOPNOTSUPP if the operation
is not supported; EKEYREJECTED if verification fails; ENOPKG if the
required crypto isn't available.
* ``int (*asym_query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);``
This method is optional. If provided it allows information about the
public or asymmetric key held in the key to be determined.
The parameter block is as for asym_eds_op() and co. but in_len and out_len
are unused. The encoding and hash_algo fields should be used to reduce
the returned buffer/data sizes as appropriate.
If successful, the following information is filled in::
struct kernel_pkey_query {
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
};
The supported_ops field will contain a bitmask indicating what operations
are supported by the key, including encryption of a blob, decryption of a
blob, signing a blob and verifying the signature on a blob. The following
constants are defined for this::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
The key_size field is the size of the key in bits. max_data_size and
max_sig_size are the maximum raw data and signature sizes for creation and
verification of a signature; max_enc_size and max_dec_size are the maximum
raw data and signature sizes for encryption and decryption. The
max_*_size fields are measured in bytes.
If successful, 0 will be returned. If the key doesn't support this,
EOPNOTSUPP will be returned.
Request-Key Callback Service Request-Key Callback Service
============================ ============================
......
...@@ -21,6 +21,18 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE ...@@ -21,6 +21,18 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
appropriate hash algorithms (such as SHA-1) must be available. appropriate hash algorithms (such as SHA-1) must be available.
ENOPKG will be reported if the requisite algorithm is unavailable. ENOPKG will be reported if the requisite algorithm is unavailable.
config ASYMMETRIC_TPM_KEY_SUBTYPE
tristate "Asymmetric TPM backed private key subtype"
depends on TCG_TPM
depends on TRUSTED_KEYS
select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_HASH_INFO
help
This option provides support for TPM backed private key type handling.
Operations such as sign, verify, encrypt, decrypt are performed by
the TPM after the private key is loaded.
config X509_CERTIFICATE_PARSER config X509_CERTIFICATE_PARSER
tristate "X.509 certificate parser" tristate "X.509 certificate parser"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
...@@ -31,6 +43,25 @@ config X509_CERTIFICATE_PARSER ...@@ -31,6 +43,25 @@ config X509_CERTIFICATE_PARSER
data and provides the ability to instantiate a crypto key from a data and provides the ability to instantiate a crypto key from a
public key packet found inside the certificate. public key packet found inside the certificate.
config PKCS8_PRIVATE_KEY_PARSER
tristate "PKCS#8 private key parser"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select ASN1
select OID_REGISTRY
help
This option provides support for parsing PKCS#8 format blobs for
private key data and provides the ability to instantiate a crypto key
from that data.
config TPM_KEY_PARSER
tristate "TPM private key parser"
depends on ASYMMETRIC_TPM_KEY_SUBTYPE
select ASN1
help
This option provides support for parsing TPM format blobs for
private key data and provides the ability to instantiate a crypto key
from that data.
config PKCS7_MESSAGE_PARSER config PKCS7_MESSAGE_PARSER
tristate "PKCS#7 message parser" tristate "PKCS#7 message parser"
depends on X509_CERTIFICATE_PARSER depends on X509_CERTIFICATE_PARSER
......
...@@ -11,6 +11,7 @@ asymmetric_keys-y := \ ...@@ -11,6 +11,7 @@ asymmetric_keys-y := \
signature.o signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
obj-$(CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE) += asym_tpm.o
# #
# X.509 Certificate handling # X.509 Certificate handling
...@@ -29,6 +30,19 @@ $(obj)/x509_cert_parser.o: \ ...@@ -29,6 +30,19 @@ $(obj)/x509_cert_parser.o: \
$(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h $(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h
$(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h $(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h
#
# PKCS#8 private key handling
#
obj-$(CONFIG_PKCS8_PRIVATE_KEY_PARSER) += pkcs8_key_parser.o
pkcs8_key_parser-y := \
pkcs8.asn1.o \
pkcs8_parser.o
$(obj)/pkcs8_parser.o: $(obj)/pkcs8.asn1.h
$(obj)/pkcs8-asn1.o: $(obj)/pkcs8.asn1.c $(obj)/pkcs8.asn1.h
clean-files += pkcs8.asn1.c pkcs8.asn1.h
# #
# PKCS#7 message handling # PKCS#7 message handling
# #
...@@ -61,3 +75,14 @@ verify_signed_pefile-y := \ ...@@ -61,3 +75,14 @@ verify_signed_pefile-y := \
$(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h
$(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h
#
# TPM private key parsing
#
obj-$(CONFIG_TPM_KEY_PARSER) += tpm_key_parser.o
tpm_key_parser-y := \
tpm.asn1.o \
tpm_parser.o
$(obj)/tpm_parser.o: $(obj)/tpm.asn1.h
$(obj)/tpm.asn1.o: $(obj)/tpm.asn1.c $(obj)/tpm.asn1.h
This diff is collapsed.
...@@ -16,3 +16,6 @@ extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); ...@@ -16,3 +16,6 @@ extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
extern int __asymmetric_key_hex_to_key_id(const char *id, extern int __asymmetric_key_hex_to_key_id(const char *id,
struct asymmetric_key_id *match_id, struct asymmetric_key_id *match_id,
size_t hexlen); size_t hexlen);
extern int asymmetric_key_eds_op(struct kernel_pkey_params *params,
const void *in, void *out);
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <keys/system_keyring.h> #include <keys/system_keyring.h>
#include <keys/user-type.h>
#include "asymmetric_keys.h" #include "asymmetric_keys.h"
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -538,6 +539,45 @@ static struct key_restriction *asymmetric_lookup_restriction( ...@@ -538,6 +539,45 @@ static struct key_restriction *asymmetric_lookup_restriction(
return ret; return ret;
} }
int asymmetric_key_eds_op(struct kernel_pkey_params *params,
const void *in, void *out)
{
const struct asymmetric_key_subtype *subtype;
struct key *key = params->key;
int ret;
pr_devel("==>%s()\n", __func__);
if (key->type != &key_type_asymmetric)
return -EINVAL;
subtype = asymmetric_key_subtype(key);
if (!subtype ||
!key->payload.data[0])
return -EINVAL;
if (!subtype->eds_op)
return -ENOTSUPP;
ret = subtype->eds_op(params, in, out);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
const void *in, const void *in2)
{
struct public_key_signature sig = {
.s_size = params->in2_len,
.digest_size = params->in_len,
.encoding = params->encoding,
.hash_algo = params->hash_algo,
.digest = (void *)in,
.s = (void *)in2,
};
return verify_signature(params->key, &sig);
}
struct key_type key_type_asymmetric = { struct key_type key_type_asymmetric = {
.name = "asymmetric", .name = "asymmetric",
.preparse = asymmetric_key_preparse, .preparse = asymmetric_key_preparse,
...@@ -548,6 +588,9 @@ struct key_type key_type_asymmetric = { ...@@ -548,6 +588,9 @@ struct key_type key_type_asymmetric = {
.destroy = asymmetric_key_destroy, .destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe, .describe = asymmetric_key_describe,
.lookup_restriction = asymmetric_lookup_restriction, .lookup_restriction = asymmetric_lookup_restriction,
.asym_query = query_asymmetric_key,
.asym_eds_op = asymmetric_key_eds_op,
.asym_verify_signature = asymmetric_key_verify_signature,
}; };
EXPORT_SYMBOL_GPL(key_type_asymmetric); EXPORT_SYMBOL_GPL(key_type_asymmetric);
......
...@@ -271,6 +271,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, ...@@ -271,6 +271,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) { switch (ctx->last_oid) {
case OID_rsaEncryption: case OID_rsaEncryption:
ctx->sinfo->sig->pkey_algo = "rsa"; ctx->sinfo->sig->pkey_algo = "rsa";
ctx->sinfo->sig->encoding = "pkcs1";
break; break;
default: default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid); printk("Unsupported pkey algo: %u\n", ctx->last_oid);
......
--
-- This is the unencrypted variant
--
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL
}
Version ::= INTEGER ({ pkcs8_note_version })
PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier ({ pkcs8_note_algo })
PrivateKey ::= OCTET STRING ({ pkcs8_note_key })
Attributes ::= SET OF Attribute
Attribute ::= ANY
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ pkcs8_note_OID }),
parameters ANY OPTIONAL
}
/* PKCS#8 Private Key parser [RFC 5208].
*
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKCS8: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <crypto/public_key.h>
#include "pkcs8.asn1.h"
struct pkcs8_parse_context {
struct public_key *pub;
unsigned long data; /* Start of data */
enum OID last_oid; /* Last OID encountered */
enum OID algo_oid; /* Algorithm OID */
u32 key_size;
const void *key;
};
/*
* Note an OID when we find one for later processing when we know how to
* interpret it.
*/
int pkcs8_note_OID(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pkcs8_parse_context *ctx = context;
ctx->last_oid = look_up_OID(value, vlen);
if (ctx->last_oid == OID__NR) {
char buffer[50];
sprint_oid(value, vlen, buffer, sizeof(buffer));
pr_info("Unknown OID: [%lu] %s\n",
(unsigned long)value - ctx->data, buffer);
}
return 0;
}
/*
* Note the version number of the ASN.1 blob.
*/
int pkcs8_note_version(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
if (vlen != 1 || ((const u8 *)value)[0] != 0) {
pr_warn("Unsupported PKCS#8 version\n");
return -EBADMSG;
}
return 0;
}
/*
* Note the public algorithm.
*/
int pkcs8_note_algo(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pkcs8_parse_context *ctx = context;
if (ctx->last_oid != OID_rsaEncryption)
return -ENOPKG;
ctx->pub->pkey_algo = "rsa";
return 0;
}
/*
* Note the key data of the ASN.1 blob.
*/
int pkcs8_note_key(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pkcs8_parse_context *ctx = context;
ctx->key = value;
ctx->key_size = vlen;
return 0;
}
/*
* Parse a PKCS#8 private key blob.
*/
static struct public_key *pkcs8_parse(const void *data, size_t datalen)
{
struct pkcs8_parse_context ctx;
struct public_key *pub;
long ret;
memset(&ctx, 0, sizeof(ctx));
ret = -ENOMEM;
ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
if (!ctx.pub)
goto error;
ctx.data = (unsigned long)data;
/* Attempt to decode the private key */
ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen);
if (ret < 0)
goto error_decode;
ret = -ENOMEM;
pub = ctx.pub;
pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL);
if (!pub->key)
goto error_decode;
pub->keylen = ctx.key_size;
pub->key_is_private = true;
return pub;
error_decode:
kfree(ctx.pub);
error:
return ERR_PTR(ret);
}
/*
* Attempt to parse a data blob for a key as a PKCS#8 private key.
*/
static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
{
struct public_key *pub;
pub = pkcs8_parse(prep->data, prep->datalen);
if (IS_ERR(pub))
return PTR_ERR(pub);
pr_devel("Cert Key Algo: %s\n", pub->pkey_algo);
pub->id_type = "PKCS8";
/* We're pinning the module by being linked against it */
__module_get(public_key_subtype.owner);
prep->payload.data[asym_subtype] = &public_key_subtype;
prep->payload.data[asym_key_ids] = NULL;
prep->payload.data[asym_crypto] = pub;
prep->payload.data[asym_auth] = NULL;
prep->quotalen = 100;
return 0;
}
static struct asymmetric_key_parser pkcs8_key_parser = {
.owner = THIS_MODULE,
.name = "pkcs8",
.parse = pkcs8_key_preparse,
};
/*
* Module stuff
*/
static int __init pkcs8_key_init(void)
{
return register_asymmetric_key_parser(&pkcs8_key_parser);
}
static void __exit pkcs8_key_exit(void)
{
unregister_asymmetric_key_parser(&pkcs8_key_parser);
}
module_init(pkcs8_key_init);
module_exit(pkcs8_key_exit);
MODULE_DESCRIPTION("PKCS#8 certificate parser");
MODULE_LICENSE("GPL");
...@@ -59,6 +59,165 @@ static void public_key_destroy(void *payload0, void *payload3) ...@@ -59,6 +59,165 @@ static void public_key_destroy(void *payload0, void *payload3)
public_key_signature_free(payload3); public_key_signature_free(payload3);
} }
/*
* Determine the crypto algorithm name.
*/
static
int software_key_determine_akcipher(const char *encoding,
const char *hash_algo,
const struct public_key *pkey,
char alg_name[CRYPTO_MAX_ALG_NAME])
{
int n;
if (strcmp(encoding, "pkcs1") == 0) {
/* The data wangled by the RSA algorithm is typically padded
* and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
* sec 8.2].
*/
if (!hash_algo)
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(%s)",
pkey->pkey_algo);
else
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(%s,%s)",
pkey->pkey_algo, hash_algo);
return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
}
if (strcmp(encoding, "raw") == 0) {
strcpy(alg_name, pkey->pkey_algo);
return 0;
}
return -ENOPKG;
}
/*
* 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];
int ret, len;
ret = software_key_determine_akcipher(params->encoding,
params->hash_algo,
pkey, alg_name);
if (ret < 0)
return ret;
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
if (pkey->key_is_private)
ret = crypto_akcipher_set_priv_key(tfm,
pkey->key, pkey->keylen);
else
ret = crypto_akcipher_set_pub_key(tfm,
pkey->key, pkey->keylen);
if (ret < 0)
goto error_free_tfm;
len = crypto_akcipher_maxsize(tfm);
info->key_size = len * 8;
info->max_data_size = len;
info->max_sig_size = len;
info->max_enc_size = len;
info->max_dec_size = len;
info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT |
KEYCTL_SUPPORTS_VERIFY);
if (pkey->key_is_private)
info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT |
KEYCTL_SUPPORTS_SIGN);
ret = 0;
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* 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];
struct akcipher_request *req;
struct crypto_akcipher *tfm;
struct crypto_wait cwait;
struct scatterlist in_sg, out_sg;
char alg_name[CRYPTO_MAX_ALG_NAME];
int ret;
pr_devel("==>%s()\n", __func__);
ret = software_key_determine_akcipher(params->encoding,
params->hash_algo,
pkey, alg_name);
if (ret < 0)
return ret;
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
req = akcipher_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto error_free_tfm;
if (pkey->key_is_private)
ret = crypto_akcipher_set_priv_key(tfm,
pkey->key, pkey->keylen);
else
ret = crypto_akcipher_set_pub_key(tfm,
pkey->key, pkey->keylen);
if (ret)
goto error_free_req;
sg_init_one(&in_sg, in, params->in_len);
sg_init_one(&out_sg, out, params->out_len);
akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len,
params->out_len);
crypto_init_wait(&cwait);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait);
/* Perform the encryption calculation. */
switch (params->op) {
case kernel_pkey_encrypt:
ret = crypto_akcipher_encrypt(req);
break;
case kernel_pkey_decrypt:
ret = crypto_akcipher_decrypt(req);
break;
case kernel_pkey_sign:
ret = crypto_akcipher_sign(req);
break;
default:
BUG();
}
ret = crypto_wait_req(ret, &cwait);
if (ret == 0)
ret = req->dst_len;
error_free_req:
akcipher_request_free(req);
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/* /*
* Verify a signature using a public key. * Verify a signature using a public key.
*/ */
...@@ -69,8 +228,7 @@ int public_key_verify_signature(const struct public_key *pkey, ...@@ -69,8 +228,7 @@ int public_key_verify_signature(const struct public_key *pkey,
struct crypto_akcipher *tfm; struct crypto_akcipher *tfm;
struct akcipher_request *req; struct akcipher_request *req;
struct scatterlist sig_sg, digest_sg; struct scatterlist sig_sg, digest_sg;
const char *alg_name; char alg_name[CRYPTO_MAX_ALG_NAME];
char alg_name_buf[CRYPTO_MAX_ALG_NAME];
void *output; void *output;
unsigned int outlen; unsigned int outlen;
int ret; int ret;
...@@ -81,21 +239,11 @@ int public_key_verify_signature(const struct public_key *pkey, ...@@ -81,21 +239,11 @@ int public_key_verify_signature(const struct public_key *pkey,
BUG_ON(!sig); BUG_ON(!sig);
BUG_ON(!sig->s); BUG_ON(!sig->s);
if (!sig->digest) ret = software_key_determine_akcipher(sig->encoding,
return -ENOPKG; sig->hash_algo,
pkey, alg_name);
alg_name = sig->pkey_algo; if (ret < 0)
if (strcmp(sig->pkey_algo, "rsa") == 0) { return ret;
/* The data wangled by the RSA algorithm is typically padded
* and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
* sec 8.2].
*/
if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(rsa,%s)", sig->hash_algo
) >= CRYPTO_MAX_ALG_NAME)
return -EINVAL;
alg_name = alg_name_buf;
}
tfm = crypto_alloc_akcipher(alg_name, 0, 0); tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm)) if (IS_ERR(tfm))
...@@ -106,7 +254,12 @@ int public_key_verify_signature(const struct public_key *pkey, ...@@ -106,7 +254,12 @@ int public_key_verify_signature(const struct public_key *pkey,
if (!req) if (!req)
goto error_free_tfm; goto error_free_tfm;
ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen); if (pkey->key_is_private)
ret = crypto_akcipher_set_priv_key(tfm,
pkey->key, pkey->keylen);
else
ret = crypto_akcipher_set_pub_key(tfm,
pkey->key, pkey->keylen);
if (ret) if (ret)
goto error_free_req; goto error_free_req;
...@@ -167,6 +320,8 @@ struct asymmetric_key_subtype public_key_subtype = { ...@@ -167,6 +320,8 @@ struct asymmetric_key_subtype public_key_subtype = {
.name_len = sizeof("public_key") - 1, .name_len = sizeof("public_key") - 1,
.describe = public_key_describe, .describe = public_key_describe,
.destroy = public_key_destroy, .destroy = public_key_destroy,
.query = software_key_query,
.eds_op = software_key_eds_op,
.verify_signature = public_key_verify_signature_2, .verify_signature = public_key_verify_signature_2,
}; };
EXPORT_SYMBOL_GPL(public_key_subtype); EXPORT_SYMBOL_GPL(public_key_subtype);
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/keyctl.h>
#include <crypto/public_key.h> #include <crypto/public_key.h>
#include <keys/user-type.h>
#include "asymmetric_keys.h" #include "asymmetric_keys.h"
/* /*
...@@ -36,6 +38,99 @@ void public_key_signature_free(struct public_key_signature *sig) ...@@ -36,6 +38,99 @@ void public_key_signature_free(struct public_key_signature *sig)
} }
EXPORT_SYMBOL_GPL(public_key_signature_free); EXPORT_SYMBOL_GPL(public_key_signature_free);
/**
* query_asymmetric_key - Get information about an aymmetric key.
* @params: Various parameters.
* @info: Where to put the information.
*/
int query_asymmetric_key(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info)
{
const struct asymmetric_key_subtype *subtype;
struct key *key = params->key;
int ret;
pr_devel("==>%s()\n", __func__);
if (key->type != &key_type_asymmetric)
return -EINVAL;
subtype = asymmetric_key_subtype(key);
if (!subtype ||
!key->payload.data[0])
return -EINVAL;
if (!subtype->query)
return -ENOTSUPP;
ret = subtype->query(params, info);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL_GPL(query_asymmetric_key);
/**
* encrypt_blob - Encrypt data using an asymmetric key
* @params: Various parameters
* @data: Data blob to be encrypted, length params->data_len
* @enc: Encrypted data buffer, length params->enc_len
*
* Encrypt the specified data blob using the private key specified by
* params->key. The encrypted data is wrapped in an encoding if
* params->encoding is specified (eg. "pkcs1").
*
* Returns the length of the data placed in the encrypted data buffer or an
* error.
*/
int encrypt_blob(struct kernel_pkey_params *params,
const void *data, void *enc)
{
params->op = kernel_pkey_encrypt;
return asymmetric_key_eds_op(params, data, enc);
}
EXPORT_SYMBOL_GPL(encrypt_blob);
/**
* decrypt_blob - Decrypt data using an asymmetric key
* @params: Various parameters
* @enc: Encrypted data to be decrypted, length params->enc_len
* @data: Decrypted data buffer, length params->data_len
*
* Decrypt the specified data blob using the private key specified by
* params->key. The decrypted data is wrapped in an encoding if
* params->encoding is specified (eg. "pkcs1").
*
* Returns the length of the data placed in the decrypted data buffer or an
* error.
*/
int decrypt_blob(struct kernel_pkey_params *params,
const void *enc, void *data)
{
params->op = kernel_pkey_decrypt;
return asymmetric_key_eds_op(params, enc, data);
}
EXPORT_SYMBOL_GPL(decrypt_blob);
/**
* create_signature - Sign some data using an asymmetric key
* @params: Various parameters
* @data: Data blob to be signed, length params->data_len
* @enc: Signature buffer, length params->enc_len
*
* Sign the specified data blob using the private key specified by params->key.
* The signature is wrapped in an encoding if params->encoding is specified
* (eg. "pkcs1"). If the encoding needs to know the digest type, this can be
* passed through params->hash_algo (eg. "sha1").
*
* Returns the length of the data placed in the signature buffer or an error.
*/
int create_signature(struct kernel_pkey_params *params,
const void *data, void *enc)
{
params->op = kernel_pkey_sign;
return asymmetric_key_eds_op(params, data, enc);
}
EXPORT_SYMBOL_GPL(create_signature);
/** /**
* verify_signature - Initiate the use of an asymmetric key to verify a signature * verify_signature - Initiate the use of an asymmetric key to verify a signature
* @key: The asymmetric key to verify against * @key: The asymmetric key to verify against
......
--
-- Unencryted TPM Blob. For details of the format, see:
-- http://david.woodhou.se/draft-woodhouse-cert-best-practice.html#I-D.mavrogiannopoulos-tpmuri
--
PrivateKeyInfo ::= OCTET STRING ({ tpm_note_key })
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) "TPM-PARSER: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <crypto/asym_tpm_subtype.h>
#include "tpm.asn1.h"
struct tpm_parse_context {
const void *blob;
u32 blob_len;
};
/*
* Note the key data of the ASN.1 blob.
*/
int tpm_note_key(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct tpm_parse_context *ctx = context;
ctx->blob = value;
ctx->blob_len = vlen;
return 0;
}
/*
* Parse a TPM-encrypted private key blob.
*/
static struct tpm_key *tpm_parse(const void *data, size_t datalen)
{
struct tpm_parse_context ctx;
long ret;
memset(&ctx, 0, sizeof(ctx));
/* Attempt to decode the private key */
ret = asn1_ber_decoder(&tpm_decoder, &ctx, data, datalen);
if (ret < 0)
goto error;
return tpm_key_create(ctx.blob, ctx.blob_len);
error:
return ERR_PTR(ret);
}
/*
* Attempt to parse a data blob for a key as a TPM private key blob.
*/
static int tpm_key_preparse(struct key_preparsed_payload *prep)
{
struct tpm_key *tk;
/*
* TPM 1.2 keys are max 2048 bits long, so assume the blob is no
* more than 4x that
*/
if (prep->datalen > 256 * 4)
return -EMSGSIZE;
tk = tpm_parse(prep->data, prep->datalen);
if (IS_ERR(tk))
return PTR_ERR(tk);
/* We're pinning the module by being linked against it */
__module_get(asym_tpm_subtype.owner);
prep->payload.data[asym_subtype] = &asym_tpm_subtype;
prep->payload.data[asym_key_ids] = NULL;
prep->payload.data[asym_crypto] = tk;
prep->payload.data[asym_auth] = NULL;
prep->quotalen = 100;
return 0;
}
static struct asymmetric_key_parser tpm_key_parser = {
.owner = THIS_MODULE,
.name = "tpm_parser",
.parse = tpm_key_preparse,
};
static int __init tpm_key_init(void)
{
return register_asymmetric_key_parser(&tpm_key_parser);
}
static void __exit tpm_key_exit(void)
{
unregister_asymmetric_key_parser(&tpm_key_parser);
}
module_init(tpm_key_init);
module_exit(tpm_key_exit);
MODULE_DESCRIPTION("TPM private key-blob parser");
MODULE_LICENSE("GPL v2");
...@@ -199,35 +199,32 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, ...@@ -199,35 +199,32 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
case OID_md4WithRSAEncryption: case OID_md4WithRSAEncryption:
ctx->cert->sig->hash_algo = "md4"; ctx->cert->sig->hash_algo = "md4";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
case OID_sha1WithRSAEncryption: case OID_sha1WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha1"; ctx->cert->sig->hash_algo = "sha1";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
case OID_sha256WithRSAEncryption: case OID_sha256WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha256"; ctx->cert->sig->hash_algo = "sha256";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
case OID_sha384WithRSAEncryption: case OID_sha384WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha384"; ctx->cert->sig->hash_algo = "sha384";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
case OID_sha512WithRSAEncryption: case OID_sha512WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha512"; ctx->cert->sig->hash_algo = "sha512";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
case OID_sha224WithRSAEncryption: case OID_sha224WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha224"; ctx->cert->sig->hash_algo = "sha224";
ctx->cert->sig->pkey_algo = "rsa"; goto rsa_pkcs1;
break;
} }
rsa_pkcs1:
ctx->cert->sig->pkey_algo = "rsa";
ctx->cert->sig->encoding = "pkcs1";
ctx->algo_oid = ctx->last_oid; ctx->algo_oid = ctx->last_oid;
return 0; return 0;
} }
......
...@@ -392,7 +392,8 @@ static int pkcs1pad_sign(struct akcipher_request *req) ...@@ -392,7 +392,8 @@ static int pkcs1pad_sign(struct akcipher_request *req)
if (!ctx->key_size) if (!ctx->key_size)
return -EINVAL; return -EINVAL;
digest_size = digest_info->size; if (digest_info)
digest_size = digest_info->size;
if (req->src_len + digest_size > ctx->key_size - 11) if (req->src_len + digest_size > ctx->key_size - 11)
return -EOVERFLOW; return -EOVERFLOW;
...@@ -412,8 +413,9 @@ static int pkcs1pad_sign(struct akcipher_request *req) ...@@ -412,8 +413,9 @@ static int pkcs1pad_sign(struct akcipher_request *req)
memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); memset(req_ctx->in_buf + 1, 0xff, ps_end - 1);
req_ctx->in_buf[ps_end] = 0x00; req_ctx->in_buf[ps_end] = 0x00;
memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data, if (digest_info)
digest_info->size); memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data,
digest_info->size);
pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf,
ctx->key_size - 1 - req->src_len, req->src); ctx->key_size - 1 - req->src_len, req->src);
...@@ -475,10 +477,13 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) ...@@ -475,10 +477,13 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
goto done; goto done;
pos++; pos++;
if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) if (digest_info) {
goto done; if (crypto_memneq(out_buf + pos, digest_info->data,
digest_info->size))
goto done;
pos += digest_info->size; pos += digest_info->size;
}
err = 0; err = 0;
...@@ -608,11 +613,14 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) ...@@ -608,11 +613,14 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
hash_name = crypto_attr_alg_name(tb[2]); hash_name = crypto_attr_alg_name(tb[2]);
if (IS_ERR(hash_name)) if (IS_ERR(hash_name))
return PTR_ERR(hash_name); hash_name = NULL;
digest_info = rsa_lookup_asn1(hash_name); if (hash_name) {
if (!digest_info) digest_info = rsa_lookup_asn1(hash_name);
return -EINVAL; if (!digest_info)
return -EINVAL;
} else
digest_info = NULL;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
if (!inst) if (!inst)
...@@ -632,14 +640,29 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) ...@@ -632,14 +640,29 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
err = -ENAMETOOLONG; err = -ENAMETOOLONG;
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, if (!hash_name) {
"pkcs1pad(%s,%s)", rsa_alg->base.cra_name, hash_name) >= if (snprintf(inst->alg.base.cra_name,
CRYPTO_MAX_ALG_NAME || CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
"pkcs1pad(%s,%s)", goto out_drop_alg;
rsa_alg->base.cra_driver_name, hash_name) >=
CRYPTO_MAX_ALG_NAME) if (snprintf(inst->alg.base.cra_driver_name,
goto out_drop_alg; CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
rsa_alg->base.cra_driver_name) >=
CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
} else {
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(%s,%s)", rsa_alg->base.cra_name,
hash_name) >= CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
if (snprintf(inst->alg.base.cra_driver_name,
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
rsa_alg->base.cra_driver_name,
hash_name) >= CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
}
inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC; inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC;
inst->alg.base.cra_priority = rsa_alg->base.cra_priority; inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
......
// SPDX-License-Identifier: GPL-2.0
#ifndef _LINUX_ASYM_TPM_SUBTYPE_H
#define _LINUX_ASYM_TPM_SUBTYPE_H
#include <linux/keyctl.h>
struct tpm_key {
void *blob;
u32 blob_len;
uint16_t key_len; /* Size in bits of the key */
const void *pub_key; /* pointer inside blob to the public key bytes */
uint16_t pub_key_len; /* length of the public key */
};
struct tpm_key *tpm_key_create(const void *blob, uint32_t blob_len);
extern struct asymmetric_key_subtype asym_tpm_subtype;
#endif /* _LINUX_ASYM_TPM_SUBTYPE_H */
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#ifndef _LINUX_PUBLIC_KEY_H #ifndef _LINUX_PUBLIC_KEY_H
#define _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H
#include <linux/keyctl.h>
/* /*
* Cryptographic data for the public-key subtype of the asymmetric key type. * Cryptographic data for the public-key subtype of the asymmetric key type.
* *
...@@ -23,6 +25,7 @@ ...@@ -23,6 +25,7 @@
struct public_key { struct public_key {
void *key; void *key;
u32 keylen; u32 keylen;
bool key_is_private;
const char *id_type; const char *id_type;
const char *pkey_algo; const char *pkey_algo;
}; };
...@@ -40,6 +43,7 @@ struct public_key_signature { ...@@ -40,6 +43,7 @@ struct public_key_signature {
u8 digest_size; /* Number of bytes in digest */ u8 digest_size; /* Number of bytes in digest */
const char *pkey_algo; const char *pkey_algo;
const char *hash_algo; const char *hash_algo;
const char *encoding;
}; };
extern void public_key_signature_free(struct public_key_signature *sig); extern void public_key_signature_free(struct public_key_signature *sig);
...@@ -65,8 +69,14 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, ...@@ -65,8 +69,14 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
const union key_payload *payload, const union key_payload *payload,
struct key *trusted); struct key *trusted);
extern int verify_signature(const struct key *key, extern int query_asymmetric_key(const struct kernel_pkey_params *,
const struct public_key_signature *sig); struct kernel_pkey_query *);
extern int encrypt_blob(struct kernel_pkey_params *, const void *, void *);
extern int decrypt_blob(struct kernel_pkey_params *, const void *, void *);
extern int create_signature(struct kernel_pkey_params *, const void *, void *);
extern int verify_signature(const struct key *,
const struct public_key_signature *);
int public_key_verify_signature(const struct public_key *pkey, int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig); const struct public_key_signature *sig);
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <keys/asymmetric-type.h> #include <keys/asymmetric-type.h>
struct kernel_pkey_query;
struct kernel_pkey_params;
struct public_key_signature; struct public_key_signature;
/* /*
...@@ -34,6 +36,13 @@ struct asymmetric_key_subtype { ...@@ -34,6 +36,13 @@ struct asymmetric_key_subtype {
/* Destroy a key of this subtype */ /* Destroy a key of this subtype */
void (*destroy)(void *payload_crypto, void *payload_auth); void (*destroy)(void *payload_crypto, void *payload_auth);
int (*query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
/* Encrypt/decrypt/sign data */
int (*eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
/* Verify the signature on a key of this subtype (optional) */ /* Verify the signature on a key of this subtype (optional) */
int (*verify_signature)(const struct key *key, int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig); const struct public_key_signature *sig);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#define __TRUSTED_KEY_H #define __TRUSTED_KEY_H
/* implementation specific TPM constants */ /* implementation specific TPM constants */
#define MAX_BUF_SIZE 512 #define MAX_BUF_SIZE 1024
#define TPM_GETRANDOM_SIZE 14 #define TPM_GETRANDOM_SIZE 14
#define TPM_OSAP_SIZE 36 #define TPM_OSAP_SIZE 36
#define TPM_OIAP_SIZE 10 #define TPM_OIAP_SIZE 10
...@@ -36,6 +36,18 @@ enum { ...@@ -36,6 +36,18 @@ enum {
SRK_keytype = 4 SRK_keytype = 4
}; };
int TSS_authhmac(unsigned char *digest, const unsigned char *key,
unsigned int keylen, unsigned char *h1,
unsigned char *h2, unsigned char h3, ...);
int TSS_checkhmac1(unsigned char *buffer,
const uint32_t command,
const unsigned char *ononce,
const unsigned char *key,
unsigned int keylen, ...);
int trusted_tpm_send(unsigned char *cmd, size_t buflen);
int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce);
#define TPM_DEBUG 0 #define TPM_DEBUG 0
#if TPM_DEBUG #if TPM_DEBUG
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
struct kernel_pkey_query;
struct kernel_pkey_params;
/* /*
* key under-construction record * key under-construction record
* - passed to the request_key actor if supplied * - passed to the request_key actor if supplied
...@@ -155,6 +158,14 @@ struct key_type { ...@@ -155,6 +158,14 @@ struct key_type {
*/ */
struct key_restriction *(*lookup_restriction)(const char *params); struct key_restriction *(*lookup_restriction)(const char *params);
/* Asymmetric key accessor functions. */
int (*asym_query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
int (*asym_eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
int (*asym_verify_signature)(struct kernel_pkey_params *params,
const void *in, const void *in2);
/* internal fields */ /* internal fields */
struct list_head link; /* link in types list */ struct list_head link; /* link in types list */
struct lock_class_key lock_class; /* key->sem lock class */ struct lock_class_key lock_class; /* key->sem lock class */
......
/* keyctl kernel bits
*
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef __LINUX_KEYCTL_H
#define __LINUX_KEYCTL_H
#include <uapi/linux/keyctl.h>
struct kernel_pkey_query {
__u32 supported_ops; /* Which ops are supported */
__u32 key_size; /* Size of the key in bits */
__u16 max_data_size; /* Maximum size of raw data to sign in bytes */
__u16 max_sig_size; /* Maximum size of signature in bytes */
__u16 max_enc_size; /* Maximum size of encrypted blob in bytes */
__u16 max_dec_size; /* Maximum size of decrypted blob in bytes */
};
enum kernel_pkey_operation {
kernel_pkey_encrypt,
kernel_pkey_decrypt,
kernel_pkey_sign,
kernel_pkey_verify,
};
struct kernel_pkey_params {
struct key *key;
const char *encoding; /* Encoding (eg. "oaep" or "raw" for none) */
const char *hash_algo; /* Digest algorithm used (eg. "sha1") or NULL if N/A */
char *info; /* Modified info string to be released later */
__u32 in_len; /* Input data size */
union {
__u32 out_len; /* Output buffer size (enc/dec/sign) */
__u32 in2_len; /* 2nd input data size (verify) */
};
enum kernel_pkey_operation op : 8;
};
#endif /* __LINUX_KEYCTL_H */
...@@ -61,6 +61,11 @@ ...@@ -61,6 +61,11 @@
#define KEYCTL_INVALIDATE 21 /* invalidate a key */ #define KEYCTL_INVALIDATE 21 /* invalidate a key */
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ #define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */
#define KEYCTL_PKEY_QUERY 24 /* Query public key parameters */
#define KEYCTL_PKEY_ENCRYPT 25 /* Encrypt a blob using a public key */
#define KEYCTL_PKEY_DECRYPT 26 /* Decrypt a blob using a public key */
#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */
#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */
#define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ #define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */
/* keyctl structures */ /* keyctl structures */
...@@ -82,4 +87,29 @@ struct keyctl_kdf_params { ...@@ -82,4 +87,29 @@ struct keyctl_kdf_params {
__u32 __spare[8]; __u32 __spare[8];
}; };
#define KEYCTL_SUPPORTS_ENCRYPT 0x01
#define KEYCTL_SUPPORTS_DECRYPT 0x02
#define KEYCTL_SUPPORTS_SIGN 0x04
#define KEYCTL_SUPPORTS_VERIFY 0x08
struct keyctl_pkey_query {
__u32 supported_ops; /* Which ops are supported */
__u32 key_size; /* Size of the key in bits */
__u16 max_data_size; /* Maximum size of raw data to sign in bytes */
__u16 max_sig_size; /* Maximum size of signature in bytes */
__u16 max_enc_size; /* Maximum size of encrypted blob in bytes */
__u16 max_dec_size; /* Maximum size of decrypted blob in bytes */
__u32 __spare[10];
};
struct keyctl_pkey_params {
__s32 key_id; /* Serial no. of public key to use */
__u32 in_len; /* Input data size */
union {
__u32 out_len; /* Output buffer size (encrypt/decrypt/sign) */
__u32 in2_len; /* 2nd input data size (verify) */
};
__u32 __spare[7];
};
#endif /* _LINUX_KEYCTL_H */ #endif /* _LINUX_KEYCTL_H */
...@@ -22,6 +22,7 @@ obj-$(CONFIG_PROC_FS) += proc.o ...@@ -22,6 +22,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o obj-$(CONFIG_SYSCTL) += sysctl.o
obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += keyctl_pkey.o
# #
# Key types # Key types
......
...@@ -141,6 +141,24 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, ...@@ -141,6 +141,24 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
return keyctl_restrict_keyring(arg2, compat_ptr(arg3), return keyctl_restrict_keyring(arg2, compat_ptr(arg3),
compat_ptr(arg4)); compat_ptr(arg4));
case KEYCTL_PKEY_QUERY:
if (arg3 != 0)
return -EINVAL;
return keyctl_pkey_query(arg2,
compat_ptr(arg4),
compat_ptr(arg5));
case KEYCTL_PKEY_ENCRYPT:
case KEYCTL_PKEY_DECRYPT:
case KEYCTL_PKEY_SIGN:
return keyctl_pkey_e_d_s(option,
compat_ptr(arg2), compat_ptr(arg3),
compat_ptr(arg4), compat_ptr(arg5));
case KEYCTL_PKEY_VERIFY:
return keyctl_pkey_verify(compat_ptr(arg2), compat_ptr(arg3),
compat_ptr(arg4), compat_ptr(arg5));
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -298,6 +298,45 @@ static inline long compat_keyctl_dh_compute( ...@@ -298,6 +298,45 @@ static inline long compat_keyctl_dh_compute(
#endif #endif
#endif #endif
#ifdef CONFIG_ASYMMETRIC_KEY_TYPE
extern long keyctl_pkey_query(key_serial_t,
const char __user *,
struct keyctl_pkey_query __user *);
extern long keyctl_pkey_verify(const struct keyctl_pkey_params __user *,
const char __user *,
const void __user *, const void __user *);
extern long keyctl_pkey_e_d_s(int,
const struct keyctl_pkey_params __user *,
const char __user *,
const void __user *, void __user *);
#else
static inline long keyctl_pkey_query(key_serial_t id,
const char __user *_info,
struct keyctl_pkey_query __user *_res)
{
return -EOPNOTSUPP;
}
static inline long keyctl_pkey_verify(const struct keyctl_pkey_params __user *params,
const char __user *_info,
const void __user *_in,
const void __user *_in2)
{
return -EOPNOTSUPP;
}
static inline long keyctl_pkey_e_d_s(int op,
const struct keyctl_pkey_params __user *params,
const char __user *_info,
const void __user *_in,
void __user *_out)
{
return -EOPNOTSUPP;
}
#endif
/* /*
* Debugging key validation * Debugging key validation
*/ */
......
...@@ -1747,6 +1747,30 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, ...@@ -1747,6 +1747,30 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
(const char __user *) arg3, (const char __user *) arg3,
(const char __user *) arg4); (const char __user *) arg4);
case KEYCTL_PKEY_QUERY:
if (arg3 != 0)
return -EINVAL;
return keyctl_pkey_query((key_serial_t)arg2,
(const char __user *)arg4,
(struct keyctl_pkey_query *)arg5);
case KEYCTL_PKEY_ENCRYPT:
case KEYCTL_PKEY_DECRYPT:
case KEYCTL_PKEY_SIGN:
return keyctl_pkey_e_d_s(
option,
(const struct keyctl_pkey_params __user *)arg2,
(const char __user *)arg3,
(const void __user *)arg4,
(void __user *)arg5);
case KEYCTL_PKEY_VERIFY:
return keyctl_pkey_verify(
(const struct keyctl_pkey_params __user *)arg2,
(const char __user *)arg3,
(const void __user *)arg4,
(const void __user *)arg5);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
/* Public-key operation keyctls
*
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/key.h>
#include <linux/keyctl.h>
#include <linux/parser.h>
#include <linux/uaccess.h>
#include <keys/user-type.h>
#include "internal.h"
static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
{
kfree(params->info);
key_put(params->key);
}
enum {
Opt_err = -1,
Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */
Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */
};
static const match_table_t param_keys = {
{ Opt_enc, "enc=%s" },
{ Opt_hash, "hash=%s" },
{ Opt_err, NULL }
};
/*
* Parse the information string which consists of key=val pairs.
*/
static int keyctl_pkey_params_parse(struct kernel_pkey_params *params)
{
unsigned long token_mask = 0;
substring_t args[MAX_OPT_ARGS];
char *c = params->info, *p, *q;
int token;
while ((p = strsep(&c, " \t"))) {
if (*p == '\0' || *p == ' ' || *p == '\t')
continue;
token = match_token(p, param_keys, args);
if (__test_and_set_bit(token, &token_mask))
return -EINVAL;
q = args[0].from;
if (!q[0])
return -EINVAL;
switch (token) {
case Opt_enc:
params->encoding = q;
break;
case Opt_hash:
params->hash_algo = q;
break;
default:
return -EINVAL;
}
}
return 0;
}
/*
* Interpret parameters. Callers must always call the free function
* on params, even if an error is returned.
*/
static int keyctl_pkey_params_get(key_serial_t id,
const char __user *_info,
struct kernel_pkey_params *params)
{
key_ref_t key_ref;
void *p;
int ret;
memset(params, 0, sizeof(*params));
params->encoding = "raw";
p = strndup_user(_info, PAGE_SIZE);
if (IS_ERR(p))
return PTR_ERR(p);
params->info = p;
ret = keyctl_pkey_params_parse(params);
if (ret < 0)
return ret;
key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
if (IS_ERR(key_ref))
return PTR_ERR(key_ref);
params->key = key_ref_to_ptr(key_ref);
if (!params->key->type->asym_query)
return -EOPNOTSUPP;
return 0;
}
/*
* Get parameters from userspace. Callers must always call the free function
* on params, even if an error is returned.
*/
static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_params,
const char __user *_info,
int op,
struct kernel_pkey_params *params)
{
struct keyctl_pkey_params uparams;
struct kernel_pkey_query info;
int ret;
memset(params, 0, sizeof(*params));
params->encoding = "raw";
if (copy_from_user(&uparams, _params, sizeof(uparams)) != 0)
return -EFAULT;
ret = keyctl_pkey_params_get(uparams.key_id, _info, params);
if (ret < 0)
return ret;
ret = params->key->type->asym_query(params, &info);
if (ret < 0)
return ret;
switch (op) {
case KEYCTL_PKEY_ENCRYPT:
case KEYCTL_PKEY_DECRYPT:
if (uparams.in_len > info.max_enc_size ||
uparams.out_len > info.max_dec_size)
return -EINVAL;
break;
case KEYCTL_PKEY_SIGN:
case KEYCTL_PKEY_VERIFY:
if (uparams.in_len > info.max_sig_size ||
uparams.out_len > info.max_data_size)
return -EINVAL;
break;
default:
BUG();
}
params->in_len = uparams.in_len;
params->out_len = uparams.out_len;
return 0;
}
/*
* Query information about an asymmetric key.
*/
long keyctl_pkey_query(key_serial_t id,
const char __user *_info,
struct keyctl_pkey_query __user *_res)
{
struct kernel_pkey_params params;
struct kernel_pkey_query res;
long ret;
memset(&params, 0, sizeof(params));
ret = keyctl_pkey_params_get(id, _info, &params);
if (ret < 0)
goto error;
ret = params.key->type->asym_query(&params, &res);
if (ret < 0)
goto error;
ret = -EFAULT;
if (copy_to_user(_res, &res, sizeof(res)) == 0 &&
clear_user(_res->__spare, sizeof(_res->__spare)) == 0)
ret = 0;
error:
keyctl_pkey_params_free(&params);
return ret;
}
/*
* Encrypt/decrypt/sign
*
* Encrypt data, decrypt data or sign data using a public key.
*
* _info is a string of supplementary information in key=val format. For
* instance, it might contain:
*
* "enc=pkcs1 hash=sha256"
*
* where enc= specifies the encoding and hash= selects the OID to go in that
* particular encoding if required. If enc= isn't supplied, it's assumed that
* the caller is supplying raw values.
*
* If successful, the amount of data written into the output buffer is
* returned.
*/
long keyctl_pkey_e_d_s(int op,
const struct keyctl_pkey_params __user *_params,
const char __user *_info,
const void __user *_in,
void __user *_out)
{
struct kernel_pkey_params params;
void *in, *out;
long ret;
ret = keyctl_pkey_params_get_2(_params, _info, op, &params);
if (ret < 0)
goto error_params;
ret = -EOPNOTSUPP;
if (!params.key->type->asym_eds_op)
goto error_params;
switch (op) {
case KEYCTL_PKEY_ENCRYPT:
params.op = kernel_pkey_encrypt;
break;
case KEYCTL_PKEY_DECRYPT:
params.op = kernel_pkey_decrypt;
break;
case KEYCTL_PKEY_SIGN:
params.op = kernel_pkey_sign;
break;
default:
BUG();
}
in = memdup_user(_in, params.in_len);
if (IS_ERR(in)) {
ret = PTR_ERR(in);
goto error_params;
}
ret = -ENOMEM;
out = kmalloc(params.out_len, GFP_KERNEL);
if (!out)
goto error_in;
ret = params.key->type->asym_eds_op(&params, in, out);
if (ret < 0)
goto error_out;
if (copy_to_user(_out, out, ret) != 0)
ret = -EFAULT;
error_out:
kfree(out);
error_in:
kfree(in);
error_params:
keyctl_pkey_params_free(&params);
return ret;
}
/*
* Verify a signature.
*
* Verify a public key signature using the given key, or if not given, search
* for a matching key.
*
* _info is a string of supplementary information in key=val format. For
* instance, it might contain:
*
* "enc=pkcs1 hash=sha256"
*
* where enc= specifies the signature blob encoding and hash= selects the OID
* to go in that particular encoding. If enc= isn't supplied, it's assumed
* that the caller is supplying raw values.
*
* If successful, 0 is returned.
*/
long keyctl_pkey_verify(const struct keyctl_pkey_params __user *_params,
const char __user *_info,
const void __user *_in,
const void __user *_in2)
{
struct kernel_pkey_params params;
void *in, *in2;
long ret;
ret = keyctl_pkey_params_get_2(_params, _info, KEYCTL_PKEY_VERIFY,
&params);
if (ret < 0)
goto error_params;
ret = -EOPNOTSUPP;
if (!params.key->type->asym_verify_signature)
goto error_params;
in = memdup_user(_in, params.in_len);
if (IS_ERR(in)) {
ret = PTR_ERR(in);
goto error_params;
}
in2 = memdup_user(_in2, params.in2_len);
if (IS_ERR(in2)) {
ret = PTR_ERR(in2);
goto error_in;
}
params.op = kernel_pkey_verify;
ret = params.key->type->asym_verify_signature(&params, in, in2);
kfree(in2);
error_in:
kfree(in);
error_params:
keyctl_pkey_params_free(&params);
return ret;
}
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/tpm.h> #include <linux/tpm.h>
#include <linux/tpm_command.h> #include <linux/tpm_command.h>
#include "trusted.h" #include <keys/trusted.h>
static const char hmac_alg[] = "hmac(sha1)"; static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1"; static const char hash_alg[] = "sha1";
...@@ -121,7 +121,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, ...@@ -121,7 +121,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
/* /*
* calculate authorization info fields to send to TPM * calculate authorization info fields to send to TPM
*/ */
static int TSS_authhmac(unsigned char *digest, const unsigned char *key, int TSS_authhmac(unsigned char *digest, const unsigned char *key,
unsigned int keylen, unsigned char *h1, unsigned int keylen, unsigned char *h1,
unsigned char *h2, unsigned char h3, ...) unsigned char *h2, unsigned char h3, ...)
{ {
...@@ -168,11 +168,12 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, ...@@ -168,11 +168,12 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
kzfree(sdesc); kzfree(sdesc);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(TSS_authhmac);
/* /*
* verify the AUTH1_COMMAND (Seal) result from TPM * verify the AUTH1_COMMAND (Seal) result from TPM
*/ */
static int TSS_checkhmac1(unsigned char *buffer, int TSS_checkhmac1(unsigned char *buffer,
const uint32_t command, const uint32_t command,
const unsigned char *ononce, const unsigned char *ononce,
const unsigned char *key, const unsigned char *key,
...@@ -249,6 +250,7 @@ static int TSS_checkhmac1(unsigned char *buffer, ...@@ -249,6 +250,7 @@ static int TSS_checkhmac1(unsigned char *buffer,
kzfree(sdesc); kzfree(sdesc);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(TSS_checkhmac1);
/* /*
* verify the AUTH2_COMMAND (unseal) result from TPM * verify the AUTH2_COMMAND (unseal) result from TPM
...@@ -355,7 +357,7 @@ static int TSS_checkhmac2(unsigned char *buffer, ...@@ -355,7 +357,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
* For key specific tpm requests, we will generate and send our * For key specific tpm requests, we will generate and send our
* own TPM command packets using the drivers send function. * own TPM command packets using the drivers send function.
*/ */
static int trusted_tpm_send(unsigned char *cmd, size_t buflen) int trusted_tpm_send(unsigned char *cmd, size_t buflen)
{ {
int rc; int rc;
...@@ -367,6 +369,7 @@ static int trusted_tpm_send(unsigned char *cmd, size_t buflen) ...@@ -367,6 +369,7 @@ static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
rc = -EPERM; rc = -EPERM;
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(trusted_tpm_send);
/* /*
* Lock a trusted key, by extending a selected PCR. * Lock a trusted key, by extending a selected PCR.
...@@ -425,7 +428,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, ...@@ -425,7 +428,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
/* /*
* Create an object independent authorisation protocol (oiap) session * Create an object independent authorisation protocol (oiap) session
*/ */
static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
{ {
int ret; int ret;
...@@ -442,6 +445,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) ...@@ -442,6 +445,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
TPM_NONCE_SIZE); TPM_NONCE_SIZE);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(oiap);
struct tpm_digests { struct tpm_digests {
unsigned char encauth[SHA1_DIGEST_SIZE]; unsigned char encauth[SHA1_DIGEST_SIZE];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment