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; } }
int SSLDecodeBufferList(uint8_t *p, size_t listLen, int itemLenSize, tls_buffer_list_t **list) { int err = 0; tls_buffer_list_t *first = NULL; tls_buffer_list_t *last = NULL; while (listLen > 0) { size_t itemLen; tls_buffer_list_t *item; if (listLen < itemLenSize) { sslErrorLog("SSLDecodeBufferList: length decode error 2\n"); err = errSSLProtocol; goto errOut; } itemLen = SSLDecodeInt(p,itemLenSize); p += itemLenSize; if (listLen < itemLen + itemLenSize) { sslErrorLog("SSLDecodeBufferList: length decode error 3\n"); err = errSSLProtocol; goto errOut; } if(itemLen==0) { sslErrorLog("SSLDecodeBufferList: lenght decode error 4 (empty item)\n"); err = errSSLProtocol; goto errOut; } item = (tls_buffer_list_t *)sslMalloc(sizeof(tls_buffer_list_t)); if(item == NULL) { err = errSSLAllocate; goto errOut; } if ((err = SSLAllocBuffer(&item->buffer, itemLen))) { sslFree(item); goto errOut; } item->next = NULL; memcpy(item->buffer.data, p, itemLen); p += itemLen; if(first==NULL) { first=item; last=item; } else { last->next=item; last=item; } listLen -= itemLenSize+itemLen; } *list = first; return 0; errOut: tls_free_buffer_list(first); return err; }
int SSLProcessCertificateRequest(tls_buffer message, tls_handshake_t ctx) { unsigned i; unsigned typeCount; unsigned shListLen = 0; UInt8 *charPtr; unsigned dnListLen; unsigned dnLen; tls_buffer dnBuf; DNListElem *dn; int err; /* * Cert request only happens in during client authentication. * Application can send a client cert if they have an appropriate one. * coreTLS does not ensure the client cert is appropriate. */ unsigned minLen = (sslVersionIsLikeTls12(ctx)) ? 5 : 3; if (message.length < minLen) { sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n"); return errSSLProtocol; } charPtr = message.data; typeCount = *charPtr++; if ((typeCount < 1) || (message.length < minLen + typeCount)) { sslErrorLog("SSLProcessCertificateRequest: length decode error 2\n"); return errSSLProtocol; } /* Update the server-specified auth types */ sslFree(ctx->clientAuthTypes); ctx->numAuthTypes = typeCount; ctx->clientAuthTypes = (tls_client_auth_type *) sslMalloc(ctx->numAuthTypes * sizeof(tls_client_auth_type)); if(ctx->clientAuthTypes==NULL) return errSSLInternal; for(i=0; i<ctx->numAuthTypes; i++) { sslLogNegotiateDebug("===Server specifies authType %d", (int)(*charPtr)); ctx->clientAuthTypes[i] = (tls_client_auth_type)(*charPtr++); } if (sslVersionIsLikeTls12(ctx)) { /* Parse the supported_signature_algorithms field added in TLS1.2 */ shListLen = SSLDecodeInt(charPtr, 2); charPtr += 2; if ((shListLen < 2) || (message.length < minLen + typeCount + shListLen)) { sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n"); return errSSLProtocol; } if (shListLen & 1) { sslErrorLog("SSLProcessCertificateRequest: signAlg len odd\n"); return errSSLProtocol; } sslFree(ctx->peerSigAlgs); ctx->numPeerSigAlgs = shListLen / 2; ctx->peerSigAlgs = (tls_signature_and_hash_algorithm *) sslMalloc((ctx->numPeerSigAlgs) * sizeof(tls_signature_and_hash_algorithm)); if(ctx->peerSigAlgs==NULL) return errSSLInternal; for(i=0; i<ctx->numPeerSigAlgs; i++) { ctx->peerSigAlgs[i].hash = *charPtr++; ctx->peerSigAlgs[i].signature = *charPtr++; sslLogNegotiateDebug("===Server specifies sigAlg %d %d", ctx->peerSigAlgs[i].hash, ctx->peerSigAlgs[i].signature); } } /* Update the acceptable DNList */ SSLFreeDNList(ctx->acceptableDNList); ctx->acceptableDNList=NULL; dnListLen = SSLDecodeInt(charPtr, 2); charPtr += 2; if (message.length != minLen + typeCount + shListLen + dnListLen) { sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n"); return errSSLProtocol; } while (dnListLen > 0) { if (dnListLen < 2) { sslErrorLog("SSLProcessCertificateRequest: dnListLen error 1\n"); return errSSLProtocol; } dnLen = SSLDecodeInt(charPtr, 2); charPtr += 2; if (dnListLen < 2 + dnLen) { sslErrorLog("SSLProcessCertificateRequest: dnListLen error 2\n"); return errSSLProtocol; } if ((err = SSLAllocBuffer(&dnBuf, sizeof(DNListElem)))) return err; dn = (DNListElem*)dnBuf.data; if ((err = SSLAllocBuffer(&dn->derDN, dnLen))) { SSLFreeBuffer(&dnBuf); return err; } memcpy(dn->derDN.data, charPtr, dnLen); charPtr += dnLen; dn->next = ctx->acceptableDNList; ctx->acceptableDNList = dn; dnListLen -= 2 + dnLen; } assert(charPtr == message.data + message.length); return errSSLSuccess; }
int SSLProcessCertificate(tls_buffer message, tls_handshake_t ctx) { size_t listLen; UInt8 *p; int err = 0; SSLCertificate *certChain; if (message.length < 3) { sslErrorLog("SSLProcessCertificate: message length decode error\n"); return errSSLProtocol; } p = message.data; listLen = SSLDecodeInt(p,3); p += 3; if (listLen + 3 != message.length) { sslErrorLog("SSLProcessCertificate: length decode error 1\n"); return errSSLProtocol; } // Note: An empty certificate list (listLen==0) is allowed by the TLS RFC, // but empty certificates (certLen==0) are not. Section 7.4.2 in RFC 5246 // defines the message syntax as such: // // opaque ASN.1Cert<1..2^24-1>; // // struct { // ASN.1Cert certificate_list<0..2^24-1>; // } Certificate; // // Note the difference between <1..2^24-1> and <0..2^24-1> // if((err = SSLDecodeBufferList(p, listLen, 3, (tls_buffer_list_t **)&certChain))) { return err; } p+=listLen; /* Do not accept a different server cert during renegotiation unless allowed */ if(!ctx->allowServerIdentityChange && ctx->peerCert && !CertificateChainEqual(ctx->peerCert, certChain)) { sslErrorLog("Illegal server identity change during renegotiation\n"); SSLFreeCertificates(certChain); return errSSLProtocol; } if (ctx->peerCert == NULL && __ssl_debug_enabled("sslLogNegotiateDebug")) { debug_log_chain("sslLogNegotiateDebug", certChain); } /* Free certs if they already exist */ SSLFreeCertificates(ctx->peerCert); ctx->peerCert=certChain; assert(p == message.data + message.length); /* Don't fail here if peerCert is NULL. An empty Certificate message is valid in some cases. The rest of the stack will handle it. */ return err; }
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 {