1 /* 2 * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* 11 * ECDSA low level APIs are deprecated for public use, but still ok for 12 * internal use - SM2 implemetation uses ECDSA_size() function. 13 */ 14 #include "internal/deprecated.h" 15 16 #include <string.h> /* memcpy */ 17 #include <openssl/crypto.h> 18 #include <openssl/core_dispatch.h> 19 #include <openssl/core_names.h> 20 #include <openssl/dsa.h> 21 #include <openssl/params.h> 22 #include <openssl/evp.h> 23 #include <openssl/err.h> 24 #include <openssl/proverr.h> 25 #include "internal/nelem.h" 26 #include "internal/sizes.h" 27 #include "internal/cryptlib.h" 28 #include "internal/sm3.h" 29 #include "prov/implementations.h" 30 #include "prov/providercommon.h" 31 #include "prov/provider_ctx.h" 32 #include "crypto/ec.h" 33 #include "crypto/sm2.h" 34 #include "prov/der_sm2.h" 35 36 static OSSL_FUNC_signature_newctx_fn sm2sig_newctx; 37 static OSSL_FUNC_signature_sign_init_fn sm2sig_signature_init; 38 static OSSL_FUNC_signature_verify_init_fn sm2sig_signature_init; 39 static OSSL_FUNC_signature_sign_fn sm2sig_sign; 40 static OSSL_FUNC_signature_verify_fn sm2sig_verify; 41 static OSSL_FUNC_signature_digest_sign_init_fn sm2sig_digest_signverify_init; 42 static OSSL_FUNC_signature_digest_sign_update_fn sm2sig_digest_signverify_update; 43 static OSSL_FUNC_signature_digest_sign_final_fn sm2sig_digest_sign_final; 44 static OSSL_FUNC_signature_digest_verify_init_fn sm2sig_digest_signverify_init; 45 static OSSL_FUNC_signature_digest_verify_update_fn sm2sig_digest_signverify_update; 46 static OSSL_FUNC_signature_digest_verify_final_fn sm2sig_digest_verify_final; 47 static OSSL_FUNC_signature_freectx_fn sm2sig_freectx; 48 static OSSL_FUNC_signature_dupctx_fn sm2sig_dupctx; 49 static OSSL_FUNC_signature_get_ctx_params_fn sm2sig_get_ctx_params; 50 static OSSL_FUNC_signature_gettable_ctx_params_fn sm2sig_gettable_ctx_params; 51 static OSSL_FUNC_signature_set_ctx_params_fn sm2sig_set_ctx_params; 52 static OSSL_FUNC_signature_settable_ctx_params_fn sm2sig_settable_ctx_params; 53 static OSSL_FUNC_signature_get_ctx_md_params_fn sm2sig_get_ctx_md_params; 54 static OSSL_FUNC_signature_gettable_ctx_md_params_fn sm2sig_gettable_ctx_md_params; 55 static OSSL_FUNC_signature_set_ctx_md_params_fn sm2sig_set_ctx_md_params; 56 static OSSL_FUNC_signature_settable_ctx_md_params_fn sm2sig_settable_ctx_md_params; 57 58 /* 59 * What's passed as an actual key is defined by the KEYMGMT interface. 60 * We happen to know that our KEYMGMT simply passes EC structures, so 61 * we use that here too. 62 */ 63 typedef struct { 64 OSSL_LIB_CTX *libctx; 65 char *propq; 66 EC_KEY *ec; 67 68 /* 69 * Flag to termine if the 'z' digest needs to be computed and fed to the 70 * hash function. 71 * This flag should be set on initialization and the compuation should 72 * be performed only once, on first update. 73 */ 74 unsigned int flag_compute_z_digest : 1; 75 76 char mdname[OSSL_MAX_NAME_SIZE]; 77 78 /* The Algorithm Identifier of the combined signature algorithm */ 79 unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; 80 unsigned char *aid; 81 size_t aid_len; 82 83 /* main digest */ 84 EVP_MD *md; 85 EVP_MD_CTX *mdctx; 86 size_t mdsize; 87 88 /* SM2 ID used for calculating the Z value */ 89 unsigned char *id; 90 size_t id_len; 91 } PROV_SM2_CTX; 92 93 static int sm2sig_set_mdname(PROV_SM2_CTX *psm2ctx, const char *mdname) 94 { 95 if (psm2ctx->md == NULL) /* We need an SM3 md to compare with */ 96 psm2ctx->md = EVP_MD_fetch(psm2ctx->libctx, psm2ctx->mdname, 97 psm2ctx->propq); 98 if (psm2ctx->md == NULL) 99 return 0; 100 101 if (mdname == NULL) 102 return 1; 103 104 if (strlen(mdname) >= sizeof(psm2ctx->mdname) 105 || !EVP_MD_is_a(psm2ctx->md, mdname)) { 106 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "digest=%s", 107 mdname); 108 return 0; 109 } 110 111 OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname)); 112 return 1; 113 } 114 115 static void *sm2sig_newctx(void *provctx, const char *propq) 116 { 117 PROV_SM2_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_SM2_CTX)); 118 119 if (ctx == NULL) 120 return NULL; 121 122 ctx->libctx = PROV_LIBCTX_OF(provctx); 123 if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) { 124 OPENSSL_free(ctx); 125 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 126 return NULL; 127 } 128 ctx->mdsize = SM3_DIGEST_LENGTH; 129 strcpy(ctx->mdname, OSSL_DIGEST_NAME_SM3); 130 return ctx; 131 } 132 133 static int sm2sig_signature_init(void *vpsm2ctx, void *ec, 134 const OSSL_PARAM params[]) 135 { 136 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 137 138 if (!ossl_prov_is_running() 139 || psm2ctx == NULL) 140 return 0; 141 142 if (ec == NULL && psm2ctx->ec == NULL) { 143 ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); 144 return 0; 145 } 146 147 if (ec != NULL) { 148 if (!EC_KEY_up_ref(ec)) 149 return 0; 150 EC_KEY_free(psm2ctx->ec); 151 psm2ctx->ec = ec; 152 } 153 154 return sm2sig_set_ctx_params(psm2ctx, params); 155 } 156 157 static int sm2sig_sign(void *vpsm2ctx, unsigned char *sig, size_t *siglen, 158 size_t sigsize, const unsigned char *tbs, size_t tbslen) 159 { 160 PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; 161 int ret; 162 unsigned int sltmp; 163 /* SM2 uses ECDSA_size as well */ 164 size_t ecsize = ECDSA_size(ctx->ec); 165 166 if (sig == NULL) { 167 *siglen = ecsize; 168 return 1; 169 } 170 171 if (sigsize < (size_t)ecsize) 172 return 0; 173 174 if (ctx->mdsize != 0 && tbslen != ctx->mdsize) 175 return 0; 176 177 ret = ossl_sm2_internal_sign(tbs, tbslen, sig, &sltmp, ctx->ec); 178 if (ret <= 0) 179 return 0; 180 181 *siglen = sltmp; 182 return 1; 183 } 184 185 static int sm2sig_verify(void *vpsm2ctx, const unsigned char *sig, size_t siglen, 186 const unsigned char *tbs, size_t tbslen) 187 { 188 PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; 189 190 if (ctx->mdsize != 0 && tbslen != ctx->mdsize) 191 return 0; 192 193 return ossl_sm2_internal_verify(tbs, tbslen, sig, siglen, ctx->ec); 194 } 195 196 static void free_md(PROV_SM2_CTX *ctx) 197 { 198 EVP_MD_CTX_free(ctx->mdctx); 199 EVP_MD_free(ctx->md); 200 ctx->mdctx = NULL; 201 ctx->md = NULL; 202 } 203 204 static int sm2sig_digest_signverify_init(void *vpsm2ctx, const char *mdname, 205 void *ec, const OSSL_PARAM params[]) 206 { 207 PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; 208 int md_nid; 209 WPACKET pkt; 210 int ret = 0; 211 212 if (!sm2sig_signature_init(vpsm2ctx, ec, params) 213 || !sm2sig_set_mdname(ctx, mdname)) 214 return ret; 215 216 if (ctx->mdctx == NULL) { 217 ctx->mdctx = EVP_MD_CTX_new(); 218 if (ctx->mdctx == NULL) 219 goto error; 220 } 221 222 md_nid = EVP_MD_get_type(ctx->md); 223 224 /* 225 * We do not care about DER writing errors. 226 * All it really means is that for some reason, there's no 227 * AlgorithmIdentifier to be had, but the operation itself is 228 * still valid, just as long as it's not used to construct 229 * anything that needs an AlgorithmIdentifier. 230 */ 231 ctx->aid_len = 0; 232 if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) 233 && ossl_DER_w_algorithmIdentifier_SM2_with_MD(&pkt, -1, ctx->ec, md_nid) 234 && WPACKET_finish(&pkt)) { 235 WPACKET_get_total_written(&pkt, &ctx->aid_len); 236 ctx->aid = WPACKET_get_curr(&pkt); 237 } 238 WPACKET_cleanup(&pkt); 239 240 if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params)) 241 goto error; 242 243 ctx->flag_compute_z_digest = 1; 244 245 ret = 1; 246 247 error: 248 return ret; 249 } 250 251 static int sm2sig_compute_z_digest(PROV_SM2_CTX *ctx) 252 { 253 uint8_t *z = NULL; 254 int ret = 1; 255 256 if (ctx->flag_compute_z_digest) { 257 /* Only do this once */ 258 ctx->flag_compute_z_digest = 0; 259 260 if ((z = OPENSSL_zalloc(ctx->mdsize)) == NULL 261 /* get hashed prefix 'z' of tbs message */ 262 || !ossl_sm2_compute_z_digest(z, ctx->md, ctx->id, ctx->id_len, 263 ctx->ec) 264 || !EVP_DigestUpdate(ctx->mdctx, z, ctx->mdsize)) 265 ret = 0; 266 OPENSSL_free(z); 267 } 268 269 return ret; 270 } 271 272 int sm2sig_digest_signverify_update(void *vpsm2ctx, const unsigned char *data, 273 size_t datalen) 274 { 275 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 276 277 if (psm2ctx == NULL || psm2ctx->mdctx == NULL) 278 return 0; 279 280 return sm2sig_compute_z_digest(psm2ctx) 281 && EVP_DigestUpdate(psm2ctx->mdctx, data, datalen); 282 } 283 284 int sm2sig_digest_sign_final(void *vpsm2ctx, unsigned char *sig, size_t *siglen, 285 size_t sigsize) 286 { 287 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 288 unsigned char digest[EVP_MAX_MD_SIZE]; 289 unsigned int dlen = 0; 290 291 if (psm2ctx == NULL || psm2ctx->mdctx == NULL) 292 return 0; 293 294 /* 295 * If sig is NULL then we're just finding out the sig size. Other fields 296 * are ignored. Defer to sm2sig_sign. 297 */ 298 if (sig != NULL) { 299 if (!(sm2sig_compute_z_digest(psm2ctx) 300 && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen))) 301 return 0; 302 } 303 304 return sm2sig_sign(vpsm2ctx, sig, siglen, sigsize, digest, (size_t)dlen); 305 } 306 307 308 int sm2sig_digest_verify_final(void *vpsm2ctx, const unsigned char *sig, 309 size_t siglen) 310 { 311 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 312 unsigned char digest[EVP_MAX_MD_SIZE]; 313 unsigned int dlen = 0; 314 315 if (psm2ctx == NULL 316 || psm2ctx->mdctx == NULL 317 || EVP_MD_get_size(psm2ctx->md) > (int)sizeof(digest)) 318 return 0; 319 320 if (!(sm2sig_compute_z_digest(psm2ctx) 321 && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen))) 322 return 0; 323 324 return sm2sig_verify(vpsm2ctx, sig, siglen, digest, (size_t)dlen); 325 } 326 327 static void sm2sig_freectx(void *vpsm2ctx) 328 { 329 PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; 330 331 free_md(ctx); 332 EC_KEY_free(ctx->ec); 333 OPENSSL_free(ctx->id); 334 OPENSSL_free(ctx); 335 } 336 337 static void *sm2sig_dupctx(void *vpsm2ctx) 338 { 339 PROV_SM2_CTX *srcctx = (PROV_SM2_CTX *)vpsm2ctx; 340 PROV_SM2_CTX *dstctx; 341 342 dstctx = OPENSSL_zalloc(sizeof(*srcctx)); 343 if (dstctx == NULL) 344 return NULL; 345 346 *dstctx = *srcctx; 347 dstctx->ec = NULL; 348 dstctx->md = NULL; 349 dstctx->mdctx = NULL; 350 351 if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec)) 352 goto err; 353 dstctx->ec = srcctx->ec; 354 355 if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) 356 goto err; 357 dstctx->md = srcctx->md; 358 359 if (srcctx->mdctx != NULL) { 360 dstctx->mdctx = EVP_MD_CTX_new(); 361 if (dstctx->mdctx == NULL 362 || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx)) 363 goto err; 364 } 365 366 if (srcctx->id != NULL) { 367 dstctx->id = OPENSSL_malloc(srcctx->id_len); 368 if (dstctx->id == NULL) 369 goto err; 370 dstctx->id_len = srcctx->id_len; 371 memcpy(dstctx->id, srcctx->id, srcctx->id_len); 372 } 373 374 return dstctx; 375 err: 376 sm2sig_freectx(dstctx); 377 return NULL; 378 } 379 380 static int sm2sig_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) 381 { 382 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 383 OSSL_PARAM *p; 384 385 if (psm2ctx == NULL) 386 return 0; 387 388 p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); 389 if (p != NULL 390 && !OSSL_PARAM_set_octet_string(p, psm2ctx->aid, psm2ctx->aid_len)) 391 return 0; 392 393 p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); 394 if (p != NULL && !OSSL_PARAM_set_size_t(p, psm2ctx->mdsize)) 395 return 0; 396 397 p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); 398 if (p != NULL && !OSSL_PARAM_set_utf8_string(p, psm2ctx->md == NULL 399 ? psm2ctx->mdname 400 : EVP_MD_get0_name(psm2ctx->md))) 401 return 0; 402 403 return 1; 404 } 405 406 static const OSSL_PARAM known_gettable_ctx_params[] = { 407 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), 408 OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), 409 OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), 410 OSSL_PARAM_END 411 }; 412 413 static const OSSL_PARAM *sm2sig_gettable_ctx_params(ossl_unused void *vpsm2ctx, 414 ossl_unused void *provctx) 415 { 416 return known_gettable_ctx_params; 417 } 418 419 static int sm2sig_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) 420 { 421 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 422 const OSSL_PARAM *p; 423 size_t mdsize; 424 425 if (psm2ctx == NULL) 426 return 0; 427 if (params == NULL) 428 return 1; 429 430 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DIST_ID); 431 if (p != NULL) { 432 void *tmp_id = NULL; 433 size_t tmp_idlen = 0; 434 435 /* 436 * If the 'z' digest has already been computed, the ID is set too late 437 */ 438 if (!psm2ctx->flag_compute_z_digest) 439 return 0; 440 441 if (p->data_size != 0 442 && !OSSL_PARAM_get_octet_string(p, &tmp_id, 0, &tmp_idlen)) 443 return 0; 444 OPENSSL_free(psm2ctx->id); 445 psm2ctx->id = tmp_id; 446 psm2ctx->id_len = tmp_idlen; 447 } 448 449 /* 450 * The following code checks that the size is the same as the SM3 digest 451 * size returning an error otherwise. 452 * If there is ever any different digest algorithm allowed with SM2 453 * this needs to be adjusted accordingly. 454 */ 455 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); 456 if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize) 457 || mdsize != psm2ctx->mdsize)) 458 return 0; 459 460 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); 461 if (p != NULL) { 462 char *mdname = NULL; 463 464 if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0)) 465 return 0; 466 if (!sm2sig_set_mdname(psm2ctx, mdname)) { 467 OPENSSL_free(mdname); 468 return 0; 469 } 470 OPENSSL_free(mdname); 471 } 472 473 return 1; 474 } 475 476 static const OSSL_PARAM known_settable_ctx_params[] = { 477 OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), 478 OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), 479 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DIST_ID, NULL, 0), 480 OSSL_PARAM_END 481 }; 482 483 static const OSSL_PARAM *sm2sig_settable_ctx_params(ossl_unused void *vpsm2ctx, 484 ossl_unused void *provctx) 485 { 486 return known_settable_ctx_params; 487 } 488 489 static int sm2sig_get_ctx_md_params(void *vpsm2ctx, OSSL_PARAM *params) 490 { 491 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 492 493 if (psm2ctx->mdctx == NULL) 494 return 0; 495 496 return EVP_MD_CTX_get_params(psm2ctx->mdctx, params); 497 } 498 499 static const OSSL_PARAM *sm2sig_gettable_ctx_md_params(void *vpsm2ctx) 500 { 501 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 502 503 if (psm2ctx->md == NULL) 504 return 0; 505 506 return EVP_MD_gettable_ctx_params(psm2ctx->md); 507 } 508 509 static int sm2sig_set_ctx_md_params(void *vpsm2ctx, const OSSL_PARAM params[]) 510 { 511 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 512 513 if (psm2ctx->mdctx == NULL) 514 return 0; 515 516 return EVP_MD_CTX_set_params(psm2ctx->mdctx, params); 517 } 518 519 static const OSSL_PARAM *sm2sig_settable_ctx_md_params(void *vpsm2ctx) 520 { 521 PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; 522 523 if (psm2ctx->md == NULL) 524 return 0; 525 526 return EVP_MD_settable_ctx_params(psm2ctx->md); 527 } 528 529 const OSSL_DISPATCH ossl_sm2_signature_functions[] = { 530 { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sm2sig_newctx }, 531 { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))sm2sig_signature_init }, 532 { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sm2sig_sign }, 533 { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))sm2sig_signature_init }, 534 { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))sm2sig_verify }, 535 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, 536 (void (*)(void))sm2sig_digest_signverify_init }, 537 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, 538 (void (*)(void))sm2sig_digest_signverify_update }, 539 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, 540 (void (*)(void))sm2sig_digest_sign_final }, 541 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, 542 (void (*)(void))sm2sig_digest_signverify_init }, 543 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, 544 (void (*)(void))sm2sig_digest_signverify_update }, 545 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, 546 (void (*)(void))sm2sig_digest_verify_final }, 547 { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sm2sig_freectx }, 548 { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))sm2sig_dupctx }, 549 { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))sm2sig_get_ctx_params }, 550 { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, 551 (void (*)(void))sm2sig_gettable_ctx_params }, 552 { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))sm2sig_set_ctx_params }, 553 { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, 554 (void (*)(void))sm2sig_settable_ctx_params }, 555 { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, 556 (void (*)(void))sm2sig_get_ctx_md_params }, 557 { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, 558 (void (*)(void))sm2sig_gettable_ctx_md_params }, 559 { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, 560 (void (*)(void))sm2sig_set_ctx_md_params }, 561 { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, 562 (void (*)(void))sm2sig_settable_ctx_md_params }, 563 { 0, NULL } 564 }; 565