CERT *ssl_cert_dup(CERT *cert) { CERT *ret = OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } memset(ret, 0, sizeof(CERT)); ret->mask_k = cert->mask_k; ret->mask_a = cert->mask_a; if (cert->dh_tmp != NULL) { ret->dh_tmp = DHparams_dup(cert->dh_tmp); if (ret->dh_tmp == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); goto err; } } ret->dh_tmp_cb = cert->dh_tmp_cb; if (cert->x509 != NULL) { ret->x509 = X509_up_ref(cert->x509); } if (cert->privatekey != NULL) { ret->privatekey = EVP_PKEY_up_ref(cert->privatekey); } if (cert->chain) { ret->chain = X509_chain_up_ref(cert->chain); if (!ret->chain) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } } ret->key_method = cert->key_method; ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; if (cert->verify_store != NULL) { X509_STORE_up_ref(cert->verify_store); ret->verify_store = cert->verify_store; } return ret; err: ssl_cert_free(ret); return NULL; }
CERT *ssl_cert_dup(CERT *cert) { CERT *ret = OPENSSL_zalloc(sizeof(*ret)); int i; if (ret == NULL) { SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); return NULL; } ret->references = 1; ret->key = &ret->pkeys[cert->key - cert->pkeys]; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } #ifndef OPENSSL_NO_DH if (cert->dh_tmp != NULL) { ret->dh_tmp = cert->dh_tmp; EVP_PKEY_up_ref(ret->dh_tmp); } ret->dh_tmp_cb = cert->dh_tmp_cb; ret->dh_tmp_auto = cert->dh_tmp_auto; #endif for (i = 0; i < SSL_PKEY_NUM; i++) { CERT_PKEY *cpk = cert->pkeys + i; CERT_PKEY *rpk = ret->pkeys + i; if (cpk->x509 != NULL) { rpk->x509 = cpk->x509; X509_up_ref(rpk->x509); } if (cpk->privatekey != NULL) { rpk->privatekey = cpk->privatekey; EVP_PKEY_up_ref(cpk->privatekey); } if (cpk->chain) { rpk->chain = X509_chain_up_ref(cpk->chain); if (!rpk->chain) { SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); goto err; } } if (cert->pkeys[i].serverinfo != NULL) { /* Just copy everything. */ ret->pkeys[i].serverinfo = OPENSSL_malloc(cert->pkeys[i].serverinfo_length); if (ret->pkeys[i].serverinfo == NULL) { SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); goto err; } ret->pkeys[i].serverinfo_length = cert->pkeys[i].serverinfo_length; memcpy(ret->pkeys[i].serverinfo, cert->pkeys[i].serverinfo, cert->pkeys[i].serverinfo_length); } } /* Configured sigalgs copied across */ if (cert->conf_sigalgs) { ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen * sizeof(*cert->conf_sigalgs)); if (ret->conf_sigalgs == NULL) goto err; memcpy(ret->conf_sigalgs, cert->conf_sigalgs, cert->conf_sigalgslen * sizeof(*cert->conf_sigalgs)); ret->conf_sigalgslen = cert->conf_sigalgslen; } else ret->conf_sigalgs = NULL; if (cert->client_sigalgs) { ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen * sizeof(*cert->client_sigalgs)); if (ret->client_sigalgs == NULL) goto err; memcpy(ret->client_sigalgs, cert->client_sigalgs, cert->client_sigalgslen * sizeof(*cert->client_sigalgs)); ret->client_sigalgslen = cert->client_sigalgslen; } else ret->client_sigalgs = NULL; /* Shared sigalgs also NULL */ ret->shared_sigalgs = NULL; /* Copy any custom client certificate types */ if (cert->ctype) { ret->ctype = OPENSSL_memdup(cert->ctype, cert->ctype_len); if (ret->ctype == NULL) goto err; ret->ctype_len = cert->ctype_len; } ret->cert_flags = cert->cert_flags; ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; if (cert->verify_store) { X509_STORE_up_ref(cert->verify_store); ret->verify_store = cert->verify_store; } if (cert->chain_store) { X509_STORE_up_ref(cert->chain_store); ret->chain_store = cert->chain_store; } ret->sec_cb = cert->sec_cb; ret->sec_level = cert->sec_level; ret->sec_ex = cert->sec_ex; if (!custom_exts_copy(&ret->custext, &cert->custext)) goto err; #ifndef OPENSSL_NO_PSK if (cert->psk_identity_hint) { ret->psk_identity_hint = OPENSSL_strdup(cert->psk_identity_hint); if (ret->psk_identity_hint == NULL) goto err; } #endif return ret; err: ssl_cert_free(ret); return NULL; }
static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_REC *server) { GIOSSLChannel *chan; GIOChannel *gchan; int fd; SSL *ssl; SSL_CTX *ctx = NULL; const char *mycert = server->connrec->tls_cert; const char *mypkey = server->connrec->tls_pkey; const char *mypass = server->connrec->tls_pass; const char *cafile = server->connrec->tls_cafile; const char *capath = server->connrec->tls_capath; const char *ciphers = server->connrec->tls_ciphers; gboolean verify = server->connrec->tls_verify; g_return_val_if_fail(handle != NULL, NULL); if(!ssl_inited && !irssi_ssl_init()) return NULL; if(!(fd = g_io_channel_unix_get_fd(handle))) return NULL; ERR_clear_error(); ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { g_error("Could not allocate memory for SSL context"); return NULL; } SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); SSL_CTX_set_default_passwd_cb(ctx, get_pem_password_callback); SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)mypass); if (ciphers != NULL && ciphers[0] != '\0') { if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) g_warning("No valid SSL cipher suite could be selected"); } if (mycert && *mycert) { char *scert = NULL, *spkey = NULL; FILE *fp; scert = convert_home(mycert); if (mypkey && *mypkey) spkey = convert_home(mypkey); if ((fp = fopen(scert, "r"))) { X509 *cert; /* Let's parse the certificate by hand instead of using * SSL_CTX_use_certificate_file so that we can validate * some parts of it. */ cert = PEM_read_X509(fp, NULL, get_pem_password_callback, (void *)mypass); if (cert != NULL) { /* Only the expiration date is checked right now */ if (X509_cmp_current_time(X509_get_notAfter(cert)) <= 0 || X509_cmp_current_time(X509_get_notBefore(cert)) >= 0) g_warning("The client certificate is expired"); ERR_clear_error(); if (! SSL_CTX_use_certificate(ctx, cert)) g_warning("Loading of client certificate '%s' failed: %s", mycert, ERR_reason_error_string(ERR_get_error())); else if (! SSL_CTX_use_PrivateKey_file(ctx, spkey ? spkey : scert, SSL_FILETYPE_PEM)) g_warning("Loading of private key '%s' failed: %s", mypkey ? mypkey : mycert, ERR_reason_error_string(ERR_get_error())); else if (! SSL_CTX_check_private_key(ctx)) g_warning("Private key does not match the certificate"); X509_free(cert); } else g_warning("Loading of client certificate '%s' failed: %s", mycert, ERR_reason_error_string(ERR_get_error())); fclose(fp); } else g_warning("Could not find client certificate '%s'", scert); g_free(scert); g_free(spkey); } if ((cafile && *cafile) || (capath && *capath)) { char *scafile = NULL; char *scapath = NULL; if (cafile && *cafile) scafile = convert_home(cafile); if (capath && *capath) scapath = convert_home(capath); if (! SSL_CTX_load_verify_locations(ctx, scafile, scapath)) { g_warning("Could not load CA list for verifying TLS server certificate"); g_free(scafile); g_free(scapath); SSL_CTX_free(ctx); return NULL; } g_free(scafile); g_free(scapath); verify = TRUE; } else if (store != NULL) { /* Make sure to increment the refcount every time the store is * used, that's essential not to get it free'd by OpenSSL when * the SSL_CTX is destroyed. */ X509_STORE_up_ref(store); SSL_CTX_set_cert_store(ctx, store); } if(!(ssl = SSL_new(ctx))) { g_warning("Failed to allocate SSL structure"); SSL_CTX_free(ctx); return NULL; } if(!SSL_set_fd(ssl, fd)) { g_warning("Failed to associate socket to SSL stream"); SSL_free(ssl); SSL_CTX_free(ctx); return NULL; } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(ssl, server->connrec->address); #endif SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); chan = g_new0(GIOSSLChannel, 1); chan->fd = fd; chan->giochan = handle; chan->ssl = ssl; chan->ctx = ctx; chan->server = server; chan->port = port; chan->verify = verify; gchan = (GIOChannel *)chan; gchan->funcs = &irssi_ssl_channel_funcs; g_io_channel_init(gchan); gchan->is_readable = gchan->is_writeable = TRUE; gchan->use_buffer = FALSE; return gchan; }