/* Send req and get response */ int http_transaction(http_t *client, http_trans_t *trans) { int rc = 0; ASSERT(client); ASSERT(trans); if (!client->initialized) return RC_HTTP_OBJECT_NOT_INITIALIZED; trans->rsp_len = 0; do { #ifdef ENABLE_SSL if (client->ssl_enabled) { TRY(ssl_send(client, trans->p_req, trans->req_len)); TRY(ssl_recv(client, trans->p_rsp, trans->max_rsp_len, &trans->rsp_len)); } else #endif { TRY(tcp_send(&client->tcp, trans->p_req, trans->req_len)); TRY(tcp_recv(&client->tcp, trans->p_rsp, trans->max_rsp_len, &trans->rsp_len)); } } while (0); trans->p_rsp[trans->rsp_len] = 0; http_response_parse(trans); return rc; }
/* Helper routines */ static IOResult client_recv(struct Client *cptr, char *buf, unsigned int length, unsigned int* count_out) { if (cli_socket(cptr).s_ssl) return ssl_recv(&cli_socket(cptr), buf, length, count_out); else return os_recv_nonb(cli_fd(cptr), buf, length, count_out); }
int gitno_recv(gitno_buffer *buf) { int ret; #ifdef GIT_SSL if (buf->ssl != NULL) { if ((ret = ssl_recv(buf->ssl, buf->data + buf->offset, buf->len - buf->offset)) < 0) return -1; } else { ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0); if (ret < 0) { net_set_error("Error receiving socket data"); return -1; } } #else ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0); if (ret < 0) { net_set_error("Error receiving socket data"); return -1; } #endif buf->offset += ret; return ret; }
/* * Receives Plain Text file to the receiver * SSL *conn -> The SSL connection of the sender * const char *fname -> The name of the file to store * returns the total amount of bytes sent and encrypted */ ssize_t ssl_recv_file(SSL *conn, const char *fname) { ssize_t len = 0, total = 0; char buf[BUFFSIZE]; FILE *file = nullptr; if((file = fopen(fname, "wb")) == nullptr) return FILE_NOT_FOUND; while((len = ssl_recv(conn, buf, sizeof(buf))-1) > 0) { total += fwrite(buf+1, sizeof(char), (size_t)len, file); } fclose(file); if(len < 0) { perror("ssl_recv() failed"); return -1; } return total; }
/* * Recieve up to len bytes from the socket in socket_fd and * store the result in buf. * Return value: * Returns the number of bytes recieved, or -1 on failure. */ ssize_t socket_recv(struct socket_in *s, const char *delim) { ssize_t bytes = 0; /* Sanity checks. */ if(s == NULL || s->buffer == NULL) return(-1); #ifdef OPENSSL_ENABLED if(s->ssl != NULL) bytes = ssl_recv(s, delim); else #endif /* OPENSSL_ENABLED */ { struct socket_buf *b = s->buffer; ssize_t temp_bytes; bytes = (b->w_next-b->w_start); do { if((temp_bytes = recv(s->fd, b->w_next, SOCKET_WBUFSIZE-bytes, 0)) == -1) { if(errno != EAGAIN && errno != EINTR) return(errno); break; } bytes += temp_bytes; b->w_next += sizeof(*b->w_next)*temp_bytes; } while(strstr(b->w_start, delim) == NULL && bytes < SOCKET_WBUFSIZE); } /* Split up the results into a linked-list. */ socket_chunk(s, delim); return(bytes); }
/* * Recieves AES-CBC-128 bit encrypted file from sender and decrypts the file * and saves it to the file specified in the arguments * SSL *conn -> The SSL connection for the sender's node * const unsigned char *key -> The already instantiated AES Key for decryption * const char *fname -> The name of the file to be stored * returns the total amount of bytes read and decrypted */ ssize_t crypto_recv_file(SSL *conn, const unsigned char *key, const char *fname) { int len, ciph_len, first = 0; size_t total = 0; unsigned char plaintxt[BUFFSIZE]; unsigned char ciphtxt[BUFFSIZE]; unsigned char iv[IV_LEN]; EVP_CIPHER_CTX cntx; FILE *file; if((file = fopen(fname, "wb")) == nullptr) { return FILE_NOT_FOUND; } while ((len = (int)ssl_recv(conn,(char *)ciphtxt, sizeof(ciphtxt))-1) > 0) { if(!first) { memcpy(iv, ciphtxt+1, sizeof(iv)); EVP_CipherInit(&cntx, EVP_aes_128_cbc(), key, iv, DECRYPT); } EVP_CipherUpdate(&cntx, plaintxt, &ciph_len, ciphtxt+1, len); total += fwrite(plaintxt+(first?0:16), 1, (size_t)ciph_len-(first?0:16), file); /* Last transmission of the file */ if(len < BUFFSIZE-1) break; first++; } if (len < 0) goto err; EVP_CipherFinal(&cntx, plaintxt, &ciph_len); total+=fwrite(plaintxt, 1, (size_t)ciph_len, file); EVP_CIPHER_CTX_cleanup(&cntx); WAITFORACK(conn); fclose(file); return total; err: perror("GOTHERE"); EVP_CIPHER_CTX_cleanup(&cntx); die_with_err("send() failed"); return 1; }
/* Send req and get response */ int http_transaction(http_t *client, http_trans_t *trans) { int rc = 0; ASSERT(client); ASSERT(trans); if (!client->initialized) return RC_HTTP_OBJECT_NOT_INITIALIZED; trans->rsp_len = 0; do { TRY(ssl_send(client, trans->req, trans->req_len)); TRY(ssl_recv(client, trans->rsp, trans->max_rsp_len, &trans->rsp_len)); } while (0); trans->rsp[trans->rsp_len] = 0; http_response_parse(trans); return rc; }
int SocketReadHTTPSHeader( mico_ssl_t ssl, HTTPHeader_t *inHeader ) { int err =0; char * buf; char * dst; char * lim; char * end; size_t len; ssize_t n; buf = inHeader->buf; dst = buf + inHeader->len; lim = buf + inHeader->bufLen; for( ;; ) { if(findHeader( inHeader, &end )) break ; n = ssl_recv( ssl, dst, (size_t)( lim - dst ) ); if( n > 0 ) len = (size_t) n; else { err = kConnectionErr; goto exit; } dst += len; inHeader->len += len; } inHeader->len = (size_t)( end - buf ); err = HTTPHeaderParse( inHeader ); require_noerr( err, exit ); inHeader->extraDataLen = (size_t)( dst - end ); if(inHeader->extraDataPtr) { free((uint8_t *)inHeader->extraDataPtr); inHeader->extraDataPtr = 0; } /* For chunked extra data without content length */ if(inHeader->chunkedData == true){ inHeader->chunkedDataBufferLen = (inHeader->extraDataLen > READ_LENGTH)? inHeader->extraDataLen:READ_LENGTH; inHeader->chunkedDataBufferPtr = calloc(inHeader->chunkedDataBufferLen, sizeof(uint8_t)); //Make extra data buffer larger than chunk length require_action(inHeader->chunkedDataBufferPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->chunkedDataBufferPtr, end, inHeader->extraDataLen); inHeader->extraDataPtr = inHeader->chunkedDataBufferPtr; return kNoErr; } /* Extra data with content length */ if (inHeader->contentLength != 0){ //Content length >0, create a memory buffer (Content length) and store extra data size_t copyDataLen = (inHeader->contentLength >= inHeader->extraDataLen)? inHeader->extraDataLen : inHeader->contentLength; if(inHeader->onReceivedDataCallback && (inHeader->onReceivedDataCallback)(inHeader, 0, (uint8_t *)end, copyDataLen, inHeader->userContext)==kNoErr){ inHeader->isCallbackSupported = true; inHeader->extraDataPtr = calloc(READ_LENGTH, sizeof(uint8_t)); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); }else{ inHeader->isCallbackSupported = false; inHeader->extraDataPtr = calloc(inHeader->contentLength , sizeof(uint8_t)); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->extraDataPtr, end, copyDataLen); } err = kNoErr; }/* Extra data without content length, data is ended by conntection close */ // else if(inHeader->extraDataLen != 0){ //Content length =0, but extra data length >0, create a memory buffer (1500)and store extra data // inHeader->dataEndedbyClose = true; // inHeader->extraDataPtr = calloc(1500, sizeof(uint8_t)); // require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); // memcpy((uint8_t *)inHeader->extraDataPtr, end, inHeader->extraDataLen); // (inHeader->onReceivedDataCallback)(inHeader, 0, (uint8_t *)inHeader->extraDataPtr, inHeader->extraDataLen, inHeader->userContext); // err = kNoErr; // } else return kNoErr; exit: return err; }
OSStatus SocketReadHTTPSBody( mico_ssl_t ssl, HTTPHeader_t *inHeader ) { OSStatus err = kParamErr; ssize_t readResult; int selectResult; fd_set readSet; size_t lastChunkLen, chunckheaderLen; char *nextPackagePtr; struct timeval_t t; size_t readLength; uint32_t pos = 0; t.tv_sec = 5; t.tv_usec = 0; int inSock = CyaSSL_get_fd( ssl ); require( inHeader, exit ); err = kNotReadableErr; FD_ZERO( &readSet ); FD_SET( inSock, &readSet ); /* Chunked data without content length */ if( inHeader->chunkedData == true ){ do{ /* Find Chunk data length */ while ( findChunkedDataLength( inHeader->chunkedDataBufferPtr, inHeader->extraDataLen, &inHeader->extraDataPtr ,"%llu", &inHeader->contentLength ) == false){ require_action(inHeader->extraDataLen < inHeader->chunkedDataBufferLen, exit, err=kMalformedErr ); selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = ssl_recv( ssl, inHeader->chunkedDataBufferPtr + inHeader->extraDataLen, (size_t)( inHeader->chunkedDataBufferLen - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } chunckheaderLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr; /* Check the last chunk */ if(inHeader->contentLength == 0){ while( findCRLF( inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, &nextPackagePtr ) == false){ //find CRLF selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = ssl_recv( ssl, (uint8_t *)( inHeader->extraDataPtr + inHeader->extraDataLen - chunckheaderLen ), 256 - inHeader->extraDataLen ); //Assume chunk trailer length is less than 256 (256 is the min chunk buffer, maybe dangerous if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, inHeader->extraDataLen - readResult, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); } err = kNoErr; goto exit; } else{ // Read chunk data /* Chunk package already exist, callback, move to buffer's head */ if( inHeader->extraDataLen >= inHeader->contentLength + chunckheaderLen + 2 ){ require_action( *(inHeader->extraDataPtr + inHeader->contentLength ) == '\r' && *(inHeader->extraDataPtr + inHeader->contentLength + 1 ) == '\n', exit, err = kMalformedErr); (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->contentLength, inHeader->userContext); pos+=inHeader->contentLength; /* Move next chunk to chunked data buffer header point */ lastChunkLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr + inHeader->contentLength; if(inHeader->contentLength) lastChunkLen += 2; //Last chunck data has a CRLF tail memmove( inHeader->chunkedDataBufferPtr, inHeader->chunkedDataBufferPtr + lastChunkLen, inHeader->chunkedDataBufferLen - lastChunkLen ); inHeader->extraDataLen -= lastChunkLen; } /* Chunck exist without the last LF, generate callback abd recv LF */ /* Callback , read LF */ else if(inHeader->extraDataLen == inHeader->contentLength + chunckheaderLen +1){ //recv CR require_action( *(inHeader->chunkedDataBufferPtr + inHeader->extraDataLen - 1) == '\r' , exit, err = kMalformedErr); (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen-1, inHeader->userContext); pos+=inHeader->extraDataLen - chunckheaderLen-1; selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = ssl_recv( ssl, (uint8_t *)inHeader->extraDataPtr, 1); if( readResult > 0 ) {} else { err = kConnectionErr; goto exit; } require_action( *(inHeader->extraDataPtr) == '\n', exit, err = kMalformedErr); inHeader->extraDataLen = 0; } else{ /* Callback , read , callback , read CRLF */ (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, inHeader->userContext); pos += inHeader->extraDataLen - chunckheaderLen; while ( inHeader->extraDataLen < inHeader->contentLength + chunckheaderLen ){ selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); if( inHeader->contentLength - (inHeader->extraDataLen - chunckheaderLen) > inHeader->chunkedDataBufferLen - chunckheaderLen) //Data needed is greater than valid buffer size readLength = inHeader->chunkedDataBufferLen - chunckheaderLen; else //Data needed is less than valid buffer size readLength = inHeader->contentLength - (inHeader->extraDataLen - chunckheaderLen) ; readResult = ssl_recv( ssl, (uint8_t *)inHeader->extraDataPtr, readLength); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); pos += readResult; } selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = ssl_recv( ssl, (uint8_t *)inHeader->extraDataPtr, 2); if( readResult > 0 ) {} else { err = kConnectionErr; goto exit; } require_action( *(inHeader->extraDataPtr) == '\r' && *(inHeader->extraDataPtr+1 ) == '\n', exit, err = kMalformedErr); inHeader->extraDataLen = 0; } } }while(inHeader->contentLength != 0); } /* We has extra data but total length is not clear, store them to 1500 bytes buffer return when connection is disconnected by remote server */ // if( inHeader->dataEndedbyClose == true){ // if(inHeader->contentLength == 0) { //First read body, return using data received by SocketReadHTTPHeader // inHeader->contentLength = inHeader->extraDataLen; // }else{ // selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); // require_action( selectResult >= 1, exit, err = kNotReadableErr ); // readResult = read( inSock, // (uint8_t*)( inHeader->extraDataPtr ), // 1500 ); // if( readResult > 0 ) inHeader->contentLength = readResult; // else { err = kConnectionErr; goto exit; } // } // err = kNoErr; // goto exit; // } while ( inHeader->extraDataLen < inHeader->contentLength ) { selectResult = select( inSock + 1, &readSet, NULL, NULL, &t ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); if(inHeader->isCallbackSupported == true){ /* We has extra data, and we give these data to application by onReceivedDataCallback function */ readLength = inHeader->contentLength - inHeader->extraDataLen > READ_LENGTH? READ_LENGTH:inHeader->contentLength - inHeader->extraDataLen; readResult = ssl_recv( ssl, (uint8_t*)( inHeader->extraDataPtr), readLength ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, inHeader->extraDataLen - readResult, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); }else{ /* We has extra data and we has a predefined buffer to store the total extra data return when all data has received*/ readResult = ssl_recv( ssl, (uint8_t*)( inHeader->extraDataPtr + inHeader->extraDataLen ), ( inHeader->contentLength - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } } err = kNoErr; exit: if(err != kNoErr) inHeader->len = 0; return err; }