提交 cbd64894 编写于 作者: D Dr. Stephen Henson

Use enc_flags when deciding protocol variations.

Use the enc_flags field to determine whether we should use explicit IV,
signature algorithms or SHA256 default PRF instead of hard coding which
versions support each requirement.
上级 6de2649a
...@@ -146,7 +146,7 @@ int tls1_cbc_remove_padding(const SSL* s, ...@@ -146,7 +146,7 @@ int tls1_cbc_remove_padding(const SSL* s,
unsigned padding_length, good, to_check, i; unsigned padding_length, good, to_check, i;
const unsigned overhead = 1 /* padding length byte */ + mac_size; const unsigned overhead = 1 /* padding length byte */ + mac_size;
/* Check if version requires explicit IV */ /* Check if version requires explicit IV */
if (s->version >= TLS1_1_VERSION || s->version == DTLS1_BAD_VER) if (SSL_USE_EXPLICIT_IV(s))
{ {
/* These lengths are all public so we can test them in /* These lengths are all public so we can test them in
* non-constant time. * non-constant time.
......
...@@ -1030,10 +1030,10 @@ int ssl3_get_server_hello(SSL *s) ...@@ -1030,10 +1030,10 @@ int ssl3_get_server_hello(SSL *s)
} }
} }
s->s3->tmp.new_cipher=c; s->s3->tmp.new_cipher=c;
/* Don't digest cached records if TLS v1.2: we may need them for /* Don't digest cached records if no sigalgs: we may need them for
* client authentication. * client authentication.
*/ */
if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s)) if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
goto f_err; goto f_err;
/* lets get the compression algorithm */ /* lets get the compression algorithm */
/* COMPRESSION */ /* COMPRESSION */
...@@ -1785,7 +1785,7 @@ int ssl3_get_key_exchange(SSL *s) ...@@ -1785,7 +1785,7 @@ int ssl3_get_key_exchange(SSL *s)
/* if it was signed, check the signature */ /* if it was signed, check the signature */
if (pkey != NULL) if (pkey != NULL)
{ {
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
int rv = tls12_check_peer_sigalg(&md, s, p, pkey); int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
if (rv == -1) if (rv == -1)
...@@ -1817,7 +1817,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); ...@@ -1817,7 +1817,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
} }
#ifndef OPENSSL_NO_RSA #ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION) if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
{ {
int num; int num;
...@@ -1991,7 +1991,7 @@ int ssl3_get_certificate_request(SSL *s) ...@@ -1991,7 +1991,7 @@ int ssl3_get_certificate_request(SSL *s)
for (i=0; i<ctype_num; i++) for (i=0; i<ctype_num; i++)
s->s3->tmp.ctype[i]= p[i]; s->s3->tmp.ctype[i]= p[i];
p+=p[-1]; p+=p[-1];
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
n2s(p, llen); n2s(p, llen);
/* Check we have enough room for signature algorithms and /* Check we have enough room for signature algorithms and
...@@ -3051,7 +3051,7 @@ int ssl3_send_client_verify(SSL *s) ...@@ -3051,7 +3051,7 @@ int ssl3_send_client_verify(SSL *s)
EVP_PKEY_sign_init(pctx); EVP_PKEY_sign_init(pctx);
if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0) if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
{ {
if (TLS1_get_version(s) < TLS1_2_VERSION) if (!SSL_USE_SIGALGS(s))
s->method->ssl3_enc->cert_verify_mac(s, s->method->ssl3_enc->cert_verify_mac(s,
NID_sha1, NID_sha1,
&(data[MD5_DIGEST_LENGTH])); &(data[MD5_DIGEST_LENGTH]));
...@@ -3063,7 +3063,7 @@ int ssl3_send_client_verify(SSL *s) ...@@ -3063,7 +3063,7 @@ int ssl3_send_client_verify(SSL *s)
/* For TLS v1.2 send signature algorithm and signature /* For TLS v1.2 send signature algorithm and signature
* using agreed digest and cached handshake records. * using agreed digest and cached handshake records.
*/ */
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
long hdatalen = 0; long hdatalen = 0;
void *hdata; void *hdata;
...@@ -3193,7 +3193,7 @@ static int ssl3_check_client_certificate(SSL *s) ...@@ -3193,7 +3193,7 @@ static int ssl3_check_client_certificate(SSL *s)
if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey) if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
return 0; return 0;
/* If no suitable signature algorithm can't use certificate */ /* If no suitable signature algorithm can't use certificate */
if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest) if (SSL_USE_SIGALGS(s) && !s->cert->key->digest)
return 0; return 0;
/* If strict mode check suitability of chain before using it. /* If strict mode check suitability of chain before using it.
* This also adjusts suite B digest if necessary. * This also adjusts suite B digest if necessary.
......
...@@ -4458,14 +4458,14 @@ need to go to SSL_ST_ACCEPT. ...@@ -4458,14 +4458,14 @@ need to go to SSL_ST_ACCEPT.
} }
return(ret); return(ret);
} }
/* If we are using TLS v1.2 or later and default SHA1+MD5 algorithms switch /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF
* to new SHA256 PRF and handshake macs * and handshake macs if required.
*/ */
long ssl_get_algorithm2(SSL *s) long ssl_get_algorithm2(SSL *s)
{ {
long alg2 = s->s3->tmp.new_cipher->algorithm2; long alg2 = s->s3->tmp.new_cipher->algorithm2;
if (TLS1_get_version(s) >= TLS1_2_VERSION && if (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SHA256_PRF
alg2 == (SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF)) && alg2 == (SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF))
return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256;
return alg2; return alg2;
} }
......
...@@ -180,7 +180,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) ...@@ -180,7 +180,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
/* For DTLS/UDP reads should not span multiple packets /* For DTLS/UDP reads should not span multiple packets
* because the read operation returns the whole packet * because the read operation returns the whole packet
* at once (as long as it fits into the buffer). */ * at once (as long as it fits into the buffer). */
if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) if (SSL_IS_DTLS(s))
{ {
if (left > 0 && n > left) if (left > 0 && n > left)
n = left; n = left;
...@@ -248,7 +248,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) ...@@ -248,7 +248,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
{ {
rb->left = left; rb->left = left;
if (s->mode & SSL_MODE_RELEASE_BUFFERS && if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) !SSL_IS_DTLS(s))
if (len+left == 0) if (len+left == 0)
ssl3_release_read_buffer(s); ssl3_release_read_buffer(s);
return(i); return(i);
...@@ -257,7 +257,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) ...@@ -257,7 +257,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
/* reads should *never* span multiple packets for DTLS because /* reads should *never* span multiple packets for DTLS because
* the underlying transport protocol is message oriented as opposed * the underlying transport protocol is message oriented as opposed
* to byte oriented as in the TLS case. */ * to byte oriented as in the TLS case. */
if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) if (SSL_IS_DTLS(s))
{ {
if (n > left) if (n > left)
n = left; /* makes the while condition false */ n = left; /* makes the while condition false */
...@@ -757,8 +757,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, ...@@ -757,8 +757,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
/* field where we are to write out packet length */ /* field where we are to write out packet length */
plen=p; plen=p;
p+=2; p+=2;
/* Explicit IV length, block ciphers and TLS version 1.1 or later */ /* Explicit IV length, block ciphers appropriate version flag */
if (s->enc_write_ctx && s->version >= TLS1_1_VERSION) if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s))
{ {
int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx); int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
if (mode == EVP_CIPH_CBC_MODE) if (mode == EVP_CIPH_CBC_MODE)
...@@ -895,7 +895,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, ...@@ -895,7 +895,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
wb->left=0; wb->left=0;
wb->offset+=i; wb->offset+=i;
if (s->mode & SSL_MODE_RELEASE_BUFFERS && if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) !SSL_IS_DTLS(s))
ssl3_release_write_buffer(s); ssl3_release_write_buffer(s);
s->rwstate=SSL_NOTHING; s->rwstate=SSL_NOTHING;
return(s->s3->wpend_ret); return(s->s3->wpend_ret);
......
...@@ -640,13 +640,13 @@ int ssl3_accept(SSL *s) ...@@ -640,13 +640,13 @@ int ssl3_accept(SSL *s)
#endif #endif
s->init_num = 0; s->init_num = 0;
} }
else if (TLS1_get_version(s) >= TLS1_2_VERSION) else if (SSL_USE_SIGALGS(s))
{ {
s->state=SSL3_ST_SR_CERT_VRFY_A; s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0; s->init_num=0;
if (!s->session->peer) if (!s->session->peer)
break; break;
/* For TLS v1.2 freeze the handshake buffer /* For sigalgs freeze the handshake buffer
* at this point and digest cached records. * at this point and digest cached records.
*/ */
if (!s->s3->handshake_buffer) if (!s->s3->handshake_buffer)
...@@ -1037,7 +1037,7 @@ int ssl3_get_client_hello(SSL *s) ...@@ -1037,7 +1037,7 @@ int ssl3_get_client_hello(SSL *s)
p+=j; p+=j;
if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) if (SSL_IS_DTLS(s))
{ {
/* cookie stuff */ /* cookie stuff */
cookie_len = *(p++); cookie_len = *(p++);
...@@ -1409,7 +1409,7 @@ int ssl3_get_client_hello(SSL *s) ...@@ -1409,7 +1409,7 @@ int ssl3_get_client_hello(SSL *s)
s->s3->tmp.new_cipher=s->session->cipher; s->s3->tmp.new_cipher=s->session->cipher;
} }
if (TLS1_get_version(s) < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER)) if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER))
{ {
if (!ssl3_digest_cached_records(s)) if (!ssl3_digest_cached_records(s))
goto f_err; goto f_err;
...@@ -1941,8 +1941,7 @@ int ssl3_send_server_key_exchange(SSL *s) ...@@ -1941,8 +1941,7 @@ int ssl3_send_server_key_exchange(SSL *s)
/* n is the length of the params, they start at &(d[4]) /* n is the length of the params, they start at &(d[4])
* and p points to the space at the end. */ * and p points to the space at the end. */
#ifndef OPENSSL_NO_RSA #ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
&& TLS1_get_version(s) < TLS1_2_VERSION)
{ {
q=md_buf; q=md_buf;
j=0; j=0;
...@@ -1973,9 +1972,8 @@ int ssl3_send_server_key_exchange(SSL *s) ...@@ -1973,9 +1972,8 @@ int ssl3_send_server_key_exchange(SSL *s)
#endif #endif
if (md) if (md)
{ {
/* For TLS1.2 and later send signature /* send signature algorithm */
* algorithm */ if (SSL_USE_SIGALGS(s))
if (TLS1_get_version(s) >= TLS1_2_VERSION)
{ {
if (!tls12_get_sigandhash(p, pkey, md)) if (!tls12_get_sigandhash(p, pkey, md))
{ {
...@@ -2002,7 +2000,7 @@ int ssl3_send_server_key_exchange(SSL *s) ...@@ -2002,7 +2000,7 @@ int ssl3_send_server_key_exchange(SSL *s)
} }
s2n(i,p); s2n(i,p);
n+=i+2; n+=i+2;
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
n+= 2; n+= 2;
} }
else else
...@@ -2052,7 +2050,7 @@ int ssl3_send_certificate_request(SSL *s) ...@@ -2052,7 +2050,7 @@ int ssl3_send_certificate_request(SSL *s)
p+=n; p+=n;
n++; n++;
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
const unsigned char *psigs; const unsigned char *psigs;
nl = tls12_get_psigalgs(s, &psigs); nl = tls12_get_psigalgs(s, &psigs);
...@@ -3024,7 +3022,7 @@ int ssl3_get_cert_verify(SSL *s) ...@@ -3024,7 +3022,7 @@ int ssl3_get_cert_verify(SSL *s)
} }
else else
{ {
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
int rv = tls12_check_peer_sigalg(&md, s, p, pkey); int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
if (rv == -1) if (rv == -1)
...@@ -3060,7 +3058,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); ...@@ -3060,7 +3058,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
goto f_err; goto f_err;
} }
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
long hdatalen = 0; long hdatalen = 0;
void *hdata; void *hdata;
......
...@@ -1112,8 +1112,7 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg) ...@@ -1112,8 +1112,7 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
return 0; return 0;
#endif #endif
if (SSL_version(s) == DTLS1_VERSION || if (SSL_IS_DTLS(s))
SSL_version(s) == DTLS1_BAD_VER)
{ {
s->d1->mtu = larg; s->d1->mtu = larg;
return larg; return larg;
......
...@@ -440,7 +440,14 @@ ...@@ -440,7 +440,14 @@
/* Check if an SSL structure is using DTLS */ /* Check if an SSL structure is using DTLS */
#define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) #define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
/* See if we need explicit IV */
#define SSL_USE_EXPLICIT_IV(s) \
(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
/* See if we use signature algorithms extension
* and signature algorithm before signatures.
*/
#define SSL_USE_SIGALGS(s) \
(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SIGALGS)
/* Mostly for SSLv3 */ /* Mostly for SSLv3 */
#define SSL_PKEY_RSA_ENC 0 #define SSL_PKEY_RSA_ENC 0
...@@ -702,8 +709,10 @@ typedef struct ssl3_enc_method ...@@ -702,8 +709,10 @@ typedef struct ssl3_enc_method
#define SSL_ENC_FLAG_EXPLICIT_IV 0x1 #define SSL_ENC_FLAG_EXPLICIT_IV 0x1
/* Uses signature algorithms extension */ /* Uses signature algorithms extension */
#define SSL_ENC_FLAG_SIGALGS 0x2 #define SSL_ENC_FLAG_SIGALGS 0x2
/* Uses SHA256 default PRF */
#define SSL_ENC_FLAG_SHA256_PRF 0x4
/* Is DTLS */ /* Is DTLS */
#define SSL_ENC_FLAG_DTLS 0x4 #define SSL_ENC_FLAG_DTLS 0x8
#ifndef OPENSSL_NO_COMP #ifndef OPENSSL_NO_COMP
/* Used for holding the relevant compression methods loaded into SSL_CTX */ /* Used for holding the relevant compression methods loaded into SSL_CTX */
......
...@@ -779,7 +779,7 @@ int tls1_enc(SSL *s, int send) ...@@ -779,7 +779,7 @@ int tls1_enc(SSL *s, int send)
seq = send?s->s3->write_sequence:s->s3->read_sequence; seq = send?s->s3->write_sequence:s->s3->read_sequence;
if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) if (SSL_IS_DTLS(s))
{ {
unsigned char dtlsseq[9],*p=dtlsseq; unsigned char dtlsseq[9],*p=dtlsseq;
...@@ -1008,7 +1008,7 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send) ...@@ -1008,7 +1008,7 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send)
mac_ctx = &hmac; mac_ctx = &hmac;
} }
if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER) if (SSL_IS_DTLS(ssl))
{ {
unsigned char dtlsseq[8],*p=dtlsseq; unsigned char dtlsseq[8],*p=dtlsseq;
...@@ -1071,7 +1071,7 @@ printf("rec="); ...@@ -1071,7 +1071,7 @@ printf("rec=");
{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); } {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
#endif #endif
if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER) if (SSL_IS_DTLS(ssl))
{ {
for (i=7; i>=0; i--) for (i=7; i>=0; i--)
{ {
......
...@@ -178,7 +178,7 @@ SSL3_ENC_METHOD TLSv1_2_enc_data={ ...@@ -178,7 +178,7 @@ SSL3_ENC_METHOD TLSv1_2_enc_data={
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code, tls1_alert_code,
tls1_export_keying_material, tls1_export_keying_material,
SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS, SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF,
SSL3_HM_HEADER_LENGTH, SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header, ssl3_set_handshake_header,
ssl3_handshake_write ssl3_handshake_write
...@@ -1297,7 +1297,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ...@@ -1297,7 +1297,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
} }
skip_ext: skip_ext:
if (TLS1_get_client_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
size_t salglen; size_t salglen;
const unsigned char *salg; const unsigned char *salg;
...@@ -3031,7 +3031,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, ...@@ -3031,7 +3031,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
if (p >= limit) if (p >= limit)
return -1; return -1;
/* Skip past DTLS cookie */ /* Skip past DTLS cookie */
if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) if (SSL_IS_DTLS(s))
{ {
i = *(p++); i = *(p++);
p+= i; p+= i;
...@@ -3458,8 +3458,8 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) ...@@ -3458,8 +3458,8 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
const EVP_MD *md; const EVP_MD *md;
CERT *c = s->cert; CERT *c = s->cert;
TLS_SIGALGS *sigptr; TLS_SIGALGS *sigptr;
/* Extension ignored for TLS versions below 1.2 */ /* Extension ignored for inappropriate versions */
if (TLS1_get_version(s) < TLS1_2_VERSION) if (!SSL_USE_SIGALGS(s))
return 1; return 1;
/* Should never happen */ /* Should never happen */
if (!c) if (!c)
......
...@@ -531,7 +531,7 @@ static int ssl_print_signature(BIO *bio, int indent, SSL *s, ...@@ -531,7 +531,7 @@ static int ssl_print_signature(BIO *bio, int indent, SSL *s,
{ {
if (*pmsglen < 2) if (*pmsglen < 2)
return 0; return 0;
if (TLS1_get_version(s) >= TLS1_2_VERSION) if (SSL_USE_SIGALGS(s))
{ {
const unsigned char *p = *pmsg; const unsigned char *p = *pmsg;
BIO_indent(bio, indent, 80); BIO_indent(bio, indent, 80);
...@@ -1046,7 +1046,7 @@ static int ssl_print_cert_request(BIO *bio, int indent, SSL *s, ...@@ -1046,7 +1046,7 @@ static int ssl_print_cert_request(BIO *bio, int indent, SSL *s,
return 0; return 0;
msg += xlen; msg += xlen;
msglen -= xlen + 1; msglen -= xlen + 1;
if (TLS1_get_version(s) < TLS1_2_VERSION) if (!SSL_USE_SIGALGS(s))
goto skip_sig; goto skip_sig;
if (msglen < 2) if (msglen < 2)
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册