SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); unsigned char dest[SSL_SESSION_MAX_DER]; unsigned int destlen = SSL_SESSION_MAX_DER; const unsigned char *ptr; apr_status_t rv; if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } rv = mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen, dest, &destlen, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } if (rv != APR_SUCCESS) { return NULL; } ptr = dest; return d2i_SSL_SESSION(NULL, &ptr, destlen); }
SSL_SESSION *ssl_scache_dc_retrieve(server_rec *s, UCHAR *id, int idlen) { unsigned char der[SSL_SESSION_MAX_DER]; unsigned int der_len; SSL_SESSION *pSession; MODSSL_D2I_SSL_SESSION_CONST unsigned char *pder = der; SSLModConfigRec *mc = myModConfig(s); DC_CTX *ctx = mc->tSessionCacheDataTable; /* Retrieve any corresponding session from the distributed cache context */ if (!DC_CTX_get_session(ctx, id, idlen, der, SSL_SESSION_MAX_DER, &der_len)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' MISS"); return NULL; } if (der_len > SSL_SESSION_MAX_DER) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' OVERFLOW"); return NULL; } pSession = d2i_SSL_SESSION(NULL, &pder, der_len); if (!pSession) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' CORRUPT"); return NULL; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' HIT"); return pSession; }
SSLSessionImpl::SSLSessionImpl(const std::string& serializedSession) { auto sessionData = reinterpret_cast<const unsigned char*>(serializedSession.data()); auto longLen = long(serializedSession.length()); if ((session_ = d2i_SSL_SESSION(nullptr, &sessionData, longLen)) == nullptr) { throw std::runtime_error("Cannot deserialize SSLSession string"); } }
static BOOL shmcb_subcache_remove(server_rec *s, SHMCBHeader *header, SHMCBSubcache *subcache, UCHAR *id, unsigned int idlen) { unsigned int pos; unsigned int loop = 0; BOOL to_return = FALSE; /* Unlike the others, we don't do an expire-run first. This is to keep * consistent statistics where a "remove" operation may actually be the * higher layer spotting an expiry issue prior to us. Our caller is * handling stats, so a failure return would be inconsistent if the * intended session was in fact removed by an expiry run. */ pos = subcache->idx_pos; while (!to_return && (loop < subcache->idx_used)) { SHMCBIndex *idx = SHMCB_INDEX(subcache, pos); /* Only consider 'idx' if the s_id2 byte matches and it's not already * removed - easiest way to avoid costly ASN decodings. */ if ((idx->s_id2 == id[1]) && !idx->removed) { SSL_SESSION *pSession; unsigned char *s_id; unsigned int s_idlen; unsigned char tempasn[SSL_SESSION_MAX_DER]; MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr = tempasn; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "possible match at idx=%d, data=%d", pos, idx->data_pos); /* Copy the data */ shmcb_cyclic_cton_memcpy(header->subcache_data_size, tempasn, SHMCB_DATA(header, subcache), idx->data_pos, idx->data_used); /* Decode the session */ pSession = d2i_SSL_SESSION(NULL, &ptr, idx->data_used); if (!pSession) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shmcb_subcache_remove internal error"); return FALSE; } s_id = SSL_SESSION_get_session_id(pSession); s_idlen = SSL_SESSION_get_session_id_length(pSession); if (s_idlen == idlen && memcmp(s_id, id, idlen) == 0) { /* Found the matching session, remove it quietly. */ idx->removed = 1; to_return = TRUE; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "shmcb_subcache_remove removing matching session"); } SSL_SESSION_free(pSession); } /* Increment */ loop++; pos = SHMCB_CYCLIC_INCREMENT(pos, 1, header->index_num); } return to_return; }
std::pair<SSL_SESSION*, size_t> getSessionWithTicket() { const unsigned char* p = kSessionDataWithTicket; size_t sessionDataWithTicketLen = sizeof(kSessionDataWithTicket); auto s = d2i_SSL_SESSION(nullptr, &p, sessionDataWithTicketLen); CHECK(isSameSession( std::make_pair(s, sessionDataWithTicketLen), std::make_pair(s, sessionDataWithTicketLen))); return std::make_pair(s, sessionDataWithTicketLen); }
static SSL_SESSION *shmcb_subcache_retrieve(server_rec *s, SHMCBHeader *header, SHMCBSubcache *subcache, UCHAR *id, unsigned int idlen) { unsigned int pos; unsigned int loop = 0; /* If there are entries to expire, ditch them first. */ shmcb_subcache_expire(s, header, subcache); pos = subcache->idx_pos; while (loop < subcache->idx_used) { SHMCBIndex *idx = SHMCB_INDEX(subcache, pos); /* Only consider 'idx' if; * (a) the s_id2 byte matches * (b) the "removed" flag isn't set. */ if ((idx->s_id2 == id[1]) && !idx->removed) { SSL_SESSION *pSession; unsigned char *s_id; unsigned int s_idlen; unsigned char tempasn[SSL_SESSION_MAX_DER]; MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr = tempasn; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "possible match at idx=%d, data=%d", pos, idx->data_pos); /* Copy the data */ shmcb_cyclic_cton_memcpy(header->subcache_data_size, tempasn, SHMCB_DATA(header, subcache), idx->data_pos, idx->data_used); /* Decode the session */ pSession = d2i_SSL_SESSION(NULL, &ptr, idx->data_used); if (!pSession) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shmcb_subcache_retrieve internal error"); return NULL; } s_id = SSL_SESSION_get_session_id(pSession); s_idlen = SSL_SESSION_get_session_id_length(pSession); if (s_idlen == idlen && memcmp(s_id, id, idlen) == 0) { /* Found the matching session */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "shmcb_subcache_retrieve returning matching session"); return pSession; } SSL_SESSION_free(pSession); } /* Increment */ loop++; pos = SHMCB_CYCLIC_INCREMENT(pos, 1, header->index_num); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "shmcb_subcache_retrieve found no match"); return NULL; }
void SSLSessionCacheManager::restoreSession( SSLCacheProvider::CacheContext* cacheCtx, const uint8_t* data, size_t length) { cacheCtx->session = d2i_SSL_SESSION(nullptr, &data, length); restartSSLAccept(cacheCtx); /* Insert in the LRU after restarting all clients. The stats logic * in getSession would treat this as a local hit otherwise. */ localCache_->storeSession(cacheCtx->sessionId, cacheCtx->session, stats_); delete cacheCtx; }
void SSLSessionCacheManager::onGetSuccess( SSLCacheProvider::CacheContext* cacheCtx, const std::string& value) { const uint8_t* cp = (uint8_t*)value.data(); cacheCtx->session = d2i_SSL_SESSION(nullptr, &cp, value.length()); restartSSLAccept(cacheCtx); /* Insert in the LRU after restarting all clients. The stats logic * in getSession would treat this as a local hit otherwise. */ localCache_->storeSession(cacheCtx->sessionId, cacheCtx->session, stats_); delete cacheCtx; }
SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) { uint64_t valsize = 0; *copy = 0; uwsgi_rlock(uwsgi.ssl_sessions_cache->lock); char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize); if (!value) { uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); if (uwsgi.ssl_verbose) { uwsgi_log("[uwsgi-ssl] cache miss\n"); } return NULL; } #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize); #else SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (unsigned char **)&value, valsize); #endif uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); return sess; }
void h2o_socket_ssl_resume_server_handshake(h2o_socket_t *sock, h2o_iovec_t session_data) { if (session_data.len != 0) { const unsigned char *p = (void *)session_data.base; sock->ssl->handshake.server.async_resumption.session_data = d2i_SSL_SESSION(NULL, &p, (long)session_data.len); /* FIXME warn on failure */ } sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; proceed_handshake(sock, 0); if (sock->ssl->handshake.server.async_resumption.session_data != NULL) { SSL_SESSION_free(sock->ssl->handshake.server.async_resumption.session_data); sock->ssl->handshake.server.async_resumption.session_data = NULL; } }
static SSL_SESSION *generate_dtls_session(struct openconnect_info *vpninfo, int dtlsver, const SSL_CIPHER *cipher) { struct oc_text_buf *buf = buf_alloc(); SSL_SESSION *dtls_session; const unsigned char *asn; uint16_t cid; buf_append_bytes(buf, "\x30\x80", 2); // SEQUENCE, indeterminate length buf_append_INTEGER(buf, 1 /* SSL_SESSION_ASN1_VERSION */); buf_append_INTEGER(buf, dtlsver); store_be16(&cid, SSL_CIPHER_get_id(cipher) & 0xffff); buf_append_OCTET_STRING(buf, &cid, 2); buf_append_OCTET_STRING(buf, vpninfo->dtls_session_id, sizeof(vpninfo->dtls_session_id)); buf_append_OCTET_STRING(buf, vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)); /* If the length actually fits in one byte (which it should), do * it that way. Else, leave it indeterminate and add two * end-of-contents octets to mark the end of the SEQUENCE. */ if (!buf_error(buf) && buf->pos <= 0x80) buf->data[1] = buf->pos - 2; else buf_append_bytes(buf, "\0\0", 2); if (buf_error(buf)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to create SSL_SESSION ASN.1 for OpenSSL: %s\n"), strerror(buf_error(buf))); buf_free(buf); return NULL; } asn = (void *)buf->data; dtls_session = d2i_SSL_SESSION(NULL, &asn, buf->pos); buf_free(buf); if (!dtls_session) { vpn_progress(vpninfo, PRG_ERR, _("OpenSSL failed to parse SSL_SESSION ASN.1\n")); openconnect_report_ssl_errors(vpninfo); return NULL; } return dtls_session; }
SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(); void *vp; SSL_SESSION *sess = NULL; UCHAR *ucpData; int nData; time_t expiry; time_t now; int n; /* allow the regular expiring to occur */ ssl_scache_shmht_expire(s); /* lookup key in table */ ssl_mutex_on(s); if (table_retrieve(mc->tSessionCacheDataTable, id, idlen, &vp, &n) != TABLE_ERROR_NONE) { ssl_mutex_off(s); return NULL; } /* copy over the information to the SCI */ nData = n-sizeof(time_t); ucpData = (UCHAR *)malloc(nData); if (ucpData == NULL) { ssl_mutex_off(s); return NULL; } memcpy(&expiry, vp, sizeof(time_t)); memcpy(ucpData, (char *)vp+sizeof(time_t), nData); ssl_mutex_off(s); /* make sure the stuff is still not expired */ now = time(NULL); if (expiry <= now) { ssl_scache_shmht_remove(s, id, idlen); return NULL; } /* unstreamed SSL_SESSION */ sess = d2i_SSL_SESSION(NULL, &ucpData, nData); return sess; }
NOEXPORT SSL_SESSION *cache_get(SSL *ssl, const unsigned char *key, int key_len) { unsigned char *val, *val_tmp=NULL; ssize_t val_len=0; SSL_SESSION *sess; cache_transfer(SSL_get_SSL_CTX(ssl), CACHE_CMD_GET, 0, key, (size_t)key_len, NULL, 0, &val, (size_t *)&val_len); if(!val) return NULL; val_tmp=val; sess=d2i_SSL_SESSION(NULL, #if OPENSSL_VERSION_NUMBER>=0x0090800fL (const unsigned char **) #endif /* OpenSSL version >= 0.8.0 */ &val_tmp, (long)val_len); str_free(val); return sess; }
/* de-serialized a SSL session and set it back to the request at lua context */ int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, const unsigned char *data, int len, char **err) { u_char *p; u_char buf[NGX_SSL_MAX_SESSION_SIZE]; ngx_ssl_conn_t *ssl_conn; ngx_connection_t *c; ngx_ssl_session_t *session = NULL; ngx_http_lua_ssl_ctx_t *cctx; c = r->connection; if (c == NULL || c->ssl == NULL) { *err = "bad request"; return NGX_ERROR; } ssl_conn = c->ssl->connection; if (ssl_conn == NULL) { *err = "bad ssl conn"; return NGX_ERROR; } ngx_memcpy(buf, data, len); p = buf; session = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, len); if (session == NULL) { ERR_clear_error(); *err = "failed to de-serialize session"; return NGX_ERROR; } cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); if (cctx == NULL) { *err = "bad lua context"; return NGX_ERROR; } cctx->session = session; return NGX_OK; }
std::vector<std::pair<SSL_SESSION*, size_t>> getSessions() { std::vector<std::pair<SSL_SESSION*, size_t>> sessions; for (size_t i = 0; i < kNumSessions; ++i) { const unsigned char* p = kSessionData[i]; auto s = d2i_SSL_SESSION(nullptr, &p, kSessionDataLen); CHECK(s) << "Invalid session " << i; sessions.emplace_back(s, kSessionDataLen); // Make sure the same session compares same to itself. CHECK(isSameSession(sessions[i], sessions[i])); } // Make sure all sessions are different from each other CHECK(!isSameSession(sessions[0], sessions[1])); CHECK(!isSameSession(sessions[1], sessions[2])); CHECK(!isSameSession(sessions[2], sessions[0])); return sessions; }
static cache_val_t cachessess_unpackverify_val_cb(cache_val_t val, int copy) { dynbuf_t *valbuf = val; SSL_SESSION *sess; const unsigned char *p; p = (const unsigned char *)valbuf->buf; sess = d2i_SSL_SESSION(NULL, &p, valbuf->sz); /* increments p */ if (!sess) return NULL; if (!ssl_session_is_valid(sess)) { SSL_SESSION_free(sess); return NULL; } if (copy) return sess; SSL_SESSION_free(sess); return ((cache_val_t)!NULL); }
NOEXPORT SSL_SESSION *sess_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy) { unsigned char *val, *val_tmp=NULL; unsigned int val_len=0; SSL_SESSION *sess; *do_copy = 0; /* allow the session to be freed autmatically */ cache_transfer(ssl->ctx, CACHE_CMD_GET, 0, key, key_len, NULL, 0, &val, &val_len); if(!val) return NULL; val_tmp=val; sess=d2i_SSL_SESSION(NULL, #if OPENSSL_VERSION_NUMBER>=0x0090800fL (const unsigned char **) #endif /* OpenSSL version >= 0.8.0 */ &val_tmp, val_len); str_free(val); return sess; }
/* tls_decrypt_ticket attempts to decrypt a session ticket. * * etick: points to the body of the session ticket extension. * eticklen: the length of the session tickets extenion. * sess_id: points at the session ID. * sesslen: the length of the session ID. * psess: (output) on return, if a ticket was decrypted, then this is set to * point to the resulting session. * * Returns: * -1: fatal error, either from parsing or decrypting the ticket. * 2: the ticket couldn't be decrypted. * 3: a ticket was successfully decrypted and *psess was set. * 4: same as 3, but the ticket needs to be renewed. */ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, const unsigned char *sess_id, int sesslen, SSL_SESSION **psess) { SSL_SESSION *sess; unsigned char *sdec; const unsigned char *p; int slen, mlen, renew_ticket = 0; unsigned char tick_hmac[EVP_MAX_MD_SIZE]; HMAC_CTX hctx; EVP_CIPHER_CTX ctx; SSL_CTX *tctx = s->initial_ctx; /* * The API guarantees EVP_MAX_IV_LENGTH bytes of space for * the iv to tlsext_ticket_key_cb(). Since the total space * required for a session cookie is never less than this, * this check isn't too strict. The exact check comes later. */ if (eticklen < 16 + EVP_MAX_IV_LENGTH) return 2; /* Initialize session ticket encryption and HMAC contexts */ HMAC_CTX_init(&hctx); EVP_CIPHER_CTX_init(&ctx); if (tctx->internal->tlsext_ticket_key_cb) { unsigned char *nctick = (unsigned char *)etick; int rv = tctx->internal->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, 0); if (rv < 0) { HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); return -1; } if (rv == 0) { HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); return 2; } if (rv == 2) renew_ticket = 1; } else { /* Check key name matches */ if (timingsafe_memcmp(etick, tctx->internal->tlsext_tick_key_name, 16)) return 2; HMAC_Init_ex(&hctx, tctx->internal->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL); EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, tctx->internal->tlsext_tick_aes_key, etick + 16); } /* * Attempt to process session ticket, first conduct sanity and * integrity checks on ticket. */ mlen = HMAC_size(&hctx); if (mlen < 0) { HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); return -1; } /* Sanity check ticket length: must exceed keyname + IV + HMAC */ if (eticklen <= 16 + EVP_CIPHER_CTX_iv_length(&ctx) + mlen) { HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); return 2; } eticklen -= mlen; /* Check HMAC of encrypted ticket */ if (HMAC_Update(&hctx, etick, eticklen) <= 0 || HMAC_Final(&hctx, tick_hmac, NULL) <= 0) { HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); return -1; } HMAC_CTX_cleanup(&hctx); if (timingsafe_memcmp(tick_hmac, etick + eticklen, mlen)) { EVP_CIPHER_CTX_cleanup(&ctx); return 2; } /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); sdec = malloc(eticklen); if (sdec == NULL || EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen) <= 0) { free(sdec); EVP_CIPHER_CTX_cleanup(&ctx); return -1; } if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0) { free(sdec); EVP_CIPHER_CTX_cleanup(&ctx); return 2; } slen += mlen; EVP_CIPHER_CTX_cleanup(&ctx); p = sdec; sess = d2i_SSL_SESSION(NULL, &p, slen); free(sdec); if (sess) { /* The session ID, if non-empty, is used by some clients to * detect that the ticket has been accepted. So we copy it to * the session structure. If it is empty set length to zero * as required by standard. */ if (sesslen) memcpy(sess->session_id, sess_id, sesslen); sess->session_id_length = sesslen; *psess = sess; if (renew_ticket) return 4; else return 3; } ERR_clear_error(); /* For session parse failure, indicate that we need to send a new * ticket. */ return 2; }
static ngx_int_t ngx_stream_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, void *data) { ngx_stream_upstream_rr_peer_data_t *rrp = data; ngx_int_t rc; ngx_ssl_session_t *ssl_session; ngx_stream_upstream_rr_peer_t *peer; #if (NGX_STREAM_UPSTREAM_ZONE) int len; #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const #endif u_char *p; ngx_stream_upstream_rr_peers_t *peers; u_char buf[NGX_SSL_MAX_SESSION_SIZE]; #endif peer = rrp->current; #if (NGX_STREAM_UPSTREAM_ZONE) peers = rrp->peers; if (peers->shpool) { ngx_stream_upstream_rr_peers_rlock(peers); ngx_stream_upstream_rr_peer_lock(peers, peer); if (peer->ssl_session == NULL) { ngx_stream_upstream_rr_peer_unlock(peers, peer); ngx_stream_upstream_rr_peers_unlock(peers); return NGX_OK; } len = peer->ssl_session_len; ngx_memcpy(buf, peer->ssl_session, len); ngx_stream_upstream_rr_peer_unlock(peers, peer); ngx_stream_upstream_rr_peers_unlock(peers); p = buf; ssl_session = d2i_SSL_SESSION(NULL, &p, len); rc = ngx_ssl_set_session(pc->connection, ssl_session); ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, "set session: %p", ssl_session); ngx_ssl_free_session(ssl_session); return rc; } #endif ssl_session = peer->ssl_session; rc = ngx_ssl_set_session(pc->connection, ssl_session); ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, "set session: %p", ssl_session); return rc; }
int MAIN(int argc, char **argv) { SSL_SESSION *x=NULL; int ret=1,i,num,badops=0; BIO *out=NULL; int informat,outformat; char *infile=NULL,*outfile=NULL,*context=NULL; int cert=0,noout=0,text=0; char **pp; apps_startup(); if (bio_err == NULL) if ((bio_err=BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); informat=FORMAT_PEM; outformat=FORMAT_PEM; argc--; argv++; num=0; while (argc >= 1) { if (strcmp(*argv,"-inform") == 0) { if (--argc < 1) goto bad; informat=str2fmt(*(++argv)); } else if (strcmp(*argv,"-outform") == 0) { if (--argc < 1) goto bad; outformat=str2fmt(*(++argv)); } else if (strcmp(*argv,"-in") == 0) { if (--argc < 1) goto bad; infile= *(++argv); } else if (strcmp(*argv,"-out") == 0) { if (--argc < 1) goto bad; outfile= *(++argv); } else if (strcmp(*argv,"-text") == 0) text= ++num; else if (strcmp(*argv,"-cert") == 0) cert= ++num; else if (strcmp(*argv,"-noout") == 0) noout= ++num; else if (strcmp(*argv,"-context") == 0) { if(--argc < 1) goto bad; context=*++argv; } else { BIO_printf(bio_err,"unknown option %s\n",*argv); badops=1; break; } argc--; argv++; } if (badops) { bad: for (pp=sess_id_usage; (*pp != NULL); pp++) BIO_printf(bio_err,*pp); goto end; } ERR_load_crypto_strings(); x=load_sess_id(infile,informat); if (x == NULL) { goto end; } if(context) { x->sid_ctx_length=strlen(context); if(x->sid_ctx_length > SSL_MAX_SID_CTX_LENGTH) { BIO_printf(bio_err,"Context too long\n"); goto end; } memcpy(x->sid_ctx,context,x->sid_ctx_length); } #ifdef undef /* just testing for memory leaks :-) */ { SSL_SESSION *s; char buf[1024*10],*p; int i; s=SSL_SESSION_new(); p= &buf; i=i2d_SSL_SESSION(x,&p); p= &buf; d2i_SSL_SESSION(&s,&p,(long)i); p= &buf; d2i_SSL_SESSION(&s,&p,(long)i); p= &buf; d2i_SSL_SESSION(&s,&p,(long)i); SSL_SESSION_free(s); } #endif if (!noout || text) { out=BIO_new(BIO_s_file()); if (out == NULL) { ERR_print_errors(bio_err); goto end; } if (outfile == NULL) { BIO_set_fp(out,stdout,BIO_NOCLOSE); #ifdef VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); out = BIO_push(tmpbio, out); } #endif } else { if (BIO_write_filename(out,outfile) <= 0) { perror(outfile); goto end; } } } if (text) { SSL_SESSION_print(out,x); if (cert) { if (x->peer == NULL) BIO_puts(out,"No certificate present\n"); else X509_print(out,x->peer); } } if (!noout && !cert) { if (outformat == FORMAT_ASN1) i=(int)i2d_SSL_SESSION_bio(out,x); else if (outformat == FORMAT_PEM) i=PEM_write_bio_SSL_SESSION(out,x); else { BIO_printf(bio_err,"bad output format specified for outfile\n"); goto end; } if (!i) { BIO_printf(bio_err,"unable to write SSL_SESSION\n"); goto end; } } else if (!noout && (x->peer != NULL)) /* just print the certificate */ { if (outformat == FORMAT_ASN1) i=(int)i2d_X509_bio(out,x->peer); else if (outformat == FORMAT_PEM) i=PEM_write_bio_X509(out,x->peer); else { BIO_printf(bio_err,"bad output format specified for outfile\n"); goto end; } if (!i) { BIO_printf(bio_err,"unable to write X509\n"); goto end; } } ret=0; end: if (out != NULL) BIO_free_all(out); if (x != NULL) SSL_SESSION_free(x); EXIT(ret); }
static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, const unsigned char *sess_id, int sesslen, SSL_SESSION **psess) { SSL_SESSION *sess; unsigned char *sdec; const unsigned char *p; int slen, mlen, renew_ticket = 0; unsigned char tick_hmac[EVP_MAX_MD_SIZE]; HMAC_CTX hctx; EVP_CIPHER_CTX ctx; SSL_CTX *tctx = s->initial_ctx; /* Need at least keyname + iv + some encrypted data */ if (eticklen < 48) goto tickerr; /* Initialize session ticket encryption and HMAC contexts */ HMAC_CTX_init(&hctx); EVP_CIPHER_CTX_init(&ctx); if (tctx->tlsext_ticket_key_cb) { unsigned char *nctick = (unsigned char *)etick; int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, 0); if (rv < 0) return -1; if (rv == 0) goto tickerr; if (rv == 2) renew_ticket = 1; } else { /* Check key name matches */ if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) goto tickerr; HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL); EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, tctx->tlsext_tick_aes_key, etick + 16); } /* Attempt to process session ticket, first conduct sanity and * integrity checks on ticket. */ mlen = HMAC_size(&hctx); eticklen -= mlen; /* Check HMAC of encrypted ticket */ HMAC_Update(&hctx, etick, eticklen); HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); if (memcmp(tick_hmac, etick + eticklen, mlen)) goto tickerr; /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); sdec = OPENSSL_malloc(eticklen); if (!sdec) { EVP_CIPHER_CTX_cleanup(&ctx); return -1; } EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) goto tickerr; slen += mlen; EVP_CIPHER_CTX_cleanup(&ctx); p = sdec; sess = d2i_SSL_SESSION(NULL, &p, slen); OPENSSL_free(sdec); if (sess) { /* The session ID if non-empty is used by some clients to * detect that the ticket has been accepted. So we copy it to * the session structure. If it is empty set length to zero * as required by standard. */ if (sesslen) memcpy(sess->session_id, sess_id, sesslen); sess->session_id_length = sesslen; *psess = sess; s->tlsext_ticket_expected = renew_ticket; return 1; } /* If session decrypt failure indicate a cache miss and set state to * send a new ticket */ tickerr: s->tlsext_ticket_expected = 1; return 0; }