Protocolpublic class Protocol extends com.sun.midp.io.j2me.http.Protocol implements HttpsConnectionThis class implements the necessary functionality
for an HTTPS connection. With support for HTTPS tunneling.
Handshake error codes at the beginning of IOException messages:
(1) certificate is expired
(2) certificate is not yet valid
(3) certificate failed signature verification
(4) certificate was signed using an unsupported algorithm
(5) certificate was issued by an unrecognized certificate authority
(6) certificate does not contain the correct site name
(7) certificate chain exceeds the length allowed
(8) certificate does not contain a signature
(9) version 3 certificate has unrecognized critical extensions
(10) version 3 certificate has an inappropriate keyUsage or
extendedKeyUsage extension
(11) certificate in the a chain was not issued by the next
authority in the chain
(12) trusted certificate authority's public key is expired
|
Fields Summary |
---|
private static final String | COMMON_NAME_LABELCommon name label. | private static final int | COMMON_NAME_LABEL_LENGTHCommon name label length. | private static SecurityToken | classSecurityTokenThis class has a different security domain than the MIDlet suite | private boolean | permissionCheckedThe methods other than openPrim need to know that the
permission occurred. | private boolean | ownerTrustedTrue if the owner of this connection is trusted. | private com.sun.midp.util.Properties | proxyHeaderscollection of "Proxy-" headers as name/value pairs | private SSLStreamConnection | sslConnectionUnderlying SSL connection. |
Constructors Summary |
---|
public Protocol()Create a new instance of this class. Override the some of the values
in our super class.
protocol = "https";
default_port = 443; // 443 is the default port for HTTPS
|
Methods Summary |
---|
private void | checkForPermission(java.lang.String name)Check for the required permission.
MIDletStateHandler midletStateHandler;
MIDletSuite midletSuite;
midletStateHandler = MIDletStateHandler.getMidletStateHandler();
midletSuite = midletStateHandler.getMIDletSuite();
if (midletSuite == null) {
throw new IllegalStateException("This class can't be used " +
"before a suite is started.");
}
name = protocol + ":" + name;
try {
midletSuite.checkForPermission(Permissions.HTTPS, name);
ownerTrusted = midletSuite.isTrusted();
permissionChecked = true;
} catch (InterruptedException ie) {
throw new InterruptedIOException(
"Interrupted while trying to ask the user permission");
}
| private static boolean | checkSiteName(java.lang.String siteName, java.lang.String certName)Check to see if the site name given by the user matches the site
name of subject in the certificate. The method supports the wild card
character for the machine name if a domain name is included after it.
int startOfDomain;
int domainLength;
if (certName == null) {
return false;
}
// try the easy way first, ignoring case
if ((siteName.length() == certName.length()) &&
siteName.regionMatches(true, 0, certName, 0,
certName.length())) {
return true;
}
if (!certName.startsWith("*.")) {
// not a wild card, done
return false;
}
startOfDomain = siteName.indexOf('.");
if (startOfDomain == -1) {
// no domain name
return false;
}
// skip past the '.'
startOfDomain++;
domainLength = siteName.length() - startOfDomain;
if ((certName.length() - 2) != domainLength) {
return false;
}
// compare the just the domain names, ignoring case
if (siteName.regionMatches(true, startOfDomain, certName, 2,
domainLength)) {
return true;
}
return false;
| protected StreamConnection | connect()Connect to the underlying secure socket transport.
Perform the SSL handshake and then proceeded to the underlying
HTTP protocol connect semantics.
StreamConnection sc;
String httpsTunnel;
com.sun.midp.io.j2me.socket.Protocol tcpConnection;
OutputStream tcpOutputStream;
InputStream tcpInputStream;
X509Certificate serverCert;
if (!permissionChecked) {
throw new SecurityException();
}
sc = connectionPool.get(classSecurityToken, protocol,
url.host, url.port);
if (sc != null) {
return sc;
}
// Open socket connection
tcpConnection =
new com.sun.midp.io.j2me.socket.Protocol();
// check to see if a protocol is specified for the tunnel
httpsTunnel = Configuration.getProperty("com.sun.midp.io.http.proxy");
if (httpsTunnel != null) {
// Make the connection to the ssl tunnel
tcpConnection.openPrim(classSecurityToken, "//" + httpsTunnel);
// Do not delay request since this delays the response.
tcpConnection.setSocketOption(SocketConnection.DELAY, 0);
tcpOutputStream = tcpConnection.openOutputStream();
tcpInputStream = tcpConnection.openInputStream();
// Do the handshake with the ssl tunnel
try {
doTunnelHandshake(tcpOutputStream, tcpInputStream);
} catch (IOException ioe) {
String temp = ioe.getMessage();
tcpConnection.close();
tcpOutputStream.close();
tcpInputStream.close();
if (temp.indexOf(" 500 ") > -1) {
throw new ConnectionNotFoundException(temp);
}
throw ioe;
}
} else {
tcpConnection.openPrim(classSecurityToken, "//" + hostAndPort);
// Do not delay request since this delays the response.
tcpConnection.setSocketOption(SocketConnection.DELAY, 0);
tcpOutputStream = tcpConnection.openOutputStream();
tcpInputStream = tcpConnection.openInputStream();
}
tcpConnection.close();
try {
// Get the SSLStreamConnection
sslConnection = new SSLStreamConnection(url.host, url.port,
tcpInputStream, tcpOutputStream,
WebPublicKeyStore.getTrustedKeyStore());
} catch (Exception e) {
try {
tcpInputStream.close();
} catch (Throwable t) {
// Ignore, we are processing an exception
}
try {
tcpOutputStream.close();
} catch (Throwable t) {
// Ignore, we are processing an exception
}
if (e instanceof IOException) {
throw (IOException)e;
} else {
throw (RuntimeException)e;
}
}
try {
serverCert = sslConnection.getServerCertificate();
/*
* if the subject alternate name is a DNS name,
* then use that instead of the common name for a
* site name match
*/
if (serverCert.getSubjectAltNameType() ==
X509Certificate.TYPE_DNS_NAME) {
if (!checkSiteName(url.host,
(String)serverCert.getSubjectAltName())) {
throw new CertificateException(
"Subject alternative name did not match site name",
serverCert, CertificateException.SITENAME_MISMATCH);
}
} else {
String cname = getCommonName(serverCert.getSubject());
if (cname == null) {
throw new CertificateException(
"Common name missing from subject name",
serverCert, CertificateException.SITENAME_MISMATCH);
}
if (!checkSiteName(url.host, cname)) {
throw new CertificateException(serverCert,
CertificateException.SITENAME_MISMATCH);
}
}
return sslConnection;
} catch (Exception e) {
try {
sslConnection.close();
} catch (Throwable t) {
// Ignore, we are processing an exception
}
if (e instanceof IOException) {
throw (IOException)e;
} else {
throw (RuntimeException)e;
}
}
| protected void | disconnect(StreamConnection connection, java.io.InputStream inputStream, java.io.OutputStream outputStream)disconnect the current connection.
try {
try {
inputStream.close();
} finally {
try {
outputStream.close();
} finally {
connection.close();
}
}
} catch (IOException e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_PROTOCOL,
"Exception while closing streams|connection");
}
} catch (NullPointerException e) {
}
| private static java.lang.String | getCommonName(java.lang.String name)Parse the common name out of a distinguished name.
int start;
int end;
if (name == null) {
return null;
}
/* The common name starts with "CN=" label */
start = name.indexOf(COMMON_NAME_LABEL);
if (start < 0) {
return null;
}
start += COMMON_NAME_LABEL_LENGTH;
end = name.indexOf(';", start);
if (end < 0) {
end = name.length();
}
return name.substring(start, end);
| public java.lang.String | getRequestProperty(java.lang.String key)Get the request header value for the named property.
/* https handles the proxy fields in a different way */
if (key.toLowerCase().startsWith("proxy-")) {
return proxyHeaders.getPropertyIgnoreCase(key);
}
return super.getRequestProperty(key);
| public SecurityInfo | getSecurityInfo()Return the security information associated with this connection.
If the connection is still in Setup state then
the connection is initiated to establish the secure connection
to the server. The method returns when the connection is
established and the Certificate supplied by the
server has been validated.
The SecurityInfo is only returned if the
connection has been successfully made to the server.
ensureOpen();
sendRequest();
if (sslConnection == null) {
/*
* This is a persistent connection so the connect method did
* not get called, so the stream connection of HTTP class
* will be a SSL connection. Get the info from that.
*/
StreamConnection sc =
((StreamConnectionElement)getStreamConnection()).
getBaseConnection();
return ((SSLStreamConnection)sc).getSecurityInfo();
}
return sslConnection.getSecurityInfo();
| public Connection | openPrim(java.lang.String name, int mode, boolean timeouts)Sets up the state of the connection, but
does not actually connect to the server until there's something
to do.
Warning: A subclass that implements this method, not call this
method and should also implement the disconnect method.
checkForPermission(name);
initStreamConnection(mode);
url = new HttpUrl(protocol, name);
if (url.port == -1) {
url.port = default_port;
}
if (url.host == null) {
throw new IllegalArgumentException("missing host in URL");
}
hostAndPort = url.host + ":" + url.port;
return this;
| protected void | setRequestField(java.lang.String key, java.lang.String value)Add the named field to the list of request fields.
/* https handles the proxy fields in a different way */
if (key.toLowerCase().startsWith("proxy-")) {
proxyHeaders.setPropertyIgnoreCase(key, value);
return;
}
super.setRequestField(key, value);
|
|