Back to index

lightning-sunbird  0.9+nobinonly
derive.c
Go to the documentation of this file.
00001 /*
00002  * Key Derivation that doesn't use PKCS11
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is the Netscape security libraries.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1994-2005
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 /* $Id: derive.c,v 1.3.2.3 2007/10/31 00:32:54 glen.beasley%sun.com Exp $ */
00040 
00041 #include "ssl.h"     /* prereq to sslimpl.h */
00042 #include "certt.h"   /* prereq to sslimpl.h */
00043 #include "keythi.h"  /* prereq to sslimpl.h */
00044 #include "sslimpl.h"
00045 #include "blapi.h"
00046 
00047 #include "secutil.h"
00048 #include "pk11func.h"
00049 #include "secasn1.h"
00050 #include "cert.h"
00051 #include "secmodt.h"
00052 
00053 #include "sslproto.h"
00054 #include "sslerr.h"
00055 
00056 /* make this a macro! */
00057 #ifdef NOT_A_MACRO
00058 static void
00059 buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result)
00060 {
00061     result->type = siBuffer;
00062     result->data = keyBlock;
00063     result->len  = keyLen;
00064     PRINT_BUF(100, (NULL, "key value", keyBlock, keyLen));
00065 }
00066 #else
00067 #define buildSSLKey(keyBlock, keyLen, result) \
00068 { \
00069     (result)->type = siBuffer; \
00070     (result)->data = keyBlock; \
00071     (result)->len  = keyLen; \
00072     PRINT_BUF(100, (NULL, "key value", keyBlock, keyLen)); \
00073 }
00074 #endif
00075 
00076 /*
00077  * SSL Key generation given pre master secret
00078  */
00079 #ifndef NUM_MIXERS
00080 #define NUM_MIXERS 9
00081 #endif
00082 static const char * const mixers[NUM_MIXERS] = { 
00083     "A", 
00084     "BB", 
00085     "CCC", 
00086     "DDDD", 
00087     "EEEEE", 
00088     "FFFFFF", 
00089     "GGGGGGG",
00090     "HHHHHHHH",
00091     "IIIIIIIII" 
00092 };
00093 
00094 
00095 SECStatus
00096 ssl3_KeyAndMacDeriveBypass(
00097     ssl3CipherSpec *      pwSpec,
00098     const unsigned char * cr,
00099     const unsigned char * sr,
00100     PRBool                isTLS,
00101     PRBool                isExport)
00102 {
00103     const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
00104     unsigned char * key_block    = pwSpec->key_block;
00105     unsigned char * key_block2   = NULL;
00106     unsigned int    block_bytes  = 0;
00107     unsigned int    block_needed = 0;
00108     unsigned int    i;
00109     unsigned int    keySize;            /* actual    size of cipher keys */
00110     unsigned int    effKeySize;           /* effective size of cipher keys */
00111     unsigned int    macSize;              /* size of MAC secret */
00112     unsigned int    IVSize;        /* size of IV */
00113     SECStatus       rv    = SECFailure;
00114     SECStatus       status = SECSuccess;
00115     PRBool          isFIPS = PR_FALSE;
00116 
00117     SECItem         srcr;
00118     SECItem         crsr;
00119 
00120     unsigned char     srcrdata[SSL3_RANDOM_LENGTH * 2];
00121     unsigned char     crsrdata[SSL3_RANDOM_LENGTH * 2];
00122     PRUint64          md5buf[22];
00123     PRUint64          shabuf[40];
00124 
00125 #define md5Ctx ((MD5Context *)md5buf)
00126 #define shaCtx ((SHA1Context *)shabuf)
00127 
00128     static const SECItem zed  = { siBuffer, NULL, 0 };
00129 
00130     if (pwSpec->msItem.data == NULL ||
00131         pwSpec->msItem.len  != SSL3_MASTER_SECRET_LENGTH) {
00132        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00133        return rv;
00134     }
00135 
00136     PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, 
00137                                            pwSpec->msItem.len));
00138 
00139     /* figure out how much is needed */
00140     macSize    = pwSpec->mac_size;
00141     keySize    = cipher_def->key_size;
00142     effKeySize = cipher_def->secret_key_size;
00143     IVSize     = cipher_def->iv_size;
00144     if (keySize == 0) {
00145        effKeySize = IVSize = 0; /* only MACing */
00146     }
00147     block_needed = 2 * (macSize + effKeySize + ((!isExport) * IVSize));
00148 
00149     /*
00150      * clear out our returned keys so we can recover on failure
00151      */
00152     pwSpec->client.write_key_item     = zed;
00153     pwSpec->client.write_mac_key_item = zed;
00154     pwSpec->server.write_key_item     = zed;
00155     pwSpec->server.write_mac_key_item = zed;
00156 
00157     /* initialize the server random, client random block */
00158     srcr.type   = siBuffer;
00159     srcr.data   = srcrdata;
00160     srcr.len    = sizeof srcrdata;
00161     PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH);
00162     PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH);
00163 
00164     /* initialize the client random, server random block */
00165     crsr.type   = siBuffer;
00166     crsr.data   = crsrdata;
00167     crsr.len    = sizeof crsrdata;
00168     PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
00169     PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
00170     PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len));
00171 
00172     /*
00173      * generate the key material:
00174      */
00175     if (isTLS) {
00176        SECItem       keyblk;
00177 
00178        keyblk.type = siBuffer;
00179        keyblk.data = key_block;
00180        keyblk.len  = block_needed;
00181 
00182        status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk,
00183                        isFIPS);
00184        if (status != SECSuccess) {
00185            goto key_and_mac_derive_fail;
00186        }
00187        block_bytes = keyblk.len;
00188     } else {
00189        /* key_block = 
00190         *     MD5(master_secret + SHA('A' + master_secret + 
00191         *                      ServerHello.random + ClientHello.random)) +
00192         *     MD5(master_secret + SHA('BB' + master_secret + 
00193         *                      ServerHello.random + ClientHello.random)) +
00194         *     MD5(master_secret + SHA('CCC' + master_secret + 
00195         *                      ServerHello.random + ClientHello.random)) +
00196         *     [...];
00197         */
00198        int made = 0;
00199        for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) {
00200            unsigned int    outLen;
00201            unsigned char   sha_out[SHA1_LENGTH];
00202 
00203            SHA1_Begin(shaCtx);
00204            SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1);
00205            SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len);
00206            SHA1_Update(shaCtx, srcr.data, srcr.len);
00207            SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
00208            PORT_Assert(outLen == SHA1_LENGTH);
00209 
00210            MD5_Begin(md5Ctx);
00211            MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len);
00212            MD5_Update(md5Ctx, sha_out, outLen);
00213            MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
00214            PORT_Assert(outLen == MD5_LENGTH);
00215            made += MD5_LENGTH;
00216        }
00217        block_bytes = made;
00218     }
00219     PORT_Assert(block_bytes >= block_needed);
00220     PORT_Assert(block_bytes <= sizeof pwSpec->key_block);
00221     PRINT_BUF(100, (NULL, "key block", key_block, block_bytes));
00222 
00223     /*
00224      * Put the key material where it goes.
00225      */
00226     key_block2 = key_block + block_bytes;
00227     i = 0;                  /* now shows how much consumed */
00228 
00229     /* 
00230      * The key_block is partitioned as follows:
00231      * client_write_MAC_secret[CipherSpec.hash_size]
00232      */
00233     buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item);
00234     i += macSize;
00235 
00236     /* 
00237      * server_write_MAC_secret[CipherSpec.hash_size]
00238      */
00239     buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item);
00240     i += macSize;
00241 
00242     if (!keySize) {
00243        /* only MACing */
00244        buildSSLKey(NULL, 0, &pwSpec->client.write_key_item);
00245        buildSSLKey(NULL, 0, &pwSpec->server.write_key_item);
00246        buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item);
00247        buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item);
00248     } else if (!isExport) {
00249        /* 
00250        ** Generate Domestic write keys and IVs.
00251        ** client_write_key[CipherSpec.key_material]
00252        */
00253        buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item);
00254        i += keySize;
00255 
00256        /* 
00257        ** server_write_key[CipherSpec.key_material]
00258        */
00259        buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item);
00260        i += keySize;
00261 
00262        if (IVSize > 0) {
00263            /* 
00264            ** client_write_IV[CipherSpec.IV_size]
00265            */
00266            buildSSLKey(&key_block[i], IVSize, &pwSpec->client.write_iv_item);
00267            i += IVSize;
00268 
00269            /* 
00270            ** server_write_IV[CipherSpec.IV_size]
00271            */
00272            buildSSLKey(&key_block[i], IVSize, &pwSpec->server.write_iv_item);
00273            i += IVSize;
00274        }
00275        PORT_Assert(i <= block_bytes);
00276 
00277     } else if (!isTLS) { 
00278        /*
00279        ** Generate SSL3 Export write keys and IVs.
00280        */
00281        unsigned int    outLen;
00282 
00283        /*
00284        ** client_write_key[CipherSpec.key_material]
00285        ** final_client_write_key = MD5(client_write_key +
00286        **                   ClientHello.random + ServerHello.random);
00287        */
00288        MD5_Begin(md5Ctx);
00289        MD5_Update(md5Ctx, &key_block[i], effKeySize);
00290        MD5_Update(md5Ctx, crsr.data, crsr.len);
00291        MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
00292        i += effKeySize;
00293        buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item);
00294        key_block2 += keySize;
00295 
00296        /*
00297        ** server_write_key[CipherSpec.key_material]
00298        ** final_server_write_key = MD5(server_write_key +
00299        **                    ServerHello.random + ClientHello.random);
00300        */
00301        MD5_Begin(md5Ctx);
00302        MD5_Update(md5Ctx, &key_block[i], effKeySize);
00303        MD5_Update(md5Ctx, srcr.data, srcr.len);
00304        MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
00305        i += effKeySize;
00306        buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item);
00307        key_block2 += keySize;
00308        PORT_Assert(i <= block_bytes);
00309 
00310        if (IVSize) {
00311            /*
00312            ** client_write_IV = 
00313            ** MD5(ClientHello.random + ServerHello.random);
00314            */
00315            MD5_Begin(md5Ctx);
00316            MD5_Update(md5Ctx, crsr.data, crsr.len);
00317            MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
00318            buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item);
00319            key_block2 += IVSize;
00320 
00321            /*
00322            ** server_write_IV = 
00323            ** MD5(ServerHello.random + ClientHello.random);
00324            */
00325            MD5_Begin(md5Ctx);
00326            MD5_Update(md5Ctx, srcr.data, srcr.len);
00327            MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
00328            buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item);
00329            key_block2 += IVSize;
00330        }
00331 
00332        PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
00333     } else {
00334        /*
00335        ** Generate TLS Export write keys and IVs.
00336        */
00337        SECItem       secret ;
00338        SECItem       keyblk ;
00339 
00340        secret.type = siBuffer;
00341        keyblk.type = siBuffer;
00342        /*
00343        ** client_write_key[CipherSpec.key_material]
00344        ** final_client_write_key = PRF(client_write_key, 
00345        **                              "client write key",
00346        **                              client_random + server_random);
00347        */
00348        secret.data = &key_block[i];
00349        secret.len  = effKeySize;
00350        i          += effKeySize;
00351        keyblk.data = key_block2;
00352        keyblk.len  = keySize;
00353        status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS);
00354        if (status != SECSuccess) {
00355            goto key_and_mac_derive_fail;
00356        }
00357        buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item);
00358        key_block2 += keySize;
00359 
00360        /*
00361        ** server_write_key[CipherSpec.key_material]
00362        ** final_server_write_key = PRF(server_write_key,
00363        **                              "server write key",
00364        **                              client_random + server_random);
00365        */
00366        secret.data = &key_block[i];
00367        secret.len  = effKeySize;
00368        i          += effKeySize;
00369        keyblk.data = key_block2;
00370        keyblk.len  = keySize;
00371        status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS);
00372        if (status != SECSuccess) {
00373            goto key_and_mac_derive_fail;
00374        }
00375        buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item);
00376        key_block2 += keySize;
00377 
00378        /*
00379        ** iv_block = PRF("", "IV block", client_random + server_random);
00380        ** client_write_IV[SecurityParameters.IV_size]
00381        ** server_write_IV[SecurityParameters.IV_size]
00382        */
00383        if (IVSize) {
00384            secret.data = NULL;
00385            secret.len  = 0;
00386            keyblk.data = key_block2;
00387            keyblk.len  = 2 * IVSize;
00388            status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS);
00389            if (status != SECSuccess) {
00390               goto key_and_mac_derive_fail;
00391            }
00392            buildSSLKey(key_block2,          IVSize, &pwSpec->client.write_iv_item);
00393            buildSSLKey(key_block2 + IVSize, IVSize, &pwSpec->server.write_iv_item);
00394            key_block2 += 2 * IVSize;
00395        }
00396        PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
00397     }
00398     rv = SECSuccess;
00399 
00400 key_and_mac_derive_fail:
00401 
00402     MD5_DestroyContext(md5Ctx, PR_FALSE);
00403     SHA1_DestroyContext(shaCtx, PR_FALSE);
00404 
00405     if (rv != SECSuccess) {
00406        PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
00407     }
00408 
00409     return rv;
00410 }
00411 
00412 
00413 /* derive the Master Secret from the PMS */
00414 /* Presently, this is only done wtih RSA PMS, and only on the server side,
00415  * so isRSA is always true. 
00416  */
00417 SECStatus
00418 ssl3_MasterKeyDeriveBypass( 
00419     ssl3CipherSpec *      pwSpec,
00420     const unsigned char * cr,
00421     const unsigned char * sr,
00422     const SECItem *       pms,
00423     PRBool                isTLS,
00424     PRBool                isRSA)
00425 {
00426     unsigned char * key_block    = pwSpec->key_block;
00427     SECStatus       rv    = SECSuccess;
00428     PRBool          isFIPS = PR_FALSE;
00429 
00430     SECItem         crsr;
00431 
00432     unsigned char     crsrdata[SSL3_RANDOM_LENGTH * 2];
00433     PRUint64          md5buf[22];
00434     PRUint64          shabuf[40];
00435 
00436 #define md5Ctx ((MD5Context *)md5buf)
00437 #define shaCtx ((SHA1Context *)shabuf)
00438 
00439     /* first do the consistancy checks */
00440     if (isRSA) { 
00441        PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH);
00442        if (pms->len != SSL3_RSA_PMS_LENGTH) {
00443            PORT_SetError(SEC_ERROR_INVALID_ARGS);
00444            return SECFailure;
00445        }
00446        /* caller must test PMS version for rollback */
00447     }
00448 
00449     /* initialize the client random, server random block */
00450     crsr.type   = siBuffer;
00451     crsr.data   = crsrdata;
00452     crsr.len    = sizeof crsrdata;
00453     PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
00454     PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
00455     PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len));
00456 
00457     /* finally do the key gen */
00458     if (isTLS) {
00459        SECItem master = { siBuffer, NULL, 0 };
00460 
00461        master.data = key_block;
00462        master.len = SSL3_MASTER_SECRET_LENGTH;
00463 
00464        rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS);
00465        if (rv != SECSuccess) {
00466            PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
00467        }
00468     } else {
00469        int i;
00470        int made = 0;
00471        for (i = 0; i < 3; i++) {
00472            unsigned int    outLen;
00473            unsigned char   sha_out[SHA1_LENGTH];
00474 
00475            SHA1_Begin(shaCtx);
00476            SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1);
00477            SHA1_Update(shaCtx, pms->data, pms->len);
00478            SHA1_Update(shaCtx, crsr.data, crsr.len);
00479            SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
00480            PORT_Assert(outLen == SHA1_LENGTH);
00481 
00482            MD5_Begin(md5Ctx);
00483            MD5_Update(md5Ctx, pms->data, pms->len);
00484            MD5_Update(md5Ctx, sha_out, outLen);
00485            MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
00486            PORT_Assert(outLen == MD5_LENGTH);
00487            made += outLen;
00488        }
00489     }
00490 
00491     /* store the results */
00492     PORT_Memcpy(pwSpec->raw_master_secret, key_block, 
00493               SSL3_MASTER_SECRET_LENGTH);
00494     pwSpec->msItem.data = pwSpec->raw_master_secret;
00495     pwSpec->msItem.len  = SSL3_MASTER_SECRET_LENGTH;
00496     PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, 
00497                                            pwSpec->msItem.len));
00498 
00499     return rv;
00500 }
00501 
00502 static SECStatus
00503 ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp)
00504 {   SECStatus       rv;
00505     PK11SymKey *    ms = NULL;
00506     SECItem         params = {siBuffer, NULL, 0};
00507     CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
00508     unsigned char   rand[SSL3_RANDOM_LENGTH];
00509     CK_VERSION      pms_version;
00510     CK_MECHANISM_TYPE master_derive;
00511     CK_MECHANISM_TYPE key_derive;
00512     CK_FLAGS          keyFlags;
00513     
00514     if (pms == NULL)
00515        return(SECFailure);
00516 
00517     PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH);
00518 
00519     if (isTLS) {
00520        if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
00521        else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
00522        key_derive    = CKM_TLS_KEY_AND_MAC_DERIVE;
00523        keyFlags      = CKF_SIGN | CKF_VERIFY;
00524     } else {
00525        if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
00526        else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
00527        key_derive    = CKM_SSL3_KEY_AND_MAC_DERIVE;
00528        keyFlags      = 0;
00529     }
00530 
00531     master_params.pVersion                     = &pms_version;
00532     master_params.RandomInfo.pClientRandom     = rand;
00533     master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
00534     master_params.RandomInfo.pServerRandom     = rand;
00535     master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
00536 
00537     params.data = (unsigned char *) &master_params;
00538     params.len  = sizeof master_params;
00539 
00540     ms = PK11_DeriveWithFlags(pms, master_derive, &params, key_derive,
00541                            CKA_DERIVE, 0, keyFlags);
00542     if (ms == NULL)
00543        return(SECFailure);
00544 
00545     rv = PK11_ExtractKeyValue(ms);
00546     *pcbp = (rv == SECSuccess);
00547     PK11_FreeSymKey(ms);
00548     
00549     return(rv);
00550 
00551 }
00552 
00553 /* Check the key exchange algorithm for each cipher in the list to see if
00554  * a master secret key can be extracted. If the KEA will use keys from the 
00555  * specified cert make sure the extract operation is attempted from the slot
00556  * where the private key resides.
00557  * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
00558  * SECSuccess is returned. In all other cases but one (*pcanbypass) is
00559  * set to FALSE and SECFailure is returned.
00560  * In that last case Derive() has been called successfully but the MS is null, 
00561  * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
00562  * arguments were all valid but the slot cannot be bypassed.
00563  */
00564 
00565 SECStatus 
00566 SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
00567              PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
00568               PRBool *pcanbypass, void *pwArg)
00569 {   SECStatus       rv;
00570     int                    i;
00571     PRUint16        suite;
00572     PK11SymKey *      pms = NULL;
00573     SECKEYPublicKey * srvPubkey = NULL;
00574     KeyType         privKeytype;
00575     PK11SlotInfo *    slot = NULL;
00576     SECItem           param;
00577     CK_VERSION             version;
00578     CK_MECHANISM_TYPE mechanism_array[2];
00579     SECItem           enc_pms = {siBuffer, NULL, 0};
00580     PRBool          isTLS = PR_FALSE;
00581     PRBool          isDH = PR_FALSE;
00582     SSLCipherSuiteInfo csdef;
00583     PRBool          extractable;
00584     PRBool          testrsa = PR_FALSE;
00585     PRBool          testrsa_export = PR_FALSE;
00586     PRBool          testecdh = PR_FALSE;
00587     PRBool          testecdhe = PR_FALSE;
00588 
00589     if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
00590        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00591         return SECFailure;
00592     }
00593     
00594     srvPubkey = CERT_ExtractPublicKey(cert);
00595     if (!srvPubkey)
00596         return SECFailure;
00597        
00598     *pcanbypass = PR_TRUE;
00599     rv = SECFailure;
00600     
00601     /* determine which KEAs to test */
00602     for (i=0; i < nsuites && (suite = *ciphersuites++) != NULL; i++) {
00603        /* skip SSL2 cipher suites and ones NSS doesn't support */
00604        if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess
00605            || SSL_IS_SSL2_CIPHER(suite) )
00606            continue;
00607        switch (csdef.keaType) {
00608        case ssl_kea_rsa:
00609            switch (csdef.cipherSuite) {
00610            case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:
00611            case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:
00612            case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
00613            case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
00614               testrsa_export = PR_TRUE;
00615            }
00616            if (!testrsa_export)
00617               testrsa = PR_TRUE;
00618            break;
00619        case ssl_kea_ecdh:
00620            if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
00621               testecdhe = PR_TRUE;
00622            else
00623               testecdh = PR_TRUE;
00624            break;
00625        case ssl_kea_dh:
00626            /* this is actually DHE */
00627        default:
00628            continue;
00629        }
00630     }
00631     
00632     /* For each protocol try to derive and extract an MS.
00633      * Failure of any function except MS extract means
00634      * continue with the next cipher test. Stop testing when the list is
00635      * exhausted or when the first MS extract--not derive--fails.
00636      */
00637     privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
00638     protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0;
00639     while (protocolmask) {
00640        if (protocolmask & SSL_CBP_SSL3) {
00641            isTLS = PR_FALSE;
00642            protocolmask ^= SSL_CBP_SSL3;
00643        } else {
00644            isTLS = PR_TRUE;
00645            protocolmask ^= SSL_CBP_TLS1_0;
00646        }
00647 
00648        if (privKeytype == rsaKey && testrsa_export) {
00649            if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) {
00650               *pcanbypass = PR_FALSE;
00651               rv = SECSuccess;
00652               break;
00653            } else
00654               testrsa = PR_TRUE;
00655        }
00656        for (; privKeytype == rsaKey && testrsa; ) {
00657            /* TLS_RSA */
00658            unsigned char     rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
00659            unsigned int      outLen = 0;
00660            CK_MECHANISM_TYPE target;
00661            SECStatus       irv;
00662            
00663            mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
00664            mechanism_array[1] = CKM_RSA_PKCS;
00665 
00666            slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
00667            if (slot == NULL) {
00668               PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
00669               break;
00670            }
00671 
00672            /* Generate the pre-master secret ...  (client side) */
00673            version.major = 3 /*MSB(clientHelloVersion)*/;
00674            version.minor = 0 /*LSB(clientHelloVersion)*/;
00675            param.data = (unsigned char *)&version;
00676            param.len  = sizeof version;
00677            pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, &param, 0, pwArg);
00678            PK11_FreeSlot(slot);
00679            if (!pms)
00680               break;
00681            /* now wrap it */
00682            enc_pms.len  = SECKEY_PublicKeyStrength(srvPubkey);
00683            enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
00684            irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms);
00685            if (irv != SECSuccess) 
00686               break;
00687            PK11_FreeSymKey(pms);
00688            /* now do the server side--check the triple bypass first */
00689            rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen,
00690                                    sizeof rsaPmsBuf,
00691                                    (unsigned char *)enc_pms.data,
00692                                    enc_pms.len);
00693            /* if decrypt worked we're done with the RSA test */
00694            if (rv == SECSuccess) {
00695               *pcanbypass = PR_TRUE;
00696               break;
00697            }
00698            /* check for fallback to double bypass */
00699            target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE
00700                      : CKM_SSL3_MASTER_KEY_DERIVE;
00701            pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
00702                                    target, CKA_DERIVE, 0);
00703            rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass);
00704            if (rv == SECSuccess && *pcanbypass == PR_FALSE)
00705               goto done;
00706            break;
00707        }
00708 #ifdef NSS_ENABLE_ECC
00709        for (; (privKeytype == ecKey && ( testecdh || testecdhe)) ||
00710               (privKeytype == rsaKey && testecdhe); ) {
00711            CK_MECHANISM_TYPE target;
00712            SECKEYPublicKey  *keapub = NULL;
00713            SECKEYPrivateKey *keapriv;
00714            SECKEYPublicKey  *cpub = NULL; /* client's ephemeral ECDH keys */
00715            SECKEYPrivateKey *cpriv = NULL;
00716            SECKEYECParams    ecParams = { siBuffer, NULL, 0 },
00717                            *pecParams;
00718 
00719            if (privKeytype == ecKey && testecdhe) {
00720               /* TLS_ECDHE_ECDSA */
00721               pecParams = &srvPubkey->u.ec.DEREncodedParams;
00722            } else if (privKeytype == rsaKey && testecdhe) {
00723               /* TLS_ECDHE_RSA */
00724               ECName       ec_curve;
00725               int            serverKeyStrengthInBits;
00726               int            signatureKeyStrength;
00727               int            requiredECCbits;
00728 
00729               /* find a curve of equivalent strength to the RSA key's */
00730               requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
00731               if (requiredECCbits < 0)
00732                   break;
00733               requiredECCbits *= BPB;
00734               serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
00735               if (srvPubkey->u.rsa.modulus.data[0] == 0) {
00736                   serverKeyStrengthInBits--;
00737               }
00738               /* convert to strength in bits */
00739               serverKeyStrengthInBits *= BPB;
00740 
00741               signatureKeyStrength =
00742                   SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
00743 
00744               if ( requiredECCbits > signatureKeyStrength ) 
00745                    requiredECCbits = signatureKeyStrength;
00746 
00747               ec_curve =
00748                   ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK,
00749                                              requiredECCbits);
00750               rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
00751               if (rv == SECFailure) {
00752                   break;
00753               }
00754               pecParams = &ecParams;
00755            }
00756 
00757            if (testecdhe) {
00758               /* generate server's ephemeral keys */
00759               keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); 
00760               if (!keapriv || !keapub) {
00761                   if (keapriv)
00762                      SECKEY_DestroyPrivateKey(keapriv);
00763                   if (keapub)
00764                      SECKEY_DestroyPublicKey(keapub);
00765                   PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
00766                   rv = SECFailure;
00767                   break;
00768               }
00769            } else {
00770               /* TLS_ECDH_ECDSA */
00771               keapub = srvPubkey;
00772               keapriv = srvPrivkey;
00773               pecParams = &srvPubkey->u.ec.DEREncodedParams;
00774            }
00775 
00776            /* perform client side ops */
00777            /* generate a pair of ephemeral keys using server's parms */
00778            cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
00779            if (!cpriv || !cpub) {
00780               if (testecdhe) {
00781                   SECKEY_DestroyPrivateKey(keapriv);
00782                   SECKEY_DestroyPublicKey(keapub);
00783               }
00784               PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
00785               rv = SECFailure;
00786               break;
00787            }
00788            /* now do the server side */
00789            /* determine the PMS using client's public value */
00790            target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH
00791                         : CKM_SSL3_MASTER_KEY_DERIVE_DH;
00792            pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
00793                                 CKM_ECDH1_DERIVE,
00794                                 target,
00795                                 CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
00796            rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass);
00797            SECKEY_DestroyPrivateKey(cpriv);
00798            SECKEY_DestroyPublicKey(cpub);
00799            if (testecdhe) {
00800               SECKEY_DestroyPrivateKey(keapriv);
00801               SECKEY_DestroyPublicKey(keapub);
00802               if (privKeytype == rsaKey)
00803                   PORT_Free(ecParams.data);
00804            }
00805            if (rv == SECSuccess && *pcanbypass == PR_FALSE)
00806               goto done;
00807            break;
00808        }
00809 #endif /* NSS_ENABLE_ECC */
00810        if (pms)
00811            PK11_FreeSymKey(pms);
00812     }
00813 
00814     /* *pcanbypass has been set */
00815     rv = SECSuccess;
00816     
00817   done:
00818     if (pms)
00819        PK11_FreeSymKey(pms);
00820 
00821     SECITEM_FreeItem(&enc_pms, PR_FALSE);
00822 
00823     if (srvPubkey) {
00824        SECKEY_DestroyPublicKey(srvPubkey);
00825        srvPubkey = NULL;
00826     }
00827 
00828 
00829     return rv;
00830 }
00831