summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libssl/s3_lib.c6
-rw-r--r--src/lib/libssl/ssl_locl.h5
-rw-r--r--src/lib/libssl/ssl_tlsext.c308
-rw-r--r--src/lib/libssl/ssl_tlsext.h10
4 files changed, 307 insertions, 22 deletions
diff --git a/src/lib/libssl/s3_lib.c b/src/lib/libssl/s3_lib.c
index 36142f0415..6e4e8eb1d3 100644
--- a/src/lib/libssl/s3_lib.c
+++ b/src/lib/libssl/s3_lib.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: s3_lib.c,v 1.181 2019/01/24 01:50:41 beck Exp $ */ 1/* $OpenBSD: s3_lib.c,v 1.182 2019/01/24 02:56:41 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -1569,6 +1569,7 @@ ssl3_free(SSL *s)
1569 freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH); 1569 freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH);
1570 freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH); 1570 freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH);
1571 freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH); 1571 freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH);
1572 freezero(S3I(s)->hs_tls13.cookie, S3I(s)->hs_tls13.cookie_len);
1572 1573
1573 sk_X509_NAME_pop_free(S3I(s)->tmp.ca_names, X509_NAME_free); 1574 sk_X509_NAME_pop_free(S3I(s)->tmp.ca_names, X509_NAME_free);
1574 1575
@@ -1605,6 +1606,9 @@ ssl3_clear(SSL *s)
1605 freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH); 1606 freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH);
1606 freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH); 1607 freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH);
1607 freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH); 1608 freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH);
1609 freezero(S3I(s)->hs_tls13.cookie, S3I(s)->hs_tls13.cookie_len);
1610 S3I(s)->hs_tls13.cookie = NULL;
1611 S3I(s)->hs_tls13.cookie_len = 0;
1608 1612
1609 S3I(s)->hs.extensions_seen = 0; 1613 S3I(s)->hs.extensions_seen = 0;
1610 1614
diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h
index 5d560f5935..90aca26625 100644
--- a/src/lib/libssl/ssl_locl.h
+++ b/src/lib/libssl/ssl_locl.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_locl.h,v 1.232 2019/01/24 01:50:41 beck Exp $ */ 1/* $OpenBSD: ssl_locl.h,v 1.233 2019/01/24 02:56:41 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -448,6 +448,9 @@ typedef struct ssl_handshake_tls13_st {
448 uint8_t *x25519_peer_public; 448 uint8_t *x25519_peer_public;
449 449
450 struct tls13_secrets *secrets; 450 struct tls13_secrets *secrets;
451
452 uint8_t *cookie;
453 size_t cookie_len;
451} SSL_HANDSHAKE_TLS13; 454} SSL_HANDSHAKE_TLS13;
452 455
453typedef struct ssl_ctx_internal_st { 456typedef struct ssl_ctx_internal_st {
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c
index 35c764f646..20acb43ccf 100644
--- a/src/lib/libssl/ssl_tlsext.c
+++ b/src/lib/libssl/ssl_tlsext.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_tlsext.c,v 1.35 2019/01/24 01:50:41 beck Exp $ */ 1/* $OpenBSD: ssl_tlsext.c,v 1.36 2019/01/24 02:56:41 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -1273,7 +1273,7 @@ tlsext_keyshare_client_build(SSL *s, CBB *cbb)
1273 1273
1274 return 1; 1274 return 1;
1275 1275
1276err: 1276 err:
1277 freezero(public_key, X25519_KEY_LENGTH); 1277 freezero(public_key, X25519_KEY_LENGTH);
1278 freezero(private_key, X25519_KEY_LENGTH); 1278 freezero(private_key, X25519_KEY_LENGTH);
1279 1279
@@ -1283,24 +1283,105 @@ err:
1283int 1283int
1284tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert) 1284tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert)
1285{ 1285{
1286 /* XXX we accept this but currently ignore it */ 1286 CBS client_shares;
1287 if (!CBS_skip(cbs, CBS_len(cbs))) { 1287 CBS key_exchange;
1288 *alert = TLS1_AD_INTERNAL_ERROR; 1288 uint16_t group;
1289 return 0; 1289 size_t out_len;
1290 int ret = 0;
1291
1292 if (!CBS_get_u16_length_prefixed(cbs, &client_shares))
1293 goto err;
1294
1295 if (CBS_len(cbs) != 0)
1296 goto err;
1297
1298 while (CBS_len(&client_shares) > 0) {
1299
1300 /* Unpack client share. */
1301 if (!CBS_get_u16(&client_shares, &group))
1302 goto err;
1303
1304 if (!CBS_get_u16_length_prefixed(&client_shares, &key_exchange))
1305 goto err;
1306
1307 /*
1308 * Skip this client share if not X25519
1309 * XXX support other groups later.
1310 * XXX enforce group can only appear once.
1311 */
1312 if (S3I(s)->hs_tls13.x25519_peer_public != NULL ||
1313 group != tls1_ec_nid2curve_id(NID_X25519))
1314 continue;
1315
1316 if (CBS_len(&key_exchange) != X25519_KEY_LENGTH)
1317 goto err;
1318
1319 if (!CBS_stow(&key_exchange, &S3I(s)->hs_tls13.x25519_peer_public,
1320 &out_len))
1321 goto err;
1322
1323 ret = 1;
1290 } 1324 }
1291 1325
1292 return 1; 1326 return ret;
1327
1328 err:
1329 *alert = SSL_AD_DECODE_ERROR;
1330 return 0;
1293} 1331}
1294 1332
1295int 1333int
1296tlsext_keyshare_server_needs(SSL *s) 1334tlsext_keyshare_server_needs(SSL *s)
1297{ 1335{
1298 return (!SSL_IS_DTLS(s) && s->version >= TLS1_3_VERSION); 1336 size_t idx;
1337
1338 if (SSL_IS_DTLS(s) || s->version < TLS1_3_VERSION)
1339 return 0;
1340 if (tls_extension_find(TLSEXT_TYPE_key_share, &idx) == NULL)
1341 return 0;
1342 /* XXX move seen check to a function */
1343 return ((S3I(s)->hs.extensions_seen & (1 << idx)) != 0);
1299} 1344}
1300 1345
1301int 1346int
1302tlsext_keyshare_server_build(SSL *s, CBB *cbb) 1347tlsext_keyshare_server_build(SSL *s, CBB *cbb)
1303{ 1348{
1349 uint8_t *public_key = NULL, *private_key = NULL;
1350 CBB key_exchange;
1351
1352 /* XXX deduplicate with client code */
1353
1354 /* X25519 */
1355 if (S3I(s)->hs_tls13.x25519_peer_public == NULL)
1356 return 0;
1357
1358 /* Generate X25519 key pair. */
1359 if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL)
1360 goto err;
1361 if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL)
1362 goto err;
1363 X25519_keypair(public_key, private_key);
1364
1365 /* Add the group and serialize the public key. */
1366 if (!CBB_add_u16(cbb, tls1_ec_nid2curve_id(NID_X25519)))
1367 goto err;
1368 if (!CBB_add_u16_length_prefixed(cbb, &key_exchange))
1369 goto err;
1370 if (!CBB_add_bytes(&key_exchange, public_key, X25519_KEY_LENGTH))
1371 goto err;
1372
1373 if (!CBB_flush(cbb))
1374 goto err;
1375
1376 S3I(s)->hs_tls13.x25519_public = public_key;
1377 S3I(s)->hs_tls13.x25519_private = private_key;
1378
1379 return 1;
1380
1381 err:
1382 freezero(public_key, X25519_KEY_LENGTH);
1383 freezero(private_key, X25519_KEY_LENGTH);
1384
1304 return 0; 1385 return 0;
1305} 1386}
1306 1387
@@ -1321,8 +1402,10 @@ tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert)
1321 1402
1322 if (!CBS_get_u16_length_prefixed(cbs, &key_exchange)) 1403 if (!CBS_get_u16_length_prefixed(cbs, &key_exchange))
1323 goto err; 1404 goto err;
1405
1324 if (CBS_len(&key_exchange) != X25519_KEY_LENGTH) 1406 if (CBS_len(&key_exchange) != X25519_KEY_LENGTH)
1325 goto err; 1407 goto err;
1408
1326 if (!CBS_stow(&key_exchange, &S3I(s)->hs_tls13.x25519_peer_public, 1409 if (!CBS_stow(&key_exchange, &S3I(s)->hs_tls13.x25519_peer_public,
1327 &out_len)) 1410 &out_len))
1328 goto err; 1411 goto err;
@@ -1340,11 +1423,9 @@ tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert)
1340int 1423int
1341tlsext_versions_client_needs(SSL *s) 1424tlsext_versions_client_needs(SSL *s)
1342{ 1425{
1343 /* XXX once this gets initialized when we get tls13_client.c */ 1426 if (SSL_IS_DTLS(s))
1344 if (S3I(s)->hs_tls13.max_version == 0)
1345 return 0; 1427 return 0;
1346 return (!SSL_IS_DTLS(s) && S3I(s)->hs_tls13.max_version >= 1428 return (S3I(s)->hs_tls13.max_version >= TLS1_3_VERSION);
1347 TLS1_3_VERSION);
1348} 1429}
1349 1430
1350int 1431int
@@ -1378,13 +1459,48 @@ tlsext_versions_client_build(SSL *s, CBB *cbb)
1378int 1459int
1379tlsext_versions_server_parse(SSL *s, CBS *cbs, int *alert) 1460tlsext_versions_server_parse(SSL *s, CBS *cbs, int *alert)
1380{ 1461{
1381 /* XXX we accept this but currently ignore it */ 1462 CBS versions;
1382 if (!CBS_skip(cbs, CBS_len(cbs))) { 1463 uint16_t version;
1383 *alert = TLS1_AD_INTERNAL_ERROR; 1464 uint16_t max, min;
1384 return 0; 1465 uint16_t matched_version = 0;
1466
1467 max = S3I(s)->hs_tls13.max_version;
1468 min = S3I(s)->hs_tls13.min_version;
1469
1470 if (!CBS_get_u8_length_prefixed(cbs, &versions))
1471 goto err;
1472
1473 while (CBS_len(&versions) > 0) {
1474 if (!CBS_get_u16(&versions, &version))
1475 goto err;
1476 /*
1477 * XXX What is below implements client preference, and
1478 * ignores any server preference entirely.
1479 */
1480 if (matched_version == 0 && version >= min && version <= max)
1481 matched_version = version;
1385 } 1482 }
1386 1483
1387 return 1; 1484 /*
1485 * XXX if we haven't mached a version we should
1486 * fail - but we currently need to succeed to
1487 * ignore this before the server code for 1.3
1488 * is set up and initialized.
1489 */
1490 if (max == 0)
1491 return 1; /* XXX */
1492
1493 if (matched_version != 0) {
1494 s->version = matched_version;
1495 return 1;
1496 }
1497
1498 *alert = SSL_AD_PROTOCOL_VERSION;
1499 return 0;
1500
1501err:
1502 *alert = SSL_AD_DECODE_ERROR;
1503 return 0;
1388} 1504}
1389 1505
1390int 1506int
@@ -1396,7 +1512,11 @@ tlsext_versions_server_needs(SSL *s)
1396int 1512int
1397tlsext_versions_server_build(SSL *s, CBB *cbb) 1513tlsext_versions_server_build(SSL *s, CBB *cbb)
1398{ 1514{
1399 return 0; 1515 if (!CBB_add_u16(cbb, TLS1_3_VERSION))
1516 return 0;
1517 /* XXX set 1.2 in legacy version? */
1518
1519 return 1;
1400} 1520}
1401 1521
1402int 1522int
@@ -1409,12 +1529,147 @@ tlsext_versions_client_parse(SSL *s, CBS *cbs, int *alert)
1409 return 0; 1529 return 0;
1410 } 1530 }
1411 1531
1532 if (selected_version < TLS1_3_VERSION) {
1533 *alert = SSL_AD_ILLEGAL_PARAMETER;
1534 return 0;
1535 }
1536
1412 /* XXX test between min and max once initialization code goes in */ 1537 /* XXX test between min and max once initialization code goes in */
1413 S3I(s)->hs_tls13.server_version = selected_version; 1538 S3I(s)->hs_tls13.server_version = selected_version;
1414 1539
1415 return 1; 1540 return 1;
1416} 1541}
1417 1542
1543
1544/*
1545 * Cookie - RFC 8446 section 4.2.2.
1546 */
1547
1548int
1549tlsext_cookie_client_needs(SSL *s)
1550{
1551 if (SSL_IS_DTLS(s))
1552 return 0;
1553 if (S3I(s)->hs_tls13.max_version < TLS1_3_VERSION)
1554 return 0;
1555 return (S3I(s)->hs_tls13.cookie_len > 0 &&
1556 S3I(s)->hs_tls13.cookie != NULL);
1557}
1558
1559int
1560tlsext_cookie_client_build(SSL *s, CBB *cbb)
1561{
1562 CBB cookie;
1563
1564 if (!CBB_add_u16_length_prefixed(cbb, &cookie))
1565 return 0;
1566
1567 if (!CBB_add_bytes(&cookie, S3I(s)->hs_tls13.cookie,
1568 S3I(s)->hs_tls13.cookie_len))
1569 return 0;
1570
1571 if (!CBB_flush(cbb))
1572 return 0;
1573
1574 return 1;
1575}
1576
1577int
1578tlsext_cookie_server_parse(SSL *s, CBS *cbs, int *alert)
1579{
1580 CBS cookie;
1581
1582 if (!CBS_get_u16_length_prefixed(cbs, &cookie))
1583 goto err;
1584
1585 if (CBS_len(&cookie) != S3I(s)->hs_tls13.cookie_len)
1586 goto err;
1587
1588 /*
1589 * Check provided cookie value against what server previously
1590 * sent - client *MUST* send the same cookie with new CR after
1591 * a cookie is sent by the server with an HRR.
1592 */
1593 if (!CBS_mem_equal(&cookie, S3I(s)->hs_tls13.cookie,
1594 S3I(s)->hs_tls13.cookie_len)) {
1595 /* XXX special cookie mismatch alert? */
1596 *alert = SSL_AD_ILLEGAL_PARAMETER;
1597 return 0;
1598 }
1599
1600 return 1;
1601
1602 err:
1603 *alert = SSL_AD_DECODE_ERROR;
1604 return 0;
1605}
1606
1607int
1608tlsext_cookie_server_needs(SSL *s)
1609{
1610
1611 if (SSL_IS_DTLS(s))
1612 return 0;
1613 if (S3I(s)->hs_tls13.max_version < TLS1_3_VERSION)
1614 return 0;
1615 /*
1616 * Server needs to set cookie value in tls13 handshake
1617 * in order to send one, should only be sent with HRR.
1618 */
1619 return (S3I(s)->hs_tls13.cookie_len > 0 &&
1620 S3I(s)->hs_tls13.cookie != NULL);
1621}
1622
1623int
1624tlsext_cookie_server_build(SSL *s, CBB *cbb)
1625{
1626 CBB cookie;
1627
1628 /* XXX deduplicate with client code */
1629
1630 if (!CBB_add_u16_length_prefixed(cbb, &cookie))
1631 return 0;
1632
1633 if (!CBB_add_bytes(&cookie, S3I(s)->hs_tls13.cookie,
1634 S3I(s)->hs_tls13.cookie_len))
1635 return 0;
1636
1637 if (!CBB_flush(cbb))
1638 return 0;
1639
1640 return 1;
1641}
1642
1643int
1644tlsext_cookie_client_parse(SSL *s, CBS *cbs, int *alert)
1645{
1646 CBS cookie;
1647
1648 /*
1649 * XXX This currently assumes we will not get a second
1650 * HRR from a server with a cookie to process after accepting
1651 * one from the server in the same handshake
1652 */
1653 if (S3I(s)->hs_tls13.cookie != NULL ||
1654 S3I(s)->hs_tls13.cookie_len != 0) {
1655 *alert = SSL_AD_ILLEGAL_PARAMETER;
1656 return 0;
1657 }
1658
1659 if (!CBS_get_u16_length_prefixed(cbs, &cookie))
1660 goto err;
1661
1662 if (!CBS_stow(&cookie, &S3I(s)->hs_tls13.cookie,
1663 &S3I(s)->hs_tls13.cookie_len))
1664 goto err;
1665
1666 return 1;
1667
1668 err:
1669 *alert = SSL_AD_DECODE_ERROR;
1670 return 0;
1671}
1672
1418struct tls_extension_funcs { 1673struct tls_extension_funcs {
1419 int (*needs)(SSL *s); 1674 int (*needs)(SSL *s);
1420 int (*build)(SSL *s, CBB *cbb); 1675 int (*build)(SSL *s, CBB *cbb);
@@ -1572,6 +1827,20 @@ static struct tls_extension tls_extensions[] = {
1572 .parse = tlsext_alpn_client_parse, 1827 .parse = tlsext_alpn_client_parse,
1573 }, 1828 },
1574 }, 1829 },
1830 {
1831 .type = TLSEXT_TYPE_cookie,
1832 .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_HRR,
1833 .client = {
1834 .needs = tlsext_cookie_client_needs,
1835 .build = tlsext_cookie_client_build,
1836 .parse = tlsext_cookie_server_parse,
1837 },
1838 .server = {
1839 .needs = tlsext_cookie_server_needs,
1840 .build = tlsext_cookie_server_build,
1841 .parse = tlsext_cookie_client_parse,
1842 },
1843 },
1575#ifndef OPENSSL_NO_SRTP 1844#ifndef OPENSSL_NO_SRTP
1576 { 1845 {
1577 .type = TLSEXT_TYPE_use_srtp, 1846 .type = TLSEXT_TYPE_use_srtp,
@@ -1595,7 +1864,7 @@ static struct tls_extension tls_extensions[] = {
1595/* Ensure that extensions fit in a uint32_t bitmask. */ 1864/* Ensure that extensions fit in a uint32_t bitmask. */
1596CTASSERT(N_TLS_EXTENSIONS <= (sizeof(uint32_t) * 8)); 1865CTASSERT(N_TLS_EXTENSIONS <= (sizeof(uint32_t) * 8));
1597 1866
1598static struct tls_extension * 1867struct tls_extension *
1599tls_extension_find(uint16_t type, size_t *tls_extensions_idx) 1868tls_extension_find(uint16_t type, size_t *tls_extensions_idx)
1600{ 1869{
1601 size_t i; 1870 size_t i;
@@ -1719,6 +1988,7 @@ tlsext_parse(SSL *s, CBS *cbs, int *alert, int is_server, uint16_t msg_type)
1719 } 1988 }
1720 1989
1721 /* Check for duplicate known extensions. */ 1990 /* Check for duplicate known extensions. */
1991 /* XXX move seen check to a function */
1722 if ((S3I(s)->hs.extensions_seen & (1 << idx)) != 0) 1992 if ((S3I(s)->hs.extensions_seen & (1 << idx)) != 0)
1723 return 0; 1993 return 0;
1724 S3I(s)->hs.extensions_seen |= (1 << idx); 1994 S3I(s)->hs.extensions_seen |= (1 << idx);
diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h
index e82be579d0..2f90a03ee9 100644
--- a/src/lib/libssl/ssl_tlsext.h
+++ b/src/lib/libssl/ssl_tlsext.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_tlsext.h,v 1.19 2019/01/23 18:24:40 beck Exp $ */ 1/* $OpenBSD: ssl_tlsext.h,v 1.20 2019/01/24 02:56:41 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -101,6 +101,13 @@ int tlsext_keyshare_server_needs(SSL *s);
101int tlsext_keyshare_server_build(SSL *s, CBB *cbb); 101int tlsext_keyshare_server_build(SSL *s, CBB *cbb);
102int tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert); 102int tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert);
103 103
104int tlsext_cookie_client_needs(SSL *s);
105int tlsext_cookie_client_build(SSL *s, CBB *cbb);
106int tlsext_cookie_client_parse(SSL *s, CBS *cbs, int *alert);
107int tlsext_cookie_server_needs(SSL *s);
108int tlsext_cookie_server_build(SSL *s, CBB *cbb);
109int tlsext_cookie_server_parse(SSL *s, CBS *cbs, int *alert);
110
104#ifndef OPENSSL_NO_SRTP 111#ifndef OPENSSL_NO_SRTP
105int tlsext_srtp_client_needs(SSL *s); 112int tlsext_srtp_client_needs(SSL *s);
106int tlsext_srtp_client_build(SSL *s, CBB *cbb); 113int tlsext_srtp_client_build(SSL *s, CBB *cbb);
@@ -116,6 +123,7 @@ int tlsext_client_parse(SSL *s, CBS *cbs, int *alert, uint16_t msg_type);
116int tlsext_server_build(SSL *s, CBB *cbb, uint16_t msg_type); 123int tlsext_server_build(SSL *s, CBB *cbb, uint16_t msg_type);
117int tlsext_server_parse(SSL *s, CBS *cbs, int *alert, uint16_t msg_type); 124int tlsext_server_parse(SSL *s, CBS *cbs, int *alert, uint16_t msg_type);
118 125
126struct tls_extension *tls_extension_find(uint16_t, size_t *);
119__END_HIDDEN_DECLS 127__END_HIDDEN_DECLS
120 128
121#endif 129#endif