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 + -
显示快捷键?