/* Create the Openssl module. This is called only once */ PUBLIC int sslOpen() { sslSettings *settings; char *certificate, *key, *cacert; int rc; if (MOCANA_initMocana() < 0) { error("NanoSSL initialization failed"); return -1; } MOCANA_initLog(nanoLog); if (SSL_init(SOMAXCONN, 0) < 0) { error("SSL_init failed"); return -1; } certificate = *ME_GOAHEAD_CERTIFICATE ? ME_GOAHEAD_CERTIFICATE : 0; key = *ME_GOAHEAD_KEY ? ME_GOAHEAD_KEY : 0; cacert = *ME_GOAHEAD_CA ? ME_GOAHEAD_CA: 0; if (certificate) { certDescriptor tmp; if ((rc = MOCANA_readFile((sbyte*) certificate, &tmp.pCertificate, &tmp.certLength)) < 0) { error("NanoSSL: Unable to read certificate %s", certificate); CA_MGMT_freeCertificate(&tmp); return -1; } assert(__ENABLE_MOCANA_PEM_CONVERSION__); if ((rc = CA_MGMT_decodeCertificate(tmp.pCertificate, tmp.certLength, &cert.pCertificate, &cert.certLength)) < 0) { error("NanoSSL: Unable to decode PEM certificate %s", certificate); CA_MGMT_freeCertificate(&tmp); return -1; } MOCANA_freeReadFile(&tmp.pCertificate); } if (key) { certDescriptor tmp; if ((rc = MOCANA_readFile((sbyte*) key, &tmp.pKeyBlob, &tmp.keyBlobLength)) < 0) { error("NanoSSL: Unable to read key file %s", key); CA_MGMT_freeCertificate(&cert); } if ((rc = CA_MGMT_convertKeyPEM(tmp.pKeyBlob, tmp.keyBlobLength, &cert.pKeyBlob, &cert.keyBlobLength)) < 0) { error("NanoSSL: Unable to decode PEM key file %s", key); CA_MGMT_freeCertificate(&tmp); return -1; } MOCANA_freeReadFile(&tmp.pKeyBlob); } if (cacert) { certDescriptor tmp; if ((rc = MOCANA_readFile((sbyte*) cacert, &tmp.pCertificate, &tmp.certLength)) < 0) { error("NanoSSL: Unable to read CA certificate file %s", cacert); CA_MGMT_freeCertificate(&tmp); return -1; } if ((rc = CA_MGMT_decodeCertificate(tmp.pCertificate, tmp.certLength, &ca.pCertificate, &ca.certLength)) < 0) { error("NanoSSL: Unable to decode PEM certificate %s", cacert); CA_MGMT_freeCertificate(&tmp); return -1; } MOCANA_freeReadFile(&tmp.pCertificate); } if (SSL_initServerCert(&cert, FALSE, 0)) { error("SSL_initServerCert failed"); return -1; } settings = SSL_sslSettings(); settings->sslTimeOutHello = SSL_HELLO_TIMEOUT; settings->sslTimeOutReceive = SSL_RECV_TIMEOUT; return 0; }
/*=================================================================================================*/ E_SERVER_FSM_RESULT ssl_server_entry(SSL_SERVER_PARS parameters) { /* server parameters */ uint8_t echo = parameters.echo; char * pc_filename = parameters.pc_filename; char * pc_ciphersuites = parameters.pc_ciphersuites; uint16_t u_port = parameters.u_port; e_sslVer_t versmin = parameters.versmin; e_sslVer_t versmax = parameters.versmax; char * key = parameters.key; e_sslKeyType_t keyType = parameters.keyType; char * keyParameters = parameters.keyParameters; char ** certs = parameters.ppc_certs; char ** CAcerts = parameters.ppc_CAcerts; e_sslAuthLevel_t authlevel = parameters.authlevel; char c_filebuf[SSL_WRITE_BLOCK_LEN]; size_t n; char c_mode = 1; en_gciResult_t err; /* Check the state of the server */ switch (i_state) { case SSL_SERVER_INIT: /*============================================================================*/ /* * General SSL Initialisation */ /*============================================================================*/ /* Initialises the SSL module */ SSL_init(); /* Initialises the crypto */ //TODO sw - where to become the user name + password ?? err = gciInit(NULL, 0, NULL, 0); //OLD-CW: cw_crypto_init(); // { // /* // * Use some "random" bytes to init the PRNG // */ // uint8_t c_rand[] = { 0x42, 0x72, 0x75, 0x63, 0x65, 0x20, 0x53, 0x63, 0x68, //TODO sw - this step in gci_init // 0x6E, 0x65, 0x69, 0x65, 0x72, 0x21, 0x0D, 0x0A, 0x00 }; // cw_prng_init(c_rand, sizeof(c_rand)); // } /* * Initialisation of keymanager for DHE and DHE private key generation */ km_dhe_init(); /*============================================================================*/ /* * Initialization of the SSL settings for the demonstration SSL context */ /*============================================================================*/ /* Initialises the SSL context */ sslSoc_initSett(&s_sslSett, keyType); /* * Init the time-function pointer implicit to NULL, this will disable * checking of the validity of the used certificates * (To enable 'getCurrentTime' function should be used) */ sslSoc_setTimeFunc(&s_sslSett, NULL); /* Setting up the SSL version */ sslSoc_setVer(&s_sslSett, versmin, versmax); /* Setting up the SSL timeout value */ sslSoc_setSessTimeout(&s_sslSett, 600); /* Setting up the SSL authentification behavior */ sslSoc_setAuthLvl(&s_sslSett, authlevel); /* Setting up read and write fonctions */ sslSoc_setReadWrite(&s_sslSett, sslTarget_read, sslTarget_write); /* Initialize server CA certificates */ if (CAcerts != NULL) { init_server_CA_certs(CAcerts); } /* ===== Initialize Server Certificates and private key ===== */ s_cdbCert_t cdb_tmp; s_sslCertList_t * list_head = sslSoc_getCertChainList(&s_sslSett); if (certs != NULL) { int i = 0; while (certs[i] != NULL) { /* printf("certs[%i] = '%s'\n", i, certs[i]); */ cdb_initCert_linear(&server_cdb_certs[i], certs[i]); list_head = sslCert_addToList(list_head, &server_cert_list[i], NULL, &server_cdb_certs[i]); i++; } } else { /* use static pre-defined certificates if * no external certificate has been provided */ /* int i; for (i = 0; i < SSL_SERVERCERTS_NUM; ++i) { cdb_initCert_linear(&server_cdb_certs[i], server_certificates_[i]); list_head = SSL_cert_list_add(list_head, &server_cert_list[i], NULL, &server_cdb_certs[i]); } */ } sslSoc_setCertChainList (&s_sslSett, list_head); if (key != NULL) { cdb_initCert_linear(&cdb_tmp, key); } else { /*cdb_initCert_linear(&cdb_tmp, ServerPrivateKey);*/ } switch(keyType) { case E_SSL_KEY_EC: if (sslSoc_setECCPrivKey(&s_sslSett, &cdb_tmp) != E_SSL_OK) { printf(DBG_STRING "Import of ECC private key failed", __FILE__, __LINE__); return (E_SERVER_FSM_ERROR); } /* if */ break; case E_SSL_KEY_RSA: if (sslSoc_setRsaPrivKey(&s_sslSett, &cdb_tmp) != E_SSL_OK) { printf(DBG_STRING "Import of RSA private key failed", __FILE__, __LINE__); return (E_SERVER_FSM_ERROR); } /* if */ break; default: return (E_SERVER_FSM_ERROR); break; } /* switch */ case SSL_SERVER_REINIT: /*============================================================================*/ /* * Initialize socket specific features */ /*============================================================================*/ /* Creates a socket */ #ifdef _WIN32 if((srv_socdesc = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET) { printf("Could not create socket : %s\n" , WSAGetLastError()); WSACleanup(); return (E_SERVER_FSM_ERROR); } #elif __linux if((srv_socdesc = socket(AF_INET , SOCK_STREAM , 0 )) < 0) { printf("Could not create socket : %s\n" , strerror(errno)); return (E_SERVER_FSM_ERROR); } #endif setsockopt(srv_socdesc, SOL_SOCKET, SO_REUSEADDR, &c_mode, sizeof(int)); printf("\n\rSocket created.\n"); /* Binding */ server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(u_port); #ifdef _WIN32 if( bind(srv_socdesc ,(struct sockaddr *)&server , sizeof(server)) == INVALID_SOCKET) { printf("Bind failed with error code : %s\n" , WSAGetLastError()); WSACleanup(); return (E_SERVER_FSM_ERROR); } #elif __linux if( bind(srv_socdesc ,(struct sockaddr *)&server , sizeof(server)) < 0) { printf("Bind failed with error code : %s\n" , strerror(errno)); return (E_SERVER_FSM_ERROR); } #endif puts("Bind done"); /* Listening */ listen(srv_socdesc , 3); puts("Waiting for incoming connections..."); i_state = SSL_SERVER_LISTEN; break; /* SSL_SERVER_INIT */ case SSL_SERVER_LISTEN: i_addr_len = sizeof(struct sockaddr_in); cli_socdesc = accept(srv_socdesc , (struct sockaddr *)&client, &i_addr_len); if (cli_socdesc == INVALID_SOCKET) { break; } /* Nonblocking mode */ #ifdef _WIN32 ioctlsocket(cli_socdesc, FIONBIO, (u_long *)&c_mode); #elif __linux fcntl(cli_socdesc, F_SETFL, O_NONBLOCK); #endif printf("\n\rConnection accepted\n"); /* Checks if a SSL context is available */ if ((ps_sslCtx = sslSoc_new ( &s_sslSett )) == NULL) { /* Not available */ i_state = SSL_SERVER_CLOSE_ERR; } else { /* Available */ sslSoc_setCtxFd(ps_sslCtx, cli_socdesc); /* set supported ciphersuites if list is provided */ if (strlen(pc_ciphersuites) > 0) { sslSoc_setCtxCipList(ps_sslCtx, pc_ciphersuites); } int i=0; switch(keyType) { case E_SSL_KEY_EC: //loop all cipher suites provided //Remove all non-ECDSA cipher suites, as certificate cannot handle non-ECDSA for(i=0; i<SSL_CIPSPEC_COUNT; i++) { if( //remove every ECDHE curve ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA && ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA && ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ) { ps_sslCtx->s_sslGut.ae_cipSpecs[i] = TLS_NULL_WITH_NULL_NULL; } } break; case E_SSL_KEY_RSA: case E_SSL_KEY_UNDEFINED: //vpy: should be handled properly //Remove all ECDSA cipher suites, as certificate cannot handle ECDSA //loop all cipher suites provided for(i=0; i<SSL_CIPSPEC_COUNT; i++) { if( //remove every ECDHE curve ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA || ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA || ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ) { ps_sslCtx->s_sslGut.ae_cipSpecs[i] = TLS_NULL_WITH_NULL_NULL; } } break; } i_state = SSL_SERVER_ACCEPT; LOG_OK("Accept"); } /* if ... else */ break; /* SSL_SERVER_LISTEN */ case SSL_SERVER_ACCEPT: /* Operates the SSL Handshake */ switch(sslSoc_accept (ps_sslCtx)) { case E_SSL_AGAIN: break; case E_SSL_OK: /* print some connection specifics */ printf("\n>INFO::Ciphers: RX = 0x%.4X, TX = 0x%.4X\n", ps_sslCtx->s_sslGut.e_rxCipSpec, ps_sslCtx->s_sslGut.e_txCipSpec); printf("\n>INFO::Version: 0x%.4X\n", ps_sslCtx->e_ver); i_state = SSL_SERVER_READ; /* Reads the current system time */ l_timeStart = fp_getCurTime(); l_Start = l_timeStart; l_bytesRead = 0; break; case E_SSL_ERROR: default: LOG_ERR("sslSoc_accept error"); i_state = SSL_SERVER_CLOSE_ERR; ps_sslCtx->e_socState = E_SSL_SOCKET_UNUSED; break; } /* switch */ break; /* SSL_SERVER_ACCEPT */ case SSL_SERVER_READ: l_bytes = 0; /* Just read and show on console. */ /* Read */ memset(c_readBuf, 0, sizeof(c_readBuf)); /* read from SSL socket */ l_bytes = sslSoc_read(ps_sslCtx, c_readBuf, sizeof(c_readBuf)); if (l_bytes > 0) { if (echo != 0) { /* server echo: transmit received byte string */ memcpy(c_writeBuf, c_readBuf, l_bytes); l_bytesWrite = l_bytes; i_state = SSL_SERVER_WRITE; } else if (strncmp(c_readBuf, "GET / HTTP/1.1\r\n\r\n", 16) == 0) { /* open file to transmit */ fp = fopen(pc_filename, "rb"); if (fp == NULL) { /* could not open file => send an error message */ l_bytesWrite = sprintf(c_writeBuf, "HTTP/1.1 404 Not Found\r\n\r\n"); i_state = SSL_SERVER_WRITE; } else { /* determine the number of bytes in the file to put * that piece of information into the HTTP header */ n = 0; while (fgetc(fp) != EOF) { n++; } rewind(fp); printf("Transmitting file: '%s'\n", pc_filename); /* prepare HTTP header */ l_bytesWrite = sprintf(c_writeBuf, "HTTP/1.1 200 OK\r\n"\ "Content-Type: application/octet-stream\r\n"\ "Content-Length: %d\r\n\r\n", n); /* next step: read first chunk of bytes from file */ i_state = SSL_SERVER_READ_FILE; } } break; } else if (l_bytes < 0) { switch(l_bytes) { case E_SSL_ERROR: i_state = SSL_SERVER_CLOSING; break; case E_SSL_WANT_WRITE: i_state = SSL_SERVER_FLUSH; break; default: break; } } else if (l_bytes == E_SSL_AGAIN) { break; } i_state = SSL_SERVER_CLOSE; break; /* SSL_SERVER_READ */ case SSL_SERVER_READ_FILE: n = 0; if (fp != NULL) { /* read chunk of bytes from file and copy to write buffer */ n = fread(c_filebuf, 1, SSL_WRITE_BLOCK_LEN - l_bytesWrite - 100, fp); } memcpy(&(c_writeBuf[l_bytesWrite]), c_filebuf, n); l_bytesWrite += n; if (n > 0) { /* next step: send data just read from file to peer */ i_state = SSL_SERVER_WRITE; } else { /* we have reached the end of the file: close file and connection */ if (fp != NULL) { fclose(fp); } i_state = SSL_SERVER_CLOSING; } break; /* case SSL_SERVER_READ_FILE */ case SSL_SERVER_WRITE: /* send data to peer */ l_bytes = sslSoc_write(ps_sslCtx, (char*)c_writeBuf, l_bytesWrite); if (l_bytes > 0) { i_state = SSL_SERVER_FLUSH; } else { switch(l_bytes) { case E_SSL_ERROR: printf(DBG_STRING " sslSoc_write error %s", __FILE__, __LINE__, sslDiag_getError(ps_sslCtx)); i_state = SSL_SERVER_CLOSING; break; case E_SSL_WANT_AGAIN: i_state = SSL_SERVER_READ; break; default: break; } } /* need to reset l_bytesWrite to zero because otherwise step * SSL_SERVER_READ_FILE would *append* new data (thinking * previous chunk of bytes from file is the HTTP header) */ l_bytesWrite = 0; break; /* case SSL_SERVER_WRITE */ case SSL_SERVER_FLUSH: { switch(sslSoc_flush(ps_sslCtx)) { case E_SSL_OK: if (echo != 0) { /* in echo mode: start listening again */ i_state = SSL_SERVER_READ; } else { /* in normal mode: read next chunk of bytes from file */ i_state = SSL_SERVER_READ_FILE; } break; /* * It is not, so we can fall thru */ case E_SSL_WANT_AGAIN: i_state = SSL_SERVER_READ; break; case E_SSL_AGAIN: break; case E_SSL_ERROR: default: i_state = SSL_SERVER_CLOSING; break; } }/* SSL_SERVER_FLUSH */ break; case SSL_SERVER_CLOSING: case SSL_SERVER_CLOSING_ERR: LOG_RAW("Shutting down SSL connection..."); do { l_bytes = sslSoc_shutdown(ps_sslCtx); printf("sslSoc_shutdown(...) returned: %d\n", l_bytes); if (l_bytes == E_SSL_OK && i_state == SSL_SERVER_CLOSING) { /* connection successfully closed (passive close) */ i_state = SSL_SERVER_CLOSE; } else if (l_bytes != E_SSL_AGAIN) { /* connection successfully closed (error case) */ i_state = SSL_SERVER_CLOSE_ERR; } } while (l_bytes != E_SSL_OK && l_bytes != E_SSL_ERROR); printf("done!\n"); break; case SSL_SERVER_CLOSE: case SSL_SERVER_CLOSE_ERR: sslSoc_free(ps_sslCtx); close(srv_socdesc); puts("Socket closed"); E_SERVER_FSM_RESULT retval = (i_state == SSL_SERVER_CLOSE_ERR) ? E_SERVER_FSM_ERROR : E_SERVER_FSM_DONE; i_state = SSL_SERVER_REINIT; return retval; break; } /* switch */ /* server FSM would like to be re-entered again */ return E_SERVER_FSM_AGAIN; }