示例#1
0
SECStatus
SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, 
                                 SSLExtensionType extId,
                                 PRBool *pYes)
{
  /* some decisions derived from SSL_GetChannelInfo */
  sslSocket * sslsocket = NULL;
  PRBool enoughFirstHsDone = PR_FALSE;

  if (!pYes) {
    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    return SECFailure;
  }

  sslsocket = ssl_FindSocket(socket);
  if (!sslsocket) {
    SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension",
             SSL_GETPID(), socket));
    return SECFailure;
  }

  *pYes = PR_FALSE;

  if (sslsocket->firstHsDone) {
    enoughFirstHsDone = PR_TRUE;
  } else if (sslsocket->ssl3.initialized && ssl3_CanFalseStart(sslsocket)) {
    enoughFirstHsDone = PR_TRUE;
  }

  /* according to public API SSL_GetChannelInfo, this doesn't need a lock */
  if (sslsocket->opt.useSecurity && enoughFirstHsDone) {
    if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
      /* now we know this socket went through ssl3_InitState() and
       * ss->xtnData got initialized, which is the only member accessed by
       * ssl3_ExtensionNegotiated();
       * Member xtnData appears to get accessed in functions that handle
       * the handshake (hello messages and extension sending),
       * therefore the handshake lock should be sufficient.
       */
      ssl_GetSSL3HandshakeLock(sslsocket);
      *pYes = ssl3_ExtensionNegotiated(sslsocket, extId);
      ssl_ReleaseSSL3HandshakeLock(sslsocket);
    }
  }

  return SECSuccess;
}
示例#2
0
SECStatus 
SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
{
    sslSocket *      ss;
    SSLChannelInfo   inf;
    sslSessionID *   sid;
    PRBool           enoughFirstHsDone = PR_FALSE;

    if (!info || len < sizeof inf.length) { 
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return SECFailure;
    }

    ss = ssl_FindSocket(fd);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo",
		 SSL_GETPID(), fd));
	return SECFailure;
    }

    memset(&inf, 0, sizeof inf);
    inf.length = PR_MIN(sizeof inf, len);

    if (ss->firstHsDone) {
	enoughFirstHsDone = PR_TRUE;
    } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
	       ssl3_CanFalseStart(ss)) {
	enoughFirstHsDone = PR_TRUE;
    }

    if (ss->opt.useSecurity && enoughFirstHsDone) {
        sid = ss->sec.ci.sid;
	inf.protocolVersion  = ss->version;
	inf.authKeyBits      = ss->sec.authKeyBits;
	inf.keaKeyBits       = ss->sec.keaKeyBits;
	if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
	    inf.cipherSuite           = ss->sec.cipherType | 0xff00;
	    inf.compressionMethod     = ssl_compression_null;
	    inf.compressionMethodName = "N/A";
	} else if (ss->ssl3.initialized) { 	/* SSL3 and TLS */
	    ssl_GetSpecReadLock(ss);
	    /* XXX  The cipher suite should be in the specs and this
	     * function should get it from crSpec rather than from the "hs".
	     * See bug 275744 comment 69.
	     */
	    inf.cipherSuite           = ss->ssl3.hs.cipher_suite;
	    inf.compressionMethod     = ss->ssl3.crSpec->compression_method;
	    ssl_ReleaseSpecReadLock(ss);
	    inf.compressionMethodName =
		ssl_GetCompressionMethodName(inf.compressionMethod);
	}
	if (sid) {
	    inf.creationTime   = sid->creationTime;
	    inf.lastAccessTime = sid->lastAccessTime;
	    inf.expirationTime = sid->expirationTime;
	    if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
	        inf.sessionIDLength = SSL2_SESSIONID_BYTES;
		memcpy(inf.sessionID, sid->u.ssl2.sessionID, 
		       SSL2_SESSIONID_BYTES);
	    } else {
		unsigned int sidLen = sid->u.ssl3.sessionIDLength;
	        sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
	        inf.sessionIDLength = sidLen;
		memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
	    }
	}
    }

    memcpy(info, &inf, inf.length);

    return SECSuccess;
}
示例#3
0
/* NEED LOCKS IN HERE.  */
SECStatus
SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
		   char **ip, char **sp)
{
    sslSocket *ss;
    const char *cipherName;
    PRBool isDes = PR_FALSE;
    PRBool enoughFirstHsDone = PR_FALSE;

    ss = ssl_FindSocket(fd);
    if (!ss) {
	SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
		 SSL_GETPID(), fd));
	return SECFailure;
    }

    if (cp) *cp = 0;
    if (kp0) *kp0 = 0;
    if (kp1) *kp1 = 0;
    if (ip) *ip = 0;
    if (sp) *sp = 0;
    if (op) {
	*op = SSL_SECURITY_STATUS_OFF;
    }

    if (ss->firstHsDone) {
	enoughFirstHsDone = PR_TRUE;
    } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
	       ssl3_CanFalseStart(ss)) {
	enoughFirstHsDone = PR_TRUE;
    }

    if (ss->opt.useSecurity && enoughFirstHsDone) {
	if (ss->version < SSL_LIBRARY_VERSION_3_0) {
	    cipherName = ssl_cipherName[ss->sec.cipherType];
	} else {
	    cipherName = ssl3_cipherName[ss->sec.cipherType];
	}
	PORT_Assert(cipherName);
	if (cipherName) {
            if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;

            if (cp) {
                *cp = PORT_Strdup(cipherName);
            }
        }

	if (kp0) {
	    *kp0 = ss->sec.keyBits;
	    if (isDes) *kp0 = (*kp0 * 7) / 8;
	}
	if (kp1) {
	    *kp1 = ss->sec.secretKeyBits;
	    if (isDes) *kp1 = (*kp1 * 7) / 8;
	}
	if (op) {
	    if (ss->sec.keyBits == 0) {
		*op = SSL_SECURITY_STATUS_OFF;
	    } else if (ss->sec.secretKeyBits < 90) {
		*op = SSL_SECURITY_STATUS_ON_LOW;

	    } else {
		*op = SSL_SECURITY_STATUS_ON_HIGH;
	    }
	}

	if (ip || sp) {
	    CERTCertificate *cert;

	    cert = ss->sec.peerCert;
	    if (cert) {
		if (ip) {
		    *ip = CERT_NameToAscii(&cert->issuer);
		}
		if (sp) {
		    *sp = CERT_NameToAscii(&cert->subject);
		}
	    } else {
		if (ip) {
		    *ip = PORT_Strdup("no certificate");
		}
		if (sp) {
		    *sp = PORT_Strdup("no certificate");
		}
	    }
	}
    }

    return SECSuccess;
}
示例#4
0
/* 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;
}
示例#5
0
/* Gather in a record and when complete, Handle that record.
 * Repeat this until the handshake is complete, 
 * or until application data is available.
 *
 * Returns  1 when the handshake is completed without error, or 
 *                 application data is available.
 * Returns  0 if ssl3_GatherData hits EOF.
 * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
 * Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
 *
 * Called from ssl_GatherRecord1stHandshake       in sslcon.c, 
 *    and from SSL_ForceHandshake in sslsecur.c
 *    and from ssl3_GatherAppDataRecord below (<- DoRecv in sslsecur.c).
 *
 * Caller must hold the recv buf lock.
 */
int
ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
{
    SSL3Ciphertext cText;
    int            rv;
    PRBool         canFalseStart = PR_FALSE;

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    do {
	/* Without this, we may end up wrongly reporting
	 * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
	 * peer while we are waiting to be restarted.
	 */
	ssl_GetSSL3HandshakeLock(ss);
	rv = ss->ssl3.hs.restartTarget == NULL ? SECSuccess : SECFailure;
	ssl_ReleaseSSL3HandshakeLock(ss);
	if (rv != SECSuccess) {
	    PORT_SetError(PR_WOULD_BLOCK_ERROR);
	    return (int) SECFailure;
	}

	/* Treat an empty msgState like a NULL msgState. (Most of the time
	 * when ssl3_HandleHandshake returns SECWouldBlock, it leaves
	 * behind a non-NULL but zero-length msgState).
	 * Test: async_cert_restart_server_sends_hello_request_first_in_separate_record
	 */
	if (ss->ssl3.hs.msgState.buf != NULL) {
	    if (ss->ssl3.hs.msgState.len == 0) {
		ss->ssl3.hs.msgState.buf = NULL;
	    }
	}

	if (ss->ssl3.hs.msgState.buf != NULL) {
	    /* ssl3_HandleHandshake previously returned SECWouldBlock and the
	     * as-yet-unprocessed plaintext of that previous handshake record.
	     * We need to process it now before we overwrite it with the next
	     * handshake record.
	     */
	    rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
	} else {
	    /* bring in the next sslv3 record. */
	    rv = ssl3_GatherData(ss, &ss->gs, flags);
	    if (rv <= 0) {
		return rv;
	    }

	    /* decipher it, and handle it if it's a handshake.
	     * If it's application data, ss->gs.buf will not be empty upon return.
	     * If it's a change cipher spec, alert, or handshake message,
	     * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
	     */
	    cText.type    = (SSL3ContentType)ss->gs.hdr[0];
	    cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
	    cText.buf     = &ss->gs.inbuf;
	    rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
	}
	if (rv < 0) {
	    return ss->recvdCloseNotify ? 0 : rv;
	}

	/* If we kicked off a false start in ssl3_HandleServerHelloDone, break
	 * out of this loop early without finishing the handshake.
	 */
	if (ss->opt.enableFalseStart) {
	    ssl_GetSSL3HandshakeLock(ss);
	    canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher ||
			     ss->ssl3.hs.ws == wait_new_session_ticket) &&
		            ssl3_CanFalseStart(ss);
	    ssl_ReleaseSSL3HandshakeLock(ss);
	}
    } while (ss->ssl3.hs.ws != idle_handshake &&
             !canFalseStart &&
             ss->gs.buf.len == 0);

    ss->gs.readOffset = 0;
    ss->gs.writeOffset = ss->gs.buf.len;
    return 1;
}