/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */ int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { int rv = 0; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); rv = PR_FAILURE; goto done; } if (flags) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); rv = ssl_SendSavedWriteData(ss); if (rv >= 0 && ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } } ssl_ReleaseXmitBufLock(ss); if (rv < 0) { goto done; } if (len > 0) ss->writerThread = PR_GetCurrentThread(); /* If any of these is non-zero, the initial handshake is not done. */ if (!ss->firstHsDone) { PRBool canFalseStart = PR_FALSE; ssl_Get1stHandshakeLock(ss); if (ss->version >= SSL_LIBRARY_VERSION_3_0) { ssl_GetSSL3HandshakeLock(ss); if ((ss->ssl3.hs.ws == wait_change_cipher || ss->ssl3.hs.ws == wait_finished || ss->ssl3.hs.ws == wait_new_session_ticket) && ssl3_CanFalseStart(ss)) { canFalseStart = PR_TRUE; } ssl_ReleaseSSL3HandshakeLock(ss); } if (!canFalseStart && (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { ss->writerThread = NULL; goto done; } /* Check for zero length writes after we do housekeeping so we make forward * progress. */ if (len == 0) { rv = 0; goto done; } PORT_Assert(buf != NULL); if (!buf) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } /* Send out the data using one of these functions: * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, * ssl3_SendApplicationData */ ssl_GetXmitBufLock(ss); rv = (*ss->sec.send)(ss, buf, len, flags); ssl_ReleaseXmitBufLock(ss); ss->writerThread = NULL; done: if (rv < 0) { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", SSL_GETPID(), ss->fd, rv, PORT_GetError())); } else { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", SSL_GETPID(), ss->fd, rv)); } 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) { int rv; int amount; int available; ssl_GetRecvBufLock(ss); available = ss->gs.writeOffset - ss->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 = ss->gs.writeOffset - ss->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, ss->gs.buf.buf + ss->gs.readOffset, amount); if (!(flags & PR_MSG_PEEK)) { ss->gs.readOffset += amount; } PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset); 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; }
static void fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced) { CERTCertTrust* trust = NULL; NSSTrust *nssTrust; NSSCryptoContext *context = c->object.cryptoContext; nssCryptokiInstance *instance; NSSUTF8 *stanNick = NULL; /* We are holding the base class object's lock on entry of this function * This lock protects writes to fields of the CERTCertificate . * It is also needed by some functions to compute values such as trust. */ instance = get_cert_instance(c); if (instance) { stanNick = instance->label; } else if (context) { stanNick = c->object.tempName; } /* fill other fields needed by NSS3 functions using CERTCertificate */ if ((!cc->nickname && stanNick) || forced) { PRStatus nssrv; int nicklen, tokenlen, len; NSSUTF8 *tokenName = NULL; char *nick; if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) || (stanNick && PORT_Strchr(stanNick, ':') != NULL))) { tokenName = nssToken_GetName(instance->token); tokenlen = nssUTF8_Size(tokenName, &nssrv); } else { /* don't use token name for internal slot; 3.3 didn't */ tokenlen = 0; } if (stanNick) { nicklen = nssUTF8_Size(stanNick, &nssrv); len = tokenlen + nicklen; nick = PORT_ArenaAlloc(cc->arena, len); if (tokenName) { memcpy(nick, tokenName, tokenlen-1); nick[tokenlen-1] = ':'; memcpy(nick+tokenlen, stanNick, nicklen-1); } else { memcpy(nick, stanNick, nicklen-1); } nick[len-1] = '\0'; cc->nickname = nick; } else { cc->nickname = NULL; } } if (context) { /* trust */ nssTrust = nssCryptoContext_FindTrustForCertificate(context, c); if (!nssTrust) { /* chicken and egg issue: * * c->issuer and c->serial are empty at this point, but * nssTrustDomain_FindTrustForCertificate use them to look up * up the trust object, so we point them to cc->derIssuer and * cc->serialNumber. * * Our caller will fill these in with proper arena copies when we * return. */ c->issuer.data = cc->derIssuer.data; c->issuer.size = cc->derIssuer.len; c->serial.data = cc->serialNumber.data; c->serial.size = cc->serialNumber.len; nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c); } if (nssTrust) { trust = cert_trust_from_stan_trust(nssTrust, cc->arena); if (trust) { /* we should destroy cc->trust before replacing it, but it's allocated in cc->arena, so memory growth will occur on each refresh */ cc->trust = trust; } nssTrust_Destroy(nssTrust); } } else if (instance) { /* slot */ if (cc->slot != instance->token->pk11slot) { if (cc->slot) { PK11_FreeSlot(cc->slot); } cc->slot = PK11_ReferenceSlot(instance->token->pk11slot); } cc->ownSlot = PR_TRUE; /* pkcs11ID */ cc->pkcs11ID = instance->handle; /* trust */ trust = nssTrust_GetCERTCertTrustForCert(c, cc); if (trust) { /* we should destroy cc->trust before replacing it, but it's allocated in cc->arena, so memory growth will occur on each refresh */ cc->trust = trust; } nssCryptokiObject_Destroy(instance); } /* database handle is now the trust domain */ cc->dbhandle = c->object.trustDomain; /* subjectList ? */ /* istemp and isperm are supported in NSS 3.4 */ cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */ cc->isperm = PR_TRUE; /* by default */ /* pointer back */ cc->nssCertificate = c; if (trust) { /* force the cert type to be recomputed to include trust info */ PRUint32 nsCertType = cert_ComputeCertType(cc); /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */ PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32)); PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType); } }