mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
cose: keys and signing + validation
Support for COSE keys and signing / validation - lws_cose_key_t and import / export / generation apis for EC / RSA / SYMMETRIC - cose_sign1 ES256/384/512,RS256/384/512 sign + validate, passes RFC8152 WG tests sign1-tests - cose_sign ES256/384/512,RS256/384/512 sign + validate, passes RFC8152 WG tests sign-tests - cose_mac0 HS256/HS256_64/384/512 sign + validate, passes RFC8152 WG tests hmac-examples - cose_mac HS256/HS256_64/384/512 validate, passes RFC8152 WG tests hmac-examples - lws-crypto-cose-key commandline tool for key / key set dumping and creation - lws-crypro-cose-sign commandline tool for signing / validation - lws-api-test-cose - large number of test vectors and tests from RFC8152
This commit is contained in:
parent
dcaa0013b4
commit
4db2ff872b
61 changed files with 9185 additions and 671 deletions
|
@ -101,6 +101,8 @@ if(LWS_WITH_DISTRO_RECOMMENDED)
|
|||
set(LWS_WITH_PLUGINS_BUILTIN 1) # selfcontained
|
||||
set(LWS_ROLE_RAW_PROXY 1) # selfcontained
|
||||
set(LWS_WITH_GENCRYPTO 1) # selfcontained / tls
|
||||
set(LWS_WITH_CBOR 1) # selfcontained
|
||||
set(LWS_WITH_COSE 1) # selfcontained
|
||||
set(LWS_WITH_JOSE 1) # selfcontained
|
||||
set(LWS_WITH_STRUCT_JSON 1) # selfcontained
|
||||
set(LWS_WITH_STRUCT_SQLITE3 1) # sqlite3
|
||||
|
|
|
@ -251,7 +251,8 @@ set(LWS_LOGGING_BITFIELD_CLEAR 0 CACHE STRING "Bitfield describing which log lev
|
|||
option(LWS_LOGS_TIMESTAMP "Timestamp at start of logs" ON)
|
||||
option(LWS_LOG_TAG_LIFECYCLE "Log tagged object lifecycle as NOTICE" ON)
|
||||
option(LWS_AVOID_SIGPIPE_IGN "Android 7+ reportedly needs this" OFF)
|
||||
option(LWS_WITH_JOSE "JSON Web Signature / Encryption / Keys (RFC7515/6/) API" OFF)
|
||||
option(LWS_WITH_JOSE "JOSE JSON Web Signature / Encryption / Keys (RFC7515/6/) API" OFF)
|
||||
option(LWS_WITH_COSE "COSE CBOR Signature / Encryption / Keys (RFC8152) API" OFF)
|
||||
option(LWS_WITH_GENCRYPTO "Enable support for Generic Crypto apis independent of TLS backend" OFF)
|
||||
option(LWS_WITH_SELFTESTS "Selftests run at context creation" OFF)
|
||||
option(LWS_WITH_GCOV "Build with gcc gcov coverage instrumentation" OFF)
|
||||
|
|
272
READMEs/README.cbor-cose.md
Normal file
272
READMEs/README.cbor-cose.md
Normal file
|
@ -0,0 +1,272 @@
|
|||
# RFC8152 COSE apis
|
||||
|
||||
|||
|
||||
|---|---|---|
|
||||
|cmake| `LWS_WITH_COSE`|
|
||||
|Header| ./include/libwebsockets/lws-cose.h|
|
||||
|api-test| ./minimal-examples/api-tests/api-test-cose/|
|
||||
|README| ./READMEs/README.cbor-cose.md
|
||||
|
||||
COSE is the CBOR equivalent of the JOSE suite of crypto objects and operations.
|
||||
You can represent public and private EC, RSA and SYMMETRIC keys, and sets of
|
||||
keys of various types; import the logical keys to and from CBOR; and sign /
|
||||
verify and encrypt / decrypt payloads using structured CBOR. Key generation is
|
||||
also supported.
|
||||
|
||||
|type|operations|algs|
|
||||
|---|---|---|
|
||||
|lws_cose_key_t|import, export, generation|EC / RSA / SYMMETRIC|
|
||||
|cose_sign1|sign, validate|ES256/384/512, RS256/384/512|
|
||||
|cose_sign|sign, validate|ES256/384/512, RS256/384/512|
|
||||
|cose_mac0|sign, validate|HS256/HS256_64/384/512|
|
||||
|cose_mac|validate only|HS256/HS256_64/384/512|
|
||||
|
||||
The lws COSE support uses the lws gencrypto layer, which calls through to the
|
||||
tls crypto library, and so works on both OpenSSL and mbedTLS the same.
|
||||
|
||||
An increasing number of higher-level IETF specifications use COSE underneath.
|
||||
|
||||
## cose_key and sets
|
||||
|
||||
Lws provides an `lws_cose_key_t` object to contain a single key's metadata and
|
||||
key material for EC, RSA and SYMMETRIC key types.
|
||||
|
||||
There is a commandline tool wrapping the key dumping and generation apis
|
||||
available at `./minimal-examples/crypto/lws-crypto-cose-key`
|
||||
|
||||
### cose_key and sets import from CBOR and destroying
|
||||
|
||||
```
|
||||
lws_cose_key_t *
|
||||
lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
|
||||
void *user, const uint8_t *in, size_t len);
|
||||
void
|
||||
lws_cose_key_destroy(lws_cose_key_t **ck);
|
||||
|
||||
void
|
||||
lws_cose_key_set_destroy(lws_dll2_owner_t *o);
|
||||
```
|
||||
|
||||
To convert a single key, `pkey_set` should be NULL and the created key will be
|
||||
returned, for a cose_key set, which is simply a CBOR array of cose_keys, it
|
||||
should be a prepared (ie, zero'd down if nothing in it) lws_dll2_owner_t that
|
||||
will contain the resulting list of `lws_cose_key_t` objects that were created.
|
||||
In both cases the return is NULL if there was a fatal error and anything created
|
||||
has been cleaned up, the return has no other meaning in the cose_key set case.
|
||||
|
||||
`lws_cose_key_destroy()` destroys a single `lws_cose_key_t` and sets the
|
||||
contents of the pointer to NULL, for cose_key sets you instead pass a pointer to
|
||||
the owner object to `lws_cose_key_set_destroy()` to destroy all the keys in the
|
||||
set in one step.
|
||||
|
||||
cose_key has some confusions about type, kty and alg may be either ints,
|
||||
representing well-known standardized key and alg types, or freeform strings.
|
||||
We convert the well-known ints to their string representations at import, so
|
||||
there can be no confusion later.
|
||||
|
||||
### cose_key generation
|
||||
|
||||
```
|
||||
lws_cose_key_t *
|
||||
lws_cose_key_generate(struct lws_context *context, int cose_kty, int use_mask,
|
||||
int bits, const char *curve, const char *kid);
|
||||
```
|
||||
|
||||
This creates an `lws_cose_key_t`, generates a key (SYMMETRIC) or keypair into
|
||||
it and returns a pointer to it.
|
||||
|
||||
`cose_kty` is one of `LWSCOSE_WKKTV_OKP`, `LWSCOSE_WKKTV_EC2`, `LWSCOSE_WKKTV_RSA`,
|
||||
or `LWSCOSE_WKKTV_SYMMETRIC`. `bits` is valid for RSA keys and for EC keys,
|
||||
`curve` should be a well-known curve name, one of `P-256`, `P-384` and `P-521`
|
||||
currently. `use_mask` is a bitfield made up of (1 << LWSCOSE_WKKO_...) set to
|
||||
enable the usage on the key.
|
||||
|
||||
### cose_key export to CBOR
|
||||
|
||||
The export api uses the same CBOR write context as `lws_lec_printf()` uses to
|
||||
emit the key into an output buffer. Like the CBOR output apis, it may return
|
||||
`LWS_LECPCTX_RET_AGAIN` to indicate it filled the buffer and should be called
|
||||
again to fill another buffer. `lws_lec_init()` should be used to prepare the
|
||||
write context and `lws_lec_setbuf()` to reset the output buffer on subsequent
|
||||
calls, exactly the same as the CBOR write apis.
|
||||
|
||||
```
|
||||
enum lws_lec_pctx_ret
|
||||
lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
|
||||
```
|
||||
|
||||
`flags` may be 0 to only output the public key pieces, or `LWSJWKF_EXPORT_PRIVATE`
|
||||
to output everything.
|
||||
|
||||
## Signing and signature validation
|
||||
|
||||
COSE specifies three kinds of signed object, `cose_sign1` which signs a payload
|
||||
with a single algorithm and key, `cose_sign` which may sign a payload with
|
||||
multiple algorithms and keys, and `countersign`.
|
||||
|
||||
`cose_sign1` has the advantage it can be validated with a single pass through
|
||||
the signed object; `cose_sign` unfortunately specifies the parameters of the
|
||||
signatures after the payload and must be done with multiple passes through the
|
||||
payload, for inline payloads, by caching it in heap.
|
||||
|
||||
`cose_sign` and `cose_sign1` objects are supported by lws, Countersigned
|
||||
objects are not yet supported.
|
||||
|
||||
`cose_mac0` is supported using HMAC for signing and validation, `cose_mac` is
|
||||
only supported for validation.
|
||||
|
||||
There is a commandline tool wrapping the signing and validation apis
|
||||
available at `./minimal-examples/crypto/lws-crypto-cose-sign`
|
||||
|
||||
### Signature validation
|
||||
|
||||
Signature validation does not have to be done synchronously, to facilitate this
|
||||
first you create a validation context specifying the type (eg, `SIGTYPE_SINGLE`)
|
||||
and a keyset of public keys the signature might use to validate (notice even a
|
||||
single key is passed in an lws_dll2_owner_t keyset).
|
||||
|
||||
Creation uses a public `lws_cose_validate_create_info_t` info struct
|
||||
|
||||
```
|
||||
typedef struct lws_cose_validate_create_info {
|
||||
struct lws_context *cx;
|
||||
/**< REQUIRED: the lws context */
|
||||
lws_dll2_owner_t *keyset;
|
||||
/**< REQUIRED: one or more cose_keys */
|
||||
|
||||
enum lws_cose_sig_types sigtype;
|
||||
/**< 0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
|
||||
* SIGTYPE_SINGLE, etc*/
|
||||
|
||||
lws_cose_validate_pay_cb_t pay_cb;
|
||||
/**< optional: called back with unvalidated payload pieces */
|
||||
void *pay_opaque;
|
||||
/**< optional: passed into pay_cb callback along with payload chunk */
|
||||
|
||||
lws_cose_sign_ext_pay_cb_t ext_cb;
|
||||
/**< optional extra application data provision callback */
|
||||
void *ext_opaque;
|
||||
/**< optional extra application data provision callback opaque */
|
||||
size_t ext_len;
|
||||
/**< if we have extra app data, this must be set to the length of it */
|
||||
} lws_cose_validate_create_info_t;
|
||||
```
|
||||
|
||||
```
|
||||
struct lws_cose_validate_context *
|
||||
lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
|
||||
|
||||
void
|
||||
lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
|
||||
```
|
||||
|
||||
after that as pieces of the signature CBOR become available, they can be
|
||||
processed by the validation context
|
||||
|
||||
```
|
||||
int
|
||||
lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
|
||||
const uint8_t *in, size_t in_len, size_t *used_in);
|
||||
```
|
||||
|
||||
The parsing of the signature yields a list of result objects indicating
|
||||
information about each signature it encountered and whether it was validated or
|
||||
not. The parsing itself only fails if there is an unrecoverable error, the
|
||||
completion of parsing does not indicate validation, it may yield zero or more
|
||||
result objects indicating the validation failed.
|
||||
|
||||
```
|
||||
lws_dll2_owner_t *
|
||||
lws_cose_validate_results(struct lws_cose_validate_context *cps);
|
||||
|
||||
typedef struct {
|
||||
lws_dll2_t list;
|
||||
|
||||
const lws_cose_key_t *cose_key;
|
||||
cose_param_t cose_alg;
|
||||
|
||||
int result; /* 0 = validated */
|
||||
|
||||
} lws_cose_validate_res_t;
|
||||
```
|
||||
|
||||
It's like this because for multiple signatures, we may only have keys for some
|
||||
of them, and we may have different policies for validation that can only be
|
||||
assessed as a whole, eg, we may inisit that signatures pass with specific
|
||||
algorithms, or all signatures for specific keys must be present and pass. This
|
||||
way user code can assess the situation after the signature parsing and make its
|
||||
decision about overall validity according to its own policies.
|
||||
|
||||
## Signing
|
||||
|
||||
Signing is again done by creating a signing context using an info struct to pass
|
||||
in the paramter (a `lws_cose_sign_create_info_t`).
|
||||
|
||||
```
|
||||
#define LCSC_FL_ADD_CBOR_TAG (1 << 0)
|
||||
#define LCSC_FL_ADD_CBOR_PREFER_MAC0 (1 << 1)
|
||||
|
||||
typedef struct lws_cose_sign_create_info {
|
||||
struct lws_context *cx;
|
||||
/**< REQUIRED: the lws context */
|
||||
lws_dll2_owner_t *keyset;
|
||||
/**< REQUIRED: one or more cose_keys */
|
||||
|
||||
lws_lec_pctx_t *lec;
|
||||
/**< REQUIRED: the cbor output context to emit to, user must
|
||||
* initialize with lws_lec_init() beforehand */
|
||||
|
||||
lws_cose_sign_ext_pay_cb_t ext_cb;
|
||||
/**< optional extra application data provision callback */
|
||||
void *ext_opaque;
|
||||
/**< optional extra application data provision callback opaque */
|
||||
size_t ext_len;
|
||||
/**< if we have extra app data, this must be set to the length of it */
|
||||
|
||||
size_t inline_payload_len;
|
||||
/**< REQUIRED: size of the inline payload we will provide */
|
||||
|
||||
int flags;
|
||||
/**< bitmap of LCSC_FL_* */
|
||||
enum lws_cose_sig_types sigtype;
|
||||
/**< 0, or sign type hint */
|
||||
} lws_cose_sign_create_info_t;
|
||||
```
|
||||
|
||||
```
|
||||
struct lws_cose_sign_context *
|
||||
lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
|
||||
```
|
||||
|
||||
After creating the signing context, you call `lws_cose_sign_add()` one or more
|
||||
times to add algorithms and keys to sign with (since cose_sign allows multiple
|
||||
recipients with the same payload signed in different ways).
|
||||
|
||||
```
|
||||
int
|
||||
lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
|
||||
const lws_cose_key_t *ck);
|
||||
```
|
||||
|
||||
The payload does not have to be provided all at once and can be passed in chunk
|
||||
by chunk over time via `lws_cose_sign_payload_chunk()`.
|
||||
|
||||
Output is mediated via an lws CBOR output context provided in the info at
|
||||
creation-time, it's only emitted during the `lws_cose_sign_payload_chunk()`
|
||||
phase. If it returns `LWS_LECPCTX_RET_AGAIN`, you must call that api again
|
||||
after using the CBOR output context data and resetting its buffer by
|
||||
`lws_lec_setbuf()`, so it can continue to output.
|
||||
|
||||
```
|
||||
enum lws_lec_pctx_ret
|
||||
lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
|
||||
const uint8_t *in, size_t in_len);
|
||||
```
|
||||
|
||||
Finally the signing context is destroyed.
|
||||
|
||||
```
|
||||
void
|
||||
lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
|
||||
```
|
||||
|
|
@ -142,6 +142,7 @@
|
|||
#cmakedefine LWS_WITH_BORINGSSL
|
||||
#cmakedefine LWS_WITH_CGI
|
||||
#cmakedefine LWS_WITH_CONMON
|
||||
#cmakedefine LWS_WITH_COSE
|
||||
#cmakedefine LWS_WITH_CUSTOM_HEADERS
|
||||
#cmakedefine LWS_WITH_DEPRECATED_LWS_DLL
|
||||
#cmakedefine LWS_WITH_DETAILED_LATENCY
|
||||
|
|
|
@ -616,8 +616,11 @@ struct lws;
|
|||
#if defined(LWS_WITH_FILE_OPS)
|
||||
#include <libwebsockets/lws-vfs.h>
|
||||
#endif
|
||||
#include <libwebsockets/lws-gencrypto.h>
|
||||
|
||||
#include <libwebsockets/lws-lejp.h>
|
||||
#include <libwebsockets/lws-lecp.h>
|
||||
#include <libwebsockets/lws-cose.h>
|
||||
#include <libwebsockets/lws-struct.h>
|
||||
#include <libwebsockets/lws-threadpool.h>
|
||||
#include <libwebsockets/lws-tokenize.h>
|
||||
|
@ -647,7 +650,6 @@ struct lws;
|
|||
#include <mbedtls/sha512.h>
|
||||
#endif
|
||||
|
||||
#include <libwebsockets/lws-gencrypto.h>
|
||||
#include <libwebsockets/lws-genhash.h>
|
||||
#include <libwebsockets/lws-genrsa.h>
|
||||
#include <libwebsockets/lws-genaes.h>
|
||||
|
|
511
include/libwebsockets/lws-cose.h
Normal file
511
include/libwebsockets/lws-cose.h
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \defgroup cose COSE apis
|
||||
* ##COSE related functions
|
||||
* \ingroup lwsaoi
|
||||
*
|
||||
* COSE RFC 8152 relates to signed and encrypted CBOR
|
||||
*/
|
||||
//@{
|
||||
|
||||
enum {
|
||||
/* RFC8152: Table 2: Common Header Parameters
|
||||
* https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
|
||||
*/
|
||||
|
||||
LWSCOSE_WKL_ALG = 1, /* int / tstr */
|
||||
LWSCOSE_WKL_CRIT, /* [+ label ] */
|
||||
LWSCOSE_WKL_CONTENT_TYPE, /* tstr / uint */
|
||||
LWSCOSE_WKL_KID, /* bstr */
|
||||
LWSCOSE_WKL_IV, /* bstr */
|
||||
LWSCOSE_WKL_IV_PARTIAL, /* bstr */
|
||||
LWSCOSE_WKL_COUNTERSIG, /* COSE sig(s) */
|
||||
LWSCOSE_WKL_COUNTERSIG0 = 9, /* bstr */
|
||||
LWSCOSE_WKL_KID_CONTEXT, /* bstr */
|
||||
LWSCOSE_WKL_CUPH_NONCE = 256, /* bstr */
|
||||
LWSCOSE_WKL_CUPH_OWNER_PUBKEY = 257, /* array */
|
||||
|
||||
/* RFC8152: Table 3: key map labels */
|
||||
|
||||
LWSCOSE_WKK_KTY = 1, /* int / tstr */
|
||||
LWSCOSE_WKK_KID, /* bstr */
|
||||
LWSCOSE_WKK_ALG, /* int / tstr */
|
||||
LWSCOSE_WKK_KEY_OPS, /* [ + (int / tstr) ] */
|
||||
LWSCOSE_WKK_BASE_IV, /* bstr */
|
||||
|
||||
/* RFC8152: Table 4: Key Operation Values */
|
||||
|
||||
LWSCOSE_WKKO_SIGN = 1,
|
||||
LWSCOSE_WKKO_VERIFY,
|
||||
LWSCOSE_WKKO_ENCRYPT,
|
||||
LWSCOSE_WKKO_DECRYPT,
|
||||
LWSCOSE_WKKO_WRAP_KEY,
|
||||
LWSCOSE_WKKO_UNWRAP_KEY,
|
||||
LWSCOSE_WKKO_DERIVE_KEY,
|
||||
LWSCOSE_WKKO_DERIVE_BITS,
|
||||
LWSCOSE_WKKO_MAC_CREATE,
|
||||
LWSCOSE_WKKO_MAC_VERIFY,
|
||||
|
||||
/* RFC8152: Table 5: ECDSA algs */
|
||||
|
||||
LWSCOSE_WKAECDSA_ALG_ES256 = -7,
|
||||
LWSCOSE_WKAECDSA_ALG_ES384 = -35,
|
||||
LWSCOSE_WKAECDSA_ALG_ES512 = -36,
|
||||
|
||||
/* RFC8152: Table 6: EDDSA algs */
|
||||
|
||||
LWSCOSE_WKAEDDSA_ALG_EDDSA = -8,
|
||||
|
||||
/* RFC8152: Table 7: HMAC algs */
|
||||
|
||||
LWSCOSE_WKAHMAC_256_64 = 4,
|
||||
LWSCOSE_WKAHMAC_256_256,
|
||||
LWSCOSE_WKAHMAC_384_384,
|
||||
LWSCOSE_WKAHMAC_512_512,
|
||||
|
||||
/* RFC8152: Table 8: AES algs */
|
||||
|
||||
LWSCOSE_WKAAES_128_64 = 14,
|
||||
LWSCOSE_WKAAES_256_64,
|
||||
LWSCOSE_WKAAES_128_128 = 25,
|
||||
LWSCOSE_WKAAES_256_128,
|
||||
|
||||
/* RFC8152: Table 9: AES GCM algs */
|
||||
|
||||
LWSCOSE_WKAAESGCM_128 = 1,
|
||||
LWSCOSE_WKAAESGCM_192,
|
||||
LWSCOSE_WKAAESGCM_256,
|
||||
|
||||
/* RFC8152: Table 10: AES CCM algs */
|
||||
|
||||
LWSCOSE_WKAAESCCM_16_64_128 = 10,
|
||||
LWSCOSE_WKAAESCCM_16_64_256,
|
||||
LWSCOSE_WKAAESCCM_64_64_128,
|
||||
LWSCOSE_WKAAESCCM_64_64_256,
|
||||
LWSCOSE_WKAAESCCM_16_128_128,
|
||||
LWSCOSE_WKAAESCCM_16_128_256,
|
||||
LWSCOSE_WKAAESCCM_64_128_128,
|
||||
LWSCOSE_WKAAESCCM_64_128_256,
|
||||
|
||||
/* RFC8152: Table 11: CHACHA20 / Poly1305 */
|
||||
|
||||
LWSCOSE_WKACHACHA_POLY1305 = 24,
|
||||
|
||||
/* RFC8152: Table 13: HKDF param */
|
||||
|
||||
LWSCOSE_WKAPHKDF_SALT = -20,
|
||||
|
||||
/* RFC8152: Table 14: Context Algorithm Parameters */
|
||||
|
||||
LWSCOSE_WKAPCTX_PARTY_U_IDENTITY = -21,
|
||||
LWSCOSE_WKAPCTX_PARTY_U_NONCE = -22,
|
||||
LWSCOSE_WKAPCTX_PARTY_U_OTHER = -23,
|
||||
LWSCOSE_WKAPCTX_PARTY_V_IDENTITY = -24,
|
||||
LWSCOSE_WKAPCTX_PARTY_V_NONCE = -25,
|
||||
LWSCOSE_WKAPCTX_PARTY_V_OTHER = -26,
|
||||
|
||||
/* RFC8152: Table 15: Direct key */
|
||||
|
||||
LWSCOSE_WKK_DIRECT_CEK = -6,
|
||||
|
||||
/* RFC8152: Table 16: Direct key with KDF */
|
||||
|
||||
LWSCOSE_WKK_DIRECT_HKDF_SHA_256 = -10,
|
||||
LWSCOSE_WKK_DIRECT_HKDF_SHA_512 = -11,
|
||||
LWSCOSE_WKK_DIRECT_HKDF_AES_128 = -12,
|
||||
LWSCOSE_WKK_DIRECT_HKDF_AES_256 = -13,
|
||||
|
||||
/* RFC8152: Table 17: AES Key Wrap Algorithm Values */
|
||||
|
||||
LWSCOSE_WKK_DIRECT_HKDFKW_SHA_256 = -3,
|
||||
LWSCOSE_WKK_DIRECT_HKDFKW_SHA_512 = -4,
|
||||
LWSCOSE_WKK_DIRECT_HKDFKW_AES_128 = -5,
|
||||
|
||||
/* RFC8152: Table 18: ECDH Algorithm Values */
|
||||
|
||||
LWSCOSE_WKAECDH_ALG_ES_HKDF_256 = -25,
|
||||
LWSCOSE_WKAECDH_ALG_ES_HKDF_512 = -26,
|
||||
LWSCOSE_WKAECDH_ALG_SS_HKDF_256 = -27,
|
||||
LWSCOSE_WKAECDH_ALG_SS_HKDF_512 = -28,
|
||||
|
||||
/* RFC8152: Table 19: ECDH Algorithm Parameters */
|
||||
|
||||
LWSCOSE_WKAPECDH_EPHEMERAL_KEY = -1,
|
||||
LWSCOSE_WKAPECDH_STATIC_KEY = -2,
|
||||
LWSCOSE_WKAPECDH_STATIC_KEY_ID = -3,
|
||||
|
||||
/* RFC8152: Table 20: ECDH Algorithm Parameters with key wrap */
|
||||
|
||||
LWSCOSE_WKAPECDH_ES_A128KW = -29,
|
||||
LWSCOSE_WKAPECDH_ES_A192KW = -30,
|
||||
LWSCOSE_WKAPECDH_ES_A256KW = -31,
|
||||
LWSCOSE_WKAPECDH_SS_A128KW = -32,
|
||||
LWSCOSE_WKAPECDH_SS_A192KW = -33,
|
||||
LWSCOSE_WKAPECDH_SS_A256KW = -34,
|
||||
|
||||
/* RFC8152: Table 21: Key Type Values
|
||||
* https://www.iana.org/assignments/cose/cose.xhtml#key-type
|
||||
*/
|
||||
|
||||
LWSCOSE_WKKTV_OKP = 1,
|
||||
LWSCOSE_WKKTV_EC2 = 2,
|
||||
LWSCOSE_WKKTV_RSA = 3,
|
||||
LWSCOSE_WKKTV_SYMMETRIC = 4,
|
||||
LWSCOSE_WKKTV_HSS_LMS = 5,
|
||||
LWSCOSE_WKKTV_WALNUTDSA = 6,
|
||||
|
||||
|
||||
/* RFC8152: Table 22: Elliptic Curves
|
||||
* https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
|
||||
*/
|
||||
|
||||
LWSCOSE_WKEC_P256 = 1,
|
||||
LWSCOSE_WKEC_P384,
|
||||
LWSCOSE_WKEC_P521,
|
||||
LWSCOSE_WKEC_X25519,
|
||||
LWSCOSE_WKEC_X448,
|
||||
LWSCOSE_WKEC_ED25519,
|
||||
LWSCOSE_WKEC_ED448,
|
||||
LWSCOSE_WKEC_SECP256K1,
|
||||
|
||||
/* RFC8152: Table 23: EC Key Parameters */
|
||||
|
||||
LWSCOSE_WKECKP_CRV = -1,
|
||||
LWSCOSE_WKECKP_X = -2,
|
||||
LWSCOSE_WKECKP_Y = -3,
|
||||
LWSCOSE_WKECKP_D = -4,
|
||||
|
||||
/* RFC8152: Table 24: Octet Key Pair (OKP) Parameters */
|
||||
|
||||
LWSCOSE_WKOKP_CRV = -1,
|
||||
LWSCOSE_WKOKP_X = -2,
|
||||
LWSCOSE_WKOKP_D = -4,
|
||||
|
||||
/* Additional from
|
||||
* https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters
|
||||
*/
|
||||
|
||||
LWSCOSE_WKKPRSA_N = -1,
|
||||
LWSCOSE_WKKPRSA_E = -2,
|
||||
LWSCOSE_WKKPRSA_D = -3,
|
||||
LWSCOSE_WKKPRSA_P = -4,
|
||||
LWSCOSE_WKKPRSA_Q = -5,
|
||||
LWSCOSE_WKKPRSA_DP = -6,
|
||||
LWSCOSE_WKKPRSA_DQ = -7,
|
||||
LWSCOSE_WKKPRSA_QINV = -8,
|
||||
LWSCOSE_WKKPRSA_OTHER = -9,
|
||||
LWSCOSE_WKKPRSA_RI = -10,
|
||||
LWSCOSE_WKKPRSA_DI = -11,
|
||||
LWSCOSE_WKKPRSA_TI = -12,
|
||||
|
||||
/* RFC8152: Table 25: Symmetric Key Parameters */
|
||||
|
||||
LWSCOSE_WKSYMKP_KEY_VALUE = 4,
|
||||
|
||||
/* RFC8152: Table 26: CoAP Content-Formats for COSE */
|
||||
|
||||
LWSCOAP_CONTENTFORMAT_COSE_SIGN = 98,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_SIGN1 = 18,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT = 96,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT0 = 16,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_MAC = 97,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_MAC0 = 17,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_KEY = 101,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_KEY_SET = 102,
|
||||
|
||||
/* RFC8152: Table 27: Header Parameter for CounterSignature0 */
|
||||
|
||||
LWSCOSE_WKL_COUNTERSIGNATURE0 = 9, /* bstr */
|
||||
|
||||
/* RFC8812: Table 1: RSASSA-PKCS1-v1_5 Algorithm Values */
|
||||
|
||||
LWSCOSE_WKARSA_ALG_RS256 = -257, /* + SHA-256 */
|
||||
LWSCOSE_WKARSA_ALG_RS384 = -258, /* + SHA-384 */
|
||||
LWSCOSE_WKARSA_ALG_RS512 = -259, /* + SHA-512 */
|
||||
};
|
||||
|
||||
enum enum_cose_key_meta_tok {
|
||||
COSEKEY_META_KTY,
|
||||
COSEKEY_META_KID,
|
||||
COSEKEY_META_KEY_OPS,
|
||||
COSEKEY_META_BASE_IV,
|
||||
COSEKEY_META_ALG,
|
||||
|
||||
LWS_COUNT_COSE_KEY_ELEMENTS
|
||||
};
|
||||
|
||||
typedef int64_t cose_param_t;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_cose_alg_to_name(cose_param_t alg);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN cose_param_t
|
||||
lws_cose_name_to_alg(const char *name);
|
||||
|
||||
/*
|
||||
* cose_key
|
||||
*/
|
||||
|
||||
typedef struct lws_cose_key {
|
||||
/* key data elements */
|
||||
struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
|
||||
/* generic meta key elements, like KID */
|
||||
struct lws_gencrypto_keyelem meta[LWS_COUNT_COSE_KEY_ELEMENTS];
|
||||
lws_dll2_t list; /* used when part of a set */
|
||||
int gencrypto_kty; /**< one of LWS_GENCRYPTO_KTY_ */
|
||||
cose_param_t kty;
|
||||
cose_param_t cose_alg;
|
||||
cose_param_t cose_curve;
|
||||
char private_key; /* nonzero = has private key elements */
|
||||
} lws_cose_key_t;
|
||||
|
||||
typedef int (*lws_cose_key_import_callback)(struct lws_cose_key *s, void *user);
|
||||
|
||||
/** lws_cose_jwk_import() - Create an lws_cose_key_t object from cose_key CBOR
|
||||
*
|
||||
* \param pkey_set: NULL, or a pointer to an lws_dll2_owner_t for a cose_key set
|
||||
* \param cb: callback for each jwk-processed key, or NULL if importing a single
|
||||
* key with no parent "keys" JSON
|
||||
* \param user: pointer to be passed to the callback, otherwise ignored by lws.
|
||||
* NULL if importing a single key with no parent "keys" JSON
|
||||
* \param in: a single cose_key
|
||||
* \param len: the length of the cose_key in bytes
|
||||
*
|
||||
* Creates a single lws_cose_key_t if \p pkey_set is NULL or if the incoming
|
||||
* CBOR doesn't start with an array, otherwise expects a CBOR array containing
|
||||
* zero or more cose_key CBOR, and adds each to the \p pkey_set
|
||||
* lws_dll2_owner_t struct. Created lws_cose_key_t are filled with data from
|
||||
* the COSE representation and can be used with other COSE crypto ops.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
|
||||
lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
|
||||
void *user, const uint8_t *in, size_t len);
|
||||
|
||||
/** lws_cose_key_export() - Create cose_key CBOR from an lws_cose_key_t
|
||||
*
|
||||
* \param ck: the lws_cose_key_t to export to CBOR
|
||||
* \param ctx: the CBOR writing context (same as for lws_lec_printf())
|
||||
* \param flags: 0 to export only public elements, or LWSJWKF_EXPORT_PRIVATE
|
||||
*
|
||||
* Creates an lws_jwk struct filled with data from the COSE representation.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
|
||||
lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
|
||||
|
||||
/**
|
||||
* lws_cose_key_generate() - generate a fresh key
|
||||
*
|
||||
* \param context: the lws_context used to get random
|
||||
* \param cose_kty: one of LWSCOSE_WKKTV_ indicating the well-known key type
|
||||
* \param use_mask: 0, or a bitfield where (1 << LWSCOSE_WKKO_...) set means valid for use
|
||||
* \param bits: key bits for RSA
|
||||
* \param curve: for EC keys, one of "P-256", "P-384" or "P-521" currently
|
||||
* \param kid: string describing the key, or NULL
|
||||
*
|
||||
* Create an lws_cose_key_t of the specified type and return it
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
|
||||
lws_cose_key_generate(struct lws_context *context, cose_param_t cose_kty,
|
||||
int use_mask, int bits, const char *curve,
|
||||
const uint8_t *kid, size_t kl);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
|
||||
lws_cose_key_from_set(lws_dll2_owner_t *set, const uint8_t *kid, size_t kl);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_cose_key_destroy(lws_cose_key_t **ck);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_cose_key_set_destroy(lws_dll2_owner_t *o);
|
||||
|
||||
/* only available in _DEBUG build */
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_cose_key_dump(const lws_cose_key_t *ck);
|
||||
|
||||
/*
|
||||
* cose_sign
|
||||
*/
|
||||
|
||||
struct lws_cose_validate_context;
|
||||
|
||||
|
||||
enum lws_cose_sig_types {
|
||||
SIGTYPE_UNKNOWN,
|
||||
SIGTYPE_MULTI,
|
||||
SIGTYPE_SINGLE,
|
||||
SIGTYPE_COUNTERSIGNED, /* not yet supported */
|
||||
SIGTYPE_MAC, /* only supported for validation */
|
||||
SIGTYPE_MAC0,
|
||||
};
|
||||
|
||||
/* a list of these result objects is the output of the validation process */
|
||||
|
||||
typedef struct {
|
||||
lws_dll2_t list;
|
||||
|
||||
const lws_cose_key_t *cose_key;
|
||||
cose_param_t cose_alg;
|
||||
|
||||
int result; /* 0 = validated */
|
||||
|
||||
} lws_cose_validate_res_t;
|
||||
|
||||
enum {
|
||||
LCOSESIGEXTCB_RET_FINISHED,
|
||||
LCOSESIGEXTCB_RET_AGAIN,
|
||||
LCOSESIGEXTCB_RET_ERROR = -1
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct lws_cose_validate_context *cps;
|
||||
const uint8_t *ext;
|
||||
size_t xl;
|
||||
} lws_cose_sig_ext_pay_t;
|
||||
|
||||
typedef int (*lws_cose_sign_ext_pay_cb_t)(lws_cose_sig_ext_pay_t *x);
|
||||
typedef int (*lws_cose_validate_pay_cb_t)(struct lws_cose_validate_context *cps,
|
||||
void *opaque, const uint8_t *paychunk,
|
||||
size_t paychunk_len);
|
||||
|
||||
typedef struct lws_cose_validate_create_info {
|
||||
struct lws_context *cx;
|
||||
/**< REQUIRED: the lws context */
|
||||
lws_dll2_owner_t *keyset;
|
||||
/**< REQUIRED: one or more cose_keys */
|
||||
|
||||
enum lws_cose_sig_types sigtype;
|
||||
/**< 0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
|
||||
* SIGTYPE_SINGLE, etc*/
|
||||
|
||||
lws_cose_validate_pay_cb_t pay_cb;
|
||||
/**< optional: called back with unvalidated payload pieces */
|
||||
void *pay_opaque;
|
||||
/**< optional: passed into pay_cb callback along with payload chunk */
|
||||
|
||||
lws_cose_sign_ext_pay_cb_t ext_cb;
|
||||
/**< optional extra application data provision callback */
|
||||
void *ext_opaque;
|
||||
/**< optional extra application data provision callback opaque */
|
||||
size_t ext_len;
|
||||
/**< if we have extra app data, this must be set to the length of it */
|
||||
} lws_cose_validate_create_info_t;
|
||||
|
||||
/**
|
||||
* lws_cose_validate_create() - create a signature validation context
|
||||
*
|
||||
* \param info: struct describing the validation context to create
|
||||
*
|
||||
* Creates a signature validation context set up as described in \p info.
|
||||
*
|
||||
* You can then pass the signature cbor chunks to it using
|
||||
* lws_cose_validate_chunk(), finialize and get the results list using
|
||||
* lws_cose_validate_results() and destroy with lws_cose_validate_destroy().
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_cose_validate_context *
|
||||
lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
|
||||
|
||||
/**
|
||||
* lws_cose_validate_chunk() - passes chunks of CBOR into the signature validator
|
||||
*
|
||||
* \param cps: the validation context
|
||||
* \param in: the chunk of CBOR (does not have to be logically complete)
|
||||
* \param in_len: number of bytes available at \p in
|
||||
*
|
||||
* Parses signature CBOR to produce a list of result objects.
|
||||
*
|
||||
*
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
|
||||
const uint8_t *in, size_t in_len, size_t *used_in);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN lws_dll2_owner_t *
|
||||
lws_cose_validate_results(struct lws_cose_validate_context *cps);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
|
||||
|
||||
struct lws_cose_sign_context;
|
||||
|
||||
#define LCSC_FL_ADD_CBOR_TAG (1 << 0)
|
||||
#define LCSC_FL_ADD_CBOR_PREFER_MAC0 (1 << 1)
|
||||
|
||||
typedef struct lws_cose_sign_create_info {
|
||||
struct lws_context *cx;
|
||||
/**< REQUIRED: the lws context */
|
||||
lws_dll2_owner_t *keyset;
|
||||
/**< REQUIRED: one or more cose_keys */
|
||||
|
||||
lws_lec_pctx_t *lec;
|
||||
/**< REQUIRED: the cbor output context to emit to, user must
|
||||
* initialize with lws_lec_init() beforehand */
|
||||
|
||||
lws_cose_sign_ext_pay_cb_t ext_cb;
|
||||
/**< optional extra application data provision callback */
|
||||
void *ext_opaque;
|
||||
/**< optional extra application data provision callback opaque */
|
||||
size_t ext_len;
|
||||
/**< if we have extra app data, this must be set to the length of it */
|
||||
|
||||
size_t inline_payload_len;
|
||||
/**< REQUIRED: size of the inline payload we will provide */
|
||||
|
||||
int flags;
|
||||
/**< bitmap of LCSC_FL_* */
|
||||
enum lws_cose_sig_types sigtype;
|
||||
/**< 0, or sign type hint */
|
||||
} lws_cose_sign_create_info_t;
|
||||
|
||||
/**
|
||||
* lws_cose_sign_create() - Create a signing context
|
||||
*
|
||||
* \param info: a structure describing the signing context you want to create
|
||||
*
|
||||
* This allocates and returns a signing context created according to what is in
|
||||
* the \p info parameter.
|
||||
*
|
||||
* \p info must be prepared with the lws_context, a keyset to use, a CBOR
|
||||
* output context, and the inline payload length.
|
||||
*
|
||||
* Returns NULL on failure or the created signing context ready to add alg(s)
|
||||
* to.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_cose_sign_context *
|
||||
lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
|
||||
const lws_cose_key_t *ck);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
|
||||
lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
|
||||
const uint8_t *in, size_t in_len);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
|
||||
|
||||
//@}
|
|
@ -59,6 +59,13 @@ enum lws_gencrypto_rsa_tok {
|
|||
LWS_GENCRYPTO_RSA_KEYEL_DQ,
|
||||
LWS_GENCRYPTO_RSA_KEYEL_QI,
|
||||
|
||||
/* we don't actively use these if given, but may come from COSE */
|
||||
|
||||
LWS_GENCRYPTO_RSA_KEYEL_OTHER,
|
||||
LWS_GENCRYPTO_RSA_KEYEL_RI,
|
||||
LWS_GENCRYPTO_RSA_KEYEL_DI,
|
||||
LWS_GENCRYPTO_RSA_KEYEL_TI,
|
||||
|
||||
LWS_GENCRYPTO_RSA_KEYEL_COUNT
|
||||
};
|
||||
|
||||
|
@ -89,10 +96,10 @@ enum lws_gencrypto_aes_tok {
|
|||
* type.
|
||||
*/
|
||||
|
||||
struct lws_gencrypto_keyelem {
|
||||
typedef struct lws_gencrypto_keyelem {
|
||||
uint8_t *buf;
|
||||
uint32_t len;
|
||||
};
|
||||
} lws_gc_elem_t;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -147,7 +147,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
|
||||
struct lws_gencrypto_keyelem *el);
|
||||
const struct lws_gencrypto_keyelem *el);
|
||||
|
||||
/** lws_genecdsa_hash_sig_verify_jws() - Verifies a JWS ECDSA signature on a given hash
|
||||
*
|
||||
|
|
|
@ -74,7 +74,8 @@ struct lws_genrsa_ctx {
|
|||
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx,
|
||||
const struct lws_gencrypto_keyelem *el,
|
||||
struct lws_context *context, enum enum_genrsa_mode mode,
|
||||
enum lws_genhash_types oaep_hashid);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ struct lws_jwk {
|
|||
struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
|
||||
/* generic meta key elements, like KID */
|
||||
struct lws_gencrypto_keyelem meta[LWS_COUNT_JWK_ELEMENTS];
|
||||
int kty; /**< one of LWS_JWK_ */
|
||||
int kty; /**< one of LWS_GENCRYPTO_KTY_ */
|
||||
char private_key; /* nonzero = has private key elements */
|
||||
};
|
||||
|
||||
|
@ -64,6 +64,8 @@ struct lws_jwk_parse_state {
|
|||
lws_jwk_key_import_callback per_key_cb;
|
||||
void *user;
|
||||
int pos;
|
||||
int cose_state;
|
||||
int seen;
|
||||
unsigned short possible;
|
||||
};
|
||||
|
||||
|
|
|
@ -146,6 +146,10 @@ endif()
|
|||
if (LWS_WITH_JOSE)
|
||||
add_subdir_include_dirs(jose)
|
||||
endif()
|
||||
if (LWS_WITH_COSE)
|
||||
add_subdir_include_dirs(cose)
|
||||
endif()
|
||||
|
||||
|
||||
if (LWS_WITH_SECURE_STREAMS)
|
||||
add_subdir_include_dirs(secure-streams)
|
||||
|
|
|
@ -950,6 +950,15 @@ lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
|
|||
int alloc_file(struct lws_context *context, const char *filename,
|
||||
uint8_t **buf, lws_filepos_t *amount);
|
||||
|
||||
int
|
||||
lws_lec_scratch(lws_lec_pctx_t *ctx);
|
||||
void
|
||||
lws_lec_signed(lws_lec_pctx_t *ctx, int64_t num);
|
||||
|
||||
int
|
||||
lws_cose_key_checks(const lws_cose_key_t *key, int64_t kty, int64_t alg,
|
||||
int key_op, const char *crv);
|
||||
|
||||
void lws_msleep(unsigned int);
|
||||
|
||||
void
|
||||
|
|
39
lib/cose/CMakeLists.txt
Normal file
39
lib/cose/CMakeLists.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
if (LWS_WITH_COSE)
|
||||
list(APPEND SOURCES
|
||||
cose/cose_key.c
|
||||
cose/cose_validate.c
|
||||
cose/cose_validate_alg.c
|
||||
cose/cose_sign.c
|
||||
cose/cose_sign_alg.c
|
||||
)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
1188
lib/cose/cose_key.c
Normal file
1188
lib/cose/cose_key.c
Normal file
File diff suppressed because it is too large
Load diff
536
lib/cose/cose_sign.c
Normal file
536
lib/cose/cose_sign.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-cose.h"
|
||||
|
||||
struct lws_cose_sign_context *
|
||||
lws_cose_sign_create(const lws_cose_sign_create_info_t *info)
|
||||
{
|
||||
struct lws_cose_sign_context *csc;
|
||||
|
||||
/* you have to have prepared a cbor output context for us to use */
|
||||
assert(info->lec);
|
||||
/* you have to provide at least one key in a cose_keyset */
|
||||
assert(info->keyset);
|
||||
/* you have to provide an lws_context (for crypto random) */
|
||||
assert(info->cx);
|
||||
|
||||
if (info->sigtype == SIGTYPE_MAC) {
|
||||
lwsl_err("%s: only mac0 supported for signing\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
csc = lws_zalloc(sizeof(*csc), __func__);
|
||||
if (!csc)
|
||||
return NULL;
|
||||
|
||||
csc->info = *info;
|
||||
|
||||
return csc;
|
||||
}
|
||||
|
||||
int
|
||||
lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
|
||||
const lws_cose_key_t *ck)
|
||||
{
|
||||
lws_cose_sig_alg_t *si = lws_cose_sign_alg_create(csc->info.cx, ck, alg,
|
||||
LWSCOSE_WKKO_SIGN);
|
||||
|
||||
if (!si)
|
||||
return 1;
|
||||
|
||||
lws_dll2_add_tail(&si->list, &csc->algs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static signed char cose_tags[] = {
|
||||
0,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_SIGN,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_SIGN1,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_SIGN,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_MAC,
|
||||
LWSCOAP_CONTENTFORMAT_COSE_MAC0
|
||||
};
|
||||
|
||||
static void
|
||||
lws_cose_sign_hashing(struct lws_cose_sign_context *csc,
|
||||
const uint8_t *in, size_t in_len)
|
||||
{
|
||||
//lwsl_hexdump_warn(in, in_len);
|
||||
|
||||
assert(in_len);
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
lws_dll2_get_head(&csc->algs)) {
|
||||
lws_cose_sig_alg_t *alg = lws_container_of(p,
|
||||
lws_cose_sig_alg_t, list);
|
||||
|
||||
if (lws_cose_sign_alg_hash(alg, in, in_len))
|
||||
alg->failed = 1;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* These chunks may be payload or application AAD being emitted into the
|
||||
* signed object somewhere else. But we do not emit them ourselves here
|
||||
* (since other non-emitted things are also hashed by us) and so can always
|
||||
* deal with the whole in_len in one step.
|
||||
*/
|
||||
|
||||
enum lws_lec_pctx_ret
|
||||
lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
|
||||
const uint8_t *in, size_t in_len)
|
||||
{
|
||||
uint8_t lbuf[MAX_BLOBBED_PARAMS], lb[9];
|
||||
const struct lws_gencrypto_keyelem *ke;
|
||||
enum lws_lec_pctx_ret ret;
|
||||
lws_lec_pctx_t lec, lec1;
|
||||
lws_cose_sig_alg_t *alg;
|
||||
uint8_t c;
|
||||
size_t s;
|
||||
|
||||
switch (csc->tli) {
|
||||
case ST_UNKNOWN:
|
||||
/*
|
||||
* We need to figure out what signing structure we need to use,
|
||||
* given the algorithms that are in it. So let's have a look
|
||||
* and decide.
|
||||
*/
|
||||
|
||||
if (!csc->algs.count) {
|
||||
lwsl_err("%s: must add at least one signature\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
csc->type = SIGTYPE_MULTI;
|
||||
alg = lws_container_of(csc->algs.head, lws_cose_sig_alg_t, list);
|
||||
|
||||
switch (alg->cose_alg) {
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
// if (csc->info.sigtype == SIGTYPE_MAC0)
|
||||
csc->type = SIGTYPE_MAC0;
|
||||
// else
|
||||
// csc->type = SIGTYPE_MAC;
|
||||
break;
|
||||
}
|
||||
|
||||
if (csc->algs.count == 1) {
|
||||
if (!csc->info.sigtype && csc->type == SIGTYPE_MAC) {
|
||||
if (csc->info.flags & LCSC_FL_ADD_CBOR_PREFER_MAC0)
|
||||
csc->type = SIGTYPE_MAC0;
|
||||
} else
|
||||
if (!csc->info.sigtype ||
|
||||
csc->info.sigtype == SIGTYPE_SINGLE) /* ie, if no hint */
|
||||
csc->type = SIGTYPE_SINGLE;
|
||||
}
|
||||
|
||||
lwsl_notice("%s: decided on type %d\n", __func__, csc->type);
|
||||
|
||||
/*
|
||||
* Start emitting the appropriate tag if that's requested
|
||||
*/
|
||||
|
||||
if (csc->info.flags & LCSC_FL_ADD_CBOR_TAG) {
|
||||
ret = lws_lec_printf(csc->info.lec, "%t(",
|
||||
cose_tags[csc->type]);
|
||||
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The */
|
||||
c = 0;
|
||||
switch (csc->type) {
|
||||
case SIGTYPE_MAC0:
|
||||
case SIGTYPE_MULTI:
|
||||
case SIGTYPE_SINGLE:
|
||||
c = 0x84;
|
||||
break;
|
||||
case SIGTYPE_MAC:
|
||||
c = 0x85;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* The outer array */
|
||||
csc->info.lec->scratch[csc->info.lec->scratch_len++] = c;
|
||||
|
||||
/*
|
||||
* Then, let's start hashing with the sigtype constant part
|
||||
*/
|
||||
|
||||
lws_cose_sign_hashing(csc, sig_mctx[csc->type],
|
||||
sig_mctx_len[csc->type]);
|
||||
|
||||
csc->tli = ST_OUTER_PROTECTED;
|
||||
csc->subsequent = 0;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_OUTER_PROTECTED:
|
||||
|
||||
/*
|
||||
* We need to list and emit any outer protected data as a map
|
||||
* into its own buffer, then emit that into the output as a bstr
|
||||
*/
|
||||
|
||||
switch (csc->type) {
|
||||
case SIGTYPE_SINGLE:
|
||||
case SIGTYPE_MAC0:
|
||||
alg = lws_container_of(csc->algs.head,
|
||||
lws_cose_sig_alg_t, list);
|
||||
|
||||
lws_lec_init(&lec, lbuf, sizeof(lbuf));
|
||||
|
||||
/* we know it will fit */
|
||||
lws_lec_printf(&lec, "{1:%lld}",
|
||||
(long long)alg->cose_alg);
|
||||
lws_lec_scratch(&lec);
|
||||
|
||||
if (!csc->subsequent) {
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
|
||||
lec.used);
|
||||
lws_cose_sign_hashing(csc, lec1.scratch,
|
||||
lec1.scratch_len);
|
||||
lws_cose_sign_hashing(csc, lec.start, lec.used);
|
||||
ret = lws_lec_printf(csc->info.lec, "%.*b",
|
||||
(int)lec.used, lec.start);
|
||||
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
csc->subsequent = 1;
|
||||
}
|
||||
break;
|
||||
case SIGTYPE_MAC:
|
||||
case SIGTYPE_MULTI:
|
||||
lws_lec_init(&lec, lbuf, sizeof(lbuf));
|
||||
lws_lec_int(&lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
|
||||
lws_lec_scratch(&lec);
|
||||
lec.used = lws_ptr_diff_size_t(lec.buf, lec.start);
|
||||
lws_cose_sign_hashing(csc, lec.start,
|
||||
lec.used);
|
||||
break;
|
||||
default:
|
||||
lec.used = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
csc->tli = ST_OUTER_UNPROTECTED;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_OUTER_UNPROTECTED:
|
||||
|
||||
/*
|
||||
* We need to list and emit any outer unprotected data, as
|
||||
* an inline cbor map
|
||||
*/
|
||||
|
||||
switch (csc->type) {
|
||||
case SIGTYPE_SINGLE:
|
||||
case SIGTYPE_MAC0:
|
||||
alg = lws_container_of(csc->algs.head,
|
||||
lws_cose_sig_alg_t, list);
|
||||
ke = &alg->cose_key->meta[COSEKEY_META_KID];
|
||||
if (ke->len) {
|
||||
ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
|
||||
LWSCOSE_WKL_KID,
|
||||
(int)ke->len, ke->buf);
|
||||
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
}
|
||||
/* hack for no extra data */
|
||||
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
|
||||
lws_cose_sign_hashing(csc, lec1.scratch,
|
||||
lec1.scratch_len);
|
||||
break;
|
||||
case SIGTYPE_MAC:
|
||||
case SIGTYPE_MULTI:
|
||||
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
|
||||
|
||||
/*
|
||||
* For cose-sign, we need to feed each sig alg its alg-
|
||||
* specific protected data into the hash before letting
|
||||
* all the hashes see the payload
|
||||
*/
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
lws_dll2_get_head(&csc->algs)) {
|
||||
alg = lws_container_of(p, lws_cose_sig_alg_t, list);
|
||||
|
||||
lws_lec_init(&lec, lbuf, sizeof(lbuf));
|
||||
|
||||
/* we know it will fit */
|
||||
lws_lec_printf(&lec, "{1:%lld}",
|
||||
(long long)alg->cose_alg);
|
||||
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
|
||||
lec.used);
|
||||
|
||||
// lwsl_hexdump_warn(lec1.scratch, lec1.scratch_len);
|
||||
// lwsl_hexdump_warn(lec.start, lec.used);
|
||||
if (lws_cose_sign_alg_hash(alg, lec1.scratch,
|
||||
lec1.scratch_len))
|
||||
alg->failed = 1;
|
||||
if (lws_cose_sign_alg_hash(alg, lec.start,
|
||||
lec.used))
|
||||
alg->failed = 1;
|
||||
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
|
||||
lws_cose_sign_hashing(csc, lec1.scratch,
|
||||
lec1.scratch_len);
|
||||
|
||||
break;
|
||||
default:
|
||||
ret = lws_lec_printf(csc->info.lec, "{}");
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
csc->tli = ST_OUTER_PAYLOAD;
|
||||
csc->subsequent = 0;
|
||||
|
||||
/* Prepare the payload BSTR */
|
||||
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0,
|
||||
csc->info.inline_payload_len);
|
||||
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
|
||||
csc->info.inline_payload_len);
|
||||
lws_cose_sign_hashing(csc, lec1.scratch,
|
||||
lec1.scratch_len);
|
||||
|
||||
lws_lec_scratch(csc->info.lec);
|
||||
|
||||
csc->rem_pay = csc->info.inline_payload_len;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_OUTER_PAYLOAD:
|
||||
|
||||
if (csc->along) {
|
||||
in += csc->along;
|
||||
in_len -= csc->along;
|
||||
}
|
||||
|
||||
lws_lec_scratch(csc->info.lec);
|
||||
|
||||
if (csc->rem_pay) {
|
||||
|
||||
lws_cose_sign_hashing(csc, in, in_len);
|
||||
|
||||
/*
|
||||
* in / in_len is the payload chunk
|
||||
*/
|
||||
|
||||
s = lws_ptr_diff_size_t(csc->info.lec->end,
|
||||
csc->info.lec->buf);
|
||||
if (s > (size_t)csc->rem_pay)
|
||||
s = (size_t)csc->rem_pay;
|
||||
if (s > in_len)
|
||||
s = in_len;
|
||||
|
||||
memcpy(csc->info.lec->buf, in, s);
|
||||
csc->info.lec->buf += s;
|
||||
csc->info.lec->used = lws_ptr_diff_size_t(
|
||||
csc->info.lec->buf,
|
||||
csc->info.lec->start);
|
||||
csc->rem_pay -= s;
|
||||
|
||||
csc->along = s;
|
||||
|
||||
return LWS_LECPCTX_RET_AGAIN;
|
||||
}
|
||||
|
||||
/* finished with rem_pay */
|
||||
|
||||
if (csc->type == SIGTYPE_MULTI) {
|
||||
|
||||
csc->alg = lws_container_of(csc->algs.head,
|
||||
lws_cose_sig_alg_t, list);
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
|
||||
csc->algs.count);
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
|
||||
csc->algs.count);
|
||||
csc->tli = ST_INNER_PROTECTED;
|
||||
goto inner_protected;
|
||||
}
|
||||
csc->tli = ST_OUTER_SIGN1_SIGNATURE;
|
||||
csc->along = 0;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_OUTER_SIGN1_SIGNATURE:
|
||||
|
||||
alg = lws_container_of(lws_dll2_get_head(&csc->algs),
|
||||
lws_cose_sig_alg_t, list);
|
||||
|
||||
if (!alg->completed)
|
||||
lws_cose_sign_alg_complete(alg);
|
||||
if (alg->failed)
|
||||
return LWS_LECPCTX_RET_FAIL;
|
||||
|
||||
ret = lws_lec_printf(csc->info.lec, "%.*b",
|
||||
(int)alg->rhash_len, alg->rhash);
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
|
||||
if (csc->type == SIGTYPE_MAC) {
|
||||
csc->alg = lws_container_of(csc->algs.head,
|
||||
lws_cose_sig_alg_t, list);
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
|
||||
csc->algs.count);
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
|
||||
csc->algs.count);
|
||||
csc->tli = ST_INNER_PROTECTED;
|
||||
goto inner_protected;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ST_INNER_PROTECTED:
|
||||
inner_protected:
|
||||
|
||||
/*
|
||||
* We need to list and emit any outer protected data as a map
|
||||
* into its own buffer, then emit that into the output as a bstr
|
||||
*/
|
||||
|
||||
switch (csc->type) {
|
||||
case SIGTYPE_MAC:
|
||||
case SIGTYPE_MULTI:
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
|
||||
|
||||
lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
|
||||
|
||||
lws_lec_init(&lec, lbuf, sizeof(lbuf));
|
||||
|
||||
/* we know it will fit */
|
||||
lws_lec_printf(&lec, "{1:%lld}",
|
||||
(long long)csc->alg->cose_alg);
|
||||
|
||||
lws_lec_init(&lec1, lb, sizeof(lb));
|
||||
lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
|
||||
lec.used);
|
||||
lws_lec_printf(csc->info.lec, "{1:%lld}",
|
||||
(long long)csc->alg->cose_alg);
|
||||
break;
|
||||
default:
|
||||
lec.used = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
csc->tli = ST_INNER_UNPROTECTED;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_INNER_UNPROTECTED:
|
||||
|
||||
switch (csc->type) {
|
||||
case SIGTYPE_MULTI:
|
||||
alg = lws_container_of(csc->algs.head,
|
||||
lws_cose_sig_alg_t, list);
|
||||
ke = &alg->cose_key->meta[COSEKEY_META_KID];
|
||||
if (ke->len) {
|
||||
ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
|
||||
LWSCOSE_WKL_KID,
|
||||
(int)ke->len, ke->buf);
|
||||
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = lws_lec_printf(csc->info.lec, "{}");
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
lws_cose_sign_alg_complete(csc->alg);
|
||||
if (csc->alg->failed)
|
||||
return LWS_LECPCTX_RET_FAIL;
|
||||
csc->tli = ST_INNER_SIGNATURE;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case ST_INNER_SIGNATURE:
|
||||
|
||||
ret = lws_lec_printf(csc->info.lec, "%.*b",
|
||||
(int)csc->alg->rhash_len, csc->alg->rhash);
|
||||
if (ret != LWS_LECPCTX_RET_FINISHED)
|
||||
return ret;
|
||||
|
||||
if (csc->alg->list.next) {
|
||||
csc->alg = (lws_cose_sig_alg_t *)csc->alg->list.next;
|
||||
csc->tli = ST_INNER_PROTECTED;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_cose_sign_destroy(struct lws_cose_sign_context **_csc)
|
||||
{
|
||||
struct lws_cose_sign_context *csc = *_csc;
|
||||
|
||||
if (!csc)
|
||||
return;
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
lws_dll2_get_head(&csc->algs)) {
|
||||
lws_cose_sig_alg_t *alg = lws_container_of(p,
|
||||
lws_cose_sig_alg_t, list);
|
||||
|
||||
lws_dll2_remove(p);
|
||||
lws_cose_sign_alg_destroy(&alg);
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
lws_free_set_NULL(*_csc);
|
||||
}
|
271
lib/cose/cose_sign_alg.c
Normal file
271
lib/cose/cose_sign_alg.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-cose.h"
|
||||
|
||||
lws_cose_sig_alg_t *
|
||||
lws_cose_sign_alg_create(struct lws_context *cx, const lws_cose_key_t *ck,
|
||||
cose_param_t cose_alg, int op)
|
||||
{
|
||||
lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__);
|
||||
const struct lws_gencrypto_keyelem *ke;
|
||||
enum lws_genhmac_types ghm;
|
||||
enum lws_genhash_types gh;
|
||||
const char *crv;
|
||||
|
||||
if (!alg)
|
||||
return NULL;
|
||||
|
||||
alg->cose_alg = cose_alg;
|
||||
alg->cose_key = ck;
|
||||
|
||||
switch (cose_alg) {
|
||||
|
||||
/* ECDSA algs */
|
||||
|
||||
case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
|
||||
crv = "P-256";
|
||||
gh = LWS_GENHASH_TYPE_SHA256;
|
||||
alg->keybits = 256;
|
||||
goto ecdsa;
|
||||
case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
|
||||
crv = "P-384";
|
||||
gh = LWS_GENHASH_TYPE_SHA384;
|
||||
alg->keybits = 384;
|
||||
goto ecdsa;
|
||||
case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
|
||||
crv = "P-521";
|
||||
gh = LWS_GENHASH_TYPE_SHA512;
|
||||
alg->keybits = 521;
|
||||
ecdsa:
|
||||
|
||||
/* the key is good for this? */
|
||||
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg,
|
||||
op, crv))
|
||||
goto bail_ecdsa;
|
||||
|
||||
if (lws_genhash_init(&alg->hash_ctx, gh))
|
||||
goto bail_ecdsa;
|
||||
|
||||
if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) {
|
||||
lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
|
||||
__func__);
|
||||
goto bail_ecdsa1;
|
||||
}
|
||||
|
||||
if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) {
|
||||
lwsl_notice("%s: ec key import fail\n", __func__);
|
||||
goto bail_ecdsa2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* HMAC algs */
|
||||
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA256;
|
||||
alg->keybits = 64;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA256;
|
||||
alg->keybits = 256;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA384;
|
||||
alg->keybits = 384;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA512;
|
||||
alg->keybits = 512;
|
||||
|
||||
hmac:
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC,
|
||||
cose_alg, op, NULL))
|
||||
goto bail_hmac;
|
||||
|
||||
ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
|
||||
if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len))
|
||||
goto bail_hmac;
|
||||
|
||||
break;
|
||||
|
||||
/* RSASSA algs */
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS256:
|
||||
gh = LWS_GENHASH_TYPE_SHA256;
|
||||
goto rsassa;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS384:
|
||||
gh = LWS_GENHASH_TYPE_SHA384;
|
||||
goto rsassa;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS512:
|
||||
gh = LWS_GENHASH_TYPE_SHA512;
|
||||
|
||||
rsassa:
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg,
|
||||
op, NULL))
|
||||
goto bail_hmac;
|
||||
|
||||
alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8;
|
||||
|
||||
if (lws_genhash_init(&alg->hash_ctx, gh))
|
||||
goto bail_hmac;
|
||||
|
||||
if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx,
|
||||
LGRSAM_PKCS1_1_5, gh)) {
|
||||
lwsl_notice("%s: lws_genrsa_create fail\n", __func__);
|
||||
goto bail_hmac;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_warn("%s: unsupported alg %lld\n", __func__,
|
||||
(long long)cose_alg);
|
||||
goto bail_hmac;
|
||||
}
|
||||
|
||||
return alg;
|
||||
|
||||
bail_ecdsa2:
|
||||
lws_genec_destroy(&alg->u.ecdsactx);
|
||||
bail_ecdsa1:
|
||||
lws_genhash_destroy(&alg->hash_ctx, NULL);
|
||||
bail_ecdsa:
|
||||
lws_free(alg);
|
||||
|
||||
return NULL;
|
||||
|
||||
bail_hmac:
|
||||
lws_free(alg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_cose_sign_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len)
|
||||
{
|
||||
#if defined(VERBOSE)
|
||||
lwsl_hexdump_warn(in, in_len);
|
||||
#endif
|
||||
|
||||
switch (alg->cose_alg) {
|
||||
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
return lws_genhmac_update(&alg->u.hmacctx, in, in_len);
|
||||
}
|
||||
|
||||
/* EC, rsa are just making the hash before signing */
|
||||
|
||||
return lws_genhash_update(&alg->hash_ctx, in, in_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* We fill up alg-> rhash and rhash_len with the results, and destroy the
|
||||
* crypto pieces cleanly. Call lws_cose_sign_alg_destroy() afterwards to
|
||||
* clean up the alg itself.
|
||||
*/
|
||||
|
||||
void
|
||||
lws_cose_sign_alg_complete(lws_cose_sig_alg_t *alg)
|
||||
{
|
||||
uint8_t digest[LWS_GENHASH_LARGEST];
|
||||
unsigned int bytes;
|
||||
uint8_t htype;
|
||||
size_t hs;
|
||||
|
||||
if (alg->completed)
|
||||
return;
|
||||
|
||||
switch (alg->cose_alg) {
|
||||
case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
|
||||
case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
|
||||
case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
|
||||
hs = lws_genhash_size(alg->hash_ctx.type);
|
||||
bytes = (unsigned int)lws_gencrypto_bits_to_bytes(alg->keybits);
|
||||
lws_genhash_destroy(&alg->hash_ctx, digest);
|
||||
alg->rhash_len = 0;
|
||||
lwsl_notice("alg keybits %d hs %d\n", (int)alg->keybits, (int)hs);
|
||||
if (!alg->failed &&
|
||||
lws_genecdsa_hash_sign_jws(&alg->u.ecdsactx, digest,
|
||||
alg->hash_ctx.type,
|
||||
(int)alg->keybits, alg->rhash,
|
||||
2u * bytes) >= 0)
|
||||
alg->rhash_len = (int)(2 * bytes);
|
||||
else
|
||||
alg->failed = 1;
|
||||
|
||||
lws_genec_destroy(&alg->u.ecdsactx);
|
||||
break;
|
||||
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
alg->rhash_len = (int)lws_genhmac_size(alg->u.hmacctx.type);
|
||||
if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64)
|
||||
alg->rhash_len = 8;
|
||||
|
||||
if (lws_genhmac_destroy(&alg->u.hmacctx, alg->rhash)) {
|
||||
lwsl_err("%s: destroy failed\n", __func__);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS256:
|
||||
case LWSCOSE_WKARSA_ALG_RS384:
|
||||
case LWSCOSE_WKARSA_ALG_RS512:
|
||||
bytes = (unsigned int)lws_gencrypto_bits_to_bytes(alg->keybits);
|
||||
htype = alg->hash_ctx.type;
|
||||
|
||||
if (!lws_genhash_destroy(&alg->hash_ctx, digest) &&
|
||||
!alg->failed &&
|
||||
lws_genrsa_hash_sign(&alg->u.rsactx, digest, htype,
|
||||
alg->rhash, bytes) >= 0)
|
||||
alg->rhash_len = (int)bytes;
|
||||
else
|
||||
lwsl_err("%s: lws_genrsa_hash_sign\n", __func__);
|
||||
|
||||
lws_genrsa_destroy(&alg->u.rsactx);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
alg->completed = 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_cose_sign_alg_destroy(lws_cose_sig_alg_t **_alg)
|
||||
{
|
||||
lws_dll2_remove(&(*_alg)->list);
|
||||
lws_cose_sign_alg_complete(*_alg);
|
||||
lws_free_set_NULL(*_alg);
|
||||
}
|
1051
lib/cose/cose_validate.c
Normal file
1051
lib/cose/cose_validate.c
Normal file
File diff suppressed because it is too large
Load diff
274
lib/cose/cose_validate_alg.c
Normal file
274
lib/cose/cose_validate_alg.c
Normal file
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-cose.h"
|
||||
|
||||
lws_cose_sig_alg_t *
|
||||
lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck,
|
||||
cose_param_t cose_alg, int op)
|
||||
{
|
||||
lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__);
|
||||
struct lws_gencrypto_keyelem *ke;
|
||||
enum lws_genhmac_types ghm;
|
||||
enum lws_genhash_types gh;
|
||||
const char *crv;
|
||||
|
||||
if (!alg)
|
||||
return NULL;
|
||||
|
||||
alg->cose_alg = cose_alg;
|
||||
alg->cose_key = ck;
|
||||
|
||||
switch (cose_alg) {
|
||||
|
||||
/* ECDSA algs */
|
||||
|
||||
case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
|
||||
crv = "P-256";
|
||||
gh = LWS_GENHASH_TYPE_SHA256;
|
||||
alg->keybits = 256;
|
||||
goto ecdsa;
|
||||
case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
|
||||
crv = "P-384";
|
||||
gh = LWS_GENHASH_TYPE_SHA384;
|
||||
alg->keybits = 384;
|
||||
goto ecdsa;
|
||||
case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
|
||||
crv = "P-521";
|
||||
gh = LWS_GENHASH_TYPE_SHA512;
|
||||
alg->keybits = 521;
|
||||
ecdsa:
|
||||
|
||||
/* the key is good for this? */
|
||||
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg,
|
||||
op, crv))
|
||||
goto bail_ecdsa;
|
||||
|
||||
if (lws_genhash_init(&alg->hash_ctx, gh))
|
||||
goto bail_ecdsa;
|
||||
|
||||
if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) {
|
||||
lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
|
||||
__func__);
|
||||
goto bail_ecdsa1;
|
||||
}
|
||||
|
||||
if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) {
|
||||
lwsl_notice("%s: ec key import fail\n", __func__);
|
||||
goto bail_ecdsa2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* HMAC algs */
|
||||
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA256;
|
||||
alg->keybits = 64;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA256;
|
||||
alg->keybits = 256;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA384;
|
||||
alg->keybits = 384;
|
||||
goto hmac;
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
ghm = LWS_GENHMAC_TYPE_SHA512;
|
||||
alg->keybits = 512;
|
||||
|
||||
hmac:
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC,
|
||||
cose_alg, op, NULL))
|
||||
goto bail_hmac;
|
||||
|
||||
ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
|
||||
if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len))
|
||||
goto bail_hmac;
|
||||
|
||||
break;
|
||||
|
||||
/* RSASSA algs */
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS256:
|
||||
gh = LWS_GENHASH_TYPE_SHA256;
|
||||
goto rsassa;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS384:
|
||||
gh = LWS_GENHASH_TYPE_SHA384;
|
||||
goto rsassa;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS512:
|
||||
gh = LWS_GENHASH_TYPE_SHA512;
|
||||
|
||||
rsassa:
|
||||
if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg,
|
||||
op, NULL))
|
||||
goto bail_hmac;
|
||||
alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8;
|
||||
|
||||
if (lws_genhash_init(&alg->hash_ctx, gh))
|
||||
goto bail_ecdsa;
|
||||
|
||||
if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx,
|
||||
LGRSAM_PKCS1_1_5, gh)) {
|
||||
lwsl_notice("%s: lws_genrsa_create fail\n", __func__);
|
||||
goto bail_ecdsa1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_warn("%s: unsupported alg %lld\n", __func__,
|
||||
(long long)cose_alg);
|
||||
goto bail_hmac;
|
||||
}
|
||||
|
||||
return alg;
|
||||
|
||||
bail_ecdsa2:
|
||||
lws_genec_destroy(&alg->u.ecdsactx);
|
||||
bail_ecdsa1:
|
||||
lws_genhash_destroy(&alg->hash_ctx, NULL);
|
||||
bail_ecdsa:
|
||||
lws_free(alg);
|
||||
|
||||
lwsl_notice("%s: failed\n", __func__);
|
||||
|
||||
return NULL;
|
||||
|
||||
bail_hmac:
|
||||
lws_free(alg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len)
|
||||
{
|
||||
#if defined(VERBOSE)
|
||||
lwsl_hexdump_warn(in, in_len);
|
||||
#endif
|
||||
|
||||
switch (alg->cose_alg) {
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
return lws_genhmac_update(&alg->u.hmacctx, in, in_len);
|
||||
}
|
||||
|
||||
return lws_genhash_update(&alg->hash_ctx, in, in_len);
|
||||
}
|
||||
|
||||
void
|
||||
lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps,
|
||||
lws_cose_sig_alg_t **_alg, const uint8_t *against,
|
||||
size_t against_len)
|
||||
{
|
||||
uint8_t digest[LWS_GENHASH_LARGEST];
|
||||
lws_cose_sig_alg_t *alg = *_alg;
|
||||
lws_cose_validate_res_t *res;
|
||||
size_t hs, shs;
|
||||
int keybits;
|
||||
uint8_t ht;
|
||||
|
||||
lws_dll2_remove(&alg->list);
|
||||
ht = alg->hash_ctx.type;
|
||||
keybits = alg->keybits;
|
||||
|
||||
res = lws_zalloc(sizeof(*res), __func__);
|
||||
if (res) {
|
||||
|
||||
res->cose_key = alg->cose_key;
|
||||
res->cose_alg = alg->cose_alg;
|
||||
res->result = -999;
|
||||
|
||||
lws_dll2_add_tail(&res->list, &cps->results);
|
||||
}
|
||||
|
||||
switch (alg->cose_alg) {
|
||||
case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
|
||||
case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
|
||||
case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
|
||||
hs = lws_genhash_size(alg->hash_ctx.type);
|
||||
lws_genhash_destroy(&alg->hash_ctx, digest);
|
||||
|
||||
lwsl_notice("%d %d %d\n", (int)hs, (int)keybits, (int)against_len);
|
||||
|
||||
if (res && against)
|
||||
res->result = lws_genecdsa_hash_sig_verify_jws(
|
||||
&alg->u.ecdsactx, digest, ht,
|
||||
keybits, against, against_len);
|
||||
lws_genec_destroy(&alg->u.ecdsactx);
|
||||
break;
|
||||
|
||||
case LWSCOSE_WKAHMAC_256_64:
|
||||
case LWSCOSE_WKAHMAC_256_256:
|
||||
case LWSCOSE_WKAHMAC_384_384:
|
||||
case LWSCOSE_WKAHMAC_512_512:
|
||||
shs = hs = lws_genhmac_size(alg->u.hmacctx.type);
|
||||
if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64)
|
||||
shs = 8;
|
||||
|
||||
if (lws_genhmac_destroy(&alg->u.hmacctx, digest)) {
|
||||
lwsl_err("%s: destroy failed\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cps->mac_pos != shs) {
|
||||
lwsl_warn("%s: mac wrong size\n", __func__);
|
||||
/* we can't compare it, leave it at fail */
|
||||
break;
|
||||
}
|
||||
if (res && against) {
|
||||
res->result = lws_timingsafe_bcmp(digest, cps->mac,
|
||||
(uint32_t)shs);
|
||||
if (res->result)
|
||||
lwsl_warn("%s: hash mismatch\n", __func__);
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSCOSE_WKARSA_ALG_RS256:
|
||||
case LWSCOSE_WKARSA_ALG_RS384:
|
||||
case LWSCOSE_WKARSA_ALG_RS512:
|
||||
|
||||
if (!lws_genhash_destroy(&alg->hash_ctx, digest) &&
|
||||
!alg->failed &&
|
||||
lws_genrsa_hash_sig_verify(&alg->u.rsactx, digest,
|
||||
alg->hash_ctx.type,
|
||||
against, against_len) >= 0) {
|
||||
if (res)
|
||||
res->result = 0;
|
||||
} else
|
||||
lwsl_err("%s: lws_genrsa_hash_verify\n", __func__);
|
||||
|
||||
lws_genrsa_destroy(&alg->u.rsactx);
|
||||
break;
|
||||
}
|
||||
|
||||
lws_free_set_NULL(*_alg);
|
||||
}
|
148
lib/cose/private-lib-cose.h
Normal file
148
lib/cose/private-lib-cose.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define VERBOSE
|
||||
|
||||
#define MAX_BLOBBED_PARAMS 96 /* largest bstr-encoded params */
|
||||
|
||||
enum {
|
||||
ST_UNKNOWN,
|
||||
|
||||
ST_OUTER_PROTECTED,
|
||||
ST_OUTER_UNPROTECTED,
|
||||
ST_OUTER_PAYLOAD,
|
||||
ST_OUTER_SIGN1_SIGNATURE,
|
||||
|
||||
ST_OUTER_SIGN_SIGARRAY,
|
||||
|
||||
ST_OUTER_MACTAG,
|
||||
|
||||
ST_INNER_PROTECTED,
|
||||
ST_INNER_UNPROTECTED,
|
||||
ST_INNER_SIGNATURE,
|
||||
|
||||
ST_INNER_EXCESS,
|
||||
};
|
||||
|
||||
typedef struct lws_cose_sig_alg {
|
||||
lws_dll2_t list;
|
||||
uint8_t rhash[512];
|
||||
const lws_cose_key_t *cose_key;
|
||||
struct lws_genhash_ctx hash_ctx;
|
||||
union {
|
||||
struct lws_genec_ctx ecdsactx;
|
||||
struct lws_genrsa_ctx rsactx;
|
||||
struct lws_genhmac_ctx hmacctx;
|
||||
} u;
|
||||
cose_param_t cose_alg;
|
||||
int keybits;
|
||||
int rhash_len;
|
||||
|
||||
char failed;
|
||||
char completed;
|
||||
} lws_cose_sig_alg_t;
|
||||
|
||||
typedef struct lws_cose_validate_param_stack {
|
||||
uint8_t ph[4][MAX_BLOBBED_PARAMS];
|
||||
int ph_pos[4];
|
||||
struct lws_gencrypto_keyelem kid;
|
||||
cose_param_t alg;
|
||||
} lws_cose_validate_param_stack_t;
|
||||
|
||||
struct lws_cose_validate_context {
|
||||
lws_cose_validate_create_info_t info;
|
||||
uint8_t mac[LWS_GENHASH_LARGEST];
|
||||
uint8_t sig_agg[512];
|
||||
lws_cose_validate_param_stack_t st[3];
|
||||
lws_dll2_owner_t algs;
|
||||
lws_dll2_owner_t results;
|
||||
uint8_t *payload_stash;
|
||||
struct lwsac *ac;
|
||||
struct lecp_ctx ctx;
|
||||
void *user;
|
||||
|
||||
size_t payload_pos;
|
||||
size_t payload_stash_size;
|
||||
|
||||
int seen;
|
||||
int depth;
|
||||
|
||||
int outer;
|
||||
size_t mac_pos;
|
||||
size_t sig_agg_pos;
|
||||
|
||||
cose_param_t map_key; /* parsing temp before val */
|
||||
|
||||
int tli; /* toplevel item */
|
||||
int sp;
|
||||
|
||||
uint8_t sub;
|
||||
};
|
||||
|
||||
struct lws_cose_sign_context {
|
||||
lws_cose_sign_create_info_t info;
|
||||
|
||||
lws_dll2_owner_t algs;
|
||||
lws_cose_sig_alg_t *alg;
|
||||
|
||||
size_t rem_pay;
|
||||
enum lws_cose_sig_types type; /* computed */
|
||||
int flags;
|
||||
|
||||
size_t along;
|
||||
|
||||
int tli;
|
||||
|
||||
char subsequent;
|
||||
};
|
||||
|
||||
extern const uint8_t *sig_mctx[];
|
||||
extern uint8_t sig_mctx_len[];
|
||||
extern const char *cose_sections[];
|
||||
|
||||
lws_cose_sig_alg_t *
|
||||
lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck,
|
||||
cose_param_t cose_alg, int op);
|
||||
|
||||
int
|
||||
lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len);
|
||||
|
||||
void
|
||||
lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps,
|
||||
lws_cose_sig_alg_t **_alg, const uint8_t *against,
|
||||
size_t against_len);
|
||||
|
||||
lws_cose_sig_alg_t *
|
||||
lws_cose_sign_alg_create(struct lws_context *cx, const lws_cose_key_t *ck,
|
||||
cose_param_t cose_alg, int op);
|
||||
|
||||
int
|
||||
lws_cose_sign_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len);
|
||||
|
||||
void
|
||||
lws_cose_sign_alg_complete(lws_cose_sig_alg_t *alg);
|
||||
|
||||
void
|
||||
lws_cose_sign_alg_destroy(lws_cose_sig_alg_t **_alg);
|
||||
|
|
@ -26,8 +26,9 @@ include_directories(. ./jwe ./jws ./jwk)
|
|||
|
||||
if (LWS_WITH_JOSE)
|
||||
list(APPEND SOURCES
|
||||
jose/jwk/jwk.c
|
||||
jose/jws/jose.c
|
||||
jose/jwk/jwk.c
|
||||
jose/jwk/jose_key.c
|
||||
jose/jws/jws.c
|
||||
jose/jwe/jwe.c
|
||||
jose/jwe/enc/aescbc.c
|
||||
|
|
649
lib/jose/jwk/jose_key.c
Normal file
649
lib/jose/jwk/jose_key.c
Normal file
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* JOSE-specific JWK code
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-jose.h"
|
||||
|
||||
#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
static const char * const kty_names[] = {
|
||||
"unknown", /* LWS_GENCRYPTO_KTY_UNKNOWN */
|
||||
"oct", /* LWS_GENCRYPTO_KTY_OCT */
|
||||
"RSA", /* LWS_GENCRYPTO_KTY_RSA */
|
||||
"EC" /* LWS_GENCRYPTO_KTY_EC */
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the entire legal token set for names in jwk.
|
||||
*
|
||||
* The first version is used to parse a detached single jwk that don't have any
|
||||
* parent JSON context. The second version is used to parse full jwk objects
|
||||
* that has a "keys": [ ] array containing the keys.
|
||||
*/
|
||||
|
||||
const char * const jwk_tok[] = {
|
||||
"keys[]", /* dummy */
|
||||
"e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
|
||||
"kty", /* generic */
|
||||
"k", /* symmetric key data */
|
||||
"crv", "x", "y", /* EC (also "D") */
|
||||
"kid", /* generic */
|
||||
"use" /* mutually exclusive with "key_ops" */,
|
||||
"key_ops" /* mutually exclusive with "use" */,
|
||||
"x5c", /* generic */
|
||||
"alg" /* generic */
|
||||
}, * const jwk_outer_tok[] = {
|
||||
"keys[]",
|
||||
"keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
|
||||
"keys[].dq", "keys[].qi",
|
||||
|
||||
"keys[].kty", "keys[].k", /* generic */
|
||||
"keys[].crv", "keys[].x", "keys[].y", /* EC (also "D") */
|
||||
"keys[].kid", "keys[].use" /* mutually exclusive with "key_ops" */,
|
||||
"keys[].key_ops", /* mutually exclusive with "use" */
|
||||
"keys[].x5c", "keys[].alg"
|
||||
};
|
||||
|
||||
static unsigned short tok_map[] = {
|
||||
F_RSA | F_EC | F_OCT | F_META | 0xff,
|
||||
F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
|
||||
F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
|
||||
F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY,
|
||||
F_OCT | F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
|
||||
|
||||
F_EC | F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
|
||||
F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
|
||||
F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_KID,
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_USE,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS,
|
||||
F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C,
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG,
|
||||
};
|
||||
|
||||
struct lexico {
|
||||
const char *name;
|
||||
int idx;
|
||||
char meta;
|
||||
} lexico_ec[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "crv", LWS_GENCRYPTO_EC_KEYEL_CRV, 0 },
|
||||
{ "d", LWS_GENCRYPTO_EC_KEYEL_D, 2 | 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x", LWS_GENCRYPTO_EC_KEYEL_X, 0 },
|
||||
{ "x5c", JWK_META_X5C, 1 },
|
||||
{ "y", LWS_GENCRYPTO_EC_KEYEL_Y, 0 }
|
||||
}, lexico_oct[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "k", LWS_GENCRYPTO_OCT_KEYEL_K, 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x5c", JWK_META_X5C, 1 }
|
||||
}, lexico_rsa[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "d", LWS_GENCRYPTO_RSA_KEYEL_D, 2 | 0 },
|
||||
{ "dp", LWS_GENCRYPTO_RSA_KEYEL_DP, 2 | 0 },
|
||||
{ "dq", LWS_GENCRYPTO_RSA_KEYEL_DQ, 2 | 0 },
|
||||
{ "e", LWS_GENCRYPTO_RSA_KEYEL_E, 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "n", LWS_GENCRYPTO_RSA_KEYEL_N, 0 },
|
||||
{ "p", LWS_GENCRYPTO_RSA_KEYEL_P, 2 | 0 },
|
||||
{ "q", LWS_GENCRYPTO_RSA_KEYEL_Q, 2 | 0 },
|
||||
{ "qi", LWS_GENCRYPTO_RSA_KEYEL_QI, 2 | 0 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x5c", JWK_META_X5C, 1 }
|
||||
};
|
||||
|
||||
static int
|
||||
_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
|
||||
{
|
||||
size_t dec_size = (unsigned int)lws_base64_size(len);
|
||||
int n;
|
||||
|
||||
e->buf = lws_malloc(dec_size, "jwk");
|
||||
if (!e->buf)
|
||||
return -1;
|
||||
|
||||
/* same decoder accepts both url or original styles */
|
||||
|
||||
n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
e->len = (uint32_t)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
|
||||
{
|
||||
size_t dec_size = (size_t)lws_base64_size(len);
|
||||
int n;
|
||||
|
||||
e->buf = lws_malloc(dec_size, "jwk");
|
||||
if (!e->buf)
|
||||
return -1;
|
||||
|
||||
/* same decoder accepts both url or original styles */
|
||||
|
||||
n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
e->len = (uint32_t)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
signed char
|
||||
cb_jwk(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
|
||||
struct lws_jwk *jwk = jps->jwk;
|
||||
unsigned int idx, n;
|
||||
unsigned short poss;
|
||||
char dotstar[64];
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_START)
|
||||
jps->pos = 0;
|
||||
|
||||
if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
|
||||
/*
|
||||
* new keys[] member is starting
|
||||
*
|
||||
* Until we see some JSON names, it could be anything...
|
||||
* there is no requirement for kty to be given first and eg,
|
||||
* ACME specifies the keys must be ordered in lexographic
|
||||
* order - where kty is not first.
|
||||
*/
|
||||
jps->possible = F_RSA | F_EC | F_OCT;
|
||||
|
||||
if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
|
||||
/* we completed parsing a key */
|
||||
if (jps->per_key_cb && jps->possible) {
|
||||
if (jps->per_key_cb(jps->jwk, jps->user)) {
|
||||
|
||||
lwsl_notice("%s: user cb halts import\n",
|
||||
__func__);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* clear it down */
|
||||
lws_jwk_destroy(jps->jwk);
|
||||
jps->possible = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_COMPLETE) {
|
||||
|
||||
/*
|
||||
* Now we saw the whole jwk and know the key type, let'jwk insist
|
||||
* that as a whole, it must be consistent and complete.
|
||||
*
|
||||
* The tracking of ->possible bits from even before we know the
|
||||
* kty already makes certain we cannot have key element members
|
||||
* defined that are inconsistent with the key type.
|
||||
*/
|
||||
|
||||
for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
|
||||
/*
|
||||
* All mandataory elements for the key type
|
||||
* must be present
|
||||
*/
|
||||
if ((tok_map[n] & jps->possible) && (
|
||||
((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
|
||||
!jwk->meta[tok_map[n] & 0xff].buf) ||
|
||||
((tok_map[n] & (F_M | F_META)) == F_M &&
|
||||
!jwk->e[tok_map[n] & 0xff].buf))) {
|
||||
lwsl_notice("%s: missing %s\n", __func__,
|
||||
jwk_tok[n]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the key may be public or public + private, ensure the
|
||||
* intra-key members related to that are consistent.
|
||||
*
|
||||
* Only RSA keys need extra care, since EC keys are already
|
||||
* confirmed by making CRV, X and Y mandatory and only D
|
||||
* (the singular private part) optional. For RSA, N and E are
|
||||
* also already known to be present using mandatory checking.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If a private key, it must have all D, P and Q. Public key
|
||||
* must have none of them.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
|
||||
(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
|
||||
) {
|
||||
lwsl_notice("%s: RSA requires D, P and Q for private\n",
|
||||
__func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the precomputed private key terms appear, they must all
|
||||
* appear together.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
|
||||
(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
|
||||
) {
|
||||
lwsl_notice("%s: RSA DP, DQ, QI must all appear "
|
||||
"or none\n", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The precomputed private key terms must not appear without
|
||||
* the private key itself also appearing.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
|
||||
lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
|
||||
"private key\n", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
|
||||
jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
|
||||
jwk->private_key = 1;
|
||||
}
|
||||
|
||||
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
|
||||
return 0;
|
||||
|
||||
if (ctx->path_match == 0 + 1)
|
||||
return 0;
|
||||
|
||||
idx = tok_map[ctx->path_match - 1];
|
||||
if ((idx & 0xff) == 0xff)
|
||||
return 0;
|
||||
|
||||
switch (idx) {
|
||||
/* note: kty is not necessarily first... we have to keep track of
|
||||
* what could match given which element names have already been
|
||||
* seen. Once kty comes, we confirm it'jwk still possible (ie, it'jwk
|
||||
* not trying to tell us that it'jwk RSA now when we saw a "crv"
|
||||
* earlier) and then reduce the possibilities to just the one that
|
||||
* kty told. */
|
||||
case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
|
||||
|
||||
if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
|
||||
if (!(jps->possible & F_OCT))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_OCT;
|
||||
jps->possible = F_OCT;
|
||||
goto cont;
|
||||
}
|
||||
if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
|
||||
if (!(jps->possible & F_RSA))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_RSA;
|
||||
jps->possible = F_RSA;
|
||||
goto cont;
|
||||
}
|
||||
if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
|
||||
if (!(jps->possible & F_EC))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_EC;
|
||||
jps->possible = F_EC;
|
||||
goto cont;
|
||||
}
|
||||
lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
|
||||
lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
cont:
|
||||
if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
|
||||
goto bail;
|
||||
|
||||
memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
|
||||
jps->pos += ctx->npos;
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_CHUNK)
|
||||
return 0;
|
||||
|
||||
/* chunking has been collated */
|
||||
|
||||
poss = idx & (F_RSA | F_EC | F_OCT);
|
||||
jps->possible &= poss;
|
||||
if (!jps->possible)
|
||||
goto elements_mismatch;
|
||||
|
||||
if (idx & F_META) {
|
||||
if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
|
||||
jps->b64, (unsigned int)jps->pos) < 0)
|
||||
goto bail;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx & F_B64U) {
|
||||
/* key data... do the base64 decode as needed */
|
||||
if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
|
||||
jps->b64, jps->pos) < 0)
|
||||
goto bail;
|
||||
|
||||
if (jwk->e[idx & 0x7f].len >
|
||||
LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
|
||||
lwsl_notice("%s: oversize keydata\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (idx & F_B64) {
|
||||
|
||||
/* cert data... do non-urlcoded base64 decode */
|
||||
if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
|
||||
jps->b64, jps->pos) < 0)
|
||||
goto bail;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
|
||||
jps->b64, (unsigned int)jps->pos) < 0)
|
||||
goto bail;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
elements_mismatch:
|
||||
lwsl_err("%s: jwk elements mismatch\n", __func__);
|
||||
|
||||
bail:
|
||||
lwsl_err("%s: element failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
|
||||
const char *in, size_t len)
|
||||
{
|
||||
struct lejp_ctx jctx;
|
||||
struct lws_jwk_parse_state jps;
|
||||
int m;
|
||||
|
||||
lws_jwk_init_jps(&jps, jwk, cb, user);
|
||||
|
||||
lejp_construct(&jctx, cb_jwk, &jps, cb ? jwk_outer_tok: jwk_tok,
|
||||
LWS_ARRAY_SIZE(jwk_tok));
|
||||
|
||||
m = lejp_parse(&jctx, (uint8_t *)in, (int)len);
|
||||
lejp_destruct(&jctx);
|
||||
|
||||
if (m < 0) {
|
||||
lwsl_notice("%s: parse got %d\n", __func__, m);
|
||||
lws_jwk_destroy(jwk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (jwk->kty) {
|
||||
case LWS_GENCRYPTO_KTY_UNKNOWN:
|
||||
lwsl_notice("%s: missing or unknown kty\n", __func__);
|
||||
lws_jwk_destroy(jwk);
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
|
||||
{
|
||||
char *start = p, *end = &p[*len - 1];
|
||||
int n, m, limit, first = 1, asym = 0;
|
||||
struct lexico *l;
|
||||
|
||||
/* RFC7638 lexicographic order requires
|
||||
* RSA: e -> kty -> n
|
||||
* oct: k -> kty
|
||||
*
|
||||
* ie, meta and key data elements appear interleaved in name alpha order
|
||||
*/
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{");
|
||||
|
||||
switch (jwk->kty) {
|
||||
case LWS_GENCRYPTO_KTY_OCT:
|
||||
l = lexico_oct;
|
||||
limit = LWS_ARRAY_SIZE(lexico_oct);
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_RSA:
|
||||
l = lexico_rsa;
|
||||
limit = LWS_ARRAY_SIZE(lexico_rsa);
|
||||
asym = 1;
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_EC:
|
||||
l = lexico_ec;
|
||||
limit = LWS_ARRAY_SIZE(lexico_ec);
|
||||
asym = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < limit; n++) {
|
||||
const char *q, *q_end;
|
||||
char tok[12];
|
||||
int pos = 0, f = 1;
|
||||
|
||||
if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
|
||||
l->idx == (int)JWK_META_KTY)) {
|
||||
|
||||
switch (l->idx) {
|
||||
case JWK_META_KTY:
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"%s\"",
|
||||
l->name, kty_names[jwk->kty]);
|
||||
break;
|
||||
case JWK_META_KEY_OPS:
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
q = (const char *)jwk->meta[l->idx].buf;
|
||||
q_end = q + jwk->meta[l->idx].len;
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
"\"%s\":[", l->name);
|
||||
/*
|
||||
* For the public version, usages that
|
||||
* require the private part must be
|
||||
* snipped
|
||||
*/
|
||||
|
||||
while (q < q_end) {
|
||||
if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
|
||||
tok[pos++] = *q++;
|
||||
if (q != q_end)
|
||||
continue;
|
||||
}
|
||||
tok[pos] = '\0';
|
||||
pos = 0;
|
||||
if ((flags & LWSJWKF_EXPORT_PRIVATE) ||
|
||||
!asym || (strcmp(tok, "sign") &&
|
||||
strcmp(tok, "encrypt"))) {
|
||||
if (!f)
|
||||
*p++ = ',';
|
||||
f = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
"\"%s\"", tok);
|
||||
}
|
||||
q++;
|
||||
}
|
||||
|
||||
*p++ = ']';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* both sig and enc require asym private key */
|
||||
if (!(flags & LWSJWKF_EXPORT_PRIVATE) &&
|
||||
asym && l->idx == (int)JWK_META_USE)
|
||||
break;
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"",
|
||||
l->name);
|
||||
lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
|
||||
jwk->meta[l->idx].len, end - p);
|
||||
p += strlen(p);
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
|
||||
((flags & LWSJWKF_EXPORT_PRIVATE) || !(l->meta & 2))) {
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"", l->name);
|
||||
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
|
||||
l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
|
||||
lws_strnncpy(p,
|
||||
(const char *)jwk->e[l->idx].buf,
|
||||
jwk->e[l->idx].len, end - p);
|
||||
m = (int)strlen(p);
|
||||
} else
|
||||
m = lws_jws_base64_enc(
|
||||
(const char *)jwk->e[l->idx].buf,
|
||||
jwk->e[l->idx].len, p, lws_ptr_diff_size_t(end, p) - 4);
|
||||
if (m < 0) {
|
||||
lwsl_notice("%s: enc failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
p += m;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
|
||||
}
|
||||
|
||||
l++;
|
||||
}
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
(flags & LWSJWKF_EXPORT_NOCRLF) ? "}" : "}\n");
|
||||
|
||||
*len -= lws_ptr_diff(p, start);
|
||||
|
||||
return lws_ptr_diff(p, start);
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_load(struct lws_jwk *jwk, const char *filename,
|
||||
lws_jwk_key_import_callback cb, void *user)
|
||||
{
|
||||
unsigned int buflen = 4096;
|
||||
char *buf = lws_malloc(buflen, "jwk-load");
|
||||
int n;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
n = lws_plat_read_file(filename, buf, buflen);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
n = lws_jwk_import(jwk, cb, user, buf, (unsigned int)n);
|
||||
lws_free(buf);
|
||||
|
||||
return n;
|
||||
bail:
|
||||
lws_free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_save(struct lws_jwk *jwk, const char *filename)
|
||||
{
|
||||
int buflen = 4096;
|
||||
char *buf = lws_malloc((unsigned int)buflen, "jwk-save");
|
||||
int n, m;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
n = lws_jwk_export(jwk, LWSJWKF_EXPORT_PRIVATE, buf, &buflen);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
m = lws_plat_write_file(filename, buf, (size_t)n);
|
||||
|
||||
lws_free(buf);
|
||||
if (m)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lws_free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
@ -20,133 +20,17 @@
|
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Shared JWK handling that's the same whether JOSE or COSE
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-jose.h"
|
||||
|
||||
#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
static const char * const kty_names[] = {
|
||||
"unknown", /* LWS_GENCRYPTO_KTY_UNKNOWN */
|
||||
"oct", /* LWS_GENCRYPTO_KTY_OCT */
|
||||
"RSA", /* LWS_GENCRYPTO_KTY_RSA */
|
||||
"EC" /* LWS_GENCRYPTO_KTY_EC */
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the entire legal token set for names in jwk.
|
||||
*
|
||||
* The first version is used to parse a detached single jwk that don't have any
|
||||
* parent JSON context. The second version is used to parse full jwk objects
|
||||
* that has a "keys": [ ] array containing the keys.
|
||||
*/
|
||||
|
||||
static const char * const jwk_tok[] = {
|
||||
"keys[]", /* dummy */
|
||||
"e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
|
||||
"kty", /* generic */
|
||||
"k", /* symmetric key data */
|
||||
"crv", "x", "y", /* EC (also "D") */
|
||||
"kid", /* generic */
|
||||
"use" /* mutually exclusive with "key_ops" */,
|
||||
"key_ops" /* mutually exclusive with "use" */,
|
||||
"x5c", /* generic */
|
||||
"alg" /* generic */
|
||||
}, * const jwk_outer_tok[] = {
|
||||
"keys[]",
|
||||
"keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
|
||||
"keys[].dq", "keys[].qi",
|
||||
|
||||
"keys[].kty", "keys[].k", /* generic */
|
||||
"keys[].crv", "keys[].x", "keys[].y", /* EC (also "D") */
|
||||
"keys[].kid", "keys[].use" /* mutually exclusive with "key_ops" */,
|
||||
"keys[].key_ops", /* mutually exclusive with "use" */
|
||||
"keys[].x5c", "keys[].alg"
|
||||
};
|
||||
|
||||
/* information about each token declared above */
|
||||
|
||||
#define F_M (1 << 9) /* Mandatory for key type */
|
||||
#define F_B64 (1 << 10) /* Base64 coded octets */
|
||||
#define F_B64U (1 << 11) /* Base64 Url coded octets */
|
||||
#define F_META (1 << 12) /* JWK key metainformation */
|
||||
#define F_RSA (1 << 13) /* RSA key */
|
||||
#define F_EC (1 << 14) /* Elliptic curve key */
|
||||
#define F_OCT (1 << 15) /* octet key */
|
||||
|
||||
static unsigned short tok_map[] = {
|
||||
F_RSA | F_EC | F_OCT | F_META | 0xff,
|
||||
F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
|
||||
F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
|
||||
F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ,
|
||||
F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY,
|
||||
F_OCT | F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
|
||||
|
||||
F_EC | F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
|
||||
F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
|
||||
F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_KID,
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_USE,
|
||||
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS,
|
||||
F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C,
|
||||
F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG,
|
||||
};
|
||||
|
||||
static const char *meta_names[] = {
|
||||
"kty", "kid", "use", "key_ops", "x5c", "alg"
|
||||
};
|
||||
|
||||
struct lexico {
|
||||
const char *name;
|
||||
int idx;
|
||||
char meta;
|
||||
} lexico_ec[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "crv", LWS_GENCRYPTO_EC_KEYEL_CRV, 0 },
|
||||
{ "d", LWS_GENCRYPTO_EC_KEYEL_D, 2 | 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x", LWS_GENCRYPTO_EC_KEYEL_X, 0 },
|
||||
{ "x5c", JWK_META_X5C, 1 },
|
||||
{ "y", LWS_GENCRYPTO_EC_KEYEL_Y, 0 }
|
||||
}, lexico_oct[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "k", LWS_GENCRYPTO_OCT_KEYEL_K, 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x5c", JWK_META_X5C, 1 }
|
||||
}, lexico_rsa[] = {
|
||||
{ "alg", JWK_META_ALG, 1 },
|
||||
{ "d", LWS_GENCRYPTO_RSA_KEYEL_D, 2 | 0 },
|
||||
{ "dp", LWS_GENCRYPTO_RSA_KEYEL_DP, 2 | 0 },
|
||||
{ "dq", LWS_GENCRYPTO_RSA_KEYEL_DQ, 2 | 0 },
|
||||
{ "e", LWS_GENCRYPTO_RSA_KEYEL_E, 0 },
|
||||
{ "key_ops", JWK_META_KEY_OPS, 1 },
|
||||
{ "kid", JWK_META_KID, 1 },
|
||||
{ "kty", JWK_META_KTY, 1 },
|
||||
{ "n", LWS_GENCRYPTO_RSA_KEYEL_N, 0 },
|
||||
{ "p", LWS_GENCRYPTO_RSA_KEYEL_P, 2 | 0 },
|
||||
{ "q", LWS_GENCRYPTO_RSA_KEYEL_Q, 2 | 0 },
|
||||
{ "qi", LWS_GENCRYPTO_RSA_KEYEL_QI, 2 | 0 },
|
||||
{ "use", JWK_META_USE, 1 },
|
||||
{ "x5c", JWK_META_X5C, 1 }
|
||||
};
|
||||
|
||||
static const char meta_b64[] = { 0, 0, 0, 0, 1, 0 };
|
||||
|
||||
static const char *oct_names[] = {
|
||||
|
@ -221,7 +105,7 @@ lws_jwk_dump(struct lws_jwk *jwk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len)
|
||||
{
|
||||
e->buf = lws_malloc(len + 1, "jwk");
|
||||
|
@ -235,46 +119,6 @@ _lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
|
||||
{
|
||||
size_t dec_size = (unsigned int)lws_base64_size(len);
|
||||
int n;
|
||||
|
||||
e->buf = lws_malloc(dec_size, "jwk");
|
||||
if (!e->buf)
|
||||
return -1;
|
||||
|
||||
/* same decoder accepts both url or original styles */
|
||||
|
||||
n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
e->len = (uint32_t)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
|
||||
{
|
||||
size_t dec_size = (size_t)lws_base64_size(len);
|
||||
int n;
|
||||
|
||||
e->buf = lws_malloc(dec_size, "jwk");
|
||||
if (!e->buf)
|
||||
return -1;
|
||||
|
||||
/* same decoder accepts both url or original styles */
|
||||
|
||||
n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
e->len = (uint32_t)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
|
||||
{
|
||||
|
@ -296,261 +140,21 @@ lws_jwk_destroy(struct lws_jwk *jwk)
|
|||
lws_jwk_destroy_elements(jwk->meta, LWS_ARRAY_SIZE(jwk->meta));
|
||||
}
|
||||
|
||||
static signed char
|
||||
cb_jwk(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
|
||||
struct lws_jwk *jwk = jps->jwk;
|
||||
unsigned int idx, n;
|
||||
unsigned short poss;
|
||||
char dotstar[64];
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_START)
|
||||
jps->pos = 0;
|
||||
|
||||
if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
|
||||
/*
|
||||
* new keys[] member is starting
|
||||
*
|
||||
* Until we see some JSON names, it could be anything...
|
||||
* there is no requirement for kty to be given first and eg,
|
||||
* ACME specifies the keys must be ordered in lexographic
|
||||
* order - where kty is not first.
|
||||
*/
|
||||
jps->possible = F_RSA | F_EC | F_OCT;
|
||||
|
||||
if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
|
||||
/* we completed parsing a key */
|
||||
if (jps->per_key_cb && jps->possible) {
|
||||
if (jps->per_key_cb(jps->jwk, jps->user)) {
|
||||
|
||||
lwsl_notice("%s: user cb halts import\n",
|
||||
__func__);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* clear it down */
|
||||
lws_jwk_destroy(jps->jwk);
|
||||
jps->possible = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_COMPLETE) {
|
||||
|
||||
/*
|
||||
* Now we saw the whole jwk and know the key type, let'jwk insist
|
||||
* that as a whole, it must be consistent and complete.
|
||||
*
|
||||
* The tracking of ->possible bits from even before we know the
|
||||
* kty already makes certain we cannot have key element members
|
||||
* defined that are inconsistent with the key type.
|
||||
*/
|
||||
|
||||
for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
|
||||
/*
|
||||
* All mandataory elements for the key type
|
||||
* must be present
|
||||
*/
|
||||
if ((tok_map[n] & jps->possible) && (
|
||||
((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
|
||||
!jwk->meta[tok_map[n] & 0xff].buf) ||
|
||||
((tok_map[n] & (F_M | F_META)) == F_M &&
|
||||
!jwk->e[tok_map[n] & 0xff].buf))) {
|
||||
lwsl_notice("%s: missing %s\n", __func__,
|
||||
jwk_tok[n]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the key may be public or public + private, ensure the
|
||||
* intra-key members related to that are consistent.
|
||||
*
|
||||
* Only RSA keys need extra care, since EC keys are already
|
||||
* confirmed by making CRV, X and Y mandatory and only D
|
||||
* (the singular private part) optional. For RSA, N and E are
|
||||
* also already known to be present using mandatory checking.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If a private key, it must have all D, P and Q. Public key
|
||||
* must have none of them.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
|
||||
(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
|
||||
) {
|
||||
lwsl_notice("%s: RSA requires D, P and Q for private\n",
|
||||
__func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the precomputed private key terms appear, they must all
|
||||
* appear together.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
|
||||
(!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
|
||||
(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
|
||||
) {
|
||||
lwsl_notice("%s: RSA DP, DQ, QI must all appear "
|
||||
"or none\n", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The precomputed private key terms must not appear without
|
||||
* the private key itself also appearing.
|
||||
*/
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
|
||||
!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
|
||||
lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
|
||||
"private key\n", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
|
||||
jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
|
||||
jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
|
||||
jwk->private_key = 1;
|
||||
}
|
||||
|
||||
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
|
||||
return 0;
|
||||
|
||||
if (ctx->path_match == 0 + 1)
|
||||
return 0;
|
||||
|
||||
idx = tok_map[ctx->path_match - 1];
|
||||
if ((idx & 0xff) == 0xff)
|
||||
return 0;
|
||||
|
||||
switch (idx) {
|
||||
/* note: kty is not necessarily first... we have to keep track of
|
||||
* what could match given which element names have already been
|
||||
* seen. Once kty comes, we confirm it'jwk still possible (ie, it'jwk
|
||||
* not trying to tell us that it'jwk RSA now when we saw a "crv"
|
||||
* earlier) and then reduce the possibilities to just the one that
|
||||
* kty told. */
|
||||
case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
|
||||
|
||||
if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
|
||||
if (!(jps->possible & F_OCT))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_OCT;
|
||||
jps->possible = F_OCT;
|
||||
goto cont;
|
||||
}
|
||||
if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
|
||||
if (!(jps->possible & F_RSA))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_RSA;
|
||||
jps->possible = F_RSA;
|
||||
goto cont;
|
||||
}
|
||||
if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
|
||||
if (!(jps->possible & F_EC))
|
||||
goto elements_mismatch;
|
||||
jwk->kty = LWS_GENCRYPTO_KTY_EC;
|
||||
jps->possible = F_EC;
|
||||
goto cont;
|
||||
}
|
||||
lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
|
||||
lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
cont:
|
||||
if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
|
||||
goto bail;
|
||||
|
||||
memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
|
||||
jps->pos += ctx->npos;
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_CHUNK)
|
||||
return 0;
|
||||
|
||||
/* chunking has been collated */
|
||||
|
||||
poss = idx & (F_RSA | F_EC | F_OCT);
|
||||
jps->possible &= poss;
|
||||
if (!jps->possible)
|
||||
goto elements_mismatch;
|
||||
|
||||
if (idx & F_META) {
|
||||
if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
|
||||
jps->b64, (unsigned int)jps->pos) < 0)
|
||||
goto bail;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx & F_B64U) {
|
||||
/* key data... do the base64 decode as needed */
|
||||
if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
|
||||
jps->b64, jps->pos) < 0)
|
||||
goto bail;
|
||||
|
||||
if (jwk->e[idx & 0x7f].len >
|
||||
LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
|
||||
lwsl_notice("%s: oversize keydata\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (idx & F_B64) {
|
||||
|
||||
/* cert data... do non-urlcoded base64 decode */
|
||||
if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
|
||||
jps->b64, jps->pos) < 0)
|
||||
goto bail;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
|
||||
jps->b64, (unsigned int)jps->pos) < 0)
|
||||
goto bail;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
elements_mismatch:
|
||||
lwsl_err("%s: jwk elements mismatch\n", __func__);
|
||||
|
||||
bail:
|
||||
lwsl_err("%s: element failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps,
|
||||
lws_jwk_init_jps(struct lws_jwk_parse_state *jps,
|
||||
struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
|
||||
void *user)
|
||||
{
|
||||
if (jwk)
|
||||
memset(jwk, 0, sizeof(*jwk));
|
||||
|
||||
jps->jwk = jwk;
|
||||
jps->possible = F_RSA | F_EC | F_OCT;
|
||||
jps->per_key_cb = cb;
|
||||
jps->user = user;
|
||||
jps->pos = 0;
|
||||
|
||||
lejp_construct(jctx, cb_jwk, jps, cb ? jwk_outer_tok: jwk_tok,
|
||||
LWS_ARRAY_SIZE(jwk_tok));
|
||||
jps->jwk = jwk;
|
||||
jps->possible = F_RSA | F_EC | F_OCT;
|
||||
jps->per_key_cb = cb;
|
||||
jps->user = user;
|
||||
jps->pos = 0;
|
||||
jps->seen = 0;
|
||||
jps->cose_state = 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -600,6 +204,8 @@ lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
|
|||
case LWS_GENCRYPTO_KTY_OCT:
|
||||
sn = (unsigned int)lws_gencrypto_bits_to_bytes(bits);
|
||||
jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(sn, "oct");
|
||||
if (!jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf)
|
||||
return 1;
|
||||
jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = (uint32_t)sn;
|
||||
if (lws_get_random(context,
|
||||
jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, sn) != sn) {
|
||||
|
@ -641,183 +247,6 @@ lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
|
||||
const char *in, size_t len)
|
||||
{
|
||||
struct lejp_ctx jctx;
|
||||
struct lws_jwk_parse_state jps;
|
||||
int m;
|
||||
|
||||
lws_jwk_init_jps(&jctx, &jps, jwk, cb, user);
|
||||
|
||||
m = lejp_parse(&jctx, (uint8_t *)in, (int)len);
|
||||
lejp_destruct(&jctx);
|
||||
|
||||
if (m < 0) {
|
||||
lwsl_notice("%s: parse got %d\n", __func__, m);
|
||||
lws_jwk_destroy(jwk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (jwk->kty) {
|
||||
case LWS_GENCRYPTO_KTY_UNKNOWN:
|
||||
lwsl_notice("%s: missing or unknown kyt\n", __func__);
|
||||
lws_jwk_destroy(jwk);
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
|
||||
{
|
||||
char *start = p, *end = &p[*len - 1];
|
||||
int n, m, limit, first = 1, asym = 0;
|
||||
struct lexico *l;
|
||||
|
||||
/* RFC7638 lexicographic order requires
|
||||
* RSA: e -> kty -> n
|
||||
* oct: k -> kty
|
||||
*
|
||||
* ie, meta and key data elements appear interleaved in name alpha order
|
||||
*/
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{");
|
||||
|
||||
switch (jwk->kty) {
|
||||
case LWS_GENCRYPTO_KTY_OCT:
|
||||
l = lexico_oct;
|
||||
limit = LWS_ARRAY_SIZE(lexico_oct);
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_RSA:
|
||||
l = lexico_rsa;
|
||||
limit = LWS_ARRAY_SIZE(lexico_rsa);
|
||||
asym = 1;
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_EC:
|
||||
l = lexico_ec;
|
||||
limit = LWS_ARRAY_SIZE(lexico_ec);
|
||||
asym = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < limit; n++) {
|
||||
const char *q, *q_end;
|
||||
char tok[12];
|
||||
int pos = 0, f = 1;
|
||||
|
||||
if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
|
||||
l->idx == (int)JWK_META_KTY)) {
|
||||
|
||||
switch (l->idx) {
|
||||
case JWK_META_KTY:
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"%s\"",
|
||||
l->name, kty_names[jwk->kty]);
|
||||
break;
|
||||
case JWK_META_KEY_OPS:
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
q = (const char *)jwk->meta[l->idx].buf;
|
||||
q_end = q + jwk->meta[l->idx].len;
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
"\"%s\":[", l->name);
|
||||
/*
|
||||
* For the public version, usages that
|
||||
* require the private part must be
|
||||
* snipped
|
||||
*/
|
||||
|
||||
while (q < q_end) {
|
||||
if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
|
||||
tok[pos++] = *q++;
|
||||
if (q != q_end)
|
||||
continue;
|
||||
}
|
||||
tok[pos] = '\0';
|
||||
pos = 0;
|
||||
if ((flags & LWSJWKF_EXPORT_PRIVATE) ||
|
||||
!asym || (strcmp(tok, "sign") &&
|
||||
strcmp(tok, "encrypt"))) {
|
||||
if (!f)
|
||||
*p++ = ',';
|
||||
f = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
"\"%s\"", tok);
|
||||
}
|
||||
q++;
|
||||
}
|
||||
|
||||
*p++ = ']';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* both sig and enc require asym private key */
|
||||
if (!(flags & LWSJWKF_EXPORT_PRIVATE) &&
|
||||
asym && l->idx == (int)JWK_META_USE)
|
||||
break;
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"",
|
||||
l->name);
|
||||
lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
|
||||
jwk->meta[l->idx].len, end - p);
|
||||
p += strlen(p);
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
|
||||
((flags & LWSJWKF_EXPORT_PRIVATE) || !(l->meta & 2))) {
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
first = 0;
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"", l->name);
|
||||
|
||||
if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
|
||||
l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
|
||||
lws_strnncpy(p,
|
||||
(const char *)jwk->e[l->idx].buf,
|
||||
jwk->e[l->idx].len, end - p);
|
||||
m = (int)strlen(p);
|
||||
} else
|
||||
m = lws_jws_base64_enc(
|
||||
(const char *)jwk->e[l->idx].buf,
|
||||
jwk->e[l->idx].len, p, lws_ptr_diff_size_t(end, p) - 4);
|
||||
if (m < 0) {
|
||||
lwsl_notice("%s: enc failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
p += m;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
|
||||
}
|
||||
|
||||
l++;
|
||||
}
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
||||
(flags & LWSJWKF_EXPORT_NOCRLF) ? "}" : "}\n");
|
||||
|
||||
*len -= lws_ptr_diff(p, start);
|
||||
|
||||
return lws_ptr_diff(p, start);
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32)
|
||||
{
|
||||
|
@ -866,55 +295,3 @@ lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_load(struct lws_jwk *jwk, const char *filename,
|
||||
lws_jwk_key_import_callback cb, void *user)
|
||||
{
|
||||
unsigned int buflen = 4096;
|
||||
char *buf = lws_malloc(buflen, "jwk-load");
|
||||
int n;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
n = lws_plat_read_file(filename, buf, buflen);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
n = lws_jwk_import(jwk, cb, user, buf, (unsigned int)n);
|
||||
lws_free(buf);
|
||||
|
||||
return n;
|
||||
bail:
|
||||
lws_free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwk_save(struct lws_jwk *jwk, const char *filename)
|
||||
{
|
||||
int buflen = 4096;
|
||||
char *buf = lws_malloc((unsigned int)buflen, "jwk-save");
|
||||
int n, m;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
n = lws_jwk_export(jwk, LWSJWKF_EXPORT_PRIVATE, buf, &buflen);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
m = lws_plat_write_file(filename, buf, (size_t)n);
|
||||
|
||||
lws_free(buf);
|
||||
if (m)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lws_free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -404,7 +404,6 @@ lws_jose_destroy(struct lws_jose *jose)
|
|||
lws_jose_recip_destroy(&jose->recipient[n]);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
|
||||
char *temp, int *temp_len, int is_jwe)
|
||||
|
@ -413,11 +412,14 @@ lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
|
|||
struct jose_cb_args args;
|
||||
int m;
|
||||
|
||||
if (is_jwe)
|
||||
if (is_jwe) {
|
||||
/* prepare a context for JOSE epk ephemeral jwk parsing */
|
||||
lws_jwk_init_jps(&args.jwk_jctx, &args.jps,
|
||||
lws_jwk_init_jps(&args.jps,
|
||||
&jose->recipient[jose->recipients].jwk_ephemeral,
|
||||
NULL, NULL);
|
||||
lejp_construct(&args.jwk_jctx, cb_jwk, &args.jps,
|
||||
jwk_tok, LWS_ARRAY_SIZE(jwk_tok));
|
||||
}
|
||||
|
||||
args.is_jwe = (unsigned int)is_jwe;
|
||||
args.temp = temp;
|
||||
|
|
|
@ -22,14 +22,32 @@
|
|||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
void
|
||||
lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m);
|
||||
/* information about each token declared above */
|
||||
|
||||
#define F_M (1 << 9) /* Mandatory for key type */
|
||||
#define F_B64 (1 << 10) /* Base64 coded octets */
|
||||
#define F_B64U (1 << 11) /* Base64 Url coded octets */
|
||||
#define F_META (1 << 12) /* JWK key metainformation */
|
||||
#define F_RSA (1 << 13) /* RSA key */
|
||||
#define F_EC (1 << 14) /* Elliptic curve key */
|
||||
#define F_OCT (1 << 15) /* octet key */
|
||||
|
||||
void
|
||||
lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps,
|
||||
struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
|
||||
void *user);
|
||||
lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m);
|
||||
|
||||
int
|
||||
lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
|
||||
char *out, size_t out_len);
|
||||
|
||||
int
|
||||
_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len);
|
||||
|
||||
void
|
||||
lws_jwk_init_jps(struct lws_jwk_parse_state *jps,
|
||||
struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
|
||||
void *user);
|
||||
|
||||
signed char
|
||||
cb_jwk(struct lejp_ctx *ctx, char reason);
|
||||
|
||||
extern const char * const jwk_tok[19], * const jwk_outer_tok[19];
|
||||
|
|
|
@ -53,7 +53,7 @@ const struct lws_ec_curves lws_ec_curves[] = {
|
|||
|
||||
static int
|
||||
lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
|
||||
struct lws_gencrypto_keyelem *el)
|
||||
const struct lws_gencrypto_keyelem *el)
|
||||
{
|
||||
const struct lws_ec_curves *curve;
|
||||
mbedtls_ecp_keypair kp;
|
||||
|
@ -202,7 +202,7 @@ lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
|
|||
|
||||
int
|
||||
lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
|
||||
struct lws_gencrypto_keyelem *el)
|
||||
const struct lws_gencrypto_keyelem *el)
|
||||
{
|
||||
if (ctx->genec_alg != LEGENEC_ECDSA)
|
||||
return -1;
|
||||
|
|
|
@ -41,7 +41,8 @@ lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el)
|
|||
static int mode_map[] = { MBEDTLS_RSA_PKCS_V15, MBEDTLS_RSA_PKCS_V21 };
|
||||
|
||||
int
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx,
|
||||
const struct lws_gencrypto_keyelem *el,
|
||||
struct lws_context *context, enum enum_genrsa_mode mode,
|
||||
enum lws_genhash_types oaep_hashid)
|
||||
{
|
||||
|
@ -169,7 +170,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
|
|||
};
|
||||
|
||||
for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++)
|
||||
if (mbedtls_mpi_size(mpi[n])) {
|
||||
if (mpi[n] && mbedtls_mpi_size(mpi[n])) {
|
||||
el[n].buf = lws_malloc(
|
||||
mbedtls_mpi_size(mpi[n]), "genrsakey");
|
||||
if (!el[n].buf)
|
||||
|
|
|
@ -402,7 +402,7 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
|
|||
mpi[LWS_GENCRYPTO_RSA_KEYEL_DQ] = &rsactx->MBEDTLS_PRIVATE(DQ);
|
||||
mpi[LWS_GENCRYPTO_RSA_KEYEL_QI] = &rsactx->MBEDTLS_PRIVATE(QP);
|
||||
|
||||
count = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
|
||||
count = LWS_GENCRYPTO_RSA_KEYEL_QI + 1;
|
||||
n = LWS_GENCRYPTO_RSA_KEYEL_E;
|
||||
break;
|
||||
|
||||
|
|
|
@ -102,7 +102,8 @@ const struct lws_ec_curves lws_ec_curves[4] = {
|
|||
};
|
||||
|
||||
static int
|
||||
lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el)
|
||||
lws_genec_eckey_import(int nid, EVP_PKEY *pkey,
|
||||
const struct lws_gencrypto_keyelem *el)
|
||||
{
|
||||
EC_KEY *ec = EC_KEY_new_by_curve_name(nid);
|
||||
BIGNUM *bn_d, *bn_x, *bn_y;
|
||||
|
@ -184,7 +185,8 @@ bail:
|
|||
static int
|
||||
lws_genec_keypair_import(struct lws_genec_ctx *ctx,
|
||||
const struct lws_ec_curves *curve_table,
|
||||
EVP_PKEY_CTX **pctx, struct lws_gencrypto_keyelem *el)
|
||||
EVP_PKEY_CTX **pctx,
|
||||
const struct lws_gencrypto_keyelem *el)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
const struct lws_ec_curves *curve;
|
||||
|
@ -273,7 +275,7 @@ lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
|
|||
|
||||
int
|
||||
lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
|
||||
struct lws_gencrypto_keyelem *el)
|
||||
const struct lws_gencrypto_keyelem *el)
|
||||
{
|
||||
if (ctx->genec_alg != LEGENEC_ECDSA)
|
||||
return -1;
|
||||
|
@ -486,6 +488,7 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
uint8_t *sig, size_t sig_len)
|
||||
{
|
||||
int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits);
|
||||
size_t hs = lws_genhash_size(hash_type);
|
||||
const BIGNUM *r = NULL, *s = NULL;
|
||||
ECDSA_SIG *ecdsasig;
|
||||
EC_KEY *eckey;
|
||||
|
@ -498,9 +501,9 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
if (!ctx->has_private)
|
||||
return -1;
|
||||
|
||||
if ((int)sig_len < keybytes * 2) {
|
||||
if ((int)sig_len != (int)(keybytes * 2)) {
|
||||
lwsl_notice("%s: sig buff %d < %d\n", __func__,
|
||||
(int)sig_len, keybytes * 2);
|
||||
(int)sig_len, (int)(hs * 2));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -525,7 +528,7 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
* 4. The resulting 64-octet sequence is the JWS Signature value.
|
||||
*/
|
||||
|
||||
ecdsasig = ECDSA_do_sign(in, (int)lws_genhash_size(hash_type), eckey);
|
||||
ecdsasig = ECDSA_do_sign(in, (int)hs, eckey);
|
||||
EC_KEY_free(eckey);
|
||||
if (!ecdsasig) {
|
||||
lwsl_notice("%s: ECDSA_do_sign fail\n", __func__);
|
||||
|
@ -567,8 +570,8 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
enum lws_genhash_types hash_type, int keybits,
|
||||
const uint8_t *sig, size_t sig_len)
|
||||
{
|
||||
int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits),
|
||||
hlen = (int)lws_genhash_size(hash_type);
|
||||
int ret = -1, n, hlen = (int)lws_genhash_size(hash_type),
|
||||
keybytes = lws_gencrypto_bits_to_bytes(keybits);
|
||||
ECDSA_SIG *ecsig = ECDSA_SIG_new();
|
||||
BIGNUM *r = NULL, *s = NULL;
|
||||
EC_KEY *eckey;
|
||||
|
@ -580,7 +583,7 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
goto bail;
|
||||
|
||||
if ((int)sig_len != keybytes * 2) {
|
||||
lwsl_err("%s: sig buf too small %d vs %d\n", __func__,
|
||||
lwsl_err("%s: sig buf size %d vs %d\n", __func__,
|
||||
(int)sig_len, keybytes * 2);
|
||||
goto bail;
|
||||
}
|
||||
|
@ -620,7 +623,7 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
|
|||
n = ECDSA_do_verify(in, hlen, ecsig, eckey);
|
||||
EC_KEY_free(eckey);
|
||||
if (n != 1) {
|
||||
lwsl_err("%s: ECDSA_do_verify fail\n", __func__);
|
||||
lwsl_err("%s: ECDSA_do_verify fail, hlen %d\n", __func__, (int)hlen);
|
||||
lws_tls_err_describe_clear();
|
||||
goto bail;
|
||||
}
|
||||
|
|
|
@ -83,12 +83,16 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
|
|||
unsigned int len;
|
||||
int ret = 0;
|
||||
|
||||
if (!ctx->mdctx)
|
||||
return 0;
|
||||
|
||||
if (result)
|
||||
ret = EVP_DigestFinal_ex(ctx->mdctx, result, &len) != 1;
|
||||
|
||||
(void)len;
|
||||
|
||||
EVP_MD_CTX_destroy(ctx->mdctx);
|
||||
ctx->mdctx = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ bail:
|
|||
}
|
||||
|
||||
int
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx,
|
||||
const struct lws_gencrypto_keyelem *el,
|
||||
struct lws_context *context, enum enum_genrsa_mode mode,
|
||||
enum lws_genhash_types oaep_hashid)
|
||||
{
|
||||
|
@ -293,7 +294,8 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
|
|||
|
||||
switch(ctx->mode) {
|
||||
case LGRSAM_PKCS1_1_5:
|
||||
n = RSA_verify(n, in, (unsigned int)h, (uint8_t *)sig, (unsigned int)sig_len, ctx->rsa);
|
||||
n = RSA_verify(n, in, (unsigned int)h, (uint8_t *)sig,
|
||||
(unsigned int)sig_len, ctx->rsa);
|
||||
break;
|
||||
case LGRSAM_PKCS1_OAEP_PSS:
|
||||
md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type);
|
||||
|
|
29
minimal-examples/api-tests/api-test-cose/CMakeLists.txt
Normal file
29
minimal-examples/api-tests/api-test-cose/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
project(lws-api-test-cose C)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
find_package(libwebsockets CONFIG REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
|
||||
include(CheckCSourceCompiles)
|
||||
include(LwsCheckRequirements)
|
||||
|
||||
set(SAMP lws-api-test-cose)
|
||||
set(SRCS main.c keys.c sign.c)
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITH_COSE 1 requirements)
|
||||
require_lws_config(LWS_WITH_CBOR 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (NOT (LWS_WITH_MBEDTLS AND NOT LWS_HAVE_mbedtls_internal_aes_encrypt))
|
||||
add_test(NAME api-test-cose COMMAND lws-api-test-cose)
|
||||
endif()
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
endif()
|
||||
endif()
|
22
minimal-examples/api-tests/api-test-cose/README.md
Normal file
22
minimal-examples/api-tests/api-test-cose/README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# lws api test lwsac
|
||||
|
||||
Demonstrates how to use and performs selftests for lwsac
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
Commandline option|Meaning
|
||||
---|---
|
||||
-d <loglevel>|Debug verbosity in decimal, eg, -d15
|
||||
|
||||
```
|
||||
$ ./lws-api-test-lwsac
|
||||
[2018/10/09 09:14:17:4834] USER: LWS API selftest: lwsac
|
||||
[2018/10/09 09:14:17:4835] USER: Completed: PASS
|
||||
```
|
||||
|
931
minimal-examples/api-tests/api-test-cose/keys.c
Normal file
931
minimal-examples/api-tests/api-test-cose/keys.c
Normal file
|
@ -0,0 +1,931 @@
|
|||
/*
|
||||
* lws-api-test-jose - RFC8152 cose_key tests
|
||||
*
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* Raw key CBOR created from descriptions at
|
||||
*
|
||||
* https://github.com/cose-wg/Examples/blob/master/KeySet.txt
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int
|
||||
key_import_cb(struct lws_cose_key *s, void *user)
|
||||
{
|
||||
lwsl_notice("%s: key type %lld\n", __func__, (long long)s->kty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint8_t
|
||||
cose_key1[] = {
|
||||
0xa6, 0x01, 0x02, 0x02, 0x62,
|
||||
0x31, 0x31, 0x20, 0x01, 0x21,
|
||||
0x58, 0x20, 0xba, 0xc5, 0xb1,
|
||||
0x1c, 0xad, 0x8f, 0x99, 0xf9,
|
||||
0xc7, 0x2b, 0x05, 0xcf, 0x4b,
|
||||
0x9e, 0x26, 0xd2, 0x44, 0xdc,
|
||||
0x18, 0x9f, 0x74, 0x52, 0x28,
|
||||
0x25, 0x5a, 0x21, 0x9a, 0x86,
|
||||
0xd6, 0xa0, 0x9e, 0xff, 0x22,
|
||||
0x58, 0x20, 0x20, 0x13, 0x8b,
|
||||
0xf8, 0x2d, 0xc1, 0xb6, 0xd5,
|
||||
0x62, 0xbe, 0x0f, 0xa5, 0x4a,
|
||||
0xb7, 0x80, 0x4a, 0x3a, 0x64,
|
||||
0xb6, 0xd7, 0x2c, 0xcf, 0xed,
|
||||
0x6b, 0x6f, 0xb6, 0xed, 0x28,
|
||||
0xbb, 0xfc, 0x11, 0x7e, 0x23,
|
||||
0x58, 0x20, 0x57, 0xc9, 0x20,
|
||||
0x77, 0x66, 0x41, 0x46, 0xe8,
|
||||
0x76, 0x76, 0x0c, 0x95, 0x20,
|
||||
0xd0, 0x54, 0xaa, 0x93, 0xc3,
|
||||
0xaf, 0xb0, 0x4e, 0x30, 0x67,
|
||||
0x05, 0xdb, 0x60, 0x90, 0x30,
|
||||
0x85, 0x07, 0xb4, 0xd3 },
|
||||
cose_key2[] = {
|
||||
0xa6, 0x01, 0x02, 0x02, 0x78,
|
||||
0x24, 0x6d, 0x65, 0x72, 0x69,
|
||||
0x61, 0x64, 0x6f, 0x63, 0x2e,
|
||||
0x62, 0x72, 0x61, 0x6e, 0x64,
|
||||
0x79, 0x62, 0x75, 0x63, 0x6b,
|
||||
0x40, 0x62, 0x75, 0x63, 0x6b,
|
||||
0x6c, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x20, 0x01, 0x21,
|
||||
0x58, 0x20, 0x65, 0xed, 0xa5,
|
||||
0xa1, 0x25, 0x77, 0xc2, 0xba,
|
||||
0xe8, 0x29, 0x43, 0x7f, 0xe3,
|
||||
0x38, 0x70, 0x1a, 0x10, 0xaa,
|
||||
0xa3, 0x75, 0xe1, 0xbb, 0x5b,
|
||||
0x5d, 0xe1, 0x08, 0xde, 0x43,
|
||||
0x9c, 0x08, 0x55, 0x1d, 0x22,
|
||||
0x58, 0x20, 0x1e, 0x52, 0xed,
|
||||
0x75, 0x70, 0x11, 0x63, 0xf7,
|
||||
0xf9, 0xe4, 0x0d, 0xdf, 0x9f,
|
||||
0x34, 0x1b, 0x3d, 0xc9, 0xba,
|
||||
0x86, 0x0a, 0xf7, 0xe0, 0xca,
|
||||
0x7c, 0xa7, 0xe9, 0xee, 0xcd,
|
||||
0x00, 0x84, 0xd1, 0x9c, 0x23,
|
||||
0x58, 0x20, 0xaf, 0xf9, 0x07,
|
||||
0xc9, 0x9f, 0x9a, 0xd3, 0xaa,
|
||||
0xe6, 0xc4, 0xcd, 0xf2, 0x11,
|
||||
0x22, 0xbc, 0xe2, 0xbd, 0x68,
|
||||
0xb5, 0x28, 0x3e, 0x69, 0x07,
|
||||
0x15, 0x4a, 0xd9, 0x11, 0x84,
|
||||
0x0f, 0xa2, 0x08, 0xcf },
|
||||
|
||||
cose_key3[] = { 0xa3, 0x01, 0x04, 0x02, 0x6a,
|
||||
0x6f, 0x75, 0x72, 0x2d, 0x73,
|
||||
0x65, 0x63, 0x72, 0x65, 0x74,
|
||||
0x20, 0x58, 0x20, 0x84, 0x9b,
|
||||
0x57, 0x21, 0x9d, 0xae, 0x48,
|
||||
0xde, 0x64, 0x6d, 0x07, 0xdb,
|
||||
0xb5, 0x33, 0x56, 0x6e, 0x97,
|
||||
0x66, 0x86, 0x45, 0x7c, 0x14,
|
||||
0x91, 0xbe, 0x3a, 0x76, 0xdc,
|
||||
0xea, 0x6c, 0x42, 0x71, 0x88 },
|
||||
|
||||
cose_key4[] = { 0xa6, 0x01, 0x02, 0x02, 0x78,
|
||||
0x1e, 0x62, 0x69, 0x6c, 0x62,
|
||||
0x6f, 0x2e, 0x62, 0x61, 0x67,
|
||||
0x67, 0x69, 0x6e, 0x73, 0x40,
|
||||
0x68, 0x6f, 0x62, 0x62, 0x69,
|
||||
0x74, 0x6f, 0x6e, 0x2e, 0x65,
|
||||
0x78, 0x61, 0x6d, 0x70, 0x6c,
|
||||
0x65, 0x20, 0x03, 0x21, 0x58,
|
||||
0x42, 0x00, 0x72, 0x99, 0x2c,
|
||||
0xb3, 0xac, 0x08, 0xec, 0xf3,
|
||||
0xe5, 0xc6, 0x3d, 0xed, 0xec,
|
||||
0x0d, 0x51, 0xa8, 0xc1, 0xf7,
|
||||
0x9e, 0xf2, 0xf8, 0x2f, 0x94,
|
||||
0xf3, 0xc7, 0x37, 0xbf, 0x5d,
|
||||
0xe7, 0x98, 0x66, 0x71, 0xea,
|
||||
0xc6, 0x25, 0xfe, 0x82, 0x57,
|
||||
0xbb, 0xd0, 0x39, 0x46, 0x44,
|
||||
0xca, 0xaa, 0x3a, 0xaf, 0x8f,
|
||||
0x27, 0xa4, 0x58, 0x5f, 0xbb,
|
||||
0xca, 0xd0, 0xf2, 0x45, 0x76,
|
||||
0x20, 0x08, 0x5e, 0x5c, 0x8f,
|
||||
0x42, 0xad, 0x22, 0x58, 0x42,
|
||||
0x01, 0xdc, 0xa6, 0x94, 0x7b,
|
||||
0xce, 0x88, 0xbc, 0x57, 0x90,
|
||||
0x48, 0x5a, 0xc9, 0x74, 0x27,
|
||||
0x34, 0x2b, 0xc3, 0x5f, 0x88,
|
||||
0x7d, 0x86, 0xd6, 0x5a, 0x08,
|
||||
0x93, 0x77, 0xe2, 0x47, 0xe6,
|
||||
0x0b, 0xaa, 0x55, 0xe4, 0xe8,
|
||||
0x50, 0x1e, 0x2a, 0xda, 0x57,
|
||||
0x24, 0xac, 0x51, 0xd6, 0x90,
|
||||
0x90, 0x08, 0x03, 0x3e, 0xbc,
|
||||
0x10, 0xac, 0x99, 0x9b, 0x9d,
|
||||
0x7f, 0x5c, 0xc2, 0x51, 0x9f,
|
||||
0x3f, 0xe1, 0xea, 0x1d, 0x94,
|
||||
0x75, 0x23, 0x58, 0x42, 0x00,
|
||||
0x08, 0x51, 0x38, 0xdd, 0xab,
|
||||
0xf5, 0xca, 0x97, 0x5f, 0x58,
|
||||
0x60, 0xf9, 0x1a, 0x08, 0xe9,
|
||||
0x1d, 0x6d, 0x5f, 0x9a, 0x76,
|
||||
0xad, 0x40, 0x18, 0x76, 0x6a,
|
||||
0x47, 0x66, 0x80, 0xb5, 0x5c,
|
||||
0xd3, 0x39, 0xe8, 0xab, 0x6c,
|
||||
0x72, 0xb5, 0xfa, 0xcd, 0xb2,
|
||||
0xa2, 0xa5, 0x0a, 0xc2, 0x5b,
|
||||
0xd0, 0x86, 0x64, 0x7d, 0xd3,
|
||||
0xe2, 0xe6, 0xe9, 0x9e, 0x84,
|
||||
0xca, 0x2c, 0x36, 0x09, 0xfd,
|
||||
0xf1, 0x77, 0xfe, 0xb2, 0x6d },
|
||||
cose_key5[] = { 0xa3, 0x01, 0x04, 0x02, 0x6b,
|
||||
0x6f, 0x75, 0x72, 0x2d, 0x73,
|
||||
0x65, 0x63, 0x72, 0x65, 0x74,
|
||||
0x32, 0x20, 0x50, 0x84, 0x9b,
|
||||
0x57, 0x86, 0x45, 0x7c, 0x14,
|
||||
0x91, 0xbe, 0x3a, 0x76, 0xdc,
|
||||
0xea, 0x6c, 0x42, 0x71 },
|
||||
|
||||
cose_key6[] = { 0xa6, 0x01, 0x02, 0x02, 0x78,
|
||||
0x21, 0x70, 0x65, 0x72, 0x65,
|
||||
0x67, 0x72, 0x69, 0x6e, 0x2e,
|
||||
0x74, 0x6f, 0x6f, 0x6b, 0x40,
|
||||
0x74, 0x75, 0x63, 0x6b, 0x62,
|
||||
0x6f, 0x72, 0x6f, 0x75, 0x67,
|
||||
0x68, 0x2e, 0x65, 0x78, 0x61,
|
||||
0x6d, 0x70, 0x6c, 0x65, 0x20,
|
||||
0x01, 0x21, 0x58, 0x20, 0x98,
|
||||
0xf5, 0x0a, 0x4f, 0xf6, 0xc0,
|
||||
0x58, 0x61, 0xc8, 0x86, 0x0d,
|
||||
0x13, 0xa6, 0x38, 0xea, 0x56,
|
||||
0xc3, 0xf5, 0xad, 0x75, 0x90,
|
||||
0xbb, 0xfb, 0xf0, 0x54, 0xe1,
|
||||
0xc7, 0xb4, 0xd9, 0x1d, 0x62,
|
||||
0x80, 0x22, 0x58, 0x20, 0xf0,
|
||||
0x14, 0x00, 0xb0, 0x89, 0x86,
|
||||
0x78, 0x04, 0xb8, 0xe9, 0xfc,
|
||||
0x96, 0xc3, 0x93, 0x21, 0x61,
|
||||
0xf1, 0x93, 0x4f, 0x42, 0x23,
|
||||
0x06, 0x91, 0x70, 0xd9, 0x24,
|
||||
0xb7, 0xe0, 0x3b, 0xf8, 0x22,
|
||||
0xbb, 0x23, 0x58, 0x20, 0x02,
|
||||
0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
|
||||
0x43, 0xd4, 0x86, 0x8d, 0x87,
|
||||
0xce, 0xb2, 0x35, 0x31, 0x61,
|
||||
0x74, 0x0a, 0xac, 0xf1, 0xf7,
|
||||
0x16, 0x36, 0x47, 0x98, 0x4b,
|
||||
0x52, 0x2a, 0x84, 0x8d, 0xf1,
|
||||
0xc3 },
|
||||
cose_key7[] = { 0xa3, 0x01, 0x04, 0x02, 0x58,
|
||||
0x24, 0x30, 0x31, 0x38, 0x63,
|
||||
0x30, 0x61, 0x65, 0x35, 0x2d,
|
||||
0x34, 0x64, 0x39, 0x62, 0x2d,
|
||||
0x34, 0x37, 0x31, 0x62, 0x2d,
|
||||
0x62, 0x66, 0x64, 0x36, 0x2d,
|
||||
0x65, 0x65, 0x66, 0x33, 0x31,
|
||||
0x34, 0x62, 0x63, 0x37, 0x30,
|
||||
0x33, 0x37, 0x20, 0x58, 0x20,
|
||||
0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88 },
|
||||
|
||||
cose_key8[] = {
|
||||
/* kid "sec-48" for hmac 384 */
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x66,
|
||||
0x73, 0x65, 0x63, 0x2d, 0x34,
|
||||
0x38, 0x20, 0x58, 0x30, 0x84,
|
||||
0x9b, 0x57, 0x21, 0x9d, 0xae,
|
||||
0x48, 0xde, 0x64, 0x6d, 0x07,
|
||||
0xdb, 0xb5, 0x33, 0x56, 0x6e,
|
||||
0x97, 0x66, 0x86, 0x45, 0x7c,
|
||||
0x14, 0x91, 0xbe, 0x3a, 0x76,
|
||||
0xdc, 0xea, 0x6c, 0x42, 0x71,
|
||||
0x88, 0x00, 0x11, 0x22, 0x33,
|
||||
0x77, 0x88, 0x99, 0xaa, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26,
|
||||
0x27, 0x28
|
||||
},
|
||||
|
||||
cose_key9[] = {
|
||||
/* kid "sec-64" for hmac 512 */
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x46,
|
||||
0x73, 0x65, 0x63, 0x2d, 0x36,
|
||||
0x34, 0x20, 0x58, 0x40, 0x84,
|
||||
0x9b, 0x57, 0x21, 0x9d, 0xae,
|
||||
0x48, 0xde, 0x64, 0x6d, 0x07,
|
||||
0xdb, 0xb5, 0x33, 0x56, 0x6e,
|
||||
0x97, 0x66, 0x86, 0x45, 0x7c,
|
||||
0x14, 0x91, 0xbe, 0x3a, 0x76,
|
||||
0xdc, 0xea, 0x6c, 0x42, 0x71,
|
||||
0x88, 0x00, 0x11, 0x22, 0x33,
|
||||
0x77, 0x88, 0x99, 0xaa, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26,
|
||||
0x27, 0x28, 0xaa, 0xbb, 0xcc,
|
||||
0xdd, 0xee, 0xff, 0xa5, 0xa6,
|
||||
0xa7, 0xa8, 0xa9, 0xa0, 0xb1,
|
||||
0xb2, 0xb3, 0xb4,
|
||||
},
|
||||
|
||||
cose_key10[] = { /* kid "11" (again) ed22519 OKP key */
|
||||
0xa5, 0x01, 0x01, 0x02, 0x42,
|
||||
0x31, 0x31, 0x20, 0x06, 0x21,
|
||||
0x58, 0x20, 0xd7, 0x5a, 0x98,
|
||||
0x01, 0x82, 0xb1, 0x0a, 0xb7,
|
||||
0xd5, 0x4b, 0xfe, 0xd3, 0xc9,
|
||||
0x64, 0x07, 0x3a, 0x0e, 0xe1,
|
||||
0x72, 0xf3, 0xda, 0xa6, 0x23,
|
||||
0x25, 0xaf, 0x02, 0x1a, 0x68,
|
||||
0xf7, 0x07, 0x51, 0x1a, 0x23,
|
||||
0x58, 0x20, 0x9d, 0x61, 0xb1,
|
||||
0x9d, 0xef, 0xfd, 0x5a, 0x60,
|
||||
0xba, 0x84, 0x4a, 0xf4, 0x92,
|
||||
0xec, 0x2c, 0xc4, 0x44, 0x49,
|
||||
0xc5, 0x69, 0x7b, 0x32, 0x69,
|
||||
0x19, 0x70, 0x3b, 0xac, 0x03,
|
||||
0x1c, 0xae, 0x7f, 0x60
|
||||
},
|
||||
|
||||
cose_key_set1[] = {
|
||||
|
||||
0x89,
|
||||
|
||||
0xa6, 0x01, 0x02, 0x02, 0x42,
|
||||
0x31, 0x31, 0x20, 0x01, 0x21,
|
||||
0x58, 0x20, 0xba, 0xc5, 0xb1,
|
||||
0x1c, 0xad, 0x8f, 0x99, 0xf9,
|
||||
0xc7, 0x2b, 0x05, 0xcf, 0x4b,
|
||||
0x9e, 0x26, 0xd2, 0x44, 0xdc,
|
||||
0x18, 0x9f, 0x74, 0x52, 0x28,
|
||||
0x25, 0x5a, 0x21, 0x9a, 0x86,
|
||||
0xd6, 0xa0, 0x9e, 0xff, 0x22,
|
||||
0x58, 0x20, 0x20, 0x13, 0x8b,
|
||||
0xf8, 0x2d, 0xc1, 0xb6, 0xd5,
|
||||
0x62, 0xbe, 0x0f, 0xa5, 0x4a,
|
||||
0xb7, 0x80, 0x4a, 0x3a, 0x64,
|
||||
0xb6, 0xd7, 0x2c, 0xcf, 0xed,
|
||||
0x6b, 0x6f, 0xb6, 0xed, 0x28,
|
||||
0xbb, 0xfc, 0x11, 0x7e, 0x23,
|
||||
0x58, 0x20, 0x57, 0xc9, 0x20,
|
||||
0x77, 0x66, 0x41, 0x46, 0xe8,
|
||||
0x76, 0x76, 0x0c, 0x95, 0x20,
|
||||
0xd0, 0x54, 0xaa, 0x93, 0xc3,
|
||||
0xaf, 0xb0, 0x4e, 0x30, 0x67,
|
||||
0x05, 0xdb, 0x60, 0x90, 0x30,
|
||||
0x85, 0x07, 0xb4, 0xd3,
|
||||
|
||||
0xa6, 0x01, 0x02, 0x02, 0x58,
|
||||
0x24, 0x6d, 0x65, 0x72, 0x69,
|
||||
0x61, 0x64, 0x6f, 0x63, 0x2e,
|
||||
0x62, 0x72, 0x61, 0x6e, 0x64,
|
||||
0x79, 0x62, 0x75, 0x63, 0x6b,
|
||||
0x40, 0x62, 0x75, 0x63, 0x6b,
|
||||
0x6c, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x20, 0x01, 0x21,
|
||||
0x58, 0x20, 0x65, 0xed, 0xa5,
|
||||
0xa1, 0x25, 0x77, 0xc2, 0xba,
|
||||
0xe8, 0x29, 0x43, 0x7f, 0xe3,
|
||||
0x38, 0x70, 0x1a, 0x10, 0xaa,
|
||||
0xa3, 0x75, 0xe1, 0xbb, 0x5b,
|
||||
0x5d, 0xe1, 0x08, 0xde, 0x43,
|
||||
0x9c, 0x08, 0x55, 0x1d, 0x22,
|
||||
0x58, 0x20, 0x1e, 0x52, 0xed,
|
||||
0x75, 0x70, 0x11, 0x63, 0xf7,
|
||||
0xf9, 0xe4, 0x0d, 0xdf, 0x9f,
|
||||
0x34, 0x1b, 0x3d, 0xc9, 0xba,
|
||||
0x86, 0x0a, 0xf7, 0xe0, 0xca,
|
||||
0x7c, 0xa7, 0xe9, 0xee, 0xcd,
|
||||
0x00, 0x84, 0xd1, 0x9c, 0x23,
|
||||
0x58, 0x20, 0xaf, 0xf9, 0x07,
|
||||
0xc9, 0x9f, 0x9a, 0xd3, 0xaa,
|
||||
0xe6, 0xc4, 0xcd, 0xf2, 0x11,
|
||||
0x22, 0xbc, 0xe2, 0xbd, 0x68,
|
||||
0xb5, 0x28, 0x3e, 0x69, 0x07,
|
||||
0x15, 0x4a, 0xd9, 0x11, 0x84,
|
||||
0x0f, 0xa2, 0x08, 0xcf,
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x4a,
|
||||
0x6f, 0x75, 0x72, 0x2d, 0x73,
|
||||
0x65, 0x63, 0x72, 0x65, 0x74,
|
||||
0x20, 0x58, 0x20, 0x84, 0x9b,
|
||||
0x57, 0x21, 0x9d, 0xae, 0x48,
|
||||
0xde, 0x64, 0x6d, 0x07, 0xdb,
|
||||
0xb5, 0x33, 0x56, 0x6e, 0x97,
|
||||
0x66, 0x86, 0x45, 0x7c, 0x14,
|
||||
0x91, 0xbe, 0x3a, 0x76, 0xdc,
|
||||
0xea, 0x6c, 0x42, 0x71, 0x88,
|
||||
|
||||
0xa6, 0x01, 0x02, 0x02, 0x58,
|
||||
0x1e, 0x62, 0x69, 0x6c, 0x62,
|
||||
0x6f, 0x2e, 0x62, 0x61, 0x67,
|
||||
0x67, 0x69, 0x6e, 0x73, 0x40,
|
||||
0x68, 0x6f, 0x62, 0x62, 0x69,
|
||||
0x74, 0x6f, 0x6e, 0x2e, 0x65,
|
||||
0x78, 0x61, 0x6d, 0x70, 0x6c,
|
||||
0x65, 0x20, 0x03, 0x21, 0x58,
|
||||
0x42, 0x00, 0x72, 0x99, 0x2c,
|
||||
0xb3, 0xac, 0x08, 0xec, 0xf3,
|
||||
0xe5, 0xc6, 0x3d, 0xed, 0xec,
|
||||
0x0d, 0x51, 0xa8, 0xc1, 0xf7,
|
||||
0x9e, 0xf2, 0xf8, 0x2f, 0x94,
|
||||
0xf3, 0xc7, 0x37, 0xbf, 0x5d,
|
||||
0xe7, 0x98, 0x66, 0x71, 0xea,
|
||||
0xc6, 0x25, 0xfe, 0x82, 0x57,
|
||||
0xbb, 0xd0, 0x39, 0x46, 0x44,
|
||||
0xca, 0xaa, 0x3a, 0xaf, 0x8f,
|
||||
0x27, 0xa4, 0x58, 0x5f, 0xbb,
|
||||
0xca, 0xd0, 0xf2, 0x45, 0x76,
|
||||
0x20, 0x08, 0x5e, 0x5c, 0x8f,
|
||||
0x42, 0xad, 0x22, 0x58, 0x42,
|
||||
0x01, 0xdc, 0xa6, 0x94, 0x7b,
|
||||
0xce, 0x88, 0xbc, 0x57, 0x90,
|
||||
0x48, 0x5a, 0xc9, 0x74, 0x27,
|
||||
0x34, 0x2b, 0xc3, 0x5f, 0x88,
|
||||
0x7d, 0x86, 0xd6, 0x5a, 0x08,
|
||||
0x93, 0x77, 0xe2, 0x47, 0xe6,
|
||||
0x0b, 0xaa, 0x55, 0xe4, 0xe8,
|
||||
0x50, 0x1e, 0x2a, 0xda, 0x57,
|
||||
0x24, 0xac, 0x51, 0xd6, 0x90,
|
||||
0x90, 0x08, 0x03, 0x3e, 0xbc,
|
||||
0x10, 0xac, 0x99, 0x9b, 0x9d,
|
||||
0x7f, 0x5c, 0xc2, 0x51, 0x9f,
|
||||
0x3f, 0xe1, 0xea, 0x1d, 0x94,
|
||||
0x75, 0x23, 0x58, 0x42, 0x00,
|
||||
0x08, 0x51, 0x38, 0xdd, 0xab,
|
||||
0xf5, 0xca, 0x97, 0x5f, 0x58,
|
||||
0x60, 0xf9, 0x1a, 0x08, 0xe9,
|
||||
0x1d, 0x6d, 0x5f, 0x9a, 0x76,
|
||||
0xad, 0x40, 0x18, 0x76, 0x6a,
|
||||
0x47, 0x66, 0x80, 0xb5, 0x5c,
|
||||
0xd3, 0x39, 0xe8, 0xab, 0x6c,
|
||||
0x72, 0xb5, 0xfa, 0xcd, 0xb2,
|
||||
0xa2, 0xa5, 0x0a, 0xc2, 0x5b,
|
||||
0xd0, 0x86, 0x64, 0x7d, 0xd3,
|
||||
0xe2, 0xe6, 0xe9, 0x9e, 0x84,
|
||||
0xca, 0x2c, 0x36, 0x09, 0xfd,
|
||||
0xf1, 0x77, 0xfe, 0xb2, 0x6d,
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x4b,
|
||||
0x6f, 0x75, 0x72, 0x2d, 0x73,
|
||||
0x65, 0x63, 0x72, 0x65, 0x74,
|
||||
0x32, 0x20, 0x50, 0x84, 0x9b,
|
||||
0x57, 0x86, 0x45, 0x7c, 0x14,
|
||||
0x91, 0xbe, 0x3a, 0x76, 0xdc,
|
||||
0xea, 0x6c, 0x42, 0x71,
|
||||
|
||||
0xa6, 0x01, 0x02, 0x02, 0x58,
|
||||
0x21, 0x70, 0x65, 0x72, 0x65,
|
||||
0x67, 0x72, 0x69, 0x6e, 0x2e,
|
||||
0x74, 0x6f, 0x6f, 0x6b, 0x40,
|
||||
0x74, 0x75, 0x63, 0x6b, 0x62,
|
||||
0x6f, 0x72, 0x6f, 0x75, 0x67,
|
||||
0x68, 0x2e, 0x65, 0x78, 0x61,
|
||||
0x6d, 0x70, 0x6c, 0x65, 0x20,
|
||||
0x01, 0x21, 0x58, 0x20, 0x98,
|
||||
0xf5, 0x0a, 0x4f, 0xf6, 0xc0,
|
||||
0x58, 0x61, 0xc8, 0x86, 0x0d,
|
||||
0x13, 0xa6, 0x38, 0xea, 0x56,
|
||||
0xc3, 0xf5, 0xad, 0x75, 0x90,
|
||||
0xbb, 0xfb, 0xf0, 0x54, 0xe1,
|
||||
0xc7, 0xb4, 0xd9, 0x1d, 0x62,
|
||||
0x80, 0x22, 0x58, 0x20, 0xf0,
|
||||
0x14, 0x00, 0xb0, 0x89, 0x86,
|
||||
0x78, 0x04, 0xb8, 0xe9, 0xfc,
|
||||
0x96, 0xc3, 0x93, 0x21, 0x61,
|
||||
0xf1, 0x93, 0x4f, 0x42, 0x23,
|
||||
0x06, 0x91, 0x70, 0xd9, 0x24,
|
||||
0xb7, 0xe0, 0x3b, 0xf8, 0x22,
|
||||
0xbb, 0x23, 0x58, 0x20, 0x02,
|
||||
0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
|
||||
0x43, 0xd4, 0x86, 0x8d, 0x87,
|
||||
0xce, 0xb2, 0x35, 0x31, 0x61,
|
||||
0x74, 0x0a, 0xac, 0xf1, 0xf7,
|
||||
0x16, 0x36, 0x47, 0x98, 0x4b,
|
||||
0x52, 0x2a, 0x84, 0x8d, 0xf1,
|
||||
0xc3,
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x58,
|
||||
0x24, 0x30, 0x31, 0x38, 0x63,
|
||||
0x30, 0x61, 0x65, 0x35, 0x2d,
|
||||
0x34, 0x64, 0x39, 0x62, 0x2d,
|
||||
0x34, 0x37, 0x31, 0x62, 0x2d,
|
||||
0x62, 0x66, 0x64, 0x36, 0x2d,
|
||||
0x65, 0x65, 0x66, 0x33, 0x31,
|
||||
0x34, 0x62, 0x63, 0x37, 0x30,
|
||||
0x33, 0x37, 0x04, 0x58, 0x20,
|
||||
0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88,
|
||||
|
||||
/* kid "sec-48" for hmac 384 */
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x46,
|
||||
0x73, 0x65, 0x63, 0x2d, 0x34,
|
||||
0x38, 0x20, 0x58, 0x30, 0x84,
|
||||
0x9b, 0x57, 0x21, 0x9d, 0xae,
|
||||
0x48, 0xde, 0x64, 0x6d, 0x07,
|
||||
0xdb, 0xb5, 0x33, 0x56, 0x6e,
|
||||
0x97, 0x66, 0x86, 0x45, 0x7c,
|
||||
0x14, 0x91, 0xbe, 0x3a, 0x76,
|
||||
0xdc, 0xea, 0x6c, 0x42, 0x71,
|
||||
0x88, 0x00, 0x11, 0x22, 0x33,
|
||||
0x77, 0x88, 0x99, 0xaa, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26,
|
||||
0x27, 0x28,
|
||||
|
||||
/* kid "sec-64" for hmac 512 */
|
||||
|
||||
0xa3, 0x01, 0x04, 0x02, 0x46,
|
||||
0x73, 0x65, 0x63, 0x2d, 0x36,
|
||||
0x34, 0x20, 0x58, 0x40, 0x84,
|
||||
0x9b, 0x57, 0x21, 0x9d, 0xae,
|
||||
0x48, 0xde, 0x64, 0x6d, 0x07,
|
||||
0xdb, 0xb5, 0x33, 0x56, 0x6e,
|
||||
0x97, 0x66, 0x86, 0x45, 0x7c,
|
||||
0x14, 0x91, 0xbe, 0x3a, 0x76,
|
||||
0xdc, 0xea, 0x6c, 0x42, 0x71,
|
||||
0x88, 0x00, 0x11, 0x22, 0x33,
|
||||
0x77, 0x88, 0x99, 0xaa, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26,
|
||||
0x27, 0x28, 0xaa, 0xbb, 0xcc,
|
||||
0xdd, 0xee, 0xff, 0xa5, 0xa6,
|
||||
0xa7, 0xa8, 0xa9, 0xa0, 0xb1,
|
||||
0xb2, 0xb3, 0xb4,
|
||||
}
|
||||
;
|
||||
|
||||
struct keyinfo {
|
||||
const uint8_t *set;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct keyinfo keyset1 = { cose_key_set1, sizeof(cose_key_set1) },
|
||||
key3 = { cose_key3, sizeof(cose_key3) },
|
||||
key8 = { cose_key8, sizeof(cose_key8) },
|
||||
key9 = { cose_key9, sizeof(cose_key9) },
|
||||
key10 = { cose_key10, sizeof(cose_key10) }
|
||||
;
|
||||
|
||||
/* key pieces */
|
||||
|
||||
static const uint8_t
|
||||
key1_x[] = { 0xba, 0xc5, 0xb1, 0x1c, 0xad,
|
||||
0x8f, 0x99, 0xf9, 0xc7, 0x2b,
|
||||
0x05, 0xcf, 0x4b, 0x9e, 0x26,
|
||||
0xd2, 0x44, 0xdc, 0x18, 0x9f,
|
||||
0x74, 0x52, 0x28, 0x25, 0x5a,
|
||||
0x21, 0x9a, 0x86, 0xd6, 0xa0,
|
||||
0x9e, 0xff },
|
||||
key1_y[] = { 0x20, 0x13, 0x8b, 0xf8, 0x2d,
|
||||
0xc1, 0xb6, 0xd5, 0x62, 0xbe,
|
||||
0x0f, 0xa5, 0x4a, 0xb7, 0x80,
|
||||
0x4a, 0x3a, 0x64, 0xb6, 0xd7,
|
||||
0x2c, 0xcf, 0xed, 0x6b, 0x6f,
|
||||
0xb6, 0xed, 0x28, 0xbb, 0xfc,
|
||||
0x11, 0x7e },
|
||||
key1_d[] = { 0x57, 0xc9, 0x20, 0x77, 0x66,
|
||||
0x41, 0x46, 0xe8, 0x76, 0x76,
|
||||
0x0c, 0x95, 0x20, 0xd0, 0x54,
|
||||
0xaa, 0x93, 0xc3, 0xaf, 0xb0,
|
||||
0x4e, 0x30, 0x67, 0x05, 0xdb,
|
||||
0x60, 0x90, 0x30, 0x85, 0x07,
|
||||
0xb4, 0xd3 },
|
||||
|
||||
key2_x[] = { 0x65, 0xed, 0xa5, 0xa1, 0x25,
|
||||
0x77, 0xc2, 0xba, 0xe8, 0x29,
|
||||
0x43, 0x7f, 0xe3, 0x38, 0x70,
|
||||
0x1a, 0x10, 0xaa, 0xa3, 0x75,
|
||||
0xe1, 0xbb, 0x5b, 0x5d, 0xe1,
|
||||
0x08, 0xde, 0x43, 0x9c, 0x08,
|
||||
0x55, 0x1d },
|
||||
key2_y[] = { 0x1e, 0x52, 0xed, 0x75, 0x70,
|
||||
0x11, 0x63, 0xf7, 0xf9, 0xe4,
|
||||
0x0d, 0xdf, 0x9f, 0x34, 0x1b,
|
||||
0x3d, 0xc9, 0xba, 0x86, 0x0a,
|
||||
0xf7, 0xe0, 0xca, 0x7c, 0xa7,
|
||||
0xe9, 0xee, 0xcd, 0x00, 0x84,
|
||||
0xd1, 0x9c },
|
||||
key2_d[] = { 0xaf, 0xf9, 0x07, 0xc9, 0x9f,
|
||||
0x9a, 0xd3, 0xaa, 0xe6, 0xc4,
|
||||
0xcd, 0xf2, 0x11, 0x22, 0xbc,
|
||||
0xe2, 0xbd, 0x68, 0xb5, 0x28,
|
||||
0x3e, 0x69, 0x07, 0x15, 0x4a,
|
||||
0xd9, 0x11, 0x84, 0x0f, 0xa2,
|
||||
0x08, 0xcf },
|
||||
|
||||
key3_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88 },
|
||||
|
||||
key4_x[] = { 0x00, 0x72, 0x99, 0x2c, 0xb3,
|
||||
0xac, 0x08, 0xec, 0xf3, 0xe5,
|
||||
0xc6, 0x3d, 0xed, 0xec, 0x0d,
|
||||
0x51, 0xa8, 0xc1, 0xf7, 0x9e,
|
||||
0xf2, 0xf8, 0x2f, 0x94, 0xf3,
|
||||
0xc7, 0x37, 0xbf, 0x5d, 0xe7,
|
||||
0x98, 0x66, 0x71, 0xea, 0xc6,
|
||||
0x25, 0xfe, 0x82, 0x57, 0xbb,
|
||||
0xd0, 0x39, 0x46, 0x44, 0xca,
|
||||
0xaa, 0x3a, 0xaf, 0x8f, 0x27,
|
||||
0xa4, 0x58, 0x5f, 0xbb, 0xca,
|
||||
0xd0, 0xf2, 0x45, 0x76, 0x20,
|
||||
0x08, 0x5e, 0x5c, 0x8f, 0x42,
|
||||
0xad },
|
||||
key4_y[] = { 0x01, 0xdc, 0xa6, 0x94, 0x7b,
|
||||
0xce, 0x88, 0xbc, 0x57, 0x90,
|
||||
0x48, 0x5a, 0xc9, 0x74, 0x27,
|
||||
0x34, 0x2b, 0xc3, 0x5f, 0x88,
|
||||
0x7d, 0x86, 0xd6, 0x5a, 0x08,
|
||||
0x93, 0x77, 0xe2, 0x47, 0xe6,
|
||||
0x0b, 0xaa, 0x55, 0xe4, 0xe8,
|
||||
0x50, 0x1e, 0x2a, 0xda, 0x57,
|
||||
0x24, 0xac, 0x51, 0xd6, 0x90,
|
||||
0x90, 0x08, 0x03, 0x3e, 0xbc,
|
||||
0x10, 0xac, 0x99, 0x9b, 0x9d,
|
||||
0x7f, 0x5c, 0xc2, 0x51, 0x9f,
|
||||
0x3f, 0xe1, 0xea, 0x1d, 0x94,
|
||||
0x75 },
|
||||
key4_d[] = { 0x00, 0x08, 0x51, 0x38, 0xdd,
|
||||
0xab, 0xf5, 0xca, 0x97, 0x5f,
|
||||
0x58, 0x60, 0xf9, 0x1a, 0x08,
|
||||
0xe9, 0x1d, 0x6d, 0x5f, 0x9a,
|
||||
0x76, 0xad, 0x40, 0x18, 0x76,
|
||||
0x6a, 0x47, 0x66, 0x80, 0xb5,
|
||||
0x5c, 0xd3, 0x39, 0xe8, 0xab,
|
||||
0x6c, 0x72, 0xb5, 0xfa, 0xcd,
|
||||
0xb2, 0xa2, 0xa5, 0x0a, 0xc2,
|
||||
0x5b, 0xd0, 0x86, 0x64, 0x7d,
|
||||
0xd3, 0xe2, 0xe6, 0xe9, 0x9e,
|
||||
0x84, 0xca, 0x2c, 0x36, 0x09,
|
||||
0xfd, 0xf1, 0x77, 0xfe, 0xb2,
|
||||
0x6d },
|
||||
key5_k[] = { 0x84, 0x9b, 0x57, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71 },
|
||||
|
||||
key6_x[] = { 0x98, 0xf5, 0x0a, 0x4f, 0xf6,
|
||||
0xc0, 0x58, 0x61, 0xc8, 0x86,
|
||||
0x0d, 0x13, 0xa6, 0x38, 0xea,
|
||||
0x56, 0xc3, 0xf5, 0xad, 0x75,
|
||||
0x90, 0xbb, 0xfb, 0xf0, 0x54,
|
||||
0xe1, 0xc7, 0xb4, 0xd9, 0x1d,
|
||||
0x62, 0x80 },
|
||||
key6_y[] = { 0xf0, 0x14, 0x00, 0xb0, 0x89,
|
||||
0x86, 0x78, 0x04, 0xb8, 0xe9,
|
||||
0xfc, 0x96, 0xc3, 0x93, 0x21,
|
||||
0x61, 0xf1, 0x93, 0x4f, 0x42,
|
||||
0x23, 0x06, 0x91, 0x70, 0xd9,
|
||||
0x24, 0xb7, 0xe0, 0x3b, 0xf8,
|
||||
0x22, 0xbb },
|
||||
key6_d[] = { 0x02, 0xd1, 0xf7, 0xe6, 0xf2,
|
||||
0x6c, 0x43, 0xd4, 0x86, 0x8d,
|
||||
0x87, 0xce, 0xb2, 0x35, 0x31,
|
||||
0x61, 0x74, 0x0a, 0xac, 0xf1,
|
||||
0xf7, 0x16, 0x36, 0x47, 0x98,
|
||||
0x4b, 0x52, 0x2a, 0x84, 0x8d,
|
||||
0xf1, 0xc3 },
|
||||
|
||||
key7_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88 },
|
||||
|
||||
key8_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88, 0x00, 0x11, 0x22,
|
||||
0x33, 0x77, 0x88, 0x99, 0xaa,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x26, 0x27, 0x28 },
|
||||
|
||||
key9_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
|
||||
0xae, 0x48, 0xde, 0x64, 0x6d,
|
||||
0x07, 0xdb, 0xb5, 0x33, 0x56,
|
||||
0x6e, 0x97, 0x66, 0x86, 0x45,
|
||||
0x7c, 0x14, 0x91, 0xbe, 0x3a,
|
||||
0x76, 0xdc, 0xea, 0x6c, 0x42,
|
||||
0x71, 0x88, 0x00, 0x11, 0x22,
|
||||
0x33, 0x77, 0x88, 0x99, 0xaa,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x26, 0x27, 0x28, 0xaa, 0xbb,
|
||||
0xcc, 0xdd, 0xee, 0xff, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xa0,
|
||||
0xb1, 0xb2, 0xb3, 0xb4 }
|
||||
#if 0
|
||||
,
|
||||
key10_x[] = {
|
||||
0xd7, 0x5a, 0x98, 0x01, 0x82,
|
||||
0xb1, 0x0a, 0xb7, 0xd5, 0x4b,
|
||||
0xfe, 0xd3, 0xc9, 0x64, 0x07,
|
||||
0x3a, 0x0e, 0xe1, 0x72, 0xf3,
|
||||
0xda, 0xa6, 0x23, 0x25, 0xaf,
|
||||
0x02, 0x1a, 0x68, 0xf7, 0x07,
|
||||
0x51, 0x1a
|
||||
}, key10_d[] = {
|
||||
0x9d, 0x61, 0xb1, 0x9d, 0xef,
|
||||
0xfd, 0x5a, 0x60, 0xba, 0x84,
|
||||
0x4a, 0xf4, 0x92, 0xec, 0x2c,
|
||||
0xc4, 0x44, 0x49, 0xc5, 0x69,
|
||||
0x7b, 0x32, 0x69, 0x19, 0x70,
|
||||
0x3b, 0xac, 0x03, 0x1c, 0xae,
|
||||
0x7f, 0x60
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
int
|
||||
test_cose_keys(struct lws_context *context)
|
||||
{
|
||||
struct lws_cose_key *ck;
|
||||
lws_dll2_owner_t set;
|
||||
lws_lec_pctx_t wc;
|
||||
uint8_t buf[4096];
|
||||
int n;
|
||||
|
||||
#if 0
|
||||
{
|
||||
int fd = open("set1.cks",
|
||||
LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
|
||||
|
||||
if (fd >= 0) {
|
||||
write(fd, cose_key_set1, sizeof(cose_key_set1));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
lws_lec_pctx_t wx;
|
||||
uint8_t dump[8192];
|
||||
|
||||
lws_lec_init(&wx, buf, sizeof(buf));
|
||||
|
||||
if (lws_lec_printf(&wx,
|
||||
"{%d:%d, %d:%.*b, %d:%d, %d:%.*b, %d:%.*b}",
|
||||
LWSCOSE_WKK_KTY, LWSCOSE_WKKTV_OKP,
|
||||
LWSCOSE_WKK_KID, 2, "11",
|
||||
LWSCOSE_WKOKP_CRV, LWSCOSE_WKEC_ED25519,
|
||||
LWSCOSE_WKECKP_X, (int)sizeof(key10_x), key10_x,
|
||||
// LWSCOSE_WKECKP_Y, (int)sizeof(key6_y), key6_y,
|
||||
LWSCOSE_WKECKP_D, (int)sizeof(key10_d), key10_d) !=
|
||||
LWS_LECPCTX_RET_FINISHED)
|
||||
return 1;
|
||||
|
||||
lws_hex_from_byte_array(buf, wx.used, (char *)dump, sizeof(dump));
|
||||
puts((const char *)dump);
|
||||
#endif
|
||||
#if 0
|
||||
lws_lec_pctx_t wx;
|
||||
uint8_t dump[8192];
|
||||
|
||||
lws_lec_init(&wx, buf, sizeof(buf));
|
||||
|
||||
if (lws_lec_printf(&wx,
|
||||
"{%d:%d, %d:%.*b, %d:%.*b}",
|
||||
LWSCOSE_WKK_KTY, LWSCOSE_WKKTV_SYMMETRIC,
|
||||
LWSCOSE_WKK_KID, 6, "sec-64",
|
||||
-1, (int)sizeof(key9_k), key9_k) !=
|
||||
LWS_LECPCTX_RET_FINISHED)
|
||||
return 1;
|
||||
|
||||
lws_hex_from_byte_array(buf, wx.used, (char *)dump, sizeof(dump));
|
||||
puts((const char *)dump);
|
||||
#endif
|
||||
|
||||
/* key1 import */
|
||||
|
||||
lwsl_user("%s: key 1 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, key_import_cb, NULL, cose_key1, sizeof(cose_key1));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_EC2 ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key1_x) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key1_y) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key1_d) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key1_x, sizeof(key1_x)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key1_y, sizeof(key1_y)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key1_d, sizeof(key1_d)))
|
||||
goto bail;
|
||||
|
||||
// lws_cose_key_dump(ck);
|
||||
|
||||
/* key 1 export */
|
||||
|
||||
lwsl_user("%s: key 1 export\n", __func__);
|
||||
|
||||
lws_lec_init(&wc, buf, sizeof(buf));
|
||||
n = (int)lws_cose_key_export(ck, &wc, LWSJWKF_EXPORT_PRIVATE);
|
||||
lws_cose_key_destroy(&ck);
|
||||
if (n != LWS_LECPCTX_RET_FINISHED)
|
||||
goto bail;
|
||||
|
||||
// lwsl_hexdump_notice(buf, wc.used);
|
||||
|
||||
/* key2 import */
|
||||
|
||||
lwsl_user("%s: key 2 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key2, sizeof(cose_key2));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_EC2 ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key2_x) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key2_y) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key2_d) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key2_x, sizeof(key2_x)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key2_y, sizeof(key2_y)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key2_d, sizeof(key2_d)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key3 import */
|
||||
|
||||
lwsl_user("%s: key 3 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key3, sizeof(cose_key3));
|
||||
if (!ck) {
|
||||
lwsl_err("%s: key 3 import failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
|
||||
ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key3_k) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key3_k, sizeof(key3_k))) {
|
||||
lwsl_err("%s: key 3 checks failed %d %d %d\n", __func__,
|
||||
(int)ck->kty, (int)ck->gencrypto_kty,
|
||||
(int)ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key4 import */
|
||||
|
||||
lwsl_user("%s: key 4 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key4, sizeof(cose_key4));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_EC2 ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key4_x) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key4_y) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key4_d) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key4_x, sizeof(key4_x)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key4_y, sizeof(key4_y)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key4_d, sizeof(key4_d)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key5 import */
|
||||
|
||||
lwsl_user("%s: key 5 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key5, sizeof(cose_key5));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
|
||||
ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key5_k) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key5_k, sizeof(key5_k)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key6 import */
|
||||
|
||||
lwsl_user("%s: key 6 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key6, sizeof(cose_key6));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_EC2 ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key6_x) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key6_y) ||
|
||||
ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key6_d) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key6_x, sizeof(key6_x)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key6_y, sizeof(key6_y)) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key6_d, sizeof(key6_d)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key7 import */
|
||||
|
||||
lwsl_user("%s: key 7 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key7, sizeof(cose_key7));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
|
||||
ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key7_k) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key7_k, sizeof(key7_k)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key8 import */
|
||||
|
||||
lwsl_user("%s: key 8 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key8, sizeof(cose_key8));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
|
||||
ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key8_k) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key8_k, sizeof(key8_k)))
|
||||
goto bail;
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key9 import */
|
||||
|
||||
lwsl_user("%s: key 9 import\n", __func__);
|
||||
|
||||
ck = lws_cose_key_import(NULL, NULL, NULL, cose_key9, sizeof(cose_key9));
|
||||
if (!ck) {
|
||||
lwsl_err("%s: cose9 import fail\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
|
||||
ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
|
||||
ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key9_k) ||
|
||||
memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key9_k, sizeof(key9_k))) {
|
||||
lwsl_notice("%s: key9 check fails\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
/* key set 1 */
|
||||
|
||||
lwsl_user("%s: key_set1\n", __func__);
|
||||
lws_dll2_owner_clear(&set);
|
||||
ck = lws_cose_key_import(&set, NULL, NULL, cose_key_set1, sizeof(cose_key_set1));
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
lws_cose_key_set_destroy(&set);
|
||||
|
||||
/* generate */
|
||||
|
||||
ck = lws_cose_key_generate(context, LWSCOSE_WKKTV_EC2,
|
||||
(1 << LWSCOSE_WKKO_SIGN) |
|
||||
(1 << LWSCOSE_WKKO_VERIFY) |
|
||||
(1 << LWSCOSE_WKKO_ENCRYPT) |
|
||||
(1 << LWSCOSE_WKKO_DECRYPT),
|
||||
0, "P-256", (const uint8_t *)"the-keyid", 9);
|
||||
if (!ck)
|
||||
return 1;
|
||||
|
||||
// lws_cose_key_dump(ck);
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
50
minimal-examples/api-tests/api-test-cose/main.c
Normal file
50
minimal-examples/api-tests/api-test-cose/main.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* lws-api-test-cose
|
||||
*
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
int
|
||||
test_cose_keys(struct lws_context *context);
|
||||
int
|
||||
test_cose_sign(struct lws_context *context);
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
const char *p;
|
||||
int result = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS COSE api tests\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
#endif
|
||||
info.options = 0;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
result |= test_cose_keys(context);
|
||||
result |= test_cose_sign(context);
|
||||
|
||||
lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS");
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return result;
|
||||
}
|
1862
minimal-examples/api-tests/api-test-cose/sign.c
Normal file
1862
minimal-examples/api-tests/api-test-cose/sign.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -50,6 +50,7 @@ static const char * const reason_names[] = {
|
|||
"LECPCB_VAL_BLOB_END",
|
||||
"LECPCB_ARRAY_ITEM_START",
|
||||
"LECPCB_ARRAY_ITEM_END",
|
||||
"LECPCB_LITERAL_CBOR"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
project(lws-crypto-cose-key C)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
find_package(libwebsockets CONFIG REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
|
||||
include(CheckCSourceCompiles)
|
||||
include(LwsCheckRequirements)
|
||||
|
||||
set(SAMP lws-crypto-cose-key)
|
||||
set(SRCS main.c)
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITH_COSE 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
add_test(NAME crypto-cose-key-1
|
||||
COMMAND lws-crypto-cose-key --stdin set1.cks )
|
||||
add_test(NAME crypto-cose-key-2
|
||||
COMMAND lws-crypto-cose-key --kty EC2 --curve P-256 --kid ctest-256 --stdout ctest-ec-256.key)
|
||||
add_test(NAME crypto-cose-key-3
|
||||
COMMAND lws-crypto-cose-key --kty EC2 --curve P-384 --kid ctest-384 --stdout ctest-ec-384.key)
|
||||
add_test(NAME crypto-cose-key-4
|
||||
COMMAND lws-crypto-cose-key --kty EC2 --curve P-521 --kid ctest-512 --stdout ctest-ec-512.key)
|
||||
add_test(NAME crypto-cose-key-5
|
||||
COMMAND lws-crypto-cose-key --kty SYMMETRIC --bits 256 --stdout ctest-sym-256.key)
|
||||
add_test(NAME crypto-cose-key-6
|
||||
COMMAND lws-crypto-cose-key --kty RSA --bits 2048 --stdout ctest-rsa-2048.key)
|
||||
add_test(NAME crypto-cose-key-7
|
||||
COMMAND lws-crypto-cose-key --stdin ctest-rsa-2048.key)
|
||||
|
||||
set_tests_properties(crypto-cose-key-1
|
||||
crypto-cose-key-2
|
||||
crypto-cose-key-3
|
||||
crypto-cose-key-4
|
||||
crypto-cose-key-5
|
||||
crypto-cose-key-6
|
||||
crypto-cose-key-7
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_SOURCE_DIR}/minimal-examples/crypto/minimal-crypto-cose-key
|
||||
TIMEOUT 5)
|
||||
|
||||
set_tests_properties(crypto-cose-key-7
|
||||
PROPERTIES
|
||||
DEPENDS crypto-cose-key-6)
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
endif()
|
||||
endif()
|
132
minimal-examples/crypto/minimal-crypto-cose-key/README.md
Normal file
132
minimal-examples/crypto/minimal-crypto-cose-key/README.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# lws minimal example for cose_key
|
||||
|
||||
Demonstrates how to create and dump cose_keys.
|
||||
|
||||
## Dump key or key_set
|
||||
|
||||
Pipe a cose_key or cose_key_set into stdin to get a textual dump of all the keys
|
||||
inside. You can optionally use --kid kid or --kid-hex HEXSTRING to dump one key
|
||||
from a set.
|
||||
|
||||
```
|
||||
$ cat set1.cks | ./bin/lws-crypto-cose-key
|
||||
$ cat set1.cks | ./bin/lws-crypto-cose-key --kid 11
|
||||
```
|
||||
|
||||
## Create keys
|
||||
|
||||
Stdin is not used, give parameters for the kty and kid etc to create a
|
||||
new key on stdout (which can be redirected to a file).
|
||||
|
||||
```
|
||||
$ ./bin/lws-crypto-cose-key --kty EC2 --curve P-521 --kid sec512 >ec512.key
|
||||
```
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
|Option|Meaning|
|
||||
|---|---|
|
||||
|--kty type|Key type, one of OKP, EC2, RSA or SYMMETRIC|
|
||||
|-k \<keyset filepath\>|One or a set of cose_keys|
|
||||
|--kid string|Specifies the key ID to use as a string|
|
||||
|--kid-hex HEXSTRING|Specifies the key ID to use as a hex blob|
|
||||
|--curve curve|For EC type key creation, specify the curve|
|
||||
|--stdin filepath|Makes tool fetch from filepath instead of stdin (useful for CI)|
|
||||
|--stdout filepath|Makes tool write to filepath instead of stdout (useful for CI)|
|
||||
|
||||
|
||||
HEXSTRING above means a string like `1a2b3c`
|
||||
|
||||
## Examples
|
||||
|
||||
### cose_key dumping
|
||||
|
||||
```
|
||||
$ cat set1.cks | ./bin/lws-crypto-cose-key
|
||||
[2021/07/30 10:14:31:0420] U: LWS cose-key example tool -k keyset [-s alg-name kid ]
|
||||
[2021/07/30 10:14:31:0780] N: lws_create_context: LWS: 4.2.99-v4.2.0-134-g8433c8b459, NET CLI SRV H1 H2 WS ConMon IPV6-on
|
||||
[2021/07/30 10:14:31:0892] N: ++ [wsi|0|pipe] (1)
|
||||
[2021/07/30 10:14:31:0926] N: ++ [vh|0|netlink] (1)
|
||||
[2021/07/30 10:14:31:0977] N: ++ [vh|1|default||-1] (2)
|
||||
[2021/07/30 10:14:31:1057] N: main: importing
|
||||
Cose key #1
|
||||
kty: EC2
|
||||
kid: 11
|
||||
kty: P-256
|
||||
x: bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff
|
||||
d: 57c92077664146e876760c9520d054aa93c3afb04e306705db6090308507b4d3
|
||||
y: 20138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e
|
||||
Cose key #2
|
||||
kty: EC2
|
||||
kid: meriadoc.brandybuck@buckland.example
|
||||
kty: P-256
|
||||
x: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
|
||||
d: aff907c99f9ad3aae6c4cdf21122bce2bd68b5283e6907154ad911840fa208cf
|
||||
y: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
|
||||
Cose key #3
|
||||
kty: SYMMETRIC
|
||||
kid: our-secret
|
||||
k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188
|
||||
Cose key #4
|
||||
kty: EC2
|
||||
kid: bilbo.baggins@hobbiton.example
|
||||
kty: P-521
|
||||
x: 0072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad
|
||||
d: 00085138ddabf5ca975f5860f91a08e91d6d5f9a76ad4018766a476680b55cd339e8ab6c72b5facdb2a2a50ac25bd086647dd3e2e6e99e84ca2c3609fdf177feb26d
|
||||
y: 01dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475
|
||||
Cose key #5
|
||||
kty: SYMMETRIC
|
||||
kid: our-secret2
|
||||
k: 849b5786457c1491be3a76dcea6c4271
|
||||
Cose key #6
|
||||
kty: EC2
|
||||
kid: peregrin.took@tuckborough.example
|
||||
kty: P-256
|
||||
x: 98f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280
|
||||
d: 02d1f7e6f26c43d4868d87ceb2353161740aacf1f7163647984b522a848df1c3
|
||||
y: f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb
|
||||
Cose key #7
|
||||
kty: SYMMETRIC
|
||||
kid: 018c0ae5-4d9b-471b-bfd6-eef314bc7037
|
||||
use: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188
|
||||
Cose key #8
|
||||
kty: SYMMETRIC
|
||||
kid: sec-48
|
||||
k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c42718800112233778899aa2122232425262728
|
||||
Cose key #9
|
||||
kty: SYMMETRIC
|
||||
kid: sec-64
|
||||
k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c42718800112233778899aa2122232425262728aabbccddeeffa5a6a7a8a9a0b1b2b3b4
|
||||
Cose key #10
|
||||
kty: EC2
|
||||
kid: sec384
|
||||
kty: P-384
|
||||
x: ea2866349fe3a2f9ad4d6bfe7c30c527436e901c5fb22210b67b2150574ffcd0b1dd8c43d5d1e3d5cb849ecec202117c
|
||||
d: 4d46a58480d43d5454307edcf501e098ef7c0186cc6b56b41dfd13fe4b9b1ab1425851cf5b23e6636ed18f5bbdde1896
|
||||
y: 4c3d245515a688ef25ff68034089ca4f10a01bef51cc57309f12919c3d484142368795c6f2a5d30af650b4e12d0133e4
|
||||
Cose key #11
|
||||
kty: EC2
|
||||
kid: sec512
|
||||
kty: P-521
|
||||
x: 003b81ed66d8a2194b42f29ecb2c9ae48199be695924804a8407194ed0e172f39693f870f32463e2d36950034a21901487c5a0c43a1713a818fb89fa8a5b3b2dc181
|
||||
d: 013e0f06ce394ac14a3df3953fc560679ad0dee14779ef0d475787451fca71e3b4b827b6f7cedcf00e23c716fb829b5419234ba5c92c33e0bc94351fe97be21f2b82
|
||||
y: 004b9b6b0adf41913b5d700cf43bfe0ee8b79eb58fc308509e574fcb910b3fd5a2ad585affc6776f7fc9d4ff48f5923fe900660ecc6e3720f89c1363eecfffb38b5b
|
||||
[2021/07/30 10:14:31:1430] N: -- [wsi|0|pipe] (0) 52.763ms
|
||||
[2021/07/30 10:14:31:1441] N: -- [vh|0|netlink] (1) 51.437ms
|
||||
[2021/07/30 10:14:31:1491] N: -- [vh|1|default||-1] (0) 51.591ms
|
||||
[2021/07/30 10:14:31:1536] N: main: PASS
|
||||
|
||||
```
|
||||
|
||||
### cose_key creation
|
||||
|
||||
```
|
||||
$ ./bin/lws-crypto-cose-key --kty EC2 --curve P-521 --kid sec512 >ec512.key
|
||||
```
|
||||
|
313
minimal-examples/crypto/minimal-crypto-cose-key/main.c
Normal file
313
minimal-examples/crypto/minimal-crypto-cose-key/main.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* lws-minimal-crypto-cose-key
|
||||
*
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int fdin = 0, fdout = 1;
|
||||
|
||||
static const char *meta_names[] = {
|
||||
"kty", "kid", "use", "key_ops", "base_iv", "alg"
|
||||
};
|
||||
|
||||
static const char *oct_names[] = {
|
||||
"k"
|
||||
};
|
||||
|
||||
static const char *rsa_names[] = {
|
||||
"e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
|
||||
};
|
||||
|
||||
static const char *ec_names[] = {
|
||||
"crv", "x", "d", "y",
|
||||
};
|
||||
|
||||
static void
|
||||
cose_key_dump(const struct lws_cose_key *ck)
|
||||
{
|
||||
const char **enames;
|
||||
char hex[2048], dump[3072];
|
||||
int elems;
|
||||
size_t l;
|
||||
int n;
|
||||
|
||||
(void)enames;
|
||||
(void)meta_names;
|
||||
|
||||
switch (ck->gencrypto_kty) {
|
||||
|
||||
case LWS_GENCRYPTO_KTY_OCT:
|
||||
elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
|
||||
enames = oct_names;
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_RSA:
|
||||
elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
|
||||
enames = rsa_names;
|
||||
break;
|
||||
case LWS_GENCRYPTO_KTY_EC:
|
||||
elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
|
||||
enames = ec_names;
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
|
||||
if (ck->meta[n].buf) {
|
||||
if (n < 2) {
|
||||
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
||||
" %s: %.*s\n", meta_names[n],
|
||||
(int)ck->meta[n].len,
|
||||
ck->meta[n].buf);
|
||||
write(fdout, dump, l);
|
||||
} else {
|
||||
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
||||
" %s: ", meta_names[n]);
|
||||
write(fdout, dump, l);
|
||||
lws_hex_from_byte_array(ck->meta[n].buf,
|
||||
ck->meta[n].len,
|
||||
hex, sizeof(hex));
|
||||
write(fdout, hex, strlen(hex));
|
||||
write(fdout, "\n", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < elems; n++) {
|
||||
if (ck->e[n].buf) {
|
||||
if (!n && ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
|
||||
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
||||
" %s: %.*s\n", enames[n],
|
||||
(int)ck->e[n].len,
|
||||
ck->e[n].buf);
|
||||
write(fdout, dump, l);
|
||||
} else {
|
||||
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
||||
" %s: ", enames[n]);
|
||||
write(fdout, dump, l);
|
||||
lws_hex_from_byte_array(ck->e[n].buf,
|
||||
ck->e[n].len,
|
||||
hex, sizeof(hex));
|
||||
write(fdout, hex, strlen(hex));
|
||||
write(fdout, "\n", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
uint8_t *kid = NULL, ktmp[4096], set_temp[32 * 1024], temp[256];
|
||||
int result = 1, bits = 0,
|
||||
logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
struct lws_context_creation_info info;
|
||||
size_t kid_len = 0, stp = 0;
|
||||
struct lws_context *context;
|
||||
lws_cose_key_t *ck = NULL;
|
||||
cose_param_t cose_kty = 0;
|
||||
lws_dll2_owner_t set;
|
||||
const char *p, *crv;
|
||||
lws_lec_pctx_t lec;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
|
||||
lwsl_user("LWS cose-key example tool -k keyset [-s alg-name kid ]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
#endif
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
|
||||
fdin = open(p, LWS_O_RDONLY, 0);
|
||||
if (fdin < 0) {
|
||||
lwsl_err("%s: unable to open stdin file\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
|
||||
fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
|
||||
if (fdout < 0) {
|
||||
lwsl_err("%s: unable to open stdout file\n", __func__);
|
||||
goto bail_early;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
|
||||
kid = (uint8_t *)p;
|
||||
kid_len = strlen(p);
|
||||
//lwsl_hexdump_notice(kid, kid_len);
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
|
||||
kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
|
||||
kid = (uint8_t *)ktmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have some stdin queued up, we understand we are dumping
|
||||
* an existing cose_key or key_set from stdin
|
||||
*/
|
||||
|
||||
if (!fdin) {
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 1000;
|
||||
|
||||
if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0)
|
||||
goto no_stdin;
|
||||
|
||||
if (!FD_ISSET(0, &fds))
|
||||
goto no_stdin;
|
||||
}
|
||||
|
||||
do {
|
||||
int n = (int)read(fdin, temp, sizeof(temp));
|
||||
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
if (!n) {
|
||||
int kc = 0;
|
||||
|
||||
if (!stp)
|
||||
/* there was no stdin */
|
||||
break;
|
||||
|
||||
lwsl_notice("%s: importing\n", __func__);
|
||||
|
||||
lws_dll2_owner_clear(&set);
|
||||
ck = lws_cose_key_import(&set, NULL, NULL, set_temp, stp);
|
||||
if (!ck) {
|
||||
lwsl_err("%s: import failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, p,
|
||||
lws_dll2_get_head(&set)) {
|
||||
lws_cose_key_t *ck = lws_container_of(p,
|
||||
lws_cose_key_t, list);
|
||||
struct lws_gencrypto_keyelem *ke =
|
||||
&ck->meta[COSEKEY_META_KID];
|
||||
|
||||
kc++;
|
||||
|
||||
if (!kid_len || (ke->len &&
|
||||
ke->len == (uint32_t)kid_len &&
|
||||
!memcmp(ke->buf, kid, kid_len))) {
|
||||
printf("Cose key #%d\n", kc);
|
||||
cose_key_dump(ck);
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll(p);
|
||||
|
||||
lws_cose_key_set_destroy(&set);
|
||||
result = 0;
|
||||
goto bail;
|
||||
|
||||
}
|
||||
|
||||
if (stp + (size_t)n > sizeof(set_temp)) {
|
||||
lwsl_err("%s: stdin bigger than our buffer\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
memcpy(set_temp + stp, temp, (size_t)n);
|
||||
stp += (size_t)n;
|
||||
} while (1);
|
||||
|
||||
no_stdin:
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
p = lws_cmdline_option(argc, argv, "--kty");
|
||||
if (!p) {
|
||||
lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
|
||||
__func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!strcmp(p, "OKP"))
|
||||
cose_kty = LWSCOSE_WKKTV_OKP;
|
||||
if (!strcmp(p, "EC2"))
|
||||
cose_kty = LWSCOSE_WKKTV_EC2;
|
||||
if (!strcmp(p, "RSA"))
|
||||
cose_kty = LWSCOSE_WKKTV_RSA;
|
||||
if (!strcmp(p, "SYMMETRIC") || !strcmp(p, "SYM"))
|
||||
cose_kty = LWSCOSE_WKKTV_SYMMETRIC;
|
||||
|
||||
if (!cose_kty) {
|
||||
lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
|
||||
__func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
crv = NULL;
|
||||
if (cose_kty == LWSCOSE_WKKTV_OKP ||
|
||||
cose_kty == LWSCOSE_WKKTV_EC2) {
|
||||
crv = lws_cmdline_option(argc, argv, "--curve");
|
||||
if (!crv) {
|
||||
lwsl_err("%s: use --curve P-256 etc\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
p = lws_cmdline_option(argc, argv, "--bits");
|
||||
if (p)
|
||||
bits = atoi(p);
|
||||
|
||||
ck = lws_cose_key_generate(context, cose_kty, 0, bits, crv,
|
||||
kid, kid_len);
|
||||
if (!ck)
|
||||
goto bail;
|
||||
|
||||
lws_lec_init(&lec, ktmp, sizeof(ktmp));
|
||||
lws_cose_key_export(ck, &lec, LWSJWKF_EXPORT_PRIVATE);
|
||||
write(fdout, ktmp, lec.used);
|
||||
|
||||
lws_cose_key_destroy(&ck);
|
||||
result = 0;
|
||||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
|
||||
if (result)
|
||||
lwsl_err("%s: FAIL: %d\n", __func__, result);
|
||||
else
|
||||
lwsl_notice("%s: PASS\n", __func__);
|
||||
|
||||
bail_early:
|
||||
if (fdin > 0)
|
||||
close(fdin);
|
||||
if (fdout != 1 && fdout >= 0)
|
||||
close(fdout);
|
||||
|
||||
return result;
|
||||
}
|
BIN
minimal-examples/crypto/minimal-crypto-cose-key/set1.cks
Normal file
BIN
minimal-examples/crypto/minimal-crypto-cose-key/set1.cks
Normal file
Binary file not shown.
BIN
minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig
Normal file
BIN
minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig
Normal file
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
Ò„C¡&¡B11TThis is the content.X@rœ×Ë8ØØéD¨Úqç²XɽÊa5÷®Ûî• ‰gƒ~3½6ÁP2jæ'UƽŽT><EFBFBD>’×Ò%èÛr¸‚
|
|
@ -0,0 +1 @@
|
|||
„C¡&¡B11TThis is the content.X@Ž³>L£FZ°Z¬4Ìk#Õ<>ï\1ÄÒZ‘®ð°~*ù¢‘ª2áJ¸4ÜVí*"4DT~ñ; å¤ÃEÊË6
|
|
@ -0,0 +1 @@
|
|||
Øb„A TThis is the content.<EFBFBD>ƒC¡&¡B11X@⮯Ô
iÑ<EFBFBD>þnR|]ôä(,¾û]Ëô¯.Ù‚¬E¬˜¸TL<54>‹EÞ<1E>·ÃÓHþ’j+˜õ:ý/ ó
|
|
@ -0,0 +1 @@
|
|||
Øb„@ TThis is the content.<EFBFBD>ƒC¡&¡B11X@˸ÚÙ¾¯¸<C2AF>á¤M‹ûÂkíò©OËZˆ$2¿öÖ>õtQØ?¢Ëö&rëôÇÙ“°ôÂDvGØ1ºW̨k“
|
|
@ -0,0 +1 @@
|
|||
„@ TThis is the content.<EFBFBD>ƒC¡&¡B11X@⮯Ô
iÑ<EFBFBD>þnR|]ôä(,¾û]Ëô¯.Ù‚¬E¬˜¸TL<54>‹EÞ<1E>·ÃÓHþ’j+˜õ:ý/ ó
|
219
minimal-examples/crypto/minimal-crypto-cose-sign/CMakeLists.txt
Normal file
219
minimal-examples/crypto/minimal-crypto-cose-sign/CMakeLists.txt
Normal file
|
@ -0,0 +1,219 @@
|
|||
project(lws-crypto-cose-sign C)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
find_package(libwebsockets CONFIG REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
|
||||
include(CheckCSourceCompiles)
|
||||
include(LwsCheckRequirements)
|
||||
|
||||
set(SAMP lws-crypto-cose-sign)
|
||||
set(SRCS main.c)
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITH_COSE 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
# EC signing
|
||||
|
||||
add_test(NAME crypto-cose-sign-1
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid 11
|
||||
--alg ES256 --cose-sign
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-es256.sig)
|
||||
add_test(NAME crypto-cose-sign-2
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec384
|
||||
--alg ES384 --cose-sign
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-es384.sig)
|
||||
add_test(NAME crypto-cose-sign-3
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec512
|
||||
--alg ES512 --cose-sign
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-es512.sig)
|
||||
|
||||
# EC validation
|
||||
|
||||
add_test(NAME crypto-cose-sign-4
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r1.txt
|
||||
--stdin ctest-sig-es256.sig)
|
||||
set_tests_properties(crypto-cose-sign-4 PROPERTIES
|
||||
DEPENDS crypto-cose-sign-1)
|
||||
|
||||
add_test(NAME crypto-cose-sign-5
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r2.txt
|
||||
--stdin ctest-sig-es384.sig)
|
||||
set_tests_properties(crypto-cose-sign-5 PROPERTIES
|
||||
DEPENDS crypto-cose-sign-2)
|
||||
|
||||
add_test(NAME crypto-cose-sign-6
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks --cose-sign
|
||||
--stdout r3.txt
|
||||
--stdin ctest-sig-es512.sig)
|
||||
set_tests_properties(crypto-cose-sign-6 PROPERTIES
|
||||
DEPENDS crypto-cose-sign-3)
|
||||
|
||||
# RSA 4096 signing
|
||||
|
||||
add_test(NAME crypto-cose-sign-7
|
||||
COMMAND lws-crypto-cose-sign -s -k rsa-4096.ck
|
||||
--alg RS512 --cose-sign
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-rs512.sig)
|
||||
|
||||
# RSA 4096 validation
|
||||
|
||||
add_test(NAME crypto-cose-sign-8
|
||||
COMMAND lws-crypto-cose-sign -k rsa-4096.ck --cose-sign
|
||||
--stdout r8.txt
|
||||
--stdin ctest-sig-rs512.sig)
|
||||
set_tests_properties(crypto-cose-sign-8 PROPERTIES
|
||||
DEPENDS crypto-cose-sign-7)
|
||||
|
||||
# HMAC signing, cose-mac
|
||||
|
||||
# add_test(NAME crypto-cose-sign-9
|
||||
# COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
|
||||
# --alg HS256 --cose-mac
|
||||
# --stdin payload.txt
|
||||
# --stdout ctest-sig-hmac256.sig)
|
||||
# add_test(NAME crypto-cose-sign-10
|
||||
# COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-48
|
||||
# --alg HS384 --cose-mac
|
||||
# --stdin payload.txt
|
||||
# --stdout ctest-sig-hmac384.sig)
|
||||
# add_test(NAME crypto-cose-sign-11
|
||||
# COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-64
|
||||
# --alg HS512 --cose-mac
|
||||
# --stdin payload.txt
|
||||
# --stdout ctest-sig-hmac512.sig)
|
||||
# add_test(NAME crypto-cose-sign-12
|
||||
# COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
|
||||
# --alg HS256_64 --cose-mac
|
||||
# --stdin payload.txt
|
||||
# --stdout ctest-sig-hmac256_64.sig)
|
||||
|
||||
# HMAC validation, cose-mac
|
||||
|
||||
# add_test(NAME crypto-cose-sign-13
|
||||
# COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
# --stdout r1.txt
|
||||
# --stdin ctest-sig-hmac256.sig)
|
||||
# set_tests_properties(crypto-cose-sign-13
|
||||
# PROPERTIES DEPENDS crypto-cose-sign-9)
|
||||
#
|
||||
# add_test(NAME crypto-cose-sign-14
|
||||
# COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
# --stdout r2.txt
|
||||
# --stdin ctest-sig-hmac384.sig)
|
||||
# set_tests_properties(crypto-cose-sign-14
|
||||
# PROPERTIES DEPENDS crypto-cose-sign-10)
|
||||
#
|
||||
# add_test(NAME crypto-cose-sign-15
|
||||
# COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
# --stdout r3.txt
|
||||
# --stdin ctest-sig-hmac512.sig)
|
||||
# set_tests_properties(crypto-cose-sign-15
|
||||
# PROPERTIES DEPENDS crypto-cose-sign-11)
|
||||
#
|
||||
# add_test(NAME crypto-cose-sign-16
|
||||
# COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
# --stdout r4.txt
|
||||
# --stdin ctest-sig-hmac256_64.sig)
|
||||
# set_tests_properties(crypto-cose-sign-16
|
||||
# PROPERTIES DEPENDS crypto-cose-sign-12)
|
||||
|
||||
# HMAC signing, cose-mac0
|
||||
|
||||
add_test(NAME crypto-cose-sign-17
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
|
||||
--alg HS256 --cose-mac0
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-hmac0256.sig)
|
||||
add_test(NAME crypto-cose-sign-18
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-48
|
||||
--alg HS384 --cose-mac0
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-hmac0384.sig)
|
||||
add_test(NAME crypto-cose-sign-19
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-64
|
||||
--alg HS512 --cose-mac0
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-hmac0512.sig)
|
||||
add_test(NAME crypto-cose-sign-20
|
||||
COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
|
||||
--alg HS256_64 --cose-mac0
|
||||
--stdin payload.txt
|
||||
--stdout ctest-sig-hmac0256_64.sig)
|
||||
|
||||
# HMAC validation, cose-mac0
|
||||
|
||||
add_test(NAME crypto-cose-sign-21
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r1.txt
|
||||
--stdin ctest-sig-hmac0256.sig)
|
||||
set_tests_properties(crypto-cose-sign-21
|
||||
PROPERTIES DEPENDS crypto-cose-sign-17)
|
||||
|
||||
add_test(NAME crypto-cose-sign-22
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r2.txt
|
||||
--stdin ctest-sig-hmac0384.sig)
|
||||
set_tests_properties(crypto-cose-sign-22
|
||||
PROPERTIES DEPENDS crypto-cose-sign-18)
|
||||
|
||||
add_test(NAME crypto-cose-sign-23
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r3.txt
|
||||
--stdin ctest-sig-hmac0512.sig)
|
||||
set_tests_properties(crypto-cose-sign-23
|
||||
PROPERTIES DEPENDS crypto-cose-sign-19)
|
||||
|
||||
add_test(NAME crypto-cose-sign-24
|
||||
COMMAND lws-crypto-cose-sign -k set1.cks
|
||||
--stdout r4.txt
|
||||
--stdin ctest-sig-hmac0256_64.sig)
|
||||
set_tests_properties(crypto-cose-sign-24
|
||||
PROPERTIES DEPENDS crypto-cose-sign-20)
|
||||
|
||||
|
||||
set_tests_properties(crypto-cose-sign-1
|
||||
crypto-cose-sign-2
|
||||
crypto-cose-sign-3
|
||||
crypto-cose-sign-4
|
||||
crypto-cose-sign-5
|
||||
crypto-cose-sign-6
|
||||
crypto-cose-sign-7
|
||||
crypto-cose-sign-8
|
||||
# crypto-cose-sign-9
|
||||
# crypto-cose-sign-10
|
||||
# crypto-cose-sign-11
|
||||
# crypto-cose-sign-12
|
||||
# crypto-cose-sign-13
|
||||
# crypto-cose-sign-14
|
||||
# crypto-cose-sign-15
|
||||
# crypto-cose-sign-16
|
||||
crypto-cose-sign-17
|
||||
crypto-cose-sign-18
|
||||
crypto-cose-sign-19
|
||||
crypto-cose-sign-20
|
||||
crypto-cose-sign-21
|
||||
crypto-cose-sign-22
|
||||
crypto-cose-sign-23
|
||||
crypto-cose-sign-24
|
||||
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_SOURCE_DIR}/minimal-examples/crypto/minimal-crypto-cose-sign
|
||||
TIMEOUT 5)
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
endif()
|
||||
endif()
|
105
minimal-examples/crypto/minimal-crypto-cose-sign/README.md
Normal file
105
minimal-examples/crypto/minimal-crypto-cose-sign/README.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
# lws minimal example for cose_sign
|
||||
|
||||
Demonstrates how to sign and verify using cose_sign and cose_key, providing a
|
||||
commandline tool for signing and verifying stdin.
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
|Option|Sig|Val|Meaning|
|
||||
|---|---|---|---|
|
||||
|-s|o|||Select signing mode (stdin is payload)|
|
||||
|-k <keyset filepath>|o|o|One or a set of cose_keys|
|
||||
|--kid string|o|mac0|Specifies the key ID to use as a string|
|
||||
|--kid-hex HEXSTRING|o|mac0|Specifies the key ID to use as a hex blob|
|
||||
|--cose-sign|o|if no tag|Sets cose-sign mode|
|
||||
|--cose-sign1|o|if no tag|Sets cose-sign1 mode|
|
||||
|--cose-mac|o|if no tag|Sets cose-sign1 mode|
|
||||
|--cose-mac0|o|if no tag|Sets cose-sign1 mode|
|
||||
|--extra HEXSTRING|o|o|Optional extra payload data|
|
||||
|
||||
HEXSTRING above means a string like `1a2b3c`
|
||||
|
||||
Stdin is either the plaintext (if signing) or cose_sign (if verifying).
|
||||
|
||||
For convenience, a keyset from the COSE RFC is provided in
|
||||
`minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks`. Six example
|
||||
cose_sign1 and cose_sign are also provided in that directory signed with keys
|
||||
from the provided keyset.
|
||||
|
||||
## Examples
|
||||
|
||||
### Validation
|
||||
|
||||
The RFC8152 sign1_pass01.sig is a cose_sign1 that contains the ES256 alg
|
||||
parameter along with a kid hint that it was signed with the key with kid "11"
|
||||
from the RFC8152 key set. So we just need to provide the signature and the key
|
||||
set and lws can sort it out.
|
||||
|
||||
```
|
||||
$ cat sign1_pass01.sig | ./lws-crypto-cose-sign -k set1.cks
|
||||
[2021/07/26 05:41:29:1663] N: lws_create_context: LWS: 4.2.99-v4.2.0-133-g300f3f3250, NET CLI SRV H1 H2 WS ConMon IPV6-on
|
||||
[2021/07/26 05:41:29:3892] N: results count 1
|
||||
[2021/07/26 05:41:29:3901] N: result: 0 (alg ES256, kid 3131)
|
||||
[2021/07/26 05:41:29:4168] N: main: PASS
|
||||
```
|
||||
|
||||
Notice how the validation just delivers a results list and leaves it to the user
|
||||
code to iterate it, and confirm that it's happy with the result, the alg used,
|
||||
and the kid that was used.
|
||||
|
||||
RFC8152 sign1_pass02.sig is similar but contains extra application data in the
|
||||
signature, that must be given at validation too.
|
||||
|
||||
```
|
||||
$cat sign1_pass02.sig | ./lws-crypto-cose-sign -k set1.cks --extra 11aa22bb33cc44dd55006699
|
||||
[2021/07/26 05:55:50:9103] N: lws_create_context: LWS: 4.2.99-v4.2.0-133-g300f3f3250, NET CLI SRV H1 H2 WS ConMon IPV6-on
|
||||
[2021/07/26 05:55:50:9381] N: 12
|
||||
[2021/07/26 05:55:51:0924] N:
|
||||
[2021/07/26 05:55:51:0939] N: 0000: 11 AA 22 BB 33 CC 44 DD 55 00 66 99 ..".3.D.U.f.
|
||||
[2021/07/26 05:55:51:0943] N:
|
||||
[2021/07/26 05:55:51:1368] N: results count 1
|
||||
[2021/07/26 05:55:51:1377] N: result: 0 (alg ES256, kid 3131)
|
||||
[2021/07/26 05:55:51:1657] N: main: PASS
|
||||
```
|
||||
|
||||
### Signing
|
||||
|
||||
Generate a cose-sign1 using ES256 and the key set key with id "11" for the
|
||||
payload given on stdin
|
||||
|
||||
```
|
||||
$ echo -n "This is the content." |\
|
||||
./bin/lws-crypto-cose-sign -s -k set1.cks \
|
||||
--kid 11 --alg ES256 > ./test.sig
|
||||
|
||||
00000000 d2 84 43 a1 01 26 a1 04 42 31 31 54 54 68 69 73 |..C..&..B11TThis|
|
||||
00000010 20 69 73 20 74 68 65 20 63 6f 6e 74 65 6e 74 2e | is the content.|
|
||||
00000020 58 40 b9 a8 85 09 17 7f 01 f6 78 5d 39 62 d0 44 |X@........x]9b.D|
|
||||
00000030 08 0b fa b4 b4 5b 17 80 c2 e3 ba a3 af 33 6f e6 |.....[.......3o.|
|
||||
00000040 44 09 13 1f cf 4f 17 5c 62 9f 8d 29 29 1c ab 28 |D....O.\b..))..(|
|
||||
00000050 b2 f4 e6 af f9 62 ea 69 52 90 07 0e 2c 40 72 d3 |.....b.iR...,@r.|
|
||||
00000060 12 cf |..|
|
||||
|
||||
```
|
||||
|
||||
Same as above, but force it to use cose-sign layout
|
||||
|
||||
```
|
||||
$ echo -n "This is the content." |\
|
||||
./bin/lws-crypto-cose-sign -s -k set1.cks \
|
||||
--kid 11 --alg ES256 --cose-sign > ./test.sig
|
||||
|
||||
00000000 d8 62 84 40 40 54 54 68 69 73 20 69 73 20 74 68 |.b.@@TThis is th|
|
||||
00000010 65 20 63 6f 6e 74 65 6e 74 2e 81 83 a1 01 26 a1 |e content.....&.|
|
||||
00000020 04 42 31 31 58 40 37 5d 93 48 20 b0 d0 75 16 41 |.B11X@7].H ..u.A|
|
||||
00000030 db 95 95 5b 39 7d 6d 92 6e 52 c9 78 96 d8 a2 9b |...[9}m.nR.x....|
|
||||
00000040 62 62 89 9e e5 26 31 63 4b 90 d1 37 86 ca 82 a2 |bb...&1cK..7....|
|
||||
00000050 28 9a d2 82 a7 6d 24 23 cd de 58 91 47 98 bb 11 |(....m$#..X.G...|
|
||||
00000060 e4 b9 08 18 48 65 |....He|
|
||||
```
|
406
minimal-examples/crypto/minimal-crypto-cose-sign/main.c
Normal file
406
minimal-examples/crypto/minimal-crypto-cose-sign/main.c
Normal file
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* lws-minimal-crypto-cose-sign
|
||||
*
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int fdin = 0, fdout = 1;
|
||||
static uint8_t extra[4096];
|
||||
static size_t ext_len;
|
||||
|
||||
int
|
||||
_alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
size_t *amount)
|
||||
{
|
||||
FILE *f;
|
||||
size_t s;
|
||||
ssize_t m;
|
||||
int n = 0;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) != 0) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
m = ftell(f);
|
||||
if (m == -1l) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
s = (size_t)m;
|
||||
|
||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*buf = malloc(s + 1);
|
||||
if (!*buf) {
|
||||
n = 2;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fread(*buf, s, 1, f) != 1) {
|
||||
free(*buf);
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*amount = s;
|
||||
|
||||
bail:
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
return n;
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
extra_cb(lws_cose_sig_ext_pay_t *x)
|
||||
{
|
||||
x->ext = extra;
|
||||
x->xl = ext_len;
|
||||
|
||||
// lwsl_hexdump_notice(extra, ext_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pay_cb(struct lws_cose_validate_context *cps, void *opaque,
|
||||
const uint8_t *paychunk, size_t paychunk_len)
|
||||
{
|
||||
write(fdout, paychunk, paychunk_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
uint8_t *ks, temp[256], *kid = NULL, ktmp[4096], sbuf[512];
|
||||
int n, m, sign = 0, result = 1,
|
||||
logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
enum lws_cose_sig_types sigtype = SIGTYPE_UNKNOWN;
|
||||
struct lws_cose_validate_context *cps = NULL;
|
||||
struct lws_cose_sign_context *csc = NULL;
|
||||
const struct lws_gencrypto_keyelem *ke;
|
||||
struct lws_context_creation_info info;
|
||||
lws_cose_validate_create_info_t vi;
|
||||
struct lws_buflist *paybuf = NULL;
|
||||
lws_cose_sign_create_info_t i;
|
||||
struct lws_context *context;
|
||||
size_t ks_len, kid_len = 0;
|
||||
lws_cose_key_t *ck = NULL;
|
||||
lws_dll2_owner_t *o, set;
|
||||
lws_lec_pctx_t lec;
|
||||
cose_param_t alg;
|
||||
const char *p;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
|
||||
lwsl_user("LWS cose-sign example tool -k keyset [-s alg-name kid ]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
#endif
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
|
||||
fdin = open(p, LWS_O_RDONLY, 0);
|
||||
if (fdin < 0) {
|
||||
lwsl_err("%s: unable to open stdin file\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
|
||||
fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
|
||||
if (fdout < 0) {
|
||||
lwsl_err("%s: unable to open stdout file\n", __func__);
|
||||
goto bail_early;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no tag, you can tell it the signature type, otherwise it will
|
||||
* use the tag to select the right type without these
|
||||
*/
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--cose-sign"))
|
||||
sigtype = SIGTYPE_MULTI;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--cose-sign1"))
|
||||
sigtype = SIGTYPE_SINGLE;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--cose-mac"))
|
||||
sigtype = SIGTYPE_MAC;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--cose-mac0"))
|
||||
sigtype = SIGTYPE_MAC0;
|
||||
|
||||
/* if signing, set the ciphers */
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-s"))
|
||||
sign = 1;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
|
||||
kid = (uint8_t *)p;
|
||||
kid_len = strlen(p);
|
||||
//lwsl_hexdump_notice(kid, kid_len);
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
|
||||
kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
|
||||
kid = (uint8_t *)ktmp;
|
||||
}
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--extra"))) {
|
||||
ext_len = (size_t)lws_hex_to_byte_array(p, extra, sizeof(extra));
|
||||
lwsl_notice("%llu\n", (unsigned long long)ext_len);
|
||||
if (ext_len == (size_t)-1ll)
|
||||
ext_len = 0;
|
||||
}
|
||||
|
||||
/* grab the key */
|
||||
|
||||
if (!(p = lws_cmdline_option(argc, argv, "-k"))) {
|
||||
lwsl_err("-k <key set file> is required\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (_alloc_file(context, p, &ks, &ks_len)) {
|
||||
lwsl_err("%s: unable to load %s\n", __func__, p);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_dll2_owner_clear(&set);
|
||||
if (!lws_cose_key_import(&set, NULL, NULL, ks, ks_len)) {
|
||||
lwsl_notice("%s: key import fail\n", __func__);
|
||||
free(ks);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
free(ks);
|
||||
|
||||
if (!fdin) {
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 1000;
|
||||
|
||||
if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0 ||
|
||||
!FD_ISSET(0, &fds)) {
|
||||
lwsl_err("%s: pass cose_sign or plaintext "
|
||||
"on stdin or --stdin\n", __func__);
|
||||
goto bail2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
uint8_t *ppay;
|
||||
size_t s;
|
||||
|
||||
p = lws_cmdline_option(argc, argv, "--alg");
|
||||
if (!p) {
|
||||
lwsl_err("%s: need to specify alg (eg, ES256) "
|
||||
"when signing\n", __func__);
|
||||
goto bail2;
|
||||
}
|
||||
alg = lws_cose_name_to_alg(p);
|
||||
|
||||
lws_lec_init(&lec, sbuf, sizeof(sbuf));
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.cx = context;
|
||||
i.keyset = &set;
|
||||
i.lec = &lec;
|
||||
i.flags = LCSC_FL_ADD_CBOR_TAG |
|
||||
LCSC_FL_ADD_CBOR_PREFER_MAC0;
|
||||
i.sigtype = sigtype;
|
||||
|
||||
/*
|
||||
* Unfortunately, with COSE we must know the payload length
|
||||
* before we have seen the payload. It's illegal to use
|
||||
* indeterminite lengths inside COSE objects.
|
||||
*/
|
||||
|
||||
do {
|
||||
n = (int)read(fdin, temp, sizeof(temp));
|
||||
if (n < 0)
|
||||
goto bail3;
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
s = (size_t)n;
|
||||
|
||||
if (lws_buflist_append_segment(&paybuf, temp, s) < 0)
|
||||
goto bail3;
|
||||
i.inline_payload_len += s;
|
||||
|
||||
} while (1);
|
||||
|
||||
// lwsl_notice("%s: inline_payload_len %llu\n", __func__,
|
||||
// (unsigned long long)i.inline_payload_len);
|
||||
|
||||
csc = lws_cose_sign_create(&i);
|
||||
if (!csc)
|
||||
goto bail2;
|
||||
ck = lws_cose_key_from_set(&set, kid, kid_len);
|
||||
if (!ck)
|
||||
goto bail2;
|
||||
|
||||
if (lws_cose_sign_add(csc, alg, ck))
|
||||
goto bail2;
|
||||
|
||||
do {
|
||||
s = lws_buflist_next_segment_len(&paybuf, &ppay);
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
do {
|
||||
m = (int)lws_cose_sign_payload_chunk(csc,
|
||||
ppay, s);
|
||||
if (lec.used) {
|
||||
// lwsl_hexdump_err(sbuf, lec.used);
|
||||
write(fdout, sbuf, lec.used);
|
||||
lws_lec_setbuf(&lec, sbuf, sizeof(sbuf));
|
||||
}
|
||||
} while (m == LCOSESIGEXTCB_RET_AGAIN);
|
||||
|
||||
if (m == LWS_LECPCTX_RET_FAIL)
|
||||
goto bail2;
|
||||
|
||||
if (lec.used) {
|
||||
write(fdout, sbuf, lec.used);
|
||||
lws_lec_setbuf(&lec, sbuf, sizeof(sbuf));
|
||||
}
|
||||
|
||||
lws_buflist_use_segment(&paybuf, s);
|
||||
} while(1);
|
||||
|
||||
} else {
|
||||
memset(&vi, 0, sizeof(vi));
|
||||
|
||||
vi.cx = context;
|
||||
vi.keyset = &set;
|
||||
vi.sigtype = sigtype;
|
||||
vi.ext_cb = extra_cb;
|
||||
vi.ext_opaque = extra;
|
||||
vi.ext_len = ext_len;
|
||||
vi.pay_cb = pay_cb;
|
||||
|
||||
cps = lws_cose_validate_create(&vi);
|
||||
if (!cps) {
|
||||
lwsl_notice("%s: sign_val_create fail\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
do {
|
||||
n = (int)read(fdin, temp, sizeof(temp));
|
||||
if (n < 0)
|
||||
goto bail3;
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
n = lws_cose_validate_chunk(cps, temp, (size_t)n, NULL);
|
||||
if (n && n != LECP_CONTINUE) {
|
||||
lwsl_err("%s: chunk validation failed: %d\n",
|
||||
__func__, n);
|
||||
goto bail2;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
bail3:
|
||||
|
||||
result = 0;
|
||||
|
||||
if (!sign) {
|
||||
char buf[2048];
|
||||
int os;
|
||||
|
||||
o = lws_cose_validate_results(cps);
|
||||
if (!o)
|
||||
result = 1;
|
||||
else {
|
||||
os = lws_snprintf(buf, sizeof(buf),
|
||||
"\nresults count %d\n", o->count);
|
||||
write(fdout, buf, (size_t)os);
|
||||
|
||||
if (!o->count)
|
||||
result = 1;
|
||||
}
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
lws_dll2_get_head(o)) {
|
||||
lws_cose_validate_res_t *res = lws_container_of(p,
|
||||
lws_cose_validate_res_t, list);
|
||||
char khr[256];
|
||||
|
||||
khr[0] = '\0';
|
||||
if (res->cose_key) {
|
||||
ke = &res->cose_key->meta[COSEKEY_META_KID];
|
||||
if (ke && ke->buf)
|
||||
lws_hex_from_byte_array(ke->buf, ke->len,
|
||||
khr, sizeof(khr));
|
||||
}
|
||||
os = lws_snprintf(buf, sizeof(buf),
|
||||
" result: %d (alg %s, kid %s)\n",
|
||||
res->result,
|
||||
lws_cose_alg_to_name(res->cose_alg), khr);
|
||||
write(fdout, buf, (size_t)os);
|
||||
result |= res->result;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
}
|
||||
|
||||
bail2:
|
||||
if (!sign)
|
||||
lws_cose_validate_destroy(&cps);
|
||||
else {
|
||||
lws_buflist_destroy_all_segments(&paybuf);
|
||||
lws_cose_sign_destroy(&csc);
|
||||
}
|
||||
//bail1:
|
||||
lws_cose_key_set_destroy(&set);
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
|
||||
if (result)
|
||||
lwsl_err("%s: FAIL: %d\n", __func__, result);
|
||||
else
|
||||
lwsl_notice("%s: PASS\n", __func__);
|
||||
|
||||
bail_early:
|
||||
if (fdin > 0)
|
||||
close(fdin);
|
||||
if (fdout != 1 && fdout >= 0)
|
||||
close(fdout);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
The Test Payload
|
BIN
minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck
Normal file
BIN
minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck
Normal file
Binary file not shown.
BIN
minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks
Normal file
BIN
minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
Ò„C¡&¡B11TThis is the content.X@rœ×Ë8ØØéD¨Úqç²XɽÊa5÷®Ûî• ‰gƒ~3½6ÁP2jæ'UƽŽT><EFBFBD>’×Ò%èÛr¸‚
|
|
@ -0,0 +1 @@
|
|||
„C¡&¡B11TThis is the content.X@Ž³>L£FZ°Z¬4Ìk#Õ<>ï\1ÄÒZ‘®ð°~*ù¢‘ª2áJ¸4ÜVí*"4DT~ñ; å¤ÃEÊË6
|
|
@ -0,0 +1 @@
|
|||
Øb„A TThis is the content.<EFBFBD>ƒC¡&¡B11X@⮯Ô
iÑ<EFBFBD>þnR|]ôä(,¾û]Ëô¯.Ù‚¬E¬˜¸TL<54>‹EÞ<1E>·ÃÓHþ’j+˜õ:ý/ ó
|
|
@ -0,0 +1 @@
|
|||
Øb„@ TThis is the content.<EFBFBD>ƒC¡&¡B11X@˸ÚÙ¾¯¸<C2AF>á¤M‹ûÂkíò©OËZˆ$2¿öÖ>õtQØ?¢Ëö&rëôÇÙ“°ôÂDvGØ1ºW̨k“
|
|
@ -0,0 +1 @@
|
|||
„@ TThis is the content.<EFBFBD>ƒC¡&¡B11X@⮯Ô
iÑ<EFBFBD>þnR|]ôä(,¾û]Ëô¯.Ù‚¬E¬˜¸TL<54>‹EÞ<1E>·ÃÓHþ’j+˜õ:ý/ ó
|
|
@ -5,8 +5,9 @@ if [ -z "$1" ] ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p certs
|
||||
openssl genrsa -out $1.key 4096 && \
|
||||
printf "\\n\\n\\n\\n\\nlocalhost\\n\\n1234\\n\\n" | \
|
||||
printf "\\n\\n\\n\\n\\n$1\\n\\n1234\\n\\n" | \
|
||||
openssl req -config tmp.cnf -new -key $1.key -out $1.csr && \
|
||||
openssl ca -config tmp.cnf \
|
||||
-keyfile ca.key \
|
||||
|
|
|
@ -5,6 +5,7 @@ if [ -z "$1" ] ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p certs
|
||||
openssl genrsa -out $1.key 4096 && \
|
||||
printf "\\n\\n\\n\\n\\nlocalhost\\n\\n1234\\n\\n" | \
|
||||
openssl req -config tmp.cnf -new -key $1.key -out $1.csr && \
|
||||
|
|
Loading…
Add table
Reference in a new issue