1/* 2 * Copyright 2019-2024 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{- 10use OpenSSL::paramnames qw(produce_param_decoder); 11-} 12 13/* Dispatch functions for gcm mode */ 14 15#include <openssl/rand.h> 16#include <openssl/proverr.h> 17#include "prov/ciphercommon.h" 18#include "prov/ciphercommon_gcm.h" 19#include "prov/providercommon.h" 20#include "prov/provider_ctx.h" 21 22static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len); 23static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv, 24 size_t len); 25static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen, 26 const unsigned char *in, size_t len); 27static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out, 28 size_t *padlen, const unsigned char *in, 29 size_t len); 30 31/* 32 * Called from EVP_CipherInit when there is currently no context via 33 * the new_ctx() function 34 */ 35void ossl_gcm_initctx(void *provctx, PROV_GCM_CTX *ctx, size_t keybits, 36 const PROV_GCM_HW *hw) 37{ 38 ctx->pad = 1; 39 ctx->mode = EVP_CIPH_GCM_MODE; 40 ctx->taglen = UNINITIALISED_SIZET; 41 ctx->tls_aad_len = UNINITIALISED_SIZET; 42 ctx->ivlen = (EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN); 43 ctx->keylen = keybits / 8; 44 ctx->hw = hw; 45 ctx->libctx = PROV_LIBCTX_OF(provctx); 46} 47 48/* 49 * Called by EVP_CipherInit via the _einit and _dinit functions 50 */ 51static int gcm_init(void *vctx, const unsigned char *key, size_t keylen, 52 const unsigned char *iv, size_t ivlen, 53 const OSSL_PARAM params[], int enc) 54{ 55 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 56 57 if (!ossl_prov_is_running()) 58 return 0; 59 60 ctx->enc = enc; 61 62 if (iv != NULL) { 63 if (ivlen == 0 || ivlen > sizeof(ctx->iv)) { 64 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 65 return 0; 66 } 67 ctx->ivlen = ivlen; 68 memcpy(ctx->iv, iv, ivlen); 69 ctx->iv_state = IV_STATE_BUFFERED; 70 } 71 72 if (key != NULL) { 73 if (keylen != ctx->keylen) { 74 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 75 return 0; 76 } 77 if (!ctx->hw->setkey(ctx, key, ctx->keylen)) 78 return 0; 79 ctx->tls_enc_records = 0; 80 } 81 return ossl_gcm_set_ctx_params(ctx, params); 82} 83 84int ossl_gcm_einit(void *vctx, const unsigned char *key, size_t keylen, 85 const unsigned char *iv, size_t ivlen, 86 const OSSL_PARAM params[]) 87{ 88 return gcm_init(vctx, key, keylen, iv, ivlen, params, 1); 89} 90 91int ossl_gcm_dinit(void *vctx, const unsigned char *key, size_t keylen, 92 const unsigned char *iv, size_t ivlen, 93 const OSSL_PARAM params[]) 94{ 95 return gcm_init(vctx, key, keylen, iv, ivlen, params, 0); 96} 97 98/* increment counter (64-bit int) by 1 */ 99static void ctr64_inc(unsigned char *counter) 100{ 101 int n = 8; 102 unsigned char c; 103 104 do { 105 --n; 106 c = counter[n]; 107 ++c; 108 counter[n] = c; 109 if (c > 0) 110 return; 111 } while (n > 0); 112} 113 114static int getivgen(PROV_GCM_CTX *ctx, unsigned char *out, size_t olen) 115{ 116 if (!ctx->iv_gen 117 || !ctx->key_set 118 || !ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen)) 119 return 0; 120 if (olen == 0 || olen > ctx->ivlen) 121 olen = ctx->ivlen; 122 memcpy(out, ctx->iv + ctx->ivlen - olen, olen); 123 /* 124 * Invocation field will be at least 8 bytes in size and so no need 125 * to check wrap around or increment more than last 8 bytes. 126 */ 127 ctr64_inc(ctx->iv + ctx->ivlen - 8); 128 ctx->iv_state = IV_STATE_COPIED; 129 return 1; 130} 131 132static int setivinv(PROV_GCM_CTX *ctx, unsigned char *in, size_t inl) 133{ 134 if (!ctx->iv_gen 135 || !ctx->key_set 136 || ctx->enc) 137 return 0; 138 139 memcpy(ctx->iv + ctx->ivlen - inl, in, inl); 140 if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen)) 141 return 0; 142 ctx->iv_state = IV_STATE_COPIED; 143 return 1; 144} 145 146{- produce_param_decoder('ossl_cipher_gcm_get_ctx_params', 147 (['CIPHER_PARAM_KEYLEN', 'keylen', 'size_t'], 148 ['CIPHER_PARAM_IVLEN', 'ivlen', 'size_t'], 149 ['CIPHER_PARAM_AEAD_TAGLEN', 'taglen', 'size_t'], 150 ['CIPHER_PARAM_IV', 'iv', 'octet_string'], 151 ['CIPHER_PARAM_UPDATED_IV', 'updiv', 'octet_string'], 152 ['CIPHER_PARAM_AEAD_TAG', 'tag', 'octet_string'], 153 ['CIPHER_PARAM_AEAD_TLS1_AAD_PAD', 'pad', 'size_t'], 154 ['CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN', 'ivgen', 'octet_string'], 155 ['CIPHER_PARAM_AEAD_IV_GENERATED', 'gen', 'uint'], 156 )); -} 157 158const OSSL_PARAM *ossl_gcm_gettable_ctx_params( 159 ossl_unused void *cctx, ossl_unused void *provctx 160 ) 161{ 162 return ossl_cipher_gcm_get_ctx_params_list; 163} 164 165int ossl_gcm_get_ctx_params(void *vctx, OSSL_PARAM params[]) 166{ 167 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 168 size_t sz; 169 struct ossl_cipher_gcm_get_ctx_params_st p; 170 171 if (ctx == NULL || !ossl_cipher_gcm_get_ctx_params_decoder(params, &p)) 172 return 0; 173 174 if (p.ivlen != NULL && !OSSL_PARAM_set_size_t(p.ivlen, ctx->ivlen)) { 175 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 176 return 0; 177 } 178 179 if (p.keylen != NULL && !OSSL_PARAM_set_size_t(p.keylen, ctx->keylen)) { 180 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 181 return 0; 182 } 183 184 if (p.taglen != NULL) { 185 size_t taglen = (ctx->taglen != UNINITIALISED_SIZET) ? ctx->taglen : 186 GCM_TAG_MAX_SIZE; 187 188 if (!OSSL_PARAM_set_size_t(p.taglen, taglen)) { 189 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 190 return 0; 191 } 192 } 193 194 if (p.iv != NULL) { 195 if (ctx->iv_state == IV_STATE_UNINITIALISED) 196 return 0; 197 if (ctx->ivlen > p.iv->data_size) { 198 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 199 return 0; 200 } 201 if (!OSSL_PARAM_set_octet_string_or_ptr(p.iv, ctx->iv, ctx->ivlen)) { 202 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 203 return 0; 204 } 205 } 206 207 if (p.updiv != NULL) { 208 if (ctx->iv_state == IV_STATE_UNINITIALISED) 209 return 0; 210 if (ctx->ivlen > p.updiv->data_size) { 211 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 212 return 0; 213 } 214 if (!OSSL_PARAM_set_octet_string_or_ptr(p.updiv, ctx->iv, ctx->ivlen)) { 215 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 216 return 0; 217 } 218 } 219 220 if (p.pad != NULL && !OSSL_PARAM_set_size_t(p.pad, ctx->tls_aad_pad_sz)) { 221 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 222 return 0; 223 } 224 225 if (p.tag != NULL) { 226 sz = p.tag->data_size; 227 if (sz == 0 228 || sz > EVP_GCM_TLS_TAG_LEN 229 || !ctx->enc 230 || ctx->taglen == UNINITIALISED_SIZET) { 231 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); 232 return 0; 233 } 234 if (!OSSL_PARAM_set_octet_string(p.tag, ctx->buf, sz)) { 235 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 236 return 0; 237 } 238 } 239 240 if (p.ivgen != NULL) 241 if (p.ivgen->data == NULL 242 || p.ivgen->data_type != OSSL_PARAM_OCTET_STRING 243 || !getivgen(ctx, p.ivgen->data, p.ivgen->data_size)) 244 return 0; 245 246 if (p.gen != NULL && !OSSL_PARAM_set_uint(p.gen, ctx->iv_gen_rand)) 247 return 0; 248 249 return 1; 250} 251 252{- produce_param_decoder 253 ('ossl_cipher_gcm_set_ctx_params', 254 (['CIPHER_PARAM_AEAD_IVLEN', 'ivlen', 'size_t'], 255 ['CIPHER_PARAM_AEAD_TAG', 'tag', 'octet_string'], 256 ['CIPHER_PARAM_AEAD_TLS1_AAD', 'aad', 'octet_string'], 257 ['CIPHER_PARAM_AEAD_TLS1_IV_FIXED', 'fixed', 'octet_string'], 258 ['CIPHER_PARAM_AEAD_TLS1_SET_IV_INV', 'inviv', 'octet_string'], 259 )); -} 260 261const OSSL_PARAM *ossl_gcm_settable_ctx_params( 262 ossl_unused void *cctx, ossl_unused void *provctx 263 ) 264{ 265 return ossl_cipher_gcm_set_ctx_params_list; 266} 267 268int ossl_gcm_set_ctx_params(void *vctx, const OSSL_PARAM params[]) 269{ 270 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 271 size_t sz; 272 void *vp; 273 struct ossl_cipher_gcm_set_ctx_params_st p; 274 275 if (ctx == NULL || !ossl_cipher_gcm_set_ctx_params_decoder(params, &p)) 276 return 0; 277 278 if (p.tag != NULL) { 279 vp = ctx->buf; 280 if (!OSSL_PARAM_get_octet_string(p.tag, &vp, EVP_GCM_TLS_TAG_LEN, &sz)) { 281 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 282 return 0; 283 } 284 if (sz == 0 || ctx->enc) { 285 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); 286 return 0; 287 } 288 ctx->taglen = sz; 289 } 290 291 if (p.ivlen != NULL) { 292 if (!OSSL_PARAM_get_size_t(p.ivlen, &sz)) { 293 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 294 return 0; 295 } 296 if (sz == 0 || sz > sizeof(ctx->iv)) { 297 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 298 return 0; 299 } 300 if (ctx->ivlen != sz) { 301 /* If the iv was already set or autogenerated, it is invalid. */ 302 if (ctx->iv_state != IV_STATE_UNINITIALISED) 303 ctx->iv_state = IV_STATE_FINISHED; 304 ctx->ivlen = sz; 305 } 306 } 307 308 if (p.aad != NULL) { 309 if (p.aad->data_type != OSSL_PARAM_OCTET_STRING) { 310 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 311 return 0; 312 } 313 sz = gcm_tls_init(ctx, p.aad->data, p.aad->data_size); 314 if (sz == 0) { 315 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_AAD); 316 return 0; 317 } 318 ctx->tls_aad_pad_sz = sz; 319 } 320 321 if (p.fixed != NULL) { 322 if (p.fixed->data_type != OSSL_PARAM_OCTET_STRING) { 323 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 324 return 0; 325 } 326 if (gcm_tls_iv_set_fixed(ctx, p.fixed->data, p.fixed->data_size) == 0) { 327 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 328 return 0; 329 } 330 } 331 332 if (p.inviv != NULL) 333 if (p.inviv->data == NULL 334 || p.inviv->data_type != OSSL_PARAM_OCTET_STRING 335 || !setivinv(ctx, p.inviv->data, p.inviv->data_size)) 336 return 0; 337 338 return 1; 339} 340 341int ossl_gcm_stream_update(void *vctx, unsigned char *out, size_t *outl, 342 size_t outsize, const unsigned char *in, size_t inl) 343{ 344 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 345 346 if (inl == 0) { 347 *outl = 0; 348 return 1; 349 } 350 351 if (outsize < inl) { 352 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 353 return 0; 354 } 355 356 if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0) { 357 ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); 358 return 0; 359 } 360 return 1; 361} 362 363int ossl_gcm_stream_final(void *vctx, unsigned char *out, size_t *outl, 364 size_t outsize) 365{ 366 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 367 int i; 368 369 if (!ossl_prov_is_running()) 370 return 0; 371 372 i = gcm_cipher_internal(ctx, out, outl, NULL, 0); 373 if (i <= 0) 374 return 0; 375 376 *outl = 0; 377 return 1; 378} 379 380int ossl_gcm_cipher(void *vctx, 381 unsigned char *out, size_t *outl, size_t outsize, 382 const unsigned char *in, size_t inl) 383{ 384 PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; 385 386 if (!ossl_prov_is_running()) 387 return 0; 388 389 if (outsize < inl) { 390 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 391 return 0; 392 } 393 394 if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0) 395 return 0; 396 397 *outl = inl; 398 return 1; 399} 400 401/* 402 * See SP800-38D (GCM) Section 8 "Uniqueness requirement on IVS and keys" 403 * 404 * See also 8.2.2 RBG-based construction. 405 * Random construction consists of a free field (which can be NULL) and a 406 * random field which will use a DRBG that can return at least 96 bits of 407 * entropy strength. (The DRBG must be seeded by the FIPS module). 408 */ 409static int gcm_iv_generate(PROV_GCM_CTX *ctx, int offset) 410{ 411 int sz = (int)(ctx->ivlen - offset); 412 413 /* Must be at least 96 bits */ 414 if (sz <= 0 || ctx->ivlen < GCM_IV_DEFAULT_SIZE) 415 return 0; 416 417 /* Use DRBG to generate random iv */ 418 if (RAND_bytes_ex(ctx->libctx, ctx->iv + offset, sz, 0) <= 0) 419 return 0; 420 ctx->iv_state = IV_STATE_BUFFERED; 421 ctx->iv_gen_rand = 1; 422 return 1; 423} 424 425static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out, 426 size_t *padlen, const unsigned char *in, 427 size_t len) 428{ 429 size_t olen = 0; 430 int rv = 0; 431 const PROV_GCM_HW *hw = ctx->hw; 432 433 if (ctx->tls_aad_len != UNINITIALISED_SIZET) 434 return gcm_tls_cipher(ctx, out, padlen, in, len); 435 436 if (!ctx->key_set || ctx->iv_state == IV_STATE_FINISHED) 437 goto err; 438 439 /* 440 * FIPS requires generation of AES-GCM IV's inside the FIPS module. 441 * The IV can still be set externally (the security policy will state that 442 * this is not FIPS compliant). There are some applications 443 * where setting the IV externally is the only option available. 444 */ 445 if (ctx->iv_state == IV_STATE_UNINITIALISED) { 446 if (!ctx->enc || !gcm_iv_generate(ctx, 0)) 447 goto err; 448 } 449 450 if (ctx->iv_state == IV_STATE_BUFFERED) { 451 if (!hw->setiv(ctx, ctx->iv, ctx->ivlen)) 452 goto err; 453 ctx->iv_state = IV_STATE_COPIED; 454 } 455 456 if (in != NULL) { 457 /* The input is AAD if out is NULL */ 458 if (out == NULL) { 459 if (!hw->aadupdate(ctx, in, len)) 460 goto err; 461 } else { 462 /* The input is ciphertext OR plaintext */ 463 if (!hw->cipherupdate(ctx, in, len, out)) 464 goto err; 465 } 466 } else { 467 /* The tag must be set before actually decrypting data */ 468 if (!ctx->enc && ctx->taglen == UNINITIALISED_SIZET) 469 goto err; 470 if (!hw->cipherfinal(ctx, ctx->buf)) 471 goto err; 472 ctx->iv_state = IV_STATE_FINISHED; /* Don't reuse the IV */ 473 goto finish; 474 } 475 olen = len; 476finish: 477 rv = 1; 478err: 479 *padlen = olen; 480 return rv; 481} 482 483static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len) 484{ 485 unsigned char *buf; 486 size_t len; 487 488 if (!ossl_prov_is_running() || aad_len != EVP_AEAD_TLS1_AAD_LEN) 489 return 0; 490 491 /* Save the aad for later use. */ 492 buf = dat->buf; 493 memcpy(buf, aad, aad_len); 494 dat->tls_aad_len = aad_len; 495 496 len = buf[aad_len - 2] << 8 | buf[aad_len - 1]; 497 /* Correct length for explicit iv. */ 498 if (len < EVP_GCM_TLS_EXPLICIT_IV_LEN) 499 return 0; 500 len -= EVP_GCM_TLS_EXPLICIT_IV_LEN; 501 502 /* If decrypting correct for tag too. */ 503 if (!dat->enc) { 504 if (len < EVP_GCM_TLS_TAG_LEN) 505 return 0; 506 len -= EVP_GCM_TLS_TAG_LEN; 507 } 508 buf[aad_len - 2] = (unsigned char)(len >> 8); 509 buf[aad_len - 1] = (unsigned char)(len & 0xff); 510 /* Extra padding: tag appended to record. */ 511 return EVP_GCM_TLS_TAG_LEN; 512} 513 514static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv, 515 size_t len) 516{ 517 /* Special case: -1 length restores whole IV */ 518 if (len == (size_t)-1) { 519 memcpy(ctx->iv, iv, ctx->ivlen); 520 ctx->iv_gen = 1; 521 ctx->iv_state = IV_STATE_BUFFERED; 522 return 1; 523 } 524 /* Fixed field must be at least 4 bytes and invocation field at least 8 */ 525 if ((len < EVP_GCM_TLS_FIXED_IV_LEN) 526 || (ctx->ivlen - (int)len) < EVP_GCM_TLS_EXPLICIT_IV_LEN) 527 return 0; 528 if (len > 0) 529 memcpy(ctx->iv, iv, len); 530 if (ctx->enc) { 531 if (RAND_bytes_ex(ctx->libctx, ctx->iv + len, ctx->ivlen - len, 0) <= 0) 532 return 0; 533 ctx->iv_gen_rand = 1; 534 } 535 ctx->iv_gen = 1; 536 ctx->iv_state = IV_STATE_BUFFERED; 537 return 1; 538} 539 540/* 541 * Handle TLS GCM packet format. This consists of the last portion of the IV 542 * followed by the payload and finally the tag. On encrypt generate IV, 543 * encrypt payload and write the tag. On verify retrieve IV, decrypt payload 544 * and verify tag. 545 */ 546static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen, 547 const unsigned char *in, size_t len) 548{ 549 int rv = 0; 550 size_t arg = EVP_GCM_TLS_EXPLICIT_IV_LEN; 551 size_t plen = 0; 552 unsigned char *tag = NULL; 553 554 if (!ossl_prov_is_running() || !ctx->key_set) 555 goto err; 556 557 /* Encrypt/decrypt must be performed in place */ 558 if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN)) 559 goto err; 560 561 /* 562 * Check for too many keys as per FIPS 140-2 IG A.5 "Key/IV Pair Uniqueness 563 * Requirements from SP 800-38D". The requirements is for one party to the 564 * communication to fail after 2^64 - 1 keys. We do this on the encrypting 565 * side only. 566 */ 567 if (ctx->enc && ++ctx->tls_enc_records == 0) { 568 ERR_raise(ERR_LIB_PROV, PROV_R_TOO_MANY_RECORDS); 569 goto err; 570 } 571 572 /* 573 * Set IV from start of buffer or generate IV and write to start of 574 * buffer. 575 */ 576 if (ctx->enc) { 577 if (!getivgen(ctx, out, arg)) 578 goto err; 579 } else { 580 if (!setivinv(ctx, out, arg)) 581 goto err; 582 } 583 584 /* Fix buffer and length to point to payload */ 585 in += EVP_GCM_TLS_EXPLICIT_IV_LEN; 586 out += EVP_GCM_TLS_EXPLICIT_IV_LEN; 587 len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN; 588 589 tag = ctx->enc ? out + len : (unsigned char *)in + len; 590 if (!ctx->hw->oneshot(ctx, ctx->buf, ctx->tls_aad_len, in, len, out, tag, 591 EVP_GCM_TLS_TAG_LEN)) { 592 if (!ctx->enc) 593 OPENSSL_cleanse(out, len); 594 goto err; 595 } 596 if (ctx->enc) 597 plen = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN; 598 else 599 plen = len; 600 601 rv = 1; 602err: 603 ctx->iv_state = IV_STATE_FINISHED; 604 ctx->tls_aad_len = UNINITIALISED_SIZET; 605 *padlen = plen; 606 return rv; 607} 608