summaryrefslogtreecommitdiffstats
path: root/ssl/s3_clnt.c
diff options
context:
space:
mode:
authorNils Larsch <nils@openssl.org>2006-03-10 23:06:27 +0000
committerNils Larsch <nils@openssl.org>2006-03-10 23:06:27 +0000
commitddac197404f585b8da58df794fc3beb9d08e8cd2 (patch)
treebe75e03f93b8ad8c2cf5e76f58d3b11bb73854ed /ssl/s3_clnt.c
parent0e8e6f19b2919e14c5bb7b645a359b96ad9fc13d (diff)
add initial support for RFC 4279 PSK SSL ciphersuites
PR: 1191 Submitted by: Mika Kousa and Pasi Eronen of Nokia Corporation Reviewed by: Nils Larsch
Diffstat (limited to 'ssl/s3_clnt.c')
-rw-r--r--ssl/s3_clnt.c180
1 files changed, 173 insertions, 7 deletions
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 995c8298b8..237dfb61d9 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -121,6 +121,32 @@
* Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
*
*/
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
#include <stdio.h>
#include "ssl_locl.h"
@@ -266,7 +292,9 @@ int ssl3_connect(SSL *s)
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
/* Check if it is anon DH/ECDH */
- if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+ /* or PSK */
+ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithms & SSL_kPSK))
{
ret=ssl3_get_server_certificate(s);
if (ret <= 0) goto end;
@@ -1043,17 +1071,28 @@ int ssl3_get_key_exchange(SSL *s)
-1,
s->max_cert_list,
&ok);
-
if (!ok) return((int)n);
if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE)
{
+#ifndef OPENSSL_NO_PSK
+ /* In plain PSK ciphersuite, ServerKeyExchange can be
+ omitted if no identity hint is sent. Set
+ session->sess_cert anyway to avoid problems
+ later.*/
+ if (s->s3->tmp.new_cipher->algorithms & SSL_kPSK)
+ {
+ s->session->sess_cert=ssl_sess_cert_new();
+ if (s->ctx->psk_identity_hint)
+ OPENSSL_free(s->ctx->psk_identity_hint);
+ s->ctx->psk_identity_hint = NULL;
+ }
+#endif
s->s3->tmp.reuse_message=1;
return(1);
}
param=p=(unsigned char *)s->init_msg;
-
if (s->session->sess_cert != NULL)
{
#ifndef OPENSSL_NO_RSA
@@ -1087,6 +1126,51 @@ int ssl3_get_key_exchange(SSL *s)
alg=s->s3->tmp.new_cipher->algorithms;
EVP_MD_CTX_init(&md_ctx);
+#ifndef OPENSSL_NO_PSK
+ if (alg & SSL_kPSK)
+ {
+ char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
+
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ n2s(p,i);
+ param_len=i+2;
+ /* Store PSK identity hint for later use, hint is used
+ * in ssl3_send_client_key_exchange. Assume that the
+ * maximum length of a PSK identity hint can be as
+ * long as the maximum length of a PSK identity. */
+ if (i > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+ SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
+ goto f_err;
+ }
+ /* If received PSK identity hint contains NULL
+ * characters, the hint is truncated from the first
+ * NULL. p may not be ending with NULL, so create a
+ * NULL-terminated string. */
+ memcpy(tmp_id_hint, p, i);
+ memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+ if (s->ctx->psk_identity_hint != NULL)
+ OPENSSL_free(s->ctx->psk_identity_hint);
+ s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+ if (s->ctx->psk_identity_hint == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+
+ p+=i;
+ n-=param_len;
+ }
+ else
+#endif /* !OPENSSL_NO_PSK */
#ifndef OPENSSL_NO_RSA
if (alg & SSL_kRSA)
{
@@ -1430,12 +1514,13 @@ int ssl3_get_key_exchange(SSL *s)
}
else
{
- /* still data left over */
- if (!(alg & SSL_aNULL))
+ if (!(alg & SSL_aNULL) && !(alg & SSL_kPSK))
+ /* aNULL or kPSK do not need public keys */
{
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
goto err;
}
+ /* still data left over */
if (n != 0)
{
al=SSL_AD_DECODE_ERROR;
@@ -2104,6 +2189,88 @@ int ssl3_send_client_key_exchange(SSL *s)
EVP_PKEY_free(srvr_pub_pkey);
}
#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_PSK
+ else if (l & SSL_kPSK)
+ {
+ char identity[PSK_MAX_IDENTITY_LEN];
+ unsigned char *t = NULL;
+ unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+ unsigned int pre_ms_len = 0, psk_len = 0;
+ int psk_err = 1;
+
+ n = 0;
+ if (s->psk_client_callback == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_NO_CLIENT_CB);
+ goto err;
+ }
+
+ psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+ identity, PSK_MAX_IDENTITY_LEN,
+ psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_len > PSK_MAX_PSK_LEN)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto psk_err;
+ }
+ else if (psk_len == 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_IDENTITY_NOT_FOUND);
+ goto psk_err;
+ }
+
+ /* create PSK pre_master_secret */
+ pre_ms_len = 2+psk_len+2+psk_len;
+ t = psk_or_pre_ms;
+ memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+ s2n(psk_len, t);
+ memset(t, 0, psk_len);
+ t+=psk_len;
+ s2n(psk_len, t);
+
+ if (s->session->psk_identity_hint != NULL)
+ OPENSSL_free(s->session->psk_identity_hint);
+ s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+ if (s->ctx->psk_identity_hint != NULL &&
+ s->session->psk_identity_hint == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ if (s->session->psk_identity != NULL)
+ OPENSSL_free(s->session->psk_identity);
+ s->session->psk_identity = BUF_strdup(identity);
+ if (s->session->psk_identity == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ s->session->master_key_length =
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ psk_or_pre_ms, pre_ms_len);
+ n = strlen(identity);
+ s2n(n, p);
+ memcpy(p, identity, n);
+ n+=2;
+ psk_err = 0;
+ psk_err:
+ OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
+ OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_err != 0)
+ {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ }
+#endif
else
{
ssl3_send_alert(s, SSL3_AL_FATAL,
@@ -2316,7 +2483,6 @@ int ssl3_check_cert_and_algorithm(SSL *s)
#endif
sc=s->session->sess_cert;
-
if (sc == NULL)
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR);
@@ -2326,7 +2492,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
algs=s->s3->tmp.new_cipher->algorithms;
/* we don't have a certificate */
- if (algs & (SSL_aDH|SSL_aNULL|SSL_aKRB5))
+ if (algs & (SSL_aDH|SSL_aNULL|SSL_aKRB5|SSL_kPSK))
return(1);
#ifndef OPENSSL_NO_RSA