sslsecur.c

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

C
1,378
字号
	if (rv < 0) {	    return rv;	} 	if (rv < len) {	    /* UGH !! This shifts the whole buffer down by copying it, and 	    ** it depends on PORT_Memmove doing overlapping moves correctly!	    ** It should advance the pointer offset instead !!	    */	    PORT_Memmove(buf->buf, buf->buf + rv, len - rv);	    buf->len = len - rv;	} else {	    buf->len = 0;    	}    }    return rv;}/************************************************************************//*** Receive some application data on a socket.  Reads SSL records from the input** stream, decrypts them and then copies them to the output buffer.** Called from ssl_SecureRecv() below.**** Caller does NOT hold 1stHandshakeLock because that handshake is over.** Caller doesn't call this until initial handshake is complete.** For SSLv2, there is no subsequent handshake.** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake** messages from a subsequent handshake.**** This code is similar to, and easily confused with, **   ssl_GatherRecord1stHandshake() in sslcon.c*/static int DoRecv(sslSocket *ss, unsigned char *out, int len, int flags){    sslGather *      gs;    int              rv;    int              amount;    int              available;    ssl_GetRecvBufLock(ss);    PORT_Assert((ss->sec != 0) && (ss->gather != 0));    gs = ss->gather;    available = gs->writeOffset - gs->readOffset;    if (available == 0) {	/* Get some more data */	if (ss->version >= SSL_LIBRARY_VERSION_3_0) {	    /* Wait for application data to arrive.  */	    rv = ssl3_GatherAppDataRecord(ss, 0);	} else {	    /* See if we have a complete record */	    rv = ssl2_GatherRecord(ss, 0);	}	if (rv <= 0) {	    if (rv == 0) {		/* EOF */		SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF",			     SSL_GETPID(), ss->fd));		goto done;	    }	    if ((rv != SECWouldBlock) && 	        (PR_GetError() != PR_WOULD_BLOCK_ERROR)) {		/* Some random error */		goto done;	    }	    /*	    ** Gather record is blocked waiting for more record data to	    ** arrive. Try to process what we have already received	    */	} else {	    /* Gather record has finished getting a complete record */	}	/* See if any clear data is now available */	available = gs->writeOffset - gs->readOffset;	if (available == 0) {	    /*	    ** No partial data is available. Force error code to	    ** EWOULDBLOCK so that caller will try again later. Note	    ** that the error code is probably EWOULDBLOCK already,	    ** but if it isn't (for example, if we received a zero	    ** length record) then this will force it to be correct.	    */	    PORT_SetError(PR_WOULD_BLOCK_ERROR);	    rv = SECFailure;	    goto done;	}	SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d",		     SSL_GETPID(), ss->fd, available));    }    /* Dole out clear data to reader */    amount = PR_MIN(len, available);    PORT_Memcpy(out, gs->buf.buf + gs->readOffset, amount);    if (!(flags & MSG_PEEK)) {	gs->readOffset += amount;    }    rv = amount;    SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",		 SSL_GETPID(), ss->fd, amount, available));    PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount));done:    ssl_ReleaseRecvBufLock(ss);    return rv;}/************************************************************************/SSLKEATypessl_FindCertKEAType(CERTCertificate * cert){  SSLKEAType keaType = kt_null;   int tag;    if (!cert) goto loser;    tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));    switch (tag) {  case SEC_OID_X500_RSA_ENCRYPTION:  case SEC_OID_PKCS1_RSA_ENCRYPTION:    keaType = kt_rsa;    break;  case SEC_OID_MISSI_KEA_DSS_OLD:  case SEC_OID_MISSI_KEA_DSS:  case SEC_OID_MISSI_DSS_OLD:  case SEC_OID_MISSI_DSS:    keaType = kt_fortezza;    break;  case SEC_OID_X942_DIFFIE_HELMAN_KEY:    keaType = kt_dh;    break;  default:    keaType = kt_null;  }   loser:    return keaType;}/* XXX need to protect the data that gets changed here.!! */SECStatusSSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,		       SECKEYPrivateKey *key, SSL3KEAType kea){    int rv;    sslSocket *ss;    sslSecurityInfo *sec;    ss = ssl_FindSocket(fd);    if ((rv = ssl_CreateSecurityInfo(ss)) != 0) {	return((SECStatus)rv);    }    sec = ss->sec;    if (sec == NULL) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    /* Both key and cert must have a value or be NULL */    /* Passing a value of NULL will turn off key exchange algorithms that were     * previously turned on */    if (!cert != !key) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    /* make sure the key exchange is recognized */    if ((kea > kt_kea_size) || (kea < kt_null)) {	PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);	return SECFailure;    }    if (kea != ssl_FindCertKEAType(cert)) {    	PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);	return SECFailure;    }    /* load the server certificate */    if (ss->serverCert[kea] != NULL)	CERT_DestroyCertificate(ss->serverCert[kea]);    if (cert) {	ss->serverCert[kea] = CERT_DupCertificate(cert);	if (ss->serverCert[kea] == NULL)	    goto loser;    } else ss->serverCert[kea] = NULL;    /* load the server cert chain */    if (ss->serverCertChain[kea] != NULL)	CERT_DestroyCertificateList(ss->serverCertChain[kea]);    if (cert) {	ss->serverCertChain[kea] = CERT_CertChainFromCert(			    ss->serverCert[kea], certUsageSSLServer, PR_TRUE);	if (ss->serverCertChain[kea] == NULL)	     goto loser;    } else ss->serverCertChain[kea] = NULL;    /* Only do this once because it's global. */    if (ssl3_server_ca_list == NULL)	ssl3_server_ca_list = CERT_GetSSLCACerts(ss->dbHandle);    /* load the private key */    if (ss->serverKey[kea] != NULL)	SECKEY_DestroyPrivateKey(ss->serverKey[kea]);    if (key) {	ss->serverKey[kea] = SECKEY_CopyPrivateKey(key);	if (ss->serverKey[kea] == NULL)	    goto loser;    } else ss->serverKey[kea] = NULL;    if (kea == kt_rsa) {        rv = ssl3_CreateRSAStepDownKeys(ss);	if (rv != SECSuccess) {	    return SECFailure;	/* err set by ssl3_CreateRSAStepDownKeys */	}    }    return SECSuccess;loser:    if (ss->serverCert[kea] != NULL) {	CERT_DestroyCertificate(ss->serverCert[kea]);	ss->serverCert[kea] = NULL;    }    if (ss->serverCertChain != NULL) {	CERT_DestroyCertificateList(ss->serverCertChain[kea]);	ss->serverCertChain[kea] = NULL;    }    if (ss->serverKey[kea] != NULL) {	SECKEY_DestroyPrivateKey(ss->serverKey[kea]);	ss->serverKey[kea] = NULL;    }    return SECFailure;}/************************************************************************/SECStatusssl_CreateSecurityInfo(sslSocket *ss){    sslSecurityInfo * sec  = (sslSecurityInfo *)0;    sslGather *       gs   = (sslGather *      )0;    int               rv;    unsigned char     padbuf[MAX_BLOCK_CYPHER_SIZE];    if (ss->sec) {	return SECSuccess;    }    /* Force the global RNG to generate some random data that we never use */    PK11_GenerateRandom(padbuf, sizeof padbuf);    ss->sec = sec = (sslSecurityInfo*) PORT_ZAlloc(sizeof(sslSecurityInfo));    if (!sec) {	goto loser;    }    /* initialize sslv2 socket to send data in the clear. */    ssl2_UseClearSendFunc(ss);    sec->blockSize  = 1;    sec->blockShift = 0;    ssl_GetRecvBufLock(ss);    if ((gs = ss->gather) == 0) {	ss->gather = gs = ssl_NewGather();	if (!gs) {	    goto loser;	}    }    rv = sslBuffer_Grow(&gs->buf, 4096);    if (rv) {	goto loser;    }    ssl_ReleaseRecvBufLock(ss);    ssl_GetXmitBufLock(ss);    rv = sslBuffer_Grow(&sec->writeBuf, 4096);    if (rv) {	goto loser;    }    ssl_ReleaseXmitBufLock(ss);    SSL_TRC(5, ("%d: SSL[%d]: security info created", SSL_GETPID(), ss->fd));    return SECSuccess;  loser:    if (sec) {	PORT_Free(sec);	ss->sec = sec = (sslSecurityInfo *)0;    }    if (gs) {    	ssl_DestroyGather(gs);	ss->gather = gs = (sslGather *)0;    }    return SECFailure;}/* XXX We should handle errors better in this function. *//* This function assumes that none of the pointers in ss need to be ** freed.*/SECStatusssl_CopySecurityInfo(sslSocket *ss, sslSocket *os){    sslSecurityInfo *sec, *osec;    int rv;    rv = ssl_CreateSecurityInfo(ss);    if (rv < 0) {	goto loser;    }    sec = ss->sec;    osec = os->sec;    sec->send 		= osec->send;    sec->isServer 	= osec->isServer;    sec->keyBits    	= osec->keyBits;    sec->secretKeyBits 	= osec->secretKeyBits;    sec->peerCert   	= CERT_DupCertificate(osec->peerCert);    sec->cache      	= osec->cache;    sec->uncache    	= osec->uncache;    /* we don't dup the connection info. */    sec->sendSequence 	= osec->sendSequence;    sec->rcvSequence 	= osec->rcvSequence;    if (osec->hash && osec->hashcx) {	sec->hash 	= osec->hash;	sec->hashcx 	= osec->hash->clone(osec->hashcx);    } else {	sec->hash 	= NULL;	sec->hashcx 	= NULL;    }    SECITEM_CopyItem(0, &sec->sendSecret, &osec->sendSecret);    SECITEM_CopyItem(0, &sec->rcvSecret,  &osec->rcvSecret);    PORT_Assert(osec->readcx  == 0);    sec->readcx     	= osec->readcx;	/* XXX wrong if readcx  != 0 */    PORT_Assert(osec->writecx == 0);    sec->writecx    	= osec->writecx; /* XXX wrong if writecx != 0 */    sec->destroy    	= 0;		 /* XXX wrong if either cx != 0*/    sec->enc        	= osec->enc;    sec->dec        	= osec->dec;    sec->blockShift 	= osec->blockShift;    sec->blockSize  	= osec->blockSize;    return SECSuccess;loser:    return SECFailure;}/*** Called from SSL_ResetHandshake (above), and **        from ssl_FreeSocket     in sslsock.c*/void ssl_DestroySecurityInfo(sslSecurityInfo *sec){    if (sec != 0) {	/* Destroy MAC */	if (sec->hash && sec->hashcx) {	    (*sec->hash->destroy)(sec->hashcx, PR_TRUE);	    sec->hashcx = 0;	}	SECITEM_ZfreeItem(&sec->sendSecret, PR_FALSE);	SECITEM_ZfreeItem(&sec->rcvSecret, PR_FALSE);	/* Destroy ciphers */	if (sec->destroy) {	    (*sec->destroy)(sec->readcx, PR_TRUE);	    (*sec->destroy)(sec->writecx, PR_TRUE);	} else {	    PORT_Assert(sec->readcx == 0);	    PORT_Assert(sec->writecx == 0);	}	sec->readcx = 0;	sec->writecx = 0;	/* etc. */	PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space);	sec->writeBuf.buf = 0;	CERT_DestroyCertificate(sec->peerCert);	sec->peerCert = NULL;	PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space);	if (sec->ci.sid != NULL) {	    ssl_FreeSID(sec->ci.sid);	}	PORT_ZFree(sec, sizeof *sec);    }}/************************************************************************/int ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa){    PRFileDesc *osfd = ss->fd->lower;    int rv;    PORT_Assert(ss->sec != 0);    /* First connect to server */    rv = osfd->methods->connect(osfd, sa, ss->cTimeout);    if (rv < 0) {	int olderrno = PR_GetError();	SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d",		 SSL_GETPID(), ss->fd, olderrno));	if ((olderrno == PR_IS_CONNECTED_ERROR) ||	    (olderrno == PR_IN_PROGRESS_ERROR)) {	    /*	    ** Connected or trying to connect.  Caller is Using a non-blocking	    ** connect. Go ahead and set things up.	    */	} else {	    return rv;	}    }    SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, setting up handshake",		SSL_GETPID(), ss->fd));    if ( ss->handshakeAsServer ) {	ss->securityHandshake = ssl2_BeginServerHandshake;    } else {	ss->securityHandshake = ssl2_BeginClientHandshake;    }        return rv;}intssl_SecureSocksConnect(sslSocket *ss, const PRNetAddr *sa){    int rv;

⌨️ 快捷键说明

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