int tls_record_decrypt(tls_record_t ctx, const tls_buffer input, tls_buffer *output, uint8_t *contentType) { int err; tls_buffer cipherFragment; uint8_t *charPtr; uint64_t seqNum; uint8_t ct; charPtr=input.data; check(input.length>=header_size(ctx)); if(input.length<header_size(ctx)) return errSSLRecordParam; ct = *charPtr++; #if 0 // We dont actually check the record protocol version tls_protocol_version pv; pv = SSLDecodeInt(charPtr, 2); #endif charPtr+=2; if(ctx->isDTLS) { seqNum = SSLDecodeUInt64(charPtr, 8); charPtr+=8; } cipherFragment.length = SSLDecodeInt(charPtr, 2); charPtr+=2; cipherFragment.data = charPtr; #if 0 // This is too strict for the record layer. if (ct < tls_record_type_V3_Smallest || ct > tls_record_type_V3_Largest) return errSSLRecordProtocol; if ((ctx->negProtocolVersion != tls_protocol_version_Undertermined) && (pv != ctx->negProtocolVersion)) { sslErrorLog("invalid record protocol version, expected = %04x, received = %04x", ctx->negProtocolVersion, pv); return errSSLRecordProtocol; // Invalid record version ? } #endif check(input.length>=header_size(ctx)+cipherFragment.length); if(input.length<header_size(ctx)+cipherFragment.length) { return errSSLRecordParam; // input buffer not enough data } if(ctx->isDTLS) { /* if the epoch of the record is different of current read cipher, just drop it */ if((seqNum>>48)!=(ctx->readCipher.sequenceNum>>48)) { return errSSLRecordUnexpectedRecord; } else { ctx->readCipher.sequenceNum=seqNum; } }
static int SSLRecordReadInternal(SSLRecordContextRef ref, SSLRecord *rec) { int err; size_t len, contentLen; uint8_t *charPtr; SSLBuffer readData, cipherFragment; size_t head=5; int skipit=0; struct SSLRecordInternalContext *ctx = ref; if(ctx->isDTLS) head+=8; if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < head) { if (ctx->partialReadBuffer.data) if ((err = SSLFreeBuffer(&ctx->partialReadBuffer)) != 0) { return err; } if ((err = SSLAllocBuffer(&ctx->partialReadBuffer, DEFAULT_BUFFER_SIZE)) != 0) { return err; } } if (ctx->negProtocolVersion == SSL_Version_Undetermined) { if (ctx->amountRead < 1) { readData.length = 1 - ctx->amountRead; readData.data = ctx->partialReadBuffer.data + ctx->amountRead; len = readData.length; err = sslIoRead(readData, &len, ctx); if(err != 0) { if (err == errSSLRecordWouldBlock) { ctx->amountRead += len; return err; } else { /* abort */ err = errSSLRecordClosedAbort; #if 0 // TODO: revisit this in the transport layer if((ctx->protocolSide == kSSLClientSide) && (ctx->amountRead == 0) && (len == 0)) { /* * Detect "server refused to even try to negotiate" * error, when the server drops the connection before * sending a single byte. */ switch(ctx->state) { case SSL_HdskStateServerHello: sslHdskStateDebug("Server dropped initial connection\n"); err = errSSLConnectionRefused; break; default: break; } } #endif return err; } } ctx->amountRead += len; } } if (ctx->amountRead < head) { readData.length = head - ctx->amountRead; readData.data = ctx->partialReadBuffer.data + ctx->amountRead; len = readData.length; err = sslIoRead(readData, &len, ctx); if(err != 0) { switch(err) { case errSSLRecordWouldBlock: ctx->amountRead += len; break; #if SSL_ALLOW_UNNOTICED_DISCONNECT case errSSLClosedGraceful: /* legal if we're on record boundary and we've gotten past * the handshake */ if((ctx->amountRead == 0) && /* nothing pending */ (len == 0) && /* nothing new */ (ctx->state == SSL_HdskStateClientReady)) { /* handshake done */ /* * This means that the server has disconnected without * sending a closure alert notice. This is technically * illegal per the SSL3 spec, but about half of the * servers out there do it, so we report it as a separate * error which most clients - including (currently) * URLAccess - ignore by treating it the same as * a errSSLClosedGraceful error. Paranoid * clients can detect it and handle it however they * want to. */ SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose); err = errSSLClosedNoNotify; break; } else { /* illegal disconnect */ err = errSSLClosedAbort; /* and drop thru to default: fatal alert */ } #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */ default: break; } return err; } ctx->amountRead += len; } check(ctx->amountRead >= head); charPtr = ctx->partialReadBuffer.data; rec->contentType = *charPtr++; if (rec->contentType < SSL_RecordTypeV3_Smallest || rec->contentType > SSL_RecordTypeV3_Largest) return errSSLRecordProtocol; rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2); charPtr += 2; if(rec->protocolVersion == DTLS_Version_1_0) { sslUint64 seqNum; SSLDecodeUInt64(charPtr, 8, &seqNum); charPtr += 8; sslLogRecordIo("Read DTLS Record %016llx (seq is: %016llx)", seqNum, ctx->readCipher.sequenceNum); /* if the epoch of the record is different of current read cipher, just drop it */ if((seqNum>>48)!=(ctx->readCipher.sequenceNum>>48)) { skipit=1; } else {