/* * R/W. Called out from SSL. */ OSStatus SocketRead( SSLConnectionRef connection, void *data, /* owned by * caller, data * RETURNED */ size_t *dataLength) /* IN/OUT */ { UInt32 bytesToGo = *dataLength; UInt32 initLen = bytesToGo; UInt8 *currData = (UInt8 *)data; int sock = (int)((long)connection); OSStatus rtn = noErr; UInt32 bytesRead; ssize_t rrtn; *dataLength = 0; for(;;) { bytesRead = 0; /* paranoid check, ensure errno is getting written */ errno = -555; rrtn = recv(sock, currData, bytesToGo, 0); if (rrtn <= 0) { if(rrtn == 0) { /* closed, EOF */ rtn = errSSLClosedGraceful; break; } int theErr = errno; switch(theErr) { case ENOENT: /* * Undocumented but I definitely see this. * Non-blocking sockets only. Definitely retriable * just like an EAGAIN. */ dprintf(("SocketRead RETRYING on ENOENT, rrtn %d\n", (int)rrtn)); /* normal... */ //rtn = errSSLWouldBlock; /* ...for temp testing.... */ rtn = ioErr; break; case ECONNRESET: /* explicit peer abort */ rtn = errSSLClosedAbort; break; case EAGAIN: /* nonblocking, no data */ rtn = errSSLWouldBlock; break; default: dprintf(("SocketRead: read(%u) error %d, rrtn %d\n", (unsigned)bytesToGo, theErr, (int)rrtn)); rtn = ioErr; break; } /* in any case, we're done with this call if rrtn <= 0 */ break; } bytesRead = rrtn; bytesToGo -= bytesRead; currData += bytesRead; if(bytesToGo == 0) { /* filled buffer with incoming data, done */ break; } } *dataLength = initLen - bytesToGo; tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data); #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE) if((rtn == 0) && (*dataLength == 0)) { /* keep UI alive */ outputDot(); } #endif #if SSL_DISPL_WOULD_BLOCK if(rtn == errSSLWouldBlock) { printf("."); fflush(stdout); } #endif return rtn; }
/* * R/W. Called out from SSL. */ OSStatus SocketRead( SSLConnectionRef connection, void *data, /* owned by * caller, data * RETURNED */ size_t *dataLength) /* IN/OUT */ { UInt32 bytesToGo = (UInt32) *dataLength; UInt32 initLen = bytesToGo; UInt8 *currData = (UInt8 *)data; int sock = (int)connection; OSStatus rtn = noErr; UInt32 bytesRead = 0; int rrtn; *dataLength = 0; for(;;) { // bytesRead = 0; rrtn = (int) read(sock, currData, bytesToGo); if (rrtn <= 0) { /* this is guesswork... */ int theErr = errno; dprintf(("SocketRead: read(%d) error %d\n", (int)bytesToGo, theErr)); #if !NON_BLOCKING if((rrtn == 0) && (theErr == 0)) { /* try fix for iSync */ rtn = errSSLClosedGraceful; //rtn = errSSLClosedAbort; } else /* do the switch */ #endif switch(theErr) { case ENOENT: /* connection closed */ rtn = errSSLClosedGraceful; break; case ECONNRESET: rtn = errSSLClosedAbort; break; #if NON_BLOCKING case EAGAIN: #else case 0: /* ??? */ #endif rtn = errSSLWouldBlock; break; default: dprintf(("SocketRead: read(%d) error %d\n", (int)bytesToGo, theErr)); rtn = ioErr; break; } break; } else { bytesRead = rrtn; } bytesToGo -= bytesRead; currData += bytesRead; if(bytesToGo == 0) { /* filled buffer with incoming data, done */ break; } } *dataLength = initLen - bytesToGo; tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data); #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE) if((rtn == 0) && (*dataLength == 0)) { /* keep UI alive */ outputDot(); } #endif return rtn; }
static OSStatus sslServe( otSocket listenSock, SSLProtocol tryVersion, const char *hostName, // e.g., "www.amazon.com" CFArrayRef serverCerts, // required CFArrayRef encryptServerCerts, // optional CSSM_BOOL allowExpired, CSSM_BOOL allowAnyRoot, char cipherRestrict, // '2', 'd'. etc...'\0' for no // restriction SSLAuthenticate authenticate, CSSM_BOOL resumableEnable, CSSM_BOOL silent, // no stdout CSSM_BOOL pause, SSLProtocol *negVersion, // RETURNED SSLCipherSuite *negCipher, // RETURNED CFArrayRef *peerCerts) // mallocd & RETURNED { otSocket acceptSock; PeerSpec peerId; OSStatus ortn; SSLContextRef ctx = NULL; UInt32 length; uint8 rcvBuf[RCV_BUF_SIZE]; char *outMsg = SERVER_MESSAGE; *negVersion = kSSLProtocolUnknown; *negCipher = SSL_NULL_WITH_NULL_NULL; *peerCerts = NULL; #if IGNORE_SIGPIPE signal(SIGPIPE, sigpipe); #endif /* first wait for a connection */ if(!silent) { printf("Waiting for client connection..."); fflush(stdout); } ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId); if(ortn) { printf("AcceptClientConnection returned %d; aborting\n", ortn); return ortn; } /* * Set up a SecureTransport session. * First the standard calls. */ ortn = SSLNewContext(true, &ctx); if(ortn) { printSslErrStr("SSLNewContext", ortn); goto cleanup; } ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); if(ortn) { printSslErrStr("SSLSetIOFuncs", ortn); goto cleanup; } ortn = SSLSetProtocolVersion(ctx, tryVersion); if(ortn) { printSslErrStr("SSLSetProtocolVersion", ortn); goto cleanup; } ortn = SSLSetConnection(ctx, acceptSock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1); if(ortn) { printSslErrStr("SSLSetPeerDomainName", ortn); goto cleanup; } /* have to do these options befor setting server certs */ if(allowExpired) { ortn = SSLSetAllowsExpiredCerts(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowExpiredCerts", ortn); goto cleanup; } } if(allowAnyRoot) { ortn = SSLSetAllowsAnyRoot(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowAnyRoot", ortn); goto cleanup; } } ortn = SSLSetCertificate(ctx, serverCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } if(encryptServerCerts) { ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts); if(ortn) { printSslErrStr("SSLSetEncryptionCertificate", ortn); goto cleanup; } } /* * SecureTransport options. */ if(resumableEnable) { ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } } if(cipherRestrict != '\0') { ortn = setCipherRestrictions(ctx, cipherRestrict); if(ortn) { goto cleanup; } } #if AUTHENTICATE_ENABLE if(authenticate != kNeverAuthenticate) { ortn = SSLSetClientSideAuthenticate(ctx, authenticate); if(ortn) { printSslErrStr("SSLSetClientSideAuthenticate", ortn); goto cleanup; } } #endif if(pause) { doPause("SSLContext initialized"); } /* Perform SSL/TLS handshake */ do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !silent) { /* keep UI responsive */ outputDot(); } } while (ortn == errSSLWouldBlock); /* this works even if handshake failed due to cert chain invalid */ copyPeerCerts(ctx, peerCerts); SSLGetNegotiatedCipher(ctx, negCipher); SSLGetNegotiatedProtocolVersion(ctx, negVersion); if(!silent) { printf("\n"); } if(ortn) { goto cleanup; } if(pause) { doPause("SSLContext handshake complete"); } /* wait for one complete line or user says they've had enough */ while(ortn == noErr) { length = sizeof(rcvBuf); ortn = SSLRead(ctx, rcvBuf, length, &length); if(length == 0) { /* keep UI responsive */ outputDot(); } else { /* print what we have */ printf("client request: "); dumpAscii(rcvBuf, length); } if(pause) { /* allow user to bail */ char resp; fpurge(stdin); printf("\nMore client request (y/anything): "); resp = getchar(); if(resp != 'y') { break; } } /* poor person's line completion scan */ for(unsigned i=0; i<length; i++) { if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) { /* a labelled break would be nice here.... */ goto serverResp; } } if (ortn == errSSLWouldBlock) { ortn = noErr; } } serverResp: if(pause) { doPause("Client GET msg received"); } /* send out canned response */ length = strlen(outMsg); ortn = SSLWrite(ctx, outMsg, length, &length); if(ortn) { printSslErrStr("SSLWrite", ortn); } if(pause) { doPause("Server response sent"); } if (ortn == noErr) { ortn = SSLClose(ctx); } cleanup: if(acceptSock) { endpointShutdown(acceptSock); } if(ctx) { SSLDisposeContext(ctx); } /* FIXME - dispose of serverCerts */ return ortn; }
/* * R/W. Called out from SSL. */ OSStatus SocketRead( SSLConnectionRef connection, void *data, /* owned by * caller, data * RETURNED */ size_t *dataLength) /* IN/OUT */ { size_t bytesToGo = *dataLength; size_t initLen = bytesToGo; UInt8 *currData = (UInt8 *)data; int sock = (int)((long)connection); OSStatus rtn = noErr; size_t bytesRead; int rrtn; *dataLength = 0; for(;;) { bytesRead = 0; rrtn = read(sock, currData, bytesToGo); if (rrtn <= 0) { /* this is guesswork... */ switch(errno) { case ENOENT: /* connection closed */ rtn = errSSLClosedGraceful; break; #if NON_BLOCKING case EAGAIN: #else case 0: /* ??? */ #endif rtn = errSSLWouldBlock; break; default: dprintf(("SocketRead: read(%lu) error %d\n", bytesToGo, errno)); rtn = ioErr; break; } break; } else { bytesRead = rrtn; } bytesToGo -= bytesRead; currData += bytesRead; if(bytesToGo == 0) { /* filled buffer with incoming data, done */ break; } } *dataLength = initLen - bytesToGo; tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data); #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE) if((rtn == 0) && (*dataLength == 0)) { /* keep UI alive */ outputDot(); } #endif return rtn; }