diff options
author | jsing <> | 2015-09-13 12:52:07 +0000 |
---|---|---|
committer | jsing <> | 2015-09-13 12:52:07 +0000 |
commit | 2063ab2c02bc341099214d42806f2b9156acfd41 (patch) | |
tree | f6ea2b92ad7e8b51381771f6255361b62689c691 /src/lib | |
parent | aabba0bcd2c9f46be67b8024dc2ff7cacb7dc930 (diff) | |
download | openbsd-2063ab2c02bc341099214d42806f2b9156acfd41.tar.gz openbsd-2063ab2c02bc341099214d42806f2b9156acfd41.tar.bz2 openbsd-2063ab2c02bc341099214d42806f2b9156acfd41.zip |
Stop generating private keys in a network buffer.
The current client key exchange code generates DH and ECDH keys into the
same buffer that we use to send data to the network - stop doing this and
malloc() a new buffer, which we explicit_bzero() and free() on return.
This also benefits from ASLR and means that the keys are no longer
generated in a well known location.
ok beck@
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libssl/s3_clnt.c | 58 | ||||
-rw-r--r-- | src/lib/libssl/src/ssl/s3_clnt.c | 58 |
2 files changed, 58 insertions, 58 deletions
diff --git a/src/lib/libssl/s3_clnt.c b/src/lib/libssl/s3_clnt.c index e33d745b19..52b9baadbf 100644 --- a/src/lib/libssl/s3_clnt.c +++ b/src/lib/libssl/s3_clnt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: s3_clnt.c,v 1.134 2015/09/13 12:39:16 jsing Exp $ */ | 1 | /* $OpenBSD: s3_clnt.c,v 1.135 2015/09/13 12:52:07 jsing 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 | * |
@@ -1908,8 +1908,9 @@ static int | |||
1908 | ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | 1908 | ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) |
1909 | { | 1909 | { |
1910 | DH *dh_srvr = NULL, *dh_clnt = NULL; | 1910 | DH *dh_srvr = NULL, *dh_clnt = NULL; |
1911 | unsigned char *key = NULL; | ||
1912 | int key_size, n; | ||
1911 | int ret = -1; | 1913 | int ret = -1; |
1912 | int n; | ||
1913 | 1914 | ||
1914 | /* Ensure that we have an ephemeral key for DHE. */ | 1915 | /* Ensure that we have an ephemeral key for DHE. */ |
1915 | if (sess_cert->peer_dh_tmp == NULL) { | 1916 | if (sess_cert->peer_dh_tmp == NULL) { |
@@ -1929,12 +1930,13 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1929 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); | 1930 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); |
1930 | goto err; | 1931 | goto err; |
1931 | } | 1932 | } |
1932 | 1933 | key_size = DH_size(dh_clnt); | |
1933 | /* | 1934 | if ((key = malloc(key_size)) == NULL) { |
1934 | * Use the 'p' output buffer for the DH key, but make sure to clear | 1935 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
1935 | * it out afterwards. | 1936 | ERR_R_MALLOC_FAILURE); |
1936 | */ | 1937 | goto err; |
1937 | n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt); | 1938 | } |
1939 | n = DH_compute_key(key, dh_srvr->pub_key, dh_clnt); | ||
1938 | if (n <= 0) { | 1940 | if (n <= 0) { |
1939 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); | 1941 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); |
1940 | goto err; | 1942 | goto err; |
@@ -1943,10 +1945,7 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1943 | /* Generate master key from the result. */ | 1945 | /* Generate master key from the result. */ |
1944 | s->session->master_key_length = | 1946 | s->session->master_key_length = |
1945 | s->method->ssl3_enc->generate_master_secret(s, | 1947 | s->method->ssl3_enc->generate_master_secret(s, |
1946 | s->session->master_key, p, n); | 1948 | s->session->master_key, key, n); |
1947 | |||
1948 | /* Clean up. */ | ||
1949 | explicit_bzero(p, n); | ||
1950 | 1949 | ||
1951 | /* Send off the data. */ | 1950 | /* Send off the data. */ |
1952 | n = BN_num_bytes(dh_clnt->pub_key); | 1951 | n = BN_num_bytes(dh_clnt->pub_key); |
@@ -1959,6 +1958,9 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1959 | 1958 | ||
1960 | err: | 1959 | err: |
1961 | DH_free(dh_clnt); | 1960 | DH_free(dh_clnt); |
1961 | if (key != NULL) | ||
1962 | explicit_bzero(key, key_size); | ||
1963 | free(key); | ||
1962 | 1964 | ||
1963 | return (ret); | 1965 | return (ret); |
1964 | } | 1966 | } |
@@ -1967,18 +1969,17 @@ static int | |||
1967 | ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | 1969 | ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, |
1968 | int *outlen) | 1970 | int *outlen) |
1969 | { | 1971 | { |
1970 | EC_KEY *clnt_ecdh = NULL; | 1972 | EC_KEY *tkey, *clnt_ecdh = NULL; |
1971 | const EC_GROUP *srvr_group = NULL; | 1973 | const EC_GROUP *srvr_group = NULL; |
1972 | const EC_POINT *srvr_ecpoint = NULL; | 1974 | const EC_POINT *srvr_ecpoint = NULL; |
1973 | EVP_PKEY *srvr_pub_pkey = NULL; | 1975 | EVP_PKEY *srvr_pub_pkey = NULL; |
1974 | BN_CTX *bn_ctx = NULL; | 1976 | BN_CTX *bn_ctx = NULL; |
1975 | unsigned char *encodedPoint = NULL; | 1977 | unsigned char *encodedPoint = NULL; |
1978 | unsigned char *key = NULL; | ||
1976 | unsigned long alg_k; | 1979 | unsigned long alg_k; |
1977 | int encoded_pt_len = 0; | 1980 | int encoded_pt_len = 0; |
1978 | int key_size; | 1981 | int key_size, n; |
1979 | EC_KEY *tkey; | ||
1980 | int ret = -1; | 1982 | int ret = -1; |
1981 | int n; | ||
1982 | 1983 | ||
1983 | alg_k = s->s3->tmp.new_cipher->algorithm_mkey; | 1984 | alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
1984 | 1985 | ||
@@ -2025,22 +2026,21 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2025 | goto err; | 2026 | goto err; |
2026 | } | 2027 | } |
2027 | 2028 | ||
2028 | /* Generate a new ECDH key pair */ | 2029 | /* Generate a new ECDH key pair. */ |
2029 | if (!(EC_KEY_generate_key(clnt_ecdh))) { | 2030 | if (!(EC_KEY_generate_key(clnt_ecdh))) { |
2030 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2031 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2031 | goto err; | 2032 | goto err; |
2032 | } | 2033 | } |
2033 | |||
2034 | /* | ||
2035 | * Use the 'p' output buffer for the ECDH key, but make sure to clear | ||
2036 | * it out afterwards. | ||
2037 | */ | ||
2038 | key_size = ECDH_size(clnt_ecdh); | 2034 | key_size = ECDH_size(clnt_ecdh); |
2039 | if (key_size <= 0) { | 2035 | if (key_size <= 0) { |
2040 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2036 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2041 | goto err; | 2037 | goto err; |
2042 | } | 2038 | } |
2043 | n = ECDH_compute_key(p, key_size, srvr_ecpoint, clnt_ecdh, NULL); | 2039 | if ((key = malloc(key_size)) == NULL) { |
2040 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, | ||
2041 | ERR_R_MALLOC_FAILURE); | ||
2042 | } | ||
2043 | n = ECDH_compute_key(key, key_size, srvr_ecpoint, clnt_ecdh, NULL); | ||
2044 | if (n <= 0) { | 2044 | if (n <= 0) { |
2045 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2045 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2046 | goto err; | 2046 | goto err; |
@@ -2049,10 +2049,7 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2049 | /* Generate master key from the result. */ | 2049 | /* Generate master key from the result. */ |
2050 | s->session->master_key_length = | 2050 | s->session->master_key_length = |
2051 | s->method->ssl3_enc->generate_master_secret(s, | 2051 | s->method->ssl3_enc->generate_master_secret(s, |
2052 | s->session->master_key, p, n); | 2052 | s->session->master_key, key, n); |
2053 | |||
2054 | /* Clean up. */ | ||
2055 | explicit_bzero(p, n); | ||
2056 | 2053 | ||
2057 | /* | 2054 | /* |
2058 | * First check the size of encoding and allocate memory accordingly. | 2055 | * First check the size of encoding and allocate memory accordingly. |
@@ -2087,7 +2084,10 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2087 | ret = 1; | 2084 | ret = 1; |
2088 | 2085 | ||
2089 | err: | 2086 | err: |
2090 | /* Free allocated memory */ | 2087 | if (key != NULL) |
2088 | explicit_bzero(key, key_size); | ||
2089 | free(key); | ||
2090 | |||
2091 | BN_CTX_free(bn_ctx); | 2091 | BN_CTX_free(bn_ctx); |
2092 | free(encodedPoint); | 2092 | free(encodedPoint); |
2093 | EC_KEY_free(clnt_ecdh); | 2093 | EC_KEY_free(clnt_ecdh); |
@@ -2219,7 +2219,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2219 | SESS_CERT *sess_cert; | 2219 | SESS_CERT *sess_cert; |
2220 | unsigned long alg_k; | 2220 | unsigned long alg_k; |
2221 | unsigned char *p; | 2221 | unsigned char *p; |
2222 | int n; | 2222 | int n = 0; |
2223 | 2223 | ||
2224 | if (s->state == SSL3_ST_CW_KEY_EXCH_A) { | 2224 | if (s->state == SSL3_ST_CW_KEY_EXCH_A) { |
2225 | p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); | 2225 | p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); |
diff --git a/src/lib/libssl/src/ssl/s3_clnt.c b/src/lib/libssl/src/ssl/s3_clnt.c index e33d745b19..52b9baadbf 100644 --- a/src/lib/libssl/src/ssl/s3_clnt.c +++ b/src/lib/libssl/src/ssl/s3_clnt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: s3_clnt.c,v 1.134 2015/09/13 12:39:16 jsing Exp $ */ | 1 | /* $OpenBSD: s3_clnt.c,v 1.135 2015/09/13 12:52:07 jsing 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 | * |
@@ -1908,8 +1908,9 @@ static int | |||
1908 | ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | 1908 | ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) |
1909 | { | 1909 | { |
1910 | DH *dh_srvr = NULL, *dh_clnt = NULL; | 1910 | DH *dh_srvr = NULL, *dh_clnt = NULL; |
1911 | unsigned char *key = NULL; | ||
1912 | int key_size, n; | ||
1911 | int ret = -1; | 1913 | int ret = -1; |
1912 | int n; | ||
1913 | 1914 | ||
1914 | /* Ensure that we have an ephemeral key for DHE. */ | 1915 | /* Ensure that we have an ephemeral key for DHE. */ |
1915 | if (sess_cert->peer_dh_tmp == NULL) { | 1916 | if (sess_cert->peer_dh_tmp == NULL) { |
@@ -1929,12 +1930,13 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1929 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); | 1930 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); |
1930 | goto err; | 1931 | goto err; |
1931 | } | 1932 | } |
1932 | 1933 | key_size = DH_size(dh_clnt); | |
1933 | /* | 1934 | if ((key = malloc(key_size)) == NULL) { |
1934 | * Use the 'p' output buffer for the DH key, but make sure to clear | 1935 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
1935 | * it out afterwards. | 1936 | ERR_R_MALLOC_FAILURE); |
1936 | */ | 1937 | goto err; |
1937 | n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt); | 1938 | } |
1939 | n = DH_compute_key(key, dh_srvr->pub_key, dh_clnt); | ||
1938 | if (n <= 0) { | 1940 | if (n <= 0) { |
1939 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); | 1941 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); |
1940 | goto err; | 1942 | goto err; |
@@ -1943,10 +1945,7 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1943 | /* Generate master key from the result. */ | 1945 | /* Generate master key from the result. */ |
1944 | s->session->master_key_length = | 1946 | s->session->master_key_length = |
1945 | s->method->ssl3_enc->generate_master_secret(s, | 1947 | s->method->ssl3_enc->generate_master_secret(s, |
1946 | s->session->master_key, p, n); | 1948 | s->session->master_key, key, n); |
1947 | |||
1948 | /* Clean up. */ | ||
1949 | explicit_bzero(p, n); | ||
1950 | 1949 | ||
1951 | /* Send off the data. */ | 1950 | /* Send off the data. */ |
1952 | n = BN_num_bytes(dh_clnt->pub_key); | 1951 | n = BN_num_bytes(dh_clnt->pub_key); |
@@ -1959,6 +1958,9 @@ ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) | |||
1959 | 1958 | ||
1960 | err: | 1959 | err: |
1961 | DH_free(dh_clnt); | 1960 | DH_free(dh_clnt); |
1961 | if (key != NULL) | ||
1962 | explicit_bzero(key, key_size); | ||
1963 | free(key); | ||
1962 | 1964 | ||
1963 | return (ret); | 1965 | return (ret); |
1964 | } | 1966 | } |
@@ -1967,18 +1969,17 @@ static int | |||
1967 | ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | 1969 | ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, |
1968 | int *outlen) | 1970 | int *outlen) |
1969 | { | 1971 | { |
1970 | EC_KEY *clnt_ecdh = NULL; | 1972 | EC_KEY *tkey, *clnt_ecdh = NULL; |
1971 | const EC_GROUP *srvr_group = NULL; | 1973 | const EC_GROUP *srvr_group = NULL; |
1972 | const EC_POINT *srvr_ecpoint = NULL; | 1974 | const EC_POINT *srvr_ecpoint = NULL; |
1973 | EVP_PKEY *srvr_pub_pkey = NULL; | 1975 | EVP_PKEY *srvr_pub_pkey = NULL; |
1974 | BN_CTX *bn_ctx = NULL; | 1976 | BN_CTX *bn_ctx = NULL; |
1975 | unsigned char *encodedPoint = NULL; | 1977 | unsigned char *encodedPoint = NULL; |
1978 | unsigned char *key = NULL; | ||
1976 | unsigned long alg_k; | 1979 | unsigned long alg_k; |
1977 | int encoded_pt_len = 0; | 1980 | int encoded_pt_len = 0; |
1978 | int key_size; | 1981 | int key_size, n; |
1979 | EC_KEY *tkey; | ||
1980 | int ret = -1; | 1982 | int ret = -1; |
1981 | int n; | ||
1982 | 1983 | ||
1983 | alg_k = s->s3->tmp.new_cipher->algorithm_mkey; | 1984 | alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
1984 | 1985 | ||
@@ -2025,22 +2026,21 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2025 | goto err; | 2026 | goto err; |
2026 | } | 2027 | } |
2027 | 2028 | ||
2028 | /* Generate a new ECDH key pair */ | 2029 | /* Generate a new ECDH key pair. */ |
2029 | if (!(EC_KEY_generate_key(clnt_ecdh))) { | 2030 | if (!(EC_KEY_generate_key(clnt_ecdh))) { |
2030 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2031 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2031 | goto err; | 2032 | goto err; |
2032 | } | 2033 | } |
2033 | |||
2034 | /* | ||
2035 | * Use the 'p' output buffer for the ECDH key, but make sure to clear | ||
2036 | * it out afterwards. | ||
2037 | */ | ||
2038 | key_size = ECDH_size(clnt_ecdh); | 2034 | key_size = ECDH_size(clnt_ecdh); |
2039 | if (key_size <= 0) { | 2035 | if (key_size <= 0) { |
2040 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2036 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2041 | goto err; | 2037 | goto err; |
2042 | } | 2038 | } |
2043 | n = ECDH_compute_key(p, key_size, srvr_ecpoint, clnt_ecdh, NULL); | 2039 | if ((key = malloc(key_size)) == NULL) { |
2040 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, | ||
2041 | ERR_R_MALLOC_FAILURE); | ||
2042 | } | ||
2043 | n = ECDH_compute_key(key, key_size, srvr_ecpoint, clnt_ecdh, NULL); | ||
2044 | if (n <= 0) { | 2044 | if (n <= 0) { |
2045 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); | 2045 | SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); |
2046 | goto err; | 2046 | goto err; |
@@ -2049,10 +2049,7 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2049 | /* Generate master key from the result. */ | 2049 | /* Generate master key from the result. */ |
2050 | s->session->master_key_length = | 2050 | s->session->master_key_length = |
2051 | s->method->ssl3_enc->generate_master_secret(s, | 2051 | s->method->ssl3_enc->generate_master_secret(s, |
2052 | s->session->master_key, p, n); | 2052 | s->session->master_key, key, n); |
2053 | |||
2054 | /* Clean up. */ | ||
2055 | explicit_bzero(p, n); | ||
2056 | 2053 | ||
2057 | /* | 2054 | /* |
2058 | * First check the size of encoding and allocate memory accordingly. | 2055 | * First check the size of encoding and allocate memory accordingly. |
@@ -2087,7 +2084,10 @@ ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, | |||
2087 | ret = 1; | 2084 | ret = 1; |
2088 | 2085 | ||
2089 | err: | 2086 | err: |
2090 | /* Free allocated memory */ | 2087 | if (key != NULL) |
2088 | explicit_bzero(key, key_size); | ||
2089 | free(key); | ||
2090 | |||
2091 | BN_CTX_free(bn_ctx); | 2091 | BN_CTX_free(bn_ctx); |
2092 | free(encodedPoint); | 2092 | free(encodedPoint); |
2093 | EC_KEY_free(clnt_ecdh); | 2093 | EC_KEY_free(clnt_ecdh); |
@@ -2219,7 +2219,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2219 | SESS_CERT *sess_cert; | 2219 | SESS_CERT *sess_cert; |
2220 | unsigned long alg_k; | 2220 | unsigned long alg_k; |
2221 | unsigned char *p; | 2221 | unsigned char *p; |
2222 | int n; | 2222 | int n = 0; |
2223 | 2223 | ||
2224 | if (s->state == SSL3_ST_CW_KEY_EXCH_A) { | 2224 | if (s->state == SSL3_ST_CW_KEY_EXCH_A) { |
2225 | p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); | 2225 | p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); |