MONO_API int mono_btls_ssl_get_ciphers (MonoBtlsSsl *ptr, uint16_t **data) { STACK_OF(SSL_CIPHER) *ciphers; int count, i; *data = NULL; ciphers = SSL_get_ciphers (ptr->ssl); if (!ciphers) return 0; count = (int)sk_SSL_CIPHER_num (ciphers); *data = OPENSSL_malloc (2 * count); if (!*data) return 0; for (i = 0; i < count; i++) { const SSL_CIPHER *cipher = sk_SSL_CIPHER_value (ciphers, i); (*data) [i] = (uint16_t) SSL_CIPHER_get_id (cipher); } return count; }
static int use_ecc(SSL *s) { int i, end; unsigned long alg_k, alg_a; STACK_OF(SSL_CIPHER) *cipher_stack = NULL; /* See if we support any ECC ciphersuites */ if (s->version == SSL3_VERSION) return 0; cipher_stack = SSL_get_ciphers(s); end = sk_SSL_CIPHER_num(cipher_stack); for (i = 0; i < end; i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); alg_k = c->algorithm_mkey; alg_a = c->algorithm_auth; if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) || (alg_a & SSL_aECDSA) || c->min_tls >= TLS1_3_VERSION) break; } return i < end; }
char *SSL_make_ciphersuite(pool *p, SSL *ssl) { STACK_OF(SSL_CIPHER) *sk; SSL_CIPHER *c; int i; int l; char *cpCipherSuite; char *cp; if (ssl == NULL) return ""; if ((sk = SSL_get_ciphers(ssl)) == NULL) return ""; l = 0; for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { c = sk_SSL_CIPHER_value(sk, i); l += strlen(c->name)+2+1; } if (l == 0) return ""; cpCipherSuite = (char *)ap_palloc(p, l+1); cp = cpCipherSuite; for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { c = sk_SSL_CIPHER_value(sk, i); l = strlen(c->name); memcpy(cp, c->name, l); cp += l; *cp++ = '/'; *cp++ = (c->valid == 1 ? '1' : '0'); *cp++ = ':'; } *(cp-1) = NUL; return cpCipherSuite; }
static std::unordered_map<uint16_t, std::string> getOpenSSLCipherNames() { std::unordered_map<uint16_t, std::string> ret; SSL_CTX* ctx = nullptr; SSL* ssl = nullptr; const SSL_METHOD* meth = SSLv23_server_method(); OpenSSL_add_ssl_algorithms(); if ((ctx = SSL_CTX_new(meth)) == nullptr) { return ret; } SCOPE_EXIT { SSL_CTX_free(ctx); }; if ((ssl = SSL_new(ctx)) == nullptr) { return ret; } SCOPE_EXIT { SSL_free(ssl); }; STACK_OF(SSL_CIPHER)* sk = SSL_get_ciphers(ssl); for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER* c = sk_SSL_CIPHER_value(sk, i); unsigned long id = SSL_CIPHER_get_id(c); // OpenSSL 1.0.2 and prior does weird things such as stuff the SSL/TLS // version into the top 16 bits. Let's ignore those for now. This is // BoringSSL compatible (their id can be cast as uint16_t) uint16_t cipherCode = id & 0xffffL; ret[cipherCode] = SSL_CIPHER_get_name(c); } return ret; }
/** * Adds Ciphers to the Cipher List structure * * @param options Options for this run * @param ssl_method SSL method to populate ciphers for. * @return Boolean: true = success | false = error */ int populate_ciphers(struct sslCheckOptions *options, const SSL_METHOD *ssl_method) { struct sslCipher *cipher_ptr; int i; // STACK_OF is a sign that you should be using C++ :) STACK_OF(SSL_CIPHER) *cipher_list; SSL_CTX *ctx; SSL *ssl = NULL; ctx = SSL_CTX_new(ssl_method); if (ctx == NULL) { printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); return false; } SSL_CTX_set_cipher_list(ctx, "ALL:COMPLEMENTOFALL"); ssl = SSL_new(ctx); if (ssl == NULL) { printf("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); SSL_CTX_free(ctx); return false; } cipher_list = SSL_get_ciphers(ssl); if (options->ciphers != NULL) { cipher_ptr = options->ciphers; while (cipher_ptr->next != NULL) cipher_ptr = cipher_ptr->next; } // Create Cipher Struct Entries... for (i = 0; i < sk_SSL_CIPHER_num(cipher_list); i++) { if (options->ciphers == NULL) { options->ciphers = malloc(sizeof(struct sslCipher)); cipher_ptr = options->ciphers; } else { cipher_ptr->next = malloc(sizeof(struct sslCipher)); cipher_ptr = cipher_ptr->next; } memset(cipher_ptr, 0, sizeof(struct sslCipher)); cipher_ptr->next = NULL; // Add cipher information... cipher_ptr->sslMethod = ssl_method; cipher_ptr->name = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(cipher_list, i)); cipher_ptr->version = SSL_CIPHER_get_version(sk_SSL_CIPHER_value(cipher_list, i)); SSL_CIPHER_description(sk_SSL_CIPHER_value(cipher_list, i), cipher_ptr->description, sizeof(cipher_ptr->description) - 1); cipher_ptr->bits = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(cipher_list, i), &cipher_ptr->alg_bits); } SSL_free(ssl); SSL_CTX_free(ctx); return true; }
static int ssl23_no_ssl2_ciphers(SSL *s) { SSL_CIPHER *cipher; STACK_OF(SSL_CIPHER) *ciphers; int i; ciphers = SSL_get_ciphers(s); for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { cipher = sk_SSL_CIPHER_value(ciphers, i); if (cipher->algorithm_ssl == SSL_SSLV2) return 0; } return 1; }
bud_context_pkey_type_t bud_context_select_pkey(bud_context_t* context, SSL* s) { SSL_SESSION* sess; const SSL_CIPHER* cipher; sess = SSL_get_session(s); if (sess == NULL) return kBudContextPKeyRSA; /* Use session cipher */ cipher = sess->cipher; /* Select cipher */ if (cipher == NULL) cipher = ssl3_choose_cipher(s, sess->ciphers, SSL_get_ciphers(s)); if (cipher == NULL) return kBudContextPKeyRSA; if ((cipher->algorithm_auth & SSL_aECDSA) == SSL_aECDSA) return kBudContextPKeyECC; return kBudContextPKeyRSA; }
/* Switch on a filedescriptor */ int ggz_tls_enable_fd(int fd, GGZTLSType mode, GGZTLSVerificationType verify) { int ret, ret2; STACK_OF(SSL_CIPHER) *stack; SSL_CIPHER *cipher; int bits; char *cipherlist; SSL *_tls; int _tls_active; struct list_entry *entry; _state = 1; _tls_active = 0; if((mode != GGZ_TLS_CLIENT) && (mode != GGZ_TLS_SERVER)) { TLSERROR("Wrong mode."); return 0; } if(!_tlsctx) tls_init(verify); _tls = SSL_new(_tlsctx); if(_tls) { cipherlist = NULL; stack = SSL_get_ciphers(_tls); while((cipher = (SSL_CIPHER*)sk_pop(stack)) != NULL) { printf("* Cipher: %s\n", SSL_CIPHER_get_name(cipher)); printf(" Bits: %i\n", SSL_CIPHER_get_bits(cipher, &bits)); printf(" Used bits: %i\n", bits); printf(" Version: %s\n", SSL_CIPHER_get_version(cipher)); printf(" Description: %s\n", SSL_CIPHER_description(cipher, NULL, 0)); if(cipherlist) { cipherlist = (char*)realloc(cipherlist, (strlen(cipherlist) + 1) + strlen(SSL_CIPHER_get_name(cipher)) + 1); strcat(cipherlist, ":"); strcat(cipherlist, SSL_CIPHER_get_name(cipher)); } else { cipherlist = (char*)malloc(strlen(SSL_CIPHER_get_name(cipher)) + 1); strcpy(cipherlist, SSL_CIPHER_get_name(cipher)); } } printf("Available ciphers: %s\n", cipherlist); ret = SSL_set_cipher_list(_tls, cipherlist); if(!ret) TLSERROR("Cipher selection failed."); ret = SSL_set_fd(_tls, fd); if(!ret) TLSERROR("Assignment to connection failed."); else { SSL_set_read_ahead(_tls, 1); if(mode == GGZ_TLS_SERVER) { tls_certkey(_tls); if(_state) { SSL_set_accept_state(_tls); ret = SSL_accept(_tls); } } else { SSL_set_connect_state(_tls); ret = SSL_connect(_tls); } if((ret != 1) || (!_state)) { printf("Ret: %i, State: %i\n", ret, _state); TLSERROR("Handshake failed."); ret2 = ERR_get_error(); printf("EXT: %s\n%s\n%s\n%s\n%s\n", tls_exterror(_tls, ret), ERR_error_string(ret2, NULL), ERR_lib_error_string(ret2), ERR_func_error_string(ret2), ERR_reason_error_string(ret2)); } else { printf(">>>>> Handshake successful.\n"); if((mode == GGZ_TLS_SERVER) || (verify == GGZ_TLS_VERIFY_NONE)) _tls_active = 1; else { printf(">>>>> Client side, thus checking Certificate.\n"); printf("Negotiated cipher: %s\n", SSL_get_cipher(_tls)); printf("Shared ciphers: %s\n", SSL_get_shared_ciphers(_tls, NULL, 0)); if(SSL_get_peer_certificate(_tls)) { if(SSL_get_verify_result(_tls) == X509_V_OK) { _tls_active = 1; } else { printf("Error code: %li\n", SSL_get_verify_result(_tls)); TLSERROR("Invalid certificate, or certificate is not self-signed."); } } else TLSERROR("Couldn't get certificate."); } } entry = (struct list_entry*)ggz_malloc(sizeof(struct list_entry)); entry->tls = _tls; entry->fd = fd; entry->active = _tls_active; ggz_list_insert(openssllist, entry); return 1; } } return 0; }
int ciphers_main(int argc, char **argv) { char *cipherlist = NULL; STACK_OF(SSL_CIPHER) *ciphers; const SSL_CIPHER *cipher; SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; uint16_t value; int i, rv = 0; char *desc; if (single_execution) { if (pledge("stdio rpath", NULL) == -1) { perror("pledge"); exit(1); } } memset(&ciphers_config, 0, sizeof(ciphers_config)); if (options_parse(argc, argv, ciphers_options, &cipherlist, NULL) != 0) { ciphers_usage(); return (1); } if (ciphers_config.usage) { ciphers_usage(); return (1); } if ((ssl_ctx = SSL_CTX_new(TLSv1_client_method())) == NULL) goto err; if (cipherlist != NULL) { if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0) goto err; } if ((ssl = SSL_new(ssl_ctx)) == NULL) goto err; if ((ciphers = SSL_get_ciphers(ssl)) == NULL) goto err; for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { cipher = sk_SSL_CIPHER_value(ciphers, i); if (ciphers_config.verbose == 0) { fprintf(stdout, "%s%s", (i ? ":" : ""), SSL_CIPHER_get_name(cipher)); continue; } if (ciphers_config.verbose > 1) { value = SSL_CIPHER_get_value(cipher); fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "", ((value >> 8) & 0xff), (value & 0xff)); } desc = SSL_CIPHER_description(cipher, NULL, 0); if (strcmp(desc, "OPENSSL_malloc Error") == 0) { fprintf(stderr, "out of memory\n"); goto err; } fprintf(stdout, "%s", desc); free(desc); }
int connect_dtls_socket(struct openconnect_info *vpninfo) { STACK_OF(SSL_CIPHER) *ciphers; method_const SSL_METHOD *dtls_method; SSL_CIPHER *dtls_cipher; SSL *dtls_ssl; BIO *dtls_bio; int dtls_fd; if (!vpninfo->dtls_addr) { vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } if (!vpninfo->dtls_cipher) { /* We probably didn't offer it any ciphers it liked */ vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } if (vpninfo->proxy) { /* XXX: Theoretically, SOCKS5 proxies can do UDP too */ vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); if (dtls_fd < 0) { perror(_("Open UDP socket for DTLS:")); return -EINVAL; } if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) { perror(_("UDP (DTLS) connect:\n")); close(dtls_fd); return -EINVAL; } fcntl(dtls_fd, F_SETFD, FD_CLOEXEC); if (!vpninfo->dtls_ctx) { dtls_method = DTLSv1_client_method(); vpninfo->dtls_ctx = SSL_CTX_new(dtls_method); if (!vpninfo->dtls_ctx) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 CTX failed\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* If we don't readahead, then we do short reads and throw away the tail of data packets. */ SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1); if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS cipher list failed\n")); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } } if (!vpninfo->dtls_session) { /* We're going to "resume" a session which never existed. Fake it... */ vpninfo->dtls_session = SSL_SESSION_new(); if (!vpninfo->dtls_session) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 session failed\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */ } /* Do this every time; it may have changed due to a rekey */ vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret); memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)); vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id); memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id, sizeof(vpninfo->dtls_session_id)); dtls_ssl = SSL_new(vpninfo->dtls_ctx); SSL_set_connect_state(dtls_ssl); ciphers = SSL_get_ciphers(dtls_ssl); if (sk_SSL_CIPHER_num(ciphers) != 1) { vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n")); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); SSL_SESSION_free(vpninfo->dtls_session); vpninfo->dtls_ctx = NULL; vpninfo->dtls_session = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0); /* Set the appropriate cipher on our session to be resumed */ vpninfo->dtls_session->cipher = dtls_cipher; vpninfo->dtls_session->cipher_id = dtls_cipher->id; /* Add the generated session to the SSL */ if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) { vpn_progress(vpninfo, PRG_ERR, _("SSL_set_session() failed with old protocol version 0x%x\n" "Are you using a version of OpenSSL older than 0.9.8m?\n" "See http://rt.openssl.org/Ticket/Display.html?id=1751\n" "Use the --no-dtls command line option to avoid this message\n"), vpninfo->dtls_session->ssl_version); vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* Go Go Go! */ dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE); SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio); SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT); /* Set non-blocking */ BIO_set_nbio(SSL_get_rbio(dtls_ssl), 1); BIO_set_nbio(SSL_get_wbio(dtls_ssl), 1); fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK); vpninfo->new_dtls_fd = dtls_fd; vpninfo->new_dtls_ssl = dtls_ssl; if (vpninfo->select_nfds <= dtls_fd) vpninfo->select_nfds = dtls_fd + 1; FD_SET(dtls_fd, &vpninfo->select_rfds); FD_SET(dtls_fd, &vpninfo->select_efds); time(&vpninfo->new_dtls_started); return dtls_try_handshake(vpninfo); }
int dtls1_client_hello(SSL *s) { unsigned char *buf; unsigned char *p, *d; unsigned int i; unsigned long l; buf = (unsigned char *)s->init_buf->data; if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { SSL_SESSION *sess = s->session; if ((s->session == NULL) || (s->session->ssl_version != s->version) || (!sess->session_id_length && !sess->tlsext_tick) || (s->session->not_resumable)) { if (!ssl_get_new_session(s, 0)) goto err; } /* else use the pre-loaded session */ p = s->s3->client_random; /* if client_random is initialized, reuse it, we are * required to use same upon reply to HelloVerify */ for (i = 0; p[i]=='\0' && i < sizeof(s->s3->client_random); i++) ; if (i == sizeof(s->s3->client_random)) RAND_pseudo_bytes(p, sizeof(s->s3->client_random)); /* Do the message type and length last */ d = p = &(buf[DTLS1_HM_HEADER_LENGTH]); *(p++) = s->version >> 8; *(p++) = s->version&0xff; s->client_version = s->version; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID */ if (s->new_session) i = 0; else i = s->session->session_id_length; *(p++) = i; if (i != 0) { if (i > sizeof s->session->session_id) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } memcpy(p, s->session->session_id, i); p += i; } /* cookie stuff */ if (s->d1->cookie_len > sizeof(s->d1->cookie)) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } *(p++) = s->d1->cookie_len; memcpy(p, s->d1->cookie, s->d1->cookie_len); p += s->d1->cookie_len; /* Ciphers supported */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]), 0); if (i == 0) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); goto err; } s2n(i, p); p += i; /* add in (no) COMPRESSION */ *(p++) = 1; *(p++) = 0; /* Add the NULL method */ if ((p = ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } l = (p - d); d = buf; d = dtls1_set_message_header(s, d, SSL3_MT_CLIENT_HELLO, l, 0, l); s->state = SSL3_ST_CW_CLNT_HELLO_B; /* number of bytes to write */ s->init_num = p - buf; s->init_off = 0; /* buffer the message to handle re-xmits */ dtls1_buffer_message(s, 0); }
int MAIN(int argc, char **argv) { int ret = 1, i; int verbose = 0, Verbose = 0; const char **pp; const char *p; int badops = 0; SSL_CTX *ctx = NULL; SSL *ssl = NULL; char *ciphers = NULL; const SSL_METHOD *meth = NULL; STACK_OF(SSL_CIPHER) *sk; char buf[512]; BIO *STDout = NULL; meth = SSLv23_server_method(); apps_startup(); if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); STDout = BIO_new_fp(stdout, BIO_NOCLOSE); #ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); STDout = BIO_push(tmpbio, STDout); } #endif if (!load_config(bio_err, NULL)) goto end; argc--; argv++; while (argc >= 1) { if (strcmp(*argv, "-v") == 0) verbose = 1; else if (strcmp(*argv, "-V") == 0) verbose = Verbose = 1; #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv, "-ssl2") == 0) meth = SSLv2_client_method(); #endif #ifndef OPENSSL_NO_SSL3 else if (strcmp(*argv, "-ssl3") == 0) meth = SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 else if (strcmp(*argv, "-tls1") == 0) meth = TLSv1_client_method(); #endif else if ((strncmp(*argv, "-h", 2) == 0) || (strcmp(*argv, "-?") == 0)) { badops = 1; break; } else { ciphers = *argv; } argc--; argv++; } if (badops) { for (pp = ciphers_usage; (*pp != NULL); pp++) BIO_printf(bio_err, "%s", *pp); goto end; } OpenSSL_add_ssl_algorithms(); ctx = SSL_CTX_new(meth); if (ctx == NULL) goto err; if (ciphers != NULL) { if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { BIO_printf(bio_err, "Error in cipher list\n"); goto err; } } ssl = SSL_new(ctx); if (ssl == NULL) goto err; if (!verbose) { for (i = 0;; i++) { p = SSL_get_cipher_list(ssl, i); if (p == NULL) break; if (i != 0) BIO_printf(STDout, ":"); BIO_printf(STDout, "%s", p); } BIO_printf(STDout, "\n"); } else { /* verbose */ sk = SSL_get_ciphers(ssl); for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { SSL_CIPHER *c; c = sk_SSL_CIPHER_value(sk, i); if (Verbose) { unsigned long id = c->id; int id0 = (int)(id >> 24); int id1 = (int)((id >> 16) & 0xffL); int id2 = (int)((id >> 8) & 0xffL); int id3 = (int)(id & 0xffL); if ((id & 0xff000000L) == 0x02000000L) { /* SSL2 cipher */ BIO_printf(STDout, " 0x%02X,0x%02X,0x%02X - ", id1, id2, id3); } else if ((id & 0xff000000L) == 0x03000000L) { /* SSL3 cipher */ BIO_printf(STDout, " 0x%02X,0x%02X - ", id2, id3); } else { /* whatever */ BIO_printf(STDout, "0x%02X,0x%02X,0x%02X,0x%02X - ", id0, id1, id2, id3); } } BIO_puts(STDout, SSL_CIPHER_description(c, buf, sizeof buf)); } } ret = 0; if (0) { err: SSL_load_error_strings(); ERR_print_errors(bio_err); } end: if (ctx != NULL) SSL_CTX_free(ctx); if (ssl != NULL) SSL_free(ssl); if (STDout != NULL) BIO_free_all(STDout); apps_shutdown(); OPENSSL_EXIT(ret); }
static int ssl23_client_hello(SSL *s) { unsigned char *buf; unsigned char *p, *d; int i; unsigned long l; int version = 0, version_major, version_minor; int ret; unsigned long mask, options = s->options; /* * SSL_OP_NO_X disables all protocols above X *if* there are * some protocols below X enabled. This is required in order * to maintain "version capability" vector contiguous. So * that if application wants to disable TLS1.0 in favour of * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. */ mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3; version = TLS1_2_VERSION; if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) version = TLS1_1_VERSION; mask &= ~SSL_OP_NO_TLSv1_1; if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) version = TLS1_VERSION; mask &= ~SSL_OP_NO_TLSv1; if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) version = SSL3_VERSION; mask &= ~SSL_OP_NO_SSLv3; buf = (unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { p = s->s3->client_random; RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE); if (version == TLS1_2_VERSION) { version_major = TLS1_2_VERSION_MAJOR; version_minor = TLS1_2_VERSION_MINOR; } else if (version == TLS1_1_VERSION) { version_major = TLS1_1_VERSION_MAJOR; version_minor = TLS1_1_VERSION_MINOR; } else if (version == TLS1_VERSION) { version_major = TLS1_VERSION_MAJOR; version_minor = TLS1_VERSION_MINOR; } else if (version == SSL3_VERSION) { version_major = SSL3_VERSION_MAJOR; version_minor = SSL3_VERSION_MINOR; } else { SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_PROTOCOLS_AVAILABLE); return (-1); } s->client_version = version; /* create Client Hello in SSL 3.0/TLS 1.0 format */ /* * Do the record header (5 bytes) and handshake * message header (4 bytes) last */ d = p = &(buf[9]); *(p++) = version_major; *(p++) = version_minor; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID (zero since there is no reuse) */ *(p++) = 0; /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]), ssl3_put_cipher_by_char); if (i == 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); return -1; } #ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH /* * Some servers hang if client hello > 256 bytes * as hack workaround chop number of supported ciphers * to keep it well below this if we use TLS v1.2 */ if (TLS1_get_version(s) >= TLS1_2_VERSION && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; #endif s2n(i, p); p += i; /* add in (no) COMPRESSION */ *(p++) = 1; /* Add the NULL method */ *(p++) = 0; /* TLS extensions*/ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); return -1; } if ((p = ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); return -1; } l = p - d; /* fill in 4-byte handshake header */ d = &(buf[5]); *(d++) = SSL3_MT_CLIENT_HELLO; l2n3(l, d); l += 4; if (l > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); return -1; } /* fill in 5-byte record header */ d = buf; *(d++) = SSL3_RT_HANDSHAKE; *(d++) = version_major; /* * Some servers hang if we use long client hellos * and a record number > TLS 1.0. */ if (TLS1_get_client_version(s) > TLS1_VERSION) *(d++) = 1; else *(d++) = version_minor; s2n((int)l, d); /* number of bytes to write */ s->init_num = p - buf; s->init_off = 0; ssl3_finish_mac(s, &(buf[5]), s->init_num - 5); s->state = SSL23_ST_CW_CLNT_HELLO_B; s->init_off = 0; } /* SSL3_ST_CW_CLNT_HELLO_B */ ret = ssl23_write_bytes(s); if ((ret >= 2) && s->msg_callback) { /* Client Hello has been sent; tell msg_callback */ s->msg_callback(1, version, SSL3_RT_HANDSHAKE, s->init_buf->data + 5, ret - 5, s, s->msg_callback_arg); } return ret; }
int ssl_prepare_clienthello_tlsext(SSL *s) { #ifndef OPENSSL_NO_EC /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats * and elliptic curves we support. */ int using_ecc = 0; int i; unsigned char *j; unsigned long alg_k, alg_a; STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); alg_k = c->algorithm_mkey; alg_a = c->algorithm_auth; if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA))) { using_ecc = 1; break; } } using_ecc = using_ecc && (s->version == TLS1_VERSION); if (using_ecc) { if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) { SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); return -1; } s->tlsext_ecpointformatlist_length = 3; s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */ if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist); s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_list[0]) * 2; if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) { s->tlsext_ellipticcurvelist_length = 0; SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); return -1; } for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= sizeof(nid_list)/sizeof(nid_list[0]); i++) s2n(i,j); } #endif /* OPENSSL_NO_EC */ #ifdef TLSEXT_TYPE_opaque_prf_input { int r = 1; if (s->ctx->tlsext_opaque_prf_input_callback != 0) { r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); if (!r) return -1; } if (s->tlsext_opaque_prf_input != NULL) { if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ OPENSSL_free(s->s3->client_opaque_prf_input); if (s->tlsext_opaque_prf_input_len == 0) s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ else s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); if (s->s3->client_opaque_prf_input == NULL) { SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); return -1; } s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; } if (r == 2) /* at callback's request, insist on receiving an appropriate server opaque PRF input */ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; } #endif return 1; }
static int test_cipher_name(void) { SSL_CTX *ctx = NULL; SSL *ssl = NULL; const SSL_CIPHER *c; STACK_OF(SSL_CIPHER) *sk = NULL; const char *ciphers = "ALL:eNULL", *p, *q, *r; int i, id = 0, ret = 0; /* tests for invalid input */ p = SSL_CIPHER_standard_name(NULL); if (!TEST_str_eq(p, "(NONE)")) { TEST_info("test_cipher_name(std) failed: NULL input doesn't return \"(NONE)\"\n"); goto err; } p = OPENSSL_cipher_name(NULL); if (!TEST_str_eq(p, "(NONE)")) { TEST_info("test_cipher_name(ossl) failed: NULL input doesn't return \"(NONE)\"\n"); goto err; } p = OPENSSL_cipher_name("This is not a valid cipher"); if (!TEST_str_eq(p, "(NONE)")) { TEST_info("test_cipher_name(ossl) failed: invalid input doesn't return \"(NONE)\"\n"); goto err; } /* tests for valid input */ ctx = SSL_CTX_new(TLS_server_method()); if (ctx == NULL) { TEST_info("test_cipher_name failed: internal error\n"); goto err; } if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { TEST_info("test_cipher_name failed: internal error\n"); goto err; } ssl = SSL_new(ctx); if (ssl == NULL) { TEST_info("test_cipher_name failed: internal error\n"); goto err; } sk = SSL_get_ciphers(ssl); if (sk == NULL) { TEST_info("test_cipher_name failed: internal error\n"); goto err; } for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { c = sk_SSL_CIPHER_value(sk, i); id = SSL_CIPHER_get_id(c) & 0xFFFF; if ((id == 0xFF85) || (id == 0xFF87)) /* skip GOST2012-GOST8912-GOST891 and GOST2012-NULL-GOST12 */ continue; p = SSL_CIPHER_standard_name(c); q = get_std_name_by_id(id); if (!TEST_ptr(p)) { TEST_info("test_cipher_name failed: expected %s, got NULL, cipher %x\n", q, id); goto err; } /* check if p is a valid standard name */ if (!TEST_str_eq(p, q)) { TEST_info("test_cipher_name(std) failed: expected %s, got %s, cipher %x\n", q, p, id); goto err; } /* test OPENSSL_cipher_name */ q = SSL_CIPHER_get_name(c); r = OPENSSL_cipher_name(p); if (!TEST_str_eq(r, q)) { TEST_info("test_cipher_name(ossl) failed: expected %s, got %s, cipher %x\n", q, r, id); goto err; } } ret = 1; err: SSL_CTX_free(ctx); SSL_free(ssl); return ret; }
int dtls1_client_hello(SSL *s) { unsigned char *bufend, *d, *p; unsigned int i; if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { SSL_SESSION *sess = s->session; if ((s->session == NULL) || (s->session->ssl_version != s->version) || (!sess->session_id_length && !sess->tlsext_tick) || (s->session->not_resumable)) { if (!ssl_get_new_session(s, 0)) goto err; } /* else use the pre-loaded session */ p = s->s3->client_random; /* if client_random is initialized, reuse it, we are * required to use same upon reply to HelloVerify */ for (i = 0; p[i]=='\0' && i < sizeof(s->s3->client_random); i++) ; if (i == sizeof(s->s3->client_random)) arc4random_buf(p, sizeof(s->s3->client_random)); d = p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_HELLO); *(p++) = s->version >> 8; *(p++) = s->version&0xff; s->client_version = s->version; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID */ if (s->new_session) i = 0; else i = s->session->session_id_length; *(p++) = i; if (i != 0) { if (i > sizeof s->session->session_id) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } memcpy(p, s->session->session_id, i); p += i; } /* cookie stuff */ if (s->d1->cookie_len > sizeof(s->d1->cookie)) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } *(p++) = s->d1->cookie_len; memcpy(p, s->d1->cookie, s->d1->cookie_len); p += s->d1->cookie_len; /* Ciphers supported */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]); if (i == 0) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); goto err; } s2n(i, p); p += i; /* add in (no) COMPRESSION */ *(p++) = 1; *(p++) = 0; /* Add the NULL method */ bufend = (unsigned char *)s->init_buf->data + SSL3_RT_MAX_PLAIN_LENGTH; if ((p = ssl_add_clienthello_tlsext(s, p, bufend)) == NULL) { SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } ssl3_handshake_msg_finish(s, p - d); s->state = SSL3_ST_CW_CLNT_HELLO_B; }
static int get_server_hello(SSL *s) { unsigned char *buf; unsigned char *p; int i,j; unsigned long len; STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow; buf=(unsigned char *)s->init_buf->data; p=buf; if (s->state == SSL2_ST_GET_SERVER_HELLO_A) { i=ssl2_read(s,(char *)&(buf[s->init_num]),11-s->init_num); if (i < (11-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i)); s->init_num = 11; if (*(p++) != SSL2_MT_SERVER_HELLO) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_PEER_ERROR); return(-1); } #ifdef __APPLE_CC__ /* The Rhapsody 5.5 (a.k.a. MacOS X) compiler bug * workaround. <*****@*****.**> */ s->hit=(i=*(p++))?1:0; #else s->hit=(*(p++))?1:0; #endif s->s2->tmp.cert_type= *(p++); n2s(p,i); if (i < s->version) s->version=i; n2s(p,i); s->s2->tmp.cert_length=i; n2s(p,i); s->s2->tmp.csl=i; n2s(p,i); s->s2->tmp.conn_id_length=i; s->state=SSL2_ST_GET_SERVER_HELLO_B; } /* SSL2_ST_GET_SERVER_HELLO_B */ len = 11 + (unsigned long)s->s2->tmp.cert_length + (unsigned long)s->s2->tmp.csl + (unsigned long)s->s2->tmp.conn_id_length; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_MESSAGE_TOO_LONG); return -1; } j = (int)len - s->init_num; i = ssl2_read(s,(char *)&(buf[s->init_num]),j); if (i != j) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg); /* SERVER-HELLO */ /* things are looking good */ p = buf + 11; if (s->hit) { if (s->s2->tmp.cert_length != 0) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_LENGTH_NOT_ZERO); return(-1); } if (s->s2->tmp.cert_type != 0) { if (!(s->options & SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG)) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_TYPE_NOT_ZERO); return(-1); } } if (s->s2->tmp.csl != 0) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CIPHER_LIST_NOT_ZERO); return(-1); } } else { #ifdef undef /* very bad */ memset(s->session->session_id,0, SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES); s->session->session_id_length=0; */ #endif /* we need to do this in case we were trying to reuse a * client session but others are already reusing it. * If this was a new 'blank' session ID, the session-id * length will still be 0 */ if (s->session->session_id_length > 0) { if (!ssl_get_new_session(s,0)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } if (ssl2_set_certificate(s,s->s2->tmp.cert_type, s->s2->tmp.cert_length,p) <= 0) { ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); return(-1); } p+=s->s2->tmp.cert_length; if (s->s2->tmp.csl == 0) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_LIST); return(-1); } /* We have just received a list of ciphers back from the * server. We need to get the ones that match, then select * the one we want the most :-). */ /* load the ciphers */ sk=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.csl, &s->session->ciphers); p+=s->s2->tmp.csl; if (sk == NULL) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO,ERR_R_MALLOC_FAILURE); return(-1); } (void)sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp); /* get the array of ciphers we will accept */ cl=SSL_get_ciphers(s); (void)sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp); /* * If server preference flag set, choose the first * (highest priority) cipher the server sends, otherwise * client preference has priority. */ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio = sk; allow = cl; } else { prio = cl; allow = sk; } /* In theory we could have ciphers sent back that we * don't want to use but that does not matter since we * will check against the list we originally sent and * for performance reasons we should not bother to match * the two lists up just to check. */ for (i=0; i<sk_SSL_CIPHER_num(prio); i++) { if (sk_SSL_CIPHER_find(allow, sk_SSL_CIPHER_value(prio,i)) >= 0) break; } if (i >= sk_SSL_CIPHER_num(prio)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH); return(-1); } s->session->cipher=sk_SSL_CIPHER_value(prio,i); if (s->session->peer != NULL) /* can't happen*/ { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); return(-1); } s->session->peer = s->session->sess_cert->peer_key->x509; /* peer_key->x509 has been set by ssl2_set_certificate. */ CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509); } if (s->session->sess_cert == NULL || s->session->peer != s->session->sess_cert->peer_key->x509) /* can't happen */ { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); return(-1); } s->s2->conn_id_length=s->s2->tmp.conn_id_length; if (s->s2->conn_id_length > sizeof s->s2->conn_id) { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG); return -1; } memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length); return(1); }
int main(int argc, char **argv) { if (argc != 3) { usage(argv[0]); } BIO *bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); if (bio_err == NULL) { perror("BIO_ne_fp(stderr)"); exit(1); } //+ Features TLS-Client-OpenSSL-Init // The following call prints an error message and calls exit() if // the OpenSSL configuration file is unreadable. OPENSSL_config(NULL); // Provide human-readable error messages. SSL_load_error_strings(); // Register ciphers. SSL_library_init(); //- //+ Features TLS-Client-OpenSSL-CTX // Configure a client connection context. Send a hendshake for the // highest supported TLS version, and disable compression. const SSL_METHOD *const req_method = SSLv23_client_method(); SSL_CTX *const ctx = SSL_CTX_new(req_method); if (ctx == NULL) { ERR_print_errors(bio_err); exit(1); } SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION); // Adjust the ciphers list based on a whitelist. First enable all // ciphers of at least medium strength, to get the list which is // compiled into OpenSSL. if (SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM") != 1) { ERR_print_errors(bio_err); exit(1); } { // Create a dummy SSL session to obtain the cipher list. SSL *ssl = SSL_new(ctx); if (ssl == NULL) { ERR_print_errors(bio_err); exit(1); } STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl); if (active_ciphers == NULL) { ERR_print_errors(bio_err); exit(1); } // Whitelist of candidate ciphers. static const char *const candidates[] = { "AES128-GCM-SHA256", "AES128-SHA256", "AES256-SHA256", // strong ciphers "AES128-SHA", "AES256-SHA", // strong ciphers, also in older versions "RC4-SHA", "RC4-MD5", // backwards compatibility, supposed to be weak "DES-CBC3-SHA", "DES-CBC3-MD5", // more backwards compatibility NULL }; // Actually selected ciphers. char ciphers[300]; ciphers[0] = '\0'; for (const char *const *c = candidates; *c; ++c) { for (int i = 0; i < sk_SSL_CIPHER_num(active_ciphers); ++i) { if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)), *c) == 0) { if (*ciphers) { strcat(ciphers, ":"); } strcat(ciphers, *c); break; } } } SSL_free(ssl); // Apply final cipher list. if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) { ERR_print_errors(bio_err); exit(1); } } // Load the set of trusted root certificates. if (!SSL_CTX_set_default_verify_paths(ctx)) { ERR_print_errors(bio_err); exit(1); } //- const char *host = argv[1]; const char *service = argv[2]; // Perform name lookup, create the TCP client socket, and connect to // the server. int sockfd = tcp_connect(host, service); if (sockfd < 0) { perror("connect"); exit(1); } // Deactivate the Nagle algorithm. //+ Features TLS-Nagle const int val = 1; int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); if (ret < 0) { perror("setsockopt(TCP_NODELAY)"); exit(1); } //- //+ Features TLS-Client-OpenSSL-Connect // Create the connection object. SSL *ssl = SSL_new(ctx); if (ssl == NULL) { ERR_print_errors(bio_err); exit(1); } SSL_set_fd(ssl, sockfd); // Enable the ServerNameIndication extension if (!SSL_set_tlsext_host_name(ssl, host)) { ERR_print_errors(bio_err); exit(1); } // Perform the TLS handshake with the server. ret = SSL_connect(ssl); if (ret != 1) { // Error status can be 0 or negative. ssl_print_error_and_exit(ssl, "SSL_connect", ret); } // Obtain the server certificate. X509 *peercert = SSL_get_peer_certificate(ssl); if (peercert == NULL) { fprintf(stderr, "peer certificate missing"); exit(1); } // Check the certificate verification result. Allow an explicit // certificate validation override in case verification fails. int verifystatus = SSL_get_verify_result(ssl); if (verifystatus != X509_V_OK && !certificate_validity_override(peercert)) { fprintf(stderr, "SSL_connect: verify result: %s\n", X509_verify_cert_error_string(verifystatus)); exit(1); } // Check if the server certificate matches the host name used to // establish the connection. // FIXME: Currently needs OpenSSL 1.1. if (X509_check_host(peercert, (const unsigned char *)host, strlen(host), 0) != 1 && !certificate_host_name_override(peercert, host)) { fprintf(stderr, "SSL certificate does not match host name\n"); exit(1); } X509_free(peercert); //- //+ Features TLS-Client-OpenSSL-Connection-Use const char *const req = "GET / HTTP/1.0\r\n\r\n"; if (SSL_write(ssl, req, strlen(req)) < 0) { ssl_print_error_and_exit(ssl, "SSL_write", ret); } char buf[4096]; ret = SSL_read(ssl, buf, sizeof(buf)); if (ret < 0) { ssl_print_error_and_exit(ssl, "SSL_read", ret); } //- write(STDOUT_FILENO, buf, ret); //+ Features TLS-OpenSSL-Connection-Close // Send the close_notify alert. ret = SSL_shutdown(ssl); switch (ret) { case 1: // A close_notify alert has already been received. break; case 0: // Wait for the close_notify alert from the peer. ret = SSL_shutdown(ssl); switch (ret) { case 0: fprintf(stderr, "info: second SSL_shutdown returned zero\n"); break; case 1: break; default: ssl_print_error_and_exit(ssl, "SSL_shutdown 2", ret); } break; default: ssl_print_error_and_exit(ssl, "SSL_shutdown 1", ret); } SSL_free(ssl); close(sockfd); //- //+ Features TLS-OpenSSL-Context-Close SSL_CTX_free(ctx); //- BIO_free(bio_err); return 0; }
static int ssl23_client_hello(SSL *s) { unsigned char *buf; unsigned char *p,*d; int i; unsigned long l; int version = 0, version_major, version_minor; int ret; unsigned long mask, options = s->options; /* * SSL_OP_NO_X disables all protocols above X *if* there are * some protocols below X enabled. This is required in order * to maintain "version capability" vector contiguous. So * that if application wants to disable TLS1.0 in favour of * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. */ mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3; version = TLS1_2_VERSION; if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) version = TLS1_1_VERSION; mask &= ~SSL_OP_NO_TLSv1_1; if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) version = TLS1_VERSION; mask &= ~SSL_OP_NO_TLSv1; if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) version = SSL3_VERSION; mask &= ~SSL_OP_NO_SSLv3; buf=(unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { /* Check if the session is resumable. If not, drop it. */ if (s->session != NULL) { if (s->session->ssl_version > version || s->session->session_id_length == 0 || s->session->not_resumable) { SSL_SESSION_free(s->session); s->session = NULL; } } p=s->s3->client_random; if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) return -1; if (version == TLS1_2_VERSION) { version_major = TLS1_2_VERSION_MAJOR; version_minor = TLS1_2_VERSION_MINOR; } else if (version == TLS1_1_VERSION) { version_major = TLS1_1_VERSION_MAJOR; version_minor = TLS1_1_VERSION_MINOR; } else if (version == TLS1_VERSION) { version_major = TLS1_VERSION_MAJOR; version_minor = TLS1_VERSION_MINOR; } else if (version == SSL3_VERSION) { version_major = SSL3_VERSION_MAJOR; version_minor = SSL3_VERSION_MINOR; } else if (version == SSL2_VERSION) { version_major = SSL2_VERSION_MAJOR; version_minor = SSL2_VERSION_MINOR; } else { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_NO_PROTOCOLS_AVAILABLE); return(-1); } s->client_version = version; /* create Client Hello in SSL 3.0/TLS 1.0 format */ /* do the record header (5 bytes) and handshake message * header (4 bytes) last. Note: the final argument to * ssl_add_clienthello_tlsext below depends on the size * of this prefix. */ d = p = &(buf[9]); *(p++) = version_major; *(p++) = version_minor; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID */ if (s->new_session || s->session == NULL) i=0; else i=s->session->session_id_length; *(p++)=i; if (i != 0) { if (i > (int)sizeof(s->session->session_id)) { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p,s->session->session_id,i); p+=i; } /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]); if (i == 0) { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_NO_CIPHERS_AVAILABLE); return -1; } s2n(i,p); p+=i; /* COMPRESSION */ *(p++)=1; *(p++)=0; /* Add the NULL method */ /* TLS extensions*/ if (ssl_prepare_clienthello_tlsext(s) <= 0) { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_CLIENTHELLO_TLSEXT); return -1; } /* The buffer includes the 5 byte record header, so * subtract it to compute hlen for * ssl_add_clienthello_tlsext. */ if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, p-buf-5)) == NULL) { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR); return -1; } l = p-d; /* fill in 4-byte handshake header */ d=&(buf[5]); *(d++)=SSL3_MT_CLIENT_HELLO; l2n3(l,d); l += 4; if (l > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR); return -1; } /* fill in 5-byte record header */ d=buf; *(d++) = SSL3_RT_HANDSHAKE; *(d++) = version_major; /* Some servers hang if we use long client hellos * and a record number > TLS 1.0. */ if (TLS1_get_client_version(s) > TLS1_VERSION) *(d++) = 1; else *(d++) = version_minor; s2n((int)l,d); /* number of bytes to write */ s->init_num=p-buf; s->init_off=0; ssl3_finish_mac(s,&(buf[5]), s->init_num - 5); s->state=SSL23_ST_CW_CLNT_HELLO_B; s->init_off=0; } /* SSL3_ST_CW_CLNT_HELLO_B */ ret = ssl23_write_bytes(s); if ((ret >= 2) && s->msg_callback) { /* Client Hello has been sent; tell msg_callback */ s->msg_callback(1, version, SSL3_RT_HEADER, s->init_buf->data, 5, s, s->msg_callback_arg); s->msg_callback(1, version, SSL3_RT_HANDSHAKE, s->init_buf->data+5, ret-5, s, s->msg_callback_arg); } return ret; }
static int client_hello(SSL *s) { unsigned char *buf; unsigned char *p,*d; /* CIPHER **cipher;*/ int i,n,j; buf=(unsigned char *)s->init_buf->data; if (s->state == SSL2_ST_SEND_CLIENT_HELLO_A) { if ((s->session == NULL) || (s->session->ssl_version != s->version)) { if (!ssl_get_new_session(s,0)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } /* else use the pre-loaded session */ p=buf; /* header */ d=p+9; /* data section */ *(p++)=SSL2_MT_CLIENT_HELLO; /* type */ s2n(SSL2_VERSION,p); /* version */ n=j=0; n=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),d,0); d+=n; if (n == 0) { SSLerr(SSL_F_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); return(-1); } s2n(n,p); /* cipher spec num bytes */ if ((s->session->session_id_length > 0) && (s->session->session_id_length <= SSL2_MAX_SSL_SESSION_ID_LENGTH)) { i=s->session->session_id_length; s2n(i,p); /* session id length */ memcpy(d,s->session->session_id,(unsigned int)i); d+=i; } else { s2n(0,p); } s->s2->challenge_length=SSL2_CHALLENGE_LENGTH; s2n(SSL2_CHALLENGE_LENGTH,p); /* challenge length */ /*challenge id data*/ if (RAND_pseudo_bytes(s->s2->challenge,SSL2_CHALLENGE_LENGTH) <= 0) return -1; memcpy(d,s->s2->challenge,SSL2_CHALLENGE_LENGTH); d+=SSL2_CHALLENGE_LENGTH; s->state=SSL2_ST_SEND_CLIENT_HELLO_B; s->init_num=d-buf; s->init_off=0; } /* SSL2_ST_SEND_CLIENT_HELLO_B */ return(ssl2_do_write(s)); }
static void setup_ssl(tcptest_t *item) { static int ssl_init_complete = 0; struct servent *sp; char portinfo[100]; X509 *peercert; char *certcn, *certstart, *certend; int err; strbuffer_t *sslinfo; char msglin[2048]; item->sslrunning = 1; if (!ssl_init_complete) { /* Setup entropy */ if (RAND_status() != 1) { char path[PATH_MAX]; /* Path for the random file */ /* load entropy from files */ RAND_load_file(RAND_file_name(path, sizeof (path)), -1); /* load entropy from egd sockets */ RAND_egd("/var/run/egd-pool"); RAND_egd("/dev/egd-pool"); RAND_egd("/etc/egd-pool"); RAND_egd("/var/spool/prngd/pool"); /* shuffle $RANDFILE (or ~/.rnd if unset) */ RAND_write_file(RAND_file_name(path, sizeof (path))); if (RAND_status() != 1) { errprintf("Failed to find enough entropy on your system"); item->errcode = CONTEST_ESSL; return; } } SSL_load_error_strings(); SSL_library_init(); ssl_init_complete = 1; } if (item->sslctx == NULL) { switch (item->ssloptions->sslversion) { case SSLVERSION_V2: item->sslctx = SSL_CTX_new(SSLv2_client_method()); break; case SSLVERSION_V3: item->sslctx = SSL_CTX_new(SSLv3_client_method()); break; case SSLVERSION_TLS1: item->sslctx = SSL_CTX_new(TLSv1_client_method()); break; default: item->sslctx = SSL_CTX_new(SSLv23_client_method()); break; } if (!item->sslctx) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot create SSL context - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } /* Workaround SSL bugs */ SSL_CTX_set_options(item->sslctx, SSL_OP_ALL); SSL_CTX_set_quiet_shutdown(item->sslctx, 1); /* Limit set of ciphers, if user wants to */ if (item->ssloptions->cipherlist) SSL_CTX_set_cipher_list(item->sslctx, item->ssloptions->cipherlist); if (item->ssloptions->clientcert) { int status; char certfn[PATH_MAX]; SSL_CTX_set_default_passwd_cb(item->sslctx, cert_password_cb); SSL_CTX_set_default_passwd_cb_userdata(item->sslctx, item); sprintf(certfn, "%s/certs/%s", xgetenv("XYMONHOME"), item->ssloptions->clientcert); status = SSL_CTX_use_certificate_chain_file(item->sslctx, certfn); if (status == 1) { status = SSL_CTX_use_PrivateKey_file(item->sslctx, certfn, SSL_FILETYPE_PEM); } if (status != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot load SSL client certificate/key %s: %s\n", item->ssloptions->clientcert, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } } if (item->ssldata == NULL) { item->ssldata = SSL_new(item->sslctx); if (!item->ssldata) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("SSL_new failed - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } /* Verify that the client certificate is working */ if (item->ssloptions->clientcert) { X509 *x509; x509 = SSL_get_certificate(item->ssldata); if(x509 != NULL) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(item->ssldata)); EVP_PKEY_free(pktmp); } if (!SSL_CTX_check_private_key(item->sslctx)) { errprintf("Private/public key mismatch for certificate %s\n", item->ssloptions->clientcert); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } /* SSL setup is done. Now attach the socket FD to the SSL protocol handler */ if (SSL_set_fd(item->ssldata, item->fd) != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Could not initiate SSL on connection - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } } sp = getservbyport(item->addr.sin_port, "tcp"); if (sp) { sprintf(portinfo, "%s (%d/tcp)", sp->s_name, item->addr.sin_port); } else { sprintf(portinfo, "%d/tcp", item->addr.sin_port); } if ((err = SSL_connect(item->ssldata)) != 1) { char sslerrmsg[256]; switch (SSL_get_error (item->ssldata, err)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: item->sslrunning = SSLSETUP_PENDING; break; case SSL_ERROR_SYSCALL: ERR_error_string(ERR_get_error(), sslerrmsg); /* Filter out the bogus SSL error */ if (strstr(sslerrmsg, "error:00000000:") == NULL) { errprintf("IO error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); } item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; case SSL_ERROR_SSL: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unspecified SSL error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; default: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unknown error %d in SSL_connect to %s on host %s: %s\n", err, portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; } return; } /* If we get this far, the SSL handshake has completed. So grab the certificate */ peercert = SSL_get_peer_certificate(item->ssldata); if (!peercert) { errprintf("Cannot get peer certificate for %s on host %s\n", portinfo, inet_ntoa(item->addr.sin_addr)); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); return; } sslinfo = newstrbuffer(0); certcn = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0); certstart = strdup(xymon_ASN1_UTCTIME(X509_get_notBefore(peercert))); certend = strdup(xymon_ASN1_UTCTIME(X509_get_notAfter(peercert))); snprintf(msglin, sizeof(msglin), "Server certificate:\n\tsubject:%s\n\tstart date: %s\n\texpire date:%s\n", certcn, certstart, certend); addtobuffer(sslinfo, msglin); item->certsubject = strdup(certcn); item->certexpires = sslcert_expiretime(certend); xfree(certcn); xfree(certstart); xfree(certend); X509_free(peercert); /* We list the available ciphers in the SSL cert data */ { int i; STACK_OF(SSL_CIPHER) *sk; addtobuffer(sslinfo, "\nAvailable ciphers:\n"); sk = SSL_get_ciphers(item->ssldata); for (i=0; i<sk_SSL_CIPHER_num(sk); i++) { int b1, b2; char *cph; b1 = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(sk,i), &b2); cph = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk,i)); snprintf(msglin, sizeof(msglin), "Cipher %d: %s (%d bits)\n", i, cph, b1); addtobuffer(sslinfo, msglin); if ((item->mincipherbits == 0) || (b1 < item->mincipherbits)) item->mincipherbits = b1; } } item->certinfo = grabstrbuffer(sslinfo); }
int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) { STACK_OF(SSL_CIPHER) *ciphers; method_const SSL_METHOD *dtls_method; SSL_SESSION *dtls_session; SSL *dtls_ssl; BIO *dtls_bio; int dtlsver = DTLS1_BAD_VER; const char *cipher = vpninfo->dtls_cipher; #ifdef HAVE_DTLS12 if (!strcmp(cipher, "OC-DTLS1_2-AES128-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES128-GCM-SHA256"; } else if (!strcmp(cipher, "OC-DTLS1_2-AES256-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES256-GCM-SHA384"; #ifndef OPENSSL_NO_PSK } else if (!strcmp(cipher, "PSK-NEGOTIATE")) { dtlsver = 0; /* Let it negotiate */ #endif } #endif if (!vpninfo->dtls_ctx) { #ifdef HAVE_DTLS12 dtls_method = DTLS_client_method(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) dtls_method = DTLSv1_client_method(); #ifdef HAVE_DTLS12 else if (dtlsver == DTLS1_2_VERSION) dtls_method = DTLSv1_2_client_method(); #endif #endif vpninfo->dtls_ctx = SSL_CTX_new(dtls_method); if (!vpninfo->dtls_ctx) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 CTX failed\n")); openconnect_report_ssl_errors(vpninfo); vpninfo->dtls_attempt_period = 0; return -EINVAL; } if (dtlsver) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) SSL_CTX_set_options(vpninfo->dtls_ctx, SSL_OP_CISCO_ANYCONNECT); #else if (!SSL_CTX_set_min_proto_version(vpninfo->dtls_ctx, dtlsver) || !SSL_CTX_set_max_proto_version(vpninfo->dtls_ctx, dtlsver)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS CTX version failed\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } #endif #if defined (HAVE_DTLS12) && !defined(OPENSSL_NO_PSK) } else { SSL_CTX_set_psk_client_callback(vpninfo->dtls_ctx, psk_callback); /* For PSK we override the DTLS master secret with one derived * from the HTTPS session. */ if (!SSL_export_keying_material(vpninfo->https_ssl, vpninfo->dtls_secret, PSK_KEY_SIZE, PSK_LABEL, PSK_LABEL_SIZE, NULL, 0, 0)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to generate DTLS key\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } SSL_CTX_add_client_custom_ext(vpninfo->dtls_ctx, DTLS_APP_ID_EXT, pskident_add, pskident_free, vpninfo, pskident_parse, vpninfo); /* For SSL_CTX_set_cipher_list() */ cipher = "PSK"; #endif } /* If we don't readahead, then we do short reads and throw away the tail of data packets. */ SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1); if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, cipher)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS cipher list failed\n")); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } } dtls_ssl = SSL_new(vpninfo->dtls_ctx); SSL_set_connect_state(dtls_ssl); SSL_set_app_data(dtls_ssl, vpninfo); if (dtlsver) { ciphers = SSL_get_ciphers(dtls_ssl); if (dtlsver != 0 && sk_SSL_CIPHER_num(ciphers) != 1) { vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n")); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* We're going to "resume" a session which never existed. Fake it... */ dtls_session = generate_dtls_session(vpninfo, dtlsver, sk_SSL_CIPHER_value(ciphers, 0)); if (!dtls_session) { SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* Add the generated session to the SSL */ if (!SSL_set_session(dtls_ssl, dtls_session)) { vpn_progress(vpninfo, PRG_ERR, _("SSL_set_session() failed with old protocol version 0x%x\n" "Are you using a version of OpenSSL older than 0.9.8m?\n" "See http://rt.openssl.org/Ticket/Display.html?id=1751\n" "Use the --no-dtls command line option to avoid this message\n"), DTLS1_BAD_VER); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; SSL_SESSION_free(dtls_session); return -EINVAL; } /* We don't need our own refcount on it any more */ SSL_SESSION_free(dtls_session); } dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE); /* Set non-blocking */ BIO_set_nbio(dtls_bio, 1); SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio); vpninfo->dtls_ssl = dtls_ssl; return 0; }
int MAIN(int argc, char **argv) { int ret=1,i; int verbose=0; char **pp; const char *p; int badops=0; SSL_CTX *ctx=NULL; SSL *ssl=NULL; char *ciphers=NULL; SSL_METHOD *meth=NULL; STACK_OF(SSL_CIPHER) *sk; char buf[512]; BIO *STDout=NULL; #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_server_method(); #elif !defined(OPENSSL_NO_SSL3) meth=SSLv3_server_method(); #elif !defined(OPENSSL_NO_SSL2) meth=SSLv2_server_method(); #endif apps_startup(); if (bio_err == NULL) bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); STDout=BIO_new_fp(stdout,BIO_NOCLOSE); #ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); STDout = BIO_push(tmpbio, STDout); } #endif argc--; argv++; while (argc >= 1) { if (strcmp(*argv,"-v") == 0) verbose=1; #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) meth=SSLv2_client_method(); #endif #ifndef OPENSSL_NO_SSL3 else if (strcmp(*argv,"-ssl3") == 0) meth=SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 else if (strcmp(*argv,"-tls1") == 0) meth=TLSv1_client_method(); #endif else if ((strncmp(*argv,"-h",2) == 0) || (strcmp(*argv,"-?") == 0)) { badops=1; break; } else { ciphers= *argv; } argc--; argv++; } if (badops) { for (pp=ciphers_usage; (*pp != NULL); pp++) BIO_printf(bio_err,"%s",*pp); goto end; } OpenSSL_add_ssl_algorithms(); ctx=SSL_CTX_new(meth); if (ctx == NULL) goto err; if (ciphers != NULL) { if(!SSL_CTX_set_cipher_list(ctx,ciphers)) { BIO_printf(bio_err, "Error in cipher list\n"); goto err; } } ssl=SSL_new(ctx); if (ssl == NULL) goto err; if (!verbose) { for (i=0; ; i++) { p=SSL_get_cipher_list(ssl,i); if (p == NULL) break; if (i != 0) BIO_printf(STDout,":"); BIO_printf(STDout,"%s",p); } BIO_printf(STDout,"\n"); } else { sk=SSL_get_ciphers(ssl); for (i=0; i<sk_SSL_CIPHER_num(sk); i++) { BIO_puts(STDout,SSL_CIPHER_description( sk_SSL_CIPHER_value(sk,i), buf,sizeof buf)); } } ret=0; if (0) { err: SSL_load_error_strings(); ERR_print_errors(bio_err); } end: if (ctx != NULL) SSL_CTX_free(ctx); if (ssl != NULL) SSL_free(ssl); if (STDout != NULL) BIO_free_all(STDout); apps_shutdown(); OPENSSL_EXIT(ret); }
static int ssl23_client_hello(SSL *s) { unsigned char *buf; unsigned char *p,*d; int i,ch_len; unsigned long Time,l; int ssl2_compat; int version = 0, version_major, version_minor; #ifndef OPENSSL_NO_COMP int j; SSL_COMP *comp; #endif int ret; ssl2_compat = (s->options & SSL_OP_NO_SSLv2) ? 0 : 1; if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) ssl2_compat = 0; if (!(s->options & SSL_OP_NO_TLSv1)) { version = TLS1_VERSION; } else if (!(s->options & SSL_OP_NO_SSLv3)) { version = SSL3_VERSION; } else if (!(s->options & SSL_OP_NO_SSLv2)) { version = SSL2_VERSION; } #ifndef OPENSSL_NO_TLSEXT if (version != SSL2_VERSION) { /* have to disable SSL 2.0 compatibility if we need TLS extensions */ if (s->tlsext_hostname != NULL) ssl2_compat = 0; if (s->tlsext_status_type != -1) ssl2_compat = 0; #ifdef TLSEXT_TYPE_opaque_prf_input if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL) ssl2_compat = 0; #endif } #endif buf=(unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { #if 0 /* don't reuse session-id's */ if (!ssl_get_new_session(s,0)) { return(-1); } #endif p=s->s3->client_random; Time=(unsigned long)time(NULL); /* Time */ l2n(Time,p); if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) return -1; if (version == TLS1_VERSION) { version_major = TLS1_VERSION_MAJOR; version_minor = TLS1_VERSION_MINOR; } else if (version == SSL3_VERSION) { version_major = SSL3_VERSION_MAJOR; version_minor = SSL3_VERSION_MINOR; } else if (version == SSL2_VERSION) { version_major = SSL2_VERSION_MAJOR; version_minor = SSL2_VERSION_MINOR; } else { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_PROTOCOLS_AVAILABLE); return(-1); } s->client_version = version; if (ssl2_compat) { /* create SSL 2.0 compatible Client Hello */ /* two byte record header will be written last */ d = &(buf[2]); p = d + 9; /* leave space for message type, version, individual length fields */ *(d++) = SSL2_MT_CLIENT_HELLO; *(d++) = version_major; *(d++) = version_minor; /* Ciphers supported */ i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),p,0); if (i == 0) { /* no ciphers */ SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); return -1; } s2n(i,d); p+=i; /* put in the session-id length (zero since there is no reuse) */ #if 0 s->session->session_id_length=0; #endif s2n(0,d); if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG) ch_len=SSL2_CHALLENGE_LENGTH; else ch_len=SSL2_MAX_CHALLENGE_LENGTH; /* write out sslv2 challenge */ /* Note that ch_len must be <= SSL3_RANDOM_SIZE (32), because it is one of SSL2_MAX_CHALLENGE_LENGTH (32) or SSL2_MAX_CHALLENGE_LENGTH (16), but leave the check in for futurproofing */ if (SSL3_RANDOM_SIZE < ch_len) i=SSL3_RANDOM_SIZE; else i=ch_len; s2n(i,d); memset(&(s->s3->client_random[0]),0,SSL3_RANDOM_SIZE); if (RAND_pseudo_bytes(&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i) <= 0) return -1; memcpy(p,&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i); p+=i; i= p- &(buf[2]); buf[0]=((i>>8)&0xff)|0x80; buf[1]=(i&0xff); /* number of bytes to write */ s->init_num=i+2; s->init_off=0; ssl3_finish_mac(s,&(buf[2]),i); } else { /* create Client Hello in SSL 3.0/TLS 1.0 format */ /* do the record header (5 bytes) and handshake message header (4 bytes) last */ d = p = &(buf[9]); *(p++) = version_major; *(p++) = version_minor; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID (zero since there is no reuse) */ *(p++) = 0; /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),ssl3_put_cipher_by_char); if (i == 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); return -1; } s2n(i,p); p+=i; /* COMPRESSION */ #ifdef OPENSSL_NO_COMP *(p++)=1; #else if ((s->options & SSL_OP_NO_COMPRESSION) || !s->ctx->comp_methods) j=0; else j=sk_SSL_COMP_num(s->ctx->comp_methods); *(p++)=1+j; for (i=0; i<j; i++) { comp=sk_SSL_COMP_value(s->ctx->comp_methods,i); *(p++)=comp->id; } #endif *(p++)=0; /* Add the NULL method */ #ifndef OPENSSL_NO_TLSEXT /* TLS extensions*/ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); return -1; } if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); return -1; } #endif l = p-d; /* fill in 4-byte handshake header */ d=&(buf[5]); *(d++)=SSL3_MT_CLIENT_HELLO; l2n3(l,d); l += 4; if (l > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); return -1; } /* fill in 5-byte record header */ d=buf; *(d++) = SSL3_RT_HANDSHAKE; *(d++) = version_major; *(d++) = version_minor; /* arguably we should send the *lowest* suported version here * (indicating, e.g., TLS 1.0 in "SSL 3.0 format") */ s2n((int)l,d); /* number of bytes to write */ s->init_num=p-buf; s->init_off=0; ssl3_finish_mac(s,&(buf[5]), s->init_num - 5); } s->state=SSL23_ST_CW_CLNT_HELLO_B; s->init_off=0; }
int ciphers_main(int argc, char **argv) { SSL_CTX *ctx = NULL; SSL *ssl = NULL; STACK_OF(SSL_CIPHER) *sk = NULL; const SSL_METHOD *meth = TLS_server_method(); int ret = 1, i, verbose = 0, Verbose = 0, use_supported = 0; #ifndef OPENSSL_NO_SSL_TRACE int stdname = 0; #endif #ifndef OPENSSL_NO_PSK int psk = 0; #endif #ifndef OPENSSL_NO_SRP int srp = 0; #endif const char *p; char *ciphers = NULL, *prog; char buf[512]; OPTION_CHOICE o; int min_version = 0, max_version = 0; prog = opt_init(argc, argv, ciphers_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF: case OPT_ERR: opthelp: BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); goto end; case OPT_HELP: opt_help(ciphers_options); ret = 0; goto end; case OPT_V: verbose = 1; break; case OPT_UPPER_V: verbose = Verbose = 1; break; case OPT_S: use_supported = 1; break; case OPT_STDNAME: #ifndef OPENSSL_NO_SSL_TRACE stdname = verbose = 1; #endif break; case OPT_SSL3: min_version = SSL3_VERSION; max_version = SSL3_VERSION; break; case OPT_TLS1: min_version = TLS1_VERSION; max_version = TLS1_VERSION; break; case OPT_TLS1_1: min_version = TLS1_1_VERSION; max_version = TLS1_1_VERSION; break; case OPT_TLS1_2: min_version = TLS1_2_VERSION; max_version = TLS1_2_VERSION; break; case OPT_TLS1_3: min_version = TLS1_3_VERSION; max_version = TLS1_3_VERSION; break; case OPT_PSK: #ifndef OPENSSL_NO_PSK psk = 1; #endif break; case OPT_SRP: #ifndef OPENSSL_NO_SRP srp = 1; #endif break; } } argv = opt_rest(); argc = opt_num_rest(); if (argc == 1) ciphers = *argv; else if (argc != 0) goto opthelp; ctx = SSL_CTX_new(meth); if (ctx == NULL) goto err; if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) goto err; if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto err; #ifndef OPENSSL_NO_PSK if (psk) SSL_CTX_set_psk_client_callback(ctx, dummy_psk); #endif #ifndef OPENSSL_NO_SRP if (srp) SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp); #endif if (ciphers != NULL) { if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { BIO_printf(bio_err, "Error in cipher list\n"); goto err; } } ssl = SSL_new(ctx); if (ssl == NULL) goto err; if (use_supported) sk = SSL_get1_supported_ciphers(ssl); else sk = SSL_get_ciphers(ssl); if (!verbose) { for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i); p = SSL_CIPHER_get_name(c); if (p == NULL) break; if (i != 0) BIO_printf(bio_out, ":"); BIO_printf(bio_out, "%s", p); } BIO_printf(bio_out, "\n"); } else { for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER *c; c = sk_SSL_CIPHER_value(sk, i); if (Verbose) { unsigned long id = SSL_CIPHER_get_id(c); int id0 = (int)(id >> 24); int id1 = (int)((id >> 16) & 0xffL); int id2 = (int)((id >> 8) & 0xffL); int id3 = (int)(id & 0xffL); if ((id & 0xff000000L) == 0x03000000L) BIO_printf(bio_out, " 0x%02X,0x%02X - ", id2, id3); /* SSL3 * cipher */ else BIO_printf(bio_out, "0x%02X,0x%02X,0x%02X,0x%02X - ", id0, id1, id2, id3); /* whatever */ } #ifndef OPENSSL_NO_SSL_TRACE if (stdname) { const char *nm = SSL_CIPHER_standard_name(c); if (nm == NULL) nm = "UNKNOWN"; BIO_printf(bio_out, "%s - ", nm); } #endif BIO_puts(bio_out, SSL_CIPHER_description(c, buf, sizeof buf)); } } ret = 0; goto end; err: ERR_print_errors(bio_err); end: if (use_supported) sk_SSL_CIPHER_free(sk); SSL_CTX_free(ctx); SSL_free(ssl); return (ret); }
static int ssl23_client_hello(SSL *s) { unsigned char *buf; unsigned char *p,*d; int i,ch_len; unsigned long Time,l; int ssl2_compat; int version = 0, version_major, version_minor; #ifndef OPENSSL_NO_COMP int j; SSL_COMP *comp; #endif int ret; unsigned long mask, options = s->options; ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1; if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) ssl2_compat = 0; /* * SSL_OP_NO_X disables all protocols above X *if* there are * some protocols below X enabled. This is required in order * to maintain "version capability" vector contiguous. So * that if application wants to disable TLS1.0 in favour of * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. */ mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1 #if !defined(OPENSSL_NO_SSL3) |SSL_OP_NO_SSLv3 #endif #if !defined(OPENSSL_NO_SSL2) |(ssl2_compat?SSL_OP_NO_SSLv2:0) #endif ; #if !defined(OPENSSL_NO_TLS1_2_CLIENT) version = TLS1_2_VERSION; if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) version = TLS1_1_VERSION; #else version = TLS1_1_VERSION; #endif mask &= ~SSL_OP_NO_TLSv1_1; if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) version = TLS1_VERSION; mask &= ~SSL_OP_NO_TLSv1; #if !defined(OPENSSL_NO_SSL3) if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) version = SSL3_VERSION; mask &= ~SSL_OP_NO_SSLv3; #endif #if !defined(OPENSSL_NO_SSL2) if ((options & SSL_OP_NO_SSLv3) && (options & mask) != mask) version = SSL2_VERSION; #endif #ifndef OPENSSL_NO_TLSEXT if (version != SSL2_VERSION) { /* have to disable SSL 2.0 compatibility if we need TLS extensions */ if (s->tlsext_hostname != NULL) ssl2_compat = 0; if (s->tlsext_status_type != -1) ssl2_compat = 0; #ifdef TLSEXT_TYPE_opaque_prf_input if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL) ssl2_compat = 0; #endif } #endif buf=(unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { #if 0 /* don't reuse session-id's */ if (!ssl_get_new_session(s,0)) { return(-1); } #endif p=s->s3->client_random; Time=(unsigned long)time(NULL); /* Time */ l2n(Time,p); if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) return -1; if (version == TLS1_2_VERSION) { version_major = TLS1_2_VERSION_MAJOR; version_minor = TLS1_2_VERSION_MINOR; } else if (version == TLS1_1_VERSION) { version_major = TLS1_1_VERSION_MAJOR; version_minor = TLS1_1_VERSION_MINOR; } else if (version == TLS1_VERSION) { version_major = TLS1_VERSION_MAJOR; version_minor = TLS1_VERSION_MINOR; } #ifdef OPENSSL_FIPS else if(FIPS_mode()) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); return -1; } #endif else if (version == SSL3_VERSION) { version_major = SSL3_VERSION_MAJOR; version_minor = SSL3_VERSION_MINOR; } else if (version == SSL2_VERSION) { version_major = SSL2_VERSION_MAJOR; version_minor = SSL2_VERSION_MINOR; } else { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_PROTOCOLS_AVAILABLE); return(-1); } s->client_version = version; if (ssl2_compat) { /* create SSL 2.0 compatible Client Hello */ /* two byte record header will be written last */ d = &(buf[2]); p = d + 9; /* leave space for message type, version, individual length fields */ *(d++) = SSL2_MT_CLIENT_HELLO; *(d++) = version_major; *(d++) = version_minor; /* Ciphers supported */ i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),p,0); if (i == 0) { /* no ciphers */ SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); return -1; } s2n(i,d); p+=i; /* put in the session-id length (zero since there is no reuse) */ #if 0 s->session->session_id_length=0; #endif s2n(0,d); if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG) ch_len=SSL2_CHALLENGE_LENGTH; else ch_len=SSL2_MAX_CHALLENGE_LENGTH; /* write out sslv2 challenge */ /* Note that ch_len must be <= SSL3_RANDOM_SIZE (32), because it is one of SSL2_MAX_CHALLENGE_LENGTH (32) or SSL2_MAX_CHALLENGE_LENGTH (16), but leave the check in for futurproofing */ if (SSL3_RANDOM_SIZE < ch_len) i=SSL3_RANDOM_SIZE; else i=ch_len; s2n(i,d); memset(&(s->s3->client_random[0]),0,SSL3_RANDOM_SIZE); if (RAND_pseudo_bytes(&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i) <= 0) return -1; memcpy(p,&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i); p+=i; i= p- &(buf[2]); buf[0]=((i>>8)&0xff)|0x80; buf[1]=(i&0xff); /* number of bytes to write */ s->init_num=i+2; s->init_off=0; ssl3_finish_mac(s,&(buf[2]),i); } else { /* create Client Hello in SSL 3.0/TLS 1.0 format */ /* do the record header (5 bytes) and handshake message * header (4 bytes) last. Note: the final argument to * ssl_add_clienthello_tlsext below depends on the size * of this prefix. */ d = p = &(buf[9]); *(p++) = version_major; *(p++) = version_minor; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; /* Session ID (zero since there is no reuse) */ *(p++) = 0; /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),ssl3_put_cipher_by_char); if (i == 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); return -1; } #ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH /* Some servers hang if client hello > 256 bytes * as hack workaround chop number of supported ciphers * to keep it well below this if we use TLS v1.2 */ if (TLS1_get_version(s) >= TLS1_2_VERSION && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; #endif s2n(i,p); p+=i; /* COMPRESSION */ #ifdef OPENSSL_NO_COMP *(p++)=1; #else if ((s->options & SSL_OP_NO_COMPRESSION) || !s->ctx->comp_methods) j=0; else j=sk_SSL_COMP_num(s->ctx->comp_methods); *(p++)=1+j; for (i=0; i<j; i++) { comp=sk_SSL_COMP_value(s->ctx->comp_methods,i); *(p++)=comp->id; } #endif *(p++)=0; /* Add the NULL method */ #ifndef OPENSSL_NO_TLSEXT /* TLS extensions*/ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); return -1; } /* The buffer includes the 5 byte record header, so * subtract it to compute hlen for * ssl_add_clienthello_tlsext. */ if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, p-buf-5)) == NULL) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); return -1; } #endif l = p-d; /* fill in 4-byte handshake header */ d=&(buf[5]); *(d++)=SSL3_MT_CLIENT_HELLO; l2n3(l,d); l += 4; if (l > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); return -1; } /* fill in 5-byte record header */ d=buf; *(d++) = SSL3_RT_HANDSHAKE; *(d++) = version_major; /* Some servers hang if we use long client hellos * and a record number > TLS 1.0. */ if (TLS1_get_client_version(s) > TLS1_VERSION) *(d++) = 1; else *(d++) = version_minor; s2n((int)l,d); /* number of bytes to write */ s->init_num=p-buf; s->init_off=0; ssl3_finish_mac(s,&(buf[5]), s->init_num - 5); } s->state=SSL23_ST_CW_CLNT_HELLO_B; s->init_off=0; }
static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) { STACK_OF(SSL_CIPHER) *ciphers; method_const SSL_METHOD *dtls_method; SSL_CIPHER *dtls_cipher; SSL *dtls_ssl; BIO *dtls_bio; if (!vpninfo->dtls_ctx) { dtls_method = DTLSv1_client_method(); vpninfo->dtls_ctx = SSL_CTX_new(dtls_method); if (!vpninfo->dtls_ctx) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 CTX failed\n")); openconnect_report_ssl_errors(vpninfo); vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* If we don't readahead, then we do short reads and throw away the tail of data packets. */ SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1); if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS cipher list failed\n")); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } } if (!vpninfo->dtls_session) { /* We're going to "resume" a session which never existed. Fake it... */ vpninfo->dtls_session = SSL_SESSION_new(); if (!vpninfo->dtls_session) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 session failed\n")); vpninfo->dtls_attempt_period = 0; return -EINVAL; } vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */ } /* Do this every time; it may have changed due to a rekey */ vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret); memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)); vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id); memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id, sizeof(vpninfo->dtls_session_id)); dtls_ssl = SSL_new(vpninfo->dtls_ctx); SSL_set_connect_state(dtls_ssl); ciphers = SSL_get_ciphers(dtls_ssl); if (sk_SSL_CIPHER_num(ciphers) != 1) { vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n")); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); SSL_SESSION_free(vpninfo->dtls_session); vpninfo->dtls_ctx = NULL; vpninfo->dtls_session = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0); /* Set the appropriate cipher on our session to be resumed */ vpninfo->dtls_session->cipher = dtls_cipher; vpninfo->dtls_session->cipher_id = dtls_cipher->id; /* Add the generated session to the SSL */ if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) { vpn_progress(vpninfo, PRG_ERR, _("SSL_set_session() failed with old protocol version 0x%x\n" "Are you using a version of OpenSSL older than 0.9.8m?\n" "See http://rt.openssl.org/Ticket/Display.html?id=1751\n" "Use the --no-dtls command line option to avoid this message\n"), vpninfo->dtls_session->ssl_version); vpninfo->dtls_attempt_period = 0; return -EINVAL; } dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE); /* Set non-blocking */ BIO_set_nbio(dtls_bio, 1); SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio); SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT); vpninfo->new_dtls_ssl = dtls_ssl; return 0; }