/* Convert a SecCertificateRef to an SSLCertificate * */ static OSStatus secCertToSslCert( SSLContext *ctx, SecCertificateRef certRef, SSLCertificate **sslCert) { CSSM_DATA certData; // struct is transient, referent owned by // Sec layer OSStatus ortn; SSLCertificate *thisSslCert = NULL; ortn = SecCertificateGetData(certRef, &certData); if(ortn) { sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn); return ortn; } thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate)); if(thisSslCert == NULL) { return memFullErr; } if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length, ctx)) { return memFullErr; } memcpy(thisSslCert->derCert.data, certData.Data, certData.Length); thisSslCert->derCert.length = certData.Length; *sslCert = thisSslCert; return noErr; }
int SSLEncodeCertificateStatus(tls_buffer *status, tls_handshake_t ctx) { int err; size_t totalLength; uint8_t *charPtr; int head; assert(ctx->isServer); assert(ctx->ocsp_enabled && ctx->ocsp_peer_enabled); if(ctx->ocsp_response.length==0) { return errSSLInternal; } totalLength = 1 + 3 + ctx->ocsp_response.length; head = SSLHandshakeHeaderSize(ctx); if ((err = SSLAllocBuffer(status, totalLength + head))) return err; charPtr = SSLEncodeHandshakeHeader(ctx, status, SSL_HdskCertificateStatus, totalLength); *charPtr++ = SSL_CST_Ocsp; charPtr = SSLEncodeSize(charPtr, ctx->ocsp_response.length, 3); memcpy(charPtr, ctx->ocsp_response.data, ctx->ocsp_response.length); return 0; }
int SSLEncodeCertificateRequest(tls_buffer *request, tls_handshake_t ctx) { int err; size_t shListLen = 0, dnListLen, msgLen; UInt8 *charPtr; DNListElem *dn; int head; assert(ctx->isServer); if (sslVersionIsLikeTls12(ctx)) { shListLen = 2 + 2 * ctx->numLocalSigAlgs; } dnListLen = 0; dn = ctx->acceptableDNList; while (dn) { dnListLen += 2 + dn->derDN.length; dn = dn->next; } msgLen = 1 + // number of cert types 2 + // cert types shListLen + // SignatureAlgorithms 2 + // length of DN list dnListLen; assert(ctx->negProtocolVersion >= tls_protocol_version_SSL_3); head = SSLHandshakeHeaderSize(ctx); if ((err = SSLAllocBuffer(request, msgLen + head))) return err; charPtr = SSLEncodeHandshakeHeader(ctx, request, SSL_HdskCertRequest, msgLen); *charPtr++ = 2; /* two cert types */ *charPtr++ = tls_client_auth_type_RSASign; *charPtr++ = tls_client_auth_type_ECDSASign; if (shListLen) { /* Encode the supported_signature_algorithms added in TLS1.2 */ charPtr = SSLEncodeSize(charPtr, shListLen - 2, 2); for(int i=0; i<ctx->numLocalSigAlgs; i++) { charPtr = SSLEncodeInt(charPtr, ctx->localSigAlgs[i].hash, 1); charPtr = SSLEncodeInt(charPtr, ctx->localSigAlgs[i].signature, 1); } } charPtr = SSLEncodeSize(charPtr, dnListLen, 2); dn = ctx->acceptableDNList; while (dn) { charPtr = SSLEncodeSize(charPtr, dn->derDN.length, 2); memcpy(charPtr, dn->derDN.data, dn->derDN.length); charPtr += dn->derDN.length; dn = dn->next; } assert(charPtr == request->data + request->length); return errSSLSuccess; }
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; }
/* * Wrapper for HashReference.init. */ OSStatus ReadyHash(const HashReference *ref, SSLBuffer *state, SSLContext *ctx) { OSStatus err; if ((err = SSLAllocBuffer(state, ref->contextSize, ctx)) != 0) return err; return ref->init(state, ctx); }
/* * A convenience wrapper for HashReference.clone, which has the added benefit of * allocating the state buffer for the caller. */ OSStatus CloneHashState( const HashReference *ref, const SSLBuffer *state, SSLBuffer *newState, SSLContext *ctx) { OSStatus err; if ((err = SSLAllocBuffer(newState, ref->contextSize, ctx)) != 0) return err; return ref->clone(state, newState); }
static OSStatus SSLEncodeAlert(SSLRecord *rec, AlertLevel level, AlertDescription desc, SSLContext *ctx) { OSStatus err; rec->protocolVersion = ctx->negProtocolVersion; rec->contentType = SSL_RecordTypeAlert; rec->contents.length = 2; if ((err = SSLAllocBuffer(&rec->contents, 2))) return err; rec->contents.data[0] = level; rec->contents.data[1] = desc; return errSecSuccess; }
OSStatus SSLEncodeChangeCipherSpec(SSLRecord *rec, SSLContext *ctx) { OSStatus err; assert(ctx->writePending_ready); sslLogNegotiateDebug("===Sending changeCipherSpec msg"); rec->contentType = SSL_RecordTypeChangeCipher; assert(ctx->negProtocolVersion >= SSL_Version_3_0); rec->protocolVersion = ctx->negProtocolVersion; rec->contents.length = 1; if ((err = SSLAllocBuffer(&rec->contents, 1))) return err; rec->contents.data[0] = 1; ctx->messageQueueContainsChangeCipherSpec=true; return errSecSuccess; }
static OSStatus sslGiantToBuffer( SSLContext *ctx, // Currently unused. giant g, SSLBuffer *buffer) { gi_uint8 *chars; gi_uint16 ioLen; gi_uint16 zeroCount; GIReturn giReturn; OSStatus status; ioLen = serializeGiantBytes(g); status = SSLAllocBuffer(buffer, ioLen, ctx); if (status) return status; chars = buffer->data; /* Serialize the giant g into chars. */ giReturn = serializeGiant(g, chars, &ioLen); if(giReturn) { SSLFreeBuffer(buffer, ctx); return giReturnToSSL(giReturn); } /* Trim off leading zeroes (but leave one zero if that's all there is). */ for (zeroCount = 0; zeroCount < (ioLen - 1); ++zeroCount) if (chars[zeroCount]) break; if (zeroCount > 0) { buffer->length = ioLen - zeroCount; memmove(chars, chars + zeroCount, buffer->length); } return status; }
int SSLEncodeCertificateVerify(tls_buffer *certVerify, tls_handshake_t ctx) { int err; UInt8 hashData[SSL_MAX_DIGEST_LEN]; tls_buffer hashDataBuf; size_t len; size_t outputLen; UInt8 *charPtr; int head; size_t maxSigLen; certVerify->data = 0; hashDataBuf.data = hashData; hashDataBuf.length = SSL_MAX_DIGEST_LEN; assert(ctx->signingPrivKeyRef != NULL); err = sslGetMaxSigSize(ctx->signingPrivKeyRef, &maxSigLen); if(err) { goto fail; } tls_signature_and_hash_algorithm sigAlg = {0,}; switch(ctx->signingPrivKeyRef->desc.type) { case tls_private_key_type_rsa: sigAlg.signature = tls_signature_algorithm_RSA; break; case tls_private_key_type_ecdsa: sigAlg.signature = tls_signature_algorithm_ECDSA; if (ctx->negProtocolVersion <= tls_protocol_version_SSL_3) { return errSSLInternal; } break; default: /* shouldn't be here */ assert(0); return errSSLInternal; } assert(ctx->negProtocolVersion >= tls_protocol_version_SSL_3); head = SSLHandshakeHeaderSize(ctx); outputLen = maxSigLen + head + 2; // Note: this is only used for TLS 1.2 if (sslVersionIsLikeTls12(ctx)) { err=FindCertSigAlg(ctx, &sigAlg); if(err) goto fail; outputLen += 2; ctx->certSigAlg = sigAlg; // Save for metrics reporting. } assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, &hashDataBuf, sigAlg.hash)) != 0) goto fail; if ((err = SSLAllocBuffer(certVerify, outputLen)) != 0) goto fail; /* Sign now to get the actual length */ charPtr = certVerify->data+head; if (sslVersionIsLikeTls12(ctx)) { *charPtr++ = sigAlg.hash; *charPtr++ = sigAlg.signature; switch (sigAlg.hash) { case tls_hash_algorithm_SHA512: case tls_hash_algorithm_SHA384: case tls_hash_algorithm_SHA256: case tls_hash_algorithm_SHA1: break; default: sslErrorLog("SSLEncodeCertificateVerify: unsupported signature hash algorithm (%d)\n", sigAlg.hash); assert(0); // if you get here, something is wrong in FindCertSigAlg err=errSSLInternal; goto fail; } if (sigAlg.signature == tls_signature_algorithm_RSA) { err = sslRsaSign(ctx->signingPrivKeyRef, sigAlg.hash, hashData, hashDataBuf.length, charPtr+2, maxSigLen, &outputLen); } else { err = sslEcdsaSign(ctx->signingPrivKeyRef, hashData, hashDataBuf.length, charPtr+2, maxSigLen, &outputLen); } len=outputLen+2+2; } else { err = sslRawSign(ctx->signingPrivKeyRef, hashData, // data to sign hashDataBuf.length, // Data to sign size charPtr+2, // signature destination maxSigLen, // we mallocd len+head+2 &outputLen); len = outputLen+2; } if(err) { sslErrorLog("SSLEncodeCertificateVerify: unable to sign data (error %d)\n", (int)err); goto fail; } // At this point: // len = message length // outputlen = sig length certVerify->length = len + head; /* charPtr point at the len field here */ SSLEncodeSize(charPtr, outputLen, 2); SSLEncodeHandshakeHeader(ctx, certVerify, SSL_HdskCertVerify, len); err = errSSLSuccess; fail: return err; }
int SSLEncodeCertificate(tls_buffer *certificate, tls_handshake_t ctx) { int err; size_t totalLength; uint8_t *charPtr; int certCount; SSLCertificate *cert; int head; /* * Note this can be called with localCert==0 for client side in TLS1+ and DTLS; * in that case we send an empty cert msg. */ assert(ctx->negProtocolVersion >= tls_protocol_version_SSL_3); assert((ctx->localCert != NULL) || (ctx->negProtocolVersion >= tls_protocol_version_TLS_1_0)); totalLength = 0; certCount = 0; /* If we are the client and didn't select an auth type, we will send an empty message */ if(ctx->isServer || ctx->negAuthType != tls_client_auth_type_None) { cert = ctx->localCert; while (cert) { totalLength += 3 + cert->derCert.length; /* 3 for encoded length field */ ++certCount; cert = cert->next; } cert = ctx->localCert; } else { certCount = 0; cert = NULL; } head = SSLHandshakeHeaderSize(ctx); if ((err = SSLAllocBuffer(certificate, totalLength + head + 3))) return err; charPtr = SSLEncodeHandshakeHeader(ctx, certificate, SSL_HdskCert, totalLength+3); charPtr = SSLEncodeSize(charPtr, totalLength, 3); /* Vector length */ /* Leaf cert is first in the linked list */ while(cert) { charPtr = SSLEncodeSize(charPtr, cert->derCert.length, 3); memcpy(charPtr, cert->derCert.data, cert->derCert.length); charPtr += cert->derCert.length; cert = cert->next; } assert(charPtr == certificate->data + certificate->length); if ((!ctx->isServer) && (ctx->negAuthType != tls_client_auth_type_None)) { /* this tells us to send a CertificateVerify msg after the * client key exchange. We skip the cert vfy if we just * sent an empty cert msg (i.e., we were asked for a cert * but we don't have one). */ ctx->certSent = 1; assert(ctx->clientCertState == kSSLClientCertRequested); assert(ctx->certRequested); ctx->clientCertState = kSSLClientCertSent; } if(certCount == 0) { sslCertDebug("...sending empty cert msg"); } return errSSLSuccess; }
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; }
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 {