diff options
Diffstat (limited to 'src/lib/libssl/s3_clnt.c')
-rw-r--r-- | src/lib/libssl/s3_clnt.c | 87 |
1 files changed, 42 insertions, 45 deletions
diff --git a/src/lib/libssl/s3_clnt.c b/src/lib/libssl/s3_clnt.c index b63f0bf0c9..e765da9ecd 100644 --- a/src/lib/libssl/s3_clnt.c +++ b/src/lib/libssl/s3_clnt.c | |||
@@ -5,21 +5,21 @@ | |||
5 | * This package is an SSL implementation written | 5 | * This package is an SSL implementation written |
6 | * by Eric Young (eay@cryptsoft.com). | 6 | * by Eric Young (eay@cryptsoft.com). |
7 | * The implementation was written so as to conform with Netscapes SSL. | 7 | * The implementation was written so as to conform with Netscapes SSL. |
8 | * | 8 | * |
9 | * This library is free for commercial and non-commercial use as long as | 9 | * This library is free for commercial and non-commercial use as long as |
10 | * the following conditions are aheared to. The following conditions | 10 | * the following conditions are aheared to. The following conditions |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | 11 | * apply to all code found in this distribution, be it the RC4, RSA, |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | 12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
13 | * included with this distribution is covered by the same copyright terms | 13 | * included with this distribution is covered by the same copyright terms |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | 14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
15 | * | 15 | * |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in | 16 | * Copyright remains Eric Young's, and as such any Copyright notices in |
17 | * the code are not to be removed. | 17 | * the code are not to be removed. |
18 | * If this package is used in a product, Eric Young should be given attribution | 18 | * If this package is used in a product, Eric Young should be given attribution |
19 | * as the author of the parts of the library used. | 19 | * as the author of the parts of the library used. |
20 | * This can be in the form of a textual message at program startup or | 20 | * This can be in the form of a textual message at program startup or |
21 | * in documentation (online or textual) provided with the package. | 21 | * in documentation (online or textual) provided with the package. |
22 | * | 22 | * |
23 | * Redistribution and use in source and binary forms, with or without | 23 | * Redistribution and use in source and binary forms, with or without |
24 | * modification, are permitted provided that the following conditions | 24 | * modification, are permitted provided that the following conditions |
25 | * are met: | 25 | * are met: |
@@ -34,10 +34,10 @@ | |||
34 | * Eric Young (eay@cryptsoft.com)" | 34 | * Eric Young (eay@cryptsoft.com)" |
35 | * The word 'cryptographic' can be left out if the rouines from the library | 35 | * The word 'cryptographic' can be left out if the rouines from the library |
36 | * being used are not cryptographic related :-). | 36 | * being used are not cryptographic related :-). |
37 | * 4. If you include any Windows specific code (or a derivative thereof) from | 37 | * 4. If you include any Windows specific code (or a derivative thereof) from |
38 | * the apps directory (application code) you must include an acknowledgement: | 38 | * the apps directory (application code) you must include an acknowledgement: |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | 39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
40 | * | 40 | * |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | 41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
@@ -49,7 +49,7 @@ | |||
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
51 | * SUCH DAMAGE. | 51 | * SUCH DAMAGE. |
52 | * | 52 | * |
53 | * The licence and distribution terms for any publically available version or | 53 | * The licence and distribution terms for any publically available version or |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | 54 | * derivative of this code cannot be changed. i.e. this code cannot simply be |
55 | * copied and put under another distribution licence | 55 | * copied and put under another distribution licence |
@@ -63,7 +63,7 @@ | |||
63 | * are met: | 63 | * are met: |
64 | * | 64 | * |
65 | * 1. Redistributions of source code must retain the above copyright | 65 | * 1. Redistributions of source code must retain the above copyright |
66 | * notice, this list of conditions and the following disclaimer. | 66 | * notice, this list of conditions and the following disclaimer. |
67 | * | 67 | * |
68 | * 2. Redistributions in binary form must reproduce the above copyright | 68 | * 2. Redistributions in binary form must reproduce the above copyright |
69 | * notice, this list of conditions and the following disclaimer in | 69 | * notice, this list of conditions and the following disclaimer in |
@@ -111,7 +111,7 @@ | |||
111 | /* ==================================================================== | 111 | /* ==================================================================== |
112 | * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. | 112 | * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. |
113 | * | 113 | * |
114 | * Portions of the attached software ("Contribution") are developed by | 114 | * Portions of the attached software ("Contribution") are developed by |
115 | * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. | 115 | * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. |
116 | * | 116 | * |
117 | * The Contribution is licensed pursuant to the OpenSSL open source | 117 | * The Contribution is licensed pursuant to the OpenSSL open source |
@@ -412,12 +412,12 @@ ssl3_connect(SSL *s) | |||
412 | * For TLS, cert_req is set to 2, so a cert chain | 412 | * For TLS, cert_req is set to 2, so a cert chain |
413 | * of nothing is sent, but no verify packet is sent | 413 | * of nothing is sent, but no verify packet is sent |
414 | */ | 414 | */ |
415 | /* | 415 | /* |
416 | * XXX: For now, we do not support client | 416 | * XXX: For now, we do not support client |
417 | * authentication in ECDH cipher suites with | 417 | * authentication in ECDH cipher suites with |
418 | * ECDH (rather than ECDSA) certificates. | 418 | * ECDH (rather than ECDSA) certificates. |
419 | * We need to skip the certificate verify | 419 | * We need to skip the certificate verify |
420 | * message when client's ECDH public key is sent | 420 | * message when client's ECDH public key is sent |
421 | * inside the client certificate. | 421 | * inside the client certificate. |
422 | */ | 422 | */ |
423 | if (s->s3->tmp.cert_req == 1) { | 423 | if (s->s3->tmp.cert_req == 1) { |
@@ -679,7 +679,7 @@ ssl3_client_hello(SSL *s) | |||
679 | /* Do the message type and length last */ | 679 | /* Do the message type and length last */ |
680 | d = p = &(buf[4]); | 680 | d = p = &(buf[4]); |
681 | 681 | ||
682 | /* | 682 | /* |
683 | * Version indicates the negotiated version: for example from | 683 | * Version indicates the negotiated version: for example from |
684 | * an SSLv2/v3 compatible client hello). The client_version | 684 | * an SSLv2/v3 compatible client hello). The client_version |
685 | * field is the maximum version we permit and it is also | 685 | * field is the maximum version we permit and it is also |
@@ -832,7 +832,7 @@ ssl3_get_server_hello(SSL *s) | |||
832 | if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { | 832 | if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { |
833 | if (s->d1->send_cookie == 0) { | 833 | if (s->d1->send_cookie == 0) { |
834 | s->s3->tmp.reuse_message = 1; | 834 | s->s3->tmp.reuse_message = 1; |
835 | return 1; | 835 | return (1); |
836 | } | 836 | } |
837 | else /* already sent a cookie */ | 837 | else /* already sent a cookie */ |
838 | { | 838 | { |
@@ -1473,7 +1473,7 @@ ssl3_get_key_exchange(SSL *s) | |||
1473 | p += i; | 1473 | p += i; |
1474 | n -= param_len; | 1474 | n -= param_len; |
1475 | 1475 | ||
1476 | /* | 1476 | /* |
1477 | * This should be because we are using an | 1477 | * This should be because we are using an |
1478 | * export cipher | 1478 | * export cipher |
1479 | */ | 1479 | */ |
@@ -2038,9 +2038,9 @@ ssl3_get_new_session_ticket(SSL *s) | |||
2038 | * There are two ways to detect a resumed ticket sesion. | 2038 | * There are two ways to detect a resumed ticket sesion. |
2039 | * One is to set an appropriate session ID and then the server | 2039 | * One is to set an appropriate session ID and then the server |
2040 | * must return a match in ServerHello. This allows the normal | 2040 | * must return a match in ServerHello. This allows the normal |
2041 | * client session ID matching to work and we know much | 2041 | * client session ID matching to work and we know much |
2042 | * earlier that the ticket has been accepted. | 2042 | * earlier that the ticket has been accepted. |
2043 | * | 2043 | * |
2044 | * The other way is to set zero length session ID when the | 2044 | * The other way is to set zero length session ID when the |
2045 | * ticket is presented and rely on the handshake to determine | 2045 | * ticket is presented and rely on the handshake to determine |
2046 | * session resumption. | 2046 | * session resumption. |
@@ -2049,7 +2049,7 @@ ssl3_get_new_session_ticket(SSL *s) | |||
2049 | * assumptions elsewhere in OpenSSL. The session ID is set | 2049 | * assumptions elsewhere in OpenSSL. The session ID is set |
2050 | * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the | 2050 | * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the |
2051 | * ticket. | 2051 | * ticket. |
2052 | */ | 2052 | */ |
2053 | EVP_Digest(p, ticklen, s->session->session_id, | 2053 | EVP_Digest(p, ticklen, s->session->session_id, |
2054 | &s->session->session_id_length, EVP_sha256(), NULL); | 2054 | &s->session->session_id_length, EVP_sha256(), NULL); |
2055 | ret = 1; | 2055 | ret = 1; |
@@ -2067,12 +2067,9 @@ ssl3_get_cert_status(SSL *s) | |||
2067 | unsigned long resplen, n; | 2067 | unsigned long resplen, n; |
2068 | const unsigned char *p; | 2068 | const unsigned char *p; |
2069 | 2069 | ||
2070 | n = s->method->ssl_get_message(s, | 2070 | n = s->method->ssl_get_message(s, SSL3_ST_CR_CERT_STATUS_A, |
2071 | SSL3_ST_CR_CERT_STATUS_A, | 2071 | SSL3_ST_CR_CERT_STATUS_B, SSL3_MT_CERTIFICATE_STATUS, |
2072 | SSL3_ST_CR_CERT_STATUS_B, | 2072 | 16384, &ok); |
2073 | SSL3_MT_CERTIFICATE_STATUS, | ||
2074 | 16384, | ||
2075 | &ok); | ||
2076 | 2073 | ||
2077 | if (!ok) | 2074 | if (!ok) |
2078 | return ((int)n); | 2075 | return ((int)n); |
@@ -2123,7 +2120,7 @@ ssl3_get_cert_status(SSL *s) | |||
2123 | goto f_err; | 2120 | goto f_err; |
2124 | } | 2121 | } |
2125 | } | 2122 | } |
2126 | return 1; | 2123 | return (1); |
2127 | f_err: | 2124 | f_err: |
2128 | ssl3_send_alert(s, SSL3_AL_FATAL, al); | 2125 | ssl3_send_alert(s, SSL3_AL_FATAL, al); |
2129 | return (-1); | 2126 | return (-1); |
@@ -2147,7 +2144,7 @@ ssl3_get_server_done(SSL *s) | |||
2147 | ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | 2144 | ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); |
2148 | SSLerr(SSL_F_SSL3_GET_SERVER_DONE, | 2145 | SSLerr(SSL_F_SSL3_GET_SERVER_DONE, |
2149 | SSL_R_LENGTH_MISMATCH); | 2146 | SSL_R_LENGTH_MISMATCH); |
2150 | return -1; | 2147 | return (-1); |
2151 | } | 2148 | } |
2152 | ret = 1; | 2149 | ret = 1; |
2153 | return (ret); | 2150 | return (ret); |
@@ -2229,8 +2226,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2229 | 2226 | ||
2230 | s->session->master_key_length = | 2227 | s->session->master_key_length = |
2231 | s->method->ssl3_enc->generate_master_secret( | 2228 | s->method->ssl3_enc->generate_master_secret( |
2232 | s, s->session->master_key, tmp_buf, | 2229 | s, s->session->master_key, tmp_buf, sizeof tmp_buf); |
2233 | sizeof tmp_buf); | ||
2234 | OPENSSL_cleanse(tmp_buf, sizeof tmp_buf); | 2230 | OPENSSL_cleanse(tmp_buf, sizeof tmp_buf); |
2235 | } | 2231 | } |
2236 | #ifndef OPENSSL_NO_KRB5 | 2232 | #ifndef OPENSSL_NO_KRB5 |
@@ -2246,7 +2242,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2246 | unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; | 2242 | unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; |
2247 | unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH | 2243 | unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH |
2248 | + EVP_MAX_IV_LENGTH]; | 2244 | + EVP_MAX_IV_LENGTH]; |
2249 | int padl, outl = sizeof(epms); | 2245 | int padl, outl = sizeof(epms); |
2250 | 2246 | ||
2251 | EVP_CIPHER_CTX_init(&ciph_ctx); | 2247 | EVP_CIPHER_CTX_init(&ciph_ctx); |
2252 | 2248 | ||
@@ -2283,14 +2279,14 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2283 | goto err; | 2279 | goto err; |
2284 | } | 2280 | } |
2285 | 2281 | ||
2286 | /* | 2282 | /* |
2287 | * 20010406 VRS - Earlier versions used KRB5 AP_REQ | 2283 | * 20010406 VRS - Earlier versions used KRB5 AP_REQ |
2288 | * in place of RFC 2712 KerberosWrapper, as in: | 2284 | * in place of RFC 2712 KerberosWrapper, as in: |
2289 | * | 2285 | * |
2290 | * Send ticket (copy to *p, set n = length) | 2286 | * Send ticket (copy to *p, set n = length) |
2291 | * n = krb5_ap_req.length; | 2287 | * n = krb5_ap_req.length; |
2292 | * memcpy(p, krb5_ap_req.data, krb5_ap_req.length); | 2288 | * memcpy(p, krb5_ap_req.data, krb5_ap_req.length); |
2293 | * if (krb5_ap_req.data) | 2289 | * if (krb5_ap_req.data) |
2294 | * kssl_krb5_free_data_contents(NULL,&krb5_ap_req); | 2290 | * kssl_krb5_free_data_contents(NULL,&krb5_ap_req); |
2295 | * | 2291 | * |
2296 | * Now using real RFC 2712 KerberosWrapper | 2292 | * Now using real RFC 2712 KerberosWrapper |
@@ -2435,7 +2431,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2435 | } | 2431 | } |
2436 | #endif | 2432 | #endif |
2437 | 2433 | ||
2438 | #ifndef OPENSSL_NO_ECDH | 2434 | #ifndef OPENSSL_NO_ECDH |
2439 | else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) { | 2435 | else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) { |
2440 | const EC_GROUP *srvr_group = NULL; | 2436 | const EC_GROUP *srvr_group = NULL; |
2441 | EC_KEY *tkey; | 2437 | EC_KEY *tkey; |
@@ -2449,11 +2445,11 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2449 | */ | 2445 | */ |
2450 | if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && | 2446 | if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && |
2451 | (s->cert != NULL)) { | 2447 | (s->cert != NULL)) { |
2452 | /* | 2448 | /* |
2453 | * XXX: For now, we do not support client | 2449 | * XXX: For now, we do not support client |
2454 | * authentication using ECDH certificates. | 2450 | * authentication using ECDH certificates. |
2455 | * To add such support, one needs to add | 2451 | * To add such support, one needs to add |
2456 | * code that checks for appropriate | 2452 | * code that checks for appropriate |
2457 | * conditions and sets ecdh_clnt_cert to 1. | 2453 | * conditions and sets ecdh_clnt_cert to 1. |
2458 | * For example, the cert have an ECC | 2454 | * For example, the cert have an ECC |
2459 | * key on the same curve as the server's | 2455 | * key on the same curve as the server's |
@@ -2561,7 +2557,7 @@ ssl3_send_client_key_exchange(SSL *s) | |||
2561 | 2557 | ||
2562 | /* generate master key from the result */ | 2558 | /* generate master key from the result */ |
2563 | s->session->master_key_length = s->method->ssl3_enc \ | 2559 | s->session->master_key_length = s->method->ssl3_enc \ |
2564 | -> generate_master_secret(s, | 2560 | -> generate_master_secret(s, |
2565 | s->session->master_key, p, n); | 2561 | s->session->master_key, p, n); |
2566 | 2562 | ||
2567 | memset(p, 0, n); /* clean up */ | 2563 | memset(p, 0, n); /* clean up */ |
@@ -2895,7 +2891,7 @@ ssl3_send_client_verify(SSL *s) | |||
2895 | } else { | 2891 | } else { |
2896 | ERR_clear_error(); | 2892 | ERR_clear_error(); |
2897 | } | 2893 | } |
2898 | /* | 2894 | /* |
2899 | * For TLS v1.2 send signature algorithm and signature | 2895 | * For TLS v1.2 send signature algorithm and signature |
2900 | * using agreed digest and cached handshake records. | 2896 | * using agreed digest and cached handshake records. |
2901 | */ | 2897 | */ |
@@ -3024,9 +3020,10 @@ ssl3_send_client_certificate(SSL *s) | |||
3024 | 3020 | ||
3025 | /* We need to get a client cert */ | 3021 | /* We need to get a client cert */ |
3026 | if (s->state == SSL3_ST_CW_CERT_B) { | 3022 | if (s->state == SSL3_ST_CW_CERT_B) { |
3027 | /* If we get an error, we need to | 3023 | /* |
3024 | * If we get an error, we need to | ||
3028 | * ssl->rwstate=SSL_X509_LOOKUP; return(-1); | 3025 | * ssl->rwstate=SSL_X509_LOOKUP; return(-1); |
3029 | * We then get retied later | 3026 | * We then get retied later |
3030 | */ | 3027 | */ |
3031 | i = ssl_do_client_cert_cb(s, &x509, &pkey); | 3028 | i = ssl_do_client_cert_cb(s, &x509, &pkey); |
3032 | if (i < 0) { | 3029 | if (i < 0) { |
@@ -3120,7 +3117,7 @@ ssl3_check_cert_and_algorithm(SSL *s) | |||
3120 | SSL_R_BAD_ECC_CERT); | 3117 | SSL_R_BAD_ECC_CERT); |
3121 | goto f_err; | 3118 | goto f_err; |
3122 | } else { | 3119 | } else { |
3123 | return 1; | 3120 | return (1); |
3124 | } | 3121 | } |
3125 | } | 3122 | } |
3126 | #endif | 3123 | #endif |
@@ -3221,7 +3218,7 @@ ssl3_send_next_proto(SSL *s) | |||
3221 | s->init_off = 0; | 3218 | s->init_off = 0; |
3222 | } | 3219 | } |
3223 | 3220 | ||
3224 | return ssl3_do_write(s, SSL3_RT_HANDSHAKE); | 3221 | return (ssl3_do_write(s, SSL3_RT_HANDSHAKE)); |
3225 | } | 3222 | } |
3226 | #endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ | 3223 | #endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ |
3227 | 3224 | ||
@@ -3240,7 +3237,7 @@ ssl3_check_finished(SSL *s) | |||
3240 | 3237 | ||
3241 | /* If we have no ticket it cannot be a resumed session. */ | 3238 | /* If we have no ticket it cannot be a resumed session. */ |
3242 | if (!s->session->tlsext_tick) | 3239 | if (!s->session->tlsext_tick) |
3243 | return 1; | 3240 | return (1); |
3244 | /* this function is called when we really expect a Certificate | 3241 | /* this function is called when we really expect a Certificate |
3245 | * message, so permit appropriate message length */ | 3242 | * message, so permit appropriate message length */ |
3246 | n = s->method->ssl_get_message(s, SSL3_ST_CR_CERT_A, | 3243 | n = s->method->ssl_get_message(s, SSL3_ST_CR_CERT_A, |
@@ -3250,9 +3247,9 @@ ssl3_check_finished(SSL *s) | |||
3250 | s->s3->tmp.reuse_message = 1; | 3247 | s->s3->tmp.reuse_message = 1; |
3251 | if ((s->s3->tmp.message_type == SSL3_MT_FINISHED) || | 3248 | if ((s->s3->tmp.message_type == SSL3_MT_FINISHED) || |
3252 | (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET)) | 3249 | (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET)) |
3253 | return 2; | 3250 | return (2); |
3254 | 3251 | ||
3255 | return 1; | 3252 | return (1); |
3256 | } | 3253 | } |
3257 | #endif | 3254 | #endif |
3258 | 3255 | ||
@@ -3267,10 +3264,10 @@ ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) | |||
3267 | SSL_get_client_CA_list(s), | 3264 | SSL_get_client_CA_list(s), |
3268 | px509, ppkey, NULL, NULL, NULL); | 3265 | px509, ppkey, NULL, NULL, NULL); |
3269 | if (i != 0) | 3266 | if (i != 0) |
3270 | return i; | 3267 | return (i); |
3271 | } | 3268 | } |
3272 | #endif | 3269 | #endif |
3273 | if (s->ctx->client_cert_cb) | 3270 | if (s->ctx->client_cert_cb) |
3274 | i = s->ctx->client_cert_cb(s, px509, ppkey); | 3271 | i = s->ctx->client_cert_cb(s, px509, ppkey); |
3275 | return i; | 3272 | return (i}; |
3276 | } | 3273 | } |