diff options
| author | jsing <> | 2020-09-13 16:51:30 +0000 | 
|---|---|---|
| committer | jsing <> | 2020-09-13 16:51:30 +0000 | 
| commit | 7e6ac45008128aea17a084b0274f94a64f355826 (patch) | |
| tree | 1fcd9e694ce4ea1723e996013066608d8288c25f /src | |
| parent | 0aa52b54c9a57f9625af2c4445b991cfdd4ad228 (diff) | |
| download | openbsd-7e6ac45008128aea17a084b0274f94a64f355826.tar.gz openbsd-7e6ac45008128aea17a084b0274f94a64f355826.tar.bz2 openbsd-7e6ac45008128aea17a084b0274f94a64f355826.zip | |
Add regress for SSL_{CTX_,}set_ciphersuites().
Diffstat (limited to 'src')
| -rw-r--r-- | src/regress/lib/libssl/ciphers/Makefile | 4 | ||||
| -rw-r--r-- | src/regress/lib/libssl/ciphers/cipherstest.c | 321 | 
2 files changed, 318 insertions, 7 deletions
| diff --git a/src/regress/lib/libssl/ciphers/Makefile b/src/regress/lib/libssl/ciphers/Makefile index c9a58a5e09..2575db4df4 100644 --- a/src/regress/lib/libssl/ciphers/Makefile +++ b/src/regress/lib/libssl/ciphers/Makefile | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | # $OpenBSD: Makefile,v 1.1 2015/02/06 08:48:39 jsing Exp $ | 1 | # $OpenBSD: Makefile,v 1.2 2020/09/13 16:51:30 jsing Exp $ | 
| 2 | 2 | ||
| 3 | PROG= cipherstest | 3 | PROG= cipherstest | 
| 4 | LDADD= -lssl -lcrypto | 4 | LDADD= ${SSL_INT} -lcrypto | 
| 5 | DPADD= ${LIBSSL} ${LIBCRYPTO} | 5 | DPADD= ${LIBSSL} ${LIBCRYPTO} | 
| 6 | WARNINGS= Yes | 6 | WARNINGS= Yes | 
| 7 | CFLAGS+= -DLIBRESSL_INTERNAL -Werror | 7 | CFLAGS+= -DLIBRESSL_INTERNAL -Werror | 
| diff --git a/src/regress/lib/libssl/ciphers/cipherstest.c b/src/regress/lib/libssl/ciphers/cipherstest.c index d76fbfc8c0..34ac96e48c 100644 --- a/src/regress/lib/libssl/ciphers/cipherstest.c +++ b/src/regress/lib/libssl/ciphers/cipherstest.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* | 
| 2 | * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> | 2 | * Copyright (c) 2015, 2020 Joel Sing <jsing@openbsd.org> | 
| 3 | * | 3 | * | 
| 4 | * Permission to use, copy, modify, and distribute this software for any | 4 | * Permission to use, copy, modify, and distribute this software for any | 
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above | 
| @@ -20,6 +20,8 @@ | |||
| 20 | #include <stdio.h> | 20 | #include <stdio.h> | 
| 21 | #include <string.h> | 21 | #include <string.h> | 
| 22 | 22 | ||
| 23 | int ssl_parse_ciphersuites(STACK_OF(SSL_CIPHER) **out_ciphers, const char *str); | ||
| 24 | |||
| 23 | static int | 25 | static int | 
| 24 | get_put_test(const char *name, const SSL_METHOD *method) | 26 | get_put_test(const char *name, const SSL_METHOD *method) | 
| 25 | { | 27 | { | 
| @@ -71,7 +73,7 @@ get_put_test(const char *name, const SSL_METHOD *method) | |||
| 71 | 73 | ||
| 72 | ret = 0; | 74 | ret = 0; | 
| 73 | 75 | ||
| 74 | failure: | 76 | failure: | 
| 75 | SSL_CTX_free(ssl_ctx); | 77 | SSL_CTX_free(ssl_ctx); | 
| 76 | SSL_free(ssl); | 78 | SSL_free(ssl); | 
| 77 | 79 | ||
| @@ -154,22 +156,331 @@ cipher_get_by_value_tests(void) | |||
| 154 | 156 | ||
| 155 | ret = 0; | 157 | ret = 0; | 
| 156 | 158 | ||
| 157 | failure: | 159 | failure: | 
| 158 | SSL_CTX_free(ssl_ctx); | 160 | SSL_CTX_free(ssl_ctx); | 
| 159 | SSL_free(ssl); | 161 | SSL_free(ssl); | 
| 160 | 162 | ||
| 161 | return (ret); | 163 | return (ret); | 
| 162 | } | 164 | } | 
| 163 | 165 | ||
| 166 | struct parse_ciphersuites_test { | ||
| 167 | const char *str; | ||
| 168 | const int want; | ||
| 169 | const unsigned long cids[32]; | ||
| 170 | }; | ||
| 171 | |||
| 172 | struct parse_ciphersuites_test parse_ciphersuites_tests[] = { | ||
| 173 | { | ||
| 174 | /* LibreSSL names. */ | ||
| 175 | .str = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256:AEAD-AES128-GCM-SHA256", | ||
| 176 | .want = 1, | ||
| 177 | .cids = { | ||
| 178 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 179 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 180 | TLS1_3_CK_AES_128_GCM_SHA256, | ||
| 181 | }, | ||
| 182 | }, | ||
| 183 | { | ||
| 184 | /* OpenSSL names. */ | ||
| 185 | .str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256", | ||
| 186 | .want = 1, | ||
| 187 | .cids = { | ||
| 188 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 189 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 190 | TLS1_3_CK_AES_128_GCM_SHA256, | ||
| 191 | }, | ||
| 192 | }, | ||
| 193 | { | ||
| 194 | /* Different priority order. */ | ||
| 195 | .str = "AEAD-AES128-GCM-SHA256:AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 196 | .want = 1, | ||
| 197 | .cids = { | ||
| 198 | TLS1_3_CK_AES_128_GCM_SHA256, | ||
| 199 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 200 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 201 | }, | ||
| 202 | }, | ||
| 203 | { | ||
| 204 | /* Known but unsupported names. */ | ||
| 205 | .str = "AEAD-AES256-GCM-SHA384:AEAD-AES128-CCM-SHA256:AEAD-AES128-CCM-8-SHA256", | ||
| 206 | .want = 1, | ||
| 207 | .cids = { | ||
| 208 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 209 | }, | ||
| 210 | }, | ||
| 211 | { | ||
| 212 | /* Empty string means no TLSv1.3 ciphersuites. */ | ||
| 213 | .str = "", | ||
| 214 | .want = 1, | ||
| 215 | .cids = { 0 }, | ||
| 216 | }, | ||
| 217 | { | ||
| 218 | .str = "TLS_CHACHA20_POLY1305_SHA256:TLS_NOT_A_CIPHERSUITE", | ||
| 219 | .want = 0, | ||
| 220 | }, | ||
| 221 | { | ||
| 222 | .str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256", | ||
| 223 | .want = 0, | ||
| 224 | }, | ||
| 225 | }; | ||
| 226 | |||
| 227 | #define N_PARSE_CIPHERSUITES_TESTS \ | ||
| 228 | (sizeof(parse_ciphersuites_tests) / sizeof(*parse_ciphersuites_tests)) | ||
| 229 | |||
| 230 | static int | ||
| 231 | parse_ciphersuites_test() | ||
| 232 | { | ||
| 233 | struct parse_ciphersuites_test *pct; | ||
| 234 | STACK_OF(SSL_CIPHER) *ciphers = NULL; | ||
| 235 | SSL_CIPHER *cipher; | ||
| 236 | int failed = 1; | ||
| 237 | int j, ret; | ||
| 238 | size_t i; | ||
| 239 | |||
| 240 | for (i = 0; i < N_PARSE_CIPHERSUITES_TESTS; i++) { | ||
| 241 | pct = &parse_ciphersuites_tests[i]; | ||
| 242 | |||
| 243 | ret = ssl_parse_ciphersuites(&ciphers, pct->str); | ||
| 244 | if (ret != pct->want) { | ||
| 245 | fprintf(stderr, "FAIL: test %zu - " | ||
| 246 | "ssl_parse_ciphersuites returned %d, want %d\n", | ||
| 247 | i, ret, pct->want); | ||
| 248 | goto failed; | ||
| 249 | } | ||
| 250 | if (ret == 0) | ||
| 251 | continue; | ||
| 252 | |||
| 253 | for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) { | ||
| 254 | cipher = sk_SSL_CIPHER_value(ciphers, j); | ||
| 255 | if (SSL_CIPHER_get_id(cipher) == pct->cids[j]) | ||
| 256 | continue; | ||
| 257 | fprintf(stderr, "FAIL: test %zu - got cipher %d with " | ||
| 258 | "id %lx, want %lx\n", i, j, | ||
| 259 | SSL_CIPHER_get_id(cipher), pct->cids[j]); | ||
| 260 | goto failed; | ||
| 261 | } | ||
| 262 | if (pct->cids[j] != 0) { | ||
| 263 | fprintf(stderr, "FAIL: test %zu - got %d ciphers, " | ||
| 264 | "expected more", i, sk_SSL_CIPHER_num(ciphers)); | ||
| 265 | goto failed; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | failed = 0; | ||
| 270 | |||
| 271 | failed: | ||
| 272 | sk_SSL_CIPHER_free(ciphers); | ||
| 273 | |||
| 274 | return failed; | ||
| 275 | } | ||
| 276 | |||
| 277 | struct cipher_set_test { | ||
| 278 | int ctx_ciphersuites_first; | ||
| 279 | const char *ctx_ciphersuites; | ||
| 280 | const char *ctx_rulestr; | ||
| 281 | int ssl_ciphersuites_first; | ||
| 282 | const char *ssl_ciphersuites; | ||
| 283 | const char *ssl_rulestr; | ||
| 284 | const unsigned long cids[32]; | ||
| 285 | }; | ||
| 286 | |||
| 287 | struct cipher_set_test cipher_set_tests[] = { | ||
| 288 | { | ||
| 289 | .ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 290 | .cids = { | ||
| 291 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 292 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 293 | TLS1_3_CK_AES_128_GCM_SHA256, | ||
| 294 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 295 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 296 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 297 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 298 | }, | ||
| 299 | }, | ||
| 300 | { | ||
| 301 | .ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 302 | .cids = { | ||
| 303 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 304 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 305 | TLS1_3_CK_AES_128_GCM_SHA256, | ||
| 306 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 307 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 308 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 309 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 310 | }, | ||
| 311 | }, | ||
| 312 | { | ||
| 313 | .ctx_ciphersuites_first = 1, | ||
| 314 | .ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 315 | .ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 316 | .cids = { | ||
| 317 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 318 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 319 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 320 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 321 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 322 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 323 | }, | ||
| 324 | }, | ||
| 325 | { | ||
| 326 | .ssl_ciphersuites_first = 1, | ||
| 327 | .ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 328 | .ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 329 | .cids = { | ||
| 330 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 331 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 332 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 333 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 334 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 335 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 336 | }, | ||
| 337 | }, | ||
| 338 | { | ||
| 339 | .ctx_ciphersuites_first = 0, | ||
| 340 | .ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 341 | .ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 342 | .cids = { | ||
| 343 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 344 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 345 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 346 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 347 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 348 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 349 | }, | ||
| 350 | }, | ||
| 351 | { | ||
| 352 | .ssl_ciphersuites_first = 0, | ||
| 353 | .ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 354 | .ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 355 | .cids = { | ||
| 356 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 357 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 358 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 359 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 360 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 361 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 362 | }, | ||
| 363 | }, | ||
| 364 | { | ||
| 365 | .ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 366 | .ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 367 | .cids = { | ||
| 368 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 369 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 370 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 371 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 372 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 373 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 374 | }, | ||
| 375 | }, | ||
| 376 | { | ||
| 377 | .ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES", | ||
| 378 | .ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256", | ||
| 379 | .cids = { | ||
| 380 | TLS1_3_CK_AES_256_GCM_SHA384, | ||
| 381 | TLS1_3_CK_CHACHA20_POLY1305_SHA256, | ||
| 382 | TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
| 383 | TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
| 384 | TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
| 385 | TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
| 386 | }, | ||
| 387 | }, | ||
| 388 | }; | ||
| 389 | |||
| 390 | #define N_CIPHER_SET_TESTS \ | ||
| 391 | (sizeof(cipher_set_tests) / sizeof(*cipher_set_tests)) | ||
| 392 | |||
| 393 | static int | ||
| 394 | cipher_set_test() | ||
| 395 | { | ||
| 396 | struct cipher_set_test *cst; | ||
| 397 | STACK_OF(SSL_CIPHER) *ciphers = NULL; | ||
| 398 | SSL_CIPHER *cipher; | ||
| 399 | SSL_CTX *ctx = NULL; | ||
| 400 | SSL *ssl = NULL; | ||
| 401 | int failed = 1; | ||
| 402 | size_t i; | ||
| 403 | int j; | ||
| 404 | |||
| 405 | for (i = 0; i < N_CIPHER_SET_TESTS; i++) { | ||
| 406 | cst = &cipher_set_tests[i]; | ||
| 407 | |||
| 408 | if ((ctx = SSL_CTX_new(TLS_method())) == NULL) | ||
| 409 | errx(1, "SSL_CTX_new"); | ||
| 410 | |||
| 411 | if (cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) { | ||
| 412 | if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites)) | ||
| 413 | errx(1, "SSL_CTX_set_ciphersuites"); | ||
| 414 | } | ||
| 415 | if (cst->ctx_rulestr != NULL) { | ||
| 416 | if (!SSL_CTX_set_cipher_list(ctx, cst->ctx_rulestr)) | ||
| 417 | errx(1, "SSL_CTX_set_cipher_list"); | ||
| 418 | } | ||
| 419 | if (!cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) { | ||
| 420 | if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites)) | ||
| 421 | errx(1, "SSL_CTX_set_ciphersuites"); | ||
| 422 | } | ||
| 423 | |||
| 424 | /* XXX - check SSL_CTX_get_ciphers(ctx) */ | ||
| 425 | |||
| 426 | if ((ssl = SSL_new(ctx)) == NULL) | ||
| 427 | errx(1, "SSL_new"); | ||
| 428 | |||
| 429 | if (cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) { | ||
| 430 | if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites)) | ||
| 431 | errx(1, "SSL_set_ciphersuites"); | ||
| 432 | } | ||
| 433 | if (cst->ssl_rulestr != NULL) { | ||
| 434 | if (!SSL_set_cipher_list(ssl, cst->ssl_rulestr)) | ||
| 435 | errx(1, "SSL_set_cipher_list"); | ||
| 436 | } | ||
| 437 | if (!cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) { | ||
| 438 | if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites)) | ||
| 439 | errx(1, "SSL_set_ciphersuites"); | ||
| 440 | } | ||
| 441 | |||
| 442 | ciphers = SSL_get_ciphers(ssl); | ||
| 443 | |||
| 444 | for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) { | ||
| 445 | cipher = sk_SSL_CIPHER_value(ciphers, j); | ||
| 446 | if (SSL_CIPHER_get_id(cipher) == cst->cids[j]) | ||
| 447 | continue; | ||
| 448 | fprintf(stderr, "FAIL: test %zu - got cipher %d with " | ||
| 449 | "id %lx, want %lx\n", i, j, | ||
| 450 | SSL_CIPHER_get_id(cipher), cst->cids[j]); | ||
| 451 | goto failed; | ||
| 452 | } | ||
| 453 | if (cst->cids[j] != 0) { | ||
| 454 | fprintf(stderr, "FAIL: test %zu - got %d ciphers, " | ||
| 455 | "expected more", i, sk_SSL_CIPHER_num(ciphers)); | ||
| 456 | goto failed; | ||
| 457 | } | ||
| 458 | |||
| 459 | SSL_CTX_free(ctx); | ||
| 460 | ctx = NULL; | ||
| 461 | SSL_free(ssl); | ||
| 462 | ssl = NULL; | ||
| 463 | } | ||
| 464 | |||
| 465 | failed = 0; | ||
| 466 | |||
| 467 | failed: | ||
| 468 | SSL_CTX_free(ctx); | ||
| 469 | SSL_free(ssl); | ||
| 470 | |||
| 471 | return failed; | ||
| 472 | } | ||
| 473 | |||
| 164 | int | 474 | int | 
| 165 | main(int argc, char **argv) | 475 | main(int argc, char **argv) | 
| 166 | { | 476 | { | 
| 167 | int failed = 0; | 477 | int failed = 0; | 
| 168 | 478 | ||
| 169 | SSL_library_init(); | ||
| 170 | |||
| 171 | failed |= cipher_get_put_tests(); | 479 | failed |= cipher_get_put_tests(); | 
| 172 | failed |= cipher_get_by_value_tests(); | 480 | failed |= cipher_get_by_value_tests(); | 
| 173 | 481 | ||
| 482 | failed |= parse_ciphersuites_test(); | ||
| 483 | failed |= cipher_set_test(); | ||
| 484 | |||
| 174 | return (failed); | 485 | return (failed); | 
| 175 | } | 486 | } | 
