#include <systemd/sd-daemon.h>
#endif
-#include <isc/aes.h>
#include <isc/async.h>
#include <isc/attributes.h>
#include <isc/base64.h>
INSIST(result == ISC_R_SUCCESS);
if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
server->sctx->cookiealg = ns_cookiealg_siphash24;
- } else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
- server->sctx->cookiealg = ns_cookiealg_aes;
} else {
UNREACHABLE();
}
goto cleanup_altsecrets;
}
break;
- case ns_cookiealg_aes:
- expectedlength = ISC_AES128_KEYLENGTH;
- if (usedlength != expectedlength) {
- result = ISC_R_RANGE;
- isc_log_write(
- named_g_lctx,
- NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER,
- ISC_LOG_ERROR,
- "AES cookie-secret must be 128 "
- "bits: %s",
- isc_result_totext(result));
- goto cleanup_altsecrets;
- }
- break;
}
}
} else {
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-options {
- cookie-algorithm aes;
- cookie-secret "ebc7701beabb4a40c57d140eeb6733faaa"; // 136 bits
-};
AC_CHECK_FUNCS([EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512], [:],
[AC_MSG_FAILURE([SHA-2 support in OpenSSL is mandatory.])])
-#
-# Check for OpenSSL AES support
-#
-AC_CHECK_FUNCS([EVP_aes_128_ecb EVP_aes_192_ecb EVP_aes_256_ecb], [:],
- [AC_MSG_FAILURE([AES support in OpenSSL is mandatory.])])
-
#
# Check for OpenSSL 1.1.x/LibreSSL functions
#
:tags: server
:short: Sets the algorithm to be used when generating a server cookie.
- This sets the algorithm to be used when generating the server cookie; the options are
- "aes" or "siphash24". The default is "siphash24". The "aes" option remains for legacy
- purposes.
+ This sets the algorithm to be used when generating the server cookie. The
+ default is "siphash24", which is the only supported option, as the
+ previously supported "aes" option has been removed.
.. namedconf:statement:: cookie-secret
:tags: server
If set, this is a shared secret used for generating and verifying
EDNS COOKIE options within an anycast cluster. If not set, the system
generates a random secret at startup. The shared secret is
- encoded as a hex string and needs to be 128 bits for either "siphash24"
- or "aes".
+ encoded as a hex string and needs to be 128 bits.
If there are multiple secrets specified, the first one listed in
:iscman:`named.conf` is used to generate new server cookies. The others
check-svcb <boolean>;
check-wildcard <boolean>;
clients-per-query <integer>;
- cookie-algorithm ( aes | siphash24 );
+ cookie-algorithm ( siphash24 );
cookie-secret <string>; // may occur multiple times
deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
libisc_ladir = $(includedir)/isc
libisc_la_HEADERS = \
- include/isc/aes.h \
include/isc/align.h \
include/isc/ascii.h \
include/isc/assertions.h \
netmgr/timer.c \
netmgr/tlsstream.c \
netmgr/udp.c \
- aes.c \
ascii.c \
assertions.c \
async.c \
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*! \file isc/aes.c */
-
-#include <openssl/evp.h>
-#include <openssl/opensslv.h>
-
-#include <isc/aes.h>
-#include <isc/assertions.h>
-#include <isc/string.h>
-#include <isc/types.h>
-#include <isc/util.h>
-
-void
-isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out) {
- EVP_CIPHER_CTX *c;
- int len;
-
- c = EVP_CIPHER_CTX_new();
- RUNTIME_CHECK(c != NULL);
- RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_128_ecb(), key, NULL) == 1);
- EVP_CIPHER_CTX_set_padding(c, 0);
- RUNTIME_CHECK(
- EVP_EncryptUpdate(c, out, &len, in, ISC_AES_BLOCK_LENGTH) == 1);
- RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
- EVP_CIPHER_CTX_free(c);
-}
-
-void
-isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out) {
- EVP_CIPHER_CTX *c;
- int len;
-
- c = EVP_CIPHER_CTX_new();
- RUNTIME_CHECK(c != NULL);
- RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_192_ecb(), key, NULL) == 1);
- EVP_CIPHER_CTX_set_padding(c, 0);
- RUNTIME_CHECK(
- EVP_EncryptUpdate(c, out, &len, in, ISC_AES_BLOCK_LENGTH) == 1);
- RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
- EVP_CIPHER_CTX_free(c);
-}
-
-void
-isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out) {
- EVP_CIPHER_CTX *c;
- int len;
-
- c = EVP_CIPHER_CTX_new();
- RUNTIME_CHECK(c != NULL);
- RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_256_ecb(), key, NULL) == 1);
- EVP_CIPHER_CTX_set_padding(c, 0);
- RUNTIME_CHECK(
- EVP_EncryptUpdate(c, out, &len, in, ISC_AES_BLOCK_LENGTH) == 1);
- RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
- EVP_CIPHER_CTX_free(c);
-}
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*! \file isc/aes.h */
-
-#pragma once
-
-#include <isc/lang.h>
-#include <isc/types.h>
-
-#define ISC_AES128_KEYLENGTH 16U
-#define ISC_AES192_KEYLENGTH 24U
-#define ISC_AES256_KEYLENGTH 32U
-#define ISC_AES_BLOCK_LENGTH 16U
-
-ISC_LANG_BEGINDECLS
-
-void
-isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out);
-
-void
-isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out);
-
-void
-isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
- unsigned char *out);
-
-ISC_LANG_ENDDECLS
#include <fstrm.h>
#endif
-#include <isc/aes.h>
#include <isc/base64.h>
#include <isc/buffer.h>
#include <isc/dir.h>
ccalg = cfg_obj_asstring(obj);
if (strcasecmp(ccalg, "aes") == 0) {
cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
- "cookie-algorithm 'aes' is deprecated");
+ "cookie-algorithm 'aes' is obsolete and "
+ "should be removed");
+ if (result == ISC_R_SUCCESS) {
+ result = ISC_R_FAILURE;
+ }
}
}
}
usedlength = isc_buffer_usedlength(&b);
- if (strcasecmp(ccalg, "aes") == 0 &&
- usedlength != ISC_AES128_KEYLENGTH)
- {
- cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
- "AES cookie-secret must be 128 "
- "bits");
- if (result == ISC_R_SUCCESS) {
- result = ISC_R_RANGE;
- }
- }
if (strcasecmp(ccalg, "siphash24") == 0 &&
usedlength != ISC_SIPHASH24_KEY_LENGTH)
{
&cfg_rep_list,
&cfg_type_portrange };
-static const char *cookiealg_enums[] = { "aes", "siphash24", NULL };
+static const char *cookiealg_enums[] = { "siphash24", NULL };
static cfg_type_t cfg_type_cookiealg = { "cookiealg", cfg_parse_enum,
cfg_print_ustring, cfg_doc_enum,
&cfg_rep_string, &cookiealg_enums };
#include <limits.h>
#include <stdbool.h>
-#include <isc/aes.h>
#include <isc/async.h>
#include <isc/atomic.h>
#include <isc/formatcheck.h>
#include <isc/hmac.h>
#include <isc/log.h>
#include <isc/mutex.h>
-#include <isc/nonce.h>
#include <isc/once.h>
#include <isc/random.h>
#include <isc/safe.h>
static void
ns_client_dumpmessage(ns_client_t *client, const char *reason);
static void
-compute_cookie(ns_client_t *client, uint32_t when, uint32_t nonce,
- const unsigned char *secret, isc_buffer_t *buf);
+compute_cookie(ns_client_t *client, uint32_t when, const unsigned char *secret,
+ isc_buffer_t *buf);
void
ns_client_recursing(ns_client_t *client) {
if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0) {
isc_buffer_t buf;
isc_stdtime_t now = isc_stdtime_now();
- uint32_t nonce;
isc_buffer_init(&buf, cookie, sizeof(cookie));
- isc_random_buf(&nonce, sizeof(nonce));
-
- compute_cookie(client, now, nonce,
- client->manager->sctx->secret, &buf);
+ compute_cookie(client, now, client->manager->sctx->secret,
+ &buf);
INSIST(count < DNS_EDNSOPTIONS);
ednsopts[count].code = DNS_OPT_COOKIE;
}
static void
-compute_cookie(ns_client_t *client, uint32_t when, uint32_t nonce,
- const unsigned char *secret, isc_buffer_t *buf) {
+compute_cookie(ns_client_t *client, uint32_t when, const unsigned char *secret,
+ isc_buffer_t *buf) {
unsigned char digest[ISC_MAX_MD_SIZE] ISC_NONSTRING = { 0 };
STATIC_ASSERT(ISC_MAX_MD_SIZE >= ISC_SIPHASH24_TAG_LENGTH,
"You need to increase the digest buffer.");
- STATIC_ASSERT(ISC_MAX_MD_SIZE >= ISC_AES_BLOCK_LENGTH,
- "You need to increase the digest buffer.");
switch (client->manager->sctx->cookiealg) {
case ns_cookiealg_siphash24: {
isc_buffer_putmem(buf, digest, 8);
break;
}
- case ns_cookiealg_aes: {
- unsigned char input[4 + 4 + 16] ISC_NONSTRING = { 0 };
- isc_netaddr_t netaddr;
- unsigned char *cp;
- unsigned int i;
-
- isc_buffer_putmem(buf, client->cookie, 8);
- isc_buffer_putuint32(buf, nonce);
- isc_buffer_putuint32(buf, when);
- memmove(input, (unsigned char *)isc_buffer_used(buf) - 16, 16);
- isc_aes128_crypt(secret, input, digest);
- for (i = 0; i < 8; i++) {
- input[i] = digest[i] ^ digest[i + 8];
- }
- isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
- switch (netaddr.family) {
- case AF_INET:
- cp = (unsigned char *)&netaddr.type.in;
- memmove(input + 8, cp, 4);
- memset(input + 12, 0, 4);
- isc_aes128_crypt(secret, input, digest);
- break;
- case AF_INET6:
- cp = (unsigned char *)&netaddr.type.in6;
- memmove(input + 8, cp, 16);
- isc_aes128_crypt(secret, input, digest);
- for (i = 0; i < 8; i++) {
- input[i + 8] = digest[i] ^ digest[i + 8];
- }
- isc_aes128_crypt(client->manager->sctx->secret,
- input + 8, digest);
- break;
- default:
- UNREACHABLE();
- }
- for (i = 0; i < 8; i++) {
- digest[i] ^= digest[i + 8];
- }
- isc_buffer_putmem(buf, digest, 8);
- break;
- }
-
default:
UNREACHABLE();
}
unsigned char *old;
isc_stdtime_t now;
uint32_t when;
- uint32_t nonce;
isc_buffer_t db;
/*
old = isc_buffer_current(buf);
memmove(client->cookie, old, 8);
isc_buffer_forward(buf, 8);
- nonce = isc_buffer_getuint32(buf);
+ isc_buffer_forward(buf, 4); /* version + reserved */
when = isc_buffer_getuint32(buf);
isc_buffer_forward(buf, 8);
}
isc_buffer_init(&db, dbuf, sizeof(dbuf));
- compute_cookie(client, when, nonce, client->manager->sctx->secret, &db);
+ compute_cookie(client, when, client->manager->sctx->secret, &db);
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
ns_stats_increment(client->manager->sctx->nsstats,
altsecret != NULL; altsecret = ISC_LIST_NEXT(altsecret, link))
{
isc_buffer_init(&db, dbuf, sizeof(dbuf));
- compute_cookie(client, when, nonce, altsecret->secret, &db);
+ compute_cookie(client, when, altsecret->secret, &db);
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_cookiematch);
typedef struct ns_stats ns_stats_t;
typedef struct ns_hookasync ns_hookasync_t;
-typedef enum { ns_cookiealg_aes, ns_cookiealg_siphash24 } ns_cookiealg_t;
+typedef enum { ns_cookiealg_siphash24 } ns_cookiealg_t;
#define NS_COOKIE_VERSION_1 1
check_PROGRAMS = \
ascii_test \
- aes_test \
async_test \
buffer_test \
counter_test \
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-#include <inttypes.h>
-#include <sched.h> /* IWYU pragma: keep */
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define UNIT_TESTING
-#include <cmocka.h>
-
-#include <isc/aes.h>
-#include <isc/buffer.h>
-#include <isc/hex.h>
-#include <isc/region.h>
-#include <isc/string.h>
-#include <isc/util.h>
-
-#include <tests/isc.h>
-
-/*
- * Test data from NIST KAT
- */
-
-isc_result_t
-tohexstr(unsigned char *d, char *out);
-
-size_t
-fromhexstr(const char *in, unsigned char *d);
-
-unsigned char plaintext[3 * ISC_AES_BLOCK_LENGTH];
-unsigned char ciphertext[ISC_AES_BLOCK_LENGTH];
-char str[2 * ISC_AES_BLOCK_LENGTH + 1];
-unsigned char key[ISC_AES256_KEYLENGTH + 1];
-size_t len;
-
-isc_result_t
-tohexstr(unsigned char *d, char *out) {
- isc_buffer_t b;
- isc_region_t r;
-
- isc_buffer_init(&b, out, 2 * ISC_AES_BLOCK_LENGTH + 1);
- r.base = d;
- r.length = ISC_AES_BLOCK_LENGTH;
- return (isc_hex_totext(&r, 0, "", &b));
-}
-
-size_t
-fromhexstr(const char *in, unsigned char *d) {
- isc_buffer_t b;
- isc_result_t ret;
-
- isc_buffer_init(&b, d, ISC_AES256_KEYLENGTH + 1);
- ret = isc_hex_decodestring(in, &b);
- if (ret != ISC_R_SUCCESS) {
- return (0);
- }
- return (isc_buffer_usedlength(&b));
-}
-
-typedef struct aes_testcase {
- const char *key;
- const char *input;
- const char *result;
-} aes_testcase_t;
-
-/* AES 128 test vectors */
-ISC_RUN_TEST_IMPL(isc_aes128_test) {
- aes_testcase_t testcases[] = { /* Test 1 (KAT ECBVarTxt128 #3) */
- { "00000000000000000000000000000000",
- "F0000000000000000000000000000000",
- "96D9FD5CC4F07441727DF0F33E401A36" },
- /* Test 2 (KAT ECBVarTxt128 #123) */
- { "00000000000000000000000000000000",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "F9B0FDA0C4A898F5B9E6F661C4CE4D07" },
- /* Test 3 (KAT ECBVarKey128 #3) */
- { "F0000000000000000000000000000000",
- "00000000000000000000000000000000",
- "970014D634E2B7650777E8E84D03CCD8" },
- /* Test 4 (KAT ECBVarKey128 #123) */
- { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "00000000000000000000000000000000",
- "41C78C135ED9E98C096640647265DA1E" },
- /* Test 5 (KAT ECBGFSbox128 #3) */
- { "00000000000000000000000000000000",
- "6A118A874519E64E9963798A503F1D35",
- "DC43BE40BE0E53712F7E2BF5CA707209" },
- /* Test 6 (KAT ECBKeySbox128 #3) */
- { "B6364AC4E1DE1E285EAF144A2415F7A0",
- "00000000000000000000000000000000",
- "5D9B05578FC944B3CF1CCF0E746CD581" },
- { NULL, NULL, NULL }
- };
-
- aes_testcase_t *testcase = testcases;
-
- UNUSED(state);
-
- while (testcase->key != NULL) {
- len = fromhexstr(testcase->key, key);
- assert_int_equal(len, ISC_AES128_KEYLENGTH);
- len = fromhexstr(testcase->input, plaintext);
- assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
- isc_aes128_crypt(key, plaintext, ciphertext);
- assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
- assert_string_equal(str, testcase->result);
-
- testcase++;
- }
-}
-
-/* AES 192 test vectors */
-ISC_RUN_TEST_IMPL(isc_aes192_test) {
- aes_testcase_t testcases[] = {
- /* Test 1 (KAT ECBVarTxt192 #3) */
- { "000000000000000000000000000000000000000000000000",
- "F0000000000000000000000000000000",
- "2A560364CE529EFC21788779568D5555" },
- /* Test 2 (KAT ECBVarTxt192 #123) */
- { "000000000000000000000000000000000000000000000000",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "2AABB999F43693175AF65C6C612C46FB" },
- /* Test 3 (KAT ECBVarKey192 #3) */
- { "F00000000000000000000000000000000000000000000000",
- "00000000000000000000000000000000",
- "180B09F267C45145DB2F826C2582D35C" },
- /* Test 4 (KAT ECBVarKey192 #187) */
- { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "00000000000000000000000000000000",
- "EACF1E6C4224EFB38900B185AB1DFD42" },
- /* Test 5 (KAT ECBGFSbox192 #3) */
- { "000000000000000000000000000000000000000000000000",
- "51719783D3185A535BD75ADC65071CE1",
- "4F354592FF7C8847D2D0870CA9481B7C" },
- /* Test 6 (KAT ECBKeySbox192 #3) */
- { "CD62376D5EBB414917F0C78F05266433DC9192A1EC943300",
- "00000000000000000000000000000000",
- "7F6C25FF41858561BB62F36492E93C29" },
- { NULL, NULL, NULL }
- };
-
- aes_testcase_t *testcase = testcases;
-
- while (testcase->key != NULL) {
- len = fromhexstr(testcase->key, key);
- assert_int_equal(len, ISC_AES192_KEYLENGTH);
- len = fromhexstr(testcase->input, plaintext);
- assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
- isc_aes192_crypt(key, plaintext, ciphertext);
- assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
- assert_string_equal(str, testcase->result);
-
- testcase++;
- }
-}
-
-/* AES 256 test vectors */
-ISC_RUN_TEST_IMPL(isc_aes256_test) {
- aes_testcase_t testcases[] = { /* Test 1 (KAT ECBVarTxt256 #3) */
- { "00000000000000000000000000000000"
- "00000000000000000000000000000000",
- "F0000000000000000000000000000000",
- "7F2C5ECE07A98D8BEE13C51177395FF7" },
- /* Test 2 (KAT ECBVarTxt256 #123) */
- { "00000000000000000000000000000000"
- "00000000000000000000000000000000",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "7240E524BC51D8C4D440B1BE55D1062C" },
- /* Test 3 (KAT ECBVarKey256 #3) */
- { "F0000000000000000000000000000000"
- "00000000000000000000000000000000",
- "00000000000000000000000000000000",
- "1C777679D50037C79491A94DA76A9A35" },
- /* Test 4 (KAT ECBVarKey256 #251) */
- { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
- "00000000000000000000000000000000",
- "03720371A04962EAEA0A852E69972858" },
- /* Test 5 (KAT ECBGFSbox256 #3) */
- { "00000000000000000000000000000000"
- "00000000000000000000000000000000",
- "8A560769D605868AD80D819BDBA03771",
- "38F2C7AE10612415D27CA190D27DA8B4" },
- /* Test 6 (KAT ECBKeySbox256 #3) */
- { "984CA75F4EE8D706F46C2D98C0BF4A45"
- "F5B00D791C2DFEB191B5ED8E420FD627",
- "00000000000000000000000000000000",
- "4307456A9E67813B452E15FA8FFFE398" },
- { NULL, NULL, NULL }
- };
-
- aes_testcase_t *testcase = testcases;
-
- UNUSED(state);
-
- while (testcase->key != NULL) {
- len = fromhexstr(testcase->key, key);
- assert_int_equal(len, ISC_AES256_KEYLENGTH);
- len = fromhexstr(testcase->input, plaintext);
- assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
- isc_aes256_crypt(key, plaintext, ciphertext);
- assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
- assert_string_equal(str, testcase->result);
-
- testcase++;
- }
-}
-
-ISC_TEST_LIST_START
-
-ISC_TEST_ENTRY(isc_aes128_test)
-ISC_TEST_ENTRY(isc_aes192_test)
-ISC_TEST_ENTRY(isc_aes256_test)
-
-ISC_TEST_LIST_END
-
-ISC_TEST_MAIN