1From 9c14752f8872401de413fb46a96146b0d6bf926e Mon Sep 17 00:00:00 2001 2From: Alex Klyubin <klyubin@google.com> 3Date: Tue, 8 Apr 2014 16:02:24 -0700 4Subject: tls_psk_hint 5 6Fix TLS-PSK identity hint implementation issues. 7 8PSK identity hint can be stored in SSL_CTX and in SSL/SSL_SESSION, 9similar to other TLS parameters, with the value in SSL/SSL_SESSION 10taking precedence over the one in SSL_CTX. The value in SSL_CTX is 11shared (used as the default) between all SSL instances associated 12with that SSL_CTX, whereas the value in SSL/SSL_SESSION is confined 13to that particular TLS/SSL connection/session. 14 15The existing implementation of TLS-PSK does not correctly distinguish 16between PSK identity hint in SSL_CTX and in SSL/SSL_SESSION. This 17change fixes these issues: 181. SSL_use_psk_identity_hint does nothing and returns "success" when 19 the SSL object does not have an associated SSL_SESSION. 202. On the client, the hint in SSL_CTX (which is shared between 21 multiple SSL instances) is overwritten with the hint received from 22 server or reset to NULL if no hint was received. 233. On the client, psk_client_callback is invoked with the hint from 24 SSL_CTX rather than from current SSL/SSL_SESSION (i.e., the one 25 received from the server). Issue #2 above masks this issue. 264. On the server, the hint in SSL/SSL_SESSION is ignored and the hint 27 from SSL_CTX is sent to the client. 285. On the server, the hint in SSL/SSL_SESSION is reset to the one in 29 SSL_CTX after the ClientKeyExchange message step. 30 31This change fixes the issues by: 32* Adding storage for the hint in the SSL object. The idea being that 33 the hint in the associated SSL_SESSION takes precedence. 34* Reading the hint during the handshake only from the associated 35 SSL_SESSION object. 36* Initializing the hint in SSL object with the one from the SSL_CTX 37 object. 38* Initializing the hint in SSL_SESSION object with the one from the 39 SSL object. 40* Making SSL_use_psk_identity_hint and SSL_get_psk_identity_hint 41 set/get the hint to/from SSL_SESSION associated with the provided 42 SSL object, or, if no SSL_SESSION is available, set/get the hint 43 to/from the provided SSL object. 44* Removing code which resets the hint during handshake. 45--- 46 ssl/d1_clnt.c | 13 +------------ 47 ssl/d1_srvr.c | 10 +++++----- 48 ssl/s3_clnt.c | 37 +++++++++++++------------------------ 49 ssl/s3_srvr.c | 44 ++++++++++++++++---------------------------- 50 ssl/ssl.h | 4 ++++ 51 ssl/ssl_lib.c | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 52 ssl/ssl_sess.c | 12 ++++++++++++ 53 7 files changed, 96 insertions(+), 80 deletions(-) 54 55diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c 56index f857946..b017139 100644 57--- a/ssl/d1_clnt.c 58+++ b/ssl/d1_clnt.c 59@@ -1434,7 +1434,7 @@ int dtls1_send_client_key_exchange(SSL *s) 60 goto err; 61 } 62 63- psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, 64+ psk_len = s->psk_client_callback(s, s->session->psk_identity_hint, 65 identity, PSK_MAX_IDENTITY_LEN, 66 psk_or_pre_ms, sizeof(psk_or_pre_ms)); 67 if (psk_len > PSK_MAX_PSK_LEN) 68@@ -1459,17 +1459,6 @@ int dtls1_send_client_key_exchange(SSL *s) 69 t+=psk_len; 70 s2n(psk_len, t); 71 72- if (s->session->psk_identity_hint != NULL) 73- OPENSSL_free(s->session->psk_identity_hint); 74- s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); 75- if (s->ctx->psk_identity_hint != NULL && 76- s->session->psk_identity_hint == NULL) 77- { 78- SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, 79- ERR_R_MALLOC_FAILURE); 80- goto psk_err; 81- } 82- 83 if (s->session->psk_identity != NULL) 84 OPENSSL_free(s->session->psk_identity); 85 s->session->psk_identity = BUF_strdup(identity); 86diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c 87index 1384ab0..c181db6 100644 88--- a/ssl/d1_srvr.c 89+++ b/ssl/d1_srvr.c 90@@ -471,7 +471,7 @@ int dtls1_accept(SSL *s) 91 /* PSK: send ServerKeyExchange if PSK identity 92 * hint if provided */ 93 #ifndef OPENSSL_NO_PSK 94- || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) 95+ || ((alg_k & SSL_kPSK) && s->session->psk_identity_hint) 96 #endif 97 || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) 98 || (alg_k & SSL_kEECDH) 99@@ -1288,7 +1288,7 @@ int dtls1_send_server_key_exchange(SSL *s) 100 if (type & SSL_kPSK) 101 { 102 /* reserve size for record length and PSK identity hint*/ 103- n+=2+strlen(s->ctx->psk_identity_hint); 104+ n+=2+strlen(s->session->psk_identity_hint); 105 } 106 else 107 #endif /* !OPENSSL_NO_PSK */ 108@@ -1365,9 +1365,9 @@ int dtls1_send_server_key_exchange(SSL *s) 109 if (type & SSL_kPSK) 110 { 111 /* copy PSK identity hint */ 112- s2n(strlen(s->ctx->psk_identity_hint), p); 113- strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint)); 114- p+=strlen(s->ctx->psk_identity_hint); 115+ s2n(strlen(s->session->psk_identity_hint), p); 116+ strncpy((char *)p, s->session->psk_identity_hint, strlen(s->session->psk_identity_hint)); 117+ p+=strlen(s->session->psk_identity_hint); 118 } 119 #endif 120 121diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c 122index 12c3fe8..17367a2 100644 123--- a/ssl/s3_clnt.c 124+++ b/ssl/s3_clnt.c 125@@ -1374,9 +1374,11 @@ int ssl3_get_key_exchange(SSL *s) 126 if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) 127 { 128 s->session->sess_cert=ssl_sess_cert_new(); 129- if (s->ctx->psk_identity_hint) 130- OPENSSL_free(s->ctx->psk_identity_hint); 131- s->ctx->psk_identity_hint = NULL; 132+ if (s->session->psk_identity_hint) 133+ { 134+ OPENSSL_free(s->session->psk_identity_hint); 135+ s->session->psk_identity_hint = NULL; 136+ } 137 } 138 #endif 139 s->s3->tmp.reuse_message=1; 140@@ -1426,7 +1428,11 @@ int ssl3_get_key_exchange(SSL *s) 141 } 142 n2s(p,i); 143 144- s->ctx->psk_identity_hint = NULL; 145+ if (s->session->psk_identity_hint) 146+ { 147+ OPENSSL_free(s->session->psk_identity_hint); 148+ s->session->psk_identity_hint = NULL; 149+ } 150 if (i != 0) 151 { 152 /* Store PSK identity hint for later use, hint is used 153@@ -1452,10 +1458,8 @@ int ssl3_get_key_exchange(SSL *s) 154 * NULL-terminated string. */ 155 memcpy(tmp_id_hint, p, i); 156 memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i); 157- if (s->ctx->psk_identity_hint != NULL) 158- OPENSSL_free(s->ctx->psk_identity_hint); 159- s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint); 160- if (s->ctx->psk_identity_hint == NULL) 161+ s->session->psk_identity_hint = BUF_strdup(tmp_id_hint); 162+ if (s->session->psk_identity_hint == NULL) 163 { 164 SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); 165 goto f_err; 166@@ -2338,7 +2342,8 @@ int ssl3_send_client_key_exchange(SSL *s) 167 goto err; 168 } 169 170+ memset(identity, 0, sizeof(identity)); 171- psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, 172+ psk_len = s->psk_client_callback(s, s->session->psk_identity_hint, 173 identity, sizeof(identity) - 1, psk, sizeof(psk)); 174 if (psk_len > PSK_MAX_PSK_LEN) 175 { 176@@ -2374,21 +2378,6 @@ int ssl3_send_client_key_exchange(SSL *s) 177 n += 2; 178 } 179 180- if (s->session->psk_identity_hint != NULL) 181- OPENSSL_free(s->session->psk_identity_hint); 182- s->session->psk_identity_hint = NULL; 183- if (s->ctx->psk_identity_hint) 184- { 185- s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); 186- if (s->ctx->psk_identity_hint != NULL && 187- s->session->psk_identity_hint == NULL) 188- { 189- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, 190- ERR_R_MALLOC_FAILURE); 191- goto psk_err; 192- } 193- } 194- 195 if (s->session->psk_identity != NULL) 196 OPENSSL_free(s->session->psk_identity); 197 s->session->psk_identity = BUF_strdup(identity); 198diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c 199index d6f1a35..c360337 100644 200--- a/ssl/s3_srvr.c 201+++ b/ssl/s3_srvr.c 202@@ -492,7 +492,7 @@ int ssl3_accept(SSL *s) 203 * - the key exchange is kEECDH. 204 */ 205 #ifndef OPENSSL_NO_PSK 206- || ((alg_a & SSL_aPSK) && ((alg_k & SSL_kEECDH) || s->ctx->psk_identity_hint)) 207+ || ((alg_a & SSL_aPSK) && ((alg_k & SSL_kEECDH) || s->session->psk_identity_hint)) 208 #endif 209 #ifndef OPENSSL_NO_SRP 210 /* SRP: send ServerKeyExchange */ 211@@ -1702,6 +1702,10 @@ int ssl3_send_server_key_exchange(SSL *s) 212 int curve_id = 0; 213 BN_CTX *bn_ctx = NULL; 214 #endif 215+#ifndef OPENSSL_NO_PSK 216+ const char* psk_identity_hint; 217+ size_t psk_identity_hint_len; 218+#endif 219 EVP_PKEY *pkey; 220 const EVP_MD *md = NULL; 221 unsigned char *p,*d; 222@@ -1730,9 +1734,12 @@ int ssl3_send_server_key_exchange(SSL *s) 223 if (alg_a & SSL_aPSK) 224 { 225 /* size for PSK identity hint */ 226- n+=2; 227- if (s->ctx->psk_identity_hint) 228- n+=strlen(s->ctx->psk_identity_hint); 229+ psk_identity_hint = s->session->psk_identity_hint; 230+ if (psk_identity_hint) 231+ psk_identity_hint_len = strlen(psk_identity_hint); 232+ else 233+ psk_identity_hint_len = 0; 234+ n+=2+psk_identity_hint_len; 235 } 236 #endif /* !OPENSSL_NO_PSK */ 237 #ifndef OPENSSL_NO_RSA 238@@ -2025,20 +2032,12 @@ int ssl3_send_server_key_exchange(SSL *s) 239 #ifndef OPENSSL_NO_PSK 240 if (alg_a & SSL_aPSK) 241 { 242- if (s->ctx->psk_identity_hint) 243- { 244- /* copy PSK identity hint */ 245- s2n(strlen(s->ctx->psk_identity_hint), p); 246- strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint)); 247- p+=strlen(s->ctx->psk_identity_hint); 248- } 249- else 250+ /* copy PSK identity hint (if provided) */ 251+ s2n(psk_identity_hint_len, p); 252+ if (psk_identity_hint_len > 0) 253 { 254- /* No identity hint is provided. */ 255- *p = 0; 256- p += 1; 257- *p = 0; 258- p += 1; 259+ memcpy(p, psk_identity_hint, psk_identity_hint_len); 260+ p+=psk_identity_hint_len; 261 } 262 } 263 #endif /* OPENSSL_NO_PSK */ 264@@ -2393,17 +2392,6 @@ int ssl3_get_client_key_exchange(SSL *s) 265 goto psk_err; 266 } 267 268- if (s->session->psk_identity_hint != NULL) 269- OPENSSL_free(s->session->psk_identity_hint); 270- s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); 271- if (s->ctx->psk_identity_hint != NULL && 272- s->session->psk_identity_hint == NULL) 273- { 274- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, 275- ERR_R_MALLOC_FAILURE); 276- goto psk_err; 277- } 278- 279 p += i; 280 n -= (i + 2); 281 psk_err = 0; 282diff --git a/ssl/ssl.h b/ssl/ssl.h 283index a7e1455..f044cd1 100644 284--- a/ssl/ssl.h 285+++ b/ssl/ssl.h 286@@ -1441,6 +1441,10 @@ struct ssl_st 287 #endif /* OPENSSL_NO_KRB5 */ 288 289 #ifndef OPENSSL_NO_PSK 290+ /* PSK identity hint is stored here only to enable setting a hint on an SSL object before an 291+ * SSL_SESSION is associated with it. Once an SSL_SESSION is associated with this SSL object, 292+ * the psk_identity_hint from the session takes precedence over this one. */ 293+ char *psk_identity_hint; 294 unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity, 295 unsigned int max_identity_len, unsigned char *psk, 296 unsigned int max_psk_len); 297diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c 298index 3e49cab..cf24292 100644 299--- a/ssl/ssl_lib.c 300+++ b/ssl/ssl_lib.c 301@@ -388,6 +388,13 @@ SSL *SSL_new(SSL_CTX *ctx) 302 CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); 303 304 #ifndef OPENSSL_NO_PSK 305+ s->psk_identity_hint = NULL; 306+ if (ctx->psk_identity_hint) 307+ { 308+ s->psk_identity_hint = BUF_strdup(ctx->psk_identity_hint); 309+ if (s->psk_identity_hint == NULL) 310+ goto err; 311+ } 312 s->psk_client_callback=ctx->psk_client_callback; 313 s->psk_server_callback=ctx->psk_server_callback; 314 #endif 315@@ -648,6 +655,11 @@ void SSL_free(SSL *s) 316 OPENSSL_free(s->alpn_client_proto_list); 317 #endif 318 319+#ifndef OPENSSL_NO_PSK 320+ if (s->psk_identity_hint) 321+ OPENSSL_free(s->psk_identity_hint); 322+#endif 323+ 324 if (s->client_CA != NULL) 325 sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free); 326 327@@ -3361,32 +3373,54 @@ int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) 328 if (s == NULL) 329 return 0; 330 331- if (s->session == NULL) 332- return 1; /* session not created yet, ignored */ 333- 334 if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) 335 { 336 SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG); 337 return 0; 338 } 339- if (s->session->psk_identity_hint != NULL) 340+ 341+ /* Clear hint in SSL and associated SSL_SESSION (if any). */ 342+ if (s->psk_identity_hint != NULL) 343+ { 344+ OPENSSL_free(s->psk_identity_hint); 345+ s->psk_identity_hint = NULL; 346+ } 347+ if (s->session != NULL && s->session->psk_identity_hint != NULL) 348+ { 349 OPENSSL_free(s->session->psk_identity_hint); 350+ s->session->psk_identity_hint = NULL; 351+ } 352+ 353 if (identity_hint != NULL) 354 { 355- s->session->psk_identity_hint = BUF_strdup(identity_hint); 356- if (s->session->psk_identity_hint == NULL) 357- return 0; 358+ /* The hint is stored in SSL and SSL_SESSION with the one in 359+ * SSL_SESSION taking precedence. Thus, if SSL_SESSION is avaiable, 360+ * we store the hint there, otherwise we store it in SSL. */ 361+ if (s->session != NULL) 362+ { 363+ s->session->psk_identity_hint = BUF_strdup(identity_hint); 364+ if (s->session->psk_identity_hint == NULL) 365+ return 0; 366+ } 367+ else 368+ { 369+ s->psk_identity_hint = BUF_strdup(identity_hint); 370+ if (s->psk_identity_hint == NULL) 371+ return 0; 372+ } 373 } 374- else 375- s->session->psk_identity_hint = NULL; 376 return 1; 377 } 378 379 const char *SSL_get_psk_identity_hint(const SSL *s) 380 { 381- if (s == NULL || s->session == NULL) 382+ if (s == NULL) 383 return NULL; 384- return(s->session->psk_identity_hint); 385+ /* The hint is stored in SSL and SSL_SESSION with the one in SSL_SESSION 386+ * taking precedence. */ 387+ if (s->session != NULL) 388+ return(s->session->psk_identity_hint); 389+ return(s->psk_identity_hint); 390 } 391 392 const char *SSL_get_psk_identity(const SSL *s) 393diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c 394index 44268e7..cdd198c 100644 395--- a/ssl/ssl_sess.c 396+++ b/ssl/ssl_sess.c 397@@ -437,6 +437,18 @@ int ssl_get_new_session(SSL *s, int session) 398 } 399 #endif 400 #endif 401+#ifndef OPENSSL_NO_PSK 402+ if (s->psk_identity_hint) 403+ { 404+ ss->psk_identity_hint = BUF_strdup(s->psk_identity_hint); 405+ if (ss->psk_identity_hint == NULL) 406+ { 407+ SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE); 408+ SSL_SESSION_free(ss); 409+ return 0; 410+ } 411+ } 412+#endif 413 } 414 else 415 { 416-- 4172.0.0.526.g5318336 418 419