The configuration properties described in Section 41.4 are flexible enough to satisfy the requirements of many applications, and IceSSL supports a public API that offers even more functionality for those applications that need it.
41.5.1 C++
The Plugin Interface
Applications can interact directly with the IceSSL plug‑in using the native C++ class
IceSSL::Plugin. A reference to a
Plugin object must be obtained from the communicator in which the plug‑in is installed:
Ice::CommunicatorPtr communicator = // ...
Ice::PluginManagerPtr pluginMgr =
communicator‑>getPluginManager();
Ice::PluginPtr plugin = pluginMgr‑>getPlugin("IceSSL");
IceSSL::PluginPtr sslPlugin =
IceSSL::PluginPtr::dynamicCast(plugin);
The Plugin class supports the following methods:
namespace IceSSL
{
class Plugin : public Ice::Plugin
{
public:
virtual void setContext(SSL_CTX*) = 0;
virtual SSL_CTX* getContext() = 0;
virtual void setCertificateVerifier(
const CertificateVerifierPtr&) = 0;
virtual void setPasswordPrompt(
const PasswordPromptPtr&) = 0;
};
typedef IceUtil::Handle<Plugin> PluginPtr;
}
The setContext and
getContext methods are rarely used in practice; see
Section 41.6 for more information. The
setCertificateVerifier method installs a custom certificate verifier object that the plug‑in invokes for each new connection. The
setPasswordPrompt method provides an alternate way to supply IceSSL with passwords, as discussed in
Section 41.6.
You can obtain information about any SSL connection using the Ice::Connection::getInfo operation (see
Section 36.5). It returns an
IceSSL::NativeConnectionInfo class instance that derives from the Slice class
IceSSL::ConnectionInfo. The Slice base class is defined as follows:
module Ice {
local class ConnectionInfo {
bool incoming;
string adapterName;
};
local class IPConnectionInfo extends ConnectionInfo {
string localAddress;
int localPort;
string remoteAddress;
int remotePort;
};
};
module IceSSL {
local class ConnectionInfo extends Ice::IPConnectionInfo {
string cipher;
Ice::StringSeq certs;
};
};
In turn, the C++ class NativeConnectionInfo is defined as follows:
class NativeConnectionInfo : public ConnectionInfo {
public:
std::vector<CertificatePtr> nativeCerts;
};
typedef IceUtil::Handle<NativeConnectionInfo>
NativeConnectionInfoPtr;
A new connection undergoes a series of verification steps before an application is allowed to use it. The low-level SSL engine executes the validation procedures described in
Section 41.2.2. Assuming the certificate chain is successfully validated, IceSSL performs additional verification as directed by its configuration properties (see
Section 41.4.6). Finally, if a certificate verifier is installed, IceSSL invokes it to provide the application with an opportunity to decide whether to allow the connection to proceed.
The CertificateVerifier interface has only one method:
namespace IceSSL
{
class CertificateVerifier : public IceUtil::Shared
{
public:
virtual bool verify(const NativeConnectionInfoPtr&) = 0;
};
typedef IceUtil::Handle<CertificateVerifier>
CertificateVerifierPtr;
}
IceSSL rejects the connection if verify returns
false, and allows it to proceed if the method returns
true. The
verify method receives a
ConnectionInfo object that describes the connection’s attributes.
The nativeCerts member is a vector of certificates representing the peer’s certificate chain. The vector is structured so that the first element is the peer’s certificate, followed by its signing certificates in the order they appear in the chain, with the root CA certificate as the last element. The vector is empty if the peer did not present a certificate chain.
The cipher member is a description of the ciphersuite that SSL negotiated for this connection. The local and remote address information is provided in
localAddress and
remoteAddress1, respectively. The
incoming member indicates whether the connection is inbound (a server connection) or outbound (a client connection). Finally, if
incoming is true, the
adapterName member supplies the name of the object adapter that hosts the endpoint.
class Verifier : public IceSSL::CertificateVerifier
{
public:
bool verify(const IceSSL::NativeConnectionInfo& info)
{
if (!info.nativeCerts.empty())
{
string dn = info.nativeCerts[0].getIssuerDN();
transform(dn.begin(), dn.end(), dn.begin(),
::tolower);
if (dn.find("zeroc") != string::npos)
{
return true;
}
}
return false;
}
}
In this example, the verifier rejects the connection unless the string zeroc is present in the issuer’s distinguished name of the peer’s certificate. In a more realistic implementation, the application is likely to perform detailed inspection of the certificate chain.
See Section 41.6.2 for more information on installing a certificate verifier.
The ConnectionInfo class contains a vector of
Certificate objects representing the peer’s certificate chain.
Certificate is a reference-counted convenience class that hides the complexity of the underlying OpenSSL API. Its methods are inspired by the Java class
X509Certificate:
namespace IceSSL
{
class Certificate : public IceUtil::Shared
{
public:
Certificate(X509*);
static CertificatePtr load(const string&);
static CertificatePtr decode(const string&);
bool operator==(const Certificate&) const;
bool operator!=(const Certificate&) const;
PublicKeyPtr getPublicKey() const;
bool verify(const PublicKeyPtr&) const;
string encode() const;
bool checkValidity() const;
bool checkValidity(const IceUtil::Time&) const;
IceUtil::Time getNotAfter() const;
IceUtil::Time getNotBefore() const;
string getSerialNumber() const;
DistinguishedName getIssuerDN() const;
vector<pair<int, string> > getIssuerAlternativeNames();
DistinguishedName getSubjectDN() const;
vector<pair<int, string> > getSubjectAlternativeNames();
int getVersion() const;
string toString() const;
X509* getCert() const;
};
typedef IceUtil::Handle<Certificate> CertificatePtr;
}
The more commonly-used methods are described below; refer to the documentation in
IceSSL/Plugin.h for information on the methods that are not covered.
The static method load creates a certificate from the contents of a PEM-encoded file. If an error occurs, the function raises
IceSSL::CertificateReadException; the reason member provides a description of the problem.
Use decode to obtain a certificate from a PEM-encoded string representing a certificate. The caller must be prepared to catch
IceSSL::CertificateEncodingException if
decode fails; the reason member provides a description of the problem.
The encode method creates a PEM-encoded string that represents the certificate. The return value can later be passed to
decode to recreate the certificate.
The checkValidity methods determine whether the certificate is valid. The overloading with no arguments returns true if the certificate is valid at the current time; the other overloading accepts an
IceUtil::Time object and returns true if the certificate is valid at the given time. See Appendix
F.12 for more information on
IceUtil::Time.
The getNotAfter and
getNotBefore methods return instances of
IceUtil::Time that define the certificate’s valid period.
The methods getIssuerDN and
getSubjectDN supply the distinguished names of the certificate’s issuer (i.e., the CA that signed the certificate) and subject (i.e., the person or entity to which the certificate was issued). The methods return instances of the class
IceSSL::DistinguishedName, another convenience class that is described in the next section.
Finally, the toString method returns a human-readable string describing the certificate.
X.509 certificates use a distinguished name to identify a person or entity. The name is an ordered sequence of relative distinguished names that supply values for fields such as common name, organization, state, and country. Distinguished names are commonly displayed in stringified form according to the rules specified by RFC 2253, as shown in the following example:
DistinguishedName is a convenience class provided by IceSSL to simplify the tasks of parsing, formatting and comparing distinguished names.
namespace IceSSL
{
class DistinguishedName
{
public:
DistinguishedName(const std::string&);
DistinguishedName(
const std::list<std::pair<std::string, std::string> >&);
bool operator==(const DistinguishedName&) const;
bool operator!=(const DistinguishedName&) const;
bool operator<(const DistinguishedName&) const;
bool match(const DistinguishedName&) const;
operator std::string() const;
};
}
The first overloaded constructor accepts a string argument representing a distinguished name encoded using the rules set forth in RFC 2253. The new
DistinguishedName instance preserves the order of the relative distinguished names in the string. The caller must be prepared to catch
IceSSL::ParseException if an error occurs during parsing.
The second overloaded constructor requires a list of type–value pairs representing the relative distinguished names. The new
DistinguishedName instance preserves the order of the relative distinguished names in the list.
The overloaded operator functions operator==,
operator!=, and
operator< perform an exact match of distinguished names in which the order of the relative distinguished names is important. For two distinguished names to be equal, they must have the same relative distinguished names in the same order.
The match function performs a partial comparison that does not consider the order of relative distinguished names. If
N1 and
N2 are instances of
DistinguishedName,
N1.match(N2) returns true if all of the relative distinguished names in
N2 are present in
N1.
The Plugin Interface
Applications can interact directly with the IceSSL plug‑in using the native Java interface
IceSSL.Plugin. A reference to a
Plugin object must be obtained from the communicator in which the plug‑in is installed:
Ice.Communicator comm = // ...
Ice.PluginManager pluginMgr = comm.getPluginManager();
Ice.Plugin plugin = pluginMgr.getPlugin("IceSSL");
IceSSL.Plugin sslPlugin = (IceSSL.Plugin)plugin;
The Plugin interface supports the following methods:
package IceSSL;
public interface Plugin extends Ice.Plugin
{
void setContext(javax.net.ssl.SSLContext context);
javax.net.ssl.SSLContext getContext();
void setCertificateVerifier(CertificateVerifier verifier);
CertificateVerifier getCertificateVerifier();
void setPasswordCallback(PasswordCallback callback);
PasswordCallback getPasswordCallback();
void setKeystoreStream(java.io.InputStream stream);
void setTruststoreStream(java.io.InputStream stream);
void addSeedStream(java.io.InputStream stream);
}
You can obtain information about any SSL connection using the Ice::Connection::getInfo operation (see
Section 36.5). It returns an
IceSSL.NativeConnectionInfo class instance that derives from the Slice class
IceSSL::ConnectionInfo. The Slice base class is defined as follows:
module Ice {
local class ConnectionInfo {
bool incoming;
string adapterName;
};
local class IPConnectionInfo extends ConnectionInfo {
string localAddress;
int localPort;
string remoteAddress;
int remotePort;
};
};
module IceSSL {
local class ConnectionInfo extends Ice::IPConnectionInfo {
string cipher;
Ice::StringSeq certs;
};
};
In turn, the Java class NativeConnectionInfo is defined as follows.
public class NativeConnectionInfo extends ConnectionInfo
{
public java.security.cert.Certificate[] nativeCerts;
}
A new connection undergoes a series of verification steps before an application is allowed to use it. The low-level SSL engine executes the validation procedures described in
Section 41.2.2. Assuming the certificate chain is successfully validated, IceSSL performs additional verification as directed by its configuration properties (see
Section 41.4.6). Finally, if a certificate verifier is installed, IceSSL invokes it to provide the application with an opportunity to decide whether to allow the connection to proceed.
The CertificateVerifier interface has only one method:
package IceSSL;
public interface CertificateVerifier
{
boolean verify(NativeConnectionInfo info);
}
IceSSL rejects the connection if verify returns
false, and allows it to proceed if the method returns
true. The
verify method receives a
NativeConnectionInfo object that describes the connection’s attributes.
The nativeCerts member of the
NativeConnectionInfo is an array of certificates representing the peer’s certificate chain. The array is structured so that the first element is the peer’s certificate, followed by its signing certificates in the order they appear in the chain, with the root CA certificate as the last element. This member is null if the peer did not present a certificate chain.
The cipher member is a description of the ciphersuite that SSL negotiated for this connection. The local and remote address information is provided in
localAddress and
remoteAddress, respectively. The
incoming member indicates whether the connection is inbound (a server connection) or outbound (a client connection). Finally, if
incoming is
true, the
adapterName member supplies the name of the object adapter that hosts the endpoint.
import java.security.cert.X509Certificate;
import javax.security.auth.x500.X500Principal;
class Verifier implements IceSSL.CertificateVerifier
{
public boolean
verify(IceSSL.NativeConnectionInfo info)
{
if (info.nativeCerts != null)
{
X509Certificate cert =
(X509Certificate)info.nativeCerts[0];
X500Principal p = cert.getIssuerX500Principal();
if (p.getName().toLowerCase().indexOf("zeroc") != ‑1)
{
return true;
}
}
return false;
}
}
In this example, the verifier rejects the connection unless the string zeroc is present in the issuer’s distinguished name of the peer’s certificate. In a more realistic implementation, the application is likely to perform detailed inspection of the certificate chain.
IceSSL.Plugin sslPlugin = // ...
sslPlugin.setCertificateVerifier(new Verifier());
You should install the verifier before any SSL connections are established. An alternate way of installing the verifier is to define the
IceSSL.CertVerifier property with the class name of your verifier implementation. IceSSL instantiates the class using its default constructor.
See Section 41.6.2 for more information on installing a certificate verifier.
package IceSSL;
public final class Util
{
// ...
public static java.security.cert.X509Certificate
createCertificate(String certPEM)
throws java.security.cert.CertificateException;
}
Given a string in the PEM format, createCertificate returns the equivalent
X509Certificate object.
The Plugin Interface
Applications can interact directly with the IceSSL plug‑in using the native C# interface
IceSSL.Plugin. A reference to a
Plugin object must be obtained from the communicator in which the plug‑in is installed:
Ice.Communicator comm = // ...
Ice.PluginManager pluginMgr = comm.getPluginManager();
Ice.Plugin plugin = pluginMgr.getPlugin("IceSSL");
IceSSL.Plugin sslPlugin = (IceSSL.Plugin)plugin;
The Plugin interface supports the following methods:
namespace IceSSL
{
using System.Security.Cryptography.X509Certificates;
abstract public class Plugin : Ice.Plugin
{
abstract public void
setCertificates(X509Certificate2Collection certs);
abstract public void
setCertificateVerifier(CertificateVerifier verifier);
abstract public CertificateVerifier
getCertificateVerifier();
abstract public void
setPasswordCallback(PasswordCallback callback);
abstract public PasswordCallback
getPasswordCallback();
}
}
You can obtain information about any SSL connection using the Ice::Connection::getInfo operation (see
Section 36.5). It returns an
IceSSL.NativeConnectionInfo class instance that derives from the Slice class
IceSSL::ConnectionInfo. The Slice base class is defined as follows:
module Ice {
local class ConnectionInfo {
bool incoming;
string adapterName;
};
local class IPConnectionInfo extends ConnectionInfo {
string localAddress;
int localPort;
string remoteAddress;
int remotePort;
};
};
module IceSSL {
local class ConnectionInfo extends Ice::IPConnectionInfo {
string cipher;
Ice::StringSeq certs;
};
};
In turn, the C# class NativeConnectionInfo is defined as follows.
public sealed class NativeConnectionInfo : ConnectionInfo
{
public System.Security.Cryptography.
X509Certificates.X509Certificate2[] nativeCerts;
}
A new connection undergoes a series of verification steps before an application is allowed to use it. The low-level SSL engine executes the validation procedures described in
Section 41.2.2. Assuming the certificate chain is successfully validated, IceSSL performs additional verification as directed by its configuration properties (see
Section 41.4.6). Finally, if a certificate verifier is installed, IceSSL invokes it to provide the application with an opportunity to decide whether to allow the connection to proceed.
The CertificateVerifier interface has only one method:
namespace IceSSL
{
public interface CertificateVerifier
{
bool verify(NativeConnectionInfo info);
}
}
IceSSL rejects the connection if verify returns
false, and allows it to proceed if the method returns
true. The
verify method receives a
NativeConnectionInfo object that describes the connection’s attributes.
The nativeCerts member of the
c is an array of certificates representing the peer’s certificate chain. The array is structured so that the first element is the peer’s certificate, followed by its signing certificates in the order they appear in the chain, with the root CA certificate as the last element. This member is null if the peer did not present a certificate chain.
The cipher member is a description of the ciphersuite that SSL negotiated for this connection. The local and remote address information is provided in
localAddress and
remoteAddr, respectively. The
incoming member indicates whether the connection is inbound (a server connection) or outbound (a client connection). Finally, if
incoming is true, the
adapterName member supplies the name of the object adapter that hosts the endpoint.
using System.Security.Cryptography.X509Certificates;
class Verifier : IceSSL.CertificateVerifier
{
public boolean
verify(IceSSL.NativeConnectionInfo info)
{
if (info.nativeCerts != null)
{
X500DistinguishedName dn =
info.nativeCerts[0].IssuerName;
if (dn.Name.ToLower().Contains("zeroc"))
{
return true;
}
}
return false;
}
}
In this example, the verifier rejects the connection unless the string zeroc is present in the issuer’s distinguished name of the peer’s certificate. In a more realistic implementation, the application is likely to perform detailed inspection of the certificate chain.
IceSSL.Plugin sslPlugin = // ...
sslPlugin.setCertificateVerifier(new Verifier());
You should install the verifier before any SSL connections are established. An alternate way of installing the verifier is to define the
IceSSL.CertVerifier property with the class name of your verifier implementation. IceSSL instantiates the class using its default constructor.
See Section 41.6.2 for more information on installing a certificate verifier.
namespace IceSSL
{
using System.Security.Cryptography.X509Certificates;
public sealed class Util
{
// ...
public static X509Certificate2
createCertificate(string certPEM);
}
}
Given a string in the PEM format, createCertificate returns the equivalent
X509Certificate2 object.