wolfssljni/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession....

578 lines
17 KiB
Java

/* WolfSSLImplementSession.java
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl.provider.jsse;
import com.wolfssl.WolfSSLException;
import com.wolfssl.WolfSSLJNIException;
import com.wolfssl.WolfSSLSession;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.ByteArrayInputStream;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLSessionBindingListener;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.X509KeyManager;
/**
* wolfSSL Session
* Note: suppress depreciation warning for javax.security.cert.X509Certificate
* @author wolfSSL
*/
@SuppressWarnings("deprecation")
public class WolfSSLImplementSSLSession implements SSLSession {
private WolfSSLSession ssl = null;
private final WolfSSLAuthStore authStore;
private WolfSSLSessionContext ctx = null;
private boolean valid = false;
private final HashMap<String, Object> binding;
private final int port;
private final String host;
Date creation = null;
Date accessed = null; /* when new connection was made using session */
byte[] pseudoSessionID = null; /* used with TLS 1.3*/
private int side = 0;
/** Has this session been registered */
protected boolean fromTable = false;
/** Native pointer to WOLFSSL_SESSION structure. Obtained via
* wolfSSL_get1_session(), so needs to be freed */
private long sesPtr = 0;
private String nullCipher = "SSL_NULL_WITH_NULL_NULL";
private String nullProtocol = "NONE";
/**
* Create new WolfSSLImplementSSLSession
*
* @param in WolfSSLSession to be used with this object
* @param port peer port for this session
* @param host peer hostname String for this session
* @param params WolfSSLAuthStore for this session
*/
public WolfSSLImplementSSLSession (WolfSSLSession in, int port, String host,
WolfSSLAuthStore params) {
this.ssl = in;
this.port = port;
this.host = host;
this.authStore = params;
this.valid = false; /* flag if joining or resuming session is allowed */
binding = new HashMap<String, Object>();
creation = new Date();
accessed = new Date();
}
/**
* Create new WolfSSLImplementSSLSession
*
* @param in WolfSSLSession to be used with this object
* @param params WolfSSLAuthStore for this session
*/
public WolfSSLImplementSSLSession (WolfSSLSession in,
WolfSSLAuthStore params) {
this.ssl = in;
this.port = -1;
this.host = null;
this.authStore = params;
this.valid = false; /* flag if joining or resuming session is allowed */
binding = new HashMap<String, Object>();
creation = new Date();
accessed = new Date();
}
/**
* Create new WolfSSLImplementSSLSession
*
* @param params WolfSSLAuthStore for this session
*/
public WolfSSLImplementSSLSession (WolfSSLAuthStore params) {
this.port = -1;
this.host = null;
this.authStore = params;
this.valid = false; /* flag if joining or resuming session is allowed */
binding = new HashMap<String, Object>();
creation = new Date();
accessed = new Date();
}
/**
* Get session ID for this session
*
* @return session ID as byte array, empty byte array if wrapped
* com.wolfssl.WolfSSLSession is null, or null if inner
* IllegalStateException or WolfSSLJNIException are thrown
*/
public synchronized byte[] getId() {
if (ssl == null) {
return new byte[0];
}
try {
/* use pseudo session ID if session tickets are being used */
if (this.ssl.getVersion().equals("TLSv1.3") ||
this.ssl.sessionTicketsEnabled()) {
return this.pseudoSessionID;
}
else {
return this.ssl.getSessionID();
}
} catch (IllegalStateException | WolfSSLJNIException e) {
e.printStackTrace();
return null;
}
}
/**
* Get SSLSessionContext for this session
*
* @return SSLSessionContext
*/
public synchronized SSLSessionContext getSessionContext() {
return ctx;
}
/**
* Setter function for the SSLSessionContext used with session creation
*
* @param ctx value to set the session context as
*/
protected synchronized void setSessionContext(WolfSSLSessionContext ctx) {
this.ctx = ctx;
}
/**
* Get session creation time
*
* @return session creation time
*/
public long getCreationTime() {
return creation.getTime();
}
/**
* Get session last accessed time
*
* @return session last accessed time
*/
public long getLastAccessedTime() {
return accessed.getTime();
}
/**
* Invalidate this session
*/
public void invalidate() {
this.valid = false;
}
/**
* Check if this session is valid
*
* @return boolean if this session is valid
*/
public boolean isValid() {
return this.valid;
}
/**
* After a connection has been established or on restoring connection the
* session is then valid and can be joined or resumed
* @param in true/false valid boolean
*/
protected void setValid(boolean in) {
this.valid = in;
}
/**
* Put value into this session
*
* @param name String name of value
* @param obj Object to store associated with name
*
* @throws IllegalArgumentException if input name is null
*/
public void putValue(String name, Object obj) {
Object old;
if (name == null) {
throw new IllegalArgumentException();
}
/* check if Object should be notified */
if (obj instanceof SSLSessionBindingListener) {
((SSLSessionBindingListener) obj).valueBound(
new SSLSessionBindingEvent(this, name));
}
old = binding.put(name, obj);
if (old != null) {
if (old instanceof SSLSessionBindingListener) {
((SSLSessionBindingListener) old).valueUnbound(
new SSLSessionBindingEvent(this, name));
}
}
}
/**
* Get stored value associated with name
*
* @param name String name to retrieve associated Object value
*
* @return Object value associated with name
*/
public Object getValue(String name) {
return binding.get(name);
}
/**
* Remove stored String:Object from session
*
* @param name String name to remove from session
*
* @throws IllegalArgumentException if input name is null
*/
public void removeValue(String name) {
Object obj;
if (name == null) {
throw new IllegalArgumentException();
}
obj = binding.get(name);
if (obj != null) {
/* check if Object should be notified */
if (obj instanceof SSLSessionBindingListener) {
((SSLSessionBindingListener) obj).valueUnbound(
new SSLSessionBindingEvent(this, name));
}
binding.remove(name);
}
}
/**
* Get stored value names in this session
*
* @return String array of value names stored in session
*/
public String[] getValueNames() {
return binding.keySet().toArray(new String[binding.keySet().size()]);
}
/**
* Get peer certificates for this session
*
* @return Certificate array of peer certs for session
*
* @throws SSLPeerUnverifiedException if handshake is not complete,
* or error getting certificates
*/
public synchronized Certificate[] getPeerCertificates()
throws SSLPeerUnverifiedException {
long x509;
WolfSSLX509 cert;
CertificateFactory cf;
ByteArrayInputStream der;
X509Certificate exportCert;
if (ssl == null) {
throw new SSLPeerUnverifiedException("handshake not complete");
}
try {
x509 = this.ssl.getPeerCertificate();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
return null;
}
/* if no peer cert, throw SSLPeerUnverifiedException */
if (x509 == 0) {
throw new SSLPeerUnverifiedException("No peer certificate");
}
try {
cert = new WolfSSLX509(x509);
} catch (WolfSSLException ex) {
throw new SSLPeerUnverifiedException("Error creating certificate");
}
/* convert WolfSSLX509 into X509Certificate so we can release
* our native memory */
try {
cf = CertificateFactory.getInstance("X.509");
} catch (CertificateException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting CertificateFactory instance");
}
try {
der = new ByteArrayInputStream(cert.getEncoded());
} catch (CertificateEncodingException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting encoded DER from WolfSSLX509 object");
}
try {
exportCert = (X509Certificate)cf.generateCertificate(der);
} catch (CertificateException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error generating X509Certificdate from DER encoding");
}
/* release native memory */
cert.free();
return new Certificate[] { exportCert };
}
@Override
public Certificate[] getLocalCertificates() {
X509KeyManager km = authStore.getX509KeyManager();
return km.getCertificateChain(authStore.getCertAlias());
}
@Override
public synchronized javax.security.cert.X509Certificate[] getPeerCertificateChain()
throws SSLPeerUnverifiedException {
WolfSSLX509X x509;
if (ssl == null) {
throw new SSLPeerUnverifiedException("handshake not done");
}
try {
x509 = new WolfSSLX509X(this.ssl.getPeerCertificate());
return new javax.security.cert.X509Certificate[] {
(javax.security.cert.X509Certificate)x509 };
} catch (IllegalStateException | WolfSSLJNIException |
WolfSSLException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
}
return null;
}
@Override
public synchronized Principal getPeerPrincipal()
throws SSLPeerUnverifiedException {
if (ssl == null) {
throw new SSLPeerUnverifiedException("handshake not done");
}
try {
Principal peerPrincipal = null;
WolfSSLX509 x509 = new WolfSSLX509(this.ssl.getPeerCertificate());
peerPrincipal = x509.getSubjectDN();
x509.free();
return peerPrincipal;
} catch (IllegalStateException | WolfSSLJNIException |
WolfSSLException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
}
return null;
}
@Override
public Principal getLocalPrincipal() {
X509KeyManager km = authStore.getX509KeyManager();
java.security.cert.X509Certificate[] certs =
km.getCertificateChain(authStore.getCertAlias());
Principal localPrincipal = null;
if (certs == null) {
return null;
}
for (int i = 0; i < certs.length; i++) {
if (certs[i].getBasicConstraints() < 0) {
/* is not a CA treat as end of chain */
localPrincipal = certs[i].getSubjectDN();
break;
}
}
/* free native resources earlier than garbage collection if
* X509Certificate is WolfSSLX509 */
for (int i = 0; i < certs.length; i++) {
if (certs[i] instanceof WolfSSLX509) {
((WolfSSLX509)certs[i]).free();
}
}
/* return principal, or null if not set */
return localPrincipal;
}
@Override
public synchronized String getCipherSuite() {
if (ssl == null) {
return this.nullCipher;
}
try {
return this.ssl.cipherGetName();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
}
return null;
}
@Override
public synchronized String getProtocol() {
if (ssl == null) {
return this.nullProtocol;
}
try {
return this.ssl.getVersion();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
}
return null;
}
@Override
public String getPeerHost() {
return this.host;
}
@Override
public int getPeerPort() {
return this.port;
}
@Override
public int getPacketBufferSize() {
/* Match conscrypt's calculations here for maximum potential
* SSL/TLS record length. Used by SSLEngine consumers to allocate
* output buffer size.
*
* type(1) + version(2) + length(2) + 2^14 plaintext +
* max compression overhead (1024) + max AEAD overhead (1024) */
return 18437;
}
@Override
public int getApplicationBufferSize() {
/* max plaintext bytes allowed by spec, MAX_RECORD_SIZE enum (2^14) */
return 16384;
}
/**
* Takes in a new WOLFSSL object and sets the stored session
* @param in WOLFSSL session to set resume in
*/
protected synchronized void resume(WolfSSLSession in) {
/* Set session (WOLFSSL_SESSION) into native WOLFSSL, makes
* a copy of the session so this object can free sesPtr when ready */
in.setSession(this.sesPtr);
ssl = in;
}
/**
* Should be called on shutdown to save the session pointer
*/
protected synchronized void setResume() {
if (ssl != null) {
if (this.sesPtr != 0) {
WolfSSLSession.freeSession(this.sesPtr);
}
this.sesPtr = ssl.getSession();
}
}
/**
* Sets the native WOLFSSL_SESSION timeout
* @param in timeout in seconds
*/
protected synchronized void setNativeTimeout(long in) {
ssl.setSessTimeout(in);
}
/**
* TLS 1.3 removed session ID's, this can be used instead to
* search for sessions.
* @param id pseudo session ID at the java wrapper level
*/
protected synchronized void setPseudoSessionId(byte[] id) {
this.pseudoSessionID = id.clone();
}
/**
* Sets (server/client) side of the connection for session
* @param in the side to be set, server or client
*/
protected void setSide(int in) {
this.side = in;
}
/**
* Returns the side session is on (server/client)
* @return WolfSSL.* integer value of side on
*/
protected int getSide() {
return this.side;
}
@SuppressWarnings("deprecation")
@Override
protected void finalize() throws Throwable
{
if (this.sesPtr != 0) {
WolfSSLSession.freeSession(this.sesPtr);
this.sesPtr = 0;
}
super.finalize();
}
}