int tls_handshake(struct tls *ctx) { int rv = -1; tls_error_clear(&ctx->error); if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) { tls_set_errorx(ctx, "invalid operation for context"); goto out; } if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) { tls_set_errorx(ctx, "handshake already completed"); goto out; } if ((ctx->flags & TLS_CLIENT) != 0) rv = tls_handshake_client(ctx); else if ((ctx->flags & TLS_SERVER_CONN) != 0) rv = tls_handshake_server(ctx); if (rv == 0) { ctx->ssl_peer_cert = SSL_get_peer_certificate(ctx->ssl_conn); ctx->ssl_peer_chain = SSL_get_peer_cert_chain(ctx->ssl_conn); if (tls_conninfo_populate(ctx) == -1) rv = -1; if (ctx->ocsp == NULL) ctx->ocsp = tls_ocsp_setup_from_peer(ctx); } out: /* Prevent callers from performing incorrect error handling */ errno = 0; return (rv); }
/* * call-seq: * ssl.peer_cert_chain => [cert, ...] or nil */ static VALUE ossl_ssl_get_peer_cert_chain(VALUE self) { SSL *ssl; STACK_OF(X509) *chain; X509 *cert; VALUE ary; int i, num; Data_Get_Struct(self, SSL, ssl); if(!ssl){ rb_warning("SSL session is not started yet."); return Qnil; } chain = SSL_get_peer_cert_chain(ssl); if(!chain) return Qnil; num = sk_X509_num(chain); ary = rb_ary_new2(num); for (i = 0; i < num; i++){ cert = sk_X509_value(chain, i); rb_ary_push(ary, ossl_x509_new(cert)); } return ary; }
void describeCertificates(SSL* ssl, bool isServer) { // Resumed sessions don't necessarily have chains (not included in session ticket) X509 *cert = SSL_get_peer_certificate(ssl); if (cert == NULL) { fprintf(stderr,"No peer certificates.\n"); } else { fprintf(stderr,"Peer certificates:\n"); describeCertificate(0, cert); X509_free(cert); STACK_OF(X509) *certs = SSL_get_peer_cert_chain(ssl); // We don't have to free this apparently // Cached sessions may not have a chain if (certs != NULL) { // On server, chain doesn't include client certificate if (isServer) { for (int i = 0; i < sk_X509_num(certs); i++) { describeCertificate(i+1, sk_X509_value(certs,i)); } } else { for (int i = 1; i < sk_X509_num(certs); i++) { describeCertificate(i, sk_X509_value(certs,i)); } } } long verify_result = SSL_get_verify_result(ssl); if (verify_result == X509_V_OK) { fprintf(stderr,"Certificate OK\n"); } else { // See 'man verify(1SSL)' for meanings of the codes fprintf(stderr,"Verification error %ld\n", verify_result); ERR_print_errors_fp(stderr); } } }
/** * Return the chain of certificate of the peer. */ static int meth_getpeerchain(lua_State *L) { int i; int idx = 1; int n_certs; X509 *cert; STACK_OF(X509) *certs; p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); if (ssl->state != LSEC_STATE_CONNECTED) { lua_pushnil(L); lua_pushstring(L, "closed"); return 2; } lua_newtable(L); if (ssl->ssl->server) { lsec_pushx509(L, SSL_get_peer_certificate(ssl->ssl)); lua_rawseti(L, -2, idx++); } certs = SSL_get_peer_cert_chain(ssl->ssl); n_certs = sk_X509_num(certs); for (i = 0; i < n_certs; i++) { cert = sk_X509_value(certs, i); /* Increment the reference counting of the object. */ /* See SSL_get_peer_certificate() source code. */ CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); lsec_pushx509(L, cert); lua_rawseti(L, -2, idx++); } return 1; }
static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer) { CryptoCert cert; X509* remote_cert; STACK_OF(X509) *chain; if (peer) remote_cert = SSL_get_peer_certificate(tls->ssl); else remote_cert = X509_dup(SSL_get_certificate(tls->ssl)); if (!remote_cert) { WLog_ERR(TAG, "failed to get the server TLS certificate"); return NULL; } cert = malloc(sizeof(*cert)); if (!cert) { X509_free(remote_cert); return NULL; } cert->px509 = remote_cert; /* Get the peer's chain. If it does not exist, we're setting NULL (clean data either way) */ chain = SSL_get_peer_cert_chain(tls->ssl); cert->px509chain = chain; return cert; }
static PyObject * ssl_Connection_get_peer_cert_chain(ssl_ConnectionObj *self, PyObject *args) { STACK_OF(X509) *sk; PyObject *chain; crypto_X509Obj *cert; Py_ssize_t i; if (!PyArg_ParseTuple(args, ":get_peer_cert_chain")) { return NULL; } sk = SSL_get_peer_cert_chain(self->ssl); if (sk != NULL) { chain = PyList_New(sk_X509_num(sk)); for (i = 0; i < sk_X509_num(sk); i++) { cert = new_x509(sk_X509_value(sk, i), 1); if (!cert) { /* XXX Untested */ Py_DECREF(chain); return NULL; } CRYPTO_add(&cert->x509->references, 1, CRYPTO_LOCK_X509); PyList_SET_ITEM(chain, i, (PyObject *)cert); } return chain; } else { Py_INCREF(Py_None); return Py_None; } }
static int ssl_check_certificate (CONNECTION *conn, sslsockdata *data) { int i, preauthrc, chain_len; STACK_OF(X509) *chain; X509 *cert; if ((preauthrc = ssl_check_preauth (data->cert, conn->account.host)) > 0) return preauthrc; chain = SSL_get_peer_cert_chain (data->ssl); chain_len = sk_X509_num (chain); /* negative preauthrc means the certificate won't be accepted without * manual override. */ if (preauthrc < 0 || !chain || (chain_len <= 1)) return interactive_check_cert (data->cert, 0, 0); /* check the chain from root to peer. */ for (i = chain_len-1; i >= 0; i--) { cert = sk_X509_value (chain, i); /* if the certificate validates or is manually accepted, then add it to * the trusted set and recheck the peer certificate */ if (ssl_check_preauth (cert, NULL) || interactive_check_cert (cert, i, chain_len)) { ssl_cache_trusted_cert (cert); if (ssl_check_preauth (data->cert, conn->account.host)) return 1; } } return 0; }
/* * Returns: 0 if successfully matching certificate to TLSA record bytes * -1 if there was no match */ int ca_constraint(const SSL *con, const X509 *tlsa_cert, int usage) { STACK_OF(X509) *cert_chain = NULL; cert_chain = SSL_get_peer_cert_chain(con); BIO_printf(b_err, "DANE ca_constraint() chain of %d length\n", sk_X509_num(cert_chain)); int ret_val; ret_val = 0; if (cert_chain != NULL) { int i; for (i = 0; i < sk_X509_num(cert_chain); i++) { BIO_printf(b_err, "DANE ca_constraint() cert %d of %d.\n", i, sk_X509_num(cert_chain)); /* BIO_printf(b_err, "DANE CXN Certificate\n"); PEM_write_bio_X509(b_err, sk_X509_value(cert_chain, i)); BIO_printf(b_err, "DANE TLSA Certificate\n"); PEM_write_bio_X509(b_err, tlsa_cert); */ if (X509_cmp(tlsa_cert, sk_X509_value(cert_chain, i)) < 0) { ret_val = -1; BIO_printf(b_err, "DANE ca_constraint() certificates didn't match\n"); } else { BIO_printf(b_err, "DANE ca_constraint() certificates matches\n"); if (usage == 0) return 0; /* For this to be a trust anchor, the following characteristics applies: * 1. Issuer name is the same as Subject name * 2. Either or both * a) the Key Usage field is set to keyCertSign (KU_KEY_CERT_SIGN) * b) the basicConstraints field has the attribute cA set to True (EXFLAG_CA) */ X509_NAME *issuer_name, *subject_name; issuer_name = X509_get_issuer_name(tlsa_cert); subject_name = X509_get_subject_name(tlsa_cert); if (X509_name_cmp(issuer_name, subject_name) == 0) { BIO_printf(b_err, "DANE issuer == subject\n"); if (tlsa_cert->ex_flags & EXFLAG_CA) { BIO_printf(b_err, "DANE ca_constraint() EXFLAG_CA set\n"); return 0; } /* Left unimplemented since I don't have a CA certificate to work with.*/ int ext_count, j; ext_count = X509_get_ext_count(tlsa_cert); BIO_printf(b_err, "DANE ca_constraint() %d certificate extensions\n"); } else { return 0; } } } } return ret_val; }
static int openssl_ssl_peer(lua_State*L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); X509* x = SSL_get_peer_certificate(s); STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s); PUSH_OBJECT(x, "openssl.x509"); if (sk) { sk = openssl_sk_x509_dup(sk); PUSH_OBJECT(sk, "openssl.stack_of_x509"); return 2; } return 1; }
bool SSLSocket::verifyKeyprint(const string& expKP, bool allowUntrusted) noexcept { if (!ssl) return true; if (expKP.empty() || expKP.find("/") == string::npos) return allowUntrusted; verifyData.reset(new CryptoManager::SSLVerifyData(allowUntrusted, expKP)); SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, verifyData.get()); SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); X509_STORE* store = X509_STORE_new(); bool result = false; int err = SSL_get_verify_result(ssl); if (ssl_ctx && store) { X509_STORE_CTX* vrfy_ctx = X509_STORE_CTX_new(); X509* cert = SSL_get_peer_certificate(ssl); if (vrfy_ctx && cert && X509_STORE_CTX_init(vrfy_ctx, store, cert, SSL_get_peer_cert_chain(ssl))) { X509_STORE_CTX_set_ex_data(vrfy_ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), ssl); X509_STORE_CTX_set_verify_cb(vrfy_ctx, SSL_CTX_get_verify_callback(ssl_ctx)); int verify_result = 0; if ((verify_result = X509_verify_cert(vrfy_ctx)) >= 0) { err = X509_STORE_CTX_get_error(vrfy_ctx); // Watch out for weird library errors that might not set the context error code if (err == X509_V_OK && verify_result <= 0) err = X509_V_ERR_UNSPECIFIED; // This is for people who don't restart their clients and have low expiration time on their cert result = (err == X509_V_OK || err == X509_V_ERR_CERT_HAS_EXPIRED) || (allowUntrusted && err != X509_V_ERR_APPLICATION_VERIFICATION); } } if (cert) X509_free(cert); if (vrfy_ctx) X509_STORE_CTX_free(vrfy_ctx); if (store) X509_STORE_free(store); } // KeyPrint is a strong indicator of trust SSL_set_verify_result(ssl, err); return result; }
/** * Return the nth certificate of the peer's chain. */ static int meth_getpeercertificate(lua_State *L) { int n; X509 *cert; STACK_OF(X509) *certs; p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); if (ssl->state != LSEC_STATE_CONNECTED) { lua_pushnil(L); lua_pushstring(L, "closed"); return 2; } /* Default to the first cert */ n = luaL_optint(L, 2, 1); /* This function is 1-based, but OpenSSL is 0-based */ --n; if (n < 0) { lua_pushnil(L); lua_pushliteral(L, "invalid certificate index"); return 2; } if (n == 0) { cert = SSL_get_peer_certificate(ssl->ssl); if (cert) lsec_pushx509(L, cert); else lua_pushnil(L); return 1; } /* In a server-context, the stack doesn't contain the peer cert, * so adjust accordingly. */ if (ssl->ssl->server) --n; certs = SSL_get_peer_cert_chain(ssl->ssl); if (n >= sk_X509_num(certs)) { lua_pushnil(L); return 1; } cert = sk_X509_value(certs, n); /* Increment the reference counting of the object. */ /* See SSL_get_peer_certificate() source code. */ CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); lsec_pushx509(L, cert); return 1; }
static void win_new_chain(CLI *c) { BIO *bio; int i, len; X509 *peer=NULL; STACK_OF(X509) *sk; char *chain; if(c->opt->chain) /* already cached */ return; /* this race condition is safe to ignore */ bio=BIO_new(BIO_s_mem()); if(!bio) return; sk=SSL_get_peer_cert_chain(c->ssl); for(i=0; sk && i<sk_X509_num(sk); i++) { peer=sk_X509_value(sk, i); PEM_write_bio_X509(bio, peer); } if(!sk || !c->opt->option.client) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { PEM_write_bio_X509(bio, peer); X509_free(peer); } } len=BIO_pending(bio); if(len<=0) { s_log(LOG_INFO, "No peer certificate received"); BIO_free(bio); return; } chain=str_alloc(len+1); len=BIO_read(bio, chain, len); if(len<0) { s_log(LOG_ERR, "BIO_read failed"); BIO_free(bio); str_free(chain); return; } chain[len]='\0'; BIO_free(bio); str_detach(chain); /* to prevent automatic deallocation of cached value */ c->opt->chain=chain; /* this race condition is safe to ignore */ PostMessage(hwnd, WM_NEW_CHAIN, c->opt->section_number, 0); s_log(LOG_DEBUG, "Peer certificate was cached (%d bytes)", len); }
Wt::WSslInfo *Request::sslInfo() const { #ifdef HTTP_WITH_SSL if (!ssl) return nullptr; X509 *x509 = SSL_get_peer_certificate(ssl); if (x509) { Wt::WSslCertificate clientCert = Wt::Ssl::x509ToWSslCertificate(x509); X509_free(x509); std::vector<Wt::WSslCertificate> clientCertChain; STACK_OF(X509) *certChain = SSL_get_peer_cert_chain(ssl); if (certChain) { for (int i = 0; i < sk_X509_num(certChain); ++i) { X509 *x509_i = sk_X509_value(certChain, i); clientCertChain.push_back(Wt::Ssl::x509ToWSslCertificate(x509_i)); } } Wt::ValidationState state = Wt::ValidationState::Invalid; std::string info; long SSL_state = SSL_get_verify_result(ssl); if (SSL_state == X509_V_OK) { state = Wt::ValidationState::Valid; } else { state = Wt::ValidationState::Invalid; info = X509_verify_cert_error_string(SSL_state); } Wt::WValidator::Result clientVerificationResult(state, info); return new Wt::WSslInfo(clientCert, clientCertChain, clientVerificationResult); } #endif return nullptr; }
bool SSLSocket::verifyKeyprint(const string& expKP, bool allowUntrusted) noexcept { if(!ssl) return true; if(expKP.empty() || expKP.find("/") == string::npos) return allowUntrusted; verifyData.reset(new CryptoManager::SSLVerifyData(allowUntrusted, expKP)); SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, verifyData.get()); SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); X509_STORE* store = SSL_CTX_get_cert_store(ctx); bool result = allowUntrusted; int err = SSL_get_verify_result(ssl); if(ssl_ctx && store) { X509_STORE_CTX* vrfy_ctx = X509_STORE_CTX_new(); X509* cert = SSL_get_peer_certificate(ssl); if(vrfy_ctx && cert && X509_STORE_CTX_init(vrfy_ctx, store, cert, SSL_get_peer_cert_chain(ssl))) { auto vrfy_cb = SSL_CTX_get_verify_callback(ssl_ctx); X509_STORE_CTX_set_ex_data(vrfy_ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), ssl); X509_STORE_CTX_set_verify_cb(vrfy_ctx, vrfy_cb); if(X509_verify_cert(vrfy_ctx) >= 0) { err = X509_STORE_CTX_get_error(vrfy_ctx); // This is for people who don't restart their clients and have low expiration time on their cert result = (err == X509_V_OK) || (err == X509_V_ERR_CERT_HAS_EXPIRED); } } if(cert) X509_free(cert); if(vrfy_ctx) X509_STORE_CTX_free(vrfy_ctx); } // KeyPrint is a strong indicator of trust (TODO: check that this KeyPrint is mediated by a trusted hub) SSL_set_verify_result(ssl, err); return result; }
static void sl_ssl_get_cert(void){ SLssl_Type *ssl; SLang_MMT_Type *sslmmt; STACK_OF(X509) *cert; unsigned char **buf; SLang_BString_Type **certout; SLang_Array_Type *arr; SLindex_Type nelem; int len,i; if (NULL==(sslmmt=SLang_pop_mmt(SLssl_Type_Id))) return; ssl=(SLssl_Type *)SLang_object_from_mmt(sslmmt); cert=SSL_get_peer_cert_chain((SSL *)ssl->ssl); if (cert==NULL) return NULL; nelem=(SLindex_Type)sk_X509_num(cert); // now we have chain of certs, create array of pointers and the // array to hold them buf = (unsigned char **)malloc(nelem*sizeof(unsigned char *)); arr = SLang_create_array(SLANG_BSTRING_TYPE,0,NULL,&nelem,1); // array data structure is of bstring type certout = (SLang_BString_Type **)arr->data; for (i=0;i<nelem;i++){ buf[i] = NULL; len = i2d_X509(sk_X509_value(cert,i), &(buf[i])); certout[i] = SLbstring_create(buf[i],len); } SLang_push_array(arr,1); // free the X509 stack sk_X509_pop_free(cert,X509_free); }
carray * mailstream_low_ssl_get_certificate_chain(mailstream_low * s) { #ifdef USE_SSL #ifndef USE_GNUTLS STACK_OF(X509) * skx; struct mailstream_ssl_data * ssl_data; carray * result; int skpos; ssl_data = (struct mailstream_ssl_data *) s->data; if (!(skx = SSL_get_peer_cert_chain(ssl_data->ssl_conn))) { return NULL; } result = carray_new(4); for(skpos = 0 ; skpos < sk_num(skx) ; skpos ++) { X509 * x = (X509 *) sk_value(skx, skpos); unsigned char * p; MMAPString * str; int length = i2d_X509(x, NULL); str = mmap_string_sized_new(length); p = (unsigned char *) str->str; str->len = length; i2d_X509(x, &p); carray_add(result, str, NULL); } return result; #else /* TODO: GnuTLS implementation */ return NULL; #endif #else return NULL; #endif }
/* Return a PEM-formatted buffer containing the peer's certificate chain. * * NULL is returned if there is no certificate chain, or if memory allocation fails. */ char *async_ssl__pem_peer_certificate_chain(const SSL *con) { STACK_OF(X509) *cert_stack = NULL; BIO *bio = NULL; char *certs = NULL; int i = 0, pending_bytes = 0; /* [cert_stack] is not to be freed; [SSL_get_peer_cert_chain] simply returns an * internal pointer and no reference count is incremented. */ if ((cert_stack = SSL_get_peer_cert_chain(con)) == NULL) { return NULL; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { return NULL; } for (i = 0; i < sk_X509_num(cert_stack); i++) { if ((PEM_write_bio_X509(bio, sk_X509_value(cert_stack, i))) == 0) { goto cleanup; } } pending_bytes = BIO_ctrl_pending(bio); if ((certs = malloc((pending_bytes + 1) * sizeof(char))) == NULL) { goto cleanup; } if ((BIO_read(bio, certs, pending_bytes)) < pending_bytes) { free(certs); goto cleanup; } certs[pending_bytes] = '\0'; cleanup: BIO_set_close(bio, BIO_CLOSE); BIO_free(bio); return certs; }
static int verifypeer(const struct tls_info *info, SSL *ssl) { X509 *x=NULL; X509_NAME *subj=NULL; int nentries, j; char domain[256]; char *p; char errmsg[1000]; if (!info->peer_verify_domain) return (1); if (info->isserver) { x=SSL_get_peer_certificate(ssl); if (x) subj=X509_get_subject_name(x); } else { STACK_OF(X509) *peer_cert_chain=SSL_get_peer_cert_chain(ssl); if (peer_cert_chain && peer_cert_chain->stack.num > 0) { X509 *xx=(X509 *)peer_cert_chain->stack.data[0]; if (xx) subj=X509_get_subject_name(xx); } } nentries=0; if (subj) nentries=X509_NAME_entry_count(subj); domain[0]=0; for (j=0; j<nentries; j++) { const char *obj_name; X509_NAME_ENTRY *e; ASN1_OBJECT *o; ASN1_STRING *d; int dlen; unsigned char *ddata; e=X509_NAME_get_entry(subj, j); if (!e) continue; o=X509_NAME_ENTRY_get_object(e); d=X509_NAME_ENTRY_get_data(e); if (!o || !d) continue; obj_name=OBJ_nid2sn(OBJ_obj2nid(o)); dlen=ASN1_STRING_length(d); ddata=ASN1_STRING_data(d); if (strcasecmp(obj_name, "CN") == 0) { if (dlen >= sizeof(domain)-1) dlen=sizeof(domain)-1; memcpy(domain, ddata, dlen); domain[dlen]=0; } } if (x) X509_free(x); p=domain; if (*p == '*') { int pl, l; pl=strlen(++p); l=strlen(info->peer_verify_domain); if (*p == '.' && pl <= l && strcasecmp(info->peer_verify_domain+l-pl, p) == 0) return (1); } else if (strcasecmp(info->peer_verify_domain, p) == 0) return (1); strcpy(errmsg, "couriertls: Mismatched SSL certificate: CN="); strcat(errmsg, domain); strcat(errmsg, " (expected "); strncat(errmsg, info->peer_verify_domain, 256); strcat(errmsg, ")"); (*info->tls_err_msg)(errmsg, info->app_data); return (0); }
static int do_ca_cert_bootstrap(struct stream *stream) { struct ssl_stream *sslv = ssl_stream_cast(stream); STACK_OF(X509) *chain; X509 *cert; FILE *file; int error; int fd; chain = SSL_get_peer_cert_chain(sslv->ssl); if (!chain || !sk_X509_num(chain)) { VLOG_ERR("could not bootstrap CA cert: no certificate presented by " "peer"); return EPROTO; } cert = sk_X509_value(chain, sk_X509_num(chain) - 1); /* Check that 'cert' is self-signed. Otherwise it is not a CA * certificate and we should not attempt to use it as one. */ error = X509_check_issued(cert, cert); if (error) { VLOG_ERR("could not bootstrap CA cert: obtained certificate is " "not self-signed (%s)", X509_verify_cert_error_string(error)); if (sk_X509_num(chain) < 2) { VLOG_ERR("only one certificate was received, so probably the peer " "is not configured to send its CA certificate"); } return EPROTO; } fd = open(ca_cert.file_name, O_CREAT | O_EXCL | O_WRONLY, 0444); if (fd < 0) { if (errno == EEXIST) { VLOG_INFO_RL(&rl, "reading CA cert %s created by another process", ca_cert.file_name); stream_ssl_set_ca_cert_file__(ca_cert.file_name, true, true); return EPROTO; } else { VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s", ca_cert.file_name, ovs_strerror(errno)); return errno; } } file = fdopen(fd, "w"); if (!file) { error = errno; VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s", ovs_strerror(error)); unlink(ca_cert.file_name); return error; } if (!PEM_write_X509(file, cert)) { VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: " "%s", ca_cert.file_name, ERR_error_string(ERR_get_error(), NULL)); fclose(file); unlink(ca_cert.file_name); return EIO; } if (fclose(file)) { error = errno; VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s", ca_cert.file_name, ovs_strerror(error)); unlink(ca_cert.file_name); return error; } VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert.file_name); log_ca_cert(ca_cert.file_name, cert); bootstrap_ca_cert = false; ca_cert.read = true; /* SSL_CTX_add_client_CA makes a copy of cert's relevant data. */ SSL_CTX_add_client_CA(ctx, cert); SSL_CTX_set_cert_store(ctx, X509_STORE_new()); if (SSL_CTX_load_verify_locations(ctx, ca_cert.file_name, NULL) != 1) { VLOG_ERR("SSL_CTX_load_verify_locations: %s", ERR_error_string(ERR_get_error(), NULL)); return EPROTO; } VLOG_INFO("killing successful connection to retry using CA cert"); return EPROTO; }
carray * mailstream_low_ssl_get_certificate_chain(mailstream_low * s) { #ifdef USE_SSL struct mailstream_ssl_data * ssl_data; carray * result; int skpos; #ifndef USE_GNUTLS STACK_OF(X509) * skx; ssl_data = (struct mailstream_ssl_data *) s->data; if (!(skx = SSL_get_peer_cert_chain(ssl_data->ssl_conn))) { return NULL; } result = carray_new(4); for(skpos = 0 ; skpos < sk_num((_STACK *) skx) ; skpos ++) { X509 * x = (X509 *) sk_value((_STACK *) skx, skpos); unsigned char * p; MMAPString * str; int length = i2d_X509(x, NULL); str = mmap_string_sized_new(length); p = (unsigned char *) str->str; str->len = length; i2d_X509(x, &p); carray_add(result, str, NULL); } return result; #else gnutls_session session = NULL; const gnutls_datum *raw_cert_list; unsigned int raw_cert_list_length; ssl_data = (struct mailstream_ssl_data *) s->data; session = ssl_data->session; raw_cert_list = gnutls_certificate_get_peers(session, &raw_cert_list_length); if (raw_cert_list && gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { result = carray_new(4); for(skpos = 0 ; skpos < raw_cert_list_length ; skpos ++) { gnutls_x509_crt cert = NULL; if (gnutls_x509_crt_init(&cert) >= 0 && gnutls_x509_crt_import(cert, &raw_cert_list[skpos], GNUTLS_X509_FMT_DER) >= 0) { size_t cert_size = 0; MMAPString * str = NULL; unsigned char * p; if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, NULL, &cert_size) == GNUTLS_E_SHORT_MEMORY_BUFFER) { str = mmap_string_sized_new(cert_size); p = (unsigned char *) str->str; str->len = cert_size; } if (str != NULL && gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, p, &cert_size) >= 0) { carray_add(result, str, NULL); } else { return NULL; } gnutls_x509_crt_deinit(cert); } } } return result; return NULL; #endif #else return NULL; #endif }
void ssl_barf_out(Socket_t S) { BIO *ebio; char buf[BUFSIZ], *p; sock_ssl_t m = XSsl(S); if (tb_errorlevel >= TB_NOTICE) { STACK * sk; if ((ebio=BIO_new(BIO_s_file())) == NULL) { tb_warn("Cannot create new BIO\n"); ERR_print_errors_fp(stderr); return; } BIO_set_fp(ebio,stderr,BIO_NOCLOSE); if ((sk=(STACK *)SSL_get_peer_cert_chain(m->cx)) != NULL) { int i; BIO_printf(ebio,"---\nCertificate chain\n"); for (i=0; i<sk_num(sk); i++) { X509_NAME_oneline(X509_get_subject_name((X509*)sk_value(sk,i)),buf,BUFSIZ); BIO_printf(ebio,"%2d s:%s\n",i,buf); X509_NAME_oneline(X509_get_issuer_name((X509 *)sk_value(sk,i)),buf,BUFSIZ); BIO_printf(ebio," i:%s\n",buf); } } BIO_printf(ebio,"---\n"); if ((m->peer=SSL_get_peer_certificate(m->cx)) != NULL) { BIO_printf(ebio,"Peer certificate\n"); PEM_write_bio_X509(ebio,m->peer); X509_NAME_oneline(X509_get_subject_name(m->peer),buf,BUFSIZ); BIO_printf(ebio,"subject=%s\n",buf); X509_NAME_oneline(X509_get_issuer_name(m->peer),buf,BUFSIZ); BIO_printf(ebio,"issuer=%s\n",buf); } else BIO_printf(ebio,"no peer certificate available\n"); if (((sk=SSL_get_client_CA_list(m->cx)) != NULL) && (sk_num(sk) > 0)) { int i; BIO_printf(ebio,"---\nAcceptable peer certificate CA names\n"); for (i=0; i<sk_num(sk); i++) { m->xn=(X509_NAME *)sk_value(sk,i); X509_NAME_oneline(m->xn,buf,sizeof(buf)); BIO_write(ebio,buf,strlen(buf)); BIO_write(ebio,"\n",1); } } else { BIO_printf(ebio,"---\nNo peer certificate CA names sent\n"); } if ((p=SSL_get_shared_ciphers(m->cx,buf,BUFSIZ)) != NULL) { int i, j; BIO_printf(ebio,"---\nCiphers common between both SSL endpoints:\n"); j=i=0; while (*p) { if (*p != ':') { BIO_write(ebio,p,1);j++; } else { BIO_write(ebio," ",15-j%25);i++;j=0; BIO_write(ebio,((i%3)?" ":"\n"),1); } p++; } BIO_write(ebio,"\n",1); } BIO_printf(ebio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(m->cx)), BIO_number_written(SSL_get_wbio(m->cx))); BIO_printf(ebio,((m->cx->hit)?"---\nReused, ":"---\nNew, ")); m->sc=SSL_get_current_cipher(m->cx); BIO_printf(ebio,"%s, Cipher is %s\n", SSL_CIPHER_get_version(m->sc),SSL_CIPHER_get_name(m->sc)); if(m->peer != NULL) { EVP_PKEY *pktmp; pktmp = X509_get_pubkey(m->peer); BIO_printf(ebio,"Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } SSL_SESSION_print(ebio,SSL_get_session(m->cx)); BIO_printf(ebio,"---\n"); if(m->peer != NULL) X509_free(m->peer); BIO_free(ebio); } }
static int mta_verify_certificate(struct mta_session *s) { struct ca_vrfy_req_msg req_ca_vrfy; struct iovec iov[2]; X509 *x; STACK_OF(X509) *xchain; int i; const char *pkiname; x = SSL_get_peer_certificate(s->io.ssl); if (x == NULL) return 0; xchain = SSL_get_peer_cert_chain(s->io.ssl); /* * Client provided a certificate and possibly a certificate chain. * SMTP can't verify because it does not have the information that * it needs, instead it will pass the certificate and chain to the * lookup process and wait for a reply. * */ tree_xset(&wait_ssl_verify, s->id, s); s->flags |= MTA_WAIT; /* Send the client certificate */ memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); if (s->relay->pki_name) pkiname = s->relay->pki_name; else pkiname = s->helo; if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname) >= sizeof req_ca_vrfy.pkiname) return 0; req_ca_vrfy.reqid = s->id; req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert); if (xchain) req_ca_vrfy.n_chain = sk_X509_num(xchain); iov[0].iov_base = &req_ca_vrfy; iov[0].iov_len = sizeof(req_ca_vrfy); iov[1].iov_base = req_ca_vrfy.cert; iov[1].iov_len = req_ca_vrfy.cert_len; m_composev(p_lka, IMSG_LKA_SSL_VERIFY_CERT, 0, 0, -1, iov, nitems(iov)); free(req_ca_vrfy.cert); X509_free(x); if (xchain) { /* Send the chain, one cert at a time */ for (i = 0; i < sk_X509_num(xchain); ++i) { memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; x = sk_X509_value(xchain, i); req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert); iov[0].iov_base = &req_ca_vrfy; iov[0].iov_len = sizeof(req_ca_vrfy); iov[1].iov_base = req_ca_vrfy.cert; iov[1].iov_len = req_ca_vrfy.cert_len; m_composev(p_lka, IMSG_LKA_SSL_VERIFY_CHAIN, 0, 0, -1, iov, nitems(iov)); free(req_ca_vrfy.cert); } } /* Tell lookup process that it can start verifying, we're done */ memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; m_compose(p_lka, IMSG_LKA_SSL_VERIFY, 0, 0, -1, &req_ca_vrfy, sizeof req_ca_vrfy); return 1; }
static void print_stuff(BIO * bio, SSL * s, int full) { X509 *peer = NULL; char *p; static const char *space = " "; char buf[BUFSIZ]; STACK_OF(X509) * sk; STACK_OF(X509_NAME) * sk2; const SSL_CIPHER *c; X509_NAME *xn; int j, i; unsigned char *exportedkeymat; if (full) { int got_a_chain = 0; sk = SSL_get_peer_cert_chain(s); if (sk != NULL) { got_a_chain = 1; /* we don't have it for SSL2 * (yet) */ BIO_printf(bio, "---\nCertificate chain\n"); for (i = 0; i < sk_X509_num(sk); i++) { X509_NAME_oneline(X509_get_subject_name( sk_X509_value(sk, i)), buf, sizeof buf); BIO_printf(bio, "%2d s:%s\n", i, buf); X509_NAME_oneline(X509_get_issuer_name( sk_X509_value(sk, i)), buf, sizeof buf); BIO_printf(bio, " i:%s\n", buf); if (c_showcerts) PEM_write_bio_X509(bio, sk_X509_value(sk, i)); } } BIO_printf(bio, "---\n"); peer = SSL_get_peer_certificate(s); if (peer != NULL) { BIO_printf(bio, "Server certificate\n"); if (!(c_showcerts && got_a_chain)) /* Redundant if we * showed the whole * chain */ PEM_write_bio_X509(bio, peer); X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); BIO_printf(bio, "subject=%s\n", buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); BIO_printf(bio, "issuer=%s\n", buf); } else BIO_printf(bio, "no peer certificate available\n"); sk2 = SSL_get_client_CA_list(s); if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { BIO_printf(bio, "---\nAcceptable client certificate CA names\n"); for (i = 0; i < sk_X509_NAME_num(sk2); i++) { xn = sk_X509_NAME_value(sk2, i); X509_NAME_oneline(xn, buf, sizeof(buf)); BIO_write(bio, buf, strlen(buf)); BIO_write(bio, "\n", 1); } } else { BIO_printf(bio, "---\nNo client certificate CA names sent\n"); } p = SSL_get_shared_ciphers(s, buf, sizeof buf); if (p != NULL) { /* * This works only for SSL 2. In later protocol * versions, the client does not know what other * ciphers (in addition to the one to be used in the * current connection) the server supports. */ BIO_printf(bio, "---\nCiphers common between both SSL endpoints:\n"); j = i = 0; while (*p) { if (*p == ':') { BIO_write(bio, space, 15 - j % 25); i++; j = 0; BIO_write(bio, ((i % 3) ? " " : "\n"), 1); } else { BIO_write(bio, p, 1); j++; } p++; } BIO_write(bio, "\n", 1); } BIO_printf(bio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); } BIO_printf(bio, (SSL_cache_hit(s) ? "---\nReused, " : "---\nNew, ")); c = SSL_get_current_cipher(s); BIO_printf(bio, "%s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); if (peer != NULL) { EVP_PKEY *pktmp; pktmp = X509_get_pubkey(peer); BIO_printf(bio, "Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } BIO_printf(bio, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); /* Compression is not supported and will always be none. */ BIO_printf(bio, "Compression: NONE\n"); BIO_printf(bio, "Expansion: NONE\n"); #ifdef SSL_DEBUG { /* Print out local port of connection: useful for debugging */ int sock; struct sockaddr_in ladd; socklen_t ladd_size = sizeof(ladd); sock = SSL_get_fd(s); getsockname(sock, (struct sockaddr *) & ladd, &ladd_size); BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); } #endif #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { const unsigned char *proto; unsigned int proto_len; SSL_get0_next_proto_negotiated(s, &proto, &proto_len); BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); BIO_write(bio, proto, proto_len); BIO_write(bio, "\n", 1); } #endif #ifndef OPENSSL_NO_SRTP { SRTP_PROTECTION_PROFILE *srtp_profile = SSL_get_selected_srtp_profile(s); if (srtp_profile) BIO_printf(bio, "SRTP Extension negotiated, profile=%s\n", srtp_profile->name); } #endif SSL_SESSION_print(bio, SSL_get_session(s)); if (keymatexportlabel != NULL) { BIO_printf(bio, "Keying material exporter:\n"); BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); exportedkeymat = malloc(keymatexportlen); if (exportedkeymat != NULL) { if (!SSL_export_keying_material(s, exportedkeymat, keymatexportlen, keymatexportlabel, strlen(keymatexportlabel), NULL, 0, 0)) { BIO_printf(bio, " Error\n"); } else { BIO_printf(bio, " Keying material: "); for (i = 0; i < keymatexportlen; i++) BIO_printf(bio, "%02X", exportedkeymat[i]); BIO_printf(bio, "\n"); } free(exportedkeymat); } } BIO_printf(bio, "---\n"); if (peer != NULL) X509_free(peer); /* flush, or debugging output gets mixed with http response */ (void) BIO_flush(bio); }
/** * 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; }
static int mta_verify_certificate(struct mta_session *s) { #define MAX_CERTS 16 #define MAX_CERT_LEN (MAX_IMSGSIZE - (IMSG_HEADER_SIZE + sizeof(req_ca_vrfy))) struct ca_vrfy_req_msg req_ca_vrfy; struct iovec iov[2]; X509 *x; STACK_OF(X509) *xchain; const char *name; unsigned char *cert_der[MAX_CERTS]; int cert_len[MAX_CERTS]; int i, cert_count, res; res = 0; memset(cert_der, 0, sizeof(cert_der)); memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); /* Send the client certificate */ if (s->relay->ca_name) { name = s->relay->ca_name; req_ca_vrfy.fallback = 0; } else { name = s->helo; req_ca_vrfy.fallback = 1; } if (strlcpy(req_ca_vrfy.name, name, sizeof req_ca_vrfy.name) >= sizeof req_ca_vrfy.name) return 0; x = SSL_get_peer_certificate(s->io.ssl); if (x == NULL) return 0; xchain = SSL_get_peer_cert_chain(s->io.ssl); /* * Client provided a certificate and possibly a certificate chain. * SMTP can't verify because it does not have the information that * it needs, instead it will pass the certificate and chain to the * lookup process and wait for a reply. * */ cert_len[0] = i2d_X509(x, &cert_der[0]); X509_free(x); if (cert_len[0] < 0) { log_warnx("warn: failed to encode certificate"); goto end; } log_debug("debug: certificate 0: len=%d", cert_len[0]); if (cert_len[0] > (int)MAX_CERT_LEN) { log_warnx("warn: certificate too long"); goto end; } if (xchain) { cert_count = sk_X509_num(xchain); log_debug("debug: certificate chain len: %d", cert_count); if (cert_count >= MAX_CERTS) { log_warnx("warn: certificate chain too long"); goto end; } } else cert_count = 0; for (i = 0; i < cert_count; ++i) { x = sk_X509_value(xchain, i); cert_len[i+1] = i2d_X509(x, &cert_der[i+1]); if (cert_len[i+1] < 0) { log_warnx("warn: failed to encode certificate"); goto end; } log_debug("debug: certificate %i: len=%d", i+1, cert_len[i+1]); if (cert_len[i+1] > (int)MAX_CERT_LEN) { log_warnx("warn: certificate too long"); goto end; } } tree_xset(&wait_ssl_verify, s->id, s); s->flags |= MTA_WAIT; /* Send the client certificate */ req_ca_vrfy.reqid = s->id; req_ca_vrfy.cert_len = cert_len[0]; req_ca_vrfy.n_chain = cert_count; iov[0].iov_base = &req_ca_vrfy; iov[0].iov_len = sizeof(req_ca_vrfy); iov[1].iov_base = cert_der[0]; iov[1].iov_len = cert_len[0]; m_composev(p_lka, IMSG_MTA_TLS_VERIFY_CERT, 0, 0, -1, iov, nitems(iov)); memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; /* Send the chain, one cert at a time */ for (i = 0; i < cert_count; ++i) { req_ca_vrfy.cert_len = cert_len[i+1]; iov[1].iov_base = cert_der[i+1]; iov[1].iov_len = cert_len[i+1]; m_composev(p_lka, IMSG_MTA_TLS_VERIFY_CHAIN, 0, 0, -1, iov, nitems(iov)); } /* Tell lookup process that it can start verifying, we're done */ memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; m_compose(p_lka, IMSG_MTA_TLS_VERIFY, 0, 0, -1, &req_ca_vrfy, sizeof req_ca_vrfy); res = 1; end: for (i = 0; i < MAX_CERTS; ++i) free(cert_der[i]); return res; }
int main(int argc, char *argv[]) { int sd, ocsp_status; const unsigned char *p; long len; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; char *host, *port; #ifdef _PATH_SSL_CA_FILE char *cafile = _PATH_SSL_CA_FILE; #else char *cafile = "/etc/ssl/cert.pem"; #endif SSL *ssl; SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); if (!SSL_CTX_load_verify_locations(ctx, cafile, NULL)) { printf("failed to load %s\n", cafile); exit(-1); } if (argc != 3) errx(-1, "need a host and port to connect to"); else { host = argv[1]; port = argv[2]; } sd = tcp_connect(host, port); ssl = SSL_new(ctx); SSL_set_fd(ssl, (int) sd); SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); if (SSL_connect(ssl) <= 0) { printf("SSL connect error\n"); exit(-1); } if (SSL_get_verify_result(ssl) != X509_V_OK) { printf("Certificate doesn't verify from host %s port %s\n", host, port); exit(-1); } /* ==== VERIFY OCSP RESPONSE ==== */ len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); if (!p) { printf("No OCSP response received for %s port %s\n", host, port); exit(-1); } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (!rsp) { puts("Invalid OCSP response"); exit(-1); } ocsp_status = OCSP_response_status(rsp); if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { printf("Invalid OCSP response status: %s (%d)", OCSP_response_status_str(ocsp_status), ocsp_status); exit(-1); } br = OCSP_response_get1_basic(rsp); if (!br) { puts("Invalid OCSP response"); exit(-1); } ch = SSL_get_peer_cert_chain(ssl); st = SSL_CTX_get_cert_store(ctx); if (OCSP_basic_verify(br, ch, st, 0) <= 0) { puts("OCSP response verification failed"); exit(-1); } printf("OCSP validated from %s %s\n", host, port); return 0; }
bool SSLSocket::enableCrypto(bool activate /* = true */) { if (activate && !m_data->m_ssl_active) { double timeout = m_data->m_connect_timeout; bool blocked = m_data->m_is_blocked; if (!m_data->m_state_set) { if (m_data->m_client) { SSL_set_connect_state(m_data->m_handle); } else { SSL_set_accept_state(m_data->m_handle); } m_data->m_state_set = true; } if (m_data->m_client && setBlocking(false)) { m_data->m_is_blocked = false; } int n; bool retry = true; do { if (m_data->m_client) { struct timeval tvs, tve; struct timezone tz; gettimeofday(&tvs, &tz); n = SSL_connect(m_data->m_handle); gettimeofday(&tve, &tz); timeout -= (tve.tv_sec + (double) tve.tv_usec / 1000000) - (tvs.tv_sec + (double) tvs.tv_usec / 1000000); if (timeout < 0) { raise_warning("SSL: connection timeout"); return -1; } } else { n = SSL_accept(m_data->m_handle); } if (n <= 0) { retry = handleError(n, true); } else { break; } } while (retry); if (m_data->m_client && m_data->m_is_blocked != blocked && setBlocking(blocked)) { m_data->m_is_blocked = blocked; } if (n == 1) { X509 *peer_cert = SSL_get_peer_certificate(m_data->m_handle); if (!applyVerificationPolicy(peer_cert)) { SSL_shutdown(m_data->m_handle); } else { m_data->m_ssl_active = true; /* allow the script to capture the peer cert * and/or the certificate chain */ if (m_context[s_capture_peer_cert].toBoolean()) { m_context.set(s_peer_certificate, Variant(makeSmartPtr<Certificate>(peer_cert))); peer_cert = nullptr; } if (m_context[s_capture_peer_cert_chain].toBoolean()) { Array arr; STACK_OF(X509) *chain = SSL_get_peer_cert_chain(m_data->m_handle); if (chain) { for (int i = 0; i < sk_X509_num(chain); i++) { X509 *mycert = X509_dup(sk_X509_value(chain, i)); arr.append(Variant(makeSmartPtr<Certificate>(mycert))); } } m_context.set(s_peer_certificate_chain, arr); } } if (peer_cert) { X509_free(peer_cert); } } else { n = errno == EAGAIN ? 0 : -1; } return n >= 0; } else if (!activate && m_data->m_ssl_active) { /* deactivate - common for server/client */ SSL_shutdown(m_data->m_handle); m_data->m_ssl_active = false; } return true; }
extern "C" X509Stack* CryptoNative_SslGetPeerCertChain(SSL* ssl) { return SSL_get_peer_cert_chain(ssl); }
static void print_stuff(BIO *bio, SSL *s, int full) { X509 *peer=NULL; char *p; static const char *space=" "; char buf[BUFSIZ]; STACK_OF(X509) *sk; STACK_OF(X509_NAME) *sk2; SSL_CIPHER *c; X509_NAME *xn; int j,i; #ifndef OPENSSL_NO_COMP const COMP_METHOD *comp, *expansion; #endif if (full) { int got_a_chain = 0; sk=SSL_get_peer_cert_chain(s); if (sk != NULL) { got_a_chain = 1; /* we don't have it for SSL2 (yet) */ BIO_printf(bio,"---\nCertificate chain\n"); for (i=0; i<sk_X509_num(sk); i++) { X509_NAME_oneline(X509_get_subject_name( sk_X509_value(sk,i)),buf,sizeof buf); BIO_printf(bio,"%2d s:%s\n",i,buf); X509_NAME_oneline(X509_get_issuer_name( sk_X509_value(sk,i)),buf,sizeof buf); BIO_printf(bio," i:%s\n",buf); if (c_showcerts) PEM_write_bio_X509(bio,sk_X509_value(sk,i)); } } BIO_printf(bio,"---\n"); peer=SSL_get_peer_certificate(s); if (peer != NULL) { BIO_printf(bio,"Server certificate\n"); if (!(c_showcerts && got_a_chain)) /* Redundant if we showed the whole chain */ PEM_write_bio_X509(bio,peer); X509_NAME_oneline(X509_get_subject_name(peer), buf,sizeof buf); BIO_printf(bio,"subject=%s\n",buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf,sizeof buf); BIO_printf(bio,"issuer=%s\n",buf); } else BIO_printf(bio,"no peer certificate available\n"); sk2=SSL_get_client_CA_list(s); if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { BIO_printf(bio,"---\nAcceptable client certificate CA names\n"); for (i=0; i<sk_X509_NAME_num(sk2); i++) { xn=sk_X509_NAME_value(sk2,i); X509_NAME_oneline(xn,buf,sizeof(buf)); BIO_write(bio,buf,strlen(buf)); BIO_write(bio,"\n",1); } } else { BIO_printf(bio,"---\nNo client certificate CA names sent\n"); } p=SSL_get_shared_ciphers(s,buf,sizeof buf); if (p != NULL) { /* This works only for SSL 2. In later protocol * versions, the client does not know what other * ciphers (in addition to the one to be used * in the current connection) the server supports. */ BIO_printf(bio,"---\nCiphers common between both SSL endpoints:\n"); j=i=0; while (*p) { if (*p == ':') { BIO_write(bio,space,15-j%25); i++; j=0; BIO_write(bio,((i%3)?" ":"\n"),1); } else { BIO_write(bio,p,1); j++; } p++; } BIO_write(bio,"\n",1); } BIO_printf(bio,"---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); } BIO_printf(bio,((s->hit)?"---\nReused, ":"---\nNew, ")); c=SSL_get_current_cipher(s); BIO_printf(bio,"%s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); if (peer != NULL) { EVP_PKEY *pktmp; pktmp = X509_get_pubkey(peer); BIO_printf(bio,"Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } #ifndef OPENSSL_NO_COMP comp=SSL_get_current_compression(s); expansion=SSL_get_current_expansion(s); BIO_printf(bio,"Compression: %s\n", comp ? SSL_COMP_get_name(comp) : "NONE"); BIO_printf(bio,"Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #endif SSL_SESSION_print(bio,SSL_get_session(s)); BIO_printf(bio,"---\n"); if (peer != NULL) X509_free(peer); /* flush, or debugging output gets mixed with http response */ (void)BIO_flush(bio); }
static int do_ca_cert_bootstrap(struct vconn *vconn) { struct ssl_vconn *sslv = ssl_vconn_cast(vconn); STACK_OF(X509) *chain; X509 *ca_cert; FILE *file; int error; int fd; chain = SSL_get_peer_cert_chain(sslv->ssl); if (!chain || !sk_X509_num(chain)) { VLOG_ERR("could not bootstrap CA cert: no certificate presented by " "peer"); return EPROTO; } ca_cert = sk_X509_value(chain, sk_X509_num(chain) - 1); /* Check that 'ca_cert' is self-signed. Otherwise it is not a CA * certificate and we should not attempt to use it as one. */ error = X509_check_issued(ca_cert, ca_cert); if (error) { VLOG_ERR("could not bootstrap CA cert: obtained certificate is " "not self-signed (%s)", X509_verify_cert_error_string(error)); if (sk_X509_num(chain) < 2) { VLOG_ERR("only one certificate was received, so probably the peer " "is not configured to send its CA certificate"); } return EPROTO; } fd = open(ca_cert_file, O_CREAT | O_EXCL | O_WRONLY, 0444); if (fd < 0) { VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s", ca_cert_file, strerror(errno)); return errno; } file = fdopen(fd, "w"); if (!file) { int error = errno; VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s", strerror(error)); unlink(ca_cert_file); return error; } if (!PEM_write_X509(file, ca_cert)) { VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: " "%s", ca_cert_file, ERR_error_string(ERR_get_error(), NULL)); fclose(file); unlink(ca_cert_file); return EIO; } if (fclose(file)) { int error = errno; VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s", ca_cert_file, strerror(error)); unlink(ca_cert_file); return error; } VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert_file); log_ca_cert(ca_cert_file, ca_cert); bootstrap_ca_cert = false; has_ca_cert = true; /* SSL_CTX_add_client_CA makes a copy of ca_cert's relevant data. */ SSL_CTX_add_client_CA(ctx, ca_cert); /* SSL_CTX_use_certificate() takes ownership of the certificate passed in. * 'ca_cert' is owned by sslv->ssl, so we need to duplicate it. */ ca_cert = X509_dup(ca_cert); if (!ca_cert) { out_of_memory(); } if (SSL_CTX_load_verify_locations(ctx, ca_cert_file, NULL) != 1) { VLOG_ERR("SSL_CTX_load_verify_locations: %s", ERR_error_string(ERR_get_error(), NULL)); return EPROTO; } VLOG_INFO("killing successful connection to retry using CA cert"); return EPROTO; }