1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include "private-lib-core.h" 26#include "private-lib-cose.h" 27 28lws_cose_sig_alg_t * 29lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck, 30 cose_param_t cose_alg, int op) 31{ 32 lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__); 33 struct lws_gencrypto_keyelem *ke; 34 enum lws_genhmac_types ghm; 35 enum lws_genhash_types gh; 36 const char *crv; 37 38 if (!alg) 39 return NULL; 40 41 alg->cose_alg = cose_alg; 42 alg->cose_key = ck; 43 44 switch (cose_alg) { 45 46 /* ECDSA algs */ 47 48 case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */ 49 crv = "P-256"; 50 gh = LWS_GENHASH_TYPE_SHA256; 51 alg->keybits = 256; 52 goto ecdsa; 53 case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */ 54 crv = "P-384"; 55 gh = LWS_GENHASH_TYPE_SHA384; 56 alg->keybits = 384; 57 goto ecdsa; 58 case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */ 59 crv = "P-521"; 60 gh = LWS_GENHASH_TYPE_SHA512; 61 alg->keybits = 521; 62ecdsa: 63 64 /* the key is good for this? */ 65 66 if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg, 67 op, crv)) 68 goto bail_ecdsa; 69 70 if (lws_genhash_init(&alg->hash_ctx, gh)) 71 goto bail_ecdsa; 72 73 if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) { 74 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", 75 __func__); 76 goto bail_ecdsa1; 77 } 78 79 if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) { 80 lwsl_notice("%s: ec key import fail\n", __func__); 81 goto bail_ecdsa2; 82 } 83 84 break; 85 86 /* HMAC algs */ 87 88 case LWSCOSE_WKAHMAC_256_64: 89 ghm = LWS_GENHMAC_TYPE_SHA256; 90 alg->keybits = 64; 91 goto hmac; 92 case LWSCOSE_WKAHMAC_256_256: 93 ghm = LWS_GENHMAC_TYPE_SHA256; 94 alg->keybits = 256; 95 goto hmac; 96 case LWSCOSE_WKAHMAC_384_384: 97 ghm = LWS_GENHMAC_TYPE_SHA384; 98 alg->keybits = 384; 99 goto hmac; 100 case LWSCOSE_WKAHMAC_512_512: 101 ghm = LWS_GENHMAC_TYPE_SHA512; 102 alg->keybits = 512; 103 104hmac: 105 if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC, 106 cose_alg, op, NULL)) 107 goto bail_hmac; 108 109 ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K]; 110 if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len)) 111 goto bail_hmac; 112 113 break; 114 115 /* RSASSA algs */ 116 117 case LWSCOSE_WKARSA_ALG_RS256: 118 gh = LWS_GENHASH_TYPE_SHA256; 119 goto rsassa; 120 121 case LWSCOSE_WKARSA_ALG_RS384: 122 gh = LWS_GENHASH_TYPE_SHA384; 123 goto rsassa; 124 125 case LWSCOSE_WKARSA_ALG_RS512: 126 gh = LWS_GENHASH_TYPE_SHA512; 127 128rsassa: 129 if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg, 130 op, NULL)) 131 goto bail_hmac; 132 alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8; 133 134 if (lws_genhash_init(&alg->hash_ctx, gh)) 135 goto bail_ecdsa; 136 137 if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx, 138 LGRSAM_PKCS1_1_5, gh)) { 139 lwsl_notice("%s: lws_genrsa_create fail\n", __func__); 140 goto bail_ecdsa1; 141 } 142 break; 143 144 default: 145 lwsl_warn("%s: unsupported alg %lld\n", __func__, 146 (long long)cose_alg); 147 goto bail_hmac; 148 } 149 150 return alg; 151 152bail_ecdsa2: 153 lws_genec_destroy(&alg->u.ecdsactx); 154bail_ecdsa1: 155 lws_genhash_destroy(&alg->hash_ctx, NULL); 156bail_ecdsa: 157 lws_free(alg); 158 159 lwsl_notice("%s: failed\n", __func__); 160 161 return NULL; 162 163bail_hmac: 164 lws_free(alg); 165 166 return NULL; 167} 168 169int 170lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len) 171{ 172#if defined(VERBOSE) 173 lwsl_hexdump_warn(in, in_len); 174#endif 175 176 switch (alg->cose_alg) { 177 case LWSCOSE_WKAHMAC_256_64: 178 case LWSCOSE_WKAHMAC_256_256: 179 case LWSCOSE_WKAHMAC_384_384: 180 case LWSCOSE_WKAHMAC_512_512: 181 return lws_genhmac_update(&alg->u.hmacctx, in, in_len); 182 } 183 184 return lws_genhash_update(&alg->hash_ctx, in, in_len); 185} 186 187void 188lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps, 189 lws_cose_sig_alg_t **_alg, const uint8_t *against, 190 size_t against_len) 191{ 192 uint8_t digest[LWS_GENHASH_LARGEST]; 193 lws_cose_sig_alg_t *alg = *_alg; 194 lws_cose_validate_res_t *res; 195 size_t hs, shs; 196 int keybits; 197 uint8_t ht; 198 199 lws_dll2_remove(&alg->list); 200 ht = alg->hash_ctx.type; 201 keybits = alg->keybits; 202 203 res = lws_zalloc(sizeof(*res), __func__); 204 if (res) { 205 206 res->cose_key = alg->cose_key; 207 res->cose_alg = alg->cose_alg; 208 res->result = -999; 209 210 lws_dll2_add_tail(&res->list, &cps->results); 211 } 212 213 switch (alg->cose_alg) { 214 case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */ 215 case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */ 216 case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */ 217 hs = lws_genhash_size(alg->hash_ctx.type); 218 lws_genhash_destroy(&alg->hash_ctx, digest); 219 220 lwsl_notice("%d %d %d\n", (int)hs, (int)keybits, (int)against_len); 221 222 if (res && against) 223 res->result = lws_genecdsa_hash_sig_verify_jws( 224 &alg->u.ecdsactx, digest, ht, 225 keybits, against, against_len); 226 lws_genec_destroy(&alg->u.ecdsactx); 227 break; 228 229 case LWSCOSE_WKAHMAC_256_64: 230 case LWSCOSE_WKAHMAC_256_256: 231 case LWSCOSE_WKAHMAC_384_384: 232 case LWSCOSE_WKAHMAC_512_512: 233 shs = hs = lws_genhmac_size(alg->u.hmacctx.type); 234 if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64) 235 shs = 8; 236 237 if (lws_genhmac_destroy(&alg->u.hmacctx, digest)) { 238 lwsl_err("%s: destroy failed\n", __func__); 239 break; 240 } 241 242 if (cps->mac_pos != shs) { 243 lwsl_warn("%s: mac wrong size\n", __func__); 244 /* we can't compare it, leave it at fail */ 245 break; 246 } 247 if (res && against) { 248 res->result = lws_timingsafe_bcmp(digest, cps->mac, 249 (uint32_t)shs); 250 if (res->result) 251 lwsl_warn("%s: hash mismatch\n", __func__); 252 } 253 break; 254 255 case LWSCOSE_WKARSA_ALG_RS256: 256 case LWSCOSE_WKARSA_ALG_RS384: 257 case LWSCOSE_WKARSA_ALG_RS512: 258 259 if (!lws_genhash_destroy(&alg->hash_ctx, digest) && 260 !alg->failed && 261 lws_genrsa_hash_sig_verify(&alg->u.rsactx, digest, 262 alg->hash_ctx.type, 263 against, against_len) >= 0) { 264 if (res) 265 res->result = 0; 266 } else 267 lwsl_err("%s: lws_genrsa_hash_verify\n", __func__); 268 269 lws_genrsa_destroy(&alg->u.rsactx); 270 break; 271 } 272 273 lws_free_set_NULL(*_alg); 274} 275