Skip to content

Commit

Permalink
Rework so COSE_Signature implementations are simpler + easier DECODE_…
Browse files Browse the repository at this point in the history
…ONLY (#257)

This is a major change to the internal way COSE_Sign is processed. No big API changes.

Verifier objects no longer need to decode COSE_Signatures and are half as complex as before. The COSE_SIgnature decoding is centralized. This also allows DECODE_ONLY with no verifiers (as long as COSE_Signatures don't use non-string or integer headers or need buffer size calculations).

Tests for DECODE_ONLY with multiple signatures




* Might fix aux buf size calc for multiple signatures

* Rework multiple COSE_Signatures

* Remove files that shouldn't have been added

* Documentation and clean up

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
  • Loading branch information
laurencelundblade and Laurence Lundblade authored Aug 8, 2023
1 parent ee1a6c9 commit 6ebef8d
Show file tree
Hide file tree
Showing 13 changed files with 431 additions and 393 deletions.
2 changes: 1 addition & 1 deletion examples/encryption_examples.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,11 @@ esdh_example_detached(void)
Done:
printf("---- %s EXAMPLE ESDH (%d) ----\n\n",
result ? "FAILED" : "COMPLETED", result);
return (int32_t)result;

/* Free test keys */
free_fixed_test_ec_encryption_key(pkR);
free_fixed_test_ec_encryption_key(skR);

return (int32_t)result;
}
#endif /* !T_COSE_DISABLE_ESDH */
6 changes: 3 additions & 3 deletions inc/t_cose/t_cose_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -707,15 +707,15 @@ enum t_cose_err_t {


/**
* When verifying or signing a COSE message, cryptographic operations
* like verification and decryption will not be performed. Keys needed
* When verifying a COSE message, cryptographic operations
* like verification will not be performed. Keys needed
* for these operations are not needed. This is useful to decode a
* COSE message to get the header parameter(s) to lookup/find/identify
* the required key(s) (e.g., the kid parameter). Then the key(s)
* are/is configured and the message is decoded again without this
* option.
*
* Note that anything returned (parameters, payload) will not have
* Note that anything returned (parameters and payload) will not have
* been verified and should be considered untrusted.
*/
#define T_COSE_OPT_DECODE_ONLY 0x00000800
Expand Down
100 changes: 55 additions & 45 deletions inc/t_cose/t_cose_sign_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,45 +92,54 @@ t_cose_sign_verify_init(struct t_cose_sign_verify_ctx *context,
* \param[in] context Signed message verification context.
* \param[in] verifier Pointer to verifier object.
* Verifiers are objects that do the cryptographic operations
* to verify a COSE_Sign or COSE_Sign1. They do both the
* hashing and the public key cryptography. They also
* implement the decoding of the COSE_Signature(s) in a
* COSE_Sign.
*
* At least one verifier must be added in. Before they
* are added in they should be configured with any key
* material (e.g., the verification key) needed.
*
* The verifiers added must be a complete concrete instance
* such as t_cose_signature_verify_main or t_cose_signature_verify_eddsa,
* not the abstract base object t_cose_signature_verify.
* Some verifiers like t_cose_signature_verify_main handle multiple
* cryptographic algorithms.
*
* For COSE_SIgn messages, t_cose_sign_verify() loops over
* all the COSE_Signatures. By default the verification is a success
* if one can be verified and there are no decoding errors. The
* option \ref T_COSE_OPT_VERIFY_ALL_SIGNATURES can be set
* to require that all the signatures verify for the overall COSE_Sign
* to be a success.
*
* For COSE_Sign1 messages t_cose_sign_verify() calls
* each verifier as described next.
*
* Each verifier added here is called on each COSE_Signature
* until one succeeds. An individual verifier may decline to
* attempt verification if it doesn't handle the particular
* algorithm, the kid doesn't match or for other reasons it
* may have after examining the header parameters in the
* COSE_Signature. If it declines, the next verifier will be
* invoked. If an individual verifier fails because of a CBOR
* decoding issue or if it attempts the actual signature
* cryptographic operation and that fails, processing of the
* whole COSE_Sign will fail.
*
* The header parameters for all the COSE_Signatures are
* returned in a linked list by t_cose_sign_verify().
* Verifiers are objects that do the cryptographic operations to
* verify a COSE_Sign or COSE_Sign1. They do both the hashing and the
* public key cryptography.
*
* At least one verifier must be added in. Before they are added in
* they should be configured with any key material (e.g., the
* verification key) needed.
*
* The verifiers added must be a complete concrete instance such as
* t_cose_signature_verify_main or t_cose_signature_verify_eddsa, not
* the abstract base object t_cose_signature_verify. Some verifiers
* like t_cose_signature_verify_main handle multiple cryptographic
* algorithms.
*
* For COSE_Sign messages, t_cose_sign_verify() loops over all the
* COSE_Signatures. By default, the verification is a success if one
* can be verified and there are no decoding errors. The option
* \ref T_COSE_OPT_VERIFY_ALL_SIGNATURES can be set to require that all
* the signatures verify for the overall COSE_Sign to be a success.
*
* In verifying each COSE_Signature in a COSE_Sign or the single
* signature in a COSE_Sign1, each verifier is called in a loop until
* one succeeds. An individual verifier may decline to attempt
* verification if it doesn't handle the particular algorithm, the kid
* doesn't match or for other reasons it may have after examining the
* header parameters in the COSE_Signature. If it declines, the next
* verifier will be invoked. If an individual verifier fails because
* of a CBOR decoding issue processing of the whole signed message
* will fail.
*
* The header parameters for all the COSE_Signatures are returned in a
* linked list by t_cose_sign_verify().
*
* To decode headers and compute buffer sizes, t_cose_sign_verify can
* be called with \ref T_COSE_OPT_DECODE_ONLY set. This will run most of
* the verification except the final signature verification and the
* kid check. Typically it is run with all the verifiers configured,
* but without any cryptographic keys. It will return all the decoded
* parameters for the entire signed message. Some verifiers may do
* additional work. For example, t_cose_signature_sign_eddsa computes
* the size of an auxiliary buffer. Others may decode headers that are
* not integers or strings.
*
* \ref T_COSE_OPT_DECODE_ONLY mode always succeeds in decoding the integer
* and string header parameters for all COSE_Signatures regardless of
* what verifiers are configured or whether
* \ref T_COSE_OPT_VERIFY_ALL_SIGNATURES is set or not. It can even be
* used with no verifiers configured.
*/
static void
t_cose_sign_add_verifier(struct t_cose_sign_verify_ctx *context,
Expand All @@ -145,7 +154,7 @@ t_cose_sign_add_verifier(struct t_cose_sign_verify_ctx *context,
*
* This is optionally called to increase the number of storage nodes
* for COSE_Sign or COSE_Sign1 message with
* T_COSE_NUM_DECODE_HEADERS header parameters. Decoded
* \ref T_COSE_NUM_VERIFY_DECODE_HEADERS header parameters. Decoded
* parameters are returned in a linked list of struct
* t_cose_parameter. The storage for the nodes in the list is not
* dynamically allocated as there is no dynamic storage allocation
Expand Down Expand Up @@ -198,9 +207,9 @@ t_cose_sign_set_special_param_decoder(struct t_cose_sign_verify_ctx *context,
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* See t_cose_sign_add_verifier() for discussion on where
* the verification key comes from, algorithms, formats and
* handling of multiple signatures and multiple verifiers.
* See t_cose_sign_add_verifier() for discussion on where the
* verification key comes from, algorithms, formats and handling of
* multiple signatures and multiple verifiers.
*
* Verification involves the following steps.
*
Expand All @@ -217,8 +226,9 @@ t_cose_sign_set_special_param_decoder(struct t_cose_sign_verify_ctx *context,
* algorithm used comes from the signing algorithm. If the algorithm is
* unknown or not supported this will error out.
*
* At least one verifier must be configured using t_cose_sign_add_verifier() to
* be able to perform a success verification.
* At least one verifier must be configured using
* t_cose_sign_add_verifier() to be able to perform a success
* verification.
*
* - Finally, the signature verification is performed.
*
Expand Down
51 changes: 13 additions & 38 deletions inc/t_cose/t_cose_signature_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,6 @@
struct t_cose_signature_verify;


/**
* \brief Type definition of function used to verify a COSE_Signature in a COSE_Sign.
*
* \param[in] me The context, the t_cose_signature_verify
* instance. This will actully be some thing like
* t_cose_signature_verify_main that inplements
* t_cose_signature_verify.
* \param[in] option_flags Option flags from t_cose_sign_verify_init().
* Mostly for \ref T_COSE_OPT_DECODE_ONLY.
* \param[in] loc The location of the signature inside the
* COSE_Sign.
* \param[in] sign_inputs Payload, aad and header parameters to verify.
* \param[in] params The place to put the decoded params.
* \param[in] qcbor_decoder The decoder instance from where the
* COSE_Signature is decoded.
* \param[out] decoded_params Returned linked list of decoded parameters.
*
* This must return T_COSE_ERR_NO_MORE if there are no more COSE_Signatures.
*/
typedef enum t_cose_err_t
t_cose_signature_verify_cb(struct t_cose_signature_verify *me,
uint32_t option_flags,
const struct t_cose_header_location loc,
struct t_cose_sign_inputs *sign_inputs,
struct t_cose_parameter_storage *params,
QCBORDecodeContext *qcbor_decoder,
struct t_cose_parameter **decoded_params);


/**
* \brief Type definition of function to verify the bare signature in COSE_Sign1.
*
Expand All @@ -75,9 +46,8 @@ t_cose_signature_verify_cb(struct t_cose_signature_verify *me,
* found.
* \param[in] signature The signature.
*
* This is very different from t_cose_signature_verify_cb()
* because there is no header decoding to be done. Instead the headers
* are decoded outside of this and passed in.
* This runs the crypto to actually verify a signature. The decoded headers are
* passed in \c parameter_list.
*/
typedef enum t_cose_err_t
t_cose_signature_verify1_cb(struct t_cose_signature_verify *me,
Expand All @@ -88,15 +58,20 @@ t_cose_signature_verify1_cb(struct t_cose_signature_verify *me,


/**
* Data structure that must be the first part of every context of every concrete
* implementation of t_cose_signature_verify. Callback functions must not
* be NULL, but can be stubs that return an error when COSE_SIgn1 or COSE_Sign
* are not supported.
* Data structure that must be the first part of every context of
* every concrete implementation of t_cose_signature_verify. \c
* verify_cb must not be \c NULL. Header parameter decoding for
* integer and string parameters is done automatically. \c
* special_param_decode_cb should be non-NULL if there are non-integer
* or non-string parameters to decode. \c special_param_decode_ctx is
* only passed to \c special_param_decode_cb so it may or may not by
* NULL as needed.
*/
struct t_cose_signature_verify {
struct t_cose_rs_obj rs;
t_cose_signature_verify_cb *verify_cb;
t_cose_signature_verify1_cb *verify1_cb;
t_cose_signature_verify1_cb *verify_cb;
t_cose_param_special_decode_cb *special_param_decode_cb;
void *special_param_decode_ctx;
};


Expand Down
8 changes: 4 additions & 4 deletions inc/t_cose/t_cose_signature_verify_eddsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ struct t_cose_signature_verify_eddsa {
*/
struct t_cose_signature_verify s;
struct t_cose_key verification_key;
t_cose_param_special_decode_cb *special_param_decode_cb;
void *special_param_decode_ctx;
uint32_t option_flags;

struct q_useful_buf_c verification_kid;
Expand All @@ -59,6 +57,7 @@ struct t_cose_signature_verify_eddsa {
};


// TODO: get rid of option_flags?
void
t_cose_signature_verify_eddsa_init(struct t_cose_signature_verify_eddsa *me,
uint32_t option_flags);
Expand Down Expand Up @@ -147,8 +146,9 @@ t_cose_signature_verify_eddsa_set_special_param_decoder(struct t_cose_signature_
t_cose_param_special_decode_cb *decode_cb,
void *decode_ctx)
{
me->special_param_decode_cb = decode_cb;
me->special_param_decode_ctx = decode_ctx;
struct t_cose_signature_verify *me_x = t_cose_signature_verify_from_eddsa(me);
me_x->special_param_decode_cb = decode_cb;
me_x->special_param_decode_ctx = decode_ctx;
}

static inline void
Expand Down
29 changes: 15 additions & 14 deletions inc/t_cose/t_cose_signature_verify_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,27 @@
extern "C" {
#endif

/* Warning: this is still early development. Documentation may be incorrect. */


/**
* Verification context. */
* Verification context.
*/
struct t_cose_signature_verify_main {
/* Private data structure */

/* t_cose_signature_verify must be the first item for the polymorphism to work.
* This structure, t_cose_signature_verify_main, will sometimes be uses as
* a t_cose_signature_verify.
/* t_cose_signature_verify must be the first item for the
* polymorphism to work. This structure,
* t_cose_signature_verify_main, will sometimes be uses as a
* t_cose_signature_verify.
*/
struct t_cose_signature_verify s;
struct t_cose_key verification_key;
struct q_useful_buf_c verification_kid;
t_cose_param_special_decode_cb *special_param_decode_cb;
void *special_param_decode_ctx;
void *crypto_context;

};



/* This verifier supports ECDSA and RSA (but no EdDSA).
*
* This verifier
/* This verifier supports ECDSA and RSA (but not EdDSA).
*
* The context initialized here can be cast to t_cose_signature_verify
* and given to t_cose_sign_verify which will invoke the verify through
Expand Down Expand Up @@ -95,6 +90,10 @@ t_cose_signature_verify_main_set_special_param_decoder(struct t_cose_signature_v
t_cose_param_special_decode_cb *decode_cb,
void *decode_ctx);


/*
* Return instance of bass class.
*/
static struct t_cose_signature_verify *
t_cose_signature_verify_from_main(struct t_cose_signature_verify_main *context);

Expand All @@ -120,8 +119,10 @@ t_cose_signature_verify_main_set_special_param_decoder(struct t_cose_signature_v
t_cose_param_special_decode_cb *decode_cb,
void *decode_ctx)
{
me->special_param_decode_cb = decode_cb;
me->special_param_decode_ctx = decode_ctx;
struct t_cose_signature_verify *me_x = t_cose_signature_verify_from_main(me);

me_x->special_param_decode_cb = decode_cb;
me_x->special_param_decode_ctx = decode_ctx;
}


Expand Down
2 changes: 1 addition & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

/*
This is an implementation of OutputStringCB built using stdio. If
you don't have stdio, replaces this.
you don't have stdio, replace this.
*/
static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine)
{
Expand Down
Loading

0 comments on commit 6ebef8d

Please sign in to comment.