Update from 1.0.0-stable.
authorDr. Stephen Henson <steve@openssl.org>
Sun, 31 May 2009 17:13:09 +0000 (17:13 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 31 May 2009 17:13:09 +0000 (17:13 +0000)
ssl/d1_clnt.c
ssl/d1_lib.c
ssl/d1_srvr.c

index 0425af5..2364ad2 100644 (file)
@@ -284,8 +284,9 @@ int dtls1_connect(SSL *s)
 
                case SSL3_ST_CR_CERT_A:
                case SSL3_ST_CR_CERT_B:
-                       /* Check if it is anon DH */
-                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+                       /* Check if it is anon DH or PSK */
+                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+                           !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                                {
                                ret=ssl3_get_server_certificate(s);
                                if (ret <= 0) goto end;
@@ -716,6 +717,14 @@ int dtls1_send_client_key_exchange(SSL *s)
 #ifndef OPENSSL_NO_KRB5
         KSSL_ERR kssl_err;
 #endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_ECDH
+       EC_KEY *clnt_ecdh = NULL;
+       const EC_POINT *srvr_ecpoint = NULL;
+       EVP_PKEY *srvr_pub_pkey = NULL;
+       unsigned char *encodedPoint = NULL;
+       int encoded_pt_len = 0;
+       BN_CTX * bn_ctx = NULL;
+#endif
 
        if (s->state == SSL3_ST_CW_KEY_EXCH_A)
                {
@@ -972,6 +981,274 @@ int dtls1_send_client_key_exchange(SSL *s)
 
                        /* perhaps clean things up a bit EAY EAY EAY EAY*/
                        }
+#endif
+#ifndef OPENSSL_NO_ECDH 
+               else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+                       {
+                       const EC_GROUP *srvr_group = NULL;
+                       EC_KEY *tkey;
+                       int ecdh_clnt_cert = 0;
+                       int field_size = 0;
+
+                       /* Did we send out the client's
+                        * ECDH share for use in premaster
+                        * computation as part of client certificate?
+                        * If so, set ecdh_clnt_cert to 1.
+                        */
+                       if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->cert != NULL)) 
+                               {
+                               /* XXX: For now, we do not support client
+                                * authentication using ECDH certificates.
+                                * To add such support, one needs to add
+                                * code that checks for appropriate 
+                                * conditions and sets ecdh_clnt_cert to 1.
+                                * For example, the cert have an ECC
+                                * key on the same curve as the server's
+                                * and the key should be authorized for
+                                * key agreement.
+                                *
+                                * One also needs to add code in ssl3_connect
+                                * to skip sending the certificate verify
+                                * message.
+                                *
+                                * if ((s->cert->key->privatekey != NULL) &&
+                                *     (s->cert->key->privatekey->type ==
+                                *      EVP_PKEY_EC) && ...)
+                                * ecdh_clnt_cert = 1;
+                                */
+                               }
+
+                       if (s->session->sess_cert->peer_ecdh_tmp != NULL)
+                               {
+                               tkey = s->session->sess_cert->peer_ecdh_tmp;
+                               }
+                       else
+                               {
+                               /* Get the Server Public Key from Cert */
+                               srvr_pub_pkey = X509_get_pubkey(s->session-> \
+                                   sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+                               if ((srvr_pub_pkey == NULL) ||
+                                   (srvr_pub_pkey->type != EVP_PKEY_EC) ||
+                                   (srvr_pub_pkey->pkey.ec == NULL))
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,
+                                           ERR_R_INTERNAL_ERROR);
+                                       goto err;
+                                       }
+
+                               tkey = srvr_pub_pkey->pkey.ec;
+                               }
+
+                       srvr_group   = EC_KEY_get0_group(tkey);
+                       srvr_ecpoint = EC_KEY_get0_public_key(tkey);
+
+                       if ((srvr_group == NULL) || (srvr_ecpoint == NULL))
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,
+                                   ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+
+                       if ((clnt_ecdh=EC_KEY_new()) == NULL) 
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+                               goto err;
+                               }
+
+                       if (!EC_KEY_set_group(clnt_ecdh, srvr_group))
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
+                               goto err;
+                               }
+                       if (ecdh_clnt_cert) 
+                               { 
+                               /* Reuse key info from our certificate
+                                * We only need our private key to perform
+                                * the ECDH computation.
+                                */
+                               const BIGNUM *priv_key;
+                               tkey = s->cert->key->privatekey->pkey.ec;
+                               priv_key = EC_KEY_get0_private_key(tkey);
+                               if (priv_key == NULL)
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+                                       goto err;
+                                       }
+                               if (!EC_KEY_set_private_key(clnt_ecdh, priv_key))
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB);
+                                       goto err;
+                                       }
+                               }
+                       else 
+                               {
+                               /* Generate a new ECDH key pair */
+                               if (!(EC_KEY_generate_key(clnt_ecdh)))
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+                                       goto err;
+                                       }
+                               }
+
+                       /* use the 'p' output buffer for the ECDH key, but
+                        * make sure to clear it out afterwards
+                        */
+
+                       field_size = EC_GROUP_get_degree(srvr_group);
+                       if (field_size <= 0)
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, 
+                                      ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+                       n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
+                       if (n <= 0)
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, 
+                                      ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+
+                       /* generate master key from the result */
+                       s->session->master_key_length = s->method->ssl3_enc \
+                           -> generate_master_secret(s, 
+                               s->session->master_key,
+                               p, n);
+
+                       memset(p, 0, n); /* clean up */
+
+                       if (ecdh_clnt_cert) 
+                               {
+                               /* Send empty client key exch message */
+                               n = 0;
+                               }
+                       else 
+                               {
+                               /* First check the size of encoding and
+                                * allocate memory accordingly.
+                                */
+                               encoded_pt_len = 
+                                   EC_POINT_point2oct(srvr_group, 
+                                       EC_KEY_get0_public_key(clnt_ecdh), 
+                                       POINT_CONVERSION_UNCOMPRESSED, 
+                                       NULL, 0, NULL);
+
+                               encodedPoint = (unsigned char *) 
+                                   OPENSSL_malloc(encoded_pt_len * 
+                                       sizeof(unsigned char)); 
+                               bn_ctx = BN_CTX_new();
+                               if ((encodedPoint == NULL) || 
+                                   (bn_ctx == NULL)) 
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+                                       goto err;
+                                       }
+
+                               /* Encode the public key */
+                               n = EC_POINT_point2oct(srvr_group, 
+                                   EC_KEY_get0_public_key(clnt_ecdh), 
+                                   POINT_CONVERSION_UNCOMPRESSED, 
+                                   encodedPoint, encoded_pt_len, bn_ctx);
+
+                               *p = n; /* length of encoded point */
+                               /* Encoded point will be copied here */
+                               p += 1; 
+                               /* copy the point */
+                               memcpy((unsigned char *)p, encodedPoint, n);
+                               /* increment n to account for length field */
+                               n += 1; 
+                               }
+
+                       /* Free allocated memory */
+                       BN_CTX_free(bn_ctx);
+                       if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+                       if (clnt_ecdh != NULL) 
+                                EC_KEY_free(clnt_ecdh);
+                       EVP_PKEY_free(srvr_pub_pkey);
+                       }
+#endif /* !OPENSSL_NO_ECDH */
+
+#ifndef OPENSSL_NO_PSK
+               else if (alg_k & 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_DTLS1_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_DTLS1_SEND_CLIENT_KEY_EXCHANGE,
+                                       ERR_R_INTERNAL_ERROR);
+                               goto psk_err;
+                               }
+                       else if (psk_len == 0)
+                               {
+                               SSLerr(SSL_F_DTLS1_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_DTLS1_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_DTLS1_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
                        {
@@ -1001,6 +1278,13 @@ int dtls1_send_client_key_exchange(SSL *s)
        /* SSL3_ST_CW_KEY_EXCH_B */
        return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
 err:
+#ifndef OPENSSL_NO_ECDH
+       BN_CTX_free(bn_ctx);
+       if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+       if (clnt_ecdh != NULL) 
+               EC_KEY_free(clnt_ecdh);
+       EVP_PKEY_free(srvr_pub_pkey);
+#endif
        return(-1);
        }
 
@@ -1013,7 +1297,7 @@ int dtls1_send_client_verify(SSL *s)
        unsigned u=0;
 #endif
        unsigned long n;
-#ifndef OPENSSL_NO_DSA
+#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
        int j;
 #endif
 
@@ -1060,6 +1344,23 @@ int dtls1_send_client_verify(SSL *s)
                        n=j+2;
                        }
                else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+                       if (pkey->type == EVP_PKEY_EC)
+                       {
+                       if (!ECDSA_sign(pkey->save_type,
+                               &(data[MD5_DIGEST_LENGTH]),
+                               SHA_DIGEST_LENGTH,&(p[2]),
+                               (unsigned int *)&j,pkey->pkey.ec))
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+                                   ERR_R_ECDSA_LIB);
+                               goto err;
+                               }
+                       s2n(j,p);
+                       n=j+2;
+                       }
+               else
 #endif
                        {
                        SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
index 58ea863..6450c1d 100644 (file)
@@ -203,9 +203,6 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
                {
                if (ciph->algorithm_enc == SSL_RC4)
                        return NULL;
-               /* We currently don't support ECDH either */
-               if (ciph->algorithm_mkey & SSL_kEECDH)
-                       return NULL;
                }
 
        return ciph;
index 638f384..6d6363f 100644 (file)
@@ -311,8 +311,9 @@ int dtls1_accept(SSL *s)
 
                case SSL3_ST_SW_CERT_A:
                case SSL3_ST_SW_CERT_B:
-                       /* Check if it is anon DH */
-                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+                       /* Check if it is anon DH or normal PSK */
+                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+                               && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                                {
                                dtls1_start_timer(s);
                                ret=dtls1_send_server_certificate(s);
@@ -346,7 +347,13 @@ int dtls1_accept(SSL *s)
                        /* only send if a DH key exchange or
                         * RSA but we have a sign only certificate */
                        if (s->s3->tmp.use_rsa_tmp
+                       /* PSK: send ServerKeyExchange if PSK identity
+                        * hint if provided */
+#ifndef OPENSSL_NO_PSK
+                           || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+#endif
                            || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+                           || (alg_k & SSL_kEECDH)
                            || ((alg_k & SSL_kRSA)
                                && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
                                    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
@@ -383,7 +390,10 @@ int dtls1_accept(SSL *s)
                                  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
                                 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
                                 /* never request cert in Kerberos ciphersuites */
-                               (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+                               (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
+                               /* With normal PSK Certificates and
+                                * Certificate Requests are omitted */
+                               || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                                {
                                /* no cert request */
                                skip=1;
@@ -458,15 +468,30 @@ int dtls1_accept(SSL *s)
                        s->state=SSL3_ST_SR_CERT_VRFY_A;
                        s->init_num=0;
 
-                       /* We need to get hashes here so if there is
-                        * a client cert, it can be verified */ 
-                       s->method->ssl3_enc->cert_verify_mac(s,
-                               NID_md5,
-                               &(s->s3->tmp.cert_verify_md[0]));
-                       s->method->ssl3_enc->cert_verify_mac(s,
-                               NID_sha1,
-                               &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+                       if (ret == 2)
+                               {
+                               /* For the ECDH ciphersuites when
+                                * the client sends its ECDH pub key in
+                                * a certificate, the CertificateVerify
+                                * message is not sent.
+                                */
+                               s->state=SSL3_ST_SR_FINISHED_A;
+                               s->init_num = 0;
+                               }
+                       else
+                               {
+                               s->state=SSL3_ST_SR_CERT_VRFY_A;
+                               s->init_num=0;
 
+                               /* We need to get hashes here so if there is
+                                * a client cert, it can be verified */ 
+                               s->method->ssl3_enc->cert_verify_mac(s,
+                                       NID_md5,
+                                       &(s->s3->tmp.cert_verify_md[0]));
+                               s->method->ssl3_enc->cert_verify_mac(s,
+                                       NID_sha1,
+                                       &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+                               }
                        break;
 
                case SSL3_ST_SR_CERT_VRFY_A:
@@ -788,6 +813,13 @@ int dtls1_send_server_key_exchange(SSL *s)
 #endif
 #ifndef OPENSSL_NO_DH
        DH *dh=NULL,*dhp;
+#endif
+#ifndef OPENSSL_NO_ECDH
+       EC_KEY *ecdh=NULL, *ecdhp;
+       unsigned char *encodedPoint = NULL;
+       int encodedlen = 0;
+       int curve_id = 0;
+       BN_CTX *bn_ctx = NULL; 
 #endif
        EVP_PKEY *pkey;
        unsigned char *p,*d;
@@ -897,6 +929,142 @@ int dtls1_send_server_key_exchange(SSL *s)
                        }
                else 
 #endif
+#ifndef OPENSSL_NO_ECDH
+                       if (type & SSL_kEECDH)
+                       {
+                       const EC_GROUP *group;
+
+                       ecdhp=cert->ecdh_tmp;
+                       if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+                               {
+                               ecdhp=s->cert->ecdh_tmp_cb(s,
+                                     SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+                                     SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+                               }
+                       if (ecdhp == NULL)
+                               {
+                               al=SSL_AD_HANDSHAKE_FAILURE;
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+                               goto f_err;
+                               }
+
+                       if (s->s3->tmp.ecdh != NULL)
+                               {
+                               EC_KEY_free(s->s3->tmp.ecdh); 
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+
+                       /* Duplicate the ECDH structure. */
+                       if (ecdhp == NULL)
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+                       if (!EC_KEY_up_ref(ecdhp))
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+                       ecdh = ecdhp;
+
+                       s->s3->tmp.ecdh=ecdh;
+                       if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+                           (EC_KEY_get0_private_key(ecdh) == NULL) ||
+                           (s->options & SSL_OP_SINGLE_ECDH_USE))
+                               {
+                               if(!EC_KEY_generate_key(ecdh))
+                                   {
+                                   SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+                                   goto err;
+                                   }
+                               }
+
+                       if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+                           (EC_KEY_get0_public_key(ecdh)  == NULL) ||
+                           (EC_KEY_get0_private_key(ecdh) == NULL))
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+
+                       if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+                           (EC_GROUP_get_degree(group) > 163)) 
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+                               goto err;
+                               }
+
+                       /* XXX: For now, we only support ephemeral ECDH
+                        * keys over named (not generic) curves. For 
+                        * supported named curves, curve_id is non-zero.
+                        */
+                       if ((curve_id = 
+                           tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
+                           == 0)
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+                               goto err;
+                               }
+
+                       /* Encode the public key.
+                        * First check the size of encoding and
+                        * allocate memory accordingly.
+                        */
+                       encodedlen = EC_POINT_point2oct(group, 
+                           EC_KEY_get0_public_key(ecdh),
+                           POINT_CONVERSION_UNCOMPRESSED, 
+                           NULL, 0, NULL);
+
+                       encodedPoint = (unsigned char *) 
+                           OPENSSL_malloc(encodedlen*sizeof(unsigned char)); 
+                       bn_ctx = BN_CTX_new();
+                       if ((encodedPoint == NULL) || (bn_ctx == NULL))
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+                               goto err;
+                               }
+
+
+                       encodedlen = EC_POINT_point2oct(group, 
+                           EC_KEY_get0_public_key(ecdh), 
+                           POINT_CONVERSION_UNCOMPRESSED, 
+                           encodedPoint, encodedlen, bn_ctx);
+
+                       if (encodedlen == 0) 
+                               {
+                               SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+                               goto err;
+                               }
+
+                       BN_CTX_free(bn_ctx);  bn_ctx=NULL;
+
+                       /* XXX: For now, we only support named (not 
+                        * generic) curves in ECDH ephemeral key exchanges.
+                        * In this situation, we need four additional bytes
+                        * to encode the entire ServerECDHParams
+                        * structure. 
+                        */
+                       n = 4 + encodedlen;
+
+                       /* We'll generate the serverKeyExchange message
+                        * explicitly so we can set these to NULLs
+                        */
+                       r[0]=NULL;
+                       r[1]=NULL;
+                       r[2]=NULL;
+                       r[3]=NULL;
+                       }
+               else 
+#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_PSK
+                       if (type & SSL_kPSK)
+                               {
+                               /* reserve size for record length and PSK identity hint*/
+                               n+=2+strlen(s->ctx->psk_identity_hint);
+                               }
+                       else
+#endif /* !OPENSSL_NO_PSK */
                        {
                        al=SSL_AD_HANDSHAKE_FAILURE;
                        SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
@@ -908,7 +1076,8 @@ int dtls1_send_server_key_exchange(SSL *s)
                        n+=2+nr[i];
                        }
 
-               if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+               if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+                       && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                        {
                        if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
                                == NULL)
@@ -939,6 +1108,41 @@ int dtls1_send_server_key_exchange(SSL *s)
                        p+=nr[i];
                        }
 
+#ifndef OPENSSL_NO_ECDH
+               if (type & SSL_kEECDH) 
+                       {
+                       /* XXX: For now, we only support named (not generic) curves.
+                        * In this situation, the serverKeyExchange message has:
+                        * [1 byte CurveType], [2 byte CurveName]
+                        * [1 byte length of encoded point], followed by
+                        * the actual encoded point itself
+                        */
+                       *p = NAMED_CURVE_TYPE;
+                       p += 1;
+                       *p = 0;
+                       p += 1;
+                       *p = curve_id;
+                       p += 1;
+                       *p = encodedlen;
+                       p += 1;
+                       memcpy((unsigned char*)p, 
+                           (unsigned char *)encodedPoint, 
+                           encodedlen);
+                       OPENSSL_free(encodedPoint);
+                       p += encodedlen;
+                       }
+#endif
+
+#ifndef OPENSSL_NO_PSK
+               if (type & SSL_kPSK)
+                       {
+                       /* copy PSK identity hint */
+                       s2n(strlen(s->ctx->psk_identity_hint), p); 
+                       strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+                       p+=strlen(s->ctx->psk_identity_hint);
+                       }
+#endif
+
                /* not anonymous */
                if (pkey != NULL)
                        {
@@ -991,6 +1195,25 @@ int dtls1_send_server_key_exchange(SSL *s)
                                n+=i+2;
                                }
                        else
+#endif
+#if !defined(OPENSSL_NO_ECDSA)
+                               if (pkey->type == EVP_PKEY_EC)
+                               {
+                               /* let's do ECDSA */
+                               EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+                               EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+                               EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+                               EVP_SignUpdate(&md_ctx,&(d[4]),n);
+                               if (!EVP_SignFinal(&md_ctx,&(p[2]),
+                                       (unsigned int *)&i,pkey))
+                                       {
+                                       SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
+                                       goto err;
+                                       }
+                               s2n(i,p);
+                               n+=i+2;
+                               }
+                       else
 #endif
                                {
                                /* Is this error check actually needed? */
@@ -1018,6 +1241,10 @@ int dtls1_send_server_key_exchange(SSL *s)
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
+#ifndef OPENSSL_NO_ECDH
+       if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+       BN_CTX_free(bn_ctx);
+#endif
        EVP_MD_CTX_cleanup(&md_ctx);
        return(-1);
        }