int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, #if ENABLE_INLINE_FILES const char *pkcs12_file_inline, #endif /* ENABLE_INLINE_FILES */ bool load_ca_file ) { FILE *fp; EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *ca = NULL; PKCS12 *p12; int i; char password[256]; ASSERT(NULL != ctx); #if ENABLE_INLINE_FILES if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline) { BIO *b64 = BIO_new(BIO_f_base64()); BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline, (int) strlen(pkcs12_file_inline)); ASSERT(b64 && bio); BIO_push(b64, bio); p12 = d2i_PKCS12_bio(b64, NULL); if (!p12) msg(M_SSLERR, "Error reading inline PKCS#12 file"); BIO_free(b64); BIO_free(bio); } else #endif { /* Load the PKCS #12 file */ if (!(fp = platform_fopen(pkcs12_file, "rb"))) msg(M_SSLERR, "Error opening file %s", pkcs12_file); p12 = d2i_PKCS12_fp(fp, NULL); fclose(fp); if (!p12) msg(M_SSLERR, "Error reading PKCS#12 file %s", pkcs12_file); } /* Parse the PKCS #12 file */ if (!PKCS12_parse(p12, "", &pkey, &cert, &ca)) { pem_password_callback (password, sizeof(password) - 1, 0, NULL); /* Reparse the PKCS #12 file with password */ ca = NULL; if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) { #ifdef ENABLE_MANAGEMENT if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE)) management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); #endif PKCS12_free(p12); return 1; } } PKCS12_free(p12); /* Load Certificate */ if (!SSL_CTX_use_certificate (ctx->ctx, cert)) msg (M_SSLERR, "Cannot use certificate"); /* Load Private Key */ if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey)) msg (M_SSLERR, "Cannot use private key"); warn_if_group_others_accessible (pkcs12_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ctx->ctx)) msg (M_SSLERR, "Private key does not match the certificate"); /* Set Certificate Verification chain */ if (load_ca_file) { if (ca && sk_X509_num(ca)) { for (i = 0; i < sk_X509_num(ca); i++) { if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); } } } return 0; }
void SecureSocket::checkResult(int status, int& retry) { // ssl errors are a little quirky. the "want" errors are normal and // should result in a retry. int errorCode = SSL_get_error(m_ssl->m_ssl, status); switch (errorCode) { case SSL_ERROR_NONE: retry = 0; // operation completed break; case SSL_ERROR_ZERO_RETURN: // connection closed isFatal(true); LOG((CLOG_DEBUG "ssl connection closed")); break; case SSL_ERROR_WANT_READ: retry++; LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_WRITE: // Need to make sure the socket is known to be writable so the impending // select action actually triggers on a write. This isn't necessary for // m_readable because the socket logic is always readable m_writable = true; retry++; LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_CONNECT: retry++; LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_ACCEPT: retry++; LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_SYSCALL: LOG((CLOG_ERR "ssl error occurred (system call failure)")); if (ERR_peek_error() == 0) { if (status == 0) { LOG((CLOG_ERR "eof violates ssl protocol")); } else if (status == -1) { // underlying socket I/O reproted an error try { ARCH->throwErrorOnSocket(getSocket()); } catch (XArchNetwork& e) { LOG((CLOG_ERR "%s", e.what())); } } } isFatal(true); break; case SSL_ERROR_SSL: LOG((CLOG_ERR "ssl error occurred (generic failure)")); isFatal(true); break; default: LOG((CLOG_ERR "ssl error occurred (unknown failure)")); isFatal(true); break; } if (isFatal()) { retry = 0; showError(); disconnect(); } }
static void loadSSL(void) { // SHELLINABOX_LIBSSL_SO can be used to select the specific // soname of libssl for systems where it is not libssl.so. // The feature is currently disabled. const char* path_libssl = NULL; // = getenv ("SHELLINABOX_LIBSSL_SO"); if (path_libssl == NULL) path_libssl = "libssl.so"; check(!SSL_library_init); struct { union { void *avoid_gcc_warning_about_type_punning; void **var; }; const char *fn; } symbols[] = { { { &BIO_ctrl }, "BIO_ctrl" }, { { &BIO_f_buffer }, "BIO_f_buffer" }, { { &BIO_free_all }, "BIO_free_all" }, { { &BIO_new }, "BIO_new" }, { { &BIO_new_socket }, "BIO_new_socket" }, { { &BIO_pop }, "BIO_pop" }, { { &BIO_push }, "BIO_push" }, { { &ERR_clear_error }, "ERR_clear_error" }, { { &ERR_clear_error }, "ERR_clear_error" }, { { &ERR_peek_error }, "ERR_peek_error" }, { { &ERR_peek_error }, "ERR_peek_error" }, { { &SSL_CTX_callback_ctrl }, "SSL_CTX_callback_ctrl" }, { { &SSL_CTX_check_private_key }, "SSL_CTX_check_private_key" }, { { &SSL_CTX_ctrl }, "SSL_CTX_ctrl" }, { { &SSL_CTX_free }, "SSL_CTX_free" }, { { &SSL_CTX_new }, "SSL_CTX_new" }, { { &SSL_CTX_use_PrivateKey_file }, "SSL_CTX_use_PrivateKey_file" }, { { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" }, { { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"}, { { &SSL_CTX_use_certificate_ASN1 },"SSL_CTX_use_certificate_ASN1"}, { { &SSL_ctrl }, "SSL_ctrl" }, { { &SSL_free }, "SSL_free" }, { { &SSL_get_error }, "SSL_get_error" }, { { &SSL_get_ex_data }, "SSL_get_ex_data" }, { { &SSL_get_rbio }, "SSL_get_rbio" }, #ifdef HAVE_TLSEXT { { &SSL_get_servername }, "SSL_get_servername" }, #endif { { &SSL_get_wbio }, "SSL_get_wbio" }, { { &SSL_library_init }, "SSL_library_init" }, { { &SSL_new }, "SSL_new" }, { { &SSL_read }, "SSL_read" }, #ifdef HAVE_TLSEXT { { &SSL_set_SSL_CTX }, "SSL_set_SSL_CTX" }, #endif { { &SSL_set_accept_state }, "SSL_set_accept_state" }, { { &SSL_set_bio }, "SSL_set_bio" }, { { &SSL_set_ex_data }, "SSL_set_ex_data" }, { { &SSL_shutdown }, "SSL_shutdown" }, { { &SSL_write }, "SSL_write" }, { { &SSLv23_server_method }, "SSLv23_server_method" }, { { &d2i_X509 }, "d2i_X509" }, { { &X509_free }, "X509_free" }, { { &x_SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" }, { { &x_sk_zero }, "sk_zero" } }; for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) { if (!(*symbols[i].var = loadSymbol(path_libssl, symbols[i].fn))) { debug("Failed to load SSL support. Could not find \"%s\"", symbols[i].fn); for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) { *symbols[j].var = NULL; } return; } } // These are optional x_SSL_COMP_get_compression_methods = loadSymbol(path_libssl, "SSL_COMP_get_compression_methods"); // ends SSL_library_init(); dcheck(!ERR_peek_error()); debug("Loaded SSL suppport"); }
/** * Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. * * Taken from OpenSSL & Node.js - editted for style. */ static int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, BIO *in) { int ret = 0; X509 *x = NULL; x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx, x); if (ERR_peek_error() != 0) { /* Key/certificate mismatch doesn't imply ret==0 ... */ ret = 0; } if (ret) { /* If we could set up our certificate, now proceed to the CA certificates. */ X509 *ca; int r; unsigned long err; if (ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->extra_certs, X509_free); ctx->extra_certs = NULL; } while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) { r = SSL_CTX_add_extra_chain_cert(ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /* Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { ERR_clear_error(); } else { /* some real error */ ret = 0; } } end: if (x != NULL) { X509_free(x); } return ret; }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session = 0; SSL_CIPHER_const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; char *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. For * DANE this only applies when using trust-anchor associations. */ if (TLS_MUST_TRUST(props->tls_level) && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane))) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * Per-session protocol restrictions must be applied to the SSL connection, * as restrictions in the global context cannot be cleared. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } /* DANE requires SSLv3 or later, not SSLv2. */ if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; /* * Per session cipher selection for sessions with mandatory encryption * * The cipherlist is applied to the global SSL context, since it is likely * to stay the same between connections, so we make use of a 1-element * cache to return the same result for identical inputs. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * We salt the session lookup key with the protocol list, so that sessions * found in the cache are plausibly acceptable. * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. * * With DANE, (more generally any TLScontext where we specified explicit * trust-anchor or end-entity certificates) the verification status of * the SSL session depends on the specified list. Since we verify the * certificate only during the initial handshake, we must segregate * sessions with different TA lists. Note, that TA re-verification is * not possible with cached sessions, since these don't hold the complete * peer trust chain. Therefore, we compute a digest of the sorted TA * parameters and append it to the serverid. */ myserverid = tls_serverid_digest(props, protomask, cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = myserverid; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; /* Alias DANE digest info from props */ TLScontext->dane = props->dane; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask)); /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ } } #ifdef TLSEXT_MAXLEN_host_name if (TLS_DANE_BASED(props->tls_level) && strlen(props->host) <= TLSEXT_MAXLEN_host_name) { /* * With DANE sessions, send an SNI hint. We don't care whether the * server reports finding a matching certificate or not, so no * callback is required to process the server response. Our use of * SNI is limited to giving servers that are (mis)configured to use * SNI the best opportunity to find the certificate they promised via * the associated TLSA RRs. (Generally, server administrators should * avoid SNI, and there are no plans to support SNI in the Postfix * SMTP server). * * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and * thererefore valid for use with SNI. Failure to set a valid SNI * hostname is a memory allocation error, and thus transient. Since * we must not cache the session if we failed to send the SNI name, * we have little choice but to abort. */ if (!SSL_set_tlsext_host_name(TLScontext->con, props->host)) { msg_warn("%s: error setting SNI hostname to: %s", props->namaddr, props->host); tls_free_context(TLScontext); return (0); } if (log_mask & TLS_LOG_DEBUG) msg_info("%s: SNI hostname: %s", props->namaddr, props->host); } #endif /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_cert_fprint. Check * fingerprint first, and avoid logging verified as untrusted in the * call to verify_extract_name(). */ verify_extract_print(TLScontext, peercert, props); verify_extract_name(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint=%s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_cert_fprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_cert_fprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * Fully secured only if trusted, matched and not insecure like halfdane. * Should perhaps also exclude "verify" (as opposed to "secure") here, * because that can be subject to insecure MX indirection, but that's * rather incompatible. Users have been warned. */ if (TLS_CERT_IS_PRESENT(TLScontext) && TLS_CERT_IS_TRUSTED(TLScontext) && TLS_CERT_IS_MATCHED(TLScontext) && !TLS_NEVER_SECURED(props->tls_level)) TLScontext->peer_status |= TLS_CERT_FLAG_SECURED; /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : TLS_CERT_IS_SECURED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
static VALUE ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) { SSL *ssl; int ilen, nread = 0; VALUE len, str; rb_io_t *fptr; rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); if(NIL_P(str)) { str = rb_bstr_new(); } else{ StringValue(str); rb_str_modify(str); str = rb_str_bstr(str); } rb_bstr_resize(str, ilen); if(ilen == 0) return str; Data_Get_Struct(self, SSL, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { if(!nonblock && SSL_pending(ssl) <= 0) rb_thread_wait_fd(FPTR_TO_FD(fptr)); for (;;){ nread = SSL_read(ssl, rb_bstr_bytes(str), rb_bstr_length(str)); switch(ssl_get_error(ssl, nread)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: rb_eof_error(); case SSL_ERROR_WANT_WRITE: write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read:"); } } } else { ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); rb_warning("SSL session is not started yet."); return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str); } end: rb_bstr_resize(str, nread); OBJ_TAINT(str); return str; }
int rsa_main(int argc, char **argv) { ENGINE *e = NULL; BIO *out = NULL; RSA *rsa = NULL; const EVP_CIPHER *enc = NULL; char *infile = NULL, *outfile = NULL, *prog; char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; int i; int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, check = 0; int noout = 0, modulus = 0, pubin = 0, pubout = 0, pvk_encr = 2, ret = 1; OPTION_CHOICE o; prog = opt_init(argc, argv, rsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF: case OPT_ERR: #ifdef OPENSSL_NO_RC4 case OPT_PVK_STRONG: case OPT_PVK_WEAK: case OPT_PVK_NONE: #endif opthelp: BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); goto end; case OPT_HELP: opt_help(rsa_options); ret = 0; goto end; case OPT_INFORM: if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) goto opthelp; break; case OPT_IN: infile = opt_arg(); break; case OPT_OUTFORM: if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) goto opthelp; break; case OPT_OUT: outfile = opt_arg(); break; case OPT_PASSIN: passinarg = opt_arg(); break; case OPT_PASSOUT: passoutarg = opt_arg(); break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; case OPT_PUBIN: pubin = 1; break; case OPT_PUBOUT: pubout = 1; break; case OPT_RSAPUBKEY_IN: pubin = 2; break; case OPT_RSAPUBKEY_OUT: pubout = 2; break; #ifndef OPENSSL_NO_RC4 case OPT_PVK_STRONG: pvk_encr = 2; break; case OPT_PVK_WEAK: pvk_encr = 1; break; case OPT_PVK_NONE: pvk_encr = 0; break; #endif case OPT_NOOUT: noout = 1; break; case OPT_TEXT: text = 1; break; case OPT_MODULUS: modulus = 1; break; case OPT_CHECK: check = 1; break; case OPT_CIPHER: if (!opt_cipher(opt_unknown(), &enc)) goto opthelp; break; } } argc = opt_num_rest(); argv = opt_rest(); if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { BIO_printf(bio_err, "Error getting passwords\n"); goto end; } if (check && pubin) { BIO_printf(bio_err, "Only private keys can be checked\n"); goto end; } { EVP_PKEY *pkey; if (pubin) { int tmpformat = -1; if (pubin == 2) { if (informat == FORMAT_PEM) tmpformat = FORMAT_PEMRSA; else if (informat == FORMAT_ASN1) tmpformat = FORMAT_ASN1RSA; } else tmpformat = informat; pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key"); } else pkey = load_key(infile, informat, 1, passin, e, "Private Key"); if (pkey != NULL) rsa = EVP_PKEY_get1_RSA(pkey); EVP_PKEY_free(pkey); } if (rsa == NULL) { ERR_print_errors(bio_err); goto end; } out = bio_open_default(outfile, "w"); if (out == NULL) goto end; if (text) if (!RSA_print(out, rsa, 0)) { perror(outfile); ERR_print_errors(bio_err); goto end; } if (modulus) { BIO_printf(out, "Modulus="); BN_print(out, rsa->n); BIO_printf(out, "\n"); } if (check) { int r = RSA_check_key(rsa); if (r == 1) BIO_printf(out, "RSA key ok\n"); else if (r == 0) { unsigned long err; while ((err = ERR_peek_error()) != 0 && ERR_GET_LIB(err) == ERR_LIB_RSA && ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY && ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { BIO_printf(out, "RSA key error: %s\n", ERR_reason_error_string(err)); ERR_get_error(); /* remove e from error stack */ } } /* should happen only if r == -1 */ if (r == -1 || ERR_peek_error() != 0) { ERR_print_errors(bio_err); goto end; } } if (noout) { ret = 0; goto end; } BIO_printf(bio_err, "writing RSA key\n"); if (outformat == FORMAT_ASN1) { if (pubout || pubin) { if (pubout == 2) i = i2d_RSAPublicKey_bio(out, rsa); else i = i2d_RSA_PUBKEY_bio(out, rsa); } else i = i2d_RSAPrivateKey_bio(out, rsa); } # ifndef OPENSSL_NO_RC4 else if (outformat == FORMAT_NETSCAPE) { unsigned char *p, *pp; int size; i = 1; size = i2d_RSA_NET(rsa, NULL, NULL, 0); if ((p = OPENSSL_malloc(size)) == NULL) { BIO_printf(bio_err, "Memory allocation failure\n"); goto end; } pp = p; i2d_RSA_NET(rsa, &p, NULL, 0); BIO_write(out, (char *)pp, size); OPENSSL_free(pp); } # endif else if (outformat == FORMAT_PEM) { if (pubout || pubin) { if (pubout == 2) i = PEM_write_bio_RSAPublicKey(out, rsa); else i = PEM_write_bio_RSA_PUBKEY(out, rsa); } else i = PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, passout); # if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { EVP_PKEY *pk; pk = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pk, rsa); if (outformat == FORMAT_PVK) i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); else if (pubin || pubout) i = i2b_PublicKey_bio(out, pk); else i = i2b_PrivateKey_bio(out, pk); EVP_PKEY_free(pk); # endif } else { BIO_printf(bio_err, "bad output format specified for outfile\n"); goto end; } if (i <= 0) { BIO_printf(bio_err, "unable to write key\n"); ERR_print_errors(bio_err); } else ret = 0; end: BIO_free_all(out); RSA_free(rsa); if (passin) OPENSSL_free(passin); if (passout) OPENSSL_free(passout); return (ret); }
static VALUE ORPV__verify_pss_sha1(VALUE self, VALUE vPubKey, VALUE vSig, VALUE vHashData, VALUE vSaltLen) { enum ORPV_errors err = OK; BIO * pkey_bio = NULL; RSA * rsa_pub_key = NULL; EVP_PKEY * pkey = NULL; EVP_PKEY_CTX * pkey_ctx = NULL; char * pub_key = NULL; int verify_rval = -1, salt_len; char ossl_err_strs[(OSSL_ERR_STR_LEN + 2) * ORPV_MAX_ERRS] = ""; if (ERR_peek_error()) { err = EXTERNAL; goto Cleanup; } vPubKey = StringValue(vPubKey); vSig = StringValue(vSig); vHashData = StringValue(vHashData); salt_len = NUM2INT(vSaltLen); if (RSTRING_LEN(vPubKey) > (long)INT_MAX) { err = KEY_OVERFLOW; goto Cleanup; } pub_key = malloc(RSTRING_LEN(vPubKey)); if (! pub_key) { err = NOMEM; goto Cleanup; } memcpy(pub_key, StringValuePtr(vPubKey), RSTRING_LEN(vPubKey)); pkey_bio = BIO_new_mem_buf(pub_key, (int)RSTRING_LEN(vPubKey)); rsa_pub_key = PEM_read_bio_RSA_PUBKEY(pkey_bio, NULL, NULL, NULL); if (! rsa_pub_key) { err = PUBKEY_PARSE; goto Cleanup; } pkey = EVP_PKEY_new(); if (! pkey) { err = PKEY_INIT; goto Cleanup; } if (! EVP_PKEY_set1_RSA(pkey, rsa_pub_key)) { err = RSA_ASSIGN; goto Cleanup; } pkey_ctx = EVP_PKEY_CTX_new(pkey, ENGINE_get_default_RSA()); if (! pkey_ctx) { err = PKEY_CTX_INIT; goto Cleanup; } if (EVP_PKEY_verify_init(pkey_ctx) <= 0) { err = VERIFY_INIT; goto Cleanup; } if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, EVP_sha1()) <= 0) { err = SET_SIG_MD; goto Cleanup; } if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) <= 0) { err = SET_PADDING; goto Cleanup; } if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) <= 0) { err = SET_SALTLEN; goto Cleanup; } verify_rval = EVP_PKEY_verify(pkey_ctx, (unsigned char*)StringValuePtr(vSig), (size_t)RSTRING_LEN(vSig), (unsigned char*)StringValuePtr(vHashData), (size_t)RSTRING_LEN(vHashData)); Cleanup: /* * BIO * pkey_bio = NULL; * RSA * rsa_pub_key = NULL; * EVP_PKEY * pkey = NULL; * EVP_PKEY_CTX * pkey_ctx = NULL; * char * pub_key = NULL; */ if (pkey_ctx) EVP_PKEY_CTX_free(pkey_ctx); if (pkey) EVP_PKEY_free(pkey); if (rsa_pub_key) RSA_free(rsa_pub_key); if (pkey_bio) BIO_free(pkey_bio); if (pub_key) free(pub_key); switch (err) { case OK: switch (verify_rval) { case 1: return Qtrue; case 0: return Qfalse; default: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "An error occurred during validation.\n%s", ossl_err_strs); } break; case EXTERNAL: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_eRuntimeError, "OpenSSL was in an error state prior to invoking this verification.\n%s", ossl_err_strs); break; case KEY_OVERFLOW: rb_raise(rb_cRSAError, "Your public key is too big. How is that even possible?"); break; case NOMEM: rb_raise(rb_const_get_at(rb_mErrno, rb_intern("ENOMEM")), "Insufficient memory to allocate pubkey copy. Woof."); break; case PUBKEY_PARSE: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Error parsing public key\n%s", ossl_err_strs); break; case PKEY_INIT: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to initialize PKEY\n%s", ossl_err_strs); break; case RSA_ASSIGN: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to assign RSA object to PKEY\n%s", ossl_err_strs); break; case PKEY_CTX_INIT: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to initialize PKEY context.\n%s", ossl_err_strs); break; case VERIFY_INIT: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to initialize verification process.\n%s", ossl_err_strs); break; case SET_SIG_MD: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to set signature message digest to SHA1.\n%s", ossl_err_strs); break; case SET_PADDING: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to set PSS padding.\n%s", ossl_err_strs); break; case SET_SALTLEN: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_cRSAError, "Failed to set salt length.\n%s", ossl_err_strs); break; default: bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS); rb_raise(rb_eRuntimeError, "Something has gone horribly wrong.\n%s", ossl_err_strs); } return Qnil; }
char *SDMMD_ssl_strerror(SSL *ssl, uint32_t ret) { static char buffer[200] = {0}; int result = SSL_get_error(ssl, ret); char *err = NULL; switch (result) { case SSL_ERROR_NONE: { break; } case SSL_ERROR_SSL: { if (ERR_peek_error()) { snprintf(buffer, 200, "SSL_ERROR_SSL (%s)", ERR_error_string(ERR_peek_error(), NULL)); err = buffer; } else { err = "SSL_ERROR_SSL unknown error"; } break; } case SSL_ERROR_WANT_READ: { err = "SSL_ERROR_WANT_READ"; break; } case SSL_ERROR_WANT_WRITE: { err = "SSL_ERROR_WANT_WRITE"; break; } case SSL_ERROR_WANT_X509_LOOKUP: { err = "SSL_ERROR_WANT_X509_LOOKUP"; break; } case SSL_ERROR_SYSCALL: { if (ERR_peek_error() == 0 && ret == 0) { err = "SSL_ERROR_SYSCALL (Early EOF reached)"; } else if (ERR_peek_error() == 0 && ret == -1) { snprintf(buffer, 200, "SSL_ERROR_SYSCALL errno (%s)", strerror(errno)); err = buffer; } else if (ERR_peek_error() == 0) { err = "SSL_ERROR_SYSCALL (WTFERROR)"; } else { snprintf(buffer, 200, "SSL_ERROR_SYSCALL internal (%s)", ERR_error_string(ERR_peek_error(), NULL)); err = buffer; } break; } case SSL_ERROR_ZERO_RETURN: { err = "SSL_ERROR_ZERO_RETURN"; break; } case SSL_ERROR_WANT_CONNECT: { err = "SSL_ERROR_WANT_CONNECT"; break; } case SSL_ERROR_WANT_ACCEPT: { err = "SSL_ERROR_WANT_ACCEPT"; break; } default: { ERR_print_errors_fp(stderr); fputc('\n', stderr); err = "Unknown SSL error type"; break; } } ERR_clear_error(); return err; }
/** Print errors in the TLS thread local error stack * * Drains the thread local OpenSSL error queue, and prints out errors. * * @param[in] request The current request (may be NULL). * @param[in] msg Error message describing the operation being attempted. * @param[in] ap Arguments for msg. * @return the number of errors drained from the stack. */ static int tls_log_error_va(REQUEST *request, char const *msg, va_list ap) { unsigned long error; char *p; int in_stack = 0; char buffer[256]; int line; char const *file; char const *data; int flags = 0; /* * Pop the first error, so ERR_peek_error() * can be used to determine if there are * multiple errors. */ error = ERR_get_error_line_data(&file, &line, &data, &flags); if (!(flags & ERR_TXT_STRING)) data = NULL; if (msg) { p = talloc_vasprintf(request, msg, ap); /* * Single line mode (there's only one error) */ if (error && !ERR_peek_error()) { ERR_error_string_n(error, buffer, sizeof(buffer)); /* Extra verbose */ if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) { ROPTIONAL(REDEBUG, ERROR, "%s: %s[%i]:%s%c%s", p, file, line, buffer, data ? ':' : '\0', data ? data : ""); } else { ROPTIONAL(REDEBUG, ERROR, "%s: %s%c%s", p, buffer, data ? ':' : '\0', data ? data : ""); } talloc_free(p); return 1; } /* * Print the error we were given, irrespective * of whether there were any OpenSSL errors. */ ROPTIONAL(RERROR, ERROR, "%s", p); talloc_free(p); } /* * Stack mode (there are multiple errors) */ if (!error) return 0; do { if (!(flags & ERR_TXT_STRING)) data = NULL; ERR_error_string_n(error, buffer, sizeof(buffer)); /* Extra verbose */ if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) { ROPTIONAL(REDEBUG, ERROR, "%s[%i]:%s%c%s", file, line, buffer, data ? ':' : '\0', data ? data : ""); } else { ROPTIONAL(REDEBUG, ERROR, "%s%c%s", buffer, data ? ':' : '\0', data ? data : ""); } in_stack++; } while ((error = ERR_get_error_line_data(&file, &line, &data, &flags))); return in_stack; }
/** * Accept the GSI Authentication. * @param sock the socket for communication. * @param ctx the authorization context. * @return the context identifier. */ bool GSISocketServer::AcceptGSIAuthentication() { char *name = NULL; long errorcode = 0; int flags; time_t curtime, starttime; int ret, accept_status; bool accept_timed_out = false; int expected = 0; BIO *bio = NULL; char *cert_file, *user_cert, *user_key, *user_proxy; char *serial=NULL; cert_file = user_cert = user_key = user_proxy = NULL; if (proxy_get_filenames(0, &cert_file, &cacertdir, &user_proxy, &user_cert, &user_key) == 0) { (void)load_credentials(user_cert, user_key, &ucert, &own_stack, &upkey, NULL); } free(cert_file); free(user_cert); free(user_key); free(user_proxy); own_cert = ucert; own_key = upkey; ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_load_verify_locations(ctx, NULL, cacertdir); SSL_CTX_use_certificate(ctx, ucert); SSL_CTX_use_PrivateKey(ctx,upkey); SSL_CTX_set_cipher_list(ctx, "ALL:!LOW:!EXP:!MD5:!MD2"); SSL_CTX_set_purpose(ctx, X509_PURPOSE_ANY); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, proxy_verify_callback); SSL_CTX_set_verify_depth(ctx, 100); SSL_CTX_set_cert_verify_callback(ctx, proxy_app_verify_callback, 0); if (own_stack) { /* * Certificate was a proxy with a cert. chain. * Add the certificates one by one to the chain. */ X509_STORE_add_cert(ctx->cert_store, ucert); for (int i = 0; i <sk_X509_num(own_stack); ++i) { X509 *cert = (sk_X509_value(own_stack,i)); if (!X509_STORE_add_cert(ctx->cert_store, cert)) { if (ERR_GET_REASON(ERR_peek_error()) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { ERR_clear_error(); continue; } else { SetErrorOpenSSL("Cannot add certificate to the SSL context's certificate store"); goto err; } } } } flags = fcntl(newsock, F_GETFL, 0); (void)fcntl(newsock, F_SETFL, flags | O_NONBLOCK); bio = BIO_new_socket(newsock, BIO_NOCLOSE); (void)BIO_set_nbio(bio, 1); ssl = SSL_new(ctx); setup_SSL_proxy_handler(ssl, cacertdir); writeb = bio->method->bwrite; readb = bio->method->bread; bio->method->bwrite = globusf_write; bio->method->bread = globusf_read; SSL_set_bio(ssl, bio, bio); curtime = starttime = time(NULL); ret = accept_status = -1; expected = 0; do { ret = do_select(newsock, starttime, timeout, expected); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select status: %d",ret); curtime = time(NULL); if (ret == 0){ LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select timed out."); if (curtime - starttime > timeout){ accept_timed_out = true; break; }else{ continue; } } if (ret > 0) { accept_status = SSL_accept(ssl); curtime = time(NULL); expected = errorcode = SSL_get_error(ssl, accept_status); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Accept status: %d",accept_status); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Error code: %d",errorcode); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "SSL_WANT_READ: %d, SSL_WANT_WRITE: %d",SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE); } if (ret < 0) // No more data from the select break; if (accept_status == 1) // SSL handshake completed break; if (timeout != -1 && (curtime - starttime > timeout)){ // Timeout reached accept_timed_out = true; break; } if (accept_status <= 0 && ( errorcode != SSL_ERROR_WANT_READ && errorcode != SSL_ERROR_WANT_WRITE )) // SSL handshake error break; } while (true); // Error enstabilishing context if (accept_status != 1){ LOGM(VARP, logh, LEV_INFO, T_PRE, "Error enstabilishing SSL context."); if (accept_timed_out){ SetError("SSL Handshake failed due to server timeout!"); }else{ SetErrorOpenSSL("SSL Handshake error:"); } goto err; } // Context enstabilished actual_cert = SSL_get_peer_certificate(ssl); peer_stack = SSL_get_peer_cert_chain(ssl); char buffer[1000]; // if (LogLevelMin(logh, LEV_DEBUG)) { LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s", X509_NAME_oneline(X509_get_subject_name(actual_cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s", X509_NAME_oneline(X509_get_issuer_name(actual_cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Stack Size: %d", sk_X509_num(peer_stack)); // } peer_cert = get_real_cert(actual_cert, peer_stack); if (peer_cert) { char *name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0); own_subject = std::string(name); OPENSSL_free(name); } if (LogLevelMin(logh, LEV_DEBUG)){ for (int i = 0; i < sk_X509_num(peer_stack); i++) { X509 *cert = sk_X509_value(peer_stack, i); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s", X509_NAME_oneline(X509_get_subject_name(cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s", X509_NAME_oneline(X509_get_issuer_name(cert), buffer, 999)); } } name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0); if (name) peer_subject = std::string(name); OPENSSL_free(name); name = X509_NAME_oneline(X509_get_issuer_name(peer_cert), NULL, 0); if (name) peer_ca = std::string(name); OPENSSL_free(name); serial = get_peer_serial(actual_cert); peer_serial = std::string(serial ? serial : ""); OPENSSL_free(serial); return true; err: destroy_SSL_proxy_handler(ssl); SSL_free(ssl); SSL_CTX_free(ctx); return false; }
/* Switch a socket to SSL communication * * Creates a SSL data structure for the connection; * Sets up callbacks and initiates a SSL handshake with the peer; * Reports error conditions and performs cleanup upon failure. * * flags: ssl flags, i.e connect or listen * verify: peer certificate verification flags * loglevel: is the level to output information about the connection * and certificates. * host: contains the dns name or ip address of the peer. Used for * verification. * cb: optional callback, this function will be called after the * handshake completes. * * Return value: 0 on success, !=0 on failure. */ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, IntFunc cb) { int i, err, ret; ssl_appdata *data; struct threaddata *td = threaddata(); debug0("TLS: attempting SSL negotiation..."); if (!ssl_ctx && ssl_init()) { debug0("TLS: Failed. OpenSSL not initialized properly."); return -1; } /* find the socket in the list */ i = findsock(sock); if (i == -1) { debug0("TLS: socket not in socklist"); return -2; } if (td->socklist[i].ssl) { debug0("TLS: handshake not required - SSL session already established"); return 0; } td->socklist[i].ssl = SSL_new(ssl_ctx); if (!td->socklist[i].ssl || !SSL_set_fd(td->socklist[i].ssl, td->socklist[i].sock)) { debug1("TLS: cannot initiate SSL session - %s", ERR_error_string(ERR_get_error(), 0)); return -3; } /* Prepare a ssl appdata struct for the verify callback */ data = nmalloc(sizeof(ssl_appdata)); egg_bzero(data, sizeof(ssl_appdata)); data->flags = flags & (TLS_LISTEN | TLS_CONNECT); data->verify = flags & ~(TLS_LISTEN | TLS_CONNECT); data->loglevel = loglevel; data->cb = cb; strncpyz(data->host, host ? host : "", sizeof(data->host)); SSL_set_app_data(td->socklist[i].ssl, data); SSL_set_info_callback(td->socklist[i].ssl, (void *) ssl_info); /* We set this +1 to be able to report extra long chains properly. * Otherwise, OpenSSL will break the verification reporting about * missing certificates instead. The rest of the fix is in * ssl_verify() */ SSL_set_verify_depth(td->socklist[i].ssl, tls_maxdepth + 1); SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); if (data->flags & TLS_CONNECT) { SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify); ret = SSL_connect(td->socklist[i].ssl); if (!ret) debug0("TLS: connect handshake failed."); } else { if (data->flags & TLS_VERIFYPEER) SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify); else SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify); ret = SSL_accept(td->socklist[i].ssl); if (!ret) debug0("TLS: accept handshake failed"); } err = SSL_get_error(td->socklist[i].ssl, ret); /* Normal condition for async I/O, similar to EAGAIN */ if (ret > 0 || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { debug0("TLS: handshake in progress"); return 0; } if (ERR_peek_error()) debug0("TLS: handshake failed due to the following errors: "); while ((err = ERR_get_error())) debug1("TLS: %s", ERR_error_string(err, NULL)); /* Attempt failed, cleanup and abort */ SSL_shutdown(td->socklist[i].ssl); SSL_free(td->socklist[i].ssl); td->socklist[i].ssl = NULL; nfree(data); return -4; }
NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c, OCSP_REQUEST *req, char *url) { BIO *bio=NULL; OCSP_REQ_CTX *req_ctx=NULL; OCSP_RESPONSE *resp=NULL; int err; char *host=NULL, *port=NULL, *path=NULL; SOCKADDR_UNION addr; int ssl; /* parse the OCSP URL */ if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) { s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL"); goto cleanup; } if(ssl) { s_log(LOG_ERR, "OCSP: SSL not supported for OCSP" " - additional stunnel service needs to be defined"); goto cleanup; } memset(&addr, 0, sizeof addr); addr.in.sin_family=AF_INET; if(!hostport2addr(&addr, host, port)) { s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP server address"); goto cleanup; } /* connect specified OCSP server (responder) */ c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket"); if(c->fd<0) goto cleanup; if(s_connect(c, &addr, addr_len(&addr))) goto cleanup; bio=BIO_new_fd(c->fd, BIO_NOCLOSE); if(!bio) goto cleanup; s_log(LOG_DEBUG, "OCSP: response retrieved"); /* OCSP protocol communication loop */ req_ctx=OCSP_sendreq_new(bio, path, req, -1); if(!req_ctx) { sslerror("OCSP: OCSP_sendreq_new"); goto cleanup; } while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) { s_poll_init(c->fds); s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio)); err=s_poll_wait(c->fds, c->opt->timeout_busy, 0); if(err==-1) sockerror("OCSP: s_poll_wait"); if(err==0) s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded"); if(err<=0) goto cleanup; } #if 0 s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); #endif /* http://www.mail-archive.com/[email protected]/msg61691.html */ if(resp) { s_log(LOG_DEBUG, "OCSP: request completed"); } else { if(ERR_peek_error()) sslerror("OCSP: OCSP_sendreq_nbio"); else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */ s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error"); } cleanup: if(req_ctx) OCSP_REQ_CTX_free(req_ctx); if(bio) BIO_free_all(bio); if(c->fd>=0) { closesocket(c->fd); c->fd=-1; /* avoid double close on cleanup */ } if(host) OPENSSL_free(host); if(port) OPENSSL_free(port); if(path) OPENSSL_free(path); return resp; }
int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_engine, const char *priv_key_file #if ENABLE_INLINE_FILES , const char *priv_key_file_inline #endif ) { int status; SSL_CTX *ssl_ctx = NULL; BIO *in = NULL; EVP_PKEY *pkey = NULL; int ret = 1; ASSERT(NULL != ctx); ssl_ctx = ctx->ctx; #if ENABLE_INLINE_FILES if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) in = BIO_new_mem_buf ((char *)priv_key_file_inline, -1); else #endif /* ENABLE_INLINE_FILES */ in = BIO_new_file (priv_key_file, "r"); if (!in) goto end; if (priv_key_engine) { ENGINE *engine; ENGINE_load_builtin_engines(); engine = ENGINE_by_id(priv_key_engine); if (!ENGINE_init(engine)) { msg (M_WARN|M_SSL, "Cannot init engine %s", priv_key_engine); goto end; } pkey = ENGINE_load_private_key(engine, priv_key_file, UI_OpenSSL(), NULL); } else { pkey = PEM_read_bio_PrivateKey (in, NULL, ssl_ctx->default_passwd_callback, ssl_ctx->default_passwd_callback_userdata); } if (!pkey) goto end; if (!SSL_CTX_use_PrivateKey (ssl_ctx, pkey)) { #ifdef ENABLE_MANAGEMENT if (management && (ERR_GET_REASON (ERR_peek_error()) == EVP_R_BAD_DECRYPT)) management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); #endif msg (M_WARN|M_SSL, "Cannot load private key file %s", priv_key_file); goto end; } warn_if_group_others_accessible (priv_key_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ssl_ctx)) msg (M_SSLERR, "Private key does not match the certificate"); ret = 0; end: if (pkey) EVP_PKEY_free (pkey); if (in) BIO_free (in); return ret; }
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) { BUF_MEM *b; unsigned char *p; int i; ASN1_const_CTX c; size_t want = HEADER_SIZE; int eos = 0; size_t off = 0; size_t len = 0; b = BUF_MEM_new(); if (b == NULL) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); return -1; } ERR_clear_error(); for (;;) { if (want >= (len - off)) { want -= (len - off); if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); goto err; } i = BIO_read(in, &(b->data[len]), want); if ((i < 0) && ((len - off) == 0)) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA); goto err; } if (i > 0) { if (len + i < len) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); goto err; } len += i; } } /* else data already loaded */ p = (unsigned char *) & (b->data[off]); c.p = p; c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass), len - off); if (c.inf & 0x80) { unsigned long e; e = ERR_GET_REASON(ERR_peek_error()); if (e != ASN1_R_TOO_LONG) goto err; else ERR_clear_error(); /* clear error */ } i = c.p - p; /* header length */ off += i; /* end of data */ if (c.inf & 1) { /* no data body so go round again */ eos++; if (eos < 0) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG); goto err; } want = HEADER_SIZE; } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) { /* eos value, so go back and read another header */ eos--; if (eos <= 0) break; else want = HEADER_SIZE; } else { /* suck in c.slen bytes of data */ want = c.slen; if (want > (len - off)) { want -= (len - off); if (want > INT_MAX /* BIO_read takes an int length */ || len+want < len) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); goto err; } if (!BUF_MEM_grow_clean(b, len + want)) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); goto err; } while (want > 0) { i = BIO_read(in, &(b->data[len]), want); if (i <= 0) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA); goto err; } /* This can't overflow because * |len+want| didn't overflow. */ len += i; want -= i; } } if (off + c.slen < off) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); goto err; } off += c.slen; if (eos <= 0) { break; } else want = HEADER_SIZE; } } if (off > INT_MAX) { ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); goto err; } *pb = b; return off; err: if (b != NULL) BUF_MEM_free(b); return -1; }
static int openssl_iostream_handle_error_full(struct ssl_iostream *ssl_io, int ret, const char *func_name, bool write_error) { const char *errstr = NULL; int err; err = SSL_get_error(ssl_io->ssl, ret); switch (err) { case SSL_ERROR_WANT_WRITE: if (!openssl_iostream_bio_sync(ssl_io)) { if (!write_error) i_panic("SSL ostream buffer size not unlimited"); return 0; } if (ssl_io->closed) { if (ssl_io->plain_stream_errstr != NULL) openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr); errno = ssl_io->plain_stream_errno != 0 ? ssl_io->plain_stream_errno : EPIPE; return -1; } return 1; case SSL_ERROR_WANT_READ: ssl_io->want_read = TRUE; (void)openssl_iostream_bio_sync(ssl_io); if (ssl_io->closed) { if (ssl_io->plain_stream_errstr != NULL) openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr); errno = ssl_io->plain_stream_errno != 0 ? ssl_io->plain_stream_errno : EPIPE; return -1; } return ssl_io->want_read ? 0 : 1; case SSL_ERROR_SYSCALL: /* eat up the error queue */ if (ERR_peek_error() != 0) { errstr = openssl_iostream_error(); errno = EINVAL; } else if (ret != 0) { i_assert(errno != 0); errstr = strerror(errno); } else { /* EOF. */ errno = EPIPE; errstr = "Disconnected"; break; } errstr = t_strdup_printf("%s syscall failed: %s", func_name, errstr); break; case SSL_ERROR_ZERO_RETURN: /* clean connection closing */ errno = EPIPE; i_free_and_null(ssl_io->last_error); return -1; case SSL_ERROR_SSL: errstr = t_strdup_printf("%s failed: %s", func_name, openssl_iostream_error()); errno = EINVAL; break; default: errstr = t_strdup_printf("%s failed: unknown failure %d (%s)", func_name, err, openssl_iostream_error()); errno = EINVAL; break; } openssl_iostream_set_error(ssl_io, errstr); return -1; }
/** * NOTE: From node.js * * Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. * * Taken from OpenSSL - editted for style. */ int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) { int ret; X509* x; X509* ca; X509_STORE* store; X509_STORE_CTX store_ctx; int r; unsigned long err; ERR_clear_error(); ret = 0; x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx->ctx, x); ctx->cert = x; ctx->issuer = NULL; if (ERR_peek_error() != 0) { /* Key/certificate mismatch doesn't imply ret==0 ... */ ret = 0; } if (ret) { /** * If we could set up our certificate, now proceed to * the CA certificates. */ if (ctx->ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->ctx->extra_certs, X509_free); ctx->ctx->extra_certs = NULL; } while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) { r = SSL_CTX_add_extra_chain_cert(ctx->ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /** * Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ /* Find issuer */ if (ctx->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK) continue; ctx->issuer = ca; } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { ERR_clear_error(); } else { /* some real error */ ret = 0; } } end: if (ret) { /* Try getting issuer from cert store */ if (ctx->issuer == NULL) { store = SSL_CTX_get_cert_store(ctx->ctx); ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL); if (!ret) goto fatal; ret = X509_STORE_CTX_get1_issuer(&ctx->issuer, &store_ctx, ctx->cert); X509_STORE_CTX_cleanup(&store_ctx); ret = ret < 0 ? 0 : 1; /* NOTE: get_cert_store doesn't increment reference count */ } else { /* Increment issuer reference count */ CRYPTO_add(&ctx->issuer->references, 1, CRYPTO_LOCK_X509); } if (ctx->issuer != NULL) { /* Get ocsp_id */ ctx->ocsp_id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (ctx->ocsp_id == NULL) { ctx->issuer = NULL; goto fatal; } } } else { if (ctx->issuer != NULL) X509_free(ctx->issuer); } fatal: if (ctx->cert != x && x != NULL) X509_free(x); return ret; }
/* Read a file that contains our certificate in "PEM" format, possibly followed * by a sequence of CA certificates that should be sent to the peer in the * Certificate message. */ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { BIO *in; int ret = 0; X509 *x = NULL; ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ in = BIO_new(BIO_s_file()); if (in == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); goto end; } if (BIO_read_filename(in, file) <= 0) { OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); goto end; } x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata); if (x == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx, x); if (ERR_peek_error() != 0) { ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ } if (ret) { /* If we could set up our certificate, now proceed to the CA * certificates. */ X509 *ca; int r; uint32_t err; SSL_CTX_clear_chain_certs(ctx); while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata)) != NULL) { r = SSL_CTX_add0_chain_cert(ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /* Note that we must not free r if it was successfully added to the chain * (while we must free the main certificate, since its reference count is * increased by SSL_CTX_use_certificate). */ } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { ERR_clear_error(); } else { ret = 0; /* some real error */ } } end: X509_free(x); BIO_free(in); return ret; }
/* * Read a file that contains our certificate in "PEM" format, possibly * followed by a sequence of CA certificates that should be sent to the peer * in the Certificate message. */ static int use_certificate_chain_file(SSL_CTX *ctx, SSL *ssl, const char *file) { BIO *in; int ret = 0; X509 *x = NULL; pem_password_cb *passwd_callback; void *passwd_callback_userdata; ERR_clear_error(); /* clear error stack for * SSL_CTX_use_certificate() */ if (ctx != NULL) { passwd_callback = ctx->default_passwd_callback; passwd_callback_userdata = ctx->default_passwd_callback_userdata; } else { passwd_callback = ssl->default_passwd_callback; passwd_callback_userdata = ssl->default_passwd_callback_userdata; } in = BIO_new(BIO_s_file()); if (in == NULL) { SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); goto end; } if (BIO_read_filename(in, file) <= 0) { SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_SYS_LIB); goto end; } x = PEM_read_bio_X509_AUX(in, NULL, passwd_callback, passwd_callback_userdata); if (x == NULL) { SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } if (ctx) ret = SSL_CTX_use_certificate(ctx, x); else ret = SSL_use_certificate(ssl, x); if (ERR_peek_error() != 0) ret = 0; /* Key/certificate mismatch doesn't imply * ret==0 ... */ if (ret) { /* * If we could set up our certificate, now proceed to the CA * certificates. */ X509 *ca; int r; unsigned long err; if (ctx) r = SSL_CTX_clear_chain_certs(ctx); else r = SSL_clear_chain_certs(ssl); if (r == 0) { ret = 0; goto end; } while ((ca = PEM_read_bio_X509(in, NULL, passwd_callback, passwd_callback_userdata)) != NULL) { if (ctx) r = SSL_CTX_add0_chain_cert(ctx, ca); else r = SSL_add0_chain_cert(ssl, ca); /* * Note that we must not free ca if it was successfully added to * the chain (while we must free the main certificate, since its * reference count is increased by SSL_CTX_use_certificate). */ if (!r) { X509_free(ca); ret = 0; goto end; } } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) ERR_clear_error(); else ret = 0; /* some real error */ } end: X509_free(x); BIO_free(in); return (ret); }
int MAIN(int argc, char **argv) { ENGINE *e = NULL; int ret=1; RSA *rsa=NULL; int i,badops=0, sgckey=0; const EVP_CIPHER *enc=NULL; BIO *out=NULL; int informat,outformat,text=0,check=0,noout=0; int pubin = 0, pubout = 0; char *infile,*outfile,*prog; char *passargin = NULL, *passargout = NULL; char *passin = NULL, *passout = NULL; #ifndef OPENSSL_NO_ENGINE char *engine=NULL; #endif int modulus=0; int pvk_encr = 2; apps_startup(); if (bio_err == NULL) if ((bio_err=BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err,OPENSSL_TYPE__FILE_STDERR,BIO_NOCLOSE|BIO_FP_TEXT); if (!load_config(bio_err, NULL)) goto end; infile=NULL; outfile=NULL; informat=FORMAT_PEM; outformat=FORMAT_PEM; prog=argv[0]; argc--; argv++; while (argc >= 1) { if (TINYCLR_SSL_STRCMP(*argv,"-inform") == 0) { if (--argc < 1) goto bad; informat=str2fmt(*(++argv)); } else if (TINYCLR_SSL_STRCMP(*argv,"-outform") == 0) { if (--argc < 1) goto bad; outformat=str2fmt(*(++argv)); } else if (TINYCLR_SSL_STRCMP(*argv,"-in") == 0) { if (--argc < 1) goto bad; infile= *(++argv); } else if (TINYCLR_SSL_STRCMP(*argv,"-out") == 0) { if (--argc < 1) goto bad; outfile= *(++argv); } else if (TINYCLR_SSL_STRCMP(*argv,"-passin") == 0) { if (--argc < 1) goto bad; passargin= *(++argv); } else if (TINYCLR_SSL_STRCMP(*argv,"-passout") == 0) { if (--argc < 1) goto bad; passargout= *(++argv); } #ifndef OPENSSL_NO_ENGINE else if (TINYCLR_SSL_STRCMP(*argv,"-engine") == 0) { if (--argc < 1) goto bad; engine= *(++argv); } #endif else if (TINYCLR_SSL_STRCMP(*argv,"-sgckey") == 0) sgckey=1; else if (TINYCLR_SSL_STRCMP(*argv,"-pubin") == 0) pubin=1; else if (TINYCLR_SSL_STRCMP(*argv,"-pubout") == 0) pubout=1; else if (TINYCLR_SSL_STRCMP(*argv,"-RSAPublicKey_in") == 0) pubin = 2; else if (TINYCLR_SSL_STRCMP(*argv,"-RSAPublicKey_out") == 0) pubout = 2; else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-strong") == 0) pvk_encr=2; else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-weak") == 0) pvk_encr=1; else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-none") == 0) pvk_encr=0; else if (TINYCLR_SSL_STRCMP(*argv,"-noout") == 0) noout=1; else if (TINYCLR_SSL_STRCMP(*argv,"-text") == 0) text=1; else if (TINYCLR_SSL_STRCMP(*argv,"-modulus") == 0) modulus=1; else if (TINYCLR_SSL_STRCMP(*argv,"-check") == 0) check=1; else if ((enc=EVP_get_cipherbyname(&(argv[0][1]))) == NULL) { BIO_printf(bio_err,"unknown option %s\n",*argv); badops=1; break; } argc--; argv++; } if (badops) { bad: BIO_printf(bio_err,"%s [options] <infile >outfile\n",prog); BIO_printf(bio_err,"where options are\n"); BIO_printf(bio_err," -inform arg input format - one of DER NET PEM\n"); BIO_printf(bio_err," -outform arg output format - one of DER NET PEM\n"); BIO_printf(bio_err," -in arg input file\n"); BIO_printf(bio_err," -sgckey Use IIS SGC key format\n"); BIO_printf(bio_err," -passin arg input file pass phrase source\n"); BIO_printf(bio_err," -out arg output file\n"); BIO_printf(bio_err," -passout arg output file pass phrase source\n"); BIO_printf(bio_err," -des encrypt PEM output with cbc des\n"); BIO_printf(bio_err," -des3 encrypt PEM output with ede cbc des using 168 bit key\n"); #ifndef OPENSSL_NO_IDEA BIO_printf(bio_err," -idea encrypt PEM output with cbc idea\n"); #endif #ifndef OPENSSL_NO_SEED BIO_printf(bio_err," -seed encrypt PEM output with cbc seed\n"); #endif #ifndef OPENSSL_NO_AES BIO_printf(bio_err," -aes128, -aes192, -aes256\n"); BIO_printf(bio_err," encrypt PEM output with cbc aes\n"); #endif #ifndef OPENSSL_NO_CAMELLIA BIO_printf(bio_err," -camellia128, -camellia192, -camellia256\n"); BIO_printf(bio_err," encrypt PEM output with cbc camellia\n"); #endif BIO_printf(bio_err," -text print the key in text\n"); BIO_printf(bio_err," -noout don't print key out\n"); BIO_printf(bio_err," -modulus print the RSA key modulus\n"); BIO_printf(bio_err," -check verify key consistency\n"); BIO_printf(bio_err," -pubin expect a public key in input file\n"); BIO_printf(bio_err," -pubout output a public key\n"); #ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err," -engine e use engine e, possibly a hardware device.\n"); #endif goto end; } ERR_load_crypto_strings(); #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine, 0); #endif if(!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { BIO_printf(bio_err, "Error getting passwords\n"); goto end; } if(check && pubin) { BIO_printf(bio_err, "Only private keys can be checked\n"); goto end; } out=BIO_new(BIO_s_file()); { EVP_PKEY *pkey; if (pubin) { int tmpformat=-1; if (pubin == 2) { if (informat == FORMAT_PEM) tmpformat = FORMAT_PEMRSA; else if (informat == FORMAT_ASN1) tmpformat = FORMAT_ASN1RSA; } else if (informat == FORMAT_NETSCAPE && sgckey) tmpformat = FORMAT_IISSGC; else tmpformat = informat; pkey = load_pubkey(bio_err, infile, tmpformat, 1, passin, e, "Public Key"); } else pkey = load_key(bio_err, infile, (informat == FORMAT_NETSCAPE && sgckey ? FORMAT_IISSGC : informat), 1, passin, e, "Private Key"); if (pkey != NULL) rsa = EVP_PKEY_get1_RSA(pkey); EVP_PKEY_free(pkey); } if (rsa == NULL) { ERR_print_errors(bio_err); goto end; } if (outfile == NULL) { BIO_set_fp(out,OPENSSL_TYPE__FILE_STDOUT,BIO_NOCLOSE); #ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); out = BIO_push(tmpbio, out); } #endif } else { if (BIO_write_filename(out,outfile) <= 0) { TINYCLR_SSL_PERROR(outfile); goto end; } } if (text) if (!RSA_print(out,rsa,0)) { TINYCLR_SSL_PERROR(outfile); ERR_print_errors(bio_err); goto end; } if (modulus) { BIO_printf(out,"Modulus="); BN_print(out,rsa->n); BIO_printf(out,"\n"); } if (check) { int r = RSA_check_key(rsa); if (r == 1) BIO_printf(out,"RSA key ok\n"); else if (r == 0) { unsigned long err; while ((err = ERR_peek_error()) != 0 && ERR_GET_LIB(err) == ERR_LIB_RSA && ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY && ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { BIO_printf(out, "RSA key error: %s\n", ERR_reason_error_string(err)); ERR_get_error(); /* remove e from error stack */ } } if (r == -1 || ERR_peek_error() != 0) /* should happen only if r == -1 */ { ERR_print_errors(bio_err); goto end; } } if (noout) { ret = 0; goto end; } BIO_printf(bio_err,"writing RSA key\n"); if (outformat == FORMAT_ASN1) { if(pubout || pubin) { if (pubout == 2) i=i2d_RSAPublicKey_bio(out,rsa); else i=i2d_RSA_PUBKEY_bio(out,rsa); } else i=i2d_RSAPrivateKey_bio(out,rsa); } #ifndef OPENSSL_NO_RC4 else if (outformat == FORMAT_NETSCAPE) { unsigned char *p,*pp; int size; i=1; size=i2d_RSA_NET(rsa,NULL,NULL, sgckey); if ((p=(unsigned char *)OPENSSL_malloc(size)) == NULL) { BIO_printf(bio_err,"Memory allocation failure\n"); goto end; } pp=p; i2d_RSA_NET(rsa,&p,NULL, sgckey); BIO_write(out,(char *)pp,size); OPENSSL_free(pp); } #endif else if (outformat == FORMAT_PEM) { if(pubout || pubin) { if (pubout == 2) i=PEM_write_bio_RSAPublicKey(out,rsa); else i=PEM_write_bio_RSA_PUBKEY(out,rsa); } else i=PEM_write_bio_RSAPrivateKey(out,rsa, enc,NULL,0,NULL,passout); #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { EVP_PKEY *pk; pk = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pk, rsa); if (outformat == FORMAT_PVK) i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); else if (pubin || pubout) i = i2b_PublicKey_bio(out, pk); else i = i2b_PrivateKey_bio(out, pk); EVP_PKEY_free(pk); #endif } else { BIO_printf(bio_err,"bad output format specified for outfile\n"); goto end; } if (i <= 0) { BIO_printf(bio_err,"unable to write key\n"); ERR_print_errors(bio_err); } else ret=0; end: if(out != NULL) BIO_free_all(out); if(rsa != NULL) RSA_free(rsa); if(passin) OPENSSL_free(passin); if(passout) OPENSSL_free(passout); apps_shutdown(); OPENSSL_EXIT(ret); }
bool SSLSocket::handleError(int64_t nr_bytes, bool is_init) { char esbuf[512]; std::string ebuf; unsigned long ecode; bool retry = true; int err = SSL_get_error(m_data->m_handle, nr_bytes); switch (err) { case SSL_ERROR_ZERO_RETURN: /* SSL terminated (but socket may still be active) */ retry = false; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* re-negotiation, or perhaps the SSL layer needs more * packets: retry in next iteration */ errno = EAGAIN; retry = (is_init || m_data->m_is_blocked); break; case SSL_ERROR_SYSCALL: if (ERR_peek_error() == 0) { if (nr_bytes == 0) { if (ERR_get_error()) { raise_warning("SSL: fatal protocol error"); } SSL_set_shutdown(m_data->m_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); setEof(true); retry = false; } else { raise_warning("SSL: %s", folly::errnoStr(errno).c_str()); retry = false; } break; } /* fall through */ default: /* some other error */ ecode = ERR_get_error(); switch (ERR_GET_REASON(ecode)) { case SSL_R_NO_SHARED_CIPHER: raise_warning("SSL_R_NO_SHARED_CIPHER: no suitable shared cipher " "could be used. This could be because the server is " "missing an SSL certificate (local_cert context " "option)"); retry = false; break; default: do { // NULL is automatically added ERR_error_string_n(ecode, esbuf, sizeof(esbuf)); if (!ebuf.empty()) { ebuf += '\n'; } ebuf += esbuf; } while ((ecode = ERR_get_error()) != 0); raise_warning("SSL operation failed with code %d. %s%s", err, !ebuf.empty() ? "OpenSSL Error messages:\n" : "", !ebuf.empty() ? ebuf.c_str() : ""); } retry = false; errno = 0; } return retry; }
int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, const char *pkcs12_file_inline, bool load_ca_file ) { FILE *fp; EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *ca = NULL; PKCS12 *p12; int i; char password[256]; ASSERT(NULL != ctx); if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline) { BIO *b64 = BIO_new(BIO_f_base64()); BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline, (int) strlen(pkcs12_file_inline)); ASSERT(b64 && bio); BIO_push(b64, bio); p12 = d2i_PKCS12_bio(b64, NULL); if (!p12) msg(M_SSLERR, "Error reading inline PKCS#12 file"); BIO_free(b64); BIO_free(bio); } else { /* Load the PKCS #12 file */ if (!(fp = platform_fopen(pkcs12_file, "rb"))) msg(M_SSLERR, "Error opening file %s", pkcs12_file); p12 = d2i_PKCS12_fp(fp, NULL); fclose(fp); if (!p12) msg(M_SSLERR, "Error reading PKCS#12 file %s", pkcs12_file); } /* Parse the PKCS #12 file */ if (!PKCS12_parse(p12, "", &pkey, &cert, &ca)) { pem_password_callback (password, sizeof(password) - 1, 0, NULL); /* Reparse the PKCS #12 file with password */ ca = NULL; if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) { #ifdef ENABLE_MANAGEMENT if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE)) management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); #endif PKCS12_free(p12); return 1; } } PKCS12_free(p12); /* Load Certificate */ if (!SSL_CTX_use_certificate (ctx->ctx, cert)) msg (M_SSLERR, "Cannot use certificate"); /* Load Private Key */ if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey)) msg (M_SSLERR, "Cannot use private key"); warn_if_group_others_accessible (pkcs12_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ctx->ctx)) msg (M_SSLERR, "Private key does not match the certificate"); /* Set Certificate Verification chain */ if (load_ca_file) { /* Add CAs from PKCS12 to the cert store and mark them as trusted. * They're also used to fill in the chain of intermediate certs as * necessary. */ if (ca && sk_X509_num(ca)) { for (i = 0; i < sk_X509_num(ca); i++) { if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); } } } else { /* If trusted CA certs were loaded from a PEM file, and we ignore the * ones in PKCS12, do load PKCS12-provided certs to the client extra * certs chain just in case they include intermediate CAs needed to * prove my identity to the other end. This does not make them trusted. */ if (ca && sk_X509_num(ca)) { for (i = 0; i < sk_X509_num(ca); i++) { if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); } } } return 0; }
static int ma_tls_set_certs(MYSQL *mysql) { char *certfile= mysql->options.ssl_cert, *keyfile= mysql->options.ssl_key; /* add cipher */ if ((mysql->options.ssl_cipher && mysql->options.ssl_cipher[0] != 0) && SSL_CTX_set_cipher_list(SSL_context, mysql->options.ssl_cipher) == 0) goto error; /* ca_file and ca_path */ if (SSL_CTX_load_verify_locations(SSL_context, mysql->options.ssl_ca, mysql->options.ssl_capath) == 0) { if (mysql->options.ssl_ca || mysql->options.ssl_capath) goto error; if (SSL_CTX_set_default_verify_paths(SSL_context) == 0) goto error; } if (keyfile && !certfile) certfile= keyfile; if (certfile && !keyfile) keyfile= certfile; /* set cert */ if (certfile && certfile[0] != 0) if (SSL_CTX_use_certificate_file(SSL_context, certfile, SSL_FILETYPE_PEM) != 1) goto error; /* If the private key file is encrypted, we need to register a callback function * for providing password. */ if (OPT_HAS_EXT_VAL(mysql, tls_pw)) { SSL_CTX_set_default_passwd_cb_userdata(SSL_context, (void *)mysql->options.extension->tls_pw); SSL_CTX_set_default_passwd_cb(SSL_context, ma_tls_get_password); } if (keyfile && keyfile[0]) { if (SSL_CTX_use_PrivateKey_file(SSL_context, keyfile, SSL_FILETYPE_PEM) != 1) { unsigned long err= ERR_peek_error(); if (!(ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) goto error; } } if (OPT_HAS_EXT_VAL(mysql, tls_pw)) { SSL_CTX_set_default_passwd_cb_userdata(SSL_context, NULL); SSL_CTX_set_default_passwd_cb(SSL_context, NULL); } /* verify key */ if (certfile && !SSL_CTX_check_private_key(SSL_context)) goto error; if (mysql->options.extension && (mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath)) { X509_STORE *certstore; if ((certstore= SSL_CTX_get_cert_store(SSL_context))) { if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl, mysql->options.extension->ssl_crlpath) == 0) goto error; X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } } return 0; error: ma_tls_set_error(mysql); return 1; }
int ssl_ctx_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len) { int ret; BIO *in; X509 *x; X509 *ca; unsigned long err; ret = 0; x = ca = NULL; if ((in = BIO_new_mem_buf(buf, len)) == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); goto end; } if ((x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata)) == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } if (!SSL_CTX_use_certificate(ctx, x) || ERR_peek_error() != 0) goto end; /* If we could set up our certificate, now proceed to * the CA certificates. */ if (ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->extra_certs, X509_free); ctx->extra_certs = NULL; } while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata)) != NULL) { if (!SSL_CTX_add_extra_chain_cert(ctx, ca)) goto end; } err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) ERR_clear_error(); else goto end; ret = 1; end: if (ca != NULL) X509_free(ca); if (x != NULL) X509_free(x); if (in != NULL) BIO_free(in); return (ret); }
/** * NOTE: From node.js * * Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. * * Taken from OpenSSL - editted for style. */ int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) { int ret; X509* x; X509* ca; int r; unsigned long err; bud_context_pkey_type_t type; bud_context_pem_t* pem; ERR_clear_error(); ret = 0; x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); pem = NULL; if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx->ctx, x); SSL_CTX_select_current_cert(ctx->ctx, x); type = bud_config_pkey_type(x->cert_info->key->pkey); pem = &ctx->pem[type]; pem->cert = x; pem->issuer = NULL; if (ERR_peek_error() != 0) { /* Key/certificate mismatch doesn't imply ret==0 ... */ ret = 0; } if (ret) { while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) { /* * Extra cert - add it to store to make OpenSSL pick and send proper * certs automatically */ r = SSL_CTX_add1_chain_cert(ctx->ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /** * Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ /* Find issuer */ if (pem->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK) continue; pem->issuer = ca; } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { ERR_clear_error(); } else { /* some real error */ ret = 0; } } end: if (ret) { /* Try getting issuer from cert store */ if (pem->issuer == NULL) { X509_STORE* store; X509_STORE_CTX store_ctx; store = SSL_CTX_get_cert_store(ctx->ctx); ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL); if (!ret) goto fatal; ret = X509_STORE_CTX_get1_issuer(&pem->issuer, &store_ctx, pem->cert); X509_STORE_CTX_cleanup(&store_ctx); ret = ret < 0 ? 0 : 1; /* NOTE: get_cert_store doesn't increment reference count */ } else { /* Increment issuer reference count */ CRYPTO_add(&pem->issuer->references, 1, CRYPTO_LOCK_X509); } if (pem->issuer != NULL) { /* Get ocsp_id */ pem->ocsp_id = OCSP_cert_to_id(NULL, pem->cert, pem->issuer); if (pem->ocsp_id == NULL) goto fatal; } } fatal: if (!ret && pem != NULL && pem->issuer != NULL) { X509_free(pem->issuer); pem->issuer = NULL; } if (!(pem != NULL && pem->cert == x) && x != NULL) X509_free(x); return ret; }
void context_init(void) { /* init SSL */ int i; #if SSLEAY_VERSION_NUMBER >= 0x00907000L /* Load all bundled ENGINEs into memory and make them visible */ ENGINE_load_builtin_engines(); /* Register all of them for every algorithm they collectively implement */ ENGINE_register_all_complete(); #endif if(!init_prng()) log(LOG_INFO, "PRNG seeded successfully"); SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); if(options.option.client) { ctx=SSL_CTX_new(SSLv3_client_method()); } else { /* Server mode */ ctx=SSL_CTX_new(SSLv23_server_method()); #ifndef NO_RSA SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); #endif /* NO_RSA */ if(init_dh()) log(LOG_WARNING, "Diffie-Hellman initialization failed"); } if(options.ssl_options) { log(LOG_DEBUG, "Configuration SSL options: 0x%08lX", options.ssl_options); log(LOG_DEBUG, "SSL options set: 0x%08lX", SSL_CTX_set_options(ctx, options.ssl_options)); } #if SSLEAY_VERSION_NUMBER >= 0x00906000L SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif /* OpenSSL-0.9.6 */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); SSL_CTX_set_timeout(ctx, options.session_timeout); if(options.option.cert) { if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) { log(LOG_ERR, "Error reading certificate file: %s", options.cert); sslerror("SSL_CTX_use_certificate_chain_file"); exit(1); } log(LOG_DEBUG, "Certificate: %s", options.cert); log(LOG_DEBUG, "Key file: %s", options.key); #ifdef USE_WIN32 SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); #endif for(i=0; i<3; i++) { #ifdef NO_RSA if(SSL_CTX_use_PrivateKey_file(ctx, options.key, SSL_FILETYPE_PEM)) #else /* NO_RSA */ if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key, SSL_FILETYPE_PEM)) #endif /* NO_RSA */ break; if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT) { sslerror_stack(); /* dump the error stack */ log(LOG_ERR, "Wrong pass phrase: retrying"); continue; } #ifdef NO_RSA sslerror("SSL_CTX_use_PrivateKey_file"); #else /* NO_RSA */ sslerror("SSL_CTX_use_RSAPrivateKey_file"); #endif /* NO_RSA */ exit(1); } if(!SSL_CTX_check_private_key(ctx)) { sslerror("Private key does not match the certificate"); exit(1); } } verify_init(); /* Initialize certificate verification */ SSL_CTX_set_info_callback(ctx, info_callback); if(options.cipher_list) { if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) { sslerror("SSL_CTX_set_cipher_list"); exit(1); } } }
/* Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. */ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { BIO *in; int ret=0; X509 *x=NULL; ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ in=BIO_new(BIO_s_file_internal()); if (in == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB); goto end; } if (BIO_read_filename(in,file) <= 0) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_SYS_LIB); goto end; } x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB); goto end; } ret=SSL_CTX_use_certificate(ctx,x); if (ERR_peek_error() != 0) ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ if (ret) { /* If we could set up our certificate, now proceed to * the CA certificates. */ X509 *ca; int r; unsigned long err; if (ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->extra_certs, X509_free); ctx->extra_certs = NULL; } while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata)) != NULL) { r = SSL_CTX_add_extra_chain_cert(ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /* Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) ERR_clear_error(); else ret = 0; /* some real error */ } end: if (x != NULL) X509_free(x); if (in != NULL) BIO_free(in); return(ret); }
int main(int argc, char *argv[]) { const char *hostport = HOSTPORT; const char *CAfile = CAFILE; char *hostname; char *cp; BIO *out = NULL; char buf[1024 * 10], *p; SSL_CTX *ssl_ctx = NULL; SSL *ssl; BIO *ssl_bio; int i, len, off, ret = EXIT_FAILURE; if (argc > 1) hostport = argv[1]; if (argc > 2) CAfile = argv[2]; hostname = OPENSSL_strdup(hostport); if ((cp = strchr(hostname, ':')) != NULL) *cp = 0; #ifdef WATT32 dbug_init(); sock_init(); #endif ssl_ctx = SSL_CTX_new(TLS_client_method()); /* Enable trust chain verification */ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL); /* Lets make a SSL structure */ ssl = SSL_new(ssl_ctx); SSL_set_connect_state(ssl); /* Enable peername verification */ if (SSL_set1_host(ssl, hostname) <= 0) goto err; /* Use it inside an SSL BIO */ ssl_bio = BIO_new(BIO_f_ssl()); BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); /* Lets use a connect BIO under the SSL BIO */ out = BIO_new(BIO_s_connect()); BIO_set_conn_hostname(out, hostport); BIO_set_nbio(out, 1); out = BIO_push(ssl_bio, out); p = "GET / HTTP/1.0\r\n\r\n"; len = strlen(p); off = 0; for (;;) { i = BIO_write(out, &(p[off]), len); if (i <= 0) { if (BIO_should_retry(out)) { fprintf(stderr, "write DELAY\n"); sleep(1); continue; } else { goto err; } } off += i; len -= i; if (len <= 0) break; } for (;;) { i = BIO_read(out, buf, sizeof(buf)); if (i == 0) break; if (i < 0) { if (BIO_should_retry(out)) { fprintf(stderr, "read DELAY\n"); sleep(1); continue; } goto err; } fwrite(buf, 1, i, stdout); } ret = EXIT_SUCCESS; goto done; err: if (ERR_peek_error() == 0) { /* system call error */ fprintf(stderr, "errno=%d ", errno); perror("error"); } else { ERR_print_errors_fp(stderr); } done: BIO_free_all(out); SSL_CTX_free(ssl_ctx); return ret; }
void ssl_log(server_rec *s, int level, const char *msg, ...) { char tstr[80]; char lstr[20]; char vstr[1024]; char str[1024]; char nstr[2]; int timz; struct tm *t; va_list ap; int add; int i; char *astr; int safe_errno; unsigned long e; SSLSrvConfigRec *sc; char *cpE; char *cpA; /* initialization */ va_start(ap, msg); safe_errno = errno; sc = mySrvConfig(s); /* strip out additional flags */ add = (level & ~SSL_LOG_MASK); level = (level & SSL_LOG_MASK); /* reduce flags when not reasonable in context */ if (add & SSL_ADD_ERRNO && errno == 0) add &= ~SSL_ADD_ERRNO; if (add & SSL_ADD_SSLERR && ERR_peek_error() == 0) add &= ~SSL_ADD_SSLERR; /* we log only levels below, except for errors */ if ( sc->fileLogFile == NULL && !(level & SSL_LOG_ERROR)) return; if ( level > sc->nLogLevel && !(level & SSL_LOG_ERROR)) return; /* determine the time entry string */ if (add & SSL_NO_TIMESTAMP) tstr[0] = NUL; else { t = ap_get_gmtoff(&timz); strftime(tstr, 80, "[%d/%b/%Y %H:%M:%S", t); i = strlen(tstr); ap_snprintf(tstr+i, 80-i, " %05d] ", (unsigned int)getpid()); } /* determine whether newline should be written */ if (add & SSL_NO_NEWLINE) nstr[0] = NUL; else { nstr[0] = '\n'; nstr[1] = NUL; } /* determine level name */ lstr[0] = NUL; if (!(add & SSL_NO_LEVELID)) { for (i = 0; ssl_log_level2string[i].nLevel != 0; i++) { if (ssl_log_level2string[i].nLevel == level) { ap_snprintf(lstr, sizeof(lstr), "[%s]", ssl_log_level2string[i].szLevel); break; } } for (i = strlen(lstr); i <= 7; i++) lstr[i] = ' '; lstr[i] = NUL; } /* create custom message */ ap_vsnprintf(vstr, sizeof(vstr), msg, ap); /* write out SSLog message */ if ((add & SSL_ADD_ERRNO) && (add & SSL_ADD_SSLERR)) astr = " (System and " SSL_LIBRARY_NAME " library errors follow)"; else if (add & SSL_ADD_ERRNO) astr = " (System error follows)"; else if (add & SSL_ADD_SSLERR) astr = " (" SSL_LIBRARY_NAME " library error follows)"; else astr = ""; if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { ap_snprintf(str, sizeof(str), "%s%s%s%s%s", tstr, lstr, vstr, astr, nstr); fprintf(sc->fileLogFile, "%s", str); } if (level & SSL_LOG_ERROR) ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, "mod_ssl: %s%s", vstr, astr); /* write out additional attachment messages */ if (add & SSL_ADD_ERRNO) { if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { ap_snprintf(str, sizeof(str), "%s%sSystem: %s (errno: %d)%s", tstr, lstr, strerror(safe_errno), safe_errno, nstr); fprintf(sc->fileLogFile, "%s", str); } if (level & SSL_LOG_ERROR) ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, "System: %s (errno: %d)", strerror(safe_errno), safe_errno); } if (add & SSL_ADD_SSLERR) { while ((e = ERR_get_error())) { cpE = ERR_error_string(e, NULL); cpA = ssl_log_annotation(cpE); if (level <= sc->nLogLevel && sc->fileLogFile != NULL) { ap_snprintf(str, sizeof(str), "%s%s%s: %s%s%s%s%s", tstr, lstr, SSL_LIBRARY_NAME, cpE, cpA != NULL ? " [Hint: " : "", cpA != NULL ? cpA : "", cpA != NULL ? "]" : "", nstr); fprintf(sc->fileLogFile, "%s", str); } if (level & SSL_LOG_ERROR) ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, "%s: %s%s%s%s", SSL_LIBRARY_NAME, cpE, cpA != NULL ? " [Hint: " : "", cpA != NULL ? cpA : "", cpA != NULL ? "]" : ""); } } /* make sure the next log starts from a clean base */ /* ERR_clear_error(); */ /* cleanup and return */ if (sc->fileLogFile != NULL) fflush(sc->fileLogFile); errno = safe_errno; va_end(ap); return; }
bool TLS_SOCKET_CLASS::writeBinary(const BYTE *buffer_ptr, UINT length) // DESCRIPTION : Write given data to socket. // PRECONDITIONS : // POSTCONDITIONS : // EXCEPTIONS : // NOTES : //<<=========================================================================== { int written_bytes = 0; int readFileDesc; int writeFileDesc; struct fd_set readFds; struct fd_set writeFds; bool waitOnWrite; int timeoutRemaining; // the amount of time left in the timeout period struct timeval tv = {1, 0}; // always timeout in 1 second if (terminatingM) { if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating. Cannot write."); } // return - in process of termintating return false; } if (loggerM_ptr) { loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::write(%d bytes)", length); } if (!connectedM) { if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Not connected to peer - can't write data"); } return false; } // get the file descriptors and set up the file descriptor sets for select() readFileDesc = SSL_get_rfd(sslM_ptr); if (readFileDesc == -1) { openSslError("getting read socket file descriptor"); return false; } writeFileDesc = SSL_get_wfd(sslM_ptr); if (writeFileDesc == -1) { openSslError("getting write socket file descriptor"); return false; } waitOnWrite = true; timeoutRemaining = socketTimeoutM; // write the buffer contents to socket while (written_bytes < (int) length) { int bytes; int sel; if (waitOnWrite) { FD_ZERO(&writeFds); FD_SET(writeFileDesc, &writeFds); // wait for something to write sel = select(writeFileDesc + 1, NULL, &writeFds, NULL, &tv); } else { FD_ZERO(&readFds); FD_SET(readFileDesc, &readFds); // wait for something to read sel = select(readFileDesc + 1, &readFds, NULL, NULL, &tv); } if (terminatingM) { return false; } waitOnWrite = true; if (sel == 1) { // data read to write (or possibly read - but use the same call) bytes = SSL_write(sslM_ptr, (char *)(buffer_ptr + written_bytes), (length - written_bytes)); if (bytes > 0) { // wrote some data written_bytes += bytes; timeoutRemaining = socketTimeoutM; // reset the timeout } else if (bytes == 0) { // socket closed if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Secure connection closed during socket write"); } return false; } else { // operation did not complete, see what happened int err = SSL_get_error(sslM_ptr, bytes); if (err == SSL_ERROR_WANT_READ) { // need to wait for data to be available for reading, and then retry the same operation waitOnWrite = false; timeoutRemaining = socketTimeoutM; // reset the timeout } if (err == SSL_ERROR_WANT_WRITE) { // need to wait for the write file descriptor to be able to write and then try again timeoutRemaining = socketTimeoutM; // reset the timeout } else { // an error occured if ((err == SSL_ERROR_SYSCALL) && (ERR_peek_error() == 0) && (bytes == -1)) { // an error in the system call occured openSslError("writing to secure socket"); if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_ERROR)) { loggerM_ptr->text(LOG_NONE, 1, " write() error code = %d", WSAGetLastError()); } } else { openSslError("reading from secure socket"); } return false; } } } else if (sel == 0) { // no data at the end of the timeout if (--timeoutRemaining > 0) { // still have time left on the timeout, go back and wait some more } else { // timeout expired if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Connection timed-out while waiting to send data"); } return false; } } else if (sel == SOCKET_ERROR) { // socket error if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Error waiting to send data (error code %d)", WSAGetLastError()); } return false; } else { // unknown error if (loggerM_ptr) { loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Unknown error while waiting to send data (select returned %d)", sel); } return false; } } return (written_bytes == (int) length) ? true : false; }