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
This commit is contained in:
Nils Larsch
2006-03-10 23:06:27 +00:00
parent 0e8e6f19b2
commit ddac197404
26 changed files with 1671 additions and 20 deletions

View File

@@ -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