sslcon.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,213 行 · 第 1/5 页

C
2,213
字号
/************************************************************************//* Called from ssl2_ServerSetupSessionCypher() *             ssl2_ClientSetupSessionCypher() */static SECStatusssl2_FillInSID(sslSessionID * sid,           int            cipher,	  PRUint8       *keyData, 	  int            keyLen,	  PRUint8       *ca, 	  int            caLen,	  int            keyBits, 	  int            secretKeyBits){    PORT_Assert(sid->references == 1);    PORT_Assert(sid->cached == never_cached);    PORT_Assert(sid->u.ssl2.masterKey.data == 0);    PORT_Assert(sid->u.ssl2.cipherArg.data == 0);    sid->version = SSL_LIBRARY_VERSION_2;    sid->u.ssl2.cipherType = cipher;    sid->u.ssl2.masterKey.data = (PRUint8*) PORT_Alloc(keyLen);    if (!sid->u.ssl2.masterKey.data) {	return SECFailure;    }    PORT_Memcpy(sid->u.ssl2.masterKey.data, keyData, keyLen);    sid->u.ssl2.masterKey.len = keyLen;    sid->u.ssl2.keyBits = keyBits;    sid->u.ssl2.secretKeyBits = secretKeyBits;    if (caLen) {	sid->u.ssl2.cipherArg.data = (PRUint8*) PORT_Alloc(caLen);	if (!sid->u.ssl2.cipherArg.data) {	    return SECFailure;	}	sid->u.ssl2.cipherArg.len = caLen;	PORT_Memcpy(sid->u.ssl2.cipherArg.data, ca, caLen);    }    return SECSuccess;}/*** Construct session keys given the masterKey (tied to the session-id),** the client's challenge and the server's nonce.**** Called from ssl2_CreateSessionCypher() <-*/static SECStatusssl2_ProduceKeys(sslSocket *    ss,             SECItem *      readKey, 	    SECItem *      writeKey,	    SECItem *      masterKey, 	    PRUint8 *      challenge,	    PRUint8 *      nonce, 	    int            cipherType){    PK11Context * cx        = 0;    unsigned      nkm       = 0; /* number of hashes to generate key mat. */    unsigned      nkd       = 0; /* size of readKey and writeKey. */    unsigned      part;    unsigned      i;    unsigned      off;    SECStatus     rv;    PRUint8       countChar;    PRUint8       km[3*16];	/* buffer for key material. */    readKey->data = 0;    writeKey->data = 0;    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    PORT_Assert((ss->sec != 0));    rv = SECSuccess;    cx = PK11_CreateDigestContext(SEC_OID_MD5);    if (cx == NULL) {	ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);	return SECFailure;    }    nkm = ssl_Specs[cipherType].nkm;    nkd = ssl_Specs[cipherType].nkd;    readKey->data = (PRUint8*) PORT_Alloc(nkd);    if (!readKey->data)     	goto loser;    readKey->len = nkd;    writeKey->data = (PRUint8*) PORT_Alloc(nkd);    if (!writeKey->data)     	goto loser;    writeKey->len = nkd;    /* Produce key material */    countChar = '0';    for (i = 0, off = 0; i < nkm; i++, off += 16) {	rv  = PK11_DigestBegin(cx);	rv |= PK11_DigestOp(cx, masterKey->data, masterKey->len);	rv |= PK11_DigestOp(cx, &countChar,      1);	rv |= PK11_DigestOp(cx, challenge,       SSL_CHALLENGE_BYTES);	rv |= PK11_DigestOp(cx, nonce,           SSL_CONNECTIONID_BYTES);	rv |= PK11_DigestFinal(cx, km+off, &part, MD5_LENGTH);	if (rv != SECSuccess) {	    ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);	    rv = SECFailure;	    goto loser;	}	countChar++;    }    /* Produce keys */    PORT_Memcpy(readKey->data,  km,       nkd);    PORT_Memcpy(writeKey->data, km + nkd, nkd);loser:    PK11_DestroyContext(cx, PR_TRUE);    return rv;}/* Called from ssl2_ServerSetupSessionCypher() <- ssl2_HandleClientSessionKeyMessage()                                          <- ssl2_HandleClientHelloMessage() *             ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage() */static SECStatusssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient){    sslSecurityInfo * sec;    sslConnectInfo *  ci;    SECItem         * rk;    SECItem         * wk;    SECItem *         param;    SECStatus         rv;    int               cipherType  = sid->u.ssl2.cipherType;    PK11SlotInfo *    slot        = NULL;    CK_MECHANISM_TYPE mechanism;    SECItem           readKey;    SECItem           writeKey;    void *readcx = 0;    void *writecx = 0;    readKey.data = 0;    writeKey.data = 0;    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    PORT_Assert((ss->sec != 0));    if((ss->sec == 0) || (ss->sec->ci.sid == 0))    	goto sec_loser;	/* don't crash if asserts are off */    /* Trying to cut down on all these switch statements that should be tables.     * So, test cipherType once, here, and then use tables below.      */    switch (cipherType) {    case SSL_CK_RC4_128_EXPORT40_WITH_MD5:    case SSL_CK_RC4_128_WITH_MD5:    case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:    case SSL_CK_RC2_128_CBC_WITH_MD5:    case SSL_CK_DES_64_CBC_WITH_MD5:    case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:	break;    default:	SSL_DBG(("%d: SSL[%d]: ssl2_CreateSessionCypher: unknown cipher=%d",		 SSL_GETPID(), ss->fd, cipherType));	PORT_SetError(isClient ? SSL_ERROR_BAD_SERVER : SSL_ERROR_BAD_CLIENT);	goto loser;    }    sec = ss->sec;    ci = &sec->ci;    rk = isClient ? &readKey  : &writeKey;    wk = isClient ? &writeKey : &readKey;    /* Produce the keys for this session */    rv = ssl2_ProduceKeys(ss, &readKey, &writeKey, &sid->u.ssl2.masterKey,		     ci->clientChallenge, ci->connectionID,		     cipherType);    if (rv != SECSuccess) 	goto loser;    PRINT_BUF(7, (ss, "Session read-key: ", rk->data, rk->len));    PRINT_BUF(7, (ss, "Session write-key: ", wk->data, wk->len));    PORT_Memcpy(ci->readKey, readKey.data, readKey.len);    PORT_Memcpy(ci->writeKey, writeKey.data, writeKey.len);    ci->keySize = readKey.len;    /* Setup the MAC */    rv = ssl2_CreateMAC(sec, rk, wk, cipherType);    if (rv != SECSuccess)     	goto loser;    /* First create the session key object */    SSL_TRC(3, ("%d: SSL[%d]: using %s", SSL_GETPID(), ss->fd,	    ssl_cipherName[cipherType]));    mechanism  = ssl_Specs[cipherType].mechanism;    /* set destructer before we call loser... */    sec->destroy = (void (*)(void*, PRBool)) PK11_DestroyContext;    slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);    if (slot == NULL)	goto loser;    param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);    if (param == NULL)	goto loser;    readcx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,					CKA_DECRYPT, rk, param,					ss->pkcs11PinArg);    SECITEM_FreeItem(param, PR_TRUE);    if (readcx == NULL)	goto loser;    /* build the client context */    param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);    if (param == NULL)	goto loser;    writecx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,					 CKA_ENCRYPT, wk, param,					 ss->pkcs11PinArg);    SECITEM_FreeItem(param,PR_TRUE);    if (writecx == NULL)	goto loser;    PK11_FreeSlot(slot);    rv = SECSuccess;    sec->enc           = (SSLCipher) PK11_CipherOp;    sec->dec           = (SSLCipher) PK11_CipherOp;    sec->readcx        = (void *) readcx;    sec->writecx       = (void *) writecx;    sec->blockSize     = ssl_Specs[cipherType].blockSize;    sec->blockShift    = ssl_Specs[cipherType].blockShift;    sec->cipherType    = sid->u.ssl2.cipherType;    sec->keyBits       = sid->u.ssl2.keyBits;    sec->secretKeyBits = sid->u.ssl2.secretKeyBits;    goto done;  loser:    if (sec->destroy) {	if (readcx)  (*sec->destroy)(readcx, PR_TRUE);	if (writecx) (*sec->destroy)(writecx, PR_TRUE);    }    if (slot) PK11_FreeSlot(slot);  sec_loser:    rv = SECFailure;  done:    SECITEM_ZfreeItem(rk, PR_FALSE);    SECITEM_ZfreeItem(wk, PR_FALSE);    return rv;}/*** Setup the server ciphers given information from a CLIENT-MASTER-KEY** message.** 	"ss"      pointer to the ssl-socket object** 	"cipher"  the cipher type to use** 	"keyBits" the size of the final cipher key** 	"ck"      the clear-key data** 	"ckLen"   the number of bytes of clear-key data** 	"ek"      the encrypted-key data** 	"ekLen"   the number of bytes of encrypted-key data** 	"ca"      the cipher-arg data** 	"caLen"   the number of bytes of cipher-arg data**** The MASTER-KEY is constructed by first decrypting the encrypted-key** data. This produces the SECRET-KEY-DATA. The MASTER-KEY is composed by** concatenating the clear-key data with the SECRET-KEY-DATA. This code** checks to make sure that the client didn't send us an improper amount** of SECRET-KEY-DATA (it restricts the length of that data to match the** spec).**** Called from ssl2_HandleClientSessionKeyMessage().*/static SECStatusssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,			 PRUint8 *ck, unsigned int ckLen,			 PRUint8 *ek, unsigned int ekLen,			 PRUint8 *ca, unsigned int caLen){    PRUint8           *kk;    sslSecurityInfo * sec;    sslSessionID *    sid;    PRUint8       *   kbuf = 0;	/* buffer for RSA decrypted data. */    unsigned int      el1;	/* length of RSA decrypted data in kbuf */    unsigned int      keySize;    unsigned int      modulus;    SECStatus         rv;    PRUint8           mkbuf[SSL_MAX_MASTER_KEY_BYTES];    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    PORT_Assert( ssl_HaveRecvBufLock(ss)   );    PORT_Assert((ss->sec != 0) && (ss->serverKey[kt_rsa] != 0));    sec = ss->sec;    PORT_Assert((sec->ci.sid != 0));    sid = sec->ci.sid;    keySize = (keyBits + 7) >> 3;    /* Is the message just way too big? */    if (keySize > SSL_MAX_MASTER_KEY_BYTES) {	/* bummer */	SSL_DBG(("%d: SSL[%d]: keySize=%d ckLen=%d max session key size=%d",		 SSL_GETPID(), ss->fd, keySize, ckLen,		 SSL_MAX_MASTER_KEY_BYTES));	PORT_SetError(SSL_ERROR_BAD_CLIENT);	goto loser;    }    /* Trying to cut down on all these switch statements that should be tables.     * So, test cipherType once, here, and then use tables below.      */    switch (cipher) {    case SSL_CK_RC4_128_EXPORT40_WITH_MD5:    case SSL_CK_RC4_128_WITH_MD5:    case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:    case SSL_CK_RC2_128_CBC_WITH_MD5:    case SSL_CK_DES_64_CBC_WITH_MD5:    case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:	break;    default:	SSL_DBG(("%d: SSL[%d]: ssl2_ServerSetupSessionCypher: unknown cipher=%d",		 SSL_GETPID(), ss->fd, cipher));	PORT_SetError(SSL_ERROR_BAD_CLIENT);	goto loser;    }    /* For export ciphers, make sure they didn't send too much key data. */    if (ckLen != ssl_Specs[cipher].pubLen) {	SSL_DBG(("%d: SSL[%d]: odd secret key size, keySize=%d ckLen=%d!",		 SSL_GETPID(), ss->fd, keySize, ckLen));	/* Somebody tried to sneak by a strange secret key */	PORT_SetError(SSL_ERROR_BAD_CLIENT);	goto loser;    }    /* allocate the buffer to hold the decrypted portion of the key. */    /* XXX Haven't done any range check on ekLen. */    kbuf = (PRUint8*) PORT_Alloc(ekLen);    if (!kbuf) {	goto loser;    }    /*    ** Decrypt encrypted half of the key. Note that encrypted half has    ** been made to match the modulus size of our public key using    ** PKCS#1. keySize is the real size of the data that is interesting.    ** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is    ** desired behavior here.    */    rv = PK11_PubDecryptRaw(ss->serverKey[kt_rsa], kbuf, &el1, ekLen, ek, ekLen);    if (rv != SECSuccess) 	goto hide_loser;    modulus = PK11_GetPrivateModulusLen(ss->serverKey[kt_rsa]);    if (modulus == -1) {	/* If the key was really bad, then PK11_pubDecryptRaw	 * would have failed, therefore the we must assume that the card	 * is just being a pain and not giving us the modulus... but it	 * should be the same size as the encrypted key length, so use it	 * and keep cranking */	modulus = ekLen;    }    /* Is the length of the decrypted data (el1) the expected value? */    if (modulus != el1) 	goto hide_loser;    /* Cheaply verify that PKCS#1 was used to format the encryption block */    kk = kbuf + modulus - (keySize - ckLen);    if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (kk[-1] != 0x00)) {	/* Tsk tsk. */	SSL_DBG(("%d: SSL[%d]: strange encryption block",		 SSL_GETPID(), ss->fd));	PORT_SetError(SSL_ERROR_BAD_CLIENT);	goto hide_loser;    }    /* Make sure we're not subject to a version rollback attack. */    if (ss->enableSSL3 || ss->enableTLS) {	PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03,			      0x03, 0x03, 0x03, 0x03 };		if (PORT_Memcmp(kk - 8 - 1, threes, 8) == 0) {	    PORT_SetError(SSL_ERROR_BAD_CLIENT);	    goto hide_loser;	}    }    if (0) {hide_loser:	/* Defense against the Bleichenbacher attack.	 * Provide the client with NO CLUES that the decrypted master key	 * was erroneous.  Don't send any error messages.	 * Instead, Generate a completely bogus master key .	 */	PK11_GenerateRandom(kbuf, ekLen);    }    /*    ** Construct master key out of the pieces.    */    if (ckLen) {	PORT_Memcpy(mkbuf, ck, ckLen);    }    PORT_Memcpy(mkbuf+ckLen, kk, keySize-ckLen);    /* Fill in session-id */    rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen,		   keyBits, keyBits - (ckLen<<3));    if (rv != SECSuccess) {	goto loser;    }    /* Create session ciphers */    rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE);    if (rv != SECSuccess) {	goto loser;    }    SSL_TRC(1, ("%d: SSL[%d]: server, using %s cipher, clear=%d total=%d",		SSL_GETPID(), ss->fd, ssl_cipherName[cipher],		ckLen<<3, keySize<<3));    rv = SECSuccess;    goto done;  loser:    rv = SECFailure;  done:    PORT_Free(kbuf);    return rv;}/************************************************************************//*** Rewrite the incoming cipher specs, comparing to list of specs we support,** (ss->cipherSpecs) and eliminating anything we don't support***  Note: Our list may contain SSL v3 ciphers.  

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?