/* SSLReadRecord
 *  Attempt to read & decrypt an SSL record.
 *  Record content should be freed using SSLFreeRecord
 */
OSStatus
SSLReadRecord(SSLRecord *rec, SSLContext *ctx)
{   OSStatus        err;

    err=errorTranslate(ctx->recFuncs->read(ctx->recCtx, rec));

    switch(err) {
        case errSecSuccess:
        case errSSLWouldBlock:
            break;
        case errSSLUnexpectedRecord:
            DTLSRetransmit(ctx);
            break;
        case errSSLDecryptionFail:
        case errSSLBadRecordMac:
            /* We never send a Decryption Failed alert, instead we send the BadRecordMac alert */
            /* This is TLS 1.1 compliant - Do it for all protocols versions. */
            /* Except for DTLS where we do not send any alert. */
            if(ctx->isDTLS) {
                /* This will ensure we try to read again before returning to the caller
                   We do NOT want to use errSSLWouldBlock here, as this should only indicate
                   the IO read callback status */
                err=errSSLUnexpectedRecord;
            } else {
                SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
            }
            break;
        case errSSLInternal:
            SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
            break;
        case errSSLRecordOverflow:
            SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
            break;
        case errSSLClosedAbort:
        case errSSLConnectionRefused:
            SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
            break;
        default:
            sslErrorLog("unknown error code returned in SSLReadRecord: %d\n", (int)err);
            SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
            break;
    }

    return err;
}
예제 #2
0
int
SSLProcessCertificateVerify(tls_buffer message, tls_handshake_t ctx)
{   int        err;
    UInt8           hashData[SSL_MAX_DIGEST_LEN];
    size_t          signatureLen;
    tls_buffer       hashDataBuf;
    uint8_t         *charPtr = message.data;
	uint8_t         *endCp = charPtr + message.length;

    tls_signature_and_hash_algorithm    sigAlg = {0,};

    if (sslVersionIsLikeTls12(ctx)) {
        /* Parse the algorithm field added in TLS1.2 */
        if((charPtr+2) > endCp) {
            sslErrorLog("SSLProcessCertificateVerify: msg len error 1\n");
            return errSSLProtocol;
        }
        sigAlg.hash = *charPtr++;
        sigAlg.signature = *charPtr++;
    }

    if ((charPtr + 2) > endCp) {
    	sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
        return errSSLProtocol;
    }

    signatureLen = SSLDecodeSize(charPtr, 2);
    charPtr += 2;
    if ((charPtr + signatureLen) > endCp) {
    	sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n");
        return errSSLProtocol;
    }

    hashDataBuf.data = hashData;
    hashDataBuf.length = SSL_MAX_DIGEST_LEN;

	assert(ctx->sslTslCalls != NULL);
    if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, &hashDataBuf, sigAlg.hash)) != 0)
        goto fail;

    if (sslVersionIsLikeTls12(ctx))
    {
        if(sigAlg.signature==tls_signature_algorithm_RSA) {
            err = sslRsaVerify(&ctx->peerPubKey,
                               sigAlg.hash,
                               hashData,
                               hashDataBuf.length,
                               charPtr,
                               signatureLen);
        } else {
            err = sslRawVerify(&ctx->peerPubKey,
                               hashData,
                               hashDataBuf.length,
                               charPtr,
                               signatureLen);
        }
    } else {
        /* sslRawVerify does the decrypt & compare for us in one shot. */
        err = sslRawVerify(&ctx->peerPubKey,
            hashData,				// data to verify
            hashDataBuf.length,
            charPtr, 		// signature
            signatureLen);
    }

    if(err) {
		SSLFatalSessionAlert(SSL_AlertDecryptError, ctx);
		goto fail;
	}
    err = errSSLSuccess;

fail:
    return err;
}
OSStatus
SSLProcessAlert(SSLRecord rec, SSLContext *ctx)
{   OSStatus            err = errSecSuccess;
    AlertLevel          level;
    AlertDescription    desc;
    uint8_t             *charPtr;
    size_t              remaining;

    if (rec.contents.length % 2 != 0)
    {
		err = SSLFatalSessionAlert(SSL_AlertIllegalParam, ctx);
        if (!err) {
            err = errSSLProtocol;
		}
        return err;
    }

    charPtr = rec.contents.data;
    remaining = rec.contents.length;
	bool fatal = false;

    while (remaining > 0)
    {   level = (AlertLevel)*charPtr++;
        desc = (AlertDescription)*charPtr++;
		sslHdskMsgDebug("alert msg received level %d   desc %d",
			(int)level, (int)desc);
        remaining -= 2;
        SSLLogAlertMsg(desc, false);

        if (level == SSL_AlertLevelFatal) {
			/* explicit fatal errror */
			fatal = true;
            sslErrorLog("***Fatal alert %d received\n", desc);
        }
        SSLDetectCertRejected(ctx, desc);

        switch (desc) {
			/* A number of these are fatal by implication */
            case SSL_AlertUnexpectedMsg:
				err = errSSLPeerUnexpectedMsg;
				fatal = true;
				break;
            case SSL_AlertBadRecordMac:
 				err = errSSLPeerBadRecordMac;
				fatal = true;
				break;
			case SSL_AlertDecryptionFail_RESERVED:
 				err = errSSLPeerDecryptionFail;
				fatal = true;
				break;
            case SSL_AlertRecordOverflow:
 				err = errSSLPeerRecordOverflow;
				fatal = true;
				break;
            case SSL_AlertDecompressFail:
 				err = errSSLPeerDecompressFail;
				fatal = true;
				break;
            case SSL_AlertHandshakeFail:
 				err = errSSLPeerHandshakeFail;
				fatal = true;
				break;
            case SSL_AlertIllegalParam:
 				err = errSSLIllegalParam;
				fatal = true;
				break;
            case SSL_AlertBadCert:
				err = errSSLPeerBadCert;
				break;
            case SSL_AlertUnsupportedCert:
				err = errSSLPeerUnsupportedCert;
				break;
            case SSL_AlertCertRevoked:
				err = errSSLPeerCertRevoked;
				break;
            case SSL_AlertCertExpired:
				err = errSSLPeerCertExpired;
				break;
            case SSL_AlertCertUnknown:
                err = errSSLPeerCertUnknown;
                break;
            case SSL_AlertUnknownCA:
                err = errSSLPeerUnknownCA;
                break;
            case SSL_AlertAccessDenied:
                err = errSSLPeerAccessDenied;
                break;
            case SSL_AlertDecodeError:
                err = errSSLPeerDecodeError;
                break;
            case SSL_AlertDecryptError:
                err = errSSLPeerDecryptError;
                break;
            case SSL_AlertExportRestriction_RESERVED:
                err = errSSLPeerExportRestriction;
                break;
            case SSL_AlertProtocolVersion:
                err = errSSLPeerProtocolVersion;
                break;
            case SSL_AlertInsufficientSecurity:
                err = errSSLPeerInsufficientSecurity;
                break;
            case SSL_AlertInternalError:
                err = errSSLPeerInternalError;
                break;
            case SSL_AlertUserCancelled:
                err = errSSLPeerUserCancelled;
                break;
            case SSL_AlertNoRenegotiation:
                err = errSSLPeerNoRenegotiation;
                break;
			/* unusual cases.... */
            case SSL_AlertCloseNotify:
				/* the clean "we're done" case */
                SSLClose(ctx);
                err = errSecSuccess;
                break;
            case SSL_AlertNoCert_RESERVED:
                if((ctx->state == SSL_HdskStateClientCert) &&
				   (ctx->protocolSide == kSSLServerSide) &&
				   (ctx->clientAuth != kAlwaysAuthenticate)) {
					/*
					 * Tolerate this unless we're configured to
					 * *require* a client cert. If a client cert is
					 * required, we'll catch the error at the next
					 * handshake msg we receive - which will probably
					 * be a client key exchange msg, which is illegal
					 * when we're in state SSL_HdskStateClientCert.
					 * If the client cert is optional, advance to
					 * state ClientKeyExchange by pretending we
					 * just got a client cert msg.
					 */
                    if ((err = SSLAdvanceHandshake(SSL_HdskCert,
							ctx)) != 0) {
                        return err;
					}
				}
                break;
            case SSL_AlertUnsupportedExtension:
                err = errSSLFatalAlert;
                fatal = true;
                break;

            default:
                /* Unknown alert, ignore if not fatal */
				if(level == SSL_AlertLevelFatal) {
					err = errSSLFatalAlert;
				}
				else {
					err = errSecSuccess;
				}
                break;
        }
		if(fatal) {
			/* don't bother processing any more */
			break;
		}
    }
    if(fatal) {
       	SSLDeleteSessionData(ctx);
	}
    return err;
}
OSStatus
SSLProcessChangeCipherSpec(SSLRecord rec, SSLContext *ctx)
{   OSStatus          err;

    if (rec.contents.length != 1 || rec.contents.data[0] != 1)
    {
        if(ctx->isDTLS)
            return errSSLWouldBlock;

        SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx);
    	sslErrorLog("***bad changeCipherSpec msg: length %d data 0x%x\n",
    		(unsigned)rec.contents.length, (unsigned)rec.contents.data[0]);
        return errSSLProtocol;
    }

	/*
	 * Handle PAC-style session resumption, client side only.
	 * In that case, the handshake state was left in either KeyExchange or
	 * Cert.
	 */
	if((ctx->protocolSide == kSSLClientSide) &&
	   (ctx->sessionTicket.length != 0) &&
	   ((ctx->state == SSL_HdskStateKeyExchange) || (ctx->state == SSL_HdskStateCert)) &&
	   (ctx->masterSecretCallback != NULL)) {
		size_t secretLen = SSL_MASTER_SECRET_SIZE;
		sslEapDebug("Client side resuming based on masterSecretCallback");
		ctx->masterSecretCallback(ctx, ctx->masterSecretArg,
			ctx->masterSecret, &secretLen);
		ctx->sessionMatch = 1;

		/* set up selectedCipherSpec */
		if ((err = FindCipherSpec(ctx)) != 0) {
			return err;
		}
		if((err = SSLInitPendingCiphers(ctx)) != 0) {
			SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
			return err;
		}
		SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec);
	}

    if (!ctx->readPending_ready || ctx->state != SSL_HdskStateChangeCipherSpec)
    {
        if(ctx->isDTLS)
            return errSSLWouldBlock;

        SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx);
    	sslErrorLog("***bad changeCipherSpec msg: readPending.ready %d state %d\n",
		(unsigned)ctx->readPending_ready, (unsigned)ctx->state);
        return errSSLProtocol;
    }

    sslLogNegotiateDebug("===Processing changeCipherSpec msg");

    /* Install new cipher spec on read side */
    if ((err = ctx->recFuncs->advanceReadCipher(ctx->recCtx)) != 0)
    {   SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
        return err;
    }
    ctx->readCipher_ready = 0;      /* Can't send data until Finished is sent */
    SSLChangeHdskState(ctx, SSL_HdskStateFinished);
    return errSecSuccess;
}