static void use_SNI_at_ctx(CYASSL_CTX* ctx) { byte type = CYASSL_SNI_HOST_NAME; char name[] = "www.yassl.com"; AssertIntEQ(SSL_SUCCESS, CyaSSL_CTX_UseSNI(ctx, type, (void *) name, XSTRLEN(name))); }
static CYASSL_CTX * get_cyassl_ctx(const char *hostname) { int err; CYASSL_CTX *ret; s_config *config = config_get_config(); LOCK_CYASSL_CTX(); if (NULL == cyassl_ctx) { CyaSSL_Init(); /* Create the CYASSL_CTX */ /* Allow TLSv1.0 up to TLSv1.2 */ if ((cyassl_ctx = CyaSSL_CTX_new(CyaTLSv1_client_method())) == NULL) { debug(LOG_ERR, "Could not create CYASSL context."); UNLOCK_CYASSL_CTX(); return NULL; } if (config->ssl_cipher_list) { debug(LOG_INFO, "Setting SSL cipher list to [%s]", config->ssl_cipher_list); err = CyaSSL_CTX_set_cipher_list(cyassl_ctx, config->ssl_cipher_list); if (SSL_SUCCESS != err) { debug(LOG_ERR, "Could not load SSL cipher list (error %d)", err); UNLOCK_CYASSL_CTX(); return NULL; } } #ifdef HAVE_SNI if (config->ssl_use_sni) { debug(LOG_INFO, "Setting SSL using SNI for hostname %s", hostname); err = CyaSSL_CTX_UseSNI(cyassl_ctx, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname)); if (SSL_SUCCESS != err) { debug(LOG_ERR, "Could not setup SSL using SNI for hostname %s", hostname); UNLOCK_CYASSL_CTX(); return NULL; } } #endif if (config->ssl_verify) { /* Use trusted certs */ /* Note: CyaSSL requires that the certificates are named by their hash values */ debug(LOG_INFO, "Loading SSL certificates from %s", config->ssl_certs); err = CyaSSL_CTX_load_verify_locations(cyassl_ctx, NULL, config->ssl_certs); if (err != SSL_SUCCESS) { debug(LOG_ERR, "Could not load SSL certificates (error %d)", err); if (err == ASN_UNKNOWN_OID_E) { debug(LOG_ERR, "Error is ASN_UNKNOWN_OID_E - try compiling cyassl/wolfssl with --enable-ecc"); } else { debug(LOG_ERR, "Make sure that SSLCertPath points to the correct path in the config file"); debug(LOG_ERR, "Or disable certificate loading with 'SSLPeerVerification No'."); } UNLOCK_CYASSL_CTX(); return NULL; } } else { CyaSSL_CTX_set_verify(cyassl_ctx, SSL_VERIFY_NONE, 0); debug(LOG_INFO, "Disabling SSL certificate verification!"); } } ret = cyassl_ctx; UNLOCK_CYASSL_CTX(); return ret; }
THREAD_RETURN CYASSL_THREAD client_test(void* args) { SOCKET_T sockfd = 0; CYASSL_METHOD* method = 0; CYASSL_CTX* ctx = 0; CYASSL* ssl = 0; CYASSL* sslResume = 0; CYASSL_SESSION* session = 0; char resumeMsg[] = "resuming cyassl!"; int resumeSz = sizeof(resumeMsg); char msg[32] = "hello cyassl!"; /* GET may make bigger */ char reply[80]; int input; int msgSz = (int)strlen(msg); int port = yasslPort; char* host = (char*)yasslIP; char* domain = (char*)"www.yassl.com"; int ch; int version = CLIENT_INVALID_VERSION; int usePsk = 0; int sendGET = 0; int benchmark = 0; int doDTLS = 0; int matchName = 0; int doPeerCheck = 1; int nonBlocking = 0; int resumeSession = 0; int trackMemory = 0; int useClientCert = 1; int fewerPackets = 0; int atomicUser = 0; int pkCallbacks = 0; char* cipherList = NULL; char* verifyCert = (char*)caCert; char* ourCert = (char*)cliCert; char* ourKey = (char*)cliKey; #ifdef HAVE_SNI char* sniHostName = NULL; #endif #ifdef HAVE_MAX_FRAGMENT byte maxFragment = 0; #endif #ifdef HAVE_TRUNCATED_HMAC byte truncatedHMAC = 0; #endif #ifdef HAVE_OCSP int useOcsp = 0; char* ocspUrl = NULL; #endif int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; ((func_args*)args)->return_code = -1; /* error state */ #ifdef NO_RSA verifyCert = (char*)eccCert; ourCert = (char*)cliEccCert; ourKey = (char*)cliEccKey; #endif (void)resumeSz; (void)session; (void)sslResume; (void)trackMemory; (void)atomicUser; (void)pkCallbacks; StackTrap(); while ((ch = mygetopt(argc, argv, "?gdusmNrtfxUPh:p:v:l:A:c:k:b:zS:L:ToO:")) != -1) { switch (ch) { case '?' : Usage(); exit(EXIT_SUCCESS); case 'g' : sendGET = 1; break; case 'd' : doPeerCheck = 0; break; case 'u' : doDTLS = 1; break; case 's' : usePsk = 1; break; case 't' : #ifdef USE_CYASSL_MEMORY trackMemory = 1; #endif break; case 'm' : matchName = 1; break; case 'x' : useClientCert = 0; break; case 'f' : fewerPackets = 1; break; case 'U' : #ifdef ATOMIC_USER atomicUser = 1; #endif break; case 'P' : #ifdef HAVE_PK_CALLBACKS pkCallbacks = 1; #endif break; case 'h' : host = myoptarg; domain = myoptarg; break; case 'p' : port = atoi(myoptarg); #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API) if (port == 0) err_sys("port number cannot be 0"); #endif break; case 'v' : version = atoi(myoptarg); if (version < 0 || version > 3) { Usage(); exit(MY_EX_USAGE); } break; case 'l' : cipherList = myoptarg; break; case 'A' : verifyCert = myoptarg; break; case 'c' : ourCert = myoptarg; break; case 'k' : ourKey = myoptarg; break; case 'b' : benchmark = atoi(myoptarg); if (benchmark < 0 || benchmark > 1000000) { Usage(); exit(MY_EX_USAGE); } break; case 'N' : nonBlocking = 1; break; case 'r' : resumeSession = 1; break; case 'z' : #ifndef CYASSL_LEANPSK CyaSSL_GetObjectSize(); #endif break; case 'S' : #ifdef HAVE_SNI sniHostName = myoptarg; #endif break; case 'L' : #ifdef HAVE_MAX_FRAGMENT maxFragment = atoi(myoptarg); if (maxFragment < CYASSL_MFL_2_9 || maxFragment > CYASSL_MFL_2_13) { Usage(); exit(MY_EX_USAGE); } #endif break; case 'T' : #ifdef HAVE_TRUNCATED_HMAC truncatedHMAC = 1; #endif break; case 'o' : #ifdef HAVE_OCSP useOcsp = 1; #endif break; case 'O' : #ifdef HAVE_OCSP useOcsp = 1; ocspUrl = myoptarg; #endif break; default: Usage(); exit(MY_EX_USAGE); } } myoptind = 0; /* reset for test cases */ /* sort out DTLS versus TLS versions */ if (version == CLIENT_INVALID_VERSION) { if (doDTLS) version = CLIENT_DTLS_DEFAULT_VERSION; else version = CLIENT_DEFAULT_VERSION; } else { if (doDTLS) { if (version == 3) version = -2; else version = -1; } } #ifdef USE_CYASSL_MEMORY if (trackMemory) InitMemoryTracker(); #endif switch (version) { #ifndef NO_OLD_TLS case 0: method = CyaSSLv3_client_method(); break; #ifndef NO_TLS case 1: method = CyaTLSv1_client_method(); break; case 2: method = CyaTLSv1_1_client_method(); break; #endif /* NO_TLS */ #endif /* NO_OLD_TLS */ #ifndef NO_TLS case 3: method = CyaTLSv1_2_client_method(); break; #endif #ifdef CYASSL_DTLS case -1: method = CyaDTLSv1_client_method(); break; case -2: method = CyaDTLSv1_2_client_method(); break; #endif default: err_sys("Bad SSL version"); break; } if (method == NULL) err_sys("unable to get method"); ctx = CyaSSL_CTX_new(method); if (ctx == NULL) err_sys("unable to get ctx"); if (cipherList) if (CyaSSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) err_sys("client can't set cipher list 1"); #ifdef CYASSL_LEANPSK usePsk = 1; #endif #if defined(NO_RSA) && !defined(HAVE_ECC) usePsk = 1; #endif if (fewerPackets) CyaSSL_CTX_set_group_messages(ctx); if (usePsk) { #ifndef NO_PSK CyaSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); if (cipherList == NULL) { const char *defaultCipherList; #ifdef HAVE_NULL_CIPHER defaultCipherList = "PSK-NULL-SHA256"; #else defaultCipherList = "PSK-AES128-CBC-SHA256"; #endif if (CyaSSL_CTX_set_cipher_list(ctx,defaultCipherList) !=SSL_SUCCESS) err_sys("client can't set cipher list 2"); } #endif useClientCert = 0; } #ifdef OPENSSL_EXTRA CyaSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif #if defined(CYASSL_SNIFFER) && !defined(HAVE_NTRU) && !defined(HAVE_ECC) if (cipherList == NULL) { /* don't use EDH, can't sniff tmp keys */ if (CyaSSL_CTX_set_cipher_list(ctx, "AES256-SHA256") != SSL_SUCCESS) { err_sys("client can't set cipher list 3"); } } #endif #ifdef HAVE_OCSP if (useOcsp) { if (ocspUrl != NULL) { CyaSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl); CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE | CYASSL_OCSP_URL_OVERRIDE); } else CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE); } #endif #ifdef USER_CA_CB CyaSSL_CTX_SetCACb(ctx, CaCb); #endif #ifdef VERIFY_CALLBACK CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify); #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (useClientCert){ if (CyaSSL_CTX_use_certificate_chain_file(ctx, ourCert) != SSL_SUCCESS) err_sys("can't load client cert file, check file and run from" " CyaSSL home dir"); if (CyaSSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load client private key file, check file and run " "from CyaSSL home dir"); } if (!usePsk) { if (CyaSSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from CyaSSL home dir"); } #endif #if !defined(NO_CERTS) if (!usePsk && doPeerCheck == 0) CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); #endif #ifdef HAVE_CAVIUM CyaSSL_CTX_UseCavium(ctx, CAVIUM_DEV_ID); #endif #ifdef HAVE_SNI if (sniHostName) if (CyaSSL_CTX_UseSNI(ctx, 0, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS) err_sys("UseSNI failed"); #endif #ifdef HAVE_MAX_FRAGMENT if (maxFragment) if (CyaSSL_CTX_UseMaxFragment(ctx, maxFragment) != SSL_SUCCESS) err_sys("UseMaxFragment failed"); #endif #ifdef HAVE_TRUNCATED_HMAC if (truncatedHMAC) if (CyaSSL_CTX_UseTruncatedHMAC(ctx) != SSL_SUCCESS) err_sys("UseTruncatedHMAC failed"); #endif if (benchmark) { /* time passed in number of connects give average */ int times = benchmark; int i = 0; double start = current_time(), avg; for (i = 0; i < times; i++) { tcp_connect(&sockfd, host, port, doDTLS); ssl = CyaSSL_new(ctx); CyaSSL_set_fd(ssl, sockfd); if (CyaSSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed"); CyaSSL_shutdown(ssl); CyaSSL_free(ssl); CloseSocket(sockfd); } avg = current_time() - start; avg /= times; avg *= 1000; /* milliseconds */ printf("CyaSSL_connect avg took: %8.3f milliseconds\n", avg); CyaSSL_CTX_free(ctx); ((func_args*)args)->return_code = 0; exit(EXIT_SUCCESS); } #if defined(CYASSL_MDK_ARM) CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); #endif ssl = CyaSSL_new(ctx); if (ssl == NULL) err_sys("unable to get SSL object"); if (doDTLS) { SOCKADDR_IN_T addr; build_addr(&addr, host, port, 1); CyaSSL_dtls_set_peer(ssl, &addr, sizeof(addr)); tcp_socket(&sockfd, 1); } else { tcp_connect(&sockfd, host, port, 0); } CyaSSL_set_fd(ssl, sockfd); #ifdef HAVE_CRL if (CyaSSL_EnableCRL(ssl, CYASSL_CRL_CHECKALL) != SSL_SUCCESS) err_sys("can't enable crl check"); if (CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, 0) != SSL_SUCCESS) err_sys("can't load crl, check crlfile and date validity"); if (CyaSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS) err_sys("can't set crl callback"); #endif #ifdef ATOMIC_USER if (atomicUser) SetupAtomicUser(ctx, ssl); #endif #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx, ssl); #endif if (matchName && doPeerCheck) CyaSSL_check_domain_name(ssl, domain); #ifndef CYASSL_CALLBACKS if (nonBlocking) { CyaSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&sockfd); NonBlockingSSL_Connect(ssl); } else if (CyaSSL_connect(ssl) != SSL_SUCCESS) { /* see note at top of README */ int err = CyaSSL_get_error(ssl, 0); char buffer[CYASSL_MAX_ERROR_SZ]; printf("err = %d, %s\n", err, CyaSSL_ERR_error_string(err, buffer)); err_sys("SSL_connect failed"); /* if you're getting an error here */ } #else timeout.tv_sec = 2; timeout.tv_usec = 0; NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ #endif showPeer(ssl); if (sendGET) { printf("SSL connect ok, sending GET...\n"); msgSz = 28; strncpy(msg, "GET /index.html HTTP/1.0\r\n\r\n", msgSz); msg[msgSz] = '\0'; } if (CyaSSL_write(ssl, msg, msgSz) != msgSz) err_sys("SSL_write failed"); input = CyaSSL_read(ssl, reply, sizeof(reply)-1); if (input > 0) { reply[input] = 0; printf("Server response: %s\n", reply); if (sendGET) { /* get html */ while (1) { input = CyaSSL_read(ssl, reply, sizeof(reply)-1); if (input > 0) { reply[input] = 0; printf("%s\n", reply); } else break; } } } else if (input < 0) { int readErr = CyaSSL_get_error(ssl, 0); if (readErr != SSL_ERROR_WANT_READ) err_sys("CyaSSL_read failed"); } #ifndef NO_SESSION_CACHE if (resumeSession) { if (doDTLS) { strncpy(msg, "break", 6); msgSz = (int)strlen(msg); /* try to send session close */ CyaSSL_write(ssl, msg, msgSz); } session = CyaSSL_get_session(ssl); sslResume = CyaSSL_new(ctx); } #endif if (doDTLS == 0) /* don't send alert after "break" command */ CyaSSL_shutdown(ssl); /* echoserver will interpret as new conn */ #ifdef ATOMIC_USER if (atomicUser) FreeAtomicUser(ssl); #endif CyaSSL_free(ssl); CloseSocket(sockfd); #ifndef NO_SESSION_CACHE if (resumeSession) { if (doDTLS) { SOCKADDR_IN_T addr; #ifdef USE_WINDOWS_API Sleep(500); #else sleep(1); #endif build_addr(&addr, host, port, 1); CyaSSL_dtls_set_peer(sslResume, &addr, sizeof(addr)); tcp_socket(&sockfd, 1); } else { tcp_connect(&sockfd, host, port, 0); } CyaSSL_set_fd(sslResume, sockfd); CyaSSL_set_session(sslResume, session); showPeer(sslResume); #ifndef CYASSL_CALLBACKS if (nonBlocking) { CyaSSL_set_using_nonblock(sslResume, 1); tcp_set_nonblocking(&sockfd); NonBlockingSSL_Connect(sslResume); } else if (CyaSSL_connect(sslResume) != SSL_SUCCESS) err_sys("SSL resume failed"); #else timeout.tv_sec = 2; timeout.tv_usec = 0; NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ #endif if (CyaSSL_session_reused(sslResume)) printf("reused session id\n"); else printf("didn't reuse session id!!!\n"); if (CyaSSL_write(sslResume, resumeMsg, resumeSz) != resumeSz) err_sys("SSL_write failed"); if (nonBlocking) { /* give server a chance to bounce a message back to client */ #ifdef USE_WINDOWS_API Sleep(500); #else sleep(1); #endif } input = CyaSSL_read(sslResume, reply, sizeof(reply)-1); if (input > 0) { reply[input] = 0; printf("Server resume response: %s\n", reply); } /* try to send session break */ CyaSSL_write(sslResume, msg, msgSz); CyaSSL_shutdown(sslResume); CyaSSL_free(sslResume); CloseSocket(sockfd); } #endif /* NO_SESSION_CACHE */ CyaSSL_CTX_free(ctx); ((func_args*)args)->return_code = 0; #ifdef USE_CYASSL_MEMORY if (trackMemory) ShowMemoryTracker(); #endif /* USE_CYASSL_MEMORY */ return 0; }
static void test_CyaSSL_UseSNI(void) { #ifdef HAVE_SNI callback_functions client_callbacks = {CyaSSLv23_client_method, 0, 0, 0}; callback_functions server_callbacks = {CyaSSLv23_server_method, 0, 0, 0}; CYASSL_CTX *ctx = CyaSSL_CTX_new(CyaSSLv23_client_method()); CYASSL *ssl = CyaSSL_new(ctx); AssertNotNull(ctx); AssertNotNull(ssl); /* error cases */ AssertIntNE(SSL_SUCCESS, CyaSSL_CTX_UseSNI(NULL, 0, (void *) "ctx", XSTRLEN("ctx"))); AssertIntNE(SSL_SUCCESS, CyaSSL_UseSNI( NULL, 0, (void *) "ssl", XSTRLEN("ssl"))); AssertIntNE(SSL_SUCCESS, CyaSSL_CTX_UseSNI(ctx, -1, (void *) "ctx", XSTRLEN("ctx"))); AssertIntNE(SSL_SUCCESS, CyaSSL_UseSNI( ssl, -1, (void *) "ssl", XSTRLEN("ssl"))); AssertIntNE(SSL_SUCCESS, CyaSSL_CTX_UseSNI(ctx, 0, (void *) NULL, XSTRLEN("ctx"))); AssertIntNE(SSL_SUCCESS, CyaSSL_UseSNI( ssl, 0, (void *) NULL, XSTRLEN("ssl"))); /* success case */ AssertIntEQ(SSL_SUCCESS, CyaSSL_CTX_UseSNI(ctx, 0, (void *) "ctx", XSTRLEN("ctx"))); AssertIntEQ(SSL_SUCCESS, CyaSSL_UseSNI( ssl, 0, (void *) "ssl", XSTRLEN("ssl"))); CyaSSL_free(ssl); CyaSSL_CTX_free(ctx); /* Testing success case at ctx */ client_callbacks.ctx_ready = server_callbacks.ctx_ready = use_SNI_at_ctx; server_callbacks.on_result = verify_SNI_real_matching; test_CyaSSL_client_server(&client_callbacks, &server_callbacks); /* Testing success case at ssl */ client_callbacks.ctx_ready = server_callbacks.ctx_ready = NULL; client_callbacks.ssl_ready = server_callbacks.ssl_ready = use_SNI_at_ssl; test_CyaSSL_client_server(&client_callbacks, &server_callbacks); /* Testing default mismatch behaviour */ client_callbacks.ssl_ready = different_SNI_at_ssl; client_callbacks.on_result = verify_SNI_abort_on_client; server_callbacks.on_result = verify_SNI_abort_on_server; test_CyaSSL_client_server(&client_callbacks, &server_callbacks); client_callbacks.on_result = NULL; /* Testing continue on mismatch */ client_callbacks.ssl_ready = different_SNI_at_ssl; server_callbacks.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl; server_callbacks.on_result = verify_SNI_no_matching; test_CyaSSL_client_server(&client_callbacks, &server_callbacks); /* Testing fake answer on mismatch */ server_callbacks.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl; server_callbacks.on_result = verify_SNI_fake_matching; test_CyaSSL_client_server(&client_callbacks, &server_callbacks); test_CyaSSL_SNI_GetFromBuffer(); #endif }
THREAD_RETURN CYASSL_THREAD server_test(void* args) { SOCKET_T sockfd = 0; SOCKET_T clientfd = 0; SSL_METHOD* method = 0; SSL_CTX* ctx = 0; SSL* ssl = 0; char msg[] = "I hear you fa shizzle!"; char input[80]; int idx; int ch; int version = SERVER_DEFAULT_VERSION; int doCliCertCheck = 1; int useAnyAddr = 0; word16 port = yasslPort; int usePsk = 0; int useAnon = 0; int doDTLS = 0; int useNtruKey = 0; int nonBlocking = 0; int trackMemory = 0; int fewerPackets = 0; int pkCallbacks = 0; int serverReadyFile = 0; char* cipherList = NULL; const char* verifyCert = cliCert; const char* ourCert = svrCert; const char* ourKey = svrKey; int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; #ifdef HAVE_SNI char* sniHostName = NULL; #endif #ifdef HAVE_OCSP int useOcsp = 0; char* ocspUrl = NULL; #endif ((func_args*)args)->return_code = -1; /* error state */ #ifdef NO_RSA verifyCert = (char*)cliEccCert; ourCert = (char*)eccCert; ourKey = (char*)eccKey; #endif (void)trackMemory; (void)pkCallbacks; #ifdef CYASSL_TIRTOS fdOpenSession(Task_self()); #endif while ((ch = mygetopt(argc, argv, "?dbstnNufraPp:v:l:A:c:k:S:oO:")) != -1) { switch (ch) { case '?' : Usage(); exit(EXIT_SUCCESS); case 'd' : doCliCertCheck = 0; break; case 'b' : useAnyAddr = 1; break; case 's' : usePsk = 1; break; case 't' : #ifdef USE_CYASSL_MEMORY trackMemory = 1; #endif break; case 'n' : useNtruKey = 1; break; case 'u' : doDTLS = 1; break; case 'f' : fewerPackets = 1; break; case 'r' : serverReadyFile = 1; break; case 'P' : #ifdef HAVE_PK_CALLBACKS pkCallbacks = 1; #endif break; case 'p' : port = (word16)atoi(myoptarg); #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API) if (port == 0) err_sys("port number cannot be 0"); #endif break; case 'v' : version = atoi(myoptarg); if (version < 0 || version > 3) { Usage(); exit(MY_EX_USAGE); } break; case 'l' : cipherList = myoptarg; break; case 'A' : verifyCert = myoptarg; break; case 'c' : ourCert = myoptarg; break; case 'k' : ourKey = myoptarg; break; case 'N': nonBlocking = 1; break; case 'S' : #ifdef HAVE_SNI sniHostName = myoptarg; #endif break; case 'o' : #ifdef HAVE_OCSP useOcsp = 1; #endif break; case 'O' : #ifdef HAVE_OCSP useOcsp = 1; ocspUrl = myoptarg; #endif break; case 'a' : #ifdef HAVE_ANON useAnon = 1; #endif break; default: Usage(); exit(MY_EX_USAGE); } } myoptind = 0; /* reset for test cases */ /* sort out DTLS versus TLS versions */ if (version == CLIENT_INVALID_VERSION) { if (doDTLS) version = CLIENT_DTLS_DEFAULT_VERSION; else version = CLIENT_DEFAULT_VERSION; } else { if (doDTLS) { if (version == 3) version = -2; else version = -1; } } #ifdef USE_CYASSL_MEMORY if (trackMemory) InitMemoryTracker(); #endif switch (version) { #ifndef NO_OLD_TLS case 0: method = SSLv3_server_method(); break; #ifndef NO_TLS case 1: method = TLSv1_server_method(); break; case 2: method = TLSv1_1_server_method(); break; #endif #endif #ifndef NO_TLS case 3: method = TLSv1_2_server_method(); break; #endif #ifdef CYASSL_DTLS case -1: method = DTLSv1_server_method(); break; case -2: method = DTLSv1_2_server_method(); break; #endif default: err_sys("Bad SSL version"); } if (method == NULL) err_sys("unable to get method"); ctx = SSL_CTX_new(method); if (ctx == NULL) err_sys("unable to get ctx"); if (cipherList) if (SSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 1"); #ifdef CYASSL_LEANPSK usePsk = 1; #endif #if defined(NO_RSA) && !defined(HAVE_ECC) usePsk = 1; #endif if (fewerPackets) CyaSSL_CTX_set_group_messages(ctx); #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (!usePsk && !useAnon) { if (SSL_CTX_use_certificate_file(ctx, ourCert, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server cert file, check file and run from" " CyaSSL home dir"); } #endif #ifdef HAVE_NTRU if (useNtruKey) { if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey) != SSL_SUCCESS) err_sys("can't load ntru key file, " "Please run from CyaSSL home dir"); } #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (!useNtruKey && !usePsk && !useAnon) { if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server private key file, check file and run " "from CyaSSL home dir"); } #endif if (usePsk) { #ifndef NO_PSK SSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb); SSL_CTX_use_psk_identity_hint(ctx, "cyassl server"); if (cipherList == NULL) { const char *defaultCipherList; #ifdef HAVE_NULL_CIPHER defaultCipherList = "PSK-NULL-SHA256"; #else defaultCipherList = "PSK-AES128-CBC-SHA256"; #endif if (SSL_CTX_set_cipher_list(ctx, defaultCipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 2"); } #endif } if (useAnon) { #ifdef HAVE_ANON CyaSSL_CTX_allow_anon_cipher(ctx); if (cipherList == NULL) { if (SSL_CTX_set_cipher_list(ctx, "ADH-AES128-SHA") != SSL_SUCCESS) err_sys("server can't set cipher list 4"); } #endif } #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) /* if not using PSK, verify peer with certs */ if (doCliCertCheck && usePsk == 0 && useAnon == 0) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0); if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from CyaSSL home dir"); } #endif #if defined(CYASSL_SNIFFER) && !defined(HAVE_NTRU) && !defined(HAVE_ECC) /* don't use EDH, can't sniff tmp keys */ if (cipherList == NULL) { if (SSL_CTX_set_cipher_list(ctx, "AES256-SHA256") != SSL_SUCCESS) err_sys("server can't set cipher list 3"); } #endif #ifdef HAVE_SNI if (sniHostName) if (CyaSSL_CTX_UseSNI(ctx, CYASSL_SNI_HOST_NAME, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS) err_sys("UseSNI failed"); #endif ssl = SSL_new(ctx); if (ssl == NULL) err_sys("unable to get SSL"); #ifdef HAVE_CRL CyaSSL_EnableCRL(ssl, 0); CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, CYASSL_CRL_MONITOR | CYASSL_CRL_START_MON); CyaSSL_SetCRL_Cb(ssl, CRL_CallBack); #endif #ifdef HAVE_OCSP if (useOcsp) { if (ocspUrl != NULL) { CyaSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl); CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE | CYASSL_OCSP_URL_OVERRIDE); } else CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE); } #endif #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx, ssl); #endif tcp_accept(&sockfd, &clientfd, (func_args*)args, port, useAnyAddr, doDTLS, serverReadyFile); if (!doDTLS) CloseSocket(sockfd); SSL_set_fd(ssl, clientfd); if (usePsk == 0 || useAnon == 1 || cipherList != NULL) { #if !defined(NO_FILESYSTEM) && !defined(NO_DH) CyaSSL_SetTmpDH_file(ssl, dhParam, SSL_FILETYPE_PEM); #elif !defined(NO_DH) SetDH(ssl); /* repick suites with DHE, higher priority than PSK */ #endif } #ifndef CYASSL_CALLBACKS if (nonBlocking) { CyaSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&clientfd); NonBlockingSSL_Accept(ssl); } else if (SSL_accept(ssl) != SSL_SUCCESS) { int err = SSL_get_error(ssl, 0); char buffer[CYASSL_MAX_ERROR_SZ]; printf("error = %d, %s\n", err, ERR_error_string(err, buffer)); err_sys("SSL_accept failed"); } #else NonBlockingSSL_Accept(ssl); #endif showPeer(ssl); idx = SSL_read(ssl, input, sizeof(input)-1); if (idx > 0) { input[idx] = 0; printf("Client message: %s\n", input); } else if (idx < 0) { int readErr = SSL_get_error(ssl, 0); if (readErr != SSL_ERROR_WANT_READ) err_sys("SSL_read failed"); } if (SSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) err_sys("SSL_write failed"); #if defined(CYASSL_MDK_SHELL) && defined(HAVE_MDK_RTX) os_dly_wait(500) ; #elif defined (CYASSL_TIRTOS) Task_yield(); #endif SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); CloseSocket(clientfd); ((func_args*)args)->return_code = 0; #if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \ && defined(HAVE_THREAD_LS) ecc_fp_free(); /* free per thread cache */ #endif #ifdef USE_CYASSL_MEMORY if (trackMemory) ShowMemoryTracker(); #endif #ifdef CYASSL_TIRTOS fdCloseSession(Task_self()); #endif #ifndef CYASSL_TIRTOS return 0; #endif }
/* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ static CURLcode cyassl_connect_step1(struct connectdata *conn, int sockindex) { char *ciphers; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; #define use_sni(x) sni = (x) #else #define use_sni(x) Curl_nop_stmt #endif if(connssl->state == ssl_connection_complete) return CURLE_OK; if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { failf(data, "CyaSSL does not support to set maximum SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } /* check to see if we've been told to use an explicit SSL/TLS version */ switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ /* minimum protocol version is set later after the CTX object is created */ req_method = SSLv23_client_method(); #else infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " "TLS 1.0 is used exclusively\n"); req_method = TLSv1_client_method(); #endif use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_0: #ifdef WOLFSSL_ALLOW_TLSV10 req_method = TLSv1_client_method(); use_sni(TRUE); #else failf(data, "CyaSSL does not support TLS 1.0"); return CURLE_NOT_BUILT_IN; #endif break; case CURL_SSLVERSION_TLSv1_1: req_method = TLSv1_1_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_2: req_method = TLSv1_2_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_3: #ifdef WOLFSSL_TLS13 req_method = wolfTLSv1_3_client_method(); use_sni(TRUE); break; #else failf(data, "CyaSSL: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; #endif case CURL_SSLVERSION_SSLv3: #ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); #else failf(data, "CyaSSL does not support SSLv3"); return CURLE_NOT_BUILT_IN; #endif break; case CURL_SSLVERSION_SSLv2: failf(data, "CyaSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(!req_method) { failf(data, "SSL: couldn't create a method!"); return CURLE_OUT_OF_MEMORY; } if(BACKEND->ctx) SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = SSL_CTX_new(req_method); if(!BACKEND->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever minimum version of TLS was built in and at least TLS 1.0. For later library versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so we have this short circuit evaluation to find the minimum supported TLS version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion because only the former will work before the user's CTX callback is called. */ if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1) #ifdef WOLFSSL_TLS13 && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1) #endif ) { failf(data, "SSL: couldn't set the minimum protocol version"); return CURLE_SSL_CONNECT_ERROR; } #endif break; } ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } infof(data, "Cipher selection: %s\n", ciphers); } #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", SSL_CONN_CONFIG(CAfile)? SSL_CONN_CONFIG(CAfile): "none", SSL_CONN_CONFIG(CApath)? SSL_CONN_CONFIG(CApath) : "none"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } } else { /* Everything is fine. */ infof(data, "successfully set certificate verify locations:\n"); } infof(data, " CAfile: %s\n" " CApath: %s\n", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none"); } /* Load the client certificate, and private key */ if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } file_type = do_file_type(SSL_SET_OPTION(key_type)); if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } } #endif /* !NO_FILESYSTEM */ /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(BACKEND->ctx, SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI if(sni) { struct in_addr addr4; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; size_t hostname_len = strlen(hostname); if((hostname_len < USHRT_MAX) && (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); } } #endif /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); return result; } } #ifdef NO_FILESYSTEM else if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); return CURLE_SSL_CONNECT_ERROR; } #endif /* Let's make an SSL structure */ if(BACKEND->handle) SSL_free(BACKEND->handle); BACKEND->handle = SSL_new(BACKEND->ctx); if(!BACKEND->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } #ifdef HAVE_ALPN if(conn->bits.tls_enable_alpn) { char protocols[128]; *protocols = '\0'; /* wolfSSL's ALPN protocol name list format is a comma separated string of protocols in descending order of preference, eg: "h2,http/1.1" */ #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); if(wolfSSL_UseALPN(BACKEND->handle, protocols, (unsigned)strlen(protocols), WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { failf(data, "SSL: failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } } #endif /* HAVE_ALPN */ /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { char error_buffer[CYASSL_MAX_ERROR_SZ]; Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof(data, "SSL re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layer */ if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; return CURLE_OK; }
/* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ static CURLcode cyassl_connect_step1(struct connectdata *conn, int sockindex) { char error_buffer[CYASSL_MAX_ERROR_SZ]; struct SessionHandle *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; void* ssl_sessionid = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; #define use_sni(x) sni = (x) #else #define use_sni(x) Curl_nop_stmt #endif if(conssl->state == ssl_connection_complete) return CURLE_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ switch(data->set.ssl.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ /* minimum protocol version is set later after the CTX object is created */ req_method = SSLv23_client_method(); #else infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " "TLS 1.0 is used exclusively\n"); req_method = TLSv1_client_method(); #endif use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_0: req_method = TLSv1_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_1: req_method = TLSv1_1_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_2: req_method = TLSv1_2_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: req_method = SSLv3_client_method(); use_sni(FALSE); break; case CURL_SSLVERSION_SSLv2: failf(data, "CyaSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(!req_method) { failf(data, "SSL: couldn't create a method!"); return CURLE_OUT_OF_MEMORY; } if(conssl->ctx) SSL_CTX_free(conssl->ctx); conssl->ctx = SSL_CTX_new(req_method); if(!conssl->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } switch(data->set.ssl.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever minimum version of TLS was built in and at least TLS 1.0. For later library versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so we have this short circuit evaluation to find the minimum supported TLS version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion because only the former will work before the user's CTX callback is called. */ if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) && (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) && (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) { failf(data, "SSL: couldn't set the minimum protocol version"); return CURLE_SSL_CONNECT_ERROR; } #endif break; } #ifndef NO_FILESYSTEM /* load trusted cacert */ if(data->set.str[STRING_SSL_CAFILE]) { if(1 != SSL_CTX_load_verify_locations(conssl->ctx, data->set.str[STRING_SSL_CAFILE], data->set.str[STRING_SSL_CAPATH])) { if(data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", data->set.str[STRING_SSL_CAFILE]? data->set.str[STRING_SSL_CAFILE]: "none", data->set.str[STRING_SSL_CAPATH]? data->set.str[STRING_SSL_CAPATH] : "none"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } } else { /* Everything is fine. */ infof(data, "successfully set certificate verify locations:\n"); } infof(data, " CAfile: %s\n" " CApath: %s\n", data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: "none", data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: "none"); } /* Load the client certificate, and private key */ if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) { int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]); if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT], file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } file_type = do_file_type(data->set.str[STRING_KEY_TYPE]); if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY], file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } } #endif /* !NO_FILESYSTEM */ /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(conssl->ctx, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI if(sni) { struct in_addr addr4; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif size_t hostname_len = strlen(conn->host.name); if((hostname_len < USHRT_MAX) && (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) && #endif (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); } } #endif /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; result = (*data->set.ssl.fsslctx)(data, conssl->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); return result; } } #ifdef NO_FILESYSTEM else if(data->set.ssl.verifypeer) { failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); return CURLE_SSL_CONNECT_ERROR; } #endif /* Let's make an SSL structure */ if(conssl->handle) SSL_free(conssl->handle); conssl->handle = SSL_new(conssl->ctx); if(!conssl->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } /* Check if there's a cached ID we can/should use here! */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { /* we got a session id, use it! */ if(!SSL_set_session(conssl->handle, ssl_sessionid)) { failf(data, "SSL: SSL_set_session failed: %s", ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof (data, "SSL re-using session ID\n"); } /* pass the raw socket into the SSL layer */ if(!SSL_set_fd(conssl->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } conssl->connecting_state = ssl_connect_2; return CURLE_OK; }
THREAD_RETURN CYASSL_THREAD server_test(void* args) { SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID; SOCKET_T clientfd = WOLFSSL_SOCKET_INVALID; SSL_METHOD* method = 0; SSL_CTX* ctx = 0; SSL* ssl = 0; const char msg[] = "I hear you fa shizzle!"; char input[80]; int ch; int version = SERVER_DEFAULT_VERSION; int doCliCertCheck = 1; int useAnyAddr = 0; word16 port = wolfSSLPort; int usePsk = 0; int usePskPlus = 0; int useAnon = 0; int doDTLS = 0; int needDH = 0; int useNtruKey = 0; int nonBlocking = 0; int trackMemory = 0; int fewerPackets = 0; int pkCallbacks = 0; int wc_shutdown = 0; int resume = 0; int resumeCount = 0; int loopIndefinitely = 0; int echoData = 0; int throughput = 0; int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; short minRsaKeyBits = DEFAULT_MIN_RSAKEY_BITS; short minEccKeyBits = DEFAULT_MIN_ECCKEY_BITS; int doListen = 1; int crlFlags = 0; int ret; int err = 0; char* serverReadyFile = NULL; char* alpnList = NULL; unsigned char alpn_opt = 0; char* cipherList = NULL; const char* verifyCert = cliCert; const char* ourCert = svrCert; const char* ourKey = svrKey; const char* ourDhParam = dhParam; tcp_ready* readySignal = NULL; int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; #ifdef WOLFSSL_TRUST_PEER_CERT const char* trustCert = NULL; #endif #ifndef NO_PSK int sendPskIdentityHint = 1; #endif #ifdef HAVE_SNI char* sniHostName = NULL; #endif #ifdef HAVE_OCSP int useOcsp = 0; char* ocspUrl = NULL; #endif ((func_args*)args)->return_code = -1; /* error state */ #ifdef NO_RSA verifyCert = (char*)cliEccCert; ourCert = (char*)eccCert; ourKey = (char*)eccKey; #endif (void)trackMemory; (void)pkCallbacks; (void)needDH; (void)ourKey; (void)ourCert; (void)ourDhParam; (void)verifyCert; (void)useNtruKey; (void)doCliCertCheck; (void)minDhKeyBits; (void)minRsaKeyBits; (void)minEccKeyBits; (void)alpnList; (void)alpn_opt; (void)crlFlags; (void)readySignal; #ifdef CYASSL_TIRTOS fdOpenSession(Task_self()); #endif #ifdef WOLFSSL_VXWORKS useAnyAddr = 1; #else while ((ch = mygetopt(argc, argv, "?jdbstnNufrawPIR:p:v:l:A:c:k:Z:S:oO:D:L:ieB:E:")) != -1) { switch (ch) { case '?' : Usage(); exit(EXIT_SUCCESS); case 'd' : doCliCertCheck = 0; break; case 'b' : useAnyAddr = 1; break; case 's' : usePsk = 1; break; case 'j' : usePskPlus = 1; break; case 't' : #ifdef USE_WOLFSSL_MEMORY trackMemory = 1; #endif break; case 'n' : useNtruKey = 1; break; case 'u' : doDTLS = 1; break; case 'f' : fewerPackets = 1; break; case 'R' : serverReadyFile = myoptarg; break; case 'r' : #ifndef NO_SESSION_CACHE resume = 1; #endif break; case 'P' : #ifdef HAVE_PK_CALLBACKS pkCallbacks = 1; #endif break; case 'p' : port = (word16)atoi(myoptarg); break; case 'w' : wc_shutdown = 1; break; case 'v' : version = atoi(myoptarg); if (version < 0 || version > 3) { Usage(); exit(MY_EX_USAGE); } break; case 'l' : cipherList = myoptarg; break; case 'A' : verifyCert = myoptarg; break; case 'c' : ourCert = myoptarg; break; case 'k' : ourKey = myoptarg; break; case 'D' : #ifndef NO_DH ourDhParam = myoptarg; #endif break; case 'Z' : #ifndef NO_DH minDhKeyBits = atoi(myoptarg); if (minDhKeyBits <= 0 || minDhKeyBits > 16000) { Usage(); exit(MY_EX_USAGE); } #endif break; case 'N': nonBlocking = 1; break; case 'S' : #ifdef HAVE_SNI sniHostName = myoptarg; #endif break; case 'o' : #ifdef HAVE_OCSP useOcsp = 1; #endif break; case 'O' : #ifdef HAVE_OCSP useOcsp = 1; ocspUrl = myoptarg; #endif break; case 'a' : #ifdef HAVE_ANON useAnon = 1; #endif break; case 'I': #ifndef NO_PSK sendPskIdentityHint = 0; #endif break; case 'L' : #ifdef HAVE_ALPN alpnList = myoptarg; if (alpnList[0] == 'C' && alpnList[1] == ':') alpn_opt = WOLFSSL_ALPN_CONTINUE_ON_MISMATCH; else if (alpnList[0] == 'F' && alpnList[1] == ':') alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH; else { Usage(); exit(MY_EX_USAGE); } alpnList += 2; #endif break; case 'i' : loopIndefinitely = 1; break; case 'e' : echoData = 1; break; case 'B': throughput = atoi(myoptarg); if (throughput <= 0) { Usage(); exit(MY_EX_USAGE); } break; #ifdef WOLFSSL_TRUST_PEER_CERT case 'E' : trustCert = myoptarg; break; #endif default: Usage(); exit(MY_EX_USAGE); } } myoptind = 0; /* reset for test cases */ #endif /* !WOLFSSL_VXWORKS */ /* sort out DTLS versus TLS versions */ if (version == CLIENT_INVALID_VERSION) { if (doDTLS) version = CLIENT_DTLS_DEFAULT_VERSION; else version = CLIENT_DEFAULT_VERSION; } else { if (doDTLS) { if (version == 3) version = -2; else version = -1; } } #ifdef USE_CYASSL_MEMORY if (trackMemory) InitMemoryTracker(); #endif switch (version) { #ifndef NO_OLD_TLS #ifdef WOLFSSL_ALLOW_SSLV3 case 0: method = SSLv3_server_method(); break; #endif #ifndef NO_TLS case 1: method = TLSv1_server_method(); break; case 2: method = TLSv1_1_server_method(); break; #endif #endif #ifndef NO_TLS case 3: method = TLSv1_2_server_method(); break; #endif #ifdef CYASSL_DTLS #ifndef NO_OLD_TLS case -1: method = DTLSv1_server_method(); break; #endif case -2: method = DTLSv1_2_server_method(); break; #endif default: err_sys("Bad SSL version"); } if (method == NULL) err_sys("unable to get method"); ctx = SSL_CTX_new(method); if (ctx == NULL) err_sys("unable to get ctx"); #if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ defined(HAVE_POLY1305) if (TicketInit() != 0) err_sys("unable to setup Session Ticket Key context"); wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb); #endif if (cipherList) if (SSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 1"); #ifdef CYASSL_LEANPSK if (!usePsk) { usePsk = 1; } #endif #if defined(NO_RSA) && !defined(HAVE_ECC) if (!usePsk) { usePsk = 1; } #endif if (fewerPackets) CyaSSL_CTX_set_group_messages(ctx); #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if ((!usePsk || usePskPlus) && !useAnon) { if (SSL_CTX_use_certificate_chain_file(ctx, ourCert) != SSL_SUCCESS) err_sys("can't load server cert file, check file and run from" " wolfSSL home dir"); } #endif #ifndef NO_DH if (wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits) != SSL_SUCCESS) { err_sys("Error setting minimum DH key size"); } #endif #ifndef NO_RSA if (wolfSSL_CTX_SetMinRsaKey_Sz(ctx, minRsaKeyBits) != SSL_SUCCESS){ err_sys("Error setting minimum RSA key size"); } #endif #ifdef HAVE_ECC if (wolfSSL_CTX_SetMinEccKey_Sz(ctx, minEccKeyBits) != SSL_SUCCESS){ err_sys("Error setting minimum ECC key size"); } #endif #ifdef HAVE_NTRU if (useNtruKey) { if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey) != SSL_SUCCESS) err_sys("can't load ntru key file, " "Please run from wolfSSL home dir"); } #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (!useNtruKey && (!usePsk || usePskPlus) && !useAnon) { if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server private key file, check file and run " "from wolfSSL home dir"); } #endif if (usePsk || usePskPlus) { #ifndef NO_PSK SSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb); if (sendPskIdentityHint == 1) SSL_CTX_use_psk_identity_hint(ctx, "cyassl server"); if (cipherList == NULL && !usePskPlus) { const char *defaultCipherList; #if defined(HAVE_AESGCM) && !defined(NO_DH) defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; needDH = 1; #elif defined(HAVE_NULL_CIPHER) defaultCipherList = "PSK-NULL-SHA256"; #else defaultCipherList = "PSK-AES128-CBC-SHA256"; #endif if (SSL_CTX_set_cipher_list(ctx, defaultCipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 2"); } #endif } if (useAnon) { #ifdef HAVE_ANON CyaSSL_CTX_allow_anon_cipher(ctx); if (cipherList == NULL) { if (SSL_CTX_set_cipher_list(ctx, "ADH-AES128-SHA") != SSL_SUCCESS) err_sys("server can't set cipher list 4"); } #endif } #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) /* if not using PSK, verify peer with certs if using PSK Plus then verify peer certs except PSK suites */ if (doCliCertCheck && (usePsk == 0 || usePskPlus) && useAnon == 0) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | ((usePskPlus)? SSL_VERIFY_FAIL_EXCEPT_PSK : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),0); if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from wolfSSL home dir"); #ifdef WOLFSSL_TRUST_PEER_CERT if (trustCert) { if ((ret = wolfSSL_CTX_trust_peer_cert(ctx, trustCert, SSL_FILETYPE_PEM)) != SSL_SUCCESS) { err_sys("can't load trusted peer cert file"); } } #endif /* WOLFSSL_TRUST_PEER_CERT */ } #endif #if defined(CYASSL_SNIFFER) /* don't use EDH, can't sniff tmp keys */ if (cipherList == NULL) { if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") != SSL_SUCCESS) err_sys("server can't set cipher list 3"); } #endif #ifdef HAVE_SNI if (sniHostName) if (CyaSSL_CTX_UseSNI(ctx, CYASSL_SNI_HOST_NAME, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS) err_sys("UseSNI failed"); #endif #ifdef USE_WINDOWS_API if (port == 0) { /* Generate random port for testing */ port = GetRandomPort(); } #endif /* USE_WINDOWS_API */ while (1) { /* allow resume option */ if(resumeCount > 1) { if (doDTLS == 0) { SOCKADDR_IN_T client; socklen_t client_len = sizeof(client); clientfd = accept(sockfd, (struct sockaddr*)&client, (ACCEPT_THIRD_T)&client_len); } else { tcp_listen(&sockfd, &port, useAnyAddr, doDTLS); clientfd = sockfd; } if(WOLFSSL_SOCKET_IS_INVALID(clientfd)) { err_sys("tcp accept failed"); } } ssl = SSL_new(ctx); if (ssl == NULL) err_sys("unable to get SSL"); #ifndef NO_HANDSHAKE_DONE_CB wolfSSL_SetHsDoneCb(ssl, myHsDoneCb, NULL); #endif #ifdef HAVE_CRL #ifdef HAVE_CRL_MONITOR crlFlags = CYASSL_CRL_MONITOR | CYASSL_CRL_START_MON; #endif if (CyaSSL_EnableCRL(ssl, 0) != SSL_SUCCESS) err_sys("unable to enable CRL"); if (CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, crlFlags) != SSL_SUCCESS) err_sys("unable to load CRL"); if (CyaSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS) err_sys("unable to set CRL callback url"); #endif #ifdef HAVE_OCSP if (useOcsp) { if (ocspUrl != NULL) { CyaSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl); CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE | CYASSL_OCSP_URL_OVERRIDE); } else CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE); } #endif #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) if (wolfSSL_CTX_EnableOCSPStapling(ctx) != SSL_SUCCESS) err_sys("can't enable OCSP Stapling Certificate Manager"); if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate1-ca-cert.pem", 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from wolfSSL home dir"); if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate2-ca-cert.pem", 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from wolfSSL home dir"); if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate3-ca-cert.pem", 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from wolfSSL home dir"); #endif #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx, ssl); #endif /* do accept */ readySignal = ((func_args*)args)->signal; if (readySignal) { readySignal->srfName = serverReadyFile; } tcp_accept(&sockfd, &clientfd, (func_args*)args, port, useAnyAddr, doDTLS, serverReadyFile ? 1 : 0, doListen); doListen = 0; /* Don't listen next time */ if (SSL_set_fd(ssl, clientfd) != SSL_SUCCESS) { err_sys("error in setting fd"); } #ifdef HAVE_ALPN if (alpnList != NULL) { printf("ALPN accepted protocols list : %s\n", alpnList); wolfSSL_UseALPN(ssl, alpnList, (word32)XSTRLEN(alpnList), alpn_opt); } #endif #ifdef WOLFSSL_DTLS if (doDTLS) { SOCKADDR_IN_T cliaddr; byte b[1500]; int n; socklen_t len = sizeof(cliaddr); /* For DTLS, peek at the next datagram so we can get the client's * address and set it into the ssl object later to generate the * cookie. */ n = (int)recvfrom(sockfd, (char*)b, sizeof(b), MSG_PEEK, (struct sockaddr*)&cliaddr, &len); if (n <= 0) err_sys("recvfrom failed"); wolfSSL_dtls_set_peer(ssl, &cliaddr, len); } #endif if ((usePsk == 0 || usePskPlus) || useAnon == 1 || cipherList != NULL || needDH == 1) { #if !defined(NO_FILESYSTEM) && !defined(NO_DH) && !defined(NO_ASN) CyaSSL_SetTmpDH_file(ssl, ourDhParam, SSL_FILETYPE_PEM); #elif !defined(NO_DH) SetDH(ssl); /* repick suites with DHE, higher priority than PSK */ #endif } #ifndef CYASSL_CALLBACKS if (nonBlocking) { CyaSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&clientfd); } #endif do { #ifdef WOLFSSL_ASYNC_CRYPT if (err == WC_PENDING_E) { ret = AsyncCryptPoll(ssl); if (ret < 0) { break; } else if (ret == 0) { continue; } } #endif err = 0; /* Reset error */ #ifndef CYASSL_CALLBACKS if (nonBlocking) { ret = NonBlockingSSL_Accept(ssl); } else { ret = SSL_accept(ssl); } #else ret = NonBlockingSSL_Accept(ssl); #endif if (ret != SSL_SUCCESS) { err = SSL_get_error(ssl, 0); } } while (ret != SSL_SUCCESS && err == WC_PENDING_E); if (ret != SSL_SUCCESS) { char buffer[CYASSL_MAX_ERROR_SZ]; err = SSL_get_error(ssl, 0); printf("error = %d, %s\n", err, ERR_error_string(err, buffer)); err_sys("SSL_accept failed"); } showPeer(ssl); #ifdef HAVE_ALPN if (alpnList != NULL) { char *protocol_name = NULL, *list = NULL; word16 protocol_nameSz = 0, listSz = 0; err = wolfSSL_ALPN_GetProtocol(ssl, &protocol_name, &protocol_nameSz); if (err == SSL_SUCCESS) printf("Sent ALPN protocol : %s (%d)\n", protocol_name, protocol_nameSz); else if (err == SSL_ALPN_NOT_FOUND) printf("No ALPN response sent (no match)\n"); else printf("Getting ALPN protocol name failed\n"); err = wolfSSL_ALPN_GetPeerProtocol(ssl, &list, &listSz); if (err == SSL_SUCCESS) printf("List of protocol names sent by Client: %s (%d)\n", list, listSz); else printf("Get list of client's protocol name failed\n"); free(list); } #endif if(echoData == 0 && throughput == 0) { ret = SSL_read(ssl, input, sizeof(input)-1); if (ret > 0) { input[ret] = 0; printf("Client message: %s\n", input); } else if (ret < 0) { int readErr = SSL_get_error(ssl, 0); if (readErr != SSL_ERROR_WANT_READ) err_sys("SSL_read failed"); } if (SSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) err_sys("SSL_write failed"); } else { ServerEchoData(ssl, clientfd, echoData, throughput); } #if defined(WOLFSSL_MDK_SHELL) && defined(HAVE_MDK_RTX) os_dly_wait(500) ; #elif defined (CYASSL_TIRTOS) Task_yield(); #endif if (doDTLS == 0) { ret = SSL_shutdown(ssl); if (wc_shutdown && ret == SSL_SHUTDOWN_NOT_DONE) SSL_shutdown(ssl); /* bidirectional shutdown */ } SSL_free(ssl); CloseSocket(clientfd); if (resume == 1 && resumeCount == 0) { resumeCount++; /* only do one resume for testing */ continue; } resumeCount = 0; if(!loopIndefinitely) { break; /* out of while loop, done with normal and resume option */ } } /* while(1) */ CloseSocket(sockfd); SSL_CTX_free(ctx); ((func_args*)args)->return_code = 0; #if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \ && defined(HAVE_THREAD_LS) ecc_fp_free(); /* free per thread cache */ #endif #ifdef USE_WOLFSSL_MEMORY if (trackMemory) ShowMemoryTracker(); #endif #ifdef CYASSL_TIRTOS fdCloseSession(Task_self()); #endif #if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ defined(HAVE_POLY1305) TicketCleanup(); #endif /* There are use cases when these assignments are not read. To avoid * potential confusion those warnings have been handled here. */ (void) ourKey; (void) verifyCert; (void) doCliCertCheck; (void) useNtruKey; (void) ourDhParam; (void) ourCert; #ifndef CYASSL_TIRTOS return 0; #endif }