/home/dko/projects/mobilec/trunk/src/security/xyssl-0.7/library/ssl_cli.c

Go to the documentation of this file.
00001 /* SVN FILE INFO
00002  * $Revision: 174 $ : Last Committed Revision
00003  * $Date: 2008-06-24 10:50:29 -0700 (Tue, 24 Jun 2008) $ : Last Committed Date */
00004 /*
00005  *  SSLv3/TLSv1 client-side functions
00006  *
00007  *  Copyright (C) 2006-2007  Christophe Devine
00008  *
00009  *  This library is free software; you can redistribute it and/or
00010  *  modify it under the terms of the GNU Lesser General Public
00011  *  License, version 2.1 as published by the Free Software Foundation.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Lesser General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Lesser General Public
00019  *  License along with this library; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00021  *  MA  02110-1301  USA
00022  */
00023 
00024 #ifndef _CRT_SECURE_NO_DEPRECATE
00025 #define _CRT_SECURE_NO_DEPRECATE 1
00026 #endif
00027 
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <time.h>
00031 
00032 #include "xyssl/ssl.h"
00033 
00034 static int ssl_write_client_hello( ssl_context *ssl )
00035 {
00036     int i, n;
00037     time_t t;
00038     unsigned char *buf, *p;
00039 
00040      md5_starts( &ssl->hs_md5  );
00041     sha1_starts( &ssl->hs_sha1 );
00042 
00043     ssl->major_ver = SSLV3_MAJOR_VERSION;
00044     ssl->minor_ver = SSLV3_MINOR_VERSION;
00045 
00046     /*
00047      *     0  .   0   handshake type
00048      *     1  .   3   handshake length
00049      *     4  .   5   highest version supported
00050      *     6  .   9   current UNIX time
00051      *    10  .  37   random bytes
00052      */
00053     buf = ssl->out_msg;
00054     p = buf + 4;
00055 
00056     *p++ = ssl->max_ver[0] = SSLV3_MAJOR_VERSION;
00057     *p++ = ssl->max_ver[1] = TLS10_MINOR_VERSION;
00058 
00059     t = time( NULL );
00060     *p++ = (unsigned char)( t >> 24 );
00061     *p++ = (unsigned char)( t >> 16 );
00062     *p++ = (unsigned char)( t >>  8 );
00063     *p++ = (unsigned char)( t       );
00064 
00065     for( i = 28; i > 0; i-- )
00066         *p++ = ssl->rng_f( ssl->rng_d );
00067 
00068     memcpy( ssl->randbytes, buf + 6, 32 );
00069 
00070     /*
00071      *    38   .  38    session id length
00072      *    39   .  39+n  session id
00073      *    40+n .  41+n  cipherlist length
00074      *    42+n .  ..    cipherlist
00075      *    ..   .  ..    compression alg. (0)
00076      */
00077     n = ( ssl->sidlen > 0 && ssl->sidlen <= 32 )
00078         ? ssl->sidlen : 0;
00079 
00080     *p++ = n;
00081     for( i = 0; i < n; i++ )
00082         *p++ = ssl->sessid[i];
00083     
00084     for( n = 0; ssl->cipherlist[n] != 0; n++ );
00085     *p++ = ( n >> 7 );
00086     *p++ = ( n << 1 );
00087 
00088     for( i = 0; i < n; i++ )
00089     {
00090         *p++ = ( ssl->cipherlist[i] >> 8 );
00091         *p++ = ( ssl->cipherlist[i]      );
00092     }
00093 
00094     *p++ = 1;
00095     *p++ = SSL_COMPRESS_NULL;
00096 
00097     ssl->out_msglen  = p - buf;
00098     ssl->out_msgtype = SSL_MSG_HANDSHAKE;
00099     ssl->out_msg[0]  = SSL_HS_CLIENT_HELLO;
00100 
00101     ssl->state++;
00102     return( ssl_write_record( ssl, 0 ) );
00103 }
00104 
00105 static int ssl_parse_server_hello( ssl_context *ssl )
00106 {
00107     int ret, i, n;
00108     unsigned char *buf;
00109 
00110     /*
00111      *     0  .   0   handshake type
00112      *     1  .   3   handshake length
00113      *     4  .   5   protocol version
00114      *     6  .   9   UNIX time()
00115      *    10  .  37   random bytes
00116      */
00117     buf = ssl->in_msg;
00118 
00119     if( ( ret = ssl_read_record( ssl, 0 ) ) != 0 )
00120         return( ret );
00121 
00122     if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
00123         return( ERR_SSL_UNEXPECTED_MESSAGE );
00124 
00125     if( ssl->in_hslen < 42 ||
00126         buf[0] != SSL_HS_SERVER_HELLO ||
00127         buf[4] != SSLV3_MAJOR_VERSION )
00128         return( ERR_SSL_BAD_HS_SERVER_HELLO );
00129 
00130     if( buf[5] != SSLV3_MINOR_VERSION &&
00131         buf[5] != TLS10_MINOR_VERSION )
00132         return( ERR_SSL_BAD_HS_SERVER_HELLO );
00133 
00134     ssl->minor_ver = buf[5];
00135 
00136     memcpy( ssl->randbytes + 32, buf + 6, 32 );
00137 
00138     /*
00139      *    38  .  38   session id length
00140      *    39  . 38+n  session id
00141      *   39+n . 40+n  chosen cipher
00142      *   41+n . 41+n  chosen compression alg.
00143      */
00144     n = buf[38];
00145     if( n < 0 || n > 32 || ssl->in_hslen != 42 + n )
00146         return( ERR_SSL_BAD_HS_SERVER_HELLO );
00147 
00148     ssl->cipher = ( (int) buf[39 + n] << 8 )
00149                 | ( (int) buf[40 + n]      );
00150 
00151     if( n > 0 && memcmp( ssl->sessid, buf + 39, n ) == 0 )
00152     {
00153         /*
00154          * Server accepted to resume the session
00155          */
00156         ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
00157         ssl->resumed = 1;
00158         ssl_derive_keys( ssl );
00159     }
00160     else
00161     {
00162         ssl->state++;
00163         ssl->resumed = 0;
00164         ssl->sidlen = n;
00165         memcpy( ssl->sessid, buf + 39, n );
00166     }
00167 
00168     i = 0;
00169     while( 1 )
00170     {
00171         if( ssl->cipherlist[i] == 0 )
00172             return( ERR_SSL_NO_CIPHER_CHOSEN );
00173 
00174         if( ssl->cipherlist[i++] == ssl->cipher )
00175             break;
00176     }
00177 
00178     if( buf[41 + n] != SSL_COMPRESS_NULL )
00179         return( ERR_SSL_BAD_HS_SERVER_HELLO );
00180 
00181     return( 0 );
00182 }
00183 
00184 static int ssl_parse_server_key_exchange( ssl_context *ssl )
00185 {
00186     int ret, n;
00187     unsigned char *p, *end;
00188     unsigned char hash[36];
00189     md5_context md5;
00190     sha1_context sha1;
00191 
00192     if( ssl->cipher != SSL3_EDH_RSA_DES_168_SHA &&
00193         ssl->cipher != TLS1_EDH_RSA_AES_256_SHA )
00194     {
00195         ssl->state++;
00196         return( 0 );
00197     }
00198 
00199 #if defined(NO_DHM)
00200     return( ERR_SSL_FEATURE_UNAVAILABLE );
00201 #else
00202     if( ( ret = ssl_read_record( ssl, 0 ) ) != 0 )
00203         return( ret );
00204 
00205     if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
00206         return( ERR_SSL_UNEXPECTED_MESSAGE );
00207 
00208     if( ssl->in_msg[0] != SSL_HS_SERVER_KEY_EXCHANGE )
00209         return( ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
00210 
00211     /*
00212      * Ephemeral DH parameters:
00213      *
00214      * struct {
00215      *     opaque dh_p<1..2^16-1>;
00216      *     opaque dh_g<1..2^16-1>;
00217      *     opaque dh_Ys<1..2^16-1>;
00218      * } ServerDHParams;
00219      */
00220     p   = ssl->in_msg + 4;
00221     end = ssl->in_msg + ssl->in_hslen;
00222 
00223     if( ( ret = dhm_read_params( &ssl->dhm_ctx, &p, end ) ) != 0 )
00224         return( ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE | ret );
00225 
00226     if( (int)( end - p ) != ssl->peer_cert->rsa.len )
00227         return( ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
00228 
00229     if( ssl->dhm_ctx.len < 64 || ssl->dhm_ctx.len > 256 )
00230         return( ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
00231 
00232     /*
00233      * digitally-signed struct {
00234      *     opaque md5_hash[16];
00235      *     opaque sha_hash[20];
00236      * };
00237      *
00238      * md5_hash
00239      *     MD5(ClientHello.random + ServerHello.random
00240      *                            + ServerParams);
00241      * sha_hash
00242      *     SHA(ClientHello.random + ServerHello.random
00243      *                            + ServerParams);
00244      */
00245     n = ssl->in_hslen - ( end - p ) - 6;
00246 
00247     md5_starts( &md5 );
00248     md5_update( &md5, ssl->randbytes, 64 );
00249     md5_update( &md5, ssl->in_msg + 4, n );
00250     md5_finish( &md5, hash );
00251 
00252     sha1_starts( &sha1 );
00253     sha1_update( &sha1, ssl->randbytes, 64 );
00254     sha1_update( &sha1, ssl->in_msg + 4, n );
00255     sha1_finish( &sha1, hash + 16 );
00256 
00257     n = ssl->peer_cert->rsa.len;
00258     if( ( ret = rsa_pkcs1_verify( &ssl->peer_cert->rsa,
00259                             RSA_RAW, hash, 36, p, n ) ) != 0 )
00260         return( ret );
00261 
00262     ssl->state++;
00263     return( 0 );
00264 #endif
00265 }
00266 
00267 static int ssl_parse_certificate_request( ssl_context *ssl )
00268 {
00269     int ret;
00270 
00271     /*
00272      *     0  .   0   handshake type
00273      *     1  .   3   handshake length
00274      *     4  .   5   SSL version
00275      *     6  .   6   cert type count
00276      *     7  .. n-1  cert types
00277      *     n  .. n+1  length of all DNs
00278      *    n+2 .. n+3  length of DN 1
00279      *    n+4 .. ...  Distinguished Name #1
00280      *    ... .. ...  length of DN 2, etc.
00281      */
00282     if( ( ret = ssl_read_record( ssl, 0 ) ) != 0 )
00283         return( ret );
00284 
00285     if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
00286         return( ERR_SSL_UNEXPECTED_MESSAGE );
00287 
00288     ssl->state++;
00289     ssl->client_auth = 0;
00290 
00291     if( ssl->in_msg[0] == SSL_HS_CERTIFICATE_REQUEST )
00292     {
00293         ssl->client_auth++;
00294         /*
00295          * We may want to continue the handshake, even when
00296          * no client certificate has been configured.
00297          */
00298 #if 0
00299         if( ssl->own_cert == NULL )
00300             return( ERR_SSL_CERTIFICATE_REQUIRED );
00301 
00302         if( ssl->own_key  == NULL )
00303             return( ERR_SSL_PRIVATE_KEY_REQUIRED );
00304 #endif
00305     }
00306 
00307     return( 0 );
00308 }
00309 
00310 static int ssl_parse_server_hello_done( ssl_context *ssl )
00311 {
00312     int ret;
00313 
00314     if( ssl->client_auth != 0 )
00315     {
00316         if( ( ret = ssl_read_record( ssl, 0 ) ) != 0 )
00317             return( ret );
00318 
00319         if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
00320             return( ERR_SSL_UNEXPECTED_MESSAGE );
00321     }
00322 
00323     if( ssl->in_hslen  != 4 ||
00324         ssl->in_msg[0] != SSL_HS_SERVER_HELLO_DONE )
00325         return( ERR_SSL_BAD_HS_SERVER_HELLO_DONE );
00326 
00327     ssl->state++;
00328     return( 0 );
00329 }
00330 
00331 static int ssl_write_client_key_exchange( ssl_context *ssl )
00332 {
00333     int ret, i, n;
00334 
00335     if( ssl->cipher == SSL3_EDH_RSA_DES_168_SHA ||
00336         ssl->cipher == TLS1_EDH_RSA_AES_256_SHA )
00337     {
00338 #if defined(NO_DHM)
00339         return( ERR_SSL_FEATURE_UNAVAILABLE );
00340 #else
00341         /*
00342          * DHM key exchange -- send G^X mod P
00343          */
00344         n = ssl->dhm_ctx.len;
00345 
00346         ssl->out_msg[4] = ( n >> 8 );
00347         ssl->out_msg[5] = ( n      );
00348         i = 6;
00349 
00350         if( ( ret = dhm_make_public( &ssl->dhm_ctx,
00351                                      &ssl->out_msg[i], n,
00352                                       ssl->rng_f,
00353                                       ssl->rng_d  ) ) != 0 )
00354             return( ret );
00355 
00356         ssl->pmslen = ssl->dhm_ctx.len;
00357 
00358         if( ( ret = dhm_calc_secret( &ssl->dhm_ctx,
00359                                       ssl->premaster,
00360                                      &ssl->pmslen ) ) != 0 )
00361             return( ret );
00362 #endif
00363     }
00364     else
00365     {
00366         /*
00367          * RSA key exchange -- send rsa_public(premaster)
00368          */
00369         memcpy( ssl->premaster, ssl->max_ver, 2 );
00370 
00371         ssl->pmslen = 48;
00372 
00373         for( i = 2; i < ssl->pmslen; i++ )
00374             ssl->premaster[i] = ssl->rng_f( ssl->rng_d );
00375 
00376         i = 4;
00377         n = ssl->peer_cert->rsa.len;
00378 
00379         if( ssl->minor_ver != SSLV3_MINOR_VERSION )
00380         {
00381             i += 2;
00382             ssl->out_msg[4] = ( n >> 8 );
00383             ssl->out_msg[5] = ( n      );
00384         }
00385 
00386         ret = rsa_pkcs1_encrypt( &ssl->peer_cert->rsa,
00387                                   ssl->premaster,
00388                                   ssl->pmslen,
00389                                   ssl->out_msg + i, n );
00390         if( ret != 0 )
00391             return( ret );
00392     }
00393 
00394     ssl_derive_keys( ssl );
00395 
00396     ssl->out_msglen  = i + n;
00397     ssl->out_msgtype = SSL_MSG_HANDSHAKE;
00398     ssl->out_msg[0]  = SSL_HS_CLIENT_KEY_EXCHANGE;
00399 
00400     ssl->state++;
00401     return( ssl_write_record( ssl, 0 ) );
00402 }
00403 
00404 static int ssl_write_certificate_verify( ssl_context *ssl )
00405 {
00406     int ret, n;
00407     unsigned char hash[36];
00408 
00409     if( ssl->client_auth == 0 || ssl->own_key == NULL )
00410     {
00411         ssl->state++;
00412         return( 0 );
00413     }
00414 
00415     /*
00416      * Make an RSA signature of the handshake digests
00417      */
00418     ssl_calc_verify( ssl, hash );
00419 
00420     n = ssl->own_key->len;
00421     ssl->out_msg[4] = ( n >> 8 );
00422     ssl->out_msg[5] = ( n      );
00423 
00424     if( ( ret = rsa_pkcs1_sign( ssl->own_key, RSA_RAW, hash, 36,
00425                                 ssl->out_msg + 6, n ) ) != 0 )
00426         return( ret );
00427 
00428     ssl->out_msglen  = 6 + n;
00429     ssl->out_msgtype = SSL_MSG_HANDSHAKE;
00430     ssl->out_msg[0]  = SSL_HS_CERTIFICATE_VERIFY;
00431 
00432     ssl->state++;
00433     return( ssl_write_record( ssl, 0 ) );
00434 }
00435 
00436 static const char _ssl_cli_src[] = "_ssl_cli_src";
00437 
00438 /*
00439  * SSL handshake -- client side
00440  */
00441 int ssl_client_start( ssl_context *ssl )
00442 {
00443     int ret = ssl_flush_output( ssl );
00444 
00445     while( ret == 0 )
00446     {
00447         switch( ssl->state )
00448         {
00449         case SSL_HELLO_REQUEST:
00450             ssl->state = SSL_CLIENT_HELLO;
00451             break;
00452 
00453         /*
00454          *  ==>   ClientHello
00455          */
00456         case SSL_CLIENT_HELLO:
00457             ret = ssl_write_client_hello( ssl );
00458             break;
00459 
00460         /*
00461          *  <==   ServerHello
00462          *        Certificate
00463          *      ( ServerKeyExchange  )
00464          *      ( CertificateRequest )
00465          *        ServerHelloDone
00466          */
00467         case SSL_SERVER_HELLO:
00468             ret = ssl_parse_server_hello( ssl );
00469             break;
00470 
00471         case SSL_SERVER_CERTIFICATE:
00472             ret = ssl_parse_certificate( ssl );
00473             break;
00474 
00475         case SSL_SERVER_KEY_EXCHANGE:
00476             ret = ssl_parse_server_key_exchange( ssl );
00477             break;
00478 
00479         case SSL_CERTIFICATE_REQUEST:
00480             ret = ssl_parse_certificate_request( ssl );
00481             break;
00482 
00483         case SSL_SERVER_HELLO_DONE:
00484             ret = ssl_parse_server_hello_done( ssl );
00485             break;
00486 
00487         /*
00488          *  ==> ( Certificate/Alert  )
00489          *        ClientKeyExchange
00490          *      ( CertificateVerify  )
00491          *        ChangeCipherSpec
00492          *        Finished
00493          */
00494         case SSL_CLIENT_CERTIFICATE:
00495             ret = ssl_write_certificate( ssl );
00496             break;
00497 
00498         case SSL_CLIENT_KEY_EXCHANGE:
00499             ret = ssl_write_client_key_exchange( ssl );
00500             break;
00501 
00502         case SSL_CERTIFICATE_VERIFY:
00503             ret = ssl_write_certificate_verify( ssl );
00504             break;
00505 
00506         case SSL_CLIENT_CHANGE_CIPHER_SPEC:
00507             ret = ssl_write_change_cipher_spec( ssl );
00508             break;
00509 
00510         case SSL_CLIENT_FINISHED:
00511             ret = ssl_write_finished( ssl );
00512             break;
00513 
00514         /*
00515          *  <==   ChangeCipherSpec
00516          *        Finished
00517          */
00518         case SSL_SERVER_CHANGE_CIPHER_SPEC:
00519             ret = ssl_parse_change_cipher_spec( ssl );
00520             break;
00521 
00522         case SSL_SERVER_FINISHED:
00523             ret = ssl_parse_finished( ssl );
00524             break;
00525 
00526         default:
00527             return( 0 );
00528         }
00529     }
00530 
00531     return( ret );
00532 }

Generated on Tue Jul 1 15:29:59 2008 for Mobile-C by  doxygen 1.5.4