lkml.org 
[lkml]   [2012]   [Aug]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 04/25] KEYS: Add signature verification facility
    Date
    Add a facility whereby a key subtype may be asked to verify a signature against
    the data it is purported to have signed.

    This adds four routines:

    (1) struct crypto_key_verify_context *
    verify_sig_begin(struct key *keyring, const void *sig, size_t siglen);

    This sets up a verification context for the given signature using
    information in that signature to select a key from the specified keyring
    and to request a hash algorithm from the crypto layer.

    (2) int verify_sig_add_data(struct crypto_key_verify_context *ctx,
    const void *data, size_t datalen);

    Incrementally supply data to be signed. May be called multiple times.

    (3) int verify_sig_end(struct crypto_key_verify_context *ctx,
    const void *sig, size_t siglen);

    Complete the verification process and return the result. -EKEYREJECTED
    will indicate that the verification failed and 0 will indicate success.
    Other errors are also possible.

    (4) void verify_sig_cancel(struct crypto_key_verify_context *ctx);

    Cancel the verification process.

    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    Documentation/security/keys-crypto.txt | 100 ++++++++++++++++++++
    include/keys/crypto-subtype.h | 36 +++++++
    include/keys/crypto-type.h | 9 ++
    security/keys/crypto/Makefile | 2
    security/keys/crypto/crypto_keys.h | 1
    security/keys/crypto/crypto_type.c | 2
    security/keys/crypto/crypto_verify.c | 159 ++++++++++++++++++++++++++++++++
    7 files changed, 304 insertions(+), 5 deletions(-)
    create mode 100644 security/keys/crypto/crypto_verify.c


    diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt
    index 97dee80..0a886ec 100644
    --- a/Documentation/security/keys-crypto.txt
    +++ b/Documentation/security/keys-crypto.txt
    @@ -7,6 +7,7 @@ Contents:
    - Overview.
    - Key identification.
    - Accessing crypto keys.
    + - Signature verification.
    - Implementing crypto parsers.
    - Implementing crypto subtypes.

    @@ -89,6 +90,65 @@ This gives access to the key type:
    struct key_type key_type_crypto;


    +SIGNATURE VERIFICATION
    +----------------------
    +
    +The four operations that can perform cryptographic signature verification,
    +using one of a set of keys to provide the public key:
    +
    + (1) Begin verification procedure.
    +
    + struct crypto_key_verify_context *
    + verify_sig_begin(struct key *keyring, const void *sig, size_t siglen);
    +
    + This function sets up a verification context from the information in the
    + signature and looks for a suitable key in the keyring. The signature blob
    + must be presented again at the end of the procedure. The keys will be
    + checked against parameters in the signature, and if the matching one is
    + not found then -ENOKEY will be returned.
    +
    + The hashing algorithm, if such a thing applies, will be determined from
    + information in the signature and the appropriate crypto module will be
    + used. -ENOPKG will be returned if the hash algorithm is unavailable.
    +
    + The return value is an opaque pointer to be passed to the other functions,
    + or a negative error code.
    +
    + (2) Indicate data to be verified.
    +
    + int verify_sig_add_data(struct crypto_key_verify_context *ctx,
    + const void *data, size_t datalen);
    +
    + This function is used to shovel data to the verification procedure so that
    + it can load it into the hash, pass it to hardware or whatever is
    + appropriate for the algorithm being employed.
    +
    + The data is not canonicalised for the document type specified in the
    + signature. The caller must do that.
    +
    + It will return 0 if successful and a negative error code if not.
    +
    + (3) Complete the verification process.
    +
    + int verify_sig_end(struct crypto_key_verify_context *ctx,
    + const void *sig, size_t siglen);
    +
    + This function performs the actual signature verification step and cleans
    + up the resources allocated at the beginning. The signature must be
    + presented again as some of the data therein may need to be added to the
    + internal hash.
    +
    + It will return -EKEYREJECTED if the signature didn't match, 0 if
    + successful and may return other errors as appropriate.
    +
    + (4) Cancel the verification process.
    +
    + void verify_sig_cancel(struct crypto_key_verify_context *ctx);
    +
    + This function cleans up the resources allocated at the beginning. This is
    + not necessary if verify_sig_end() was called.
    +
    +
    ===========================
    IMPLEMENTING CRYPTO PARSERS
    ===========================
    @@ -107,6 +167,8 @@ The parser definition structure looks like the following:

    int (*instantiate)(struct key *key,
    const void *data, size_t datalen);
    + struct crypto_key_verify_context *(*verify_sig_begin)(
    + struct key *keyring, const u8 *sig, size_t siglen);
    };

    The owner and name fields should be set to the owning module and the name of
    @@ -135,6 +197,44 @@ but it is expected that at least one will be defined.
    algorithm such as RSA and DSA this will likely be a printable hex version
    of the key's fingerprint.

    + (2) verify_sig_begin().
    +
    + This is similar in concept to the instantiate() function, except that it
    + is given a signature blob to parse rather than a key data blob.
    +
    + If the data format is not recognised, -EBADMSG should be returned. If it
    + is recognised, but the signature verification process cannot for some
    + reason be set up, some other negative error code should be returned.
    + -ENOKEY should be used to indicate that no matching key is available and
    + -ENOPKG should be returned if the hash algorithm or the verification
    + algorithm are unavailable.
    +
    + If successful, the parser should allocate a verification context and embed
    + the following struct in it:
    +
    + struct crypto_key_verify_context {
    + struct key *key;
    + int (*add_data)(struct crypto_key_verify_context *ctx,
    + const void *data, size_t datalen);
    + int (*end)(struct crypto_key_verify_context *ctx,
    + const u8 *sig, size_t siglen);
    + void (*cancel)(struct crypto_key_verify_context *ctx);
    + };
    +
    + and return a pointer to this to the caller, who will then pass it to the
    + verification operation wrappers described in the "Signature Verification"
    + section. The three operation pointers here correspond exactly to those
    + wrappers and are all mandatory. container_of() should be used to retrieve
    + the actual context.
    +
    + Note that the crypto key type retains a reference on the parser module for
    + the lifetime of this context, though the operation pointers need not point
    + into this module.
    +
    + The parser should also record a pointer to the key selected and take a
    + reference on that key with key_get().
    +
    +
    Functions are provided to register and unregister parsers:

    int register_crypto_key_parser(struct crypto_key_parser *parser);
    diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h
    index 1f546e6..61a5338 100644
    --- a/include/keys/crypto-subtype.h
    +++ b/include/keys/crypto-subtype.h
    @@ -34,8 +34,7 @@ struct crypto_key_subtype {
    };

    /*
    - * Data parser. Called during instantiation and signature verification
    - * initiation.
    + * Key data parser. Called during key instantiation.
    */
    struct crypto_key_parser {
    struct list_head link;
    @@ -54,4 +53,37 @@ struct crypto_key_parser {
    extern int register_crypto_key_parser(struct crypto_key_parser *);
    extern void unregister_crypto_key_parser(struct crypto_key_parser *);

    +/*
    + * Context base for signature verification methods. Allocated by the subtype
    + * and presumably embedded in something appropriate.
    + */
    +struct crypto_sig_verify_context {
    + struct key *key;
    + struct crypto_sig_parser *parser;
    + int (*add_data)(struct crypto_sig_verify_context *ctx,
    + const void *data, size_t datalen);
    + int (*end)(struct crypto_sig_verify_context *ctx,
    + const u8 *sig, size_t siglen);
    + void (*cancel)(struct crypto_sig_verify_context *ctx);
    +};
    +
    +/*
    + * Signature data parser. Called during signature verification initiation.
    + */
    +struct crypto_sig_parser {
    + struct list_head link;
    + struct module *owner;
    + const char *name;
    +
    + /* Attempt to recognise a signature blob and find a matching key.
    + *
    + * Return EBADMSG if not recognised.
    + */
    + struct crypto_sig_verify_context *(*verify_sig_begin)(
    + struct key *keyring, const u8 *sig, size_t siglen);
    +};
    +
    +extern int register_crypto_sig_parser(struct crypto_sig_parser *);
    +extern void unregister_crypto_sig_parser(struct crypto_sig_parser *);
    +
    #endif /* _KEYS_CRYPTO_SUBTYPE_H */
    diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h
    index 47c00c7..0fb362a 100644
    --- a/include/keys/crypto-type.h
    +++ b/include/keys/crypto-type.h
    @@ -18,6 +18,15 @@

    extern struct key_type key_type_crypto;

    +struct crypto_sig_verify_context;
    +extern struct crypto_sig_verify_context *verify_sig_begin(
    + struct key *key, const void *sig, size_t siglen);
    +extern int verify_sig_add_data(struct crypto_sig_verify_context *ctx,
    + const void *data, size_t datalen);
    +extern int verify_sig_end(struct crypto_sig_verify_context *ctx,
    + const void *sig, size_t siglen);
    +extern void verify_sig_cancel(struct crypto_sig_verify_context *ctx);
    +
    /*
    * The payload is at the discretion of the subtype.
    */
    diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
    index 36db1d5..67001bc 100644
    --- a/security/keys/crypto/Makefile
    +++ b/security/keys/crypto/Makefile
    @@ -4,4 +4,4 @@

    obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o

    -crypto_keys-y := crypto_type.o
    +crypto_keys-y := crypto_type.o crypto_verify.o
    diff --git a/security/keys/crypto/crypto_keys.h b/security/keys/crypto/crypto_keys.h
    index eb11788..ab9b381 100644
    --- a/security/keys/crypto/crypto_keys.h
    +++ b/security/keys/crypto/crypto_keys.h
    @@ -24,5 +24,4 @@ static inline const char *crypto_key_id(const struct key *key)
    /*
    * crypto_type.c
    */
    -extern struct list_head crypto_key_parsers;
    extern struct rw_semaphore crypto_key_parsers_sem;
    diff --git a/security/keys/crypto/crypto_type.c b/security/keys/crypto/crypto_type.c
    index e8f83a6..821db37 100644
    --- a/security/keys/crypto/crypto_type.c
    +++ b/security/keys/crypto/crypto_type.c
    @@ -18,7 +18,7 @@

    MODULE_LICENSE("GPL");

    -LIST_HEAD(crypto_key_parsers);
    +static LIST_HEAD(crypto_key_parsers);
    DECLARE_RWSEM(crypto_key_parsers_sem);

    /*
    diff --git a/security/keys/crypto/crypto_verify.c b/security/keys/crypto/crypto_verify.c
    new file mode 100644
    index 0000000..d64f1c7
    --- /dev/null
    +++ b/security/keys/crypto/crypto_verify.c
    @@ -0,0 +1,159 @@
    +/* Signature verification with a crypto key
    + *
    + * Copyright (C) 2011 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.
    + *
    + * See Documentation/security/keys-crypto.txt
    + */
    +
    +#include <keys/crypto-subtype.h>
    +#include <linux/module.h>
    +#include <linux/err.h>
    +#include "crypto_keys.h"
    +
    +static LIST_HEAD(crypto_sig_parsers);
    +
    +/**
    + * verify_sig_begin - Initiate the use of a crypto key to verify a signature
    + * @keyring: The public keys to verify against
    + * @sig: The signature data
    + * @siglen: The signature length
    + *
    + * Returns a context or an error.
    + */
    +struct crypto_sig_verify_context *verify_sig_begin(
    + struct key *keyring, const void *sig, size_t siglen)
    +{
    + struct crypto_sig_verify_context *ret;
    + struct crypto_sig_parser *parser;
    +
    + pr_devel("==>%s()\n", __func__);
    +
    + if (siglen == 0 || !sig)
    + return ERR_PTR(-EINVAL);
    +
    + down_read(&crypto_key_parsers_sem);
    +
    + ret = ERR_PTR(-EBADMSG);
    + list_for_each_entry(parser, &crypto_sig_parsers, link) {
    + if (parser->verify_sig_begin) {
    + if (!try_module_get(parser->owner))
    + continue;
    +
    + pr_debug("Trying parser '%s'\n", parser->name);
    +
    + ret = parser->verify_sig_begin(keyring, sig, siglen);
    + if (IS_ERR(ret))
    + module_put(parser->owner);
    + else
    + ret->parser = parser;
    + if (ret != ERR_PTR(-EBADMSG)) {
    + pr_debug("Parser recognised the format"
    + " (ret %ld)\n",
    + PTR_ERR(ret));
    + break;
    + }
    + }
    + }
    +
    + up_read(&crypto_key_parsers_sem);
    + pr_devel("<==%s() = %p\n", __func__, ret);
    + return ret;
    +}
    +EXPORT_SYMBOL_GPL(verify_sig_begin);
    +
    +/**
    + * verify_sig_add_data - Incrementally provide data to be verified
    + * @ctx: The context from verify_sig_begin()
    + * @data: Data
    + * @datalen: The amount of @data
    + *
    + * This may be called multiple times.
    + */
    +int verify_sig_add_data(struct crypto_sig_verify_context *ctx,
    + const void *data, size_t datalen)
    +{
    + return ctx->add_data(ctx, data, datalen);
    +}
    +EXPORT_SYMBOL_GPL(verify_sig_add_data);
    +
    +/**
    + * verify_sig_end - Finalise signature verification and return result
    + * @ctx: The context from verify_sig_begin()
    + * @sig: The signature data
    + * @siglen: The signature length
    + */
    +int verify_sig_end(struct crypto_sig_verify_context *ctx,
    + const void *sig, size_t siglen)
    +{
    + struct crypto_sig_parser *parser = ctx->parser;
    + int ret;
    +
    + ret = ctx->end(ctx, sig, siglen);
    + module_put(parser->owner);
    + return ret;
    +}
    +EXPORT_SYMBOL_GPL(verify_sig_end);
    +
    +/**
    + * verify_sig_end - Cancel signature verification
    + * @ctx: The context from verify_sig_begin()
    + */
    +void verify_sig_cancel(struct crypto_sig_verify_context *ctx)
    +{
    + struct crypto_sig_parser *parser = ctx->parser;
    +
    + ctx->cancel(ctx);
    + module_put(parser->owner);
    +}
    +EXPORT_SYMBOL_GPL(verify_sig_cancel);
    +
    +/**
    + * register_crypto_sig_parser - Register a crypto sig blob parser
    + * @parser: The parser to register
    + */
    +int register_crypto_sig_parser(struct crypto_sig_parser *parser)
    +{
    + struct crypto_sig_parser *cursor;
    + int ret;
    +
    + down_write(&crypto_key_parsers_sem);
    +
    + list_for_each_entry(cursor, &crypto_sig_parsers, link) {
    + if (strcmp(cursor->name, parser->name) == 0) {
    + pr_err("Crypto signature parser '%s' already registered\n",
    + parser->name);
    + ret = -EEXIST;
    + goto out;
    + }
    + }
    +
    + list_add_tail(&parser->link, &crypto_sig_parsers);
    +
    + pr_notice("Crypto signature parser '%s' registered\n", parser->name);
    + ret = 0;
    +
    +out:
    + up_write(&crypto_key_parsers_sem);
    + return ret;
    +}
    +EXPORT_SYMBOL_GPL(register_crypto_sig_parser);
    +
    +/**
    + * unregister_crypto_sig_parser - Unregister a crypto sig blob parser
    + * @parser: The parser to unregister
    + */
    +void unregister_crypto_sig_parser(struct crypto_sig_parser *parser)
    +{
    + down_write(&crypto_key_parsers_sem);
    + list_del(&parser->link);
    + up_write(&crypto_key_parsers_sem);
    +
    + pr_notice("Crypto signature parser '%s' unregistered\n", parser->name);
    +}
    +EXPORT_SYMBOL_GPL(unregister_crypto_sig_parser);


    \
     
     \ /
      Last update: 2012-08-16 04:23    [W:4.258 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site