#include "lwip/arch.h" #include "HTTPClientWrapper.h" #include "random.h" #include "wm_osal.h" #include "wm_sockets.h" #include "lwip/sockets.h" #include "wm_debug.h" #include "HTTPClient.h" #if TLS_CONFIG_HTTP_CLIENT /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : Stdc: HTTPWrapperIsAscii // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : Same as stdc: isascii // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperIsAscii(int c) { return (!(c & ~0177)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : Stdc: HTTPWrapperToUpper // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : Convert character to uppercase. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperToUpper(int c) { // -32 if(HTTPWrapperIsAscii(c) > 0) { if(c >= 97 && c <= 122) { return (c - 32); } } return c; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : Stdc: HTTPWrapperToLower // Last updated : 13/06/2006 // Author Name : Eitan Michaelson // Notes : Convert character to lowercase. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperToLower(int c) { // +32 if(HTTPWrapperIsAscii(c) > 0) { if(c >= 65 && c <= 90) { return (c + 32); } } return c; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : Stdc: isalpha // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : returns nonzero if c is a particular representation of an alphabetic character // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperIsAlpha(int c) { if(HTTPWrapperIsAscii(c) > 0) { if( (c >= 97 && c <= 122) || (c >= 65 && c <= 90)) { return c; } } return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : Stdc: isalnum // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : returns nonzero if c is a particular representation of an alphanumeric character // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperIsAlNum(int c) { if(HTTPWrapperIsAscii(c) > 0) { if(HTTPWrapperIsAlpha(c) > 0) { return c; } if( c >= 48 && c <= 57) { return c; } } return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_itoa // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : same as stdc itoa() // hmm.. allmost the same // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// char* HTTPWrapperItoa(char *s,int a) { unsigned int b; if(a > 2147483647) { return 0; // overflow } if (a < 0) b = -a, *s++ = '-'; else b = a; for(;a;a=a/10) s++; for(*s='\0';b;b=b/10) *--s=b%10+'0'; return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_ShutDown // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : Handles parameter changes in the socket shutdown() function in AMT // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperShutDown (int s,int how) { return shutdown(s,how); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_GetSocketError // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : WSAGetLastError Wrapper (Win32 Specific) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperGetSocketError (int s) { return errno; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_GetRandomeNumber // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : GetRandom number for Win32 & AMT // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void HTTPWrapperInitRandomeNumber() { srand((unsigned int)tls_os_get_time()); } int HTTPWrapperGetRandomeNumber() { int num; num = (int)(((double) rand()/ ((double)RAND_MAX+1)) * 16); return num; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_GetRTC // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : Get uptime under Win32 & AMT // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// long HTTPWrapperGetUpTime() { long lTime = 0; lTime = tls_os_get_time(); return lTime; } #endif //TLS_CONFIG_HTTP_CLIENT /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Section : HTTPWrapper_GetHostByName // Last updated : 15/05/2005 // Author Name : Eitan Michaelson // Notes : gethostbyname for Win32 (supports the AMT edition of the function) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsigned long HTTPWrapperGetHostByName(char *name,unsigned long *address) { HTTP_HOSTNET *HostEntry; int iPos = 0, iLen = 0,iNumPos = 0,iDots =0; long iIPElement; char c = 0; char Num[4]; int iHostType = 0; // 0 : numeric IP // Check if the name is an IP or host iLen = strlen(name); for(iPos = 0; iPos <= iLen;iPos++) { c = name[iPos]; if((c >= 48 && c <= 57) || (c == '.') ) { // c is numeric or dot if(c != '.') { // c is numeric if(iNumPos > 3) { iHostType++; break; } Num[iNumPos] = c; Num[iNumPos + 1] = 0; iNumPos ++; } else { iNumPos = 0; iDots++; iIPElement = atol(Num); if(iIPElement > 256 || iDots > 3) { return 0; // error invalid IP } } } else { break; // this is an alpha numeric address type } } if(c == 0 && iHostType == 0 && iDots == 3) { iIPElement = atol(Num); if(iIPElement > 256) { return 0; // error invalid IP } } else { iHostType++; } if(iHostType > 0) { HostEntry = gethostbyname(name); if(HostEntry) { *(address) = *((u_long*)HostEntry->h_addr_list[0]); //*(address) = (unsigned long)HostEntry->h_addr_list[0]; return 1; // Error } else { return 0; // OK } } else // numeric address - no need for DNS resolve { *(address) = inet_addr(name); return 1; } } #if TLS_CONFIG_HTTP_CLIENT_SECURE #define ALLOW_ANON_CONNECTIONS 1 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int HTTPWrapperSSLNegotiate(HTTP_SESSION_HANDLE pSession,int s,const struct sockaddr *name,int namelen,char *hostname) { return 0; } #if 1 #if 0 #define PSLL_PRT printf #else #define PSLL_PRT(x, ...) #endif /************************ memory manage ************************/ void *platform_malloc(uint32_t size) { return tls_mem_alloc(size); } void platform_free(void *ptr) { tls_mem_free(ptr); } /************************ mutex manage ************************/ void *platform_mutex_init(void) { tls_os_sem_t *mutex = NULL; tls_os_sem_create(&mutex,1); return mutex; } void platform_mutex_lock(void *mutex) { tls_os_sem_acquire(mutex,0); } void platform_mutex_unlock(void *mutex) { tls_os_sem_release(mutex); } void platform_mutex_destroy(void *mutex) { if (!mutex) return; tls_os_sem_delete(mutex); } static int ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) { return random_get_bytes( output, output_len ); } static void my_debug( void *ctx, int level, const char *str ) { PSLL_PRT("%s", str); } static int net_is_blocking( void ) { switch( errno ) { #if defined EAGAIN case EAGAIN: #endif #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif return( 1 ); } return( 0 ); } static int net_recv( void *ctx, unsigned char *buf, size_t len ) { int ret; int skt = (int)(long) ctx; #if 0 fd_set read_set; struct timeval tv; FD_ZERO(&read_set); FD_SET(skt, &read_set); tv.tv_sec = 5; tv.tv_usec = 0; ret = select(skt + 1, &read_set, NULL, NULL, &tv); if (ret > 0) { if (FD_ISSET(skt, &read_set)) { #endif ret = recv( skt, buf, len, 0); if( ret < 0 ) { if( net_is_blocking() != 0 ) return( POLARSSL_ERR_NET_WANT_READ ); if( errno == EPIPE || errno == ECONNRESET ) return( POLARSSL_ERR_NET_CONN_RESET ); if( errno == EINTR ) return( POLARSSL_ERR_NET_WANT_READ ); return( POLARSSL_ERR_NET_RECV_FAILED ); } #if 0 FD_CLR(skt, &read_set); } else { PSLL_PRT("\r\n\r\nssl select no\r\n\r\n"); } } else if (0 == ret) { PSLL_PRT("\r\n\r\nssl recv timeout\r\n\r\n"); } else { PSLL_PRT("\r\n\r\nssl select error\r\n\r\n"); } #endif return ret; } /* * Write at most 'len' characters */ static int net_send( void *ctx, const unsigned char *buf, size_t len ) { int ret = send( (long) ctx, buf, len, 0); if( ret < 0 ) { if( net_is_blocking() != 0 ) return( POLARSSL_ERR_NET_WANT_WRITE ); if( errno == EPIPE || errno == ECONNRESET ) return( POLARSSL_ERR_NET_CONN_RESET ); if( errno == EINTR ) return( POLARSSL_ERR_NET_WANT_WRITE ); return( POLARSSL_ERR_NET_SEND_FAILED ); } return( ret ); } void *platform_ssl_connect(void *tcp_fd, const char *server_cert, int server_cert_len) { int ret; ssl_context *ssl; ssl_session *ssn; x509_cert *cacert = NULL; ssl = platform_malloc(sizeof(ssl_context)); if (!ssl) return NULL; ssn = platform_malloc(sizeof(ssl_session)); if (!ssn) { platform_free(ssl); return NULL; } if (server_cert) { cacert = platform_malloc(sizeof(x509_cert)); if (!cacert) { platform_free(ssl); platform_free(ssn); return NULL; } memset(cacert, 0, sizeof(x509_cert)); ret = x509parse_crt(cacert, (unsigned char *) server_cert, server_cert_len); if( ret != 0 ) { PSLL_PRT( " failed\n ! x509parse_crt returned %d\n\n", ret ); platform_free(ssl); platform_free(ssn); if(cacert) platform_free(cacert); return NULL; } } memset(ssl, 0, sizeof(ssl_context)); if( ( ret = ssl_init( ssl ) ) != 0 ) { PSLL_PRT( " failed\n ! ssl_init returned %d\n\n", ret ); if(cacert) x509_free( cacert ); platform_free(ssl); platform_free(ssn); if(cacert) platform_free(cacert); return NULL; } ssl_set_endpoint( ssl, SSL_IS_CLIENT ); if (server_cert) ssl_set_authmode( ssl, SSL_VERIFY_REQUIRED ); else ssl_set_authmode( ssl, SSL_VERIFY_NONE ); ssl_set_rng( ssl, ctr_drbg_random, NULL ); ssl_set_dbg( ssl, my_debug, NULL); ssl_set_bio( ssl, net_recv, tcp_fd, net_send, tcp_fd ); ssl_set_ciphersuites( ssl, ssl_default_ciphersuites ); memset(ssn, 0, sizeof(ssl_session)); ssl_set_session( ssl, 1, 600, ssn ); if (server_cert) ssl_set_ca_chain( ssl, cacert, NULL, NULL); while( ( ret = ssl_handshake( ssl ) ) != 0 ) { if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) { PSLL_PRT( " failed\n ! ssl_handshake returned %d\n\n", ret ); goto fail; } PSLL_PRT("INFO: ssl_handshake returned %d\n\n", ret); } if (server_cert) { if( ( ret = ssl_get_verify_result( ssl ) ) != 0 ) { PSLL_PRT( "Verifying peer X.509 certificate failed\n" ); if( ( ret & BADCERT_EXPIRED ) != 0 ) PSLL_PRT( " ! server certificate has expired\n" ); if( ( ret & BADCERT_REVOKED ) != 0 ) PSLL_PRT( " ! server certificate has been revoked\n" ); if( ( ret & BADCERT_CN_MISMATCH ) != 0 ) PSLL_PRT( " ! CN mismatch \n"); if( ( ret & BADCERT_NOT_TRUSTED ) != 0 ) PSLL_PRT( " ! self-signed or not signed by a trusted CA\n" ); PSLL_PRT( "\n" ); ssl_close_notify( ssl ); goto fail; } else { PSLL_PRT( "Verifying X.509 certificate pass.\n" ); } } //ssl->read_lock = platform_mutex_init(); ssl->write_lock = platform_mutex_init(); //printf("ssl read/write lock 0x%p/0x%p\n", ssl->read_lock, ssl->write_lock); PSLL_PRT("ssl rdwr lock 0x%p\n", ssl->write_lock); return ssl; fail: if(cacert) x509_free( cacert ); ssl_free( ssl ); platform_free(ssl); platform_free(ssn); if(cacert) platform_free(cacert); return NULL; } int platform_ssl_close(void *ssl) { ssl_context *sslt = (ssl_context *)ssl; platform_mutex_lock(sslt->write_lock); ssl_close_notify( sslt ); x509_free( sslt->ca_chain ); platform_free(sslt->ca_chain); platform_free(sslt->session); platform_mutex_unlock(sslt->write_lock); platform_mutex_destroy(sslt->write_lock); //platform_mutex_destroy(sslt->read_lock); ssl_free(sslt); platform_free(sslt); return 0; } int platform_ssl_send(void *ssl, const char *buf, int len) { int ret; ssl_context *sslt = (ssl_context *)ssl; platform_mutex_lock(sslt->write_lock); while( ( ret = ssl_write( sslt, (u8 *)buf, len ) ) <= 0 ) { if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) { PSLL_PRT( " failed\n ! ssl_write returned %d, errno %d\n", ret , errno); break; } } platform_mutex_unlock(sslt->write_lock); return ret; } int platform_ssl_recv(void *ssl, char *buf, int len) { int ret; ssl_context *sslt = (ssl_context *)ssl; platform_mutex_lock(sslt->write_lock); //platform_mutex_lock(sslt->read_lock); do { ret = ssl_read( sslt, (u8 *)buf, len ); if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE ) continue; //if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY ) // break; if( ret < 0 ) { PSLL_PRT( "failed\n ! ssl_read returned %d, errno %d\n", ret , errno); break; } else if( ret == 0 ) { PSLL_PRT("\n\nEOF, errno %d\n\n", errno); break; } else { //PSLL_PRT( " %d bytes read\n\n%s", ret, (char *) buf ); break; } } while(1); platform_mutex_unlock(sslt->write_lock); //platform_mutex_unlock(sslt->read_lock); //PSLL_PRT(" <== platform_ssl_recv ret %d\n", ret); return ret; } int HTTPWrapperSSLConnect(tls_ssl_t **ssl_p,int fd,const struct sockaddr *name,int namelen,char *hostname) { int rc; tls_ssl_t *ssl = NULL; if(name) { char *host_ip = inet_ntoa(((struct sockaddr_in*)name)->sin_addr); rc = connect(fd, // Socket name, // Server address sizeof(struct sockaddr)); if(rc) { TLS_DBGPRT_ERR("host_ip=%s\n", host_ip); TLS_DBGPRT_ERR("Connection Failed: %d. Exiting\n", rc); return rc; } } ssl = platform_ssl_connect((void *)fd, NULL, 0); if(ssl == NULL) return -1; *ssl_p = ssl; return 0; } int HTTPWrapperSSLSend(tls_ssl_t *ssl, int s,char *sndbuf, int len,int flags) { return platform_ssl_send(ssl, sndbuf, len); } int HTTPWrapperSSLRecv(tls_ssl_t *ssl,int s,char *buf, int len,int flags) { int ret = platform_ssl_recv(ssl, buf, len); if(ssl->in_msglen > 0) return SOCKET_SSL_MORE_DATA; return ret; } int HTTPWrapperSSLRecvPending(tls_ssl_t *ssl) { return ssl_get_bytes_avail(ssl); } int HTTPWrapperSSLClose(tls_ssl_t *ssl, int s) { if(ssl == NULL) return 0; return platform_ssl_close(ssl); } #endif //TLS_CONFIG_USE_POLARSSL #endif //TLS_CONFIG_HTTP_CLIENT_SECURE