Coverage Report

Created: 2025-07-01 06:48

/src/libssh/src/dh_crypto.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This file is part of the SSH Library
3
 *
4
 * Copyright (c) 2019 by Simo Sorce - Red Hat, Inc.
5
 *
6
 * The SSH Library is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or (at your
9
 * option) any later version.
10
 *
11
 * The SSH Library is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with the SSH Library; see the file COPYING.  If not, write to
18
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19
 * MA 02111-1307, USA.
20
 */
21
22
#include "config.h"
23
#include "libssh/session.h"
24
#include "libssh/dh.h"
25
#include "libssh/buffer.h"
26
#include "libssh/ssh2.h"
27
#include "libssh/pki.h"
28
#include "libssh/bignum.h"
29
30
#include "openssl/crypto.h"
31
#include "openssl/dh.h"
32
#include "libcrypto-compat.h"
33
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
34
#include <openssl/evp.h>
35
#include <openssl/params.h>
36
#include <openssl/core_names.h>
37
#include <openssl/param_build.h>
38
#include <openssl/err.h>
39
#endif /* OPENSSL_VERSION_NUMBER */
40
41
extern bignum ssh_dh_generator;
42
extern bignum ssh_dh_group1;
43
extern bignum ssh_dh_group14;
44
extern bignum ssh_dh_group16;
45
extern bignum ssh_dh_group18;
46
47
struct dh_ctx {
48
#if OPENSSL_VERSION_NUMBER < 0x30000000L
49
    DH *keypair[2];
50
#else
51
    EVP_PKEY *keypair[2];
52
#endif /* OPENSSL_VERSION_NUMBER */
53
};
54
55
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
56
0
{
57
#ifdef DEBUG_CRYPTO
58
#if OPENSSL_VERSION_NUMBER < 0x30000000L
59
    const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
60
#else
61
    bignum x = NULL, y = NULL, e = NULL, f = NULL;
62
#endif /* OPENSSL_VERSION_NUMBER */
63
64
    ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
65
    ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
66
    ssh_print_bignum("x", x);
67
    ssh_print_bignum("y", y);
68
    ssh_print_bignum("e", e);
69
    ssh_print_bignum("f", f);
70
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
71
    bignum_safe_free(x);
72
    bignum_safe_free(y);
73
    bignum_safe_free(e);
74
    bignum_safe_free(f);
75
#endif /* OPENSSL_VERSION_NUMBER */
76
77
    ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
78
    ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
79
    ssh_print_bignum("k", c->shared_secret);
80
81
#else
82
0
    (void)c; /* UNUSED_PARAM */
83
0
#endif /* DEBUG_CRYPTO */
84
0
}
85
86
#if OPENSSL_VERSION_NUMBER < 0x30000000L
87
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
88
                            const_bignum *priv, const_bignum *pub)
89
0
{
90
0
    if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
91
0
        ((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
92
0
        (ctx->keypair[peer] == NULL)) {
93
0
        return SSH_ERROR;
94
0
    }
95
96
0
    DH_get0_key(ctx->keypair[peer], pub, priv);
97
98
0
    if (priv && (*priv == NULL || bignum_num_bits(*priv) == 0)) {
99
0
        return SSH_ERROR;
100
0
    }
101
0
    if (pub && (*pub == NULL || bignum_num_bits(*pub) == 0)) {
102
0
        return SSH_ERROR;
103
0
    }
104
105
0
    return SSH_OK;
106
0
}
107
108
#else
109
/* If set *priv and *pub should be initialized
110
 * to NULL before calling this function*/
111
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
112
                            bignum *priv, bignum *pub)
113
{
114
    int rc;
115
    if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
116
        ((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
117
        (ctx->keypair[peer] == NULL)) {
118
        return SSH_ERROR;
119
    }
120
121
    if (priv) {
122
        rc = EVP_PKEY_get_bn_param(ctx->keypair[peer],
123
                                   OSSL_PKEY_PARAM_PRIV_KEY,
124
                                   priv);
125
        if (rc != 1) {
126
            return SSH_ERROR;
127
        }
128
    }
129
    if (pub) {
130
        rc = EVP_PKEY_get_bn_param(ctx->keypair[peer],
131
                                   OSSL_PKEY_PARAM_PUB_KEY,
132
                                   pub);
133
        if (rc != 1) {
134
            return SSH_ERROR;
135
        }
136
    }
137
    if (priv && (*priv == NULL || bignum_num_bits(*priv) == 0)) {
138
        if (pub && (*pub != NULL && bignum_num_bits(*pub) != 0)) {
139
            bignum_safe_free(*pub);
140
            *pub = NULL;
141
        }
142
        return SSH_ERROR;
143
    }
144
    if (pub && (*pub == NULL || bignum_num_bits(*pub) == 0)) {
145
        if (priv) {
146
            bignum_safe_free(*priv);
147
            *priv = NULL;
148
        }
149
        return SSH_ERROR;
150
    }
151
152
    return SSH_OK;
153
}
154
#endif /* OPENSSL_VERSION_NUMBER */
155
156
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
157
                            bignum priv, bignum pub)
158
0
{
159
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
160
    int rc;
161
    OSSL_PARAM *params = NULL, *out_params = NULL, *merged_params = NULL;
162
    OSSL_PARAM_BLD *param_bld = NULL;
163
    EVP_PKEY_CTX *evp_ctx = NULL;
164
#endif /* OPENSSL_VERSION_NUMBER */
165
166
0
    if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
167
0
        ((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
168
0
        (ctx->keypair[peer] == NULL)) {
169
0
        return SSH_ERROR;
170
0
    }
171
172
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
173
0
    (void)DH_set0_key(ctx->keypair[peer], pub, priv);
174
175
0
    return SSH_OK;
176
#else
177
    rc = EVP_PKEY_todata(ctx->keypair[peer], EVP_PKEY_KEYPAIR, &out_params);
178
    if (rc != 1) {
179
        return SSH_ERROR;
180
    }
181
182
    param_bld = OSSL_PARAM_BLD_new();
183
    if (param_bld == NULL) {
184
        rc = SSH_ERROR;
185
        goto out;
186
    }
187
188
    evp_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, ctx->keypair[peer], NULL);
189
    if (evp_ctx == NULL) {
190
        rc = SSH_ERROR;
191
        goto out;
192
    }
193
194
    rc = EVP_PKEY_fromdata_init(evp_ctx);
195
    if (rc != 1) {
196
        rc = SSH_ERROR;
197
        goto out;
198
    }
199
200
    if (priv) {
201
        rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, priv);
202
        if (rc != 1) {
203
            rc = SSH_ERROR;
204
            goto out;
205
        }
206
    }
207
    if (pub) {
208
        rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PUB_KEY, pub);
209
        if (rc != 1) {
210
            rc = SSH_ERROR;
211
            goto out;
212
        }
213
    }
214
215
    params = OSSL_PARAM_BLD_to_param(param_bld);
216
    if (params == NULL) {
217
        rc = SSH_ERROR;
218
        goto out;
219
    }
220
    OSSL_PARAM_BLD_free(param_bld);
221
222
    merged_params = OSSL_PARAM_merge(out_params, params);
223
    if (merged_params == NULL) {
224
        rc = SSH_ERROR;
225
        goto out;
226
    }
227
228
    rc = EVP_PKEY_fromdata(evp_ctx,
229
                           &(ctx->keypair[peer]),
230
                           EVP_PKEY_PUBLIC_KEY,
231
                           merged_params);
232
    if (rc != 1) {
233
        rc = SSH_ERROR;
234
        goto out;
235
    }
236
237
    rc = SSH_OK;
238
out:
239
    bignum_safe_free(priv);
240
    bignum_safe_free(pub);
241
    EVP_PKEY_CTX_free(evp_ctx);
242
    OSSL_PARAM_free(out_params);
243
    OSSL_PARAM_free(params);
244
    OSSL_PARAM_free(merged_params);
245
246
    return rc;
247
#endif /* OPENSSL_VERSION_NUMBER */
248
0
}
249
250
#if OPENSSL_VERSION_NUMBER < 0x30000000L
251
int ssh_dh_get_parameters(struct dh_ctx *ctx,
252
                          const_bignum *modulus, const_bignum *generator)
253
0
{
254
0
    if (ctx == NULL || ctx->keypair[0] == NULL) {
255
0
        return SSH_ERROR;
256
0
    }
257
0
    DH_get0_pqg(ctx->keypair[0], modulus, NULL, generator);
258
0
    return SSH_OK;
259
0
}
260
#else
261
int ssh_dh_get_parameters(struct dh_ctx *ctx,
262
                          bignum *modulus, bignum *generator)
263
{
264
    int rc;
265
266
    if (ctx == NULL || ctx->keypair[0] == NULL) {
267
        return SSH_ERROR;
268
    }
269
270
    rc = EVP_PKEY_get_bn_param(ctx->keypair[0], OSSL_PKEY_PARAM_FFC_P, (BIGNUM**)modulus);
271
    if (rc != 1) {
272
        return SSH_ERROR;
273
    }
274
    rc = EVP_PKEY_get_bn_param(ctx->keypair[0], OSSL_PKEY_PARAM_FFC_G, (BIGNUM**)generator);
275
    if (rc != 1) {
276
        bignum_safe_free(*modulus);
277
        return SSH_ERROR;
278
    }
279
280
    return SSH_OK;
281
}
282
#endif /* OPENSSL_VERSION_NUMBER */
283
284
int ssh_dh_set_parameters(struct dh_ctx *ctx,
285
                          const bignum modulus, const bignum generator)
286
0
{
287
0
    size_t i;
288
0
    int rc;
289
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
290
    OSSL_PARAM *params = NULL;
291
    OSSL_PARAM_BLD *param_bld = NULL;
292
    EVP_PKEY_CTX *evp_ctx = NULL;
293
#endif /* OPENSSL_VERSION_NUMBER */
294
295
0
    if ((ctx == NULL) || (modulus == NULL) || (generator == NULL)) {
296
0
        return SSH_ERROR;
297
0
    }
298
299
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
300
    evp_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL);
301
#endif
302
303
0
    for (i = 0; i < 2; i++) {
304
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
305
0
        bignum p = NULL;
306
0
        bignum g = NULL;
307
308
        /* when setting modulus or generator,
309
         * make sure to invalidate existing keys */
310
0
        DH_free(ctx->keypair[i]);
311
0
        ctx->keypair[i] = DH_new();
312
0
        if (ctx->keypair[i] == NULL) {
313
0
            rc = SSH_ERROR;
314
0
            goto done;
315
0
        }
316
317
0
        p = BN_dup(modulus);
318
0
        g = BN_dup(generator);
319
0
        rc = DH_set0_pqg(ctx->keypair[i], p, NULL, g);
320
0
        if (rc != 1) {
321
0
            BN_free(p);
322
0
            BN_free(g);
323
0
            rc = SSH_ERROR;
324
0
            goto done;
325
0
        }
326
#else
327
        param_bld = OSSL_PARAM_BLD_new();
328
329
        if (param_bld == NULL) {
330
            rc = SSH_ERROR;
331
            goto done;
332
        }
333
334
        rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, modulus);
335
        if (rc != 1) {
336
            rc = SSH_ERROR;
337
            goto done;
338
        }
339
        rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, generator);
340
        if (rc != 1) {
341
            rc = SSH_ERROR;
342
            goto done;
343
        }
344
        params = OSSL_PARAM_BLD_to_param(param_bld);
345
        if (params == NULL) {
346
            OSSL_PARAM_BLD_free(param_bld);
347
            rc = SSH_ERROR;
348
            goto done;
349
        }
350
        OSSL_PARAM_BLD_free(param_bld);
351
352
        rc = EVP_PKEY_fromdata_init(evp_ctx);
353
        if (rc != 1) {
354
            OSSL_PARAM_free(params);
355
            rc = SSH_ERROR;
356
            goto done;
357
        }
358
359
        /* make sure to invalidate existing keys */
360
        EVP_PKEY_free(ctx->keypair[i]);
361
        ctx->keypair[i] = NULL;
362
363
        rc = EVP_PKEY_fromdata(evp_ctx,
364
                               &(ctx->keypair[i]),
365
                               EVP_PKEY_KEY_PARAMETERS,
366
                               params);
367
        if (rc != 1) {
368
            OSSL_PARAM_free(params);
369
            rc = SSH_ERROR;
370
            goto done;
371
        }
372
373
        OSSL_PARAM_free(params);
374
#endif /* OPENSSL_VERSION_NUMBER */
375
0
    }
376
377
0
    rc = SSH_OK;
378
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
379
0
done:
380
0
    if (rc != SSH_OK) {
381
0
        DH_free(ctx->keypair[0]);
382
0
        DH_free(ctx->keypair[1]);
383
0
    }
384
#else
385
done:
386
    EVP_PKEY_CTX_free(evp_ctx);
387
388
    if (rc != SSH_OK) {
389
        EVP_PKEY_free(ctx->keypair[0]);
390
        EVP_PKEY_free(ctx->keypair[1]);
391
    }
392
#endif /* OPENSSL_VERSION_NUMBER */
393
0
    if (rc != SSH_OK) {
394
0
        ctx->keypair[0] = NULL;
395
0
        ctx->keypair[1] = NULL;
396
0
    }
397
398
0
    return rc;
399
0
}
400
401
/**
402
 * @internal
403
 * @brief allocate and initialize ephemeral values used in dh kex
404
 */
405
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
406
0
{
407
0
    struct dh_ctx *ctx = NULL;
408
0
    int rc;
409
410
0
    ctx = calloc(1, sizeof(*ctx));
411
0
    if (ctx == NULL) {
412
0
        return SSH_ERROR;
413
0
    }
414
0
    crypto->dh_ctx = ctx;
415
416
0
    switch (crypto->kex_type) {
417
0
    case SSH_KEX_DH_GROUP1_SHA1:
418
0
        rc = ssh_dh_set_parameters(ctx, ssh_dh_group1, ssh_dh_generator);
419
0
        break;
420
0
    case SSH_KEX_DH_GROUP14_SHA1:
421
0
    case SSH_KEX_DH_GROUP14_SHA256:
422
0
        rc = ssh_dh_set_parameters(ctx, ssh_dh_group14, ssh_dh_generator);
423
0
        break;
424
0
    case SSH_KEX_DH_GROUP16_SHA512:
425
0
        rc = ssh_dh_set_parameters(ctx, ssh_dh_group16, ssh_dh_generator);
426
0
        break;
427
0
    case SSH_KEX_DH_GROUP18_SHA512:
428
0
        rc = ssh_dh_set_parameters(ctx, ssh_dh_group18, ssh_dh_generator);
429
0
        break;
430
0
    default:
431
0
        rc = SSH_OK;
432
0
        break;
433
0
    }
434
435
0
    if (rc != SSH_OK) {
436
0
        ssh_dh_cleanup(crypto);
437
0
    }
438
0
    return rc;
439
0
}
440
441
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
442
0
{
443
0
    if (crypto->dh_ctx != NULL) {
444
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
445
0
        DH_free(crypto->dh_ctx->keypair[0]);
446
0
        DH_free(crypto->dh_ctx->keypair[1]);
447
#else
448
        EVP_PKEY_free(crypto->dh_ctx->keypair[0]);
449
        EVP_PKEY_free(crypto->dh_ctx->keypair[1]);
450
#endif /* OPENSSL_VERSION_NUMBER */
451
0
        free(crypto->dh_ctx);
452
0
        crypto->dh_ctx = NULL;
453
0
    }
454
0
}
455
456
/** @internal
457
 * @brief generates a secret DH parameter of at least DH_SECURITY_BITS
458
 *        security as well as the corresponding public key.
459
 *
460
 * @param[out] params a dh_ctx that will hold the new keys.
461
 * @param peer Select either client or server key storage. Valid values are:
462
 *        DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR
463
 *
464
 * @return SSH_OK on success, SSH_ERROR on error
465
 */
466
int ssh_dh_keypair_gen_keys(struct dh_ctx *dh_ctx, int peer)
467
0
{
468
0
    int rc;
469
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
470
    EVP_PKEY_CTX *evp_ctx = NULL;
471
#endif
472
473
0
    if ((dh_ctx == NULL) || (dh_ctx->keypair[peer] == NULL)) {
474
0
        return SSH_ERROR;
475
0
    }
476
477
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
478
0
    rc = DH_generate_key(dh_ctx->keypair[peer]);
479
0
    if (rc != 1) {
480
0
        return SSH_ERROR;
481
0
    }
482
#else
483
    evp_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, dh_ctx->keypair[peer], NULL);
484
    if (evp_ctx == NULL) {
485
        return SSH_ERROR;
486
    }
487
488
    rc = EVP_PKEY_keygen_init(evp_ctx);
489
    if (rc != 1) {
490
        EVP_PKEY_CTX_free(evp_ctx);
491
        return SSH_ERROR;
492
    }
493
494
    rc = EVP_PKEY_generate(evp_ctx, &(dh_ctx->keypair[peer]));
495
    if (rc != 1) {
496
        EVP_PKEY_CTX_free(evp_ctx);
497
        SSH_LOG(SSH_LOG_TRACE,
498
                "Failed to generate DH: %s",
499
                ERR_error_string(ERR_get_error(), NULL));
500
        return SSH_ERROR;
501
    }
502
503
    EVP_PKEY_CTX_free(evp_ctx);
504
#endif /* OPENSSL_VERSION_NUMBER */
505
506
0
    return SSH_OK;
507
0
}
508
509
/** @internal
510
 * @brief generates a shared secret between the local peer and the remote
511
 *        peer. The local peer must have been initialized using either the
512
 *        ssh_dh_keypair_gen_keys() function or by seetting manually both
513
 *        the private and public keys. The remote peer only needs to have
514
 *        the remote's peer public key set.
515
 * @param[in] local peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
516
 * @param[in] remote peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
517
 * @param[out] dest a new bignum with the shared secret value is returned.
518
 * @return SSH_OK on success, SSH_ERROR on error
519
 */
520
int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
521
                                 bignum *dest)
522
0
{
523
0
    unsigned char *kstring = NULL;
524
0
    int rc;
525
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
526
0
    const_bignum pub_key = NULL;
527
0
    int klen;
528
#else
529
    size_t klen;
530
    EVP_PKEY_CTX *evp_ctx = NULL;
531
#endif /* OPENSSL_VERSION_NUMBER */
532
533
0
    if ((dh_ctx == NULL) ||
534
0
        (dh_ctx->keypair[local] == NULL) ||
535
0
        (dh_ctx->keypair[remote] == NULL)) {
536
0
        return SSH_ERROR;
537
0
    }
538
539
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
540
0
    kstring = malloc(DH_size(dh_ctx->keypair[local]));
541
0
    if (kstring == NULL) {
542
0
        rc = SSH_ERROR;
543
0
        goto done;
544
0
    }
545
546
0
    rc = ssh_dh_keypair_get_keys(dh_ctx, remote, NULL, &pub_key);
547
0
    if (rc != SSH_OK) {
548
0
        rc = SSH_ERROR;
549
0
        goto done;
550
0
    }
551
552
0
    klen = DH_compute_key(kstring, pub_key, dh_ctx->keypair[local]);
553
0
    if (klen == -1) {
554
0
        rc = SSH_ERROR;
555
0
        goto done;
556
0
    }
557
#else
558
    evp_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, dh_ctx->keypair[local], NULL);
559
560
    rc = EVP_PKEY_derive_init(evp_ctx);
561
    if (rc != 1) {
562
        rc = SSH_ERROR;
563
        goto done;
564
    }
565
566
    rc = EVP_PKEY_derive_set_peer(evp_ctx, dh_ctx->keypair[remote]);
567
    if (rc != 1) {
568
        SSH_LOG(SSH_LOG_TRACE,
569
                "Failed to set peer key: %s",
570
                ERR_error_string(ERR_get_error(), NULL));
571
        rc = SSH_ERROR;
572
        goto done;
573
    }
574
575
    /* getting the size of the secret */
576
    rc = EVP_PKEY_derive(evp_ctx, kstring, &klen);
577
    if (rc != 1) {
578
        rc = SSH_ERROR;
579
        goto done;
580
    }
581
582
    kstring = malloc(klen);
583
    if (kstring == NULL) {
584
        rc = SSH_ERROR;
585
        goto done;
586
    }
587
588
    rc = EVP_PKEY_derive(evp_ctx, kstring, &klen);
589
    if (rc != 1) {
590
        rc = SSH_ERROR;
591
        goto done;
592
    }
593
#endif /* OPENSSL_VERSION_NUMBER */
594
595
0
    *dest = BN_bin2bn(kstring, (int)klen, NULL);
596
0
    if (*dest == NULL) {
597
0
        rc = SSH_ERROR;
598
0
        goto done;
599
0
    }
600
601
0
    rc = SSH_OK;
602
0
done:
603
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
604
    EVP_PKEY_CTX_free(evp_ctx);
605
#endif
606
0
    free(kstring);
607
0
    return rc;
608
0
}