changeset 61:725d8ccc8684

2006-06-37 Lillian Angel <langel@redhat.com> * Makefile.am: Added to ICEDTEA_COPY_DIRS and ICEDTEA_COPY_SRC * Makefile.in: Regenerated. * jce/gnu/javax/net/ssl/AbstractSessionContext.java, jce/gnu/javax/net/ssl/EntropySource.java, jce/gnu/javax/net/ssl/NullManagerParameters.java, jce/gnu/javax/net/ssl/PreSharedKeyManager.class, jce/gnu/javax/net/ssl/PreSharedKeyManager.java, jce/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java, jce/gnu/javax/net/ssl/PrivateCredentials.java, jce/gnu/javax/net/ssl/SRPManagerParameters.java, jce/gnu/javax/net/ssl/SRPTrustManager.java, jce/gnu/javax/net/ssl/SSLCipherSuite.java, jce/gnu/javax/net/ssl/SSLProtocolVersion.java, jce/gnu/javax/net/ssl/SSLRecordHandler.java, jce/gnu/javax/net/ssl/Session.java, jce/gnu/javax/net/ssl/SessionStoreException.java, jce/gnu/javax/net/ssl/StaticTrustAnchors.java, jce/gnu/javax/net/ssl/provider/AbstractHandshake.java, jce/gnu/javax/net/ssl/provider/Alert.java, jce/gnu/javax/net/ssl/provider/AlertException.java, jce/gnu/javax/net/ssl/provider/Builder.java, jce/gnu/javax/net/ssl/provider/Certificate.java, jce/gnu/javax/net/ssl/provider/CertificateBuilder.java, jce/gnu/javax/net/ssl/provider/CertificateRequest.java, jce/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java, jce/gnu/javax/net/ssl/provider/CertificateStatusRequest.java, jce/gnu/javax/net/ssl/provider/CertificateStatusType.java, jce/gnu/javax/net/ssl/provider/CertificateType.java, jce/gnu/javax/net/ssl/provider/CertificateURL.java, jce/gnu/javax/net/ssl/provider/CertificateVerify.java, jce/gnu/javax/net/ssl/provider/CipherAlgorithm.java, jce/gnu/javax/net/ssl/provider/CipherSuite.java, jce/gnu/javax/net/ssl/provider/CipherSuiteList.java, jce/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java, jce/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java, jce/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java, jce/gnu/javax/net/ssl/provider/ClientHandshake.java, jce/gnu/javax/net/ssl/provider/ClientHello.java, jce/gnu/javax/net/ssl/provider/ClientHelloBuilder.java, jce/gnu/javax/net/ssl/provider/ClientHelloV2.java, jce/gnu/javax/net/ssl/provider/ClientKeyExchange.java, jce/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java, jce/gnu/javax/net/ssl/provider/ClientPSKParameters.java, jce/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java, jce/gnu/javax/net/ssl/provider/CompressionMethod.java, jce/gnu/javax/net/ssl/provider/CompressionMethodList.java, jce/gnu/javax/net/ssl/provider/Constructed.java, jce/gnu/javax/net/ssl/provider/ContentType.java, jce/gnu/javax/net/ssl/provider/Debug.java, jce/gnu/javax/net/ssl/provider/DelegatedTask.java, jce/gnu/javax/net/ssl/provider/DiffieHellman.java, jce/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java, jce/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java, jce/gnu/javax/net/ssl/provider/ExchangeKeys.java, jce/gnu/javax/net/ssl/provider/Extension.java, jce/gnu/javax/net/ssl/provider/ExtensionList.java, jce/gnu/javax/net/ssl/provider/Finished.java, jce/gnu/javax/net/ssl/provider/Handshake.java, jce/gnu/javax/net/ssl/provider/HelloRequest.java, jce/gnu/javax/net/ssl/provider/InputSecurityParameters.java, jce/gnu/javax/net/ssl/provider/Jessie.class, jce/gnu/javax/net/ssl/provider/Jessie.java, jce/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java, jce/gnu/javax/net/ssl/provider/MacAlgorithm.java, jce/gnu/javax/net/ssl/provider/MacException.java, jce/gnu/javax/net/ssl/provider/MaxFragmentLength.java, jce/gnu/javax/net/ssl/provider/OutputSecurityParameters.java, jce/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java, jce/gnu/javax/net/ssl/provider/ProtocolVersion.java, jce/gnu/javax/net/ssl/provider/Random.java, jce/gnu/javax/net/ssl/provider/Record.java, jce/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java, jce/gnu/javax/net/ssl/provider/SSLContextImpl.java, jce/gnu/javax/net/ssl/provider/SSLEngineImpl.java, jce/gnu/javax/net/ssl/provider/SSLHMac.java, jce/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java, jce/gnu/javax/net/ssl/provider/SSLRandom.java, jce/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java, jce/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java, jce/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java, jce/gnu/javax/net/ssl/provider/SSLSocketImpl.java, jce/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java, jce/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java, jce/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java, jce/gnu/javax/net/ssl/provider/ServerDHParams.java, jce/gnu/javax/net/ssl/provider/ServerHandshake.java, jce/gnu/javax/net/ssl/provider/ServerHello.java, jce/gnu/javax/net/ssl/provider/ServerHelloBuilder.java, jce/gnu/javax/net/ssl/provider/ServerHelloDone.java, jce/gnu/javax/net/ssl/provider/ServerKeyExchange.java, jce/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java, jce/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java, jce/gnu/javax/net/ssl/provider/ServerNameList.java, jce/gnu/javax/net/ssl/provider/ServerPSKParameters.java, jce/gnu/javax/net/ssl/provider/ServerRSAParams.java, jce/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java, jce/gnu/javax/net/ssl/provider/SessionImpl.java, jce/gnu/javax/net/ssl/provider/Signature.java, jce/gnu/javax/net/ssl/provider/SignatureAlgorithm.java, jce/gnu/javax/net/ssl/provider/SimpleSessionContext.java, jce/gnu/javax/net/ssl/provider/TLSHMac.java, jce/gnu/javax/net/ssl/provider/TLSRandom.java, jce/gnu/javax/net/ssl/provider/TruncatedHMAC.java, jce/gnu/javax/net/ssl/provider/TrustedAuthorities.java, jce/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java, jce/gnu/javax/net/ssl/provider/Util.java, jce/gnu/javax/net/ssl/provider/X500PrincipalList.java, jce/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java, jce/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java, jce/javax/net/VanillaServerSocketFactory.java, jce/javax/net/VanillaSocketFactory.java, jce/javax/net/ssl/TrivialHostnameVerifier.java, rt/gnu/java/util/Base64.java: New file
author Lillian Angel <langel@redhat.com>
date Wed, 27 Jun 2007 12:37:11 -0400
parents 89ccb8a867c5
children 4d2a546e1a10
files ChangeLog Makefile.am Makefile.in jce/gnu/javax/net/ssl/AbstractSessionContext.java jce/gnu/javax/net/ssl/EntropySource.java jce/gnu/javax/net/ssl/NullManagerParameters.java jce/gnu/javax/net/ssl/PreSharedKeyManager.class jce/gnu/javax/net/ssl/PreSharedKeyManager.java jce/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java jce/gnu/javax/net/ssl/PrivateCredentials.java jce/gnu/javax/net/ssl/SRPManagerParameters.java jce/gnu/javax/net/ssl/SRPTrustManager.java jce/gnu/javax/net/ssl/SSLCipherSuite.java jce/gnu/javax/net/ssl/SSLProtocolVersion.java jce/gnu/javax/net/ssl/SSLRecordHandler.java jce/gnu/javax/net/ssl/Session.java jce/gnu/javax/net/ssl/SessionStoreException.java jce/gnu/javax/net/ssl/StaticTrustAnchors.java jce/gnu/javax/net/ssl/provider/AbstractHandshake.java jce/gnu/javax/net/ssl/provider/Alert.java jce/gnu/javax/net/ssl/provider/AlertException.java jce/gnu/javax/net/ssl/provider/Builder.java jce/gnu/javax/net/ssl/provider/Certificate.java jce/gnu/javax/net/ssl/provider/CertificateBuilder.java jce/gnu/javax/net/ssl/provider/CertificateRequest.java jce/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java jce/gnu/javax/net/ssl/provider/CertificateStatusRequest.java jce/gnu/javax/net/ssl/provider/CertificateStatusType.java jce/gnu/javax/net/ssl/provider/CertificateType.java jce/gnu/javax/net/ssl/provider/CertificateURL.java jce/gnu/javax/net/ssl/provider/CertificateVerify.java jce/gnu/javax/net/ssl/provider/CipherAlgorithm.java jce/gnu/javax/net/ssl/provider/CipherSuite.java jce/gnu/javax/net/ssl/provider/CipherSuiteList.java jce/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java jce/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java jce/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java jce/gnu/javax/net/ssl/provider/ClientHandshake.java jce/gnu/javax/net/ssl/provider/ClientHello.java jce/gnu/javax/net/ssl/provider/ClientHelloBuilder.java jce/gnu/javax/net/ssl/provider/ClientHelloV2.java jce/gnu/javax/net/ssl/provider/ClientKeyExchange.java jce/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java jce/gnu/javax/net/ssl/provider/ClientPSKParameters.java jce/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java jce/gnu/javax/net/ssl/provider/CompressionMethod.java jce/gnu/javax/net/ssl/provider/CompressionMethodList.java jce/gnu/javax/net/ssl/provider/Constructed.java jce/gnu/javax/net/ssl/provider/ContentType.java jce/gnu/javax/net/ssl/provider/Debug.java jce/gnu/javax/net/ssl/provider/DelegatedTask.java jce/gnu/javax/net/ssl/provider/DiffieHellman.java jce/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java jce/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java jce/gnu/javax/net/ssl/provider/ExchangeKeys.java jce/gnu/javax/net/ssl/provider/Extension.java jce/gnu/javax/net/ssl/provider/ExtensionList.java jce/gnu/javax/net/ssl/provider/Finished.java jce/gnu/javax/net/ssl/provider/Handshake.java jce/gnu/javax/net/ssl/provider/HelloRequest.java jce/gnu/javax/net/ssl/provider/InputSecurityParameters.java jce/gnu/javax/net/ssl/provider/Jessie.class jce/gnu/javax/net/ssl/provider/Jessie.java jce/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java jce/gnu/javax/net/ssl/provider/MacAlgorithm.java jce/gnu/javax/net/ssl/provider/MacException.java jce/gnu/javax/net/ssl/provider/MaxFragmentLength.java jce/gnu/javax/net/ssl/provider/OutputSecurityParameters.java jce/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java jce/gnu/javax/net/ssl/provider/ProtocolVersion.java jce/gnu/javax/net/ssl/provider/Random.java jce/gnu/javax/net/ssl/provider/Record.java jce/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java jce/gnu/javax/net/ssl/provider/SSLContextImpl.java jce/gnu/javax/net/ssl/provider/SSLEngineImpl.java jce/gnu/javax/net/ssl/provider/SSLHMac.java jce/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java jce/gnu/javax/net/ssl/provider/SSLRandom.java jce/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java jce/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java jce/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java jce/gnu/javax/net/ssl/provider/SSLSocketImpl.java jce/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java jce/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java jce/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java jce/gnu/javax/net/ssl/provider/ServerDHParams.java jce/gnu/javax/net/ssl/provider/ServerHandshake.java jce/gnu/javax/net/ssl/provider/ServerHello.java jce/gnu/javax/net/ssl/provider/ServerHelloBuilder.java jce/gnu/javax/net/ssl/provider/ServerHelloDone.java jce/gnu/javax/net/ssl/provider/ServerKeyExchange.java jce/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java jce/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java jce/gnu/javax/net/ssl/provider/ServerNameList.java jce/gnu/javax/net/ssl/provider/ServerPSKParameters.java jce/gnu/javax/net/ssl/provider/ServerRSAParams.java jce/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java jce/gnu/javax/net/ssl/provider/SessionImpl.java jce/gnu/javax/net/ssl/provider/Signature.java jce/gnu/javax/net/ssl/provider/SignatureAlgorithm.java jce/gnu/javax/net/ssl/provider/SimpleSessionContext.java jce/gnu/javax/net/ssl/provider/TLSHMac.java jce/gnu/javax/net/ssl/provider/TLSRandom.java jce/gnu/javax/net/ssl/provider/TruncatedHMAC.java jce/gnu/javax/net/ssl/provider/TrustedAuthorities.java jce/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java jce/gnu/javax/net/ssl/provider/Util.java jce/gnu/javax/net/ssl/provider/X500PrincipalList.java jce/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java jce/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java jce/javax/net/VanillaServerSocketFactory.java jce/javax/net/VanillaSocketFactory.java jce/javax/net/ssl/TrivialHostnameVerifier.java rt/gnu/java/util/Base64.java
diffstat 114 files changed, 24679 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Jun 27 11:50:52 2007 -0400
+++ b/ChangeLog	Wed Jun 27 12:37:11 2007 -0400
@@ -1,3 +1,119 @@
+2006-06-37  Lillian Angel  <langel@redhat.com>
+
+	* Makefile.am: Added to ICEDTEA_COPY_DIRS and ICEDTEA_COPY_SRC
+	* Makefile.in: Regenerated.
+	* jce/gnu/javax/net/ssl/AbstractSessionContext.java,
+	jce/gnu/javax/net/ssl/EntropySource.java,
+	jce/gnu/javax/net/ssl/NullManagerParameters.java,
+	jce/gnu/javax/net/ssl/PreSharedKeyManager.class,
+	jce/gnu/javax/net/ssl/PreSharedKeyManager.java,
+	jce/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java,
+	jce/gnu/javax/net/ssl/PrivateCredentials.java,
+	jce/gnu/javax/net/ssl/SRPManagerParameters.java,
+	jce/gnu/javax/net/ssl/SRPTrustManager.java,
+	jce/gnu/javax/net/ssl/SSLCipherSuite.java,
+	jce/gnu/javax/net/ssl/SSLProtocolVersion.java,
+	jce/gnu/javax/net/ssl/SSLRecordHandler.java,
+	jce/gnu/javax/net/ssl/Session.java,
+	jce/gnu/javax/net/ssl/SessionStoreException.java,
+	jce/gnu/javax/net/ssl/StaticTrustAnchors.java,
+	jce/gnu/javax/net/ssl/provider/AbstractHandshake.java,
+	jce/gnu/javax/net/ssl/provider/Alert.java,
+	jce/gnu/javax/net/ssl/provider/AlertException.java,
+	jce/gnu/javax/net/ssl/provider/Builder.java,
+	jce/gnu/javax/net/ssl/provider/Certificate.java,
+	jce/gnu/javax/net/ssl/provider/CertificateBuilder.java,
+	jce/gnu/javax/net/ssl/provider/CertificateRequest.java,
+	jce/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java,
+	jce/gnu/javax/net/ssl/provider/CertificateStatusRequest.java,
+	jce/gnu/javax/net/ssl/provider/CertificateStatusType.java,
+	jce/gnu/javax/net/ssl/provider/CertificateType.java,
+	jce/gnu/javax/net/ssl/provider/CertificateURL.java,
+	jce/gnu/javax/net/ssl/provider/CertificateVerify.java,
+	jce/gnu/javax/net/ssl/provider/CipherAlgorithm.java,
+	jce/gnu/javax/net/ssl/provider/CipherSuite.java,
+	jce/gnu/javax/net/ssl/provider/CipherSuiteList.java,
+	jce/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java,
+	jce/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java,
+	jce/gnu/javax/net/ssl/provider/ClientHandshake.java,
+	jce/gnu/javax/net/ssl/provider/ClientHello.java,
+	jce/gnu/javax/net/ssl/provider/ClientHelloBuilder.java,
+	jce/gnu/javax/net/ssl/provider/ClientHelloV2.java,
+	jce/gnu/javax/net/ssl/provider/ClientKeyExchange.java,
+	jce/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java,
+	jce/gnu/javax/net/ssl/provider/ClientPSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/CompressionMethod.java,
+	jce/gnu/javax/net/ssl/provider/CompressionMethodList.java,
+	jce/gnu/javax/net/ssl/provider/Constructed.java,
+	jce/gnu/javax/net/ssl/provider/ContentType.java,
+	jce/gnu/javax/net/ssl/provider/Debug.java,
+	jce/gnu/javax/net/ssl/provider/DelegatedTask.java,
+	jce/gnu/javax/net/ssl/provider/DiffieHellman.java,
+	jce/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java,
+	jce/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java,
+	jce/gnu/javax/net/ssl/provider/ExchangeKeys.java,
+	jce/gnu/javax/net/ssl/provider/Extension.java,
+	jce/gnu/javax/net/ssl/provider/ExtensionList.java,
+	jce/gnu/javax/net/ssl/provider/Finished.java,
+	jce/gnu/javax/net/ssl/provider/Handshake.java,
+	jce/gnu/javax/net/ssl/provider/HelloRequest.java,
+	jce/gnu/javax/net/ssl/provider/InputSecurityParameters.java,
+	jce/gnu/javax/net/ssl/provider/Jessie.class,
+	jce/gnu/javax/net/ssl/provider/Jessie.java,
+	jce/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java,
+	jce/gnu/javax/net/ssl/provider/MacAlgorithm.java,
+	jce/gnu/javax/net/ssl/provider/MacException.java,
+	jce/gnu/javax/net/ssl/provider/MaxFragmentLength.java,
+	jce/gnu/javax/net/ssl/provider/OutputSecurityParameters.java,
+	jce/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java,
+	jce/gnu/javax/net/ssl/provider/ProtocolVersion.java,
+	jce/gnu/javax/net/ssl/provider/Random.java,
+	jce/gnu/javax/net/ssl/provider/Record.java,
+	jce/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java,
+	jce/gnu/javax/net/ssl/provider/SSLContextImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLEngineImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLHMac.java,
+	jce/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLRandom.java,
+	jce/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLSocketImpl.java,
+	jce/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java,
+	jce/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java,
+	jce/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/ServerDHParams.java,
+	jce/gnu/javax/net/ssl/provider/ServerHandshake.java,
+	jce/gnu/javax/net/ssl/provider/ServerHello.java,
+	jce/gnu/javax/net/ssl/provider/ServerHelloBuilder.java,
+	jce/gnu/javax/net/ssl/provider/ServerHelloDone.java,
+	jce/gnu/javax/net/ssl/provider/ServerKeyExchange.java,
+	jce/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java,
+	jce/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java,
+	jce/gnu/javax/net/ssl/provider/ServerNameList.java,
+	jce/gnu/javax/net/ssl/provider/ServerPSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/ServerRSAParams.java,
+	jce/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java,
+	jce/gnu/javax/net/ssl/provider/SessionImpl.java,
+	jce/gnu/javax/net/ssl/provider/Signature.java,
+	jce/gnu/javax/net/ssl/provider/SignatureAlgorithm.java,
+	jce/gnu/javax/net/ssl/provider/SimpleSessionContext.java,
+	jce/gnu/javax/net/ssl/provider/TLSHMac.java,
+	jce/gnu/javax/net/ssl/provider/TLSRandom.java,
+	jce/gnu/javax/net/ssl/provider/TruncatedHMAC.java,
+	jce/gnu/javax/net/ssl/provider/TrustedAuthorities.java,
+	jce/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java,
+	jce/gnu/javax/net/ssl/provider/Util.java,
+	jce/gnu/javax/net/ssl/provider/X500PrincipalList.java,
+	jce/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java,
+	jce/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java,
+	jce/javax/net/VanillaServerSocketFactory.java,
+	jce/javax/net/VanillaSocketFactory.java,
+	jce/javax/net/ssl/TrivialHostnameVerifier.java,
+	rt/gnu/java/util/Base64.java: New file
+
 2007-06-27  Lillian Angel  <langel@redhat.com>
 
 	* Makefile.am: Added new rt dirs.
--- a/Makefile.am	Wed Jun 27 11:50:52 2007 -0400
+++ b/Makefile.am	Wed Jun 27 12:37:11 2007 -0400
@@ -86,10 +86,11 @@
 	rt/com/sun/tools/jdi \
 	rt/java/util \
 	rt/com/sun/jmx/snmp/agent/ \
+	rt/javax/net/ssl/ \
 	rt/java/security/cert/ \
-        rt/javax/security/sasl/ \
-        rt/javax/security/auth/ \
-        rt/javax/security/auth/callback/
+	rt/javax/security/sasl/ \
+	rt/javax/security/auth/ \
+	rt/javax/security/auth/callback/
 
 ICEDTEA_COPY_SRC = \
 	com/sun/jmx/snmp/agent/SnmpMib.java \
@@ -217,6 +218,7 @@
 	com/sun/tools/jdi/LinkedHashMap.java \
 	java/util/Observer.java \
 	java/util/Timer.java \
+	java/security/cert/CertPathValidator.java \
 	javax/security/sasl/SaslException.java \
 	javax/security/sasl/AuthenticationException.java \
 	javax/security/auth/callback/NameCallback.java \
@@ -229,7 +231,24 @@
 	javax/security/auth/callback/ConfirmationCallback.java \
 	javax/security/auth/callback/LanguageCallback.java \
 	javax/security/auth/callback/TextInputCallback.java \
-	javax/security/auth/callback/TextOutputCallback.java
+	javax/security/auth/callback/TextOutputCallback.java \
+	javax/net/ssl/ManagerFactoryParameters.java \
+	javax/net/ssl/SSLSocket.java \
+	javax/net/ssl/SSLServerSocketFactory.java \
+	javax/net/ssl/SSLContextSpi.java \
+	javax/net/ssl/TrustManagerFactorySpi.java \
+	javax/net/ssl/SSLSocketFactory.java \
+	javax/net/ssl/SSLSessionBindingEvent.java \
+	javax/net/ssl/SSLSessionBindingListener.java \
+	javax/net/ssl/X509TrustManager.java \
+	javax/net/ssl/SSLServerSocket.java \
+	javax/net/ssl/HostnameVerifier.java \
+	javax/net/ssl/X509ExtendedKeyManager.java \
+	javax/net/ssl/KeyManagerFactorySpi.java \
+	javax/net/ssl/SSLException.java \
+	javax/net/ssl/SSLProtocolException.java \
+	javax/net/ssl/KeyManagerFactory.java \
+	javax/net/ssl/TrustManagerFactory.java
 
 if FOUND_ECJ
   JCOMPILER = $(ECJ) -nowarn
--- a/Makefile.in	Wed Jun 27 11:50:52 2007 -0400
+++ b/Makefile.in	Wed Jun 27 12:37:11 2007 -0400
@@ -246,10 +246,11 @@
 	rt/com/sun/tools/jdi \
 	rt/java/util \
 	rt/com/sun/jmx/snmp/agent/ \
+	rt/javax/net/ssl/ \
 	rt/java/security/cert/ \
-        rt/javax/security/sasl/ \
-        rt/javax/security/auth/ \
-        rt/javax/security/auth/callback/
+	rt/javax/security/sasl/ \
+	rt/javax/security/auth/ \
+	rt/javax/security/auth/callback/
 
 ICEDTEA_COPY_SRC = \
 	com/sun/jmx/snmp/agent/SnmpMib.java \
@@ -377,6 +378,7 @@
 	com/sun/tools/jdi/LinkedHashMap.java \
 	java/util/Observer.java \
 	java/util/Timer.java \
+	java/security/cert/CertPathValidator.java \
 	javax/security/sasl/SaslException.java \
 	javax/security/sasl/AuthenticationException.java \
 	javax/security/auth/callback/NameCallback.java \
@@ -389,7 +391,24 @@
 	javax/security/auth/callback/ConfirmationCallback.java \
 	javax/security/auth/callback/LanguageCallback.java \
 	javax/security/auth/callback/TextInputCallback.java \
-	javax/security/auth/callback/TextOutputCallback.java
+	javax/security/auth/callback/TextOutputCallback.java \
+	javax/net/ssl/ManagerFactoryParameters.java \
+	javax/net/ssl/SSLSocket.java \
+	javax/net/ssl/SSLServerSocketFactory.java \
+	javax/net/ssl/SSLContextSpi.java \
+	javax/net/ssl/TrustManagerFactorySpi.java \
+	javax/net/ssl/SSLSocketFactory.java \
+	javax/net/ssl/SSLSessionBindingEvent.java \
+	javax/net/ssl/SSLSessionBindingListener.java \
+	javax/net/ssl/X509TrustManager.java \
+	javax/net/ssl/SSLServerSocket.java \
+	javax/net/ssl/HostnameVerifier.java \
+	javax/net/ssl/X509ExtendedKeyManager.java \
+	javax/net/ssl/KeyManagerFactorySpi.java \
+	javax/net/ssl/SSLException.java \
+	javax/net/ssl/SSLProtocolException.java \
+	javax/net/ssl/KeyManagerFactory.java \
+	javax/net/ssl/TrustManagerFactory.java
 
 @FOUND_ECJ_FALSE@@FOUND_JAVAC_TRUE@JCOMPILER = $(JAVAC)
 @FOUND_ECJ_TRUE@JCOMPILER = $(ECJ) -nowarn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/AbstractSessionContext.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,288 @@
+/* AbstractSessionContext -- stores SSL sessions, possibly persistently.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import gnu.java.security.Requires;
+
+import gnu.javax.net.ssl.provider.SimpleSessionContext;
+
+import java.util.Enumeration;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPermission;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A skeletal implementation of {@link SSLSessionContext}. This class may
+ * be subclassed to add extended functionality to session contexts, such
+ * as by storing sessions in files on disk, or by sharing contexts
+ * across different JVM instances.
+ * 
+ * <p>In order to securely store sessions, along with private key data,
+ * the abstract methods {@lnk {@link #load(char[])} and {@link #store(char[])}
+ * come into play. When storing sessions, a session context implementation
+ * must pass this password to the {@link Session#prepare(char[])} method,
+ * before either writing the {@link java.io.Serializable} session to the
+ * underlying store, or getting the opaque {@link Session#privateData()}
+ * class from the session, and storing that.
+ * 
+ * <p>As a simple example, that writes sessions to some object output
+ * stream:
+ * 
+ * <pre>
+  char[] password = ...;
+  ObjectOutputStream out = ...;
+  ...
+  for (Session s : this)
+    {
+      s.prepare(password);
+      out.writeObject(s);
+    }</pre>
+ * 
+ * <p>The reverse must be done when deserializing sessions, by using the
+ * {@link Session#repair(char[])} method, possibly by first calling
+ * {@link Session#setPrivateData(java.io.Serializable)} with the read,
+ * opaque private data type. Thus an example of reading may be:
+ * 
+ * <pre>
+  char[] password = ...;
+  ObjectInputStream in = ...;
+  ...
+  while (hasMoreSessions(in))
+    {
+      Session s = (Session) in.readObject();
+      s.repair(password);
+      addToThisStore(s);
+    }</pre>
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class AbstractSessionContext implements SSLSessionContext
+{
+  protected long timeout;
+  private static Class<? extends AbstractSessionContext> 
+    implClass = SimpleSessionContext.class;
+
+  /**
+   * Create a new instance of a session context, according to the configured
+   * implementation class.
+   * 
+   * @return The new session context.
+   * @throws SSLException If an error occurs in creating the instance.
+   */
+  public static AbstractSessionContext newInstance () throws SSLException
+  {
+    try
+      {
+        return implClass.newInstance();
+      }
+    catch (IllegalAccessException iae)
+      {
+        throw new SSLException(iae);
+      }
+    catch (InstantiationException ie)
+      {
+        throw new SSLException(ie);
+      }
+  }
+
+  /**
+   * Reconfigure this instance to use a different session context
+   * implementation.
+   * 
+   * <p><strong>Note:</strong> this method requires that the caller have
+   * {@link SSLPermission} with target
+   * <code>gnu.javax.net.ssl.AbstractSessionContext</code> and action
+   * <code>setImplClass</code>.
+   * 
+   * @param clazz The new implementation class.
+   * @throws SecurityException If the caller does not have permission to
+   *  change the session context.
+   */
+  @Requires(permissionClass = SSLPermission.class,
+            target = "gnu.javax.net.ssl.AbstractSessionContext",
+            action = "setImplClass")
+  public static synchronized void setImplClass
+    (Class<? extends AbstractSessionContext> clazz)
+    throws SecurityException
+  {
+    SecurityManager sm = System.getSecurityManager ();
+    if (sm != null)
+      sm.checkPermission(new SSLPermission("gnu.javax.net.ssl.AbstractSessionContext",
+                                           "setImplClass"));
+    implClass = clazz;
+  }
+
+  /**
+   * @param timeout The initial session timeout.
+   */
+  protected AbstractSessionContext (final int timeout)
+  {
+    setSessionTimeout(timeout);
+  }
+
+  /**
+   * Fetch a saved session by its ID. This method will (possibly)
+   * deserialize and return the SSL session with that ID, or null if
+   * the requested session does not exist, or has expired.
+   *
+   * <p>Subclasses implementing this class <strong>must not</strong>
+   * perform any blocking operations in this method. If any blocking
+   * behavior is required, it must be done in the {@link load(char[])}
+   * method.
+   *
+   * @param sessionId The ID of the session to get.
+   * @return The found session, or null if no such session was found,
+   * or if that session has expired.
+   */
+  public final SSLSession getSession (byte[] sessionId)
+  {
+    Session s = implGet (sessionId);
+    if (s != null
+        && System.currentTimeMillis () - s.getLastAccessedTime () > timeout)
+      {
+        remove (sessionId);
+        return null;
+      }
+    return s;
+  }
+  
+  public final SSLSession getSession(String host, int port)
+  {
+    for (Enumeration e = getIds(); e.hasMoreElements(); )
+      {
+        byte[] id = (byte[]) e.nextElement();
+        SSLSession s = getSession(id);
+        if (s == null) // session expired.
+          continue;
+        String host2 = s.getPeerHost();
+        if (host == null)
+          {
+            if (host2 != null)
+              continue;
+          }
+        else if (!host.equals(host2))
+          continue;
+        int port2 = s.getPeerPort();
+        if (port != port2)
+          continue;
+        
+        // Else, a match.
+        return s;
+      }
+    
+    return null;
+  }
+  
+  /**
+   * To be implemented by subclasses. Subclasses do not need to check
+   * timeouts in this method.
+   * 
+   * @param sessionId The session ID.
+   * @return The session, or <code>null</code> if the requested session
+   *  was not found.
+   */
+  protected abstract Session implGet (byte[] sessionId);
+
+  public int getSessionTimeout()
+  {
+    return (int) (timeout / 1000);
+  }
+  
+  /**
+   * Load this session store from the underlying media, if supported
+   * by the implementation.
+   *
+   * @param password The password that protects the sensitive data in
+   * this store.
+   * @throws SessionStoreException If reading this store fails, such
+   * as when an I/O exception occurs, or if the password is incorrect.
+   */
+  public abstract void load (char[] password) throws SessionStoreException;
+
+  /**
+   * Add a new session to the store. The underlying implementation
+   * will add the session to its store, possibly overwriting any
+   * existing session with the same ID.
+   *
+   * <p>Subclasses implementing this class <strong>must not</strong>
+   * perform any blocking operations in this method. If any blocking
+   * behavior is required, it must be done in the {@link
+   * #store(char[])} method.
+   *
+   * @param session The session to add.
+   * @throws NullPointerException If the argument is null.
+   */
+  public abstract void put (Session session);
+
+  /**
+   * Remove a session from this store.
+   *
+   * <p>Subclasses implementing this class <strong>must not</strong>
+   * perform any blocking operations in this method. If any blocking
+   * behavior is required, it must be done in the {@link
+   * #store(char[])} method.
+   *
+   * @param sessionId The ID of the session to remove.
+   */
+  public abstract void remove (byte[] sessionId);
+
+  /**
+   * 
+   */
+  public final void setSessionTimeout(int seconds)
+  {
+    if (timeout < 0)
+      throw new IllegalArgumentException("timeout may not be negative");
+    this.timeout = (long) seconds * 1000;
+  }
+  
+  /**
+   * Commit this session store to the underlying media. For session
+   * store implementations that support saving sessions across
+   * invocations of the JVM, this method will save any sessions that
+   * have not expired to some persistent media, so they may be loaded
+   * and used again later.
+   *
+   * @param password The password that will protect the sensitive data
+   * in this store.
+   */
+  public abstract void store (char[] password) throws SessionStoreException;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/EntropySource.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,62 @@
+/* EntropySource.java -- a source of random bits.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+/**
+ * A generic interface for adding random bytes to an entropy pool.
+ */
+public interface EntropySource
+{
+
+  /**
+   * Returns the estimated quality of this source. This value should be
+   * between 0 and 100 (the running quality is computed as a percentage,
+   * 100 percent being perfect-quality).
+   *
+   * @return The quality.
+   */
+  double quality();
+
+  /**
+   * Returns a new buffer with the next random bytes to add.
+   *
+   * @return The next random bytes.
+   */
+  byte[] nextBytes();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/NullManagerParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,56 @@
+/* NullManagerParameters.java -- parameters for empty managers.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * This empty class can be used to initialize {@link
+ * javax.net.ssl.KeyManagerFactory} and {@link
+ * javax.net.ssl.TrustManagerFactory} instances for the ``JessieX509''
+ * algorithm, for cases when no keys or trusted certificates are
+ * desired or needed.
+ *
+ * <p>This is the default manager parameters object used in {@link
+ * javax.net.ssl.KeyManagerFactory} instances if no key stores are
+ * specified through security properties.
+ */
+public final class NullManagerParameters implements ManagerFactoryParameters
+{
+}
Binary file jce/gnu/javax/net/ssl/PreSharedKeyManager.class has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/PreSharedKeyManager.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,54 @@
+/* PreSharedKeyManager.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.security.KeyManagementException;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface PreSharedKeyManager extends KeyManager
+{
+  SecretKey getKey(String name) throws KeyManagementException;
+  
+  String chooseIdentityHint();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,83 @@
+/* PreSharedKeyManagerParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class PreSharedKeyManagerParameters
+  implements ManagerFactoryParameters
+{
+  private final LinkedHashMap<String, SecretKey> keys;
+  
+  public PreSharedKeyManagerParameters()
+  {
+    keys = new LinkedHashMap<String, SecretKey>();
+  }
+
+  public SecretKey getKey(String name)
+  {
+    name.getClass();
+    return keys.get(name);
+  }
+  
+  public void putKey(String name, SecretKey key)
+  {
+    name.getClass();
+    key.getClass();
+    keys.put(name, key);
+  }
+  
+  public boolean removeKey(String name)
+  {
+    name.getClass();
+    return keys.remove(name) != null;
+  }
+  
+  public Iterator<String> identities()
+  {
+    return keys.keySet().iterator();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/PrivateCredentials.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,361 @@
+/* PrivateCredentials.java -- private key/certificate pairs.
+   Copyright (C) 2006, 2007  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.math.BigInteger;
+
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.pad.WrongPaddingException;
+
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.util.Base64;
+
+/**
+ * An instance of a manager factory parameters for holding a single
+ * certificate/private key pair, encoded in PEM format.
+ */
+public class PrivateCredentials implements ManagerFactoryParameters
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  public static final String BEGIN_DSA = "-----BEGIN DSA PRIVATE KEY";
+  public static final String END_DSA   = "-----END DSA PRIVATE KEY";
+  public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY";
+  public static final String END_RSA   = "-----END RSA PRIVATE KEY";
+
+  private List<PrivateKey> privateKeys;
+  private List<X509Certificate[]> certChains;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public PrivateCredentials()
+  {
+    privateKeys = new LinkedList<PrivateKey>();
+    certChains = new LinkedList<X509Certificate[]>();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void add(InputStream certChain, InputStream privateKey)
+    throws CertificateException, InvalidKeyException, InvalidKeySpecException,
+           IOException, NoSuchAlgorithmException, WrongPaddingException
+  {
+    CertificateFactory cf = CertificateFactory.getInstance("X.509");
+    Collection<? extends Certificate> certs = cf.generateCertificates(certChain);
+    X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]);
+
+    String alg = null;
+    String line = readLine(privateKey);
+    String finalLine = null;
+    if (line.startsWith(BEGIN_DSA))
+      {
+        alg = "DSA";
+        finalLine = END_DSA;
+      }
+    else if (line.startsWith(BEGIN_RSA))
+      {
+        alg = "RSA";
+        finalLine = END_RSA;
+      }
+    else
+      throw new IOException("Unknown private key type.");
+
+    boolean encrypted = false;
+    String cipher = null;
+    String salt = null;
+    StringBuffer base64 = new StringBuffer();
+    while (true)
+      {
+        line = readLine(privateKey);
+        if (line == null)
+          throw new EOFException("premature end-of-file");
+        else if (line.startsWith("Proc-Type: 4,ENCRYPTED"))
+          encrypted = true;
+        else if (line.startsWith("DEK-Info: "))
+          {
+            int i = line.indexOf(',');
+            if (i < 0)
+              cipher = line.substring(10).trim();
+            else
+              {
+                cipher = line.substring(10, i).trim();
+                salt = line.substring(i + 1).trim();
+              }
+          }
+        else if (line.startsWith(finalLine))
+          break;
+        else if (line.length() > 0)
+          {
+            base64.append(line);
+            base64.append(System.getProperty("line.separator"));
+          }
+      }
+
+    byte[] enckey = Base64.decode(base64.toString());
+    if (encrypted)
+      {
+        enckey = decryptKey(enckey, cipher, toByteArray(salt));
+      }
+
+    DERReader der = new DERReader(enckey);
+    if (der.read().getTag() != DER.SEQUENCE)
+      throw new IOException("malformed DER sequence");
+    der.read(); // version
+
+    KeyFactory kf = KeyFactory.getInstance(alg);
+    KeySpec spec = null;
+    if (alg.equals("DSA"))
+      {
+        BigInteger p = (BigInteger) der.read().getValue();
+        BigInteger q = (BigInteger) der.read().getValue();
+        BigInteger g = (BigInteger) der.read().getValue();
+        der.read(); // y
+        BigInteger x = (BigInteger) der.read().getValue();
+        spec = new DSAPrivateKeySpec(x, p, q, g);
+      }
+    else
+      {
+        spec = new RSAPrivateCrtKeySpec(
+          (BigInteger) der.read().getValue(),  // modulus
+          (BigInteger) der.read().getValue(),  // pub exponent
+          (BigInteger) der.read().getValue(),  // priv expenent
+          (BigInteger) der.read().getValue(),  // prime p
+          (BigInteger) der.read().getValue(),  // prime q
+          (BigInteger) der.read().getValue(),  // d mod (p-1)
+          (BigInteger) der.read().getValue(),  // d mod (q-1)
+          (BigInteger) der.read().getValue()); // coefficient
+      }
+
+    privateKeys.add(kf.generatePrivate(spec));
+    certChains.add(chain);
+  }
+
+  public List<PrivateKey> getPrivateKeys()
+  {
+    if (isDestroyed())
+      {
+        throw new IllegalStateException("this object is destroyed");
+      }
+    return privateKeys;
+  }
+
+  public List<X509Certificate[]> getCertChains()
+  {
+    return certChains;
+  }
+
+  public void destroy()
+  {
+    privateKeys.clear();
+    privateKeys = null;
+  }
+
+  public boolean isDestroyed()
+  {
+    return (privateKeys == null);
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private String readLine(InputStream in) throws IOException
+  {
+    boolean eol_is_cr = System.getProperty("line.separator").equals("\r");
+    StringBuffer str = new StringBuffer();
+    while (true)
+      {
+        int i = in.read();
+        if (i == -1)
+          {
+            if (str.length() > 0)
+              break;
+            else
+              return null;
+          }
+        else if (i == '\r')
+          {
+            if (eol_is_cr)
+              break;
+          }
+        else if (i == '\n')
+          break;
+        else
+          str.append((char) i);
+      }
+    return str.toString();
+  }
+
+  private byte[] decryptKey(byte[] ct, String cipher, byte[] salt)
+    throws IOException, InvalidKeyException, WrongPaddingException
+  {
+    byte[] pt = new byte[ct.length];
+    IMode mode = null;
+    if (cipher.equals("DES-EDE3-CBC"))
+      {
+        mode = ModeFactory.getInstance("CBC", "TripleDES", 8);
+        HashMap attr = new HashMap();
+        attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 24));
+        attr.put(IMode.IV, salt);
+        attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
+        mode.init(attr);
+      }
+    else if (cipher.equals("DES-CBC"))
+      {
+        mode = ModeFactory.getInstance("CBC", "DES", 8);
+        HashMap attr = new HashMap();
+        attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 8));
+        attr.put(IMode.IV, salt);
+        attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
+        mode.init(attr);
+      }
+    else
+      throw new IllegalArgumentException("unknown cipher: " + cipher);
+
+    for (int i = 0; i < ct.length; i += 8)
+      mode.update(ct, i, pt, i);
+
+    int pad = pt[pt.length-1];
+    if (pad < 1 || pad > 8)
+      throw new WrongPaddingException();
+    for (int i = pt.length - pad; i < pt.length; i++)
+      {
+        if (pt[i] != pad)
+          throw new WrongPaddingException();
+      }
+
+    byte[] result = new byte[pt.length - pad];
+    System.arraycopy(pt, 0, result, 0, result.length);
+    return result;
+  }
+
+  private byte[] deriveKey(byte[] salt, int keylen)
+    throws IOException
+  {
+    CallbackHandler passwordHandler = new ConsoleCallbackHandler();
+    try
+      {
+        Class c = Class.forName(Security.getProperty("jessie.password.handler"));
+        passwordHandler = (CallbackHandler) c.newInstance();
+      }
+    catch (Exception x) { }
+
+    PasswordCallback passwdCallback =
+      new PasswordCallback("Enter PEM passphrase: ", false);
+    try
+      {
+        passwordHandler.handle(new Callback[] { passwdCallback });
+      }
+    catch (UnsupportedCallbackException uce)
+      {
+        throw new IOException("specified handler cannot handle passwords");
+      }
+    char[] passwd = passwdCallback.getPassword();
+
+    IMessageDigest md5 = HashFactory.getInstance("MD5");
+    byte[] key = new byte[keylen];
+    int count = 0;
+    while (count < keylen)
+      {
+        for (int i = 0; i < passwd.length; i++)
+          md5.update((byte) passwd[i]);
+        md5.update(salt, 0, salt.length);
+        byte[] digest = md5.digest();
+        int len = Math.min(digest.length, keylen - count);
+        System.arraycopy(digest, 0, key, count, len);
+        count += len;
+        if (count >= keylen)
+          break;
+        md5.reset();
+        md5.update(digest, 0, digest.length);
+      }
+    passwdCallback.clearPassword();
+    return key;
+  }
+
+  private byte[] toByteArray(String hex)
+  {
+    hex = hex.toLowerCase();
+    byte[] buf = new byte[hex.length() / 2];
+    int j = 0;
+    for (int i = 0; i < buf.length; i++)
+      {
+        buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) |
+                          Character.digit(hex.charAt(j++), 16));
+      }
+    return buf;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SRPManagerParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,81 @@
+/* SRPManagerParameters.java -- Wrapper for SRP PasswordFile.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import gnu.javax.crypto.sasl.srp.PasswordFile;
+
+/**
+ * Instances of this class are used to initialize {@link
+ * javax.net.ssl.TrustManagerFactory} instances for the ``SRP'' algorithm.
+ */
+public class SRPManagerParameters implements ManagerFactoryParameters
+{
+
+  // Field.
+  // -------------------------------------------------------------------------
+
+  private final PasswordFile file;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Initializes these parameters with the specified SRP password file.
+   *
+   * @param file The SRP password file object.
+   * @throws NullPointerException if <i>file</i> is <code>null</code>.
+   */
+  public SRPManagerParameters(PasswordFile file)
+  {
+    if (file == null)
+      {
+        throw new NullPointerException();
+      }
+    this.file = file;
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public PasswordFile getPasswordFile()
+  {
+    return file;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SRPTrustManager.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,99 @@
+/* SRPTrustManager.java -- interface to SRP trust managers.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import gnu.javax.crypto.sasl.srp.PasswordFile;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import javax.net.ssl.TrustManager;
+
+/**
+ * A trust manager for secure remote password (SRP) key exchange cipher
+ * suites. This is a read-only interface to the {@link
+ * gnu.crypto.sasl.srp.PasswordFile} class, with convenience methods to
+ * generate session key pairs.
+ */
+public interface SRPTrustManager extends TrustManager
+{
+
+  // Methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Tests if the configured password file contains the specified user name.
+   *
+   * @param user The user name.
+   * @return True if the password file has an entry for <i>user</i>
+   */
+  boolean contains(String user);
+
+  /**
+   * Create and return a session SRP key pair for the given user name.
+   *
+   * @param user The user name to generate the key pair for.
+   * @return The session key pair, or <code>null</code> if there is no
+   *   entry for <i>user</i>.
+   */
+  KeyPair getKeyPair(String user);
+
+  /**
+   * Returns the salt value for the given user.
+   *
+   * @param user The user name.
+   * @return The salt for <i>user</i>'s entry, or <code>null</code>.
+   */
+  byte[] getSalt(String user);
+
+  /**
+   * Returns the password verifier for the given user.
+   *
+   * @param user The user name.
+   * @return <i>user</i>'s password verifier, or <code>null</code>.
+   */
+  BigInteger getVerifier(String user);
+
+  /**
+   * Returns a reference to the SRP {@link PasswordFile} used by this
+   * {@link TrustManager}.
+   *
+   * @return a reference to the SRP password file in use.
+   */
+  PasswordFile getPasswordFile();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SSLCipherSuite.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,142 @@
+/* SSLCipherSuite.java -- an SSL cipher suite.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import gnu.java.security.Engine;
+
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * An SSL cipher suite.
+ */
+public abstract class SSLCipherSuite
+{
+  private static final String SERVICE = "SSLCipherSuite";
+  private final String algorithm;
+  private final byte[] id;
+  private final SSLProtocolVersion version;
+  private Provider provider;
+  
+  protected SSLCipherSuite (final String algorithm, final byte[] id,
+                            final SSLProtocolVersion version)
+  {
+    this.algorithm = algorithm;
+    if (id.length != 2)
+      throw new IllegalArgumentException ("cipher suite ID must be two bytes");
+    this.id = (byte[]) id.clone ();
+    this.version = version;
+  }
+  
+  public static final SSLCipherSuite getInstance (SSLProtocolVersion version, byte[] id)
+    throws NoSuchAlgorithmException
+  {
+    return getInstance (version + "-" + ((id[0] & 0xFF) + "/" + (id[1] & 0xFF)));
+  }
+  
+  public static final SSLCipherSuite getInstance (SSLProtocolVersion version,
+                                                  byte[] id, Provider provider)
+    throws NoSuchAlgorithmException
+  {
+    return getInstance (version + "-" + (id[0] & 0xFF) + "/" + (id[1] & 0xFF), provider);
+  }
+  
+  public static final SSLCipherSuite getInstance (String name)
+    throws NoSuchAlgorithmException
+  {
+    Provider[] providers = Security.getProviders ();
+    for (int i = 0; i < providers.length; i++)
+      {
+        try
+          {
+            return getInstance (name, providers[i]);
+          }
+        catch (NoSuchAlgorithmException nsae)
+          {
+            // Ignore.
+          }
+      }
+      
+    throw new NoSuchAlgorithmException (SERVICE + ": " + name);
+  }
+  
+  public static final SSLCipherSuite getInstance (String name, Provider provider)
+    throws NoSuchAlgorithmException
+  {
+    SSLCipherSuite suite = null;
+    try
+      {
+        suite = (SSLCipherSuite) Engine.getInstance (SERVICE, name, provider);
+        suite.provider = provider;
+      }
+    catch (InvocationTargetException ite)
+      {
+        // XXX
+        NoSuchAlgorithmException nsae = new NoSuchAlgorithmException (name);
+        nsae.initCause (ite);
+        throw nsae;
+      }
+    return suite;
+  }
+  
+  public final String getAlgorithm ()
+  {
+    return algorithm;
+  }
+  
+  public final byte[] getId ()
+  {
+    return (byte[]) id.clone ();
+  }
+  
+  public final Provider getProvider ()
+  {
+    return provider;
+  }
+  
+  public final SSLProtocolVersion getProtocolVersion ()
+  {
+    return version;
+  }
+  
+  public abstract void encipher (ByteBuffer in, ByteBuffer out);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SSLProtocolVersion.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,54 @@
+/* SSLProtocolVersion.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+public enum SSLProtocolVersion
+{
+  SSLv3 (3, 0),
+  TLSv1 (3, 1);
+
+  public final int major;
+  public final int minor;
+
+  private SSLProtocolVersion (int major, int minor)
+  {
+    this.major = major;
+    this.minor = minor;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SSLRecordHandler.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,101 @@
+/* SSLRecordHandler.java -- a class that handles SSL record layer messages.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+public abstract class SSLRecordHandler
+{
+  private final byte contentType;
+
+  /**
+   * Create a new record handler for the given content type.
+   */
+  protected SSLRecordHandler (final byte contentType)
+  {
+    this.contentType = contentType;
+  }
+
+  /**
+   * Handle an SSL record layer message, encapsulated in the supplied
+   * input buffer, and writing any output bytes to the output
+   * buffer. The input buffer is always only limited to the bytes that
+   * encapsulate the <em>fragment</em> of the record layer message
+   * &mdash; that is, the content-type, version, and length fields are
+   * not present in the input buffer, and the limit of the input
+   * buffer is always only as large as the fragment. If the message
+   * being read is not contained entirely within the given buffer,
+   * then the implementation should cache the bytes read as input, and
+   * wait until subsequent calls finish the object being read.
+   *
+   * <p>Technically, we expect only APPLICATION messages to ever
+   * produce output, but do suppose that extensions to the SSL
+   * protocol could allow other channels that produce output.
+   *
+   * @param input The input buffer.
+   * @param output The output buffer.
+   */
+  public abstract void handle (final ByteBuffer input,
+                               final ByteBuffer output)
+    throws SSLException;
+
+  /**
+   * Returns the record layer content type that this handler is for.
+   *
+   * @return The content type value.
+   */
+  public final byte contentType ()
+  {
+    return contentType;
+  }
+
+  public boolean equals (final Object o)
+  {
+    if (!(o instanceof SSLRecordHandler))
+      return false;
+    return ((SSLRecordHandler) o).contentType == contentType;
+  }
+
+  public int hashCode ()
+  {
+    return contentType & 0xFF;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/Session.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,364 @@
+/* SessionImpl.java -- concrete definition of SSLSession.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import java.io.Serializable;
+
+import java.security.Principal;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Set;
+
+import javax.crypto.SealedObject;
+import javax.net.ssl.SSLException;
+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.security.cert.X509Certificate;
+
+/**
+ * A concrete implementation of the {@link SSLSession} interface. This
+ * class is provided to allow pluggable {@link AbstractSessionContext}
+ * implementations.
+ */
+public abstract class Session implements SSLSession, Serializable
+{
+  protected final long creationTime;
+  protected long lastAccessedTime;
+  protected int applicationBufferSize;
+  
+  protected ID sessionId;
+  protected Certificate[] localCerts;
+  protected Certificate[] peerCerts;
+  protected X509Certificate[] peerCertChain;
+  protected String peerHost;
+  protected int peerPort;
+  protected boolean peerVerified;
+  protected HashMap<String,Object> values;
+  protected boolean valid;
+  protected boolean truncatedMac = false;
+  transient protected SecureRandom random;
+  transient protected SSLSessionContext context;
+
+  protected Session()
+  {
+    creationTime = System.currentTimeMillis();
+    values = new HashMap<String, Object>();
+    applicationBufferSize = (1 << 14);
+  }
+
+  public void access()
+  {
+    lastAccessedTime = System.currentTimeMillis ();
+  }
+
+  public int getApplicationBufferSize()
+  {
+    return applicationBufferSize;
+  }
+
+  public String getCipherSuite()
+  {
+    return null;
+  }
+
+  public long getCreationTime()
+  {
+    return creationTime;
+  }
+
+  public byte[] getId()
+  {
+    return sessionId.id();
+  }
+
+  public ID id()
+  {
+    return sessionId;
+  }
+
+  public long getLastAccessedTime()
+  {
+    return lastAccessedTime;
+  }
+
+  public Certificate[] getLocalCertificates()
+  {
+    if (localCerts == null)
+      return null;
+    return (Certificate[]) localCerts.clone();
+  }
+
+  public Principal getLocalPrincipal()
+  {
+    if (localCerts != null)
+      {
+        if (localCerts[0] instanceof java.security.cert.X509Certificate)
+          return ((java.security.cert.X509Certificate) localCerts[0]).getSubjectDN();
+      }
+    return null;
+  }
+  
+  public int getPacketBufferSize()
+  {
+    return applicationBufferSize + 2048;
+  }
+  
+  public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
+  {
+    if (!peerVerified)
+      throw new SSLPeerUnverifiedException("peer not verified");
+    if (peerCerts == null)
+      return null;
+    return (Certificate[]) peerCerts.clone();
+  }
+
+  public X509Certificate[] getPeerCertificateChain()
+    throws SSLPeerUnverifiedException
+  {
+    if (!peerVerified)
+      throw new SSLPeerUnverifiedException("peer not verified");
+    if (peerCertChain == null)
+      return null;
+    return (X509Certificate[]) peerCertChain.clone();
+  }
+  
+  public String getPeerHost()
+  {
+    return peerHost;
+  }
+  
+  public int getPeerPort()
+  {
+    return peerPort;
+  }
+  
+  public Principal getPeerPrincipal() throws SSLPeerUnverifiedException
+  {
+    if (!peerVerified)
+      throw new SSLPeerUnverifiedException("peer not verified");
+    if (peerCertChain == null)
+      return null;
+    return peerCertChain[0].getSubjectDN();
+  }
+  
+  public SSLSessionContext getSessionContext()
+  {
+    return context;
+  }
+  
+  public String[] getValueNames()
+  {
+    Set<String> keys = this.values.keySet();
+    return keys.toArray(new String[keys.size()]);
+  }
+  
+  public Object getValue(String name)
+  {
+    return values.get(name);
+  }
+  
+  public void invalidate()
+  {
+    valid = false;
+  }
+  
+  public boolean isValid()
+  {
+    return valid;
+  }
+  
+  public void putValue(String name, Object value)
+  {
+    values.put(name, value);
+    try
+      {
+        if (value instanceof SSLSessionBindingListener)
+          ((SSLSessionBindingListener) value).valueBound
+            (new SSLSessionBindingEvent(this, name));
+      }
+    catch (Exception x)
+      {
+      }
+  }
+  
+  public void removeValue(String name)
+  {
+    Object value = values.remove(name);
+    try
+      {
+        if (value instanceof SSLSessionBindingListener)
+          ((SSLSessionBindingListener) value).valueUnbound
+            (new SSLSessionBindingEvent(this, name));
+      }
+    catch (Exception x)
+      {
+      }   
+  }
+  
+  public final boolean isTruncatedMac()
+  {
+    return truncatedMac;
+  }
+
+  /**
+   * Prepare this session for serialization. Private data will be encrypted
+   * with the given password, and this object will then be ready to be
+   * serialized.
+   * 
+   * @param password The password to protect this session with.
+   * @throws SSLException If encrypting this session's private data fails.
+   */
+  public abstract void prepare (char[] password) throws SSLException;
+  
+  /**
+   * Repair this session's private data after deserialization. This method
+   * will decrypt this session's private data, and prepare the session for
+   * use in new SSL connections.
+   * 
+   * @param password The password to decrypt the private data with.
+   * @throws SSLException
+   */
+  public abstract void repair(char[] password) throws SSLException;
+  
+  /**
+   * Get the private data of this session. This method may only be called
+   * after first calling {@link #prepare(char[])}.
+   * 
+   * @return The sealed private data.
+   * @throws SSLException If the private data have not been sealed.
+   */
+  public abstract SealedObject privateData() throws SSLException;
+  
+  /**
+   * Set the private data of this session.
+   * @param data
+   * @throws SSLException
+   */
+  public abstract void setPrivateData(SealedObject data) throws SSLException;
+
+  // Inner classes.
+  // -------------------------------------------------------------------------
+
+  /**
+   * An SSL or TLS session ID.
+   */
+  public static final class ID implements Comparable, Serializable
+  {
+
+    // Fields.
+    // -----------------------------------------------------------------------
+
+    static final long serialVersionUID = 7887036954666565936L;
+    /** The ID itself. */
+    private final byte[] id;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    /**
+     * Creates a new ID.
+     *
+     * @param id The ID. The array is cloned.
+     */
+    public ID (final byte[] id)
+    {
+      if (id.length > 32)
+        throw new IllegalArgumentException ("session ID's are limited to 32 bytes");
+      this.id = (byte[]) id.clone();
+    }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public byte[] id()
+    {
+      return (byte[]) id.clone();
+    }
+
+    public boolean equals(Object other)
+    {
+      if (!(other instanceof ID))
+        return false;
+      return Arrays.equals(id, ((ID) other).id);
+    }
+
+    public int hashCode()
+    {
+      int code = 0;
+      for (int i = 0; i < id.length; i++)
+        code |= (id[i] & 0xFF) << ((i & 3) << 3);
+      return code;
+    }
+
+    public int compareTo(Object other)
+    {
+      byte[] id2 = ((ID) other).id;
+      if (id.length != id2.length)
+        return (id.length < id2.length) ? -1 : 1;
+      for (int i = 0; i < id.length; i++)
+        {
+          if ((id[i] & 0xFF) < (id2[i] & 0xFF))
+            return -1;
+          if ((id[i] & 0xFF) > (id2[i] & 0xFF))
+            return 1;
+        }
+      return 0;
+    }
+
+    public String toString()
+    {
+      StringBuffer str = new StringBuffer (3 * id.length + 1);
+      for (int i = 0; i < id.length; i++)
+        {
+          int x = id[i] & 0xFF;
+          str.append (Character.forDigit ((x >>> 4) & 0xF, 16));
+          str.append (Character.forDigit (x & 0xF, 16));
+          if (i != id.length - 1)
+            str.append (':');
+        }
+      return str.toString ();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/SessionStoreException.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,59 @@
+/* SessionStoreException.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import javax.net.ssl.SSLException;
+
+public class SessionStoreException extends SSLException
+{
+  public SessionStoreException (final String message)
+  {
+    super (message);
+  }
+  
+  public SessionStoreException (final String message, final Throwable cause)
+  {
+    super (message, cause);
+  }
+  
+  public SessionStoreException (final Throwable cause)
+  {
+    super (cause);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/StaticTrustAnchors.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,1942 @@
+/* StaticTrustAnchors.java -- static list of CA certificates.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import java.util.LinkedList;
+
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * This class implements a simple set of trust anchors suitable for
+ * initializing a TrustManagerFactory for the "JessieX509" algorithm.
+ *
+ * <p>The important field of this class is the {@link #CA_CERTS}
+ * constant, which contains an array of commonly accepted CA
+ * certificates.
+ */
+public class StaticTrustAnchors implements ManagerFactoryParameters
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private X509Certificate[] certs;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public StaticTrustAnchors(X509Certificate[] certs)
+  {
+    this.certs = (X509Certificate[]) certs.clone();
+  }
+
+  // Class method.
+  // -------------------------------------------------------------------------
+
+  public static X509Certificate generate(CertificateFactory factory,
+                                         String encoded)
+  {
+    try
+      {
+        ByteArrayInputStream in =
+          new ByteArrayInputStream(encoded.getBytes("UTF-8"));
+        return (X509Certificate) factory.generateCertificate(in);
+      }
+    catch (Exception x)
+      {
+        return null;
+      }
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public X509Certificate[] getCertificates()
+  {
+    return (X509Certificate[]) certs.clone();
+  }
+
+  // Constant.
+  // -------------------------------------------------------------------------
+
+  /**
+   * A list of known certificate authority certificates. This set of
+   * certificates is the same as the default CA certificates used by
+   * Mozilla.
+   */
+  public static final StaticTrustAnchors CA_CERTS;
+
+  // Static initializer.
+  // -------------------------------------------------------------------------
+
+  static
+  {
+    LinkedList certs = new LinkedList();
+    CertificateFactory factory = null;
+
+    try
+      {
+        factory = CertificateFactory.getInstance("X.509");
+      }
+    catch (CertificateException ce)
+      {
+        throw new Error(ce.toString());
+      }
+
+    X509Certificate cert = generate(factory,
+      // ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF\n" +
+      "BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz\n" +
+      "aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC\n" +
+      "QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry\n" +
+      "dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw\n" +
+      "CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x\n" +
+      "FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS\n" +
+      "b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w\n" +
+      "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC\n" +
+      "AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK\n" +
+      "pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV\n" +
+      "6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc\n" +
+      "OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV\n" +
+      "jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9\n" +
+      "cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C\n" +
+      "AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n" +
+      "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT\n" +
+      "ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg\n" +
+      "TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm\n" +
+      "/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx\n" +
+      "fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ\n" +
+      "TzFxiNmIf1Q=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AOL_Time_Warner_Root_Certification_Authority_1.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" +
+      "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" +
+      "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" +
+      "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw\n" +
+      "MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" +
+      "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" +
+      "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" +
+      "dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
+      "ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI\n" +
+      "zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt\n" +
+      "fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs\n" +
+      "trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr\n" +
+      "5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc\n" +
+      "LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw\n" +
+      "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+\n" +
+      "XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n" +
+      "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM\n" +
+      "eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7\n" +
+      "CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf\n" +
+      "WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT\n" +
+      "LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz\n" +
+      "vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw\n" +
+      "X7A5KGgOc90lmt4S\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AOL_Time_Warner_Root_Certification_Authority_2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" +
+      "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" +
+      "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" +
+      "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw\n" +
+      "MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" +
+      "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" +
+      "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" +
+      "dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" +
+      "ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs\n" +
+      "RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs\n" +
+      "i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg\n" +
+      "/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ\n" +
+      "2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0\n" +
+      "ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X\n" +
+      "+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml\n" +
+      "J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n" +
+      "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo\n" +
+      "Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ\n" +
+      "Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex\n" +
+      "MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB\n" +
+      "Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA\n" +
+      "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" +
+      "9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0\n" +
+      "cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF\n" +
+      "ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY\n" +
+      "vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/\n" +
+      "drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la\n" +
+      "5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks\n" +
+      "mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5\n" +
+      "O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD\n" +
+      "062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41\n" +
+      "xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n" +
+      "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL\n" +
+      "Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AddTrust_External_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT\n" +
+      "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4\n" +
+      "dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h\n" +
+      "bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL\n" +
+      "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B\n" +
+      "ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\n" +
+      "c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" +
+      "AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8\n" +
+      "k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50\n" +
+      "ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504\n" +
+      "B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez\n" +
+      "eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\n" +
+      "aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB\n" +
+      "3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD\n" +
+      "AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6\n" +
+      "xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" +
+      "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv\n" +
+      "cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\n" +
+      "KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" +
+      "j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R\n" +
+      "xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT\n" +
+      "K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1\n" +
+      "n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx\n" +
+      "REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\n" +
+      "hgQ=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AddTrust_Low-Value_Services_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT\n" +
+      "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" +
+      "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" +
+      "HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT\n" +
+      "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" +
+      "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" +
+      "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze\n" +
+      "xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI\n" +
+      "gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O\n" +
+      "M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc\n" +
+      "sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5\n" +
+      "mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n" +
+      "9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU\n" +
+      "tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" +
+      "MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw\n" +
+      "CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n" +
+      "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx\n" +
+      "IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\n" +
+      "MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" +
+      "iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9\n" +
+      "tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL\n" +
+      "/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV\n" +
+      "g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6\n" +
+      "tkD9xOQ14R0WHNC8K47Wcdk=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AddTrust_Public_Services_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT\n" +
+      "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" +
+      "UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe\n" +
+      "Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF\n" +
+      "MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" +
+      "IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\n" +
+      "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+\n" +
+      "A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c\n" +
+      "+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2\n" +
+      "P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX\n" +
+      "C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R\n" +
+      "s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\n" +
+      "BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf\n" +
+      "d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB\n" +
+      "jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG\n" +
+      "A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n" +
+      "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB\n" +
+      "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\n" +
+      "G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" +
+      "+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj\n" +
+      "PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY\n" +
+      "GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6\n" +
+      "NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx\n" +
+      "My3ZdvJOOjMMK7MtkAY=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // AddTrust_Qualified_Certificates_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT\n" +
+      "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" +
+      "UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v\n" +
+      "dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT\n" +
+      "AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg\n" +
+      "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\n" +
+      "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek\n" +
+      "n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk\n" +
+      "IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z\n" +
+      "sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t\n" +
+      "UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R\n" +
+      "+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\n" +
+      "a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5\n" +
+      "lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n" +
+      "AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw\n" +
+      "ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n" +
+      "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh\n" +
+      "bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\n" +
+      "lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" +
+      "GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9\n" +
+      "5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF\n" +
+      "Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA\n" +
+      "wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw\n" +
+      "dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // America_Online_Root_Certification_Authority_1.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" +
+      "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" +
+      "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X\n" +
+      "DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx\n" +
+      "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" +
+      "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n" +
+      "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa\n" +
+      "xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl\n" +
+      "GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n\n" +
+      "BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx\n" +
+      "VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE\n" +
+      "mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\n" +
+      "JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" +
+      "HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5\n" +
+      "9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA\n" +
+      "A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n" +
+      "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM\n" +
+      "IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\n" +
+      "dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g\n" +
+      "Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j\n" +
+      "8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // America_Online_Root_Certification_Authority_2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" +
+      "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" +
+      "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X\n" +
+      "DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx\n" +
+      "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" +
+      "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n" +
+      "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN\n" +
+      "t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/\n" +
+      "DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x\n" +
+      "uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE\n" +
+      "18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr\n" +
+      "kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\n" +
+      "bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX\n" +
+      "uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu\n" +
+      "Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9\n" +
+      "W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n" +
+      "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48\n" +
+      "ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\n" +
+      "AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op\n" +
+      "aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee\n" +
+      "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL\n" +
+      "M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf\n" +
+      "tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR\n" +
+      "Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n" +
+      "+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr\n" +
+      "+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM\n" +
+      "nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt\n" +
+      "d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI\n" +
+      "WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ\n" +
+      "ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n" +
+      "3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz\n" +
+      "2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n" +
+      "RY8mkaKO/qk=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Baltimore_CyberTrust_Code_Signing_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQG\n" +
+      "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" +
+      "MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcg\n" +
+      "Um9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNV\n" +
+      "BAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1\n" +
+      "c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmlu\n" +
+      "ZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKO\n" +
+      "etv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+Cc\n" +
+      "hF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1S\n" +
+      "Qdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2c\n" +
+      "vXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNA\n" +
+      "WshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Bi\n" +
+      "u641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAK\n" +
+      "BggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYD\n" +
+      "VR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF\n" +
+      "BQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT9\n" +
+      "8pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOn\n" +
+      "UxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWk\n" +
+      "Lfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++\n" +
+      "hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9\n" +
+      "qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Baltimore_CyberTrust_Mobile_Commerce_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" +
+      "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" +
+      "MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAe\n" +
+      "Fw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklF\n" +
+      "MRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAn\n" +
+      "BgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0G\n" +
+      "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+g\n" +
+      "hY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8E\n" +
+      "rqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9f\n" +
+      "Ih96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbA\n" +
+      "B+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" +
+      "DQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0a\n" +
+      "t1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2\n" +
+      "qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9\n" +
+      "m+pCDOjYVL5TZvU=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Baltimore_CyberTrust_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" +
+      "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" +
+      "MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx\n" +
+      "MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV\n" +
+      "BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ\n" +
+      "QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
+      "ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h\n" +
+      "Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR\n" +
+      "QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP\n" +
+      "wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1\n" +
+      "pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT\n" +
+      "Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\n" +
+      "AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud\n" +
+      "EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\n" +
+      "A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT\n" +
+      "I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" +
+      "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/\n" +
+      "oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\n" +
+      "G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" +
+      "RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Digital_Signature_Trust_Co._Global_CA_1.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" +
+      "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" +
+      "DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw\n" +
+      "MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" +
+      "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB\n" +
+      "AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\n" +
+      "EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth\n" +
+      "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0\n" +
+      "dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" +
+      "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" +
+      "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV\n" +
+      "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\n" +
+      "MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3\n" +
+      "pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV\n" +
+      "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" +
+      "DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n" +
+      "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA\n" +
+      "sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\n" +
+      "w4pl\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Digital_Signature_Trust_Co._Global_CA_2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp\n" +
+      "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" +
+      "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" +
+      "LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n" +
+      "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx\n" +
+      "ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" +
+      "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" +
+      "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx\n" +
+      "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" +
+      "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +
+      "ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U\n" +
+      "q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF\n" +
+      "koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh\n" +
+      "TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd\n" +
+      "lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn\n" +
+      "7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n" +
+      "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+\n" +
+      "LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV\n" +
+      "WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX\n" +
+      "8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8\n" +
+      "6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT\n" +
+      "F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Digital_Signature_Trust_Co._Global_CA_3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" +
+      "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" +
+      "DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3\n" +
+      "MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" +
+      "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB\n" +
+      "AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\n" +
+      "w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e\n" +
+      "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd\n" +
+      "55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" +
+      "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" +
+      "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV\n" +
+      "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\n" +
+      "OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s\n" +
+      "NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV\n" +
+      "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" +
+      "DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n" +
+      "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb\n" +
+      "dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\n" +
+      "w6ID\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Digital_Signature_Trust_Co._Global_CA_4.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp\n" +
+      "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" +
+      "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" +
+      "LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n" +
+      "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy\n" +
+      "MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" +
+      "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" +
+      "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx\n" +
+      "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" +
+      "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +
+      "ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6\n" +
+      "ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5\n" +
+      "/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9\n" +
+      "MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih\n" +
+      "YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv\n" +
+      "bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n" +
+      "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog\n" +
+      "WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6\n" +
+      "HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV\n" +
+      "6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8\n" +
+      "PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30\n" +
+      "sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Entrust.net_Global_Secure_Personal_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE\n" +
+      "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB\n" +
+      "X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" +
+      "HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" +
+      "c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy\n" +
+      "MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" +
+      "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y\n" +
+      "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n" +
+      "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp\n" +
+      "ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA\n" +
+      "A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU\n" +
+      "rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB\n" +
+      "3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y\n" +
+      "NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E\n" +
+      "gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw\n" +
+      "PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n" +
+      "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0\n" +
+      "Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy\n" +
+      "dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw\n" +
+      "IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD\n" +
+      "AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW\n" +
+      "BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n" +
+      "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA\n" +
+      "O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L\n" +
+      "a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l\n" +
+      "TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Entrust.net_Global_Secure_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE\n" +
+      "ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf\n" +
+      "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n" +
+      "KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz\n" +
+      "dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" +
+      "Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF\n" +
+      "bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg\n" +
+      "aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\n" +
+      "MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l\n" +
+      "dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G\n" +
+      "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw\n" +
+      "tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK\n" +
+      "wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI\n" +
+      "XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD\n" +
+      "AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu\n" +
+      "dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n" +
+      "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy\n" +
+      "MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0\n" +
+      "IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV\n" +
+      "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw\n" +
+      "NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc\n" +
+      "/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV\n" +
+      "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq\n" +
+      "hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv\n" +
+      "yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp\n" +
+      "bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/\n" +
+      "bIkz8OwVDw==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Entrust.net_Premium_2048_Secure_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE\n" +
+      "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf\n" +
+      "MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" +
+      "HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" +
+      "c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy\n" +
+      "MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" +
+      "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y\n" +
+      "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg\n" +
+      "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy\n" +
+      "dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF\n" +
+      "AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4\n" +
+      "QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\n" +
+      "DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj\n" +
+      "/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP\n" +
+      "KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd\n" +
+      "enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" +
+      "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB\n" +
+      "0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\n" +
+      "FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B\n" +
+      "AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh\n" +
+      "fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU\n" +
+      "KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho\n" +
+      "wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2\n" +
+      "+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n" +
+      "6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Entrust.net_Secure_Personal_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE\n" +
+      "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50\n" +
+      "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs\n" +
+      "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp\n" +
+      "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0\n" +
+      "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa\n" +
+      "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV\n" +
+      "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw\n" +
+      "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50\n" +
+      "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50\n" +
+      "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL\n" +
+      "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv\n" +
+      "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV\n" +
+      "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173\n" +
+      "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw\n" +
+      "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n" +
+      "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff\n" +
+      "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE\n" +
+      "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50\n" +
+      "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD\n" +
+      "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D\n" +
+      "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx\n" +
+      "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW\n" +
+      "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG\n" +
+      "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n" +
+      "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ\n" +
+      "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU\n" +
+      "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE\n" +
+      "PHayXOw=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Entrust.net_Secure_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE\n" +
+      "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50\n" +
+      "cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" +
+      "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE\n" +
+      "AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1\n" +
+      "dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\n" +
+      "CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3\n" +
+      "dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh\n" +
+      "Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow\n" +
+      "OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n" +
+      "b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0\n" +
+      "VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\n" +
+      "iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk\n" +
+      "mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT\n" +
+      "MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY\n" +
+      "pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n" +
+      "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs\n" +
+      "aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\n" +
+      "aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl\n" +
+      "cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo\n" +
+      "dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi\n" +
+      "gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC\n" +
+      "AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE\n" +
+      "FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\n" +
+      "B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn\n" +
+      "CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx\n" +
+      "xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6\n" +
+      "rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Equifax_Secure_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" +
+      "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1\n" +
+      "cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4\n" +
+      "MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx\n" +
+      "LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0\n" +
+      "eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\n" +
+      "FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO\n" +
+      "/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv\n" +
+      "K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" +
+      "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt\n" +
+      "MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\n" +
+      "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\n" +
+      "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw\n" +
+      "HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w\n" +
+      "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" +
+      "AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" +
+      "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u\n" +
+      "FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Equifax_Secure_Global_eBusiness_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV\n" +
+      "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1\n" +
+      "aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0\n" +
+      "MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT\n" +
+      "E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl\n" +
+      "IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
+      "gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy\n" +
+      "td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR\n" +
+      "OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC\n" +
+      "AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w\n" +
+      "HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o\n" +
+      "oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n" +
+      "2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa\n" +
+      "z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1\n" +
+      "pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Equifax_Secure_eBusiness_CA_1.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV\n" +
+      "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1\n" +
+      "aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN\n" +
+      "MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh\n" +
+      "eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\n" +
+      "ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\n" +
+      "k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5\n" +
+      "/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW\n" +
+      "HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG\n" +
+      "SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4\n" +
+      "MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq\n" +
+      "R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\n" +
+      "JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1\n" +
+      "tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr\n" +
+      "tWKmpj29f5JZzVoqgrI3eQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Equifax_Secure_eBusiness_CA_2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" +
+      "EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm\n" +
+      "YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5\n" +
+      "MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg\n" +
+      "U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et\n" +
+      "MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n" +
+      "7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD\n" +
+      "pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM\n" +
+      "HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" +
+      "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT\n" +
+      "ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y\n" +
+      "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\n" +
+      "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw\n" +
+      "HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w\n" +
+      "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" +
+      "AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n" +
+      "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt\n" +
+      "y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // GTE_CyberTrust_Global_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw\n" +
+      "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy\n" +
+      "dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg\n" +
+      "R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1\n" +
+      "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD\n" +
+      "VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\n" +
+      "GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA\n" +
+      "A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4\n" +
+      "ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn\n" +
+      "ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F\n" +
+      "LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3\n" +
+      "46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n" +
+      "81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d\n" +
+      "XIVtx6quTx8itc2VrbqnzPmrC3p/\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // GTE_CyberTrust_Root_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw\n" +
+      "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy\n" +
+      "dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw\n" +
+      "CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD\n" +
+      "ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n" +
+      "iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K\n" +
+      "DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw\n" +
+      "KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID\n" +
+      "AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD\n" +
+      "+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv\n" +
+      "U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e\n" +
+      "6bR64eVaH4QwnNOfpSXY\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // GeoTrust_Global_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT\n" +
+      "AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz\n" +
+      "dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC\n" +
+      "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n" +
+      "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
+      "MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\n" +
+      "CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC\n" +
+      "GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7\n" +
+      "csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj\n" +
+      "Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe\n" +
+      "JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB\n" +
+      "o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\n" +
+      "qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq\n" +
+      "hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe\n" +
+      "R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV\n" +
+      "Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" +
+      "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot\n" +
+      "2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\n" +
+      "xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" +
+      "Mw==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // GlobalSign_Root_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL\n" +
+      "MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV\n" +
+      "BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05\n" +
+      "ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw\n" +
+      "FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw\n" +
+      "GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" +
+      "A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR\n" +
+      "4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc\n" +
+      "71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4\n" +
+      "bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK\n" +
+      "OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW\n" +
+      "ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\n" +
+      "AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ\n" +
+      "UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC\n" +
+      "AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd\n" +
+      "PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n" +
+      "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT\n" +
+      "2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD\n" +
+      "NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg\n" +
+      "Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // RSA_Root_Certificate_1.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" +
+      "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" +
+      "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp\n" +
+      "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" +
+      "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" +
+      "NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" +
+      "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" +
+      "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g\n" +
+      "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" +
+      "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" +
+      "DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f\n" +
+      "NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\n" +
+      "MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34\n" +
+      "t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b\n" +
+      "e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu\n" +
+      "PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n" +
+      "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // RSA_Security_1024_v3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF\n" +
+      "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" +
+      "U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx\n" +
+      "NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" +
+      "QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" +
+      "gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY\n" +
+      "rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt\n" +
+      "bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB\n" +
+      "o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME\n" +
+      "GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N\n" +
+      "AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy\n" +
+      "HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9\n" +
+      "am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B\n" +
+      "qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // RSA_Security_2048_v3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF\n" +
+      "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" +
+      "U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5\n" +
+      "MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" +
+      "QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
+      "CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\n" +
+      "RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E\n" +
+      "0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J\n" +
+      "6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq\n" +
+      "s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD\n" +
+      "uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw\n" +
+      "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\n" +
+      "gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6\n" +
+      "/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V\n" +
+      "EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g\n" +
+      "EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n" +
+      "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq\n" +
+      "aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\n" +
+      "llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA\n" +
+      "pKnXwiJPZ9d37CAFYd4=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // TC_TrustCenter__Germany__Class_2_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" +
+      "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" +
+      "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" +
+      "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB\n" +
+      "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" +
+      "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" +
+      "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" +
+      "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" +
+      "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp\n" +
+      "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" +
+      "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk\n" +
+      "qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO\n" +
+      "gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7\n" +
+      "zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" +
+      "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" +
+      "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" +
+      "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W\n" +
+      "LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR\n" +
+      "T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac\n" +
+      "ASZ4smZHcFFk\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // TC_TrustCenter__Germany__Class_3_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" +
+      "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" +
+      "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" +
+      "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB\n" +
+      "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" +
+      "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" +
+      "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" +
+      "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" +
+      "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp\n" +
+      "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" +
+      "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ\n" +
+      "GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn\n" +
+      "v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA\n" +
+      "o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" +
+      "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" +
+      "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" +
+      "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4\n" +
+      "iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC\n" +
+      "GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS\n" +
+      "CdS7kjXvD9s0\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Personal_Basic_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" +
+      "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" +
+      "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl\n" +
+      "cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp\n" +
+      "Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow\n" +
+      "gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV\n" +
+      "BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm\n" +
+      "BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV\n" +
+      "BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ\n" +
+      "cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB\n" +
+      "jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK\n" +
+      "P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ\n" +
+      "fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j\n" +
+      "kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB\n" +
+      "gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n" +
+      "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95\n" +
+      "B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Personal_Freemail_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" +
+      "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" +
+      "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl\n" +
+      "cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m\n" +
+      "cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz\n" +
+      "NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx\n" +
+      "EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp\n" +
+      "bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" +
+      "JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG\n" +
+      "SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq\n" +
+      "hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N\n" +
+      "j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef\n" +
+      "QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY\n" +
+      "x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" +
+      "hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n" +
+      "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC\n" +
+      "neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr\n" +
+      "5PjRzneigQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Personal_Premium_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" +
+      "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" +
+      "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl\n" +
+      "cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy\n" +
+      "ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5\n" +
+      "NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw\n" +
+      "EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n\n" +
+      "MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw\n" +
+      "IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3\n" +
+      "DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3\n" +
+      "DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7\n" +
+      "7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j\n" +
+      "Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq\n" +
+      "W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" +
+      "DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n" +
+      "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx\n" +
+      "eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1\n" +
+      "KzGJ\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Premium_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" +
+      "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" +
+      "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl\n" +
+      "IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n" +
+      "cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\n" +
+      "OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ\n" +
+      "BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg\n" +
+      "Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" +
+      "ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3\n" +
+      "DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B\n" +
+      "AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\n" +
+      "NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL\n" +
+      "lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN\n" +
+      "9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" +
+      "AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" +
+      "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ\n" +
+      "a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\n" +
+      "Qg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" +
+      "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" +
+      "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl\n" +
+      "IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0\n" +
+      "ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\n" +
+      "A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw\n" +
+      "ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n" +
+      "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ\n" +
+      "VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz\n" +
+      "QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I\n" +
+      "/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n" +
+      "6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX\n" +
+      "TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G\n" +
+      "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD\n" +
+      "TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n" +
+      "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni\n" +
+      "TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Thawte_Time_Stamping_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC\n" +
+      "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls\n" +
+      "bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj\n" +
+      "YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw\n" +
+      "MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT\n" +
+      "BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n" +
+      "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x\n" +
+      "HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN\n" +
+      "AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8\n" +
+      "WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR\n" +
+      "5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7\n" +
+      "X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN\n" +
+      "AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK\n" +
+      "0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8\n" +
+      "zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ\n" +
+      "SdM=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // UTN-USER_First-Network_Applications.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF\n" +
+      "ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n" +
+      "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw\n" +
+      "HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU\n" +
+      "Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0\n" +
+      "ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT\n" +
+      "AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT\n" +
+      "RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\n" +
+      "dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh\n" +
+      "dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV\n" +
+      "hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb\n" +
+      "GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ\n" +
+      "NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4\n" +
+      "xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv\n" +
+      "/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i\n" +
+      "gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n" +
+      "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf\n" +
+      "8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0\n" +
+      "LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G\n" +
+      "CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh\n" +
+      "i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq\n" +
+      "f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf\n" +
+      "hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP\n" +
+      "NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+\n" +
+      "FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis\n" +
+      "H8SE\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // ValiCert_Class_1_VA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" +
+      "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" +
+      "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp\n" +
+      "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" +
+      "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" +
+      "NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" +
+      "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" +
+      "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g\n" +
+      "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" +
+      "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" +
+      "DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw\n" +
+      "8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n" +
+      "+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN\n" +
+      "dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V\n" +
+      "YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so\n" +
+      "gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n" +
+      "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // ValiCert_Class_2_VA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" +
+      "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" +
+      "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp\n" +
+      "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" +
+      "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" +
+      "NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" +
+      "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" +
+      "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" +
+      "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" +
+      "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" +
+      "DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc\n" +
+      "65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\n" +
+      "b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn\n" +
+      "wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4\n" +
+      "OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ\n" +
+      "oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" +
+      "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // ValiCert_OCSP_Responder.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMb\n" +
+      "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2Vy\n" +
+      "dCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0\n" +
+      "eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEg\n" +
+      "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1\n" +
+      "MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFs\n" +
+      "aWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoG\n" +
+      "A1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAf\n" +
+      "BgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJ\n" +
+      "ARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" +
+      "AoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6\n" +
+      "tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZM\n" +
+      "ddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMB\n" +
+      "AAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\n" +
+      "CwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0\n" +
+      "cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4\n" +
+      "NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0Kaz\n" +
+      "DawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDT\n" +
+      "NDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_1_Public_Primary_Certification_Authority.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x\n" +
+      "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE\n" +
+      "CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" +
+      "cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV\n" +
+      "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n" +
+      "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB\n" +
+      "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3\n" +
+      "noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B\n" +
+      "9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg\n" +
+      "1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM\n" +
+      "P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P\n" +
+      "/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj\n" +
+      "t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx\n" +
+      "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" +
+      "CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" +
+      "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" +
+      "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" +
+      "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" +
+      "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" +
+      "A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" +
+      "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" +
+      "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" +
+      "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq\n" +
+      "0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9\n" +
+      "Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c\n" +
+      "PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G\n" +
+      "CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr\n" +
+      "bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n" +
+      "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i\n" +
+      "P/68DzFc6PLZ\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK\n" +
+      "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" +
+      "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" +
+      "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" +
+      "BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm\n" +
+      "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" +
+      "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" +
+      "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" +
+      "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" +
+      "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy\n" +
+      "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" +
+      "hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR\n" +
+      "ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j\n" +
+      "Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh\n" +
+      "JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P\n" +
+      "oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n" +
+      "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh\n" +
+      "v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ\n" +
+      "BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N\n" +
+      "y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf\n" +
+      "xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM\n" +
+      "DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5\n" +
+      "SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV\n" +
+      "OBRgmaNL3gaWcSzy27YfpO8/7g==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_1_Public_Primary_OCSP_Responder.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF\n" +
+      "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" +
+      "BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" +
+      "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" +
+      "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" +
+      "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" +
+      "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx\n" +
+      "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" +
+      "AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER\n" +
+      "6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh\n" +
+      "WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz\n" +
+      "y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" +
+      "CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" +
+      "Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" +
+      "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" +
+      "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" +
+      "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" +
+      "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX\n" +
+      "fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4\n" +
+      "KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z\n" +
+      "6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_2_Public_Primary_Certification_Authority.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL\n" +
+      "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" +
+      "Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" +
+      "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" +
+      "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" +
+      "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" +
+      "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM\n" +
+      "JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE\n" +
+      "erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC\n" +
+      "JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob\n" +
+      "K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg\n" +
+      "MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3\n" +
+      "Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB\n" +
+      "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV\n" +
+      "BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\n" +
+      "b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g\n" +
+      "LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g\n" +
+      "VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla\n" +
+      "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6\n" +
+      "BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" +
+      "dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu\n" +
+      "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp\n" +
+      "Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
+      "p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf\n" +
+      "rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z\n" +
+      "Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN\n" +
+      "BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/\n" +
+      "7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n" +
+      "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x\n" +
+      "RnInjBJ7xUS0rg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox\n" +
+      "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE\n" +
+      "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg\n" +
+      "VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG\n" +
+      "A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp\n" +
+      "Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx\n" +
+      "NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg\n" +
+      "SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE\n" +
+      "CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\n" +
+      "c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp\n" +
+      "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG\n" +
+      "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8\n" +
+      "1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT\n" +
+      "2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT\n" +
+      "AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ\n" +
+      "HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n" +
+      "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC\n" +
+      "YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh\n" +
+      "ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf\n" +
+      "0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE\n" +
+      "p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B\n" +
+      "MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab\n" +
+      "5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX\n" +
+      "p/naOlXJWBD5qu9ats9LS98q\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_2_Public_Primary_OCSP_Responder.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF\n" +
+      "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" +
+      "BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" +
+      "dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX\n" +
+      "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" +
+      "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" +
+      "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy\n" +
+      "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" +
+      "AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+\n" +
+      "PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc\n" +
+      "9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM\n" +
+      "RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" +
+      "CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" +
+      "Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" +
+      "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" +
+      "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" +
+      "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" +
+      "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE\n" +
+      "nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs\n" +
+      "WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+\n" +
+      "It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_3_Public_Primary_Certification_Authority.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL\n" +
+      "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" +
+      "Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" +
+      "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" +
+      "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" +
+      "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" +
+      "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q\n" +
+      "RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In\n" +
+      "zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a\n" +
+      "/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM\n" +
+      "EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw\n" +
+      "TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk\n" +
+      "uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx\n" +
+      "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" +
+      "CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" +
+      "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" +
+      "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" +
+      "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" +
+      "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" +
+      "A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" +
+      "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" +
+      "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" +
+      "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM\n" +
+      "XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\n" +
+      "wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV\n" +
+      "j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G\n" +
+      "CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U\n" +
+      "bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n" +
+      "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo\n" +
+      "1KpYoJ2daZH9\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK\n" +
+      "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" +
+      "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" +
+      "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" +
+      "BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm\n" +
+      "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" +
+      "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" +
+      "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" +
+      "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" +
+      "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy\n" +
+      "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" +
+      "hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\n" +
+      "R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo\n" +
+      "vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg\n" +
+      "TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V\n" +
+      "k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" +
+      "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ\n" +
+      "OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n" +
+      "/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" +
+      "j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA\n" +
+      "Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S\n" +
+      "GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb\n" +
+      "o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh\n" +
+      "/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_3_Public_Primary_OCSP_Responder.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF\n" +
+      "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" +
+      "BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" +
+      "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" +
+      "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" +
+      "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" +
+      "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz\n" +
+      "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" +
+      "AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW\n" +
+      "uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA\n" +
+      "PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC\n" +
+      "7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" +
+      "CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp\n" +
+      "Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr\n" +
+      "BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp\n" +
+      "Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw\n" +
+      "KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ\n" +
+      "BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj\n" +
+      "wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU\n" +
+      "LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE\n" +
+      "KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_4_Public_Primary_Certification_Authority_-_G2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx\n" +
+      "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" +
+      "CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" +
+      "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" +
+      "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" +
+      "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" +
+      "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" +
+      "A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" +
+      "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" +
+      "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" +
+      "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6\n" +
+      "8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK\n" +
+      "QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX\n" +
+      "xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G\n" +
+      "CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI\n" +
+      "L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n" +
+      "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt\n" +
+      "ImRPT8qAkbYp\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK\n" +
+      "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" +
+      "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" +
+      "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" +
+      "BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm\n" +
+      "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" +
+      "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" +
+      "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" +
+      "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" +
+      "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy\n" +
+      "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" +
+      "hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\n" +
+      "S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC\n" +
+      "KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc\n" +
+      "VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL\n" +
+      "MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n" +
+      "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD\n" +
+      "Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\n" +
+      "IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt\n" +
+      "mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK\n" +
+      "vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP\n" +
+      "QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP\n" +
+      "mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr\n" +
+      "9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_RSA_Secure_Server_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL\n" +
+      "MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu\n" +
+      "MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y\n" +
+      "aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE\n" +
+      "BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n" +
+      "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb\n" +
+      "MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O\n" +
+      "LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs\n" +
+      "iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC\n" +
+      "sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw\n" +
+      "4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr\n" +
+      "l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1\n" +
+      "g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Secure_Server_OCSP_Responder.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF\n" +
+      "BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5\n" +
+      "LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g\n" +
+      "QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x\n" +
+      "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" +
+      "cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6\n" +
+      "Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl\n" +
+      "IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
+      "gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9\n" +
+      "zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt\n" +
+      "ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C\n" +
+      "AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt\n" +
+      "NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S\n" +
+      "U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI\n" +
+      "KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz\n" +
+      "aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB\n" +
+      "MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw\n" +
+      "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT\n" +
+      "ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+\n" +
+      "TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y\n" +
+      "dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Verisign_Time_Stamping_Authority_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF\n" +
+      "ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww\n" +
+      "OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g\n" +
+      "QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ\n" +
+      "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT\n" +
+      "aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1\n" +
+      "OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" +
+      "cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh\n" +
+      "dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD\n" +
+      "EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq\n" +
+      "hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2\n" +
+      "fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/\n" +
+      "RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB\n" +
+      "CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG\n" +
+      "A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz\n" +
+      "Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n" +
+      "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG\n" +
+      "CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp\n" +
+      "c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2\n" +
+      "DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn\n" +
+      "Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n\n" +
+      "tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Visa_International_Global_Root_2.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC\n" +
+      "VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h\n" +
+      "bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN\n" +
+      "MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN\n" +
+      "MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\n" +
+      "cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ\n" +
+      "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ\n" +
+      "DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ\n" +
+      "XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl\n" +
+      "Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm\n" +
+      "7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa\n" +
+      "xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e\n" +
+      "QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO\n" +
+      "qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG\n" +
+      "SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp\n" +
+      "NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n" +
+      "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL\n" +
+      "axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt\n" +
+      "Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8\n" +
+      "ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // Visa_eCommerce_Root.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF\n" +
+      "ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz\n" +
+      "YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT\n" +
+      "E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0\n" +
+      "MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE\n" +
+      "CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\n" +
+      "BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n" +
+      "A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh\n" +
+      "28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362\n" +
+      "rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81\n" +
+      "q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF\n" +
+      "Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\n" +
+      "lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t\n" +
+      "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" +
+      "A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC\n" +
+      "AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n" +
+      "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht\n" +
+      "cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\n" +
+      "xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" +
+      "YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/\n" +
+      "hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // beTRUSTed_Root_CA-Baltimore_Implementation.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" +
+      "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" +
+      "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0\n" +
+      "aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE\n" +
+      "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" +
+      "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh\n" +
+      "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW\n" +
+      "HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R\n" +
+      "9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3\n" +
+      "fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f\n" +
+      "HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm\n" +
+      "iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg\n" +
+      "B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB\n" +
+      "/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR\n" +
+      "MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl\n" +
+      "IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n" +
+      "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k\n" +
+      "YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj\n" +
+      "YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0\n" +
+      "eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT\n" +
+      "VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj\n" +
+      "dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3\n" +
+      "dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww\n" +
+      "HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9\n" +
+      "w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B\n" +
+      "AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z\n" +
+      "dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9\n" +
+      "beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ\n" +
+      "XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d\n" +
+      "UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py\n" +
+      "05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // beTRUSTed_Root_CA.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" +
+      "EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg\n" +
+      "Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy\n" +
+      "MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV\n" +
+      "BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow\n" +
+      "GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
+      "ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4\n" +
+      "SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3\n" +
+      "o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V\n" +
+      "cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k\n" +
+      "bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8\n" +
+      "tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC\n" +
+      "AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB\n" +
+      "TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp\n" +
+      "YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz\n" +
+      "IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n" +
+      "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u\n" +
+      "IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl\n" +
+      "VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t\n" +
+      "L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU\n" +
+      "ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD\n" +
+      "VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub\n" +
+      "2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir\n" +
+      "ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax\n" +
+      "6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl\n" +
+      "pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE\n" +
+      "/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA\n" +
+      "AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH\n" +
+      "0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG\n" +
+      "EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // beTRUSTed_Root_CA_-_Entrust_Implementation.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" +
+      "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" +
+      "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0\n" +
+      "aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE\n" +
+      "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" +
+      "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh\n" +
+      "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1\n" +
+      "Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw\n" +
+      "ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV\n" +
+      "m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb\n" +
+      "hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu\n" +
+      "6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX\n" +
+      "LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g\n" +
+      "BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH\n" +
+      "AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj\n" +
+      "YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n" +
+      "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u\n" +
+      "ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0\n" +
+      "YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj\n" +
+      "aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0\n" +
+      "cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl\n" +
+      "eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t\n" +
+      "L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD\n" +
+      "AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl\n" +
+      "ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS\n" +
+      "VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV\n" +
+      "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx\n" +
+      "MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa\n" +
+      "j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV\n" +
+      "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq\n" +
+      "hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04\n" +
+      "ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n" +
+      "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220\n" +
+      "Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2\n" +
+      "KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi\n" +
+      "aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep\n" +
+      "9w==\n" +
+      "-----END CERTIFICATE-----\n");
+    if (cert != null) certs.add(cert);
+
+    cert = generate(factory,
+      // beTRUSTed_Root_CA_-_RSA_Implementation.crt
+      "-----BEGIN CERTIFICATE-----\n" +
+      "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF\n" +
+      "ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS\n" +
+      "b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w\n" +
+      "bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi\n" +
+      "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290\n" +
+      "IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt\n" +
+      "ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw\n" +
+      "CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK\n" +
+      "Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU\n" +
+      "vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL\n" +
+      "O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe\n" +
+      "rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1\n" +
+      "S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV\n" +
+      "HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD\n" +
+      "kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v\n" +
+      "cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n" +
+      "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj\n" +
+      "cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo\n" +
+      "ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv\n" +
+      "bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l\n" +
+      "bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu\n" +
+      "IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93\n" +
+      "d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s\n" +
+      "MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN\n" +
+      "GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF\n" +
+      "BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0\n" +
+      "3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt\n" +
+      "NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1\n" +
+      "UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM\n" +
+      "m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y\n" +
+      "mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n" +
+      "-----END CERTIFICATE-----\n");
+
+    CA_CERTS = new StaticTrustAnchors((X509Certificate[]) certs.toArray(new X509Certificate[0]));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/AbstractHandshake.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,1205 @@
+/* AbstractHandshake.java -- abstract handshake handler.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.ByteArray;
+import gnu.javax.security.auth.callback.CertificateCallback;
+import gnu.javax.security.auth.callback.DefaultCallbackHandler;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ConfirmationCallback;
+
+/**
+ * The base interface for handshake implementations. Concrete
+ * subclasses of this class (one for the server, one for the client)
+ * handle the HANDSHAKE content-type in communications.
+ */
+public abstract class AbstractHandshake
+{
+  protected static final SystemLogger logger = SystemLogger.SYSTEM;
+
+  /**
+   * "server finished" -- TLS 1.0 and later
+   */
+  protected static final byte[] SERVER_FINISHED
+    = new byte[] {
+      115, 101, 114, 118, 101, 114,  32, 102, 105, 110, 105, 115,
+      104, 101, 100   
+    };
+  
+  /**
+   * "client finished" -- TLS 1.0 and later
+   */
+  protected static final byte[] CLIENT_FINISHED
+    = new byte[] {
+       99, 108, 105, 101, 110, 116,  32, 102, 105, 110, 105, 115,
+      104, 101, 100
+    };
+  
+  /**
+   * "key expansion" -- TLS 1.0 and later
+   */
+  private static final byte[] KEY_EXPANSION =
+    new byte[] { 107, 101, 121,  32, 101, 120, 112,
+                  97, 110, 115, 105, 111, 110 };
+  
+  /**
+   * "master secret" -- TLS 1.0 and later
+   */
+  private static final byte[] MASTER_SECRET
+    = new byte[] {
+      109,  97, 115, 116, 101, 114,  32, 115, 101,  99, 114, 101, 116
+    };
+  
+  /**
+   * "client write key" -- TLS 1.0 exportable whitener.
+   */
+  private static final byte[] CLIENT_WRITE_KEY
+    = new byte[] {
+       99, 108, 105, 101, 110, 116,  32, 119, 114, 105, 116, 101,  32, 107,
+      101, 121
+    };
+  
+  /**
+   * "server write key" -- TLS 1.0 exportable whitener.
+   */
+  private static final byte[] SERVER_WRITE_KEY
+    = new byte[] {
+      115, 101, 114, 118, 101, 114,  32, 119, 114, 105, 116, 101,  32, 107,
+      101, 121
+    };
+  
+  private static final byte[] IV_BLOCK
+    = new byte[] {
+       73,  86,  32,  98, 108, 111,  99, 107
+    };
+  
+  /**
+   * SSL 3.0; the string "CLNT"
+   */
+  private static final byte[] SENDER_CLIENT
+    = new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
+  
+  /**
+   * SSL 3.0; the string "SRVR"
+   */
+  private static final byte[] SENDER_SERVER
+    = new byte[] { 0x53, 0x52, 0x56, 0x52 };
+  
+  /**
+   * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+   * times.
+   */
+  protected static final byte[] PAD1 = new byte[48];
+  
+  /**
+   * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+   * times.
+   */
+  protected static final byte[] PAD2 = new byte[48];
+
+  static
+  {
+    Arrays.fill(PAD1, SSLHMac.PAD1);
+    Arrays.fill(PAD2, SSLHMac.PAD2);
+  }
+  
+  /**
+   * The currently-read handshake messages. There may be zero, or
+   * multiple, handshake messages in this buffer.
+   */
+  protected ByteBuffer handshakeBuffer;
+
+  /**
+   * The offset into `handshakeBuffer' where the first unread
+   * handshake message resides.
+   */
+  protected int handshakeOffset;
+
+  protected MessageDigest sha;
+  protected MessageDigest md5;
+  
+  protected final SSLEngineImpl engine;
+  protected KeyAgreement keyAgreement;
+  protected byte[] preMasterSecret;
+  protected InputSecurityParameters inParams;
+  protected OutputSecurityParameters outParams;
+  protected LinkedList<DelegatedTask> tasks;
+  protected Random serverRandom;
+  protected Random clientRandom;
+  protected CompressionMethod compression;
+
+  protected AbstractHandshake(SSLEngineImpl engine)
+    throws NoSuchAlgorithmException
+  {
+    this.engine = engine;
+    sha = MessageDigest.getInstance("SHA-1");
+    md5 = MessageDigest.getInstance("MD5");
+    tasks = new LinkedList<DelegatedTask>();
+  }
+  
+  /**
+   * Handles the next input message in the handshake. This is called
+   * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap}
+   * for a message with content-type HANDSHAKE.
+   *
+   * @param record The input record. The callee should not assume that
+   * the record's buffer is writable, and should not try to use it for
+   * output or temporary storage.
+   * @return An {@link SSLEngineResult} describing the result.
+   */
+  public final HandshakeStatus handleInput (ByteBuffer fragment)
+    throws SSLException
+  {
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+
+    HandshakeStatus status = status();
+    if (status != HandshakeStatus.NEED_UNWRAP)
+      return status;
+
+    // Try to read another...
+    if (!pollHandshake(fragment))
+      return HandshakeStatus.NEED_UNWRAP;
+
+    while (hasMessage() && status != HandshakeStatus.NEED_WRAP)
+      {
+        int pos = handshakeOffset;
+        status = implHandleInput();
+        int len = handshakeOffset - pos;
+        if (len == 0)
+          {
+            // Don't bother; the impl is just telling us to go around
+            // again.
+            continue;
+          }
+        if (doHash())
+          {
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}",
+                          Util.hexDump((ByteBuffer) handshakeBuffer
+                                       .duplicate().position(pos)
+                                       .limit(pos+len), " >> "));
+            sha.update((ByteBuffer) handshakeBuffer.duplicate()
+                       .position(pos).limit(pos+len));
+            md5.update((ByteBuffer) handshakeBuffer.duplicate()
+                       .position(pos).limit(pos+len));
+          }
+      }
+    return status;
+  }
+
+  /**
+   * Called to process more handshake data. This method will be called
+   * repeatedly while there is remaining handshake data, and while the
+   * status is 
+   * @return
+   * @throws SSLException
+   */
+  protected abstract HandshakeStatus implHandleInput()
+    throws SSLException;
+  
+  /**
+   * Produce more handshake output. This is called in response to a
+   * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake
+   * is still in progress.
+   *
+   * @param record The output record; the callee should put its output
+   * handshake message (or a part of it) in the argument's
+   * <code>fragment</code>, and should set the record length
+   * appropriately.
+   * @return An {@link SSLEngineResult} describing the result.
+   */
+  public final HandshakeStatus handleOutput (ByteBuffer fragment)
+    throws SSLException
+  {
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+
+    int orig = fragment.position();
+    SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment);
+    if (doHash())
+      {
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}",
+                      Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> "));
+        sha.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+        md5.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+      }
+    return status;
+  }
+  
+  /**
+   * Called to implement the underlying output handling. The callee should
+   * attempt to fill the given buffer as much as it can; this can include
+   * multiple, and even partial, handshake messages.
+   * 
+   * @param fragment The buffer the callee should write handshake messages to.
+   * @return The new status of the handshake.
+   * @throws SSLException If an error occurs processing the output message.
+   */
+  protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment)
+    throws SSLException;
+  
+  /**
+   * Return a new instance of input security parameters, initialized with
+   * the session key. It is, of course, only valid to invoke this method
+   * once the handshake is complete, and the session keys established.
+   * 
+   * <p>In the presence of a well-behaving peer, this should be called once
+   * the <code>ChangeCipherSpec</code> message is recieved.
+   * 
+   * @return The input parameters for the newly established session.
+   * @throws SSLException If the handshake is not complete.
+   */
+  final InputSecurityParameters getInputParams() throws SSLException
+  {
+    checkKeyExchange();
+    return inParams;
+  }
+
+  /**
+   * Return a new instance of output security parameters, initialized with
+   * the session key. This should be called after the
+   * <code>ChangeCipherSpec</code> message is sent to the peer.
+   * 
+   * @return The output parameters for the newly established session.
+   * @throws SSLException If the handshake is not complete.
+   */
+  final OutputSecurityParameters getOutputParams() throws SSLException
+  {
+    checkKeyExchange();
+    return outParams;
+  }
+  
+  /**
+   * Fetch a delegated task waiting to run, if any.
+   *
+   * @return The task.
+   */
+  final Runnable getTask()
+  {
+    if (tasks.isEmpty())
+      return null;
+    return tasks.removeFirst();
+  }
+  
+  /**
+   * Used by the skeletal code to query the current status of the handshake.
+   * This <em>should</em> be the same value as returned by the previous call
+   * to {@link #implHandleOutput(ByteBuffer)} or {@link
+   *  #implHandleInput(ByteBuffer)}.
+   * 
+   * @return The current handshake status.
+   */
+  abstract HandshakeStatus status();
+  
+  /**
+   * Check if the key exchange completed successfully, throwing an exception
+   * if not.
+   * 
+   * <p>Note that we assume that the caller of our SSLEngine is correct, and
+   * that they did run the delegated tasks that encapsulate the key exchange.
+   * What we are primarily checking, therefore, is that no error occurred in the
+   * key exchange operation itself.
+   *
+   * @throws SSLException If the key exchange did not complete successfully.
+   */
+  abstract void checkKeyExchange() throws SSLException;
+  
+  /**
+   * Handle an SSLv2 client hello. This is only used by SSL servers.
+   * 
+   * @param hello The hello message.
+   */
+  abstract void handleV2Hello(ByteBuffer hello) throws SSLException;
+  
+  /**
+   * Attempt to read the next handshake message from the given
+   * record. If only a partial handshake message is available, then
+   * this method saves the incoming bytes and returns false. If a
+   * complete handshake is read, or if there was one buffered in the
+   * handshake buffer, this method returns true, and `handshakeBuffer'
+   * can be used to read the handshake.
+   *
+   * @param record The input record.
+   * @return True if a complete handshake is present in the buffer;
+   * false if only a partial one.
+   */
+  protected boolean pollHandshake (final ByteBuffer fragment)
+  {
+    // Allocate space for the new fragment.
+    if (handshakeBuffer == null
+        || handshakeBuffer.remaining() < fragment.remaining())
+      {
+        // We need space for anything still unread in the handshake
+        // buffer...
+        int len = ((handshakeBuffer == null) ? 0
+                   : handshakeBuffer.position() - handshakeOffset);
+
+        // Plus room for the incoming record.
+        len += fragment.remaining();
+        reallocateBuffer(len);
+      }
+
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}",
+                  fragment, handshakeBuffer);
+    
+    // Put the fragment into the buffer.
+    handshakeBuffer.put(fragment);
+
+    return hasMessage();
+  }
+  
+  protected boolean doHash()
+  {
+    return true;
+  }
+
+  /**
+   * Tell if the handshake buffer currently has a full handshake
+   * message.
+   */
+  protected boolean hasMessage()
+  {
+    if (handshakeBuffer == null)
+      return false;
+    ByteBuffer tmp = handshakeBuffer.duplicate();
+    tmp.flip();
+    tmp.position(handshakeOffset);
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}",
+                  handshakeBuffer, tmp);
+    if (tmp.remaining() < 4)
+      return false;
+    Handshake handshake = new Handshake(tmp.slice());
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}",
+                  handshake.length(), tmp.remaining());
+    return (handshake.length() <= tmp.remaining() - 4);
+  }
+
+  /**
+   * Reallocate the handshake buffer so it can hold `totalLen'
+   * bytes. The smallest buffer allocated is 1024 bytes, and the size
+   * doubles from there until the buffer is sufficiently large.
+   */
+  private void reallocateBuffer (final int totalLen)
+  {
+    int len = handshakeBuffer == null ? -1
+                                      : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset);
+    if (len >= totalLen)
+      {
+        // Big enough; no need to reallocate; but maybe shift the contents
+        // down.
+        if (handshakeOffset > 0)
+          {
+            handshakeBuffer.flip().position(handshakeOffset);
+            handshakeBuffer.compact();
+            handshakeOffset = 0;
+          }
+        return;
+      }
+
+    // Start at 1K (probably the system's page size). Double the size
+    // from there.
+    len = 1024;
+    while (len < totalLen)
+      len = len << 1;
+    ByteBuffer newBuf = ByteBuffer.allocate (len);
+
+    // Copy the unread bytes from the old buffer.
+    if (handshakeBuffer != null)
+      {
+        handshakeBuffer.flip ();
+        handshakeBuffer.position(handshakeOffset);
+        newBuf.put(handshakeBuffer);
+      }
+    handshakeBuffer = newBuf;
+
+    // We just put only unread handshake messages in the new buffer;
+    // the offset of the next one is now zero.
+    handshakeOffset = 0;
+  }
+
+  /**
+   * Generate a certificate verify message for SSLv3. In SSLv3, a different
+   * algorithm was used to generate this value was subtly different than
+   * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is
+   * just the digest over the handshake messages.
+   * 
+   * <p>SSLv3 uses the algorithm:
+   * 
+   * <pre>
+CertificateVerify.signature.md5_hash
+  MD5(master_secret + pad_2 +
+      MD5(handshake_messages + master_secret + pad_1));
+Certificate.signature.sha_hash
+  SHA(master_secret + pad_2 +
+      SHA(handshake_messages + master_secret + pad_1));</pre>
+   * 
+   * @param md5 The running MD5 hash of the handshake.
+   * @param sha The running SHA-1 hash of the handshake.
+   * @param session The current session being negotiated.
+   * @return The computed to-be-signed value.
+   */
+  protected byte[] genV3CertificateVerify(MessageDigest md5,
+                                          MessageDigest sha,
+                                          SessionImpl session)
+  {
+    byte[] md5value = null;
+    if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+      {
+        md5.update(session.privateData.masterSecret);
+        md5.update(PAD1, 0, 48);
+        byte[] tmp = md5.digest();
+        md5.reset();
+        md5.update(session.privateData.masterSecret);
+        md5.update(PAD2, 0, 48);
+        md5.update(tmp);
+        md5value = md5.digest();
+      }
+    
+    sha.update(session.privateData.masterSecret);
+    sha.update(PAD1, 0, 40);
+    byte[] tmp = sha.digest();
+    sha.reset();
+    sha.update(session.privateData.masterSecret);
+    sha.update(PAD2, 0, 40);
+    sha.update(tmp);
+    byte[] shavalue = sha.digest();
+    
+    if (md5value != null)
+      return Util.concat(md5value, shavalue);
+    
+    return shavalue;
+  }
+  
+  /**
+   * Generate the session keys from the computed master secret.
+   * 
+   * @param clientRandom The client's nonce.
+   * @param serverRandom The server's nonce.
+   * @param session The session being established.
+   * @return The derived keys.
+   */
+  protected byte[][] generateKeys(Random clientRandom, Random serverRandom,
+                                  SessionImpl session)
+  {
+    int maclen = 20; // SHA-1.
+    if (session.suite.macAlgorithm() == MacAlgorithm.MD5)
+      maclen = 16;
+    int ivlen = 0;
+    if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES
+        || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede)
+      ivlen = 8;
+    if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES)
+      ivlen = 16;
+    int keylen = session.suite.keyLength();
+    
+    byte[][] keys = new byte[6][];
+    keys[0] = new byte[maclen]; // client_write_MAC_secret
+    keys[1] = new byte[maclen]; // server_write_MAC_secret
+    keys[2] = new byte[keylen]; // client_write_key
+    keys[3] = new byte[keylen]; // server_write_key
+    keys[4] = new byte[ivlen];  // client_write_iv
+    keys[5] = new byte[ivlen];  // server_write_iv
+    
+    IRandom prf = null;
+    if (session.version == ProtocolVersion.SSL_3)
+      {
+        byte[] seed = new byte[clientRandom.length()
+                               + serverRandom.length()];
+        serverRandom.buffer().get(seed, 0, serverRandom.length());
+        clientRandom.buffer().get(seed, serverRandom.length(),
+                                  clientRandom.length());
+        prf = new SSLRandom();
+        HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+        attr.put(SSLRandom.SECRET, session.privateData.masterSecret);
+        attr.put(SSLRandom.SEED, seed);
+        prf.init(attr);
+      }
+    else
+      {
+        byte[] seed = new byte[KEY_EXPANSION.length
+                               + clientRandom.length()
+                               + serverRandom.length()];
+        System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length);
+        serverRandom.buffer().get(seed, KEY_EXPANSION.length,
+                                  serverRandom.length());
+        clientRandom.buffer().get(seed, (KEY_EXPANSION.length
+                                         + serverRandom.length()),
+                                  clientRandom.length());
+        
+        prf = new TLSRandom();
+        HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+        attr.put(TLSRandom.SECRET, session.privateData.masterSecret);
+        attr.put(TLSRandom.SEED, seed);
+        prf.init(attr);
+      }
+    
+    try
+      {
+        prf.nextBytes(keys[0], 0, keys[0].length);
+        prf.nextBytes(keys[1], 0, keys[1].length);
+        prf.nextBytes(keys[2], 0, keys[2].length);
+        prf.nextBytes(keys[3], 0, keys[3].length);
+
+        if (session.suite.isExportable())
+          {
+            if (session.version == ProtocolVersion.SSL_3)
+              {
+                MessageDigest md5 = MessageDigest.getInstance("MD5");
+                md5.update(clientRandom.buffer());
+                md5.update(serverRandom.buffer());
+                byte[] d = md5.digest();
+                System.arraycopy(d, 0, keys[4], 0, keys[4].length);
+
+                md5.reset();
+                md5.update(serverRandom.buffer());
+                md5.update(clientRandom.buffer());
+                d = md5.digest();
+                System.arraycopy(d, 0, keys[5], 0, keys[5].length);
+
+                md5.reset();
+                md5.update(keys[2]);
+                md5.update(clientRandom.buffer());
+                md5.update(serverRandom.buffer());
+                keys[2] = Util.trim(md5.digest(), 8);
+
+                md5.reset();
+                md5.update(keys[3]);
+                md5.update(serverRandom.buffer());
+                md5.update(clientRandom.buffer());
+                keys[3] = Util.trim(md5.digest(), 8);
+              }
+            else
+              {
+                TLSRandom prf2 = new TLSRandom();
+                HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+                attr.put(TLSRandom.SECRET, keys[2]);
+                byte[] seed = new byte[CLIENT_WRITE_KEY.length +
+                                       clientRandom.length() +
+                                       serverRandom.length()];
+                System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0,
+                                 CLIENT_WRITE_KEY.length);
+                clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length,
+                                          clientRandom.length());
+                serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length
+                                          + clientRandom.length(),
+                                          serverRandom.length());
+                attr.put(TLSRandom.SEED, seed);
+                prf2.init(attr);
+                keys[2] = new byte[8];
+                prf2.nextBytes(keys[2], 0, keys[2].length);
+                
+                attr.put(TLSRandom.SECRET, keys[3]);
+                seed = new byte[SERVER_WRITE_KEY.length +
+                                serverRandom.length() +
+                                clientRandom.length()];
+                System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0,
+                                 SERVER_WRITE_KEY.length);
+                serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length,
+                                          serverRandom.length());
+                clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length
+                                          + serverRandom.length(),
+                                          + clientRandom.length());
+                attr.put(TLSRandom.SEED, seed);
+                prf2.init(attr);
+                keys[3] = new byte[8];
+                prf2.nextBytes(keys[3], 0, keys[3].length);
+                
+                attr.put(TLSRandom.SECRET, new byte[0]);
+                seed = new byte[IV_BLOCK.length +
+                                clientRandom.length() +
+                                serverRandom.length()];
+                System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length);
+                clientRandom.buffer().get(seed, IV_BLOCK.length,
+                                          clientRandom.length());
+                serverRandom.buffer().get(seed, IV_BLOCK.length
+                                          + clientRandom.length(),
+                                          serverRandom.length());
+                attr.put(TLSRandom.SEED, seed);
+                prf2.init(attr);
+                prf2.nextBytes(keys[4], 0, keys[4].length);
+                prf2.nextBytes(keys[5], 0, keys[5].length);
+              }
+          }
+        else
+          {
+            prf.nextBytes(keys[4], 0, keys[4].length);
+            prf.nextBytes(keys[5], 0, keys[5].length);
+          }
+      }
+    catch (LimitReachedException lre)
+      {
+        // Won't happen with our implementation.
+        throw new Error(lre);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new Error(nsae);
+      }
+    
+    if (Debug.DEBUG_KEY_EXCHANGE)
+      logger.logv(Component.SSL_KEY_EXCHANGE,
+                  "keys generated;\n  [0]: {0}\n  [1]: {1}\n  [2]: {2}\n" +
+                  "  [3]: {3}\n  [4]: {4}\n  [5]: {5}",
+                  Util.toHexString(keys[0], ':'),
+                  Util.toHexString(keys[1], ':'),
+                  Util.toHexString(keys[2], ':'),
+                  Util.toHexString(keys[3], ':'),
+                  Util.toHexString(keys[4], ':'),
+                  Util.toHexString(keys[5], ':'));
+    return keys;
+  }
+  
+  /**
+   * Generate a "finished" message. The hashes passed in are modified
+   * by this function, so they should be clone copies of the digest if
+   * the hash function needs to be used more.
+   * 
+   * @param md5 The MD5 computation.
+   * @param sha The SHA-1 computation.
+   * @param isClient Whether or not the client-side finished message is
+   *  being computed.
+   * @param session The current session.
+   * @return A byte buffer containing the computed finished message.
+   */
+  protected ByteBuffer generateFinished(MessageDigest md5,
+                                        MessageDigest sha,
+                                        boolean isClient,
+                                        SessionImpl session)
+  {
+    ByteBuffer finishedBuffer = null;
+    if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+      {
+        finishedBuffer = ByteBuffer.allocate(12);
+        TLSRandom prf = new TLSRandom();
+        byte[] md5val = md5.digest();
+        byte[] shaval = sha.digest();
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}",
+                      Util.toHexString(md5val, ':'),
+                      Util.toHexString(shaval, ':'));
+        byte[] seed = new byte[CLIENT_FINISHED.length
+                               + md5val.length
+                               + shaval.length];
+        if (isClient)
+          System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length);
+        else
+          System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length);
+        System.arraycopy(md5val, 0,
+                         seed, CLIENT_FINISHED.length,
+                         md5val.length);
+        System.arraycopy(shaval, 0,
+                         seed, CLIENT_FINISHED.length + md5val.length,
+                         shaval.length);
+        HashMap<String, Object> params = new HashMap<String, Object>(2);
+        params.put(TLSRandom.SECRET, session.privateData.masterSecret);
+        params.put(TLSRandom.SEED, seed);
+        prf.init(params);
+        byte[] buf = new byte[12];
+        prf.nextBytes(buf, 0, buf.length);
+        finishedBuffer.put(buf).position(0);
+      }
+    else
+      {
+        // The SSLv3 algorithm is:
+        //
+        //   enum { client(0x434C4E54), server(0x53525652) } Sender;
+        //
+        //   struct {
+        //     opaque md5_hash[16];
+        //     opaque sha_hash[20];
+        //   } Finished;
+        //
+        //   md5_hash       MD5(master_secret + pad2 +
+        //                      MD5(handshake_messages + Sender +
+        //                          master_secret + pad1));
+        //   sha_hash        SHA(master_secret + pad2 +
+        //                       SHA(handshake_messages + Sender +
+        //                           master_secret + pad1));
+        //
+
+        finishedBuffer = ByteBuffer.allocate(36);
+        
+        md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+        md5.update(session.privateData.masterSecret);
+        md5.update(PAD1);
+        
+        byte[] tmp = md5.digest();
+        md5.reset();
+        md5.update(session.privateData.masterSecret);
+        md5.update(PAD2);
+        md5.update(tmp);
+        finishedBuffer.put(md5.digest());
+        
+        sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+        sha.update(session.privateData.masterSecret);
+        sha.update(PAD1, 0, 40);
+        
+        tmp = sha.digest();
+        sha.reset();
+        sha.update(session.privateData.masterSecret);
+        sha.update(PAD2, 0, 40);
+        sha.update(tmp);
+        finishedBuffer.put(sha.digest()).position(0);
+      }
+    return finishedBuffer;
+  }
+  
+  protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)
+    throws SSLException
+  {
+    try
+      {
+        keyAgreement = KeyAgreement.getInstance("DH");
+        keyAgreement.init(dhKey, random);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new SSLException(ike);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new SSLException(nsae);
+      }
+  }
+  
+  protected void generateMasterSecret(Random clientRandom,
+                                      Random serverRandom,
+                                      SessionImpl session)
+    throws SSLException
+  {
+    assert(clientRandom != null);
+    assert(serverRandom != null);
+    assert(session != null);
+    
+    if (Debug.DEBUG_KEY_EXCHANGE)
+      logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
+                  new ByteArray(preMasterSecret));
+    
+    if (session.version == ProtocolVersion.SSL_3)
+      {
+        try
+          {
+            MessageDigest _md5 = MessageDigest.getInstance("MD5");
+            MessageDigest _sha = MessageDigest.getInstance("SHA");
+            session.privateData.masterSecret = new byte[48];
+            
+            _sha.update((byte) 'A');
+            _sha.update(preMasterSecret);
+            _sha.update(clientRandom.buffer());
+            _sha.update(serverRandom.buffer());
+            _md5.update(preMasterSecret);
+            _md5.update(_sha.digest());
+            _md5.digest(session.privateData.masterSecret, 0, 16);
+            
+            _sha.update((byte) 'B');
+            _sha.update((byte) 'B');
+            _sha.update(preMasterSecret);
+            _sha.update(clientRandom.buffer());
+            _sha.update(serverRandom.buffer());
+            _md5.update(preMasterSecret);
+            _md5.update(_sha.digest());
+            _md5.digest(session.privateData.masterSecret, 16, 16);
+
+            _sha.update((byte) 'C');
+            _sha.update((byte) 'C');
+            _sha.update((byte) 'C');
+            _sha.update(preMasterSecret);
+            _sha.update(clientRandom.buffer());
+            _sha.update(serverRandom.buffer());
+            _md5.update(preMasterSecret);
+            _md5.update(_sha.digest());
+            _md5.digest(session.privateData.masterSecret, 32, 16);
+          }
+        catch (DigestException de)
+          {
+            throw new SSLException(de);
+          }
+        catch (NoSuchAlgorithmException nsae)
+          {
+            throw new SSLException(nsae);
+          }
+      }
+    else // TLSv1.0 and later
+      {
+        byte[] seed = new byte[clientRandom.length()
+                               + serverRandom.length()
+                               + MASTER_SECRET.length];
+        System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length);
+        clientRandom.buffer().get(seed, MASTER_SECRET.length,
+                                  clientRandom.length());
+        serverRandom.buffer().get(seed,
+                                  MASTER_SECRET.length + clientRandom.length(),
+                                  serverRandom.length());
+        TLSRandom prf = new TLSRandom();
+        HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+        attr.put(TLSRandom.SECRET, preMasterSecret);
+        attr.put(TLSRandom.SEED, seed);
+        prf.init(attr);
+        
+        session.privateData.masterSecret = new byte[48];
+        prf.nextBytes(session.privateData.masterSecret, 0, 48);
+      }
+    
+    if (Debug.DEBUG_KEY_EXCHANGE)
+      logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}",
+                 new ByteArray(session.privateData.masterSecret));
+    
+    // Wipe out the preMasterSecret.
+    for (int i = 0; i < preMasterSecret.length; i++)
+      preMasterSecret[i] = 0;
+  }
+  
+  protected void setupSecurityParameters(byte[][] keys, boolean isClient,
+                                         SSLEngineImpl engine,
+                                         CompressionMethod compression)
+    throws SSLException
+  {
+    assert(keys.length == 6);
+    assert(engine != null);
+    assert(compression != null);
+
+    try
+      {
+        CipherSuite s = engine.session().suite;
+        Cipher inCipher = s.cipher();
+        Mac inMac = s.mac(engine.session().version);
+        Inflater inflater = (compression == CompressionMethod.ZLIB
+                             ? new Inflater() : null); 
+        inCipher.init(Cipher.DECRYPT_MODE,
+                      new SecretKeySpec(keys[isClient ? 3 : 2],
+                                        s.cipherAlgorithm().toString()),
+                      new IvParameterSpec(keys[isClient ? 5 : 4]));
+        inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0],
+                                     inMac.getAlgorithm()));
+        inParams = new InputSecurityParameters(inCipher, inMac,
+                                               inflater,
+                                               engine.session(), s);
+                
+        Cipher outCipher = s.cipher();
+        Mac outMac = s.mac(engine.session().version);
+        Deflater deflater = (compression == CompressionMethod.ZLIB
+                             ? new Deflater() : null);
+        outCipher.init(Cipher.ENCRYPT_MODE,
+                       new SecretKeySpec(keys[isClient ? 2 : 3],
+                                         s.cipherAlgorithm().toString()),
+                       new IvParameterSpec(keys[isClient ? 4 : 5]));
+        outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1],
+                                      outMac.getAlgorithm()));
+        outParams = new OutputSecurityParameters(outCipher, outMac,
+                                                 deflater,
+                                                 engine.session(), s);
+      }
+    catch (InvalidAlgorithmParameterException iape)
+      {
+        throw new SSLException(iape);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new SSLException(ike);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new SSLException(nsae);
+      }
+    catch (NoSuchPaddingException nspe)
+      {
+        throw new SSLException(nspe);
+      }
+  }
+
+  protected void generatePSKSecret(String identity, byte[] otherkey,
+                                   boolean isClient)
+    throws SSLException
+  {
+    SecretKey key = null;
+    try
+      {
+        key = engine.contextImpl.pskManager.getKey(identity);
+      }
+    catch (KeyManagementException kme)
+      {
+      }
+    if (key != null)
+      {
+        byte[] keyb = key.getEncoded();
+        if (otherkey == null)
+          {
+            otherkey = new byte[keyb.length];
+          }
+        preMasterSecret = new byte[otherkey.length + keyb.length + 4];
+        preMasterSecret[0] = (byte) (otherkey.length >>> 8);
+        preMasterSecret[1] = (byte)  otherkey.length;
+        System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length);
+        preMasterSecret[otherkey.length + 2]
+          = (byte) (keyb.length >>> 8);
+        preMasterSecret[otherkey.length + 3]
+          = (byte)  keyb.length;
+        System.arraycopy(keyb, 0, preMasterSecret,
+                         otherkey.length + 4, keyb.length);
+      }
+    else
+      {
+        // Generate a random, fake secret.
+        preMasterSecret = new byte[8];
+        preMasterSecret[1] = 2;
+        preMasterSecret[5] = 2;
+        preMasterSecret[6] = (byte) engine.session().random().nextInt();
+        preMasterSecret[7] = (byte) engine.session().random().nextInt();
+      }
+    
+    if (Debug.DEBUG_KEY_EXCHANGE)
+      logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}",
+                  identity, key);
+                    
+    generateMasterSecret(clientRandom, serverRandom,
+                         engine.session());
+    byte[][] keys = generateKeys(clientRandom, serverRandom,
+                                 engine.session());
+    setupSecurityParameters(keys, isClient, engine, compression);
+  }
+  
+  protected class DHPhase extends DelegatedTask
+  {
+    private final DHPublicKey key;
+    private final boolean full;
+    
+    protected DHPhase(DHPublicKey key)
+    {
+      this(key, true);
+    }
+
+    protected DHPhase(DHPublicKey key, boolean full)
+    {
+      this.key = key;
+      this.full = full;
+    }
+
+    protected void implRun() throws InvalidKeyException, SSLException
+    {
+      keyAgreement.doPhase(key, true);
+      preMasterSecret = keyAgreement.generateSecret();
+      if (full)
+        {
+          generateMasterSecret(clientRandom, serverRandom, engine.session());
+          byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+          setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression);
+        }
+    }
+  }
+  
+  protected class CertVerifier extends DelegatedTask
+  {
+    private final boolean clientSide;
+    private final X509Certificate[] chain;
+    private boolean verified;
+
+    protected CertVerifier(boolean clientSide, X509Certificate[] chain)
+    {
+      this.clientSide = clientSide;
+      this.chain = chain;
+    }
+    
+    boolean verified()
+    {
+      return verified;
+    }
+    
+    protected void implRun()
+    {
+      X509TrustManager tm = engine.contextImpl.trustManager;
+      if (clientSide)
+        {
+          try
+            {
+              tm.checkServerTrusted(chain, null);
+              verified = true;
+            }
+          catch (CertificateException ce)
+            {
+              if (Debug.DEBUG)
+                logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce);
+              // For client connections, ask the user if the certificate is OK.
+              CallbackHandler verify = new DefaultCallbackHandler();
+              GetSecurityPropertyAction gspa
+                = new GetSecurityPropertyAction("jessie.certificate.handler");
+              String clazz = AccessController.doPrivileged(gspa);
+              try
+                {
+                  ClassLoader cl =
+                    AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
+                      {
+                        public ClassLoader run() throws Exception
+                        {
+                          return ClassLoader.getSystemClassLoader();
+                        }
+                      });
+                  verify = (CallbackHandler) cl.loadClass(clazz).newInstance();
+                }
+              catch (Exception x)
+                {
+                  // Ignore.
+                  if (Debug.DEBUG)
+                    logger.log(Component.SSL_DELEGATED_TASK,
+                               "callback handler loading", x);
+                }
+              // XXX Internationalize
+              CertificateCallback confirm =
+                new CertificateCallback(chain[0],
+                "The server's certificate could not be verified. There is no proof " +
+                "that this server is who it claims to be, or that their certificate " +
+                "is valid. Do you wish to continue connecting? ");
+
+              try
+                {
+                  verify.handle(new Callback[] { confirm });
+                  verified = confirm.getSelectedIndex() == ConfirmationCallback.YES;
+                }
+              catch (Exception x)
+                {
+                  if (Debug.DEBUG)
+                    logger.log(Component.SSL_DELEGATED_TASK,
+                               "callback handler exception", x);
+                  verified = false;
+                }
+            }
+        }
+      else
+        {
+          try
+            {
+              tm.checkClientTrusted(chain, null);
+            }
+          catch (CertificateException ce)
+            {
+              verified = false;
+            }
+        }
+      
+      if (verified)
+        engine.session().setPeerVerified(true);
+    }
+  }
+  
+  protected class DHE_PSKGen extends DelegatedTask
+  {
+    private final DHPublicKey dhKey;
+    private final SecretKey psKey;
+    private final boolean isClient;
+    
+    protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)
+    {
+      this.dhKey = dhKey;
+      this.psKey = psKey;
+      this.isClient = isClient;
+    }
+
+    /* (non-Javadoc)
+     * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun()
+     */
+    @Override protected void implRun() throws Throwable
+    {
+      keyAgreement.doPhase(dhKey, true);
+      byte[] dhSecret = keyAgreement.generateSecret();
+      byte[] psSecret = null;
+      if (psKey != null)
+        psSecret = psKey.getEncoded();
+      else
+        {
+          psSecret = new byte[8];
+          engine.session().random().nextBytes(psSecret);
+        }
+      
+      preMasterSecret = new byte[dhSecret.length + psSecret.length + 4];
+      preMasterSecret[0] = (byte) (dhSecret.length >>> 8);
+      preMasterSecret[1] = (byte)  dhSecret.length;
+      System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length);
+      preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8);
+      preMasterSecret[dhSecret.length + 3] = (byte)  psSecret.length;
+      System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4,
+                       psSecret.length);
+      
+      generateMasterSecret(clientRandom, serverRandom, engine.session());
+      byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+      setupSecurityParameters(keys, isClient, engine, compression);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Alert.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,288 @@
+/* Alert.java -- SSL Alert message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An alert message in the SSL protocol. Alerts are sent both as warnings
+ * which may allow execution to continue, or they may be fatal, which will
+ * halt this session. An alert object is composed of two enums -- the level,
+ * which indicates the seriousness of the alert, and the description, which
+ * indicates the reason for the alert.
+ *
+ * <pre>
+ * struct {
+ *   AlertLevel       level;
+ *   AlertDescription description;
+ * }
+ * </pre>
+ */
+public final class Alert implements Constructed
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  /** The underlying byte buffer. */
+  private final ByteBuffer buffer;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public Alert (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+  }
+  
+  public Alert (final Level level, final Description description)
+  {
+    level.getClass ();
+    description.getClass ();
+    ByteBuffer b = ByteBuffer.allocate (2);
+    b.put (0, (byte) level.getValue ());
+    b.put (1, (byte) description.getValue ());
+    this.buffer = b.asReadOnlyBuffer ();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    return 2;
+  }
+
+  byte[] getEncoded()
+  {
+    byte[] buf = new byte[2];
+    buffer.position (0);
+    buffer.get (buf);
+    return buf;
+  }
+
+  public Level level()
+  {
+    return Level.forInteger (buffer.get (0) & 0xFF);
+  }
+
+  public Description description()
+  {
+    return Description.forInteger (buffer.get (1) & 0xFF);
+  }
+
+  public void setLevel (final Level level)
+  {
+    buffer.put (0, (byte) level.getValue ());
+  }
+
+  public void setDescription (final Description description)
+  {
+    buffer.put (1, (byte) description.getValue ());
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof Alert))
+      return false;
+    Alert that = (Alert) o;
+    return that.buffer.position (0).equals (buffer.position (0));
+  }
+
+  public int hashCode ()
+  {
+    return buffer.getShort (0) & 0xFFFF;
+  }
+
+  public String toString()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  level:       ");
+    out.print (level ());
+    out.println (";");
+    if (prefix != null) out.print (prefix);
+    out.print ("  description: ");
+    out.print (description ());
+    out.println (";");
+    if (prefix != null) out.print (prefix);
+    out.print ("} Alert;");
+    return str.toString ();
+  }
+
+  // Enumerations.
+  // -------------------------------------------------------------------------
+
+  /**
+   * The level enumeration.
+   *
+   * <pre>
+   * enum { warning(1), fatal(2), (255) } AlertLevel;
+   * </pre>
+   */
+  public static enum Level
+  {
+
+    WARNING (1), FATAL (2);
+    
+    private final int value;
+
+    private Level(int value)
+    {
+      this.value = value;
+    }
+
+    public static Level forInteger (final int value)
+    {
+      switch (value & 0xFF)
+        {
+        case 1: return WARNING;
+        case 2: return FATAL;
+        default: throw new IllegalArgumentException ("invalid alert level: " + value);
+        }
+    }
+
+    public int getValue()
+    {
+      return value;
+    }
+  }
+
+  /**
+   * The description enumeration.
+   */
+  public static enum Description
+  {
+    CLOSE_NOTIFY                    (  0),
+    UNEXPECTED_MESSAGE              ( 10),
+    BAD_RECORD_MAC                  ( 20),
+    DECRYPTION_FAILED               ( 21),
+    RECORD_OVERFLOW                 ( 22),
+    DECOMPRESSION_FAILURE           ( 30),
+    HANDSHAKE_FAILURE               ( 40),
+    NO_CERTIFICATE                  ( 41),
+    BAD_CERTIFICATE                 ( 42),
+    UNSUPPORTED_CERTIFICATE         ( 43),
+    CERTIFICATE_REVOKED             ( 44),
+    CERTIFICATE_EXPIRED             ( 45),
+    CERTIFICATE_UNKNOWN             ( 46),
+    ILLEGAL_PARAMETER               ( 47),
+    UNKNOWN_CA                      ( 48),
+    ACCESS_DENIED                   ( 49),
+    DECODE_ERROR                    ( 50),
+    DECRYPT_ERROR                   ( 51),
+    EXPORT_RESTRICTION              ( 60),
+    PROTOCOL_VERSION                ( 70),
+    INSUFFICIENT_SECURITY           ( 71),
+    INTERNAL_ERROR                  ( 80),
+    USER_CANCELED                   ( 90),
+    NO_RENEGOTIATION                (100),
+    UNSUPPORTED_EXTENSION           (110),
+    CERTIFICATE_UNOBTAINABLE        (111),
+    UNRECOGNIZED_NAME               (112),
+    BAD_CERTIFICATE_STATUS_RESPONSE (113),
+    BAD_CERTIFICATE_HASH_VALUE      (114),
+    UNKNOWN_SRP_USERNAME            (120),
+    MISSING_SRP_USERNAME            (121);
+    
+    private final int value;
+
+    private Description(int value)
+    {
+      this.value = value;
+    }
+
+    /**
+     * Return an alert description object based on the specified integer
+     * value.
+     *
+     * @param value The raw description value.
+     * @return The appropriate description object.
+     */
+    public static Description forInteger (final int value)
+    {
+      switch (value & 0xFF)
+        {
+        case 0: return CLOSE_NOTIFY;
+        case 10: return UNEXPECTED_MESSAGE;
+        case 20: return BAD_RECORD_MAC;
+        case 21: return DECRYPTION_FAILED;
+        case 22: return RECORD_OVERFLOW;
+        case 30: return DECOMPRESSION_FAILURE;
+        case 40: return HANDSHAKE_FAILURE;
+        case 41: return NO_CERTIFICATE;
+        case 42: return BAD_CERTIFICATE;
+        case 43: return UNSUPPORTED_CERTIFICATE;
+        case 44: return CERTIFICATE_REVOKED;
+        case 45: return CERTIFICATE_EXPIRED;
+        case 46: return CERTIFICATE_UNKNOWN;
+        case 47: return ILLEGAL_PARAMETER;
+        case 48: return UNKNOWN_CA;
+        case 49: return ACCESS_DENIED;
+        case 50: return DECODE_ERROR;
+        case 51: return DECRYPT_ERROR;
+        case 60: return EXPORT_RESTRICTION;
+        case 70: return PROTOCOL_VERSION;
+        case 71: return INSUFFICIENT_SECURITY;
+        case 80: return INTERNAL_ERROR;
+        case 90: return USER_CANCELED;
+        case 100: return NO_RENEGOTIATION;
+        case 120: return UNKNOWN_SRP_USERNAME;
+        case 121: return MISSING_SRP_USERNAME;
+        default: throw new IllegalArgumentException("unknown alert description: " + value);
+        }
+    }
+
+    public int getValue()
+    {
+      return value;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/AlertException.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,101 @@
+/* AlertException.java -- exceptions generated by SSL alerts.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * An exception generated by an SSL alert.
+ */
+public class AlertException extends SSLException
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final Alert alert;
+  private final boolean isLocal;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public AlertException(Alert alert, boolean isLocal)
+  {
+    super(alert.description().toString());
+    this.alert = alert;
+    this.isLocal = isLocal;
+  }
+
+  public AlertException(Alert alert)
+  {
+    this(alert, true);
+  }
+  
+  public AlertException(Alert alert, boolean isLocal, Throwable cause)
+  {
+    super(alert.description().toString(), cause);
+    this.alert = alert;
+    this.isLocal = isLocal;
+  }
+  
+  public AlertException(Alert alert, Throwable cause)
+  {
+    this(alert, true, cause);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public String getMessage()
+  {
+    return alert.description() + ": " +
+      (isLocal ? "locally generated; " : "remotely generated; ") +
+      alert.level();
+  }
+
+  public Alert alert ()
+  {
+    return alert;
+  }
+  
+  public boolean isLocal()
+  {
+    return isLocal;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Builder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,66 @@
+/* Builder.java -- builder interface for protocol objects.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The base interface for classes that build SSL protocol objects. The
+ * general contract for Builder implementations is that they maintain a
+ * buffer that grows to fit the object being built; the allocated size of
+ * this buffer may be larger than the built object needs, but the general
+ * effort will be not to allocate too large a buffer.
+ * 
+ * <p>Once the object is built, through various <em>setters</em> for
+ * the object's attributes, the final buffer may be retrieved with the
+ * {@link #buffer()} method.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface Builder extends Constructed
+{
+  /**
+   * Returns the final buffer, possibly containing the built object. The
+   * returned buffer will be "trimmed" to size: its position will be zero,
+   * and its limit and capacity set to the length of the built object.
+   * 
+   * @return The underlying buffer.
+   */
+  ByteBuffer buffer();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Certificate.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,177 @@
+/* Certificate.java -- SSL certificate message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * The certificate object. This is used by both the client and the server
+ * to send their certificates (if any) to one another.
+ * 
+ * <pre>opaque ASN.1Cert&lt;1..2^24-1&gt;;
+
+struct {
+  ASN.1Cert certificate_list&lt;0..2^24-1&gt;;
+} Certificate;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class Certificate implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  protected ByteBuffer buffer;
+  protected final CertificateType type;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public Certificate (final ByteBuffer buffer, final CertificateType type)
+  {
+    buffer.getClass ();
+    type.getClass ();
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    this.type = type;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    return (((buffer.get (0) & 0xFF) << 24)
+            | buffer.getShort (1)) + 3;
+  }
+
+  public List<java.security.cert.Certificate> certificates ()
+    throws CertificateException, NoSuchAlgorithmException
+  {
+    LinkedList<java.security.cert.Certificate> list
+      = new LinkedList<java.security.cert.Certificate>();
+    CertificateFactory factory = CertificateFactory.getInstance(type.toString());
+    int length = (((buffer.get(0) & 0xFF) << 16)
+                  | (buffer.getShort(1) & 0xFFFF));
+    ByteBuffer b = (ByteBuffer) buffer.duplicate().position(3);
+    for (int i = 3; i < length; )
+      {
+        int length2 = (((b.get () & 0xFF) << 16)
+                       | (b.getShort () & 0xFFFF));
+        byte[] buf = new byte[length2];
+        b.position(i+3);
+        b.get (buf);
+        list.add(factory.generateCertificate (new ByteArrayInputStream (buf)));
+        i += length2 + 3;
+        b.position(i);
+      }
+    return list;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println ("struct {");
+    try
+      {
+        List certs = certificates ();
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  certificateList: [");
+        out.print (certs.size ());
+        out.println ("] {");
+        for (Iterator it = certs.iterator (); it.hasNext (); )
+          {
+            java.security.cert.Certificate cert =
+              (java.security.cert.Certificate) it.next ();
+            if (prefix != null)
+              out.print (prefix);
+            out.print ("    ");
+            if (cert instanceof X509Certificate)
+              out.print (((X509Certificate) cert).getSubjectDN ());
+            else
+              out.print (cert);
+            out.println (";");
+          }
+        if (prefix != null)
+          out.print (prefix);
+        out.println ("  };");
+      }
+    catch (CertificateException ce)
+      {
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  ");
+        out.print (ce);
+        out.println (";");
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  ");
+        out.print (nsae);
+        out.println (";");
+      }
+    out.print ("} Certificate;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,94 @@
+/* CertificateBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.security.cert.CertificateException;
+
+/**
+ * Builder for {@link Certificate} objects.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateBuilder extends Certificate implements Builder
+{
+  public CertificateBuilder(final CertificateType certType)
+  {
+    super(ByteBuffer.allocate(1024), certType);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+  }
+
+  public void setCertificates (final List<? extends java.security.cert.Certificate> certificates)
+    throws CertificateException
+  {
+    ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+    for (java.security.cert.Certificate cert : certificates)
+      {
+        byte[] encoded = cert.getEncoded();
+        out.write((encoded.length >>> 16) & 0xFF);
+        out.write((encoded.length >>>  8) & 0xFF);
+        out.write( encoded.length         & 0xFF);
+        try
+          {
+            out.write(encoded);
+          }
+        catch (IOException shouldNotHappen)
+          {
+            // ignore; this is a ByteArrayOutputStream.
+          }
+      }
+    byte[] certs = out.toByteArray();
+    // There is only one field in Certificate; so it is easy to reallocate.
+    if (buffer.capacity() < certs.length + 3)
+      buffer = ByteBuffer.allocate(certs.length + 3);
+    buffer.put(0, (byte) (certs.length >>> 16));
+    buffer.putShort(1, (short) certs.length);
+    ((ByteBuffer) buffer.duplicate().position(3)).put(certs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateRequest.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,155 @@
+/* CertificateRequest.java -- SSL CertificateRequest message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A request by the server for a client certificate.
+ *
+ * <pre>
+struct
+{
+  ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
+  DistinguishedName certificate_authorities&lt;3..2^16-1&gt;;
+} CertificateRequest;
+</pre>
+ */
+public class CertificateRequest implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  protected ByteBuffer buffer;
+  
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public CertificateRequest(final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    int o1 = (buffer.get (0) & 0xFF) + 1;
+    return o1 + (buffer.getShort (o1) & 0xFFFF) + 2;
+  }
+
+  public ClientCertificateTypeList types ()
+  {
+    return new ClientCertificateTypeList(buffer.duplicate());
+  }
+
+  public X500PrincipalList authorities ()
+  {
+    int offset = (buffer.get (0) & 0xFF) + 1;
+    return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice());
+  }
+
+  public String toString()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    String subprefix = "  ";
+    if (prefix != null) subprefix = prefix + "  ";
+    if (prefix != null) out.print (prefix);
+    out.println("struct {");
+    if (prefix != null) out.print (prefix);
+    out.println ("  types =");
+    out.println (types ().toString (subprefix));
+    if (prefix != null) out.print (prefix);
+    out.println("  authorities =");
+    out.println (authorities ().toString (subprefix));
+    if (prefix != null) out.print (prefix);
+    out.print ("} CertificateRequest;");
+    return str.toString();
+  }
+
+  public static enum ClientCertificateType
+  {
+    RSA_SIGN     (1),
+    DSS_SIGN     (2),
+    RSA_FIXED_DH (3),
+    DSS_FIXED_DH (4);
+
+    private final int value;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    private ClientCertificateType (final int value)
+    {
+      this.value = value;
+    }
+
+    // Class method.
+    // -----------------------------------------------------------------------
+
+    static ClientCertificateType forValue (final int value)
+    {
+      switch (value)
+        {
+        case 1: return RSA_SIGN;
+        case 2: return DSS_SIGN;
+        case 3: return RSA_FIXED_DH;
+        case 4: return DSS_FIXED_DH;
+        default: throw new IllegalArgumentException("unknown client certificate type: " + value);
+        }
+    }
+
+    public int getValue()
+    {
+      return value;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,113 @@
+/* CertificateRequestBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Builder for {@link CertificateRequest} objects.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateRequestBuilder extends CertificateRequest
+  implements Builder
+{
+  public CertificateRequestBuilder()
+  {
+    super(ByteBuffer.allocate(1024));
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().limit(length())).slice();
+  }
+
+  public void setTypes(List<ClientCertificateType> types)
+  {
+    ensureCapacity(types.size() + 3);
+    buffer.put(0, (byte) types.size());
+    ByteBuffer b = (ByteBuffer) buffer.duplicate().position(1);
+    for (ClientCertificateType type : types)
+      b.put((byte) type.getValue());
+  }
+  
+  public void setAuthorities(List<X500Principal> authorities)
+  {
+    ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+    for (X500Principal auth : authorities)
+      {
+        byte[] encoded = auth.getEncoded();
+        out.write((encoded.length >>> 8) & 0xFF);
+        out.write( encoded.length        & 0xFF);
+        try
+          {
+            out.write(encoded);
+          }
+        catch (IOException ignored)
+          {
+            // Ignored; we use a ByteArrayOutputStream.
+          }
+      }
+    byte[] auths = out.toByteArray();
+    int typesLen = 1 + (buffer.get(0) & 0xFF);
+    int len = typesLen + auths.length + 2;
+    ensureCapacity(len);
+    buffer.putShort(typesLen, (short) auths.length);
+    ((ByteBuffer) buffer.duplicate().position(typesLen + 2)).put(auths);
+  }
+  
+  public void ensureCapacity(final int capacity)
+  {
+    if (buffer.capacity() >= capacity)
+      return;
+    ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+    newBuffer.duplicate().put(buffer);
+    buffer = newBuffer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateStatusRequest.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,272 @@
+/* CertificateStatusRequest.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * <pre>
+struct {
+  CertificateStatusType status_type;
+  select (status_type) {
+    case ocsp: OCSPStatusRequest;
+  } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+  ResponderID responder_id_list&lt;0..2^16-1&gt;;
+  Extensions  request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID&lt;1..2^16-1&gt;;
+opaque Extensions&lt;0..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class CertificateStatusRequest extends Value implements Iterable<byte[]>
+{
+  private ByteBuffer buffer;
+  
+  public CertificateStatusRequest(final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+  }
+  
+  public CertificateStatusRequest(CertificateStatusType type,
+                                  List<byte[]> responderIdList,
+                                  byte[] requestExtensions)
+  {
+    if (type != CertificateStatusType.OCSP)
+      throw new IllegalArgumentException();
+    int length = 3;
+    int idsLength = 0;
+    for (byte[] responderId : responderIdList)
+      {
+        length += 2 + responderId.length;
+        idsLength += 2 + responderId.length;
+      }
+    length += 2 + requestExtensions.length;
+    buffer = ByteBuffer.allocate(length);
+    buffer.put((byte) 1);
+    buffer.putShort((short) idsLength);
+    for (byte[] responderId : responderIdList)
+      buffer.putShort((short) responderId.length).put(responderId);
+    buffer.putShort((short) requestExtensions.length);
+    buffer.put(requestExtensions);
+    buffer.rewind();
+  }
+
+  public int length()
+  {
+    int l = 3 + (buffer.getShort(1) & 0xFFFF);
+    return l + (buffer.getShort(l) & 0xFFFF) + 2;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+  
+  public CertificateStatusType statusType()
+  {
+    int x = buffer.get(0) & 0xFF;
+    if (x == 1)
+      return CertificateStatusType.OCSP;
+    throw new IllegalArgumentException ("invalid type: " + x);
+  }
+
+  public int size()
+  {
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    for (int i = 3; i < len; )
+      {
+        int l = buffer.getShort(i);
+        i += l + 2;
+        n++;
+      }
+    return n;
+  }
+  
+  public byte[] responderId(int index)
+  {
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    int i = 3;
+    while (i < len && n <= index)
+      {
+        int l = buffer.getShort(i) & 0xFFFF;
+        if (n == index)
+          {
+            byte[] b = new byte[l];
+            ((ByteBuffer) buffer.duplicate().position(i+2)).get(b);
+            return b;
+          }
+        i += l + 2;
+        n++;
+      }
+    throw new IndexOutOfBoundsException();
+  }
+  
+  public byte[] requestExtensions()
+  {
+    int l = 2 + (buffer.getShort(0) & 0xFFFF);
+    int ll = buffer.getShort(l) & 0xFFFF;
+    byte[] b = new byte[ll];
+    ((ByteBuffer) buffer.duplicate().position(ll+2)).get(b);
+    return b;
+  }
+  
+  public void setStatusType(CertificateStatusType type)
+  {
+    buffer.put(0, (byte) type.value);
+  }
+  
+  public void setRequestIdListLength(int newLength)
+  {
+    if (newLength < 0 || newLength > 0xFFFF)
+      throw new IllegalArgumentException("length out of range");
+    buffer.putShort(1, (short) newLength);
+  }
+  
+  public void putRequestId(int index, byte[] id)
+  {
+    if (id.length > 0xFFFF)
+      throw new IllegalArgumentException("request ID too large");
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    int i = 3;
+    while (i < len && n < index)
+      {
+        int l = buffer.getShort(i) & 0xFFFF;
+        i += l + 2;
+        n++;
+      }
+    if (n < index)
+      throw new IndexOutOfBoundsException();
+    buffer.putShort(i, (short) id.length);
+    ((ByteBuffer) buffer.duplicate().position(i)).put(id);
+  }
+  
+  public void setRequestExtensions(int index, byte[] ext)
+  {
+    if (ext.length > 0xFFFF)
+      throw new IllegalArgumentException("exceptions too large");
+    int off = 3 + (buffer.getShort(1) & 0xFFFF);
+    buffer.putShort(off, (short) ext.length);
+    ((ByteBuffer) buffer.duplicate().position(off+2)).put(ext);
+  }
+  
+  public Iterator<byte[]> iterator()
+  {
+    return new ResponderIdIterator();
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  status_type = ");
+    out.print(statusType());
+    out.println(";");
+    String subprefix = "    ";
+    if (prefix != null) subprefix = prefix + subprefix;
+    if (prefix != null) out.print(prefix);
+    out.println("  responder_id_list = {");
+    for (byte[] b : this)
+      out.print(Util.hexDump(b, subprefix));
+    if (prefix != null) out.print(prefix);
+    out.println("  };");
+    if (prefix != null) out.print(prefix);
+    out.println("  request_extensions =");
+    out.print(Util.hexDump(requestExtensions(), subprefix));
+    if (prefix != null) out.print(prefix);
+    out.print("} CertificateStatus;");
+    return str.toString();
+  }
+  
+  public class ResponderIdIterator implements Iterator<byte[]>
+  {
+    private int index;
+    
+    public ResponderIdIterator()
+    {
+      index = 0;
+    }
+    
+    public byte[] next() throws NoSuchElementException
+    {
+      try
+        {
+          return responderId(index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException();
+        }
+    }
+    
+    public boolean hasNext()
+    {
+      return index < size();
+    }
+    
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateStatusType.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,13 @@
+package gnu.javax.net.ssl.provider;
+
+public enum CertificateStatusType
+{
+  OCSP (1);
+  
+  public final int value;
+  
+  private CertificateStatusType (final int value)
+  {
+    this.value = value;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateType.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,62 @@
+/* CertificateType.java -- the certificate type extension.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+public enum CertificateType
+{
+  X509     (0),
+  OPEN_PGP (1);
+
+  private final int value;
+
+  private CertificateType(int value)
+  {
+    this.value = value;
+  }
+
+  public static CertificateType forValue (final int value)
+  {
+    switch (value)
+      {
+        case 0: return X509;
+        case 1: return OPEN_PGP;
+        default: throw new IllegalArgumentException ("unknown certificate type: " + value);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateURL.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,388 @@
+/* CertificateURL.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The CertificateURL extension value.
+ * 
+ * <pre>
+enum {
+  individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+  false(0), true(1)
+} Boolean;
+
+struct {
+  CertChainType type;
+  URLAndOptionalHash url_and_hash_list&lt;1..2^16-1&gt;;
+} CertificateURL;
+
+struct {
+  opaque url&lt;1..2^16-1&gt;;
+  Boolean hash_present;
+  select (hash_present) {
+    case false: struct {};
+    case true: SHA1Hash;
+  } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];</pre>
+ *
+ * @author csm
+ *
+ */
+public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash>
+{
+  private ByteBuffer buffer;
+  
+  public CertificateURL(final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+  }
+  
+  public CertificateURL(CertChainType type, List<URLAndOptionalHash> urls)
+  {
+    int length = 3;
+    for (URLAndOptionalHash url : urls)
+      length += url.length();
+    buffer = ByteBuffer.allocate(length);
+    buffer.put((byte) type.getValue());
+    buffer.putShort((short) (length - 1));
+    for (URLAndOptionalHash url : urls)
+      buffer.put(url.buffer());
+    buffer.rewind();
+  }
+  
+  public int length()
+  {
+    return 3 + (buffer.getShort(1) & 0xFFFF);
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+
+  public CertChainType type()
+  {
+    switch (buffer.get(0))
+      {
+        case 0: return CertChainType.INDIVIDUAL_CERTS;
+        case 1: return CertChainType.PKIPATH;
+      }
+    throw new IllegalArgumentException("unknown certificate URL type");
+  }
+  
+  public int size()
+  {
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    for (int i = 3; i < len; )
+      {
+        URLAndOptionalHash u
+          = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+        int l = u.length();
+        i += l;
+        n++;
+      }
+    return n;
+  }
+  
+  public URLAndOptionalHash get(int index)
+  {
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    int l = 0;
+    int i;
+    for (i = 3; i < len && n < index; )
+      {
+        URLAndOptionalHash u
+          = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+        l = u.length();
+        i += l;
+        n++;
+      }
+    if (n < index)
+      throw new IndexOutOfBoundsException();
+    return new URLAndOptionalHash(((ByteBuffer) buffer.duplicate().position(i).limit(i+l)).slice());
+  }
+  
+  public void set(int index, URLAndOptionalHash url)
+  {
+    int len = buffer.getShort(1) & 0xFFFF;
+    int n = 0;
+    int i;
+    for (i = 3; i < len && n < index-1; )
+      {
+        URLAndOptionalHash u
+          = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+        int l = u.length();
+        i += l;
+        n++;
+      }
+    if (n < index - 1)
+      throw new IndexOutOfBoundsException();
+    int l = url.urlLength();
+    buffer.putShort(i, (short) l);
+    ((ByteBuffer) buffer.duplicate().position(i+2)).put(url.urlBuffer());
+    buffer.put(i+l+2, (byte) (url.hashPresent() ? 1 : 0));
+    if (url.hashPresent())
+      ((ByteBuffer) buffer.duplicate().position(i+l+3)).put (url.sha1Hash());
+  }
+  
+  public void setLength(final int length)
+  {
+    if (length < 0 || length > 65535)
+      throw new IllegalArgumentException("length must be between 0 and 65535");
+    buffer.putShort(1, (short) length);
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  type = ");
+    out.print(type());
+    out.println(";");
+    if (prefix != null) out.print(prefix);
+    out.println("  url_and_hash_list = {");
+    String subprefix = "  ";
+    if (prefix != null) subprefix = prefix + subprefix;
+    for (URLAndOptionalHash url : this)
+      {
+        out.println(url.toString(subprefix));
+      }
+    if (prefix != null) out.print(prefix);
+    out.println("  };");
+    if (prefix != null) out.print(prefix);
+    out.print("} CertificateURL;");
+    return str.toString();
+  }
+
+  public java.util.Iterator<URLAndOptionalHash> iterator()
+  {
+    return new Iterator();
+  }
+  
+  public class Iterator implements java.util.Iterator<URLAndOptionalHash>
+  {
+    private int index;
+    
+    public Iterator()
+    {
+      index = 0;
+    }
+    
+    public URLAndOptionalHash next() throws NoSuchElementException
+    {
+      try
+        {
+          return get(index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException();
+        }
+    }
+    
+    public boolean hasNext()
+    {
+      return index < size();
+    }
+    
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+  
+  public static enum CertChainType
+  {
+    INDIVIDUAL_CERTS (0), PKIPATH (1);
+    
+    private final int value;
+    
+    private CertChainType (final int value)
+    {
+      this.value = value;
+    }
+    
+    public int getValue()
+    {
+      return value;
+    }
+  }
+  
+  public static class URLAndOptionalHash implements Builder, Constructed
+  {
+    private ByteBuffer buffer;
+    
+    public URLAndOptionalHash (final ByteBuffer buffer)
+    {
+      this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    }
+    
+    public URLAndOptionalHash(String url)
+    {
+      this(url, null);
+    }
+    
+    public URLAndOptionalHash(String url, byte[] hash)
+    {
+      if (hash != null && hash.length < 20)
+        throw new IllegalArgumentException();
+      int length = 3 + url.length();
+      if (hash != null)
+        length += 20;
+      buffer = ByteBuffer.allocate(length);
+      buffer.putShort((short) url.length());
+      Charset cs = Charset.forName("US-ASCII");
+      CharsetEncoder ascii = cs.newEncoder();
+      ascii.encode(CharBuffer.wrap(url), buffer, true);
+      buffer.put((byte) (hash != null ? 1 : 0));
+      if (hash != null)
+        buffer.put(hash, 0, 20);
+      buffer.rewind();
+    }
+    
+    public int length()
+    {
+      return ((buffer.getShort(0) & 0xFFFF)
+              + (hashPresent() ? 23 : 3));
+    }
+    
+    public ByteBuffer buffer()
+    {
+      return (ByteBuffer) buffer.duplicate().limit(length());
+    }
+    
+    public String url()
+    {
+      Charset cs = Charset.forName("ASCII");
+      return cs.decode(urlBuffer()).toString();
+    }
+    
+    public int urlLength()
+    {
+      return buffer.getShort(0) & 0xFFFF;
+    }
+    
+    public ByteBuffer urlBuffer()
+    {
+      int len = urlLength();
+      return ((ByteBuffer) buffer.duplicate().position(2).limit(2+len)).slice();
+    }
+    
+    public boolean hashPresent()
+    {
+      int i = (buffer.getShort(0) & 0xFFFF) + 2;
+      byte b = buffer.get(i);
+      if (b == 0)
+        return false;
+      if (b == 1)
+        return true;
+      throw new IllegalArgumentException("expecting 0 or 1: " + (b & 0xFF));
+    }
+    
+    public byte[] sha1Hash()
+    {
+      int i = (buffer.getShort(0) & 0xFFFF) + 2;
+      byte b = buffer.get(i);
+      if (b == 0)
+        return null;
+      byte[] buf = new byte[20];
+      ((ByteBuffer) buffer.duplicate().position(i+1)).get(buf);
+      return buf;
+    }
+    
+    public String toString()
+    {
+      return toString(null);
+    }
+    
+    public String toString(final String prefix)
+    {
+      StringWriter str = new StringWriter();
+      PrintWriter out = new PrintWriter(str);
+      if (prefix != null) out.print(prefix);
+      out.println("struct {");
+      if (prefix != null) out.print(prefix);
+      out.print("  url = ");
+      out.print(url());
+      out.println(";");
+      boolean has_hash = hashPresent();
+      if (prefix != null) out.print(prefix);
+      out.print("  hash_present = ");
+      out.print(has_hash);
+      out.println(";");
+      if (has_hash)
+        {
+          if (prefix != null) out.print(prefix);
+          out.print("  sha1Hash = ");
+          out.print(Util.toHexString(sha1Hash(), ':'));
+          out.println(";");
+        }
+      if (prefix != null) out.print(prefix);
+      out.print("} URLAndOptionalHash;");
+      return str.toString();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CertificateVerify.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,83 @@
+/* CertificateVerify.java -- SSL CertificateVerify message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+public class CertificateVerify extends Signature implements Handshake.Body
+{
+
+  // Contstructor.
+  // -------------------------------------------------------------------------
+
+  public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg)
+  {
+    super(buffer, sigAlg);
+  }
+  
+  public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg)
+  {
+    super(sigVal, sigAlg);
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public String toString()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.println("struct {");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix = prefix + subprefix;
+    out.println (super.toString (subprefix));
+    if (prefix != null) out.print (prefix);
+    out.print ("} CertificateVerify;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CipherAlgorithm.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,47 @@
+/* CipherAlgorithm.java -- Cipher algorithm enumeration.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * The set of cipher algorithms we support.
+ */
+public enum CipherAlgorithm
+{
+  NULL, RC4, DES, DESede, CAST5, AES
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CipherSuite.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,837 @@
+/* CipherSuite.java -- Supported cipher suites.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.NullCipher;
+
+public final class CipherSuite implements Constructed
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  private static final List<String> tlsSuiteNames = new LinkedList<String>();
+  private static final HashMap<String, CipherSuite> namesToSuites = new HashMap<String, CipherSuite>();
+
+  // Core TLS cipher suites.
+  public static final CipherSuite TLS_NULL_WITH_NULL_NULL =
+    new CipherSuite (CipherAlgorithm.NULL,
+                     KeyExchangeAlgorithm.NONE,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.NULL, 0, 0x00, 0x00,
+                     "TLS_NULL_WITH_NULL_NULL");
+  public static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
+    new CipherSuite (CipherAlgorithm.NULL,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.MD5, 0, 0x00, 0x01,
+                     "TLS_RSA_WITH_NULL_MD5");
+  public static final CipherSuite TLS_RSA_WITH_NULL_SHA =
+    new CipherSuite (CipherAlgorithm.NULL,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 0, 0x00, 0x02,
+                     "TLS_RSA_WITH_NULL_SHA");
+  public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
+    new CipherSuite (CipherAlgorithm.RC4,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.MD5, 5, 0x00, 0x03,
+                     "TLS_RSA_EXPORT_WITH_RC4_40_MD5");
+  public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
+    new CipherSuite (CipherAlgorithm.RC4,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.MD5, 16, 0x00, 0x04,
+                     "TLS_RSA_WITH_RC4_128_MD5");
+  public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
+    new CipherSuite (CipherAlgorithm.RC4,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x05,
+                     "TLS_RSA_WITH_RC4_128_SHA");
+  public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 5, 0x00, 0x08,
+                     "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
+  public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 8, 0x00, 0x09,
+                     "TLS_RSA_WITH_DES_CBC_SHA");
+  public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 24, 0x00, 0x0A,
+                     "TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DH_DSS,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 5, 0x00, 0x0B,
+                     "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
+  public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DH_DSS,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 8, 0x00, 0x0C,
+                     "TLS_DH_DSS_WITH_DES_CBC_SHA");
+  public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DH_DSS,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 24, 0x00, 0x0D,
+                     "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DH_RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 5, 0x00, 0x0E,
+                     "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
+  public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DH_RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 8, 0x00, 0x0F,
+                     "TLS_DH_RSA_WITH_DES_CBC_SHA");
+  public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DH_RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 24, 0x00, 0x10,
+                     "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DHE_DSS, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 5, 0x00, 0x11,
+                     "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DHE_DSS, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 8, 0x00, 0x12,
+                     "TLS_DHE_DSS_WITH_DES_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DHE_DSS, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 24, 0x00, 0x13,
+                     "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DHE_RSA, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 5, 0x00, 0x14,
+                     "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DES,
+                     KeyExchangeAlgorithm.DHE_RSA, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 8, 0x00, 0x15,
+                     "TLS_DHE_RSA_WITH_DES_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DHE_RSA, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 24, 0x00, 0x16,
+                     "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
+
+  // AES CipherSuites.
+  public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x2F,
+                     "TLS_RSA_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DH_DSS,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 16, 0x00, 0x30,
+                     "TLS_DH_DSS_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DH_RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 16, 0x00, 0x31,
+                     "TLS_DH_RSA_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DHE_DSS, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x32,
+                     "TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DHE_RSA, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x33,
+                     "TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 32, 0x00, 0x35,
+                     "TLS_RSA_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DH_DSS,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 32, 0x00, 0x36,
+                     "TLS_DH_DSS_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DH_RSA,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 32, 0x00, 0x37,
+                     "TLS_DH_RSA_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DHE_DSS, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 32, 0x00, 0x38,
+                     "TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DHE_RSA, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 32, 0x00, 0x39,
+                     "TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
+
+  // Secure remote password (SRP) ciphersuites
+  // Actual ID values are TBD, so these are omitted until they are specified.
+  /*public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 24, 0x00, 0x50,
+                     "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 24, 0x00, 0x51,
+                     "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 24, 0x00, 0x52,
+                     "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 16, 0x00, 0x53,
+                     "TLS_SRP_SHA_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x54,
+                     "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x55,
+                     "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.ANONYMOUS,
+                     MacAlgorithm.SHA, 32, 0x00, 0x56,
+                     "TLS_SRP_SHA_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 32, 0x00, 0x57,
+                     "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA");
+  public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.SRP,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 32, 0x00, 0x58,
+                     "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");*/
+  
+  // Pre-shared key suites.
+  public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA =
+    new CipherSuite(CipherAlgorithm.RC4,
+                    KeyExchangeAlgorithm.PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x8A,
+                    "TLS_PSK_WITH_RC4_128_SHA");
+  public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.DESede,
+                    KeyExchangeAlgorithm.PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 24, 0x00, 0x8B,
+                    "TLS_PSK_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x8C,
+                    "TLS_PSK_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 32, 0x00, 0x8D,
+                    "TLS_PSK_WITH_AES_256_CBC_SHA");
+
+  public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA =
+    new CipherSuite(CipherAlgorithm.RC4,
+                    KeyExchangeAlgorithm.DHE_PSK, true,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x8E,
+                    "TLS_DHE_PSK_WITH_RC4_128_SHA");
+  public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.DESede,
+                    KeyExchangeAlgorithm.DHE_PSK, true,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 24, 0x00, 0x8F,
+                    "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.DHE_PSK, true,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x90,
+                    "TLS_DHE_PSK_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.DHE_PSK, true,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 32, 0x00, 0x91,
+                    "TLS_DHE_PSK_WITH_AES_256_CBC_SHA");
+  
+  public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA =
+    new CipherSuite(CipherAlgorithm.RC4,
+                    KeyExchangeAlgorithm.RSA_PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x92,
+                    "TLS_RSA_PSK_WITH_RC4_128_SHA");
+  public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.DESede,
+                    KeyExchangeAlgorithm.RSA_PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 24, 0x00, 0x93,
+                    "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA");
+  public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.RSA_PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 16, 0x00, 0x94,
+                    "TLS_RSA_PSK_WITH_AES_128_CBC_SHA");
+  public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA =
+    new CipherSuite(CipherAlgorithm.AES,
+                    KeyExchangeAlgorithm.RSA_PSK,
+                    SignatureAlgorithm.ANONYMOUS,
+                    MacAlgorithm.SHA, 32, 0x00, 0x95,
+                    "TLS_RSA_PSK_WITH_AES_256_CBC_SHA");
+
+  // Ciphersuites from the OpenPGP extension draft.
+  // These disappeared from a more recent draft.
+/*  public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x70,
+                     "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA");
+  public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x71,
+                     "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD");
+  public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.HMAC_RMD, 24, 0x00, 0x72,
+                     "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD");
+  public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x73,
+                     "TLS_DHE_DSS_WITH_AES_128_CBC_RMD");
+  public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.DSA,
+                     MacAlgorithm.HMAC_RMD, 32, 0x00, 0x74,
+                     "TLS_DHE_DSS_WITH_AES_256_CBC_RMD");
+  public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x75,
+                     "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA");
+  public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x76,
+                     "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD");
+  public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 24, 0x00, 0x77,
+                     "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD");
+  public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x78,
+                     "TLS_DHE_RSA_WITH_AES_128_CBC_RMD");
+  public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 32, 0x00, 0x79,
+                     "TLS_DHE_RSA_WITH_AES_256_CBC_RMD");
+  public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.SHA, 16, 0x00, 0x7A,
+                     "TLS_RSA_WITH_CAST_128_CBC_SHA");
+  public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.CAST5,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7B,
+                     "TLS_RSA_WITH_CAST_128_CBC_RMD");
+  public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.DESede,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 24, 0x00, 0x7C,
+                     "TLS_RSA_WITH_3DES_EDE_CBC_RMD");
+  public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7D,
+                     "TLS_RSA_WITH_AES_128_CBC_RMD");
+  public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
+    new CipherSuite (CipherAlgorithm.AES,
+                     KeyExchangeAlgorithm.RSA,
+                     SignatureAlgorithm.RSA,
+                     MacAlgorithm.HMAC_RMD, 32, 0x00, 0x7E,
+                     "TLS_RSA_WITH_AES_256_CBC_RMD"); */
+
+  private final CipherAlgorithm cipherAlgorithm;
+  private final KeyExchangeAlgorithm keyExchangeAlgorithm;
+  private final SignatureAlgorithm signatureAlgorithm;
+  private final MacAlgorithm macAlgorithm;
+  private final boolean ephemeralDH;
+  private final boolean exportable;
+  private final boolean isStream;
+  private final int keyLength;
+  private final byte[] id;
+  private final String name;
+  private final boolean isResolved;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+                       final KeyExchangeAlgorithm keyExchangeAlgorithm,
+                       final SignatureAlgorithm signatureAlgorithm,
+                       final MacAlgorithm macAlgorithm,
+                       final int keyLength,
+                       final int id1,
+                       final int id2,
+                       final String name)
+  {
+    this (cipherAlgorithm, keyExchangeAlgorithm, false, signatureAlgorithm,
+          macAlgorithm, keyLength, id1, id2, name);
+  }
+
+  private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+                       final KeyExchangeAlgorithm keyExchangeAlgorithm,
+                       final boolean ephemeralDH,
+                       final SignatureAlgorithm signatureAlgorithm,
+                       final MacAlgorithm macAlgorithm,
+                       final int keyLength,
+                       final int id1,
+                       final int id2,
+                       final String name)
+  {
+    this.cipherAlgorithm = cipherAlgorithm;
+    this.keyExchangeAlgorithm = keyExchangeAlgorithm;
+    this.ephemeralDH = ephemeralDH;
+    this.signatureAlgorithm = signatureAlgorithm;
+    this.macAlgorithm = macAlgorithm;
+    this.exportable = keyLength <= 5;
+    this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL
+                     || cipherAlgorithm == CipherAlgorithm.RC4);
+    this.keyLength = keyLength;
+    this.id = new byte[] { (byte) id1, (byte) id2 };
+    this.name = name.intern();
+    namesToSuites.put(name, this);
+    if (name.startsWith("TLS"))
+      {
+        tlsSuiteNames.add(name);
+      }
+    isResolved = true;
+  }
+
+  private CipherSuite(byte[] id)
+  {
+    cipherAlgorithm = null;
+    keyExchangeAlgorithm = null;
+    signatureAlgorithm = null;
+    macAlgorithm = null;
+    ephemeralDH = false;
+    exportable = false;
+    isStream = false;
+    keyLength = 0;
+    this.id = id;
+    name = null;
+    isResolved = false;
+  }
+
+  // Class methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Returns the cipher suite for the given name, or null if there is no
+   * such suite.
+   *
+   * @return The named cipher suite.
+   */
+  public static CipherSuite forName(String name)
+  {
+    if (name.startsWith("SSL_"))
+      name = "TLS_" + name.substring(4);
+    return namesToSuites.get(name);
+  }
+
+  public static CipherSuite forValue(final short raw_value)
+  {
+    byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value };
+    return new CipherSuite(b).resolve();
+  }
+
+  public static List<String> availableSuiteNames()
+  {
+    return tlsSuiteNames;
+  }
+
+  // Intance methods.
+  // -------------------------------------------------------------------------
+
+  public CipherAlgorithm cipherAlgorithm ()
+  {
+    return cipherAlgorithm;
+  }
+
+  public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException
+  {
+    if (cipherAlgorithm == null)
+      throw new NoSuchAlgorithmException (toString () + ": unresolved cipher suite");
+    if (cipherAlgorithm == CipherAlgorithm.NULL)
+      return new NullCipher ();
+
+    String alg = null;
+    if (cipherAlgorithm == CipherAlgorithm.RC4)
+      alg = "RC4";
+    else
+      alg = cipherAlgorithm + "/CBC/NoPadding";
+    GetSecurityPropertyAction gspa =
+      new GetSecurityPropertyAction ("jessie.jce.provider");
+    final String provider = (String) AccessController.doPrivileged (gspa);
+    if (provider != null)
+      {
+        try
+          {
+            return Cipher.getInstance (alg, provider);
+          }
+        catch (NoSuchProviderException nspe)
+          {
+          }
+      }
+    return Cipher.getInstance (alg);
+  }
+
+  public MacAlgorithm macAlgorithm ()
+  {
+    return macAlgorithm;
+  }
+
+  public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException
+  {
+    if (macAlgorithm == null)
+      throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite");
+    if (macAlgorithm == MacAlgorithm.NULL)
+      return null;
+    
+    String macAlg = null;
+    if (version == ProtocolVersion.SSL_3)
+      {
+        macAlg = "SSLv3HMac-" + macAlgorithm;
+      }
+    else
+      {
+        if (macAlgorithm == MacAlgorithm.MD5)
+          macAlg = "HMac-MD5";
+        if (macAlgorithm == MacAlgorithm.SHA)
+          macAlg = "HMac-SHA1";
+      }
+    
+    GetSecurityPropertyAction gspa =
+      new GetSecurityPropertyAction ("jessie.jce.provider");
+    final String provider = AccessController.doPrivileged (gspa);
+    if (provider != null)
+      {
+        try
+          {
+            return Mac.getInstance(macAlg, provider);
+          }
+        catch (NoSuchProviderException nspe)
+          {
+            // Ignore; try any installed provider.
+          }
+      }
+    return Mac.getInstance(macAlg);
+  }
+
+  public SignatureAlgorithm signatureAlgorithm ()
+  {
+    return signatureAlgorithm;
+  }
+
+  public KeyExchangeAlgorithm keyExchangeAlgorithm ()
+  {
+    return keyExchangeAlgorithm;
+  }
+
+  public boolean isEphemeralDH ()
+  {
+    return ephemeralDH;
+  }
+
+  public int length ()
+  {
+    return 2;
+  }
+
+  public void write(OutputStream out) throws IOException
+  {
+    out.write(id);
+  }
+
+  public void put (final ByteBuffer buf)
+  {
+    buf.put (id);
+  }
+  
+  public CipherSuite resolve()
+  {
+    if (id[0] == 0x00) switch (id[1] & 0xFF)
+      {
+      case 0x00: return TLS_NULL_WITH_NULL_NULL;
+      case 0x01: return TLS_RSA_WITH_NULL_MD5;
+      case 0x02: return TLS_RSA_WITH_NULL_SHA;
+      case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5;
+      case 0x04: return TLS_RSA_WITH_RC4_128_MD5;
+      case 0x05: return TLS_RSA_WITH_RC4_128_SHA;
+      case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA;
+      case 0x09: return TLS_RSA_WITH_DES_CBC_SHA;
+      case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+      case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
+      case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA;
+      case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+      case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
+      case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA;
+      case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+      case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
+      case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA;
+      case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+      case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
+      case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA;
+      case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+      case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA;
+      case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA;
+      case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA;
+      case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+      case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+      case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA;
+      case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA;
+      case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA;
+      case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+      case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+      /*case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+      case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+      case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+      case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+      case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+      case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+      case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+      case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+      case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+      case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA;
+      case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD;
+      case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD;
+      case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD;
+      case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD;
+      case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA;
+      case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD;
+      case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD;
+      case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD;
+      case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD;
+      case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA;
+      case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD;
+      case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD;
+      case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD;
+      case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;*/
+      case 0x8A: return TLS_PSK_WITH_RC4_128_SHA;
+      case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+      case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA;
+      case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA;
+      case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA;
+      case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+      case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+      case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+      case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA;
+      case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+      case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+      case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+      }
+    return this;
+  }
+  
+  public boolean isResolved()
+  {
+    return isResolved;
+  }
+
+  public int keyLength()
+  {
+    return keyLength;
+  }
+
+  public boolean isExportable()
+  {
+    return exportable;
+  }
+
+  public boolean isStreamCipher()
+  {
+    return isStream;
+  }
+
+//   String getAuthType()
+//   {
+//     if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA)
+//       {
+//         if (isExportable())
+//           {
+//             return "RSA_EXPORT";
+//           }
+//         return "RSA";
+//       }
+//     return kexName + "_" + sigName;
+//   }
+
+  public byte[] id()
+  {
+    return id;
+  }
+
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof CipherSuite))
+      {
+        return false;
+      }
+    if (o == this)
+      return true;
+    byte[] id = ((CipherSuite) o).id();
+    return (id[0] == this.id[0] &&
+            id[1] == this.id[1]);
+  }
+
+  public int hashCode()
+  {
+    return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+  }
+
+  public String toString (String prefix)
+  {
+    return toString ();
+  }
+
+  public String toString()
+  {
+    if (name == null)
+      {
+        return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
+      }
+    return name;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CipherSuiteList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,283 @@
+/* CipherSuiteList.java -- A list of cipher suites.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public final class CipherSuiteList implements Iterable<CipherSuite>
+{
+  private final ByteBuffer buffer;
+  private final ProtocolVersion version;
+  private int modCount;
+
+  public CipherSuiteList (final ByteBuffer buffer)
+  {
+    this (buffer, ProtocolVersion.SSL_3);
+  }
+
+  public CipherSuiteList (final ByteBuffer buffer, final ProtocolVersion version)
+  {
+    this.version = version;
+    this.buffer = buffer;
+    modCount = 0;
+  }
+
+  /**
+   * Return the number of elements in this list.
+   *
+   * @return The size of this list.
+   */
+  public int size ()
+  {
+    return (buffer.getShort (0) & 0xFFFF) >>> 1;
+  }
+
+  /**
+   * Get the cipher suite at the specified index.
+   *
+   * @param index The index of the suite to get.
+   * @return The cipher suite at that index.
+   * @throws IndexOutOfBoundsException If the index is negative or is
+   * not less than {@link size()}.
+   */
+  public CipherSuite get (final int index)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    return CipherSuite.forValue(buffer.getShort(2 + (index << 1))).resolve();
+  }
+
+  /**
+   * Set the CipherSuite at the specified index. The list must have
+   * sufficient size to hold the element (that is, <code>index &lt;=
+   * size ()</code>).
+   *
+   * @param index The index to put the suite.
+   * @param suite The CipherSuite object.
+   * @throws IndexOutOfBoundsException If <code>index</code> is not
+   * less than @{link #size()}, or if it is negative.
+   * @throws NullPointerException If <code>suite</code> is
+   * <code>null</code>.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   */
+  public void put (final int index, final CipherSuite suite)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    buffer.position (2 + (index << 1));
+    buffer.put (suite.id ());
+    modCount++;
+  }
+
+  /**
+   * Sets the size of this list. You must call this if you are adding
+   * elements to the list; calling {@link
+   * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+   * list size (the same goes for removing elements, as there is no
+   * <code>remove</code> method).
+   *
+   * @param newSize The new size of this list.
+   * @throws IllegalArgumentException If the new size is negative or
+   * greater than 32767, or if there is insufficient space for that
+   * many elements in the underlying buffer.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   */
+  public void setSize (final int newSize)
+  {
+    if (newSize < 0 || newSize > 32767)
+      throw new IllegalArgumentException ("size must be between 0 and 32767");
+    if ((newSize << 1) + 2 > buffer.capacity ())
+      throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+                                          + "; requested: " + newSize);
+    buffer.putShort (0, (short) (newSize << 1));
+    modCount++;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("[");
+    out.print (size ());
+    out.println ("] {");
+    for (Iterator it = new Iterator (); it.hasNext (); )
+      {
+        CipherSuite suite = (CipherSuite) it.next ();
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  ");
+        out.print (suite);
+        if (it.hasNext ())
+          out.print (",");
+        out.println ();
+      }
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("};");
+    return str.toString ();
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof CipherSuiteList))
+      return false;
+    CipherSuiteList that = (CipherSuiteList) o;
+
+    if (size () != that.size ())
+      return false;
+
+    for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+         it1.hasNext () && it2.hasNext (); )
+      {
+        if (!it1.next ().equals (it2.next ()))
+          return false;
+      }
+    return true;
+  }
+
+  public java.util.Iterator<CipherSuite> iterator ()
+  {
+    return new Iterator ();
+  }
+  
+  /**
+   * An iterator for the elements in this list. The iterator supports
+   * only the <code>set</code> method out of the optional methods,
+   * because elements in a CipherSuiteList may not be removed or
+   * added; only the size of the list can be changed, and elements at
+   * a specific index changed.
+   */
+  public class Iterator implements ListIterator<CipherSuite>
+  {
+    private final int modCount;
+    private int index;
+
+    Iterator ()
+    {
+      this.modCount = CipherSuiteList.this.modCount;
+      index = 0;
+    }
+
+    public void add (CipherSuite cs)
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public boolean hasNext ()
+    {
+      return (index < size ());
+    }
+
+    public boolean hasPrevious ()
+    {
+      return (index > 0);
+    }
+
+    public CipherSuite next () throws NoSuchElementException
+    {
+      if (modCount != CipherSuiteList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int nextIndex ()
+    {
+      if (hasNext ())
+        return (index + 1);
+      return -1;
+    }
+
+    public CipherSuite previous () throws NoSuchElementException
+    {
+      if (index == 0)
+        throw new NoSuchElementException ();
+      if (modCount != CipherSuiteList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (--index);
+        }
+      catch (IndexOutOfBoundsException ioobe) // on empty list
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int previousIndex ()
+    {
+      return (index - 1);
+    }
+
+    public void remove ()
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public void set (final CipherSuite cs)
+    {
+      put (index, cs);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,227 @@
+/* ClientCertificateTypeList.java -- A list of certificate types.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public class ClientCertificateTypeList implements Iterable<ClientCertificateType>
+{
+  private final ByteBuffer buffer;
+  private int modCount;
+
+  public ClientCertificateTypeList (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+    modCount = 0;
+  }
+
+  public int size ()
+  {
+    return (buffer.get (0) & 0xFF);
+  }
+
+  public CertificateRequest.ClientCertificateType get (final int index)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    return CertificateRequest.ClientCertificateType.forValue
+      (buffer.get (index + 1) & 0xFF);
+  }
+  
+  public java.util.Iterator<ClientCertificateType> iterator()
+  {
+    return new Iterator();
+  }
+
+  public void put (final int index, final CertificateRequest.ClientCertificateType type)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    buffer.put (index + 1, (byte) type.getValue ());
+    modCount++;
+  }
+
+  public void setSize (final int newSize)
+  {
+    if (newSize < 0 || newSize > 255)
+      throw new IllegalArgumentException ("size must be between 0 and 255");
+    if (newSize + 1 > buffer.capacity ())
+      throw new IllegalArgumentException ("limit: " + (buffer.capacity () - 1)
+                                          + "; requested: " + newSize);
+    buffer.put (0, (byte) newSize);
+    modCount++;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.print ("[");
+    out.print (size ());
+    out.println ("] {");
+    for (Iterator it = new Iterator (); it.hasNext (); )
+      {
+        if (prefix != null) out.print (prefix);
+        out.print ("  ");
+        out.print (it.next ());
+        if (it.hasNext ())
+          out.print (",");
+        out.println ();
+      }
+    if (prefix != null) out.print (prefix);
+    out.println ("};");
+    return str.toString ();
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof ClientCertificateTypeList))
+      return false;
+    ClientCertificateTypeList that = (ClientCertificateTypeList) o;
+
+    if (size () != that.size ())
+      return false;
+
+    for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+         it1.hasNext () && it2.hasNext (); )
+      {
+        if (!it1.next ().equals (it2.next ()))
+          return false;
+      }
+    return true;
+  }
+
+  public class Iterator implements ListIterator<CertificateRequest.ClientCertificateType>
+  {
+    private int index;
+    private final int modCount;
+
+    Iterator ()
+    {
+      index = 0;
+      modCount = ClientCertificateTypeList.this.modCount;
+    }
+
+    public void add (CertificateRequest.ClientCertificateType type)
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public boolean hasNext ()
+    {
+      return (index < size ());
+    }
+
+    public boolean hasPrevious ()
+    {
+      return (index > 0);
+    }
+
+    public CertificateRequest.ClientCertificateType next () throws NoSuchElementException
+    {
+      if (modCount != ClientCertificateTypeList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int nextIndex ()
+    {
+      if (hasNext ())
+        return (index + 1);
+      return -1;
+    }
+
+    public CertificateRequest.ClientCertificateType previous () throws NoSuchElementException
+    {
+      if (index == 0)
+        throw new NoSuchElementException ();
+      if (modCount != ClientCertificateTypeList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (--index);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int previousIndex ()
+    {
+      return (index - 1);
+    }
+
+    public void remove ()
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public void set (final CertificateRequest.ClientCertificateType type)
+    {
+      put (index, type);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,122 @@
+/* ClientDHE_PSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. &#42;/
+              case diffie_hellman_psk:   /* NEW &#42;/
+                  opaque psk_identity<0..2^16-1>;
+                  ClientDiffieHellmanPublic public;
+          } exchange_keys;
+      } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+  public ClientDHE_PSKParameters(ByteBuffer buffer)
+  {
+    super(buffer);
+  }
+  
+  public ClientDHE_PSKParameters(String identity, ClientDiffieHellmanPublic dh)
+  {
+    super(null);
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer idBuf = utf8.encode(identity);
+    buffer = ByteBuffer.allocate(2 + idBuf.remaining() + dh.length());
+    buffer.putShort((short) idBuf.remaining());
+    buffer.put(idBuf);
+    buffer.put(dh.buffer());
+    buffer.rewind();
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+  
+  private int identityLength()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+  
+  public String identity()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+                       (identityLength())).toString();
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    int length = (buffer.getShort(0) & 0xFFFF) + 2;
+    // XXX always explicit?
+    length += (buffer.getShort(length) & 0xFFFF) + 2;
+    return length;
+  }
+
+  public ClientDiffieHellmanPublic params()
+  {
+    return new ClientDiffieHellmanPublic(((ByteBuffer) buffer.duplicate()
+                                          .position(identityLength()).limit(length())).slice());
+  }
+  
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,129 @@
+/* ClientDiffieHellmanPublic.java -- Client Diffie-Hellman value.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's explicit Diffie Hellman value.
+ *
+ * <pre>
+struct {
+  select (PublicValueEncoding) {
+    case implicit: struct { };
+    case explicit: opaque dh_Yc&lt;1..2^16-1&gt;;
+  } dh_public;
+} ClientDiffieHellmanPublic;</pre> 
+ */
+public class ClientDiffieHellmanPublic extends ExchangeKeys implements Builder
+{
+  public ClientDiffieHellmanPublic(final ByteBuffer buffer)
+  {
+    super(buffer);
+  }
+  
+  public ClientDiffieHellmanPublic(final BigInteger Yc)
+  {
+    super(wrap(Yc));
+  }
+  
+  private static ByteBuffer wrap(BigInteger Yc)
+  {
+    byte[] b = Util.trim(Yc);
+    ByteBuffer ret = ByteBuffer.allocate(b.length + 2);
+    ret.putShort((short) b.length);
+    ret.put(b);
+    return (ByteBuffer) ret.rewind();
+  }
+
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+  
+  public BigInteger publicValue()
+  {
+    int len = length() - 2;
+    byte[] b = new byte[len];
+    buffer.position(2);
+    buffer.get(b);
+    buffer.rewind();
+    return new BigInteger(1, b);
+  }
+
+  public void setPublicValue(final BigInteger Yc)
+  {
+    byte[] buf = Util.trim(Yc);
+    if (buffer.capacity() < buf.length + 2)
+      buffer = ByteBuffer.allocate(buf.length + 2);
+    buffer.putShort((short) buf.length);
+    buffer.put(buf);
+    buffer.rewind();
+  }
+
+  public int length ()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  dh_Yc = ");
+    out.print (publicValue ().toString (16));
+    out.println (';');
+    if (prefix != null) out.print (prefix);
+    out.print ("} ClientDiffieHellmanPublic;");
+    return str.toString ();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientHandshake.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,1156 @@
+/* ClientHandshake.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.ClientHandshake.State.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.Alert.Level;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+import gnu.javax.net.ssl.provider.ServerNameList.NameType;
+import gnu.javax.net.ssl.provider.ServerNameList.ServerName;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHandshake extends AbstractHandshake
+{
+  static enum State
+  {
+    WRITE_CLIENT_HELLO (false, true),
+    READ_SERVER_HELLO (true, false),
+    READ_CERTIFICATE (true, false),
+    READ_SERVER_KEY_EXCHANGE (true, false),
+    READ_CERTIFICATE_REQUEST (true, false),
+    READ_SERVER_HELLO_DONE (true, false),
+    WRITE_CERTIFICATE (false, true),
+    WRITE_CLIENT_KEY_EXCHANGE (false, true),
+    WRITE_CERTIFICATE_VERIFY (false, true),
+    WRITE_FINISHED (false, true),
+    READ_FINISHED (true, false),
+    DONE (false, false);
+    
+    private final boolean isWriteState;
+    private final boolean isReadState;
+    
+    private State(boolean isReadState, boolean isWriteState)
+    {
+      this.isReadState = isReadState;
+      this.isWriteState = isWriteState;
+    }
+    
+    boolean isReadState()
+    {
+      return isReadState;
+    }
+    
+    boolean isWriteState()
+    {
+      return isWriteState;
+    }
+  }
+  
+  private State state;
+  private ByteBuffer outBuffer;
+  private boolean continuedSession;
+  private SessionImpl continued;
+  private KeyPair dhPair;
+  private String keyAlias;
+  private PrivateKey privateKey;
+  private MaxFragmentLength maxFragmentLengthSent;
+  private boolean truncatedHMacSent;
+  private ProtocolVersion sentVersion;
+  
+  // Delegated tasks.
+  private CertVerifier certVerifier;
+  private ParamsVerifier paramsVerifier;
+  private DelegatedTask keyExchange;
+  private CertLoader certLoader;
+  private GenCertVerify genCertVerify;
+  
+  public ClientHandshake(SSLEngineImpl engine) throws NoSuchAlgorithmException
+  {
+    super(engine);
+    state = WRITE_CLIENT_HELLO;
+    continuedSession = false;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleInput()
+   */
+  @Override protected HandshakeStatus implHandleInput() throws SSLException
+  {
+    if (state == DONE)
+      return HandshakeStatus.FINISHED;
+
+    if (state.isWriteState()
+        || (outBuffer != null && outBuffer.hasRemaining()))
+      return HandshakeStatus.NEED_WRAP;
+    
+    // Copy the current buffer, and prepare it for reading.
+    ByteBuffer buffer = handshakeBuffer.duplicate ();
+    buffer.flip();
+    buffer.position(handshakeOffset);
+
+    Handshake handshake = new Handshake(buffer.slice(),
+                                        engine.session().suite,
+                                        engine.session().version);
+        
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+                  state, handshake);
+
+    switch (state)
+      {
+        // Server Hello.
+        case READ_SERVER_HELLO:
+        {
+          if (handshake.type() != Handshake.Type.SERVER_HELLO)
+            throw new AlertException(new Alert(Alert.Level.FATAL,
+                                               Alert.Description.UNEXPECTED_MESSAGE));
+          ServerHello hello = (ServerHello) handshake.body();
+          serverRandom = hello.random().copy();
+          engine.session().suite = hello.cipherSuite();
+          engine.session().version = hello.version();
+          compression = hello.compressionMethod();
+          Session.ID serverId = new Session.ID(hello.sessionId());
+          if (continued != null
+              && continued.id().equals(serverId))
+            {
+              continuedSession = true;
+              engine.setSession(continued);
+            }
+          else if (engine.getEnableSessionCreation())
+            {
+              ((AbstractSessionContext) engine.contextImpl
+                  .engineGetClientSessionContext()).put(engine.session());
+            }
+          ExtensionList extensions = hello.extensions();
+          if (extensions != null)
+            {
+              for (Extension extension : extensions)
+                {
+                  Extension.Type type = extension.type();
+                  if (type == null)
+                    continue;
+                  switch (type)
+                    {
+                      case MAX_FRAGMENT_LENGTH:
+                        MaxFragmentLength mfl
+                          = (MaxFragmentLength) extension.value();
+                        if (maxFragmentLengthSent == mfl)
+                          engine.session().setApplicationBufferSize(mfl.maxLength());
+                        break;
+
+                      case TRUNCATED_HMAC:
+                        if (truncatedHMacSent)
+                          engine.session().setTruncatedMac(true);
+                        break;
+                    }
+                }
+            }
+
+          KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+          if (continuedSession)
+            {
+              byte[][] keys = generateKeys(clientRandom, serverRandom,
+                                           engine.session());
+              setupSecurityParameters(keys, true, engine, compression);
+              state = READ_FINISHED;
+            }
+          else if (kex == RSA || kex == DH_DSS || kex == DH_RSA
+                   || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK)
+            state = READ_CERTIFICATE;
+          else if (kex == DH_anon || kex == PSK || kex == DHE_PSK)
+            state = READ_SERVER_KEY_EXCHANGE;
+          else
+            state = READ_CERTIFICATE_REQUEST;
+        }
+        break;
+        
+        // Server Certificate.
+        case READ_CERTIFICATE:
+        {
+          if (handshake.type() != Handshake.Type.CERTIFICATE)
+            {
+              // We need a certificate for non-anonymous suites.
+              if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+                throw new AlertException(new Alert(Level.FATAL,
+                                                   Description.UNEXPECTED_MESSAGE));
+              state = READ_SERVER_KEY_EXCHANGE;
+            }
+          Certificate cert = (Certificate) handshake.body();
+          X509Certificate[] chain = null;
+          try
+            {
+              chain = cert.certificates().toArray(new X509Certificate[0]);
+            }
+          catch (CertificateException ce)
+            {
+              throw new AlertException(new Alert(Level.FATAL,
+                                                 Description.BAD_CERTIFICATE),
+                                       ce);
+            }
+          catch (NoSuchAlgorithmException nsae)
+            {
+              throw new AlertException(new Alert(Level.FATAL,
+                                                 Description.UNSUPPORTED_CERTIFICATE),
+                                       nsae);
+            }
+          engine.session().setPeerCertificates(chain);
+          certVerifier = new CertVerifier(true, chain);
+          tasks.add(certVerifier);
+          
+          // If we are doing an RSA key exchange, generate our parameters.
+          KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+          if (kea == RSA || kea == RSA_PSK)
+            {
+              keyExchange = new RSAGen(kea == RSA);
+              tasks.add(keyExchange);
+              if (kea == RSA)
+                state = READ_CERTIFICATE_REQUEST;
+              else
+                state = READ_SERVER_KEY_EXCHANGE;
+            }
+          else
+            state = READ_SERVER_KEY_EXCHANGE;
+        }
+        break;
+        
+        // Server Key Exchange.
+        case READ_SERVER_KEY_EXCHANGE:
+        {
+          CipherSuite s = engine.session().suite;
+          KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+          // XXX also SRP.
+          if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon
+              && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK)
+            throw new AlertException(new Alert(Level.FATAL,
+                                               Description.UNEXPECTED_MESSAGE));
+          
+          if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE)
+            {
+              if (kexalg != RSA_PSK && kexalg != PSK)
+                throw new AlertException(new Alert(Level.FATAL,
+                                                   Description.UNEXPECTED_MESSAGE));
+              state = READ_CERTIFICATE_REQUEST;
+              return HandshakeStatus.NEED_UNWRAP;
+            }
+
+          ServerKeyExchange skex = (ServerKeyExchange) handshake.body();
+          ByteBuffer paramsBuffer = null;
+          if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+            {
+              ServerDHParams dhParams = (ServerDHParams) skex.params();
+              ByteBuffer b = dhParams.buffer();
+              paramsBuffer = ByteBuffer.allocate(b.remaining());
+              paramsBuffer.put(b);
+            }
+          
+          if (s.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+            {
+              byte[] signature = skex.signature().signature();
+              paramsVerifier = new ParamsVerifier(paramsBuffer, signature);
+              tasks.add(paramsVerifier);
+            }
+          
+          if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+            {
+              ServerDHParams dhParams = (ServerDHParams) skex.params();
+              DHPublicKey serverKey = new GnuDHPublicKey(null,
+                                                         dhParams.p(),
+                                                         dhParams.g(),
+                                                         dhParams.y());
+              DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+                                                           dhParams.g());
+              keyExchange = new ClientDHGen(serverKey, params, true);
+              tasks.add(keyExchange);
+            }
+          if (kexalg == DHE_PSK)
+            {
+              ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters)
+                skex.params();
+              ServerDHParams dhParams = pskParams.params();
+              DHPublicKey serverKey = new GnuDHPublicKey(null,
+                                                         dhParams.p(),
+                                                         dhParams.g(),
+                                                         dhParams.y());
+              DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+                                                           dhParams.g());
+              keyExchange = new ClientDHGen(serverKey, params, false);
+              tasks.add(keyExchange);
+            }
+          state = READ_CERTIFICATE_REQUEST;
+        }
+        break;
+        
+        // Certificate Request.
+        case READ_CERTIFICATE_REQUEST:
+        {
+          if (handshake.type() != Handshake.Type.CERTIFICATE_REQUEST)
+            {
+              state = READ_SERVER_HELLO_DONE;
+              return HandshakeStatus.NEED_UNWRAP;
+            }
+          
+          CertificateRequest req = (CertificateRequest) handshake.body();
+          ClientCertificateTypeList types = req.types();
+          LinkedList<String> typeList = new LinkedList<String>();
+          for (ClientCertificateType t : types)
+            typeList.add(t.name());
+          
+          X500PrincipalList issuers = req.authorities();
+          LinkedList<X500Principal> issuerList = new LinkedList<X500Principal>();
+          for (X500Principal p : issuers)
+            issuerList.add(p);
+          
+          certLoader = new CertLoader(typeList, issuerList);
+          tasks.add(certLoader);
+        }
+        break;
+        
+        // Server Hello Done.
+        case READ_SERVER_HELLO_DONE:
+        {
+          if (handshake.type() != Handshake.Type.SERVER_HELLO_DONE)
+            throw new AlertException(new Alert(Level.FATAL,
+                                               Description.UNEXPECTED_MESSAGE));
+          state = WRITE_CERTIFICATE;
+        }
+        break;
+        
+        // Finished.
+        case READ_FINISHED:
+        {
+          if (handshake.type() != Handshake.Type.FINISHED)
+            throw new AlertException(new Alert(Level.FATAL,
+                                               Description.UNEXPECTED_MESSAGE));
+
+          Finished serverFinished = (Finished) handshake.body();
+          MessageDigest md5copy = null;
+          MessageDigest shacopy = null;
+          try
+            {
+              md5copy = (MessageDigest) md5.clone();
+              shacopy = (MessageDigest) sha.clone();
+            }
+          catch (CloneNotSupportedException cnse)
+            {
+              // We're improperly configured to use a non-cloneable
+              // md5/sha-1, OR there's a runtime bug.
+              throw new SSLException(cnse);
+            }
+          Finished clientFinished =
+            new Finished(generateFinished(md5copy, shacopy,
+                                          false, engine.session()),
+                                          engine.session().version);
+
+          if (Debug.DEBUG)
+            logger.logv(Component.SSL_HANDSHAKE, "clientFinished: {0}",
+                        clientFinished);
+          
+          if (engine.session().version == ProtocolVersion.SSL_3)
+            {
+              if (!Arrays.equals(clientFinished.md5Hash(),
+                                 serverFinished.md5Hash())
+                  || !Arrays.equals(clientFinished.shaHash(),
+                                    serverFinished.shaHash()))
+                {
+                  engine.session().invalidate();
+                  throw new SSLException("session verify failed");
+                }
+            }
+          else
+            {
+              if (!Arrays.equals(clientFinished.verifyData(),
+                                 serverFinished.verifyData()))
+                {
+                  engine.session().invalidate();
+                  throw new SSLException("session verify failed");
+                }
+            }
+
+          if (continuedSession)
+            {
+              engine.changeCipherSpec();
+              state = WRITE_FINISHED;
+            }
+          else
+            state = DONE;
+        }
+        break;
+        
+        default:
+          throw new IllegalStateException("invalid state: " + state);
+      }
+    
+    handshakeOffset += handshake.length() + 4;
+    
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+    if (state.isWriteState()
+        || (outBuffer != null && outBuffer.hasRemaining()))
+      return HandshakeStatus.NEED_WRAP;
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+
+    return HandshakeStatus.FINISHED;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleOutput(java.nio.ByteBuffer)
+   */
+  @Override protected HandshakeStatus implHandleOutput(ByteBuffer fragment)
+    throws SSLException
+  {
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "output to {0}; state:{1}; outBuffer:{2}",
+                  fragment, state, outBuffer);
+
+    // Drain the output buffer, if it needs it.
+    if (outBuffer != null && outBuffer.hasRemaining())
+      {
+        int l = Math.min(fragment.remaining(), outBuffer.remaining());
+        fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+        outBuffer.position(outBuffer.position() + l);
+      }
+    
+    if (!fragment.hasRemaining())
+      {
+        if (state.isWriteState() || outBuffer.hasRemaining())
+          return HandshakeStatus.NEED_WRAP;
+        else
+          return HandshakeStatus.NEED_UNWRAP;
+      }
+
+outer_loop:
+    while (fragment.remaining() >= 4 && state.isWriteState())
+      {
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE, "loop state={0}", state);
+
+        switch (state)
+          {
+            case WRITE_CLIENT_HELLO:
+            {
+              ClientHelloBuilder hello = new ClientHelloBuilder();
+              AbstractSessionContext ctx = (AbstractSessionContext)
+                engine.contextImpl.engineGetClientSessionContext();
+              continued = (SessionImpl) ctx.getSession(engine.getPeerHost(),
+                                                       engine.getPeerPort());
+              engine.session().setId(new Session.ID(new byte[0]));
+              Session.ID sid = engine.session().id();
+              // If we have a session that we may want to continue, send
+              // that ID.
+              if (continued != null)
+                sid = continued.id();
+              
+              hello.setSessionId(sid.id());
+              sentVersion = chooseVersion();
+              hello.setVersion(sentVersion);
+              hello.setCipherSuites(getSuites());
+              hello.setCompressionMethods(getCompressionMethods());
+              Random r = hello.random();
+              r.setGmtUnixTime(Util.unixTime());
+              byte[] nonce = new byte[28];
+              engine.session().random().nextBytes(nonce);
+              r.setRandomBytes(nonce);
+              clientRandom = r.copy();
+              if (enableExtensions())
+                {
+                  List<Extension> extensions = new LinkedList<Extension>();
+                  MaxFragmentLength fraglen = maxFragmentLength();
+                  if (fraglen != null)
+                    {
+                      extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH,
+                                                   fraglen));
+                      maxFragmentLengthSent = fraglen;
+                    }
+
+                  String host = engine.getPeerHost();
+                  if (host != null)
+                    {
+                      ServerName name
+                        = new ServerName(NameType.HOST_NAME, host);
+                      ServerNameList names
+                        = new ServerNameList(Collections.singletonList(name));
+                      extensions.add(new Extension(Extension.Type.SERVER_NAME,
+                                                   names));
+                    }
+                  
+                  if (truncatedHMac())
+                    {
+                      extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC,
+                                                   new TruncatedHMAC()));
+                      truncatedHMacSent = true;
+                    }
+
+                  ExtensionList elist = new ExtensionList(extensions);
+                  hello.setExtensions(elist.buffer());
+                }
+              else
+                hello.setDisableExtensions(true);
+              
+              if (Debug.DEBUG)
+                logger.logv(Component.SSL_HANDSHAKE, "{0}", hello);
+
+              fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24)
+                              | (hello.length() & 0xFFFFFF));
+              outBuffer = hello.buffer();
+              int l = Math.min(fragment.remaining(), outBuffer.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate()
+                           .limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              state = READ_SERVER_HELLO;
+            }
+            break;
+            
+            case WRITE_CERTIFICATE:
+            {
+              java.security.cert.Certificate[] chain
+                = engine.session().getLocalCertificates();
+              if (chain != null)
+                {
+                  CertificateBuilder cert
+                    = new CertificateBuilder(CertificateType.X509);
+                  try
+                    {
+                      cert.setCertificates(Arrays.asList(chain));
+                    }
+                  catch (CertificateException ce)
+                    {
+                      throw new AlertException(new Alert(Level.FATAL,
+                                                         Description.INTERNAL_ERROR),
+                                               ce);
+                    }
+                  
+                  outBuffer = cert.buffer();
+                  
+                  fragment.putInt((Handshake.Type.CERTIFICATE.getValue() << 24)
+                                  | (cert.length() & 0xFFFFFF));
+                  
+                  int l = Math.min(fragment.remaining(), outBuffer.remaining());
+                  fragment.put((ByteBuffer) outBuffer.duplicate()
+                               .limit(outBuffer.position() + l));
+                  outBuffer.position(outBuffer.position() + l);
+                }
+              state = WRITE_CLIENT_KEY_EXCHANGE;
+            }
+            break;
+            
+            case WRITE_CLIENT_KEY_EXCHANGE:
+            {
+              KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+              ClientKeyExchangeBuilder ckex
+                = new ClientKeyExchangeBuilder(engine.session().suite,
+                                               engine.session().version);
+              if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon
+                  || kea == DH_DSS || kea == DH_RSA)
+                {
+                  assert(dhPair != null);
+                  DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+                  ClientDiffieHellmanPublic pub
+                    = new ClientDiffieHellmanPublic(pubkey.getY());
+                  ckex.setExchangeKeys(pub.buffer());
+                }
+              if (kea == RSA || kea == RSA_PSK)
+                {
+                  assert(keyExchange instanceof RSAGen);
+                  assert(keyExchange.hasRun());
+                  if (keyExchange.thrown() != null)
+                    throw new AlertException(new Alert(Level.FATAL,
+                                                       Description.HANDSHAKE_FAILURE),
+                                             keyExchange.thrown());
+                  EncryptedPreMasterSecret epms
+                    = new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(),
+                                                   engine.session().version);
+                  if (kea == RSA)
+                    ckex.setExchangeKeys(epms.buffer());
+                  else
+                    {
+                      String identity = getPSKIdentity();
+                      if (identity == null)
+                        throw new SSLException("no pre-shared-key identity;"
+                                               + " set the security property"
+                                               + " \"jessie.client.psk.identity\"");
+                      ClientRSA_PSKParameters params =
+                        new ClientRSA_PSKParameters(identity, epms.buffer());
+                      ckex.setExchangeKeys(params.buffer());
+                      generatePSKSecret(identity, preMasterSecret, true);
+                    }
+                }
+              if (kea == DHE_PSK)
+                {
+                  assert(keyExchange instanceof ClientDHGen);
+                  assert(dhPair != null);
+                  String identity = getPSKIdentity();
+                  if (identity == null)
+                    throw new SSLException("no pre-shared key identity; set"
+                                           + " the security property"
+                                           + " \"jessie.client.psk.identity\"");
+                  DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+                  ClientDHE_PSKParameters params =
+                    new ClientDHE_PSKParameters(identity,
+                                                new ClientDiffieHellmanPublic(pubkey.getY()));
+                  ckex.setExchangeKeys(params.buffer());
+                  generatePSKSecret(identity, preMasterSecret, true);
+                }
+              if (kea == PSK)
+                {
+                  String identity = getPSKIdentity();
+                  if (identity == null)
+                    throw new SSLException("no pre-shared key identity; set"
+                                           + " the security property"
+                                           + " \"jessie.client.psk.identity\"");
+                  generatePSKSecret(identity, null, true);
+                  ClientPSKParameters params = new ClientPSKParameters(identity);
+                  ckex.setExchangeKeys(params.buffer());
+                }
+              if (kea == NONE)
+                {
+                  Inflater inflater = null;
+                  Deflater deflater = null;
+                  if (compression == CompressionMethod.ZLIB)
+                    {
+                      inflater = new Inflater();
+                      deflater = new Deflater();
+                    }
+                  inParams = new InputSecurityParameters(null, null, inflater,
+                                                         engine.session(),
+                                                         engine.session().suite);
+                  outParams = new OutputSecurityParameters(null, null, deflater,
+                                                           engine.session(),
+                                                           engine.session().suite);
+                  engine.session().privateData.masterSecret = new byte[0];
+                }
+              
+              if (Debug.DEBUG)
+                logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex);
+              
+              outBuffer = ckex.buffer();
+              if (Debug.DEBUG)
+                logger.logv(Component.SSL_HANDSHAKE, "client kex buffer {0}", outBuffer);
+              fragment.putInt((Handshake.Type.CLIENT_KEY_EXCHANGE.getValue() << 24)
+                              | (ckex.length() & 0xFFFFFF));
+              int l = Math.min(fragment.remaining(), outBuffer.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              if (privateKey != null)
+                {
+                  genCertVerify = new GenCertVerify(md5, sha);
+                  tasks.add(genCertVerify);
+                  state = WRITE_CERTIFICATE_VERIFY;
+                }
+              else
+                {
+                  engine.changeCipherSpec();
+                  state = WRITE_FINISHED;
+                }
+            }
+            // Both states terminate in a NEED_TASK, or a need to change cipher
+            // specs; so we can't write any more messages here.
+            break outer_loop;
+            
+            case WRITE_CERTIFICATE_VERIFY:
+            {
+              assert(genCertVerify != null);
+              assert(genCertVerify.hasRun());
+              CertificateVerify verify = new CertificateVerify(genCertVerify.signed(),
+                                                               engine.session().suite.signatureAlgorithm());
+              
+              outBuffer = verify.buffer();
+              fragment.putInt((Handshake.Type.CERTIFICATE_VERIFY.getValue() << 24)
+                              | (verify.length() & 0xFFFFFF));
+              int l = Math.min(fragment.remaining(), outBuffer.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+              
+              // XXX This is a potential problem: we may not have drained
+              // outBuffer, but set the changeCipherSpec toggle.
+              engine.changeCipherSpec();
+              state = WRITE_FINISHED;
+            }
+            break outer_loop;
+            
+            case WRITE_FINISHED:
+            {
+              MessageDigest md5copy = null;
+              MessageDigest shacopy = null;
+              try
+                {
+                  md5copy = (MessageDigest) md5.clone();
+                  shacopy = (MessageDigest) sha.clone();
+                }
+              catch (CloneNotSupportedException cnse)
+                {
+                  // We're improperly configured to use a non-cloneable
+                  // md5/sha-1, OR there's a runtime bug.
+                  throw new SSLException(cnse);
+                }
+              outBuffer
+                = generateFinished(md5copy, shacopy, true,
+                                   engine.session());
+              
+              fragment.putInt((Handshake.Type.FINISHED.getValue() << 24)
+                              | outBuffer.remaining() & 0xFFFFFF);
+              
+              int l = Math.min(outBuffer.remaining(), fragment.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              if (continuedSession)
+                state = DONE;
+              else
+                state = READ_FINISHED;              
+            }
+            break;
+            
+            default:
+              throw new IllegalStateException("invalid state: " + state);
+          }
+      }
+
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+    if (state.isWriteState() ||
+        (outBuffer != null && outBuffer.hasRemaining()))
+      return HandshakeStatus.NEED_WRAP;
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+
+    return HandshakeStatus.FINISHED;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.AbstractHandshake#status()
+   */
+  @Override HandshakeStatus status()
+  {
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+    if (state.isWriteState())
+      return HandshakeStatus.NEED_WRAP;
+    return HandshakeStatus.FINISHED;
+  }
+  
+  @Override void checkKeyExchange() throws SSLException
+  {
+    // XXX implement.
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.AbstractHandshake#handleV2Hello(java.nio.ByteBuffer)
+   */
+  @Override void handleV2Hello(ByteBuffer hello) throws SSLException
+  {
+    throw new SSLException("this should be impossible");
+  }
+  
+  private ProtocolVersion chooseVersion() throws SSLException
+  {
+    // Select the highest enabled version, for our initial key exchange.
+    ProtocolVersion version = null;
+    for (String ver : engine.getEnabledProtocols())
+      {
+        try
+          {
+            ProtocolVersion v = ProtocolVersion.forName(ver);
+            if (version == null || version.compareTo(v) < 0)
+              version = v;
+          }
+        catch (Exception x)
+          {
+            continue;
+          }
+      }
+    
+    if (version == null)
+      throw new SSLException("no suitable enabled versions");
+    
+    return version;
+  }
+  
+  private List<CipherSuite> getSuites() throws SSLException
+  {
+    List<CipherSuite> suites = new LinkedList<CipherSuite>();
+    for (String s : engine.getEnabledCipherSuites())
+      {
+        CipherSuite suite = CipherSuite.forName(s);
+        if (suite != null)
+          suites.add(suite);
+      }
+    if (suites.isEmpty())
+      throw new SSLException("no cipher suites enabled");
+    return suites;
+  }
+  
+  private List<CompressionMethod> getCompressionMethods()
+  {
+    List<CompressionMethod> methods = new LinkedList<CompressionMethod>();
+    GetSecurityPropertyAction gspa = new GetSecurityPropertyAction("jessie.enable.compression");
+    if (Boolean.valueOf(AccessController.doPrivileged(gspa)))
+      methods.add(CompressionMethod.ZLIB);
+    methods.add(CompressionMethod.NULL);
+    return methods;
+  }
+  
+  private boolean enableExtensions()
+  {
+    GetSecurityPropertyAction action
+      = new GetSecurityPropertyAction("jessie.client.enable.extensions");
+    return Boolean.valueOf(AccessController.doPrivileged(action));
+  }
+  
+  private MaxFragmentLength maxFragmentLength()
+  {
+    GetSecurityPropertyAction action
+      = new GetSecurityPropertyAction("jessie.client.maxFragmentLength");
+    String s = AccessController.doPrivileged(action);
+    if (s != null)
+      {
+        try
+          {
+            int len = Integer.parseInt(s);
+            switch (len)
+              {
+                case 9:
+                case (1 <<  9): return MaxFragmentLength.LEN_2_9;
+                case 10:
+                case (1 << 10): return MaxFragmentLength.LEN_2_10;
+                case 11:
+                case (1 << 11): return MaxFragmentLength.LEN_2_11;
+                case 12:
+                case (1 << 12): return MaxFragmentLength.LEN_2_12;
+              }
+          }
+        catch (NumberFormatException nfe)
+          {
+          }
+      }
+    return null;
+  }
+  
+  private boolean truncatedHMac()
+  {
+    GetSecurityPropertyAction action
+      = new GetSecurityPropertyAction("jessie.client.truncatedHMac");
+    return Boolean.valueOf(AccessController.doPrivileged(action));
+  }
+  
+  private String getPSKIdentity()
+  {
+    GetSecurityPropertyAction action
+      = new GetSecurityPropertyAction("jessie.client.psk.identity");
+    return AccessController.doPrivileged(action);
+  }
+  
+  // Delegated tasks.
+  
+  class ParamsVerifier extends DelegatedTask
+  {
+    private final ByteBuffer paramsBuffer;
+    private final byte[] signature;
+    private boolean verified;
+    
+    ParamsVerifier(ByteBuffer paramsBuffer, byte[] signature)
+    {
+      this.paramsBuffer = paramsBuffer;
+      this.signature = signature;
+    }
+    
+    public void implRun()
+      throws InvalidKeyException, NoSuchAlgorithmException,
+             SSLPeerUnverifiedException, SignatureException
+    {
+      java.security.Signature s
+        = java.security.Signature.getInstance(engine.session().suite
+                                              .signatureAlgorithm().algorithm());
+      s.initVerify(engine.session().getPeerCertificates()[0]);
+      s.update(paramsBuffer);
+      verified = s.verify(signature);
+      synchronized (this)
+        {
+          notifyAll();
+        }
+    }
+    
+    boolean verified()
+    {
+      return verified;
+    }
+  }
+  
+  class ClientDHGen extends DelegatedTask
+  {
+    private final DHPublicKey serverKey;
+    private final DHParameterSpec params;
+    private final boolean full;
+    
+    ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full)
+    {
+      this.serverKey = serverKey;
+      this.params = params;
+      this.full = full;
+    }
+    
+    public void implRun()
+      throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+             SSLException
+    {
+      if (Debug.DEBUG)
+        logger.log(Component.SSL_DELEGATED_TASK, "running client DH phase");
+      if (paramsVerifier != null)
+        {
+          synchronized (paramsVerifier)
+            {
+              try
+                {
+                  while (!paramsVerifier.hasRun())
+                    paramsVerifier.wait(500);
+                }
+              catch (InterruptedException ie)
+                {
+                  // Ignore.
+                }
+            }
+        }
+      KeyPairGenerator gen = KeyPairGenerator.getInstance("DH");
+      gen.initialize(params, engine.session().random());
+      dhPair = gen.generateKeyPair();
+      if (Debug.DEBUG_KEY_EXCHANGE)
+        logger.logv(Component.SSL_KEY_EXCHANGE,
+                    "client keys public:{0} private:{1}", dhPair.getPublic(),
+                    dhPair.getPrivate());
+
+      initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random());
+
+      // We have enough info to do the full key exchange; so let's do it.
+      DHPhase phase = new DHPhase(serverKey, full);
+      phase.run();
+      if (phase.thrown() != null)
+        throw new SSLException(phase.thrown());
+    }
+    
+    DHPublicKey serverKey()
+    {
+      return serverKey;
+    }
+  }
+  
+  class CertLoader extends DelegatedTask
+  {
+    private final List<String> keyTypes;
+    private final List<X500Principal> issuers;
+    
+    CertLoader(List<String> keyTypes, List<X500Principal> issuers)
+    {
+      this.keyTypes = keyTypes;
+      this.issuers = issuers;
+    }
+    
+    public void implRun()
+    {
+      X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+      if (km == null)
+        return;
+      keyAlias = km.chooseEngineClientAlias(keyTypes.toArray(new String[keyTypes.size()]),
+                                            issuers.toArray(new X500Principal[issuers.size()]),
+                                            engine);
+      engine.session().setLocalCertificates(km.getCertificateChain(keyAlias));
+      privateKey = km.getPrivateKey(keyAlias);
+    }
+  }
+
+  class RSAGen extends DelegatedTask
+  {
+    private byte[] encryptedPreMasterSecret;
+    private final boolean full;
+    
+    RSAGen()
+    {
+      this(true);
+    }
+    
+    RSAGen(boolean full)
+    {
+      this.full = full;
+    }
+    
+    public void implRun()
+      throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+             NoSuchAlgorithmException, NoSuchPaddingException,
+             SSLException
+    {
+      if (certVerifier != null)
+        {
+          synchronized (certVerifier)
+            {
+              try
+                {
+                  while (!certVerifier.hasRun())
+                    certVerifier.wait(500);
+                }
+              catch (InterruptedException ie)
+                {
+                  // Ignore.
+                }
+            }
+        }
+      preMasterSecret = new byte[48];
+      engine.session().random().nextBytes(preMasterSecret);
+      preMasterSecret[0] = (byte) sentVersion.major();
+      preMasterSecret[1] = (byte) sentVersion.minor();
+      Cipher rsa = Cipher.getInstance("RSA");
+      java.security.cert.Certificate cert
+        = engine.session().getPeerCertificates()[0];
+      if (cert instanceof X509Certificate)
+        {
+          boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
+          if (keyUsage != null && !keyUsage[2])
+            throw new InvalidKeyException("certificate's keyUsage does not permit keyEncipherment");
+        }
+      rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
+      encryptedPreMasterSecret = rsa.doFinal(preMasterSecret);
+      
+      // Generate our session keys, because we can.
+      if (full)
+        {
+          generateMasterSecret(clientRandom, serverRandom, engine.session());
+          byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+          setupSecurityParameters(keys, true, engine, compression);
+        }
+    }
+    
+    byte[] encryptedSecret()
+    {
+      return encryptedPreMasterSecret;
+    }
+  }
+  
+  class GenCertVerify extends DelegatedTask
+  {
+    private final MessageDigest md5, sha;
+    private byte[] signed;
+    
+    GenCertVerify(MessageDigest md5, MessageDigest sha)
+    {
+      try
+        {
+          this.md5 = (MessageDigest) md5.clone();
+          this.sha = (MessageDigest) sha.clone();
+        }
+      catch (CloneNotSupportedException cnse)
+        {
+          // Our message digests *should* be cloneable.
+          throw new Error(cnse);
+        }
+    }
+
+    public void implRun()
+      throws InvalidKeyException, NoSuchAlgorithmException, SignatureException
+    {
+      byte[] toSign;
+      if (engine.session().version == ProtocolVersion.SSL_3)
+        {
+          toSign = genV3CertificateVerify(md5, sha, engine.session());
+        }
+      else
+        {
+          if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+            toSign = Util.concat(md5.digest(), sha.digest());
+          else
+            toSign = sha.digest();
+        }
+      
+      java.security.Signature sig =
+        java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name());
+      sig.initSign(privateKey);
+      sig.update(toSign);
+      signed = sig.sign();
+    }
+    
+    byte[] signed()
+    {
+      return signed;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientHello.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,240 @@
+/* ClientHello.java -- SSL ClientHello message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A ClientHello handshake message.
+ *
+ * <pre>
+struct
+{
+  ProtocolVersion   client_version;                // 2
+  Random            random;                        // 32
+  SessionID         session_id;                    // 1 + 0..32
+  CipherSuite       cipher_suites&lt;2..2^16-1&gt;
+  CompressionMethod compression_methods&lt;1..2^8-1&gt;
+  Extension         client_hello_extension_list&lt;0..2^16-1&gt;
+} ClientHello;
+</pre>
+ */
+public class ClientHello implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  // To help track offsets into the message:
+  // The location of the 'random' field.
+  protected static final int RANDOM_OFFSET = 2;
+  // The location of the sesion_id length.
+  protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+  // The location of the session_id bytes (if any).
+  protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+
+  protected ByteBuffer buffer;
+  protected boolean disableExtensions;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public ClientHello (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    disableExtensions = false;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length()
+  {
+    int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET);
+    len += (buffer.getShort(len) & 0xFFFF) + 2;
+    len += (buffer.get(len) & 0xFF) + 1;
+    if (!disableExtensions && len + 1 < buffer.capacity())
+      len += (buffer.getShort(len) & 0xFFFF) + 2;
+    return len;
+  }
+
+  /**
+   * Gets the protocol version field.
+   *
+   * @return The protocol version field.
+   */
+  public ProtocolVersion version()
+  {
+    return ProtocolVersion.getInstance (buffer.getShort (0));
+  }
+
+  /**
+   * Gets the SSL nonce.
+   *
+   * @return The nonce.
+   */
+  public Random random()
+  {
+    ByteBuffer randomBuf =
+      ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+       .limit (SESSID_OFFSET)).slice ();
+    return new Random (randomBuf);
+  }
+
+  public byte[] sessionId()
+  {
+    int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+    byte[] sessionId = new byte[idlen];
+    buffer.position (SESSID_OFFSET2);
+    buffer.get (sessionId);
+    return sessionId;
+  }
+
+  public CipherSuiteList cipherSuites()
+  {
+    int offset = getCipherSuitesOffset ();
+
+    // We give the CipherSuiteList all the remaining bytes to play with,
+    // since this might be an in-construction packet that will fill in
+    // the length field itself.
+    ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+                          .limit (buffer.capacity ())).slice ();
+    return new CipherSuiteList (listBuf, version ());
+  }
+
+  public CompressionMethodList compressionMethods()
+  {
+    int offset = getCompressionMethodsOffset ();
+    ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+                          .limit (buffer.capacity ())).slice ();
+    return new CompressionMethodList (listBuf);
+  }
+  
+  public boolean hasExtensions()
+  {
+    int offset = getExtensionsOffset();
+    return (offset + 1 < buffer.limit());
+  }
+
+  public ExtensionList extensions()
+  {
+    int offset = getExtensionsOffset ();
+    if (offset + 1 >= buffer.limit())
+      return null;
+    int len = buffer.getShort(offset) & 0xFFFF;
+    if (len == 0)
+      len = buffer.limit() - offset - 2;
+    ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+                       .limit(offset + len + 2)).slice ();
+    return new ExtensionList(ebuf);
+  }
+  
+  public int extensionsLength()
+  {
+    if (hasExtensions())
+      return 0;
+    return buffer.getShort(getExtensionsOffset()) & 0xFFFF;
+  }
+
+  protected int getCipherSuitesOffset ()
+  {
+    return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF));
+  }
+
+  protected int getCompressionMethodsOffset ()
+  {
+    int csOffset = getCipherSuitesOffset ();
+    int csLen = buffer.getShort (csOffset) & 0xFFFF;
+    return csOffset + csLen + 2;
+  }
+
+  protected int getExtensionsOffset ()
+  {
+    int cmOffset = getCompressionMethodsOffset ();
+    return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix += prefix;
+    if (prefix != null)
+      out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("  version: ");
+    out.print (version ());
+    out.println (";");
+    out.print (subprefix);
+    out.println ("random:");
+    out.print (random ().toString (subprefix));
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("  sessionId: ");
+    out.print (Util.toHexString (sessionId (), ':'));
+    out.println (";");
+    out.print (subprefix);
+    out.println ("cipher_suites:");
+    out.println (cipherSuites ().toString (subprefix));
+    out.print (subprefix);
+    out.println ("compression_methods:");
+    out.println (compressionMethods ().toString (subprefix));
+    out.print (subprefix);
+    out.print ("extensions: ");
+    ExtensionList el = extensions();
+    out.println (el != null ? el.toString(subprefix+"  ") : "(nil)");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("} ClientHello;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientHelloBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,137 @@
+/* ClientHelloBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Builder for {@link ClientHello} objects.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHelloBuilder extends ClientHello implements Builder
+{
+  public ClientHelloBuilder()
+  {
+    super(ByteBuffer.allocate(256));
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+  }
+
+  public void setVersion(final ProtocolVersion version)
+  {
+    ensureCapacity(2);
+    buffer.putShort(0, (short) version.rawValue ());
+  }
+
+  public void setSessionId (final byte[] buffer)
+  {
+    setSessionId(buffer, 0, buffer.length);
+  }
+
+  public void setSessionId (final byte[] buffer, final int offset, final int length)
+  {
+    ensureCapacity(SESSID_OFFSET2 + length);
+    int len = Math.min (32, length);
+    this.buffer.put (SESSID_OFFSET, (byte) len);
+    this.buffer.position (SESSID_OFFSET2);
+    this.buffer.put (buffer, offset, len);
+  }
+  
+  public void setCipherSuites(List<CipherSuite> suites)
+  {
+    int off = getCipherSuitesOffset();
+    ensureCapacity(off + (2 * suites.size()) + 2);
+    buffer.putShort(off, (short) (suites.size() * 2));
+    int i = 2;
+    for (CipherSuite suite : suites)
+      {
+        ((ByteBuffer) buffer.duplicate().position(off+i)).put(suite.id());
+        i += 2;
+      }
+  }
+  
+  public void setCompressionMethods(List<CompressionMethod> methods)
+  {
+    int off = getCompressionMethodsOffset();
+    ensureCapacity(off + methods.size() + 1);
+    buffer.put(off, (byte) methods.size());
+    for (CompressionMethod method : methods)
+      buffer.put(++off, (byte) method.getValue());
+  }
+
+  public void setExtensionsLength (final int length)
+  {
+    if (length < 0 || length > 16384)
+      throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+    int needed = getExtensionsOffset() + 2 + length;
+    if (buffer.capacity() < needed)
+      ensureCapacity(needed);
+    buffer.putShort(getExtensionsOffset(), (short) length);
+  }
+  
+  public void setExtensions(ByteBuffer extensions)
+  {
+    int elen = extensions.getShort(0) & 0xFFFF;
+    setExtensionsLength(elen);
+    ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset())).put(extensions);
+  }
+  
+  public void setDisableExtensions(boolean disableExtensions)
+  {
+    this.disableExtensions = disableExtensions;
+  }
+  
+  public void ensureCapacity(final int length)
+  {
+    if (buffer.capacity() >= length)
+      return;
+    ByteBuffer newBuf = ByteBuffer.allocate(length);
+    newBuf.put((ByteBuffer) buffer.position(0));
+    newBuf.position(0);
+    this.buffer = newBuf;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientHelloV2.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,158 @@
+/* ClientHelloV2.java -- a hello message from SSLv2.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A client hello message from SSLv2. In SSLv3 and later, clients can
+ * send an SSLv2 client hello message, but set the protocol version
+ * for a later version.
+ *
+ * <p>The format of a version 2 client hello is:
+ *
+ * <pre>
+    char MSG-CLIENT-HELLO          // equals 1
+    char CLIENT-VERSION-MSB
+    char CLIENT-VERSION-LSB
+    char CIPHER-SPECS-LENGTH-MSB
+    char CIPHER-SPECS-LENGTH-LSB
+    char SESSION-ID-LENGTH-MSB
+    char SESSION-ID-LENGTH-LSB
+    char CHALLENGE-LENGTH-MSB
+    char CHALLENGE-LENGTH-LSB
+    char CIPHER-SPECS-DATA[(MSB&lt;&lt;8)|LSB]
+    char SESSION-ID-DATA[(MSB&lt;&lt;8)|LSB]
+    char CHALLENGE-DATA[(MSB&lt;&lt;8)|LSB]</pre>
+ */
+class ClientHelloV2 implements Constructed
+{
+  private final ByteBuffer buffer;
+
+  ClientHelloV2 (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+
+  public int length ()
+  {
+    return 9 + cipherSpecsLength () + sessionIdLength () + challengeLength ();
+  }
+
+  ProtocolVersion version ()
+  {
+    return ProtocolVersion.getInstance (buffer.getShort (1));
+  }
+
+  int cipherSpecsLength ()
+  {
+    return buffer.getShort (3) & 0xFFFF;
+  }
+
+  int sessionIdLength ()
+  {
+    return buffer.getShort (5) & 0xFFFF;
+  }
+
+  int challengeLength ()
+  {
+    return buffer.getShort (7) & 0xFFFF;
+  }
+
+  public List<CipherSuite> cipherSpecs ()
+  {
+    int n = cipherSpecsLength ();
+    List<CipherSuite> l = new ArrayList<CipherSuite>(n / 3);
+    ByteBuffer b = (ByteBuffer) buffer.duplicate ().position (9);
+    for (int i = 0; i < n; i += 3)
+      {
+        if (b.get () == 0)
+          l.add (CipherSuite.forValue(b.getShort()).resolve());
+        else
+          b.getShort ();
+      }
+    return l;
+  }
+
+  byte[] sessionId ()
+  {
+    byte[] id = new byte[sessionIdLength ()];
+    ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength ())).get (id);
+    return id;
+  }
+
+  byte[] challenge ()
+  {
+    byte[] challenge = new byte[challengeLength ()];
+    ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength () + sessionIdLength ())).get (challenge);
+    return challenge;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+
+    if (prefix != null) out.print (prefix);
+    out.println ("CLIENT-HELLO-MSG");
+    if (prefix != null) out.print (prefix);
+    out.print ("  version: ");
+    out.println (version ());
+    if (prefix != null) out.print (prefix);
+    out.println ("  suites: ");
+    out.println (cipherSpecs ());
+    if (prefix != null) out.print (prefix);
+    out.print ("  sessionId: ");
+    out.println (Util.toHexString (sessionId (), ':'));
+    if (prefix != null) out.print (prefix);
+    out.print ("  challenge: ");
+    out.println (Util.toHexString (challenge (), ':'));
+    return str.toString ();
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientKeyExchange.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,132 @@
+/* ClientKeyExchange.java -- SSL ClientKeyExchange message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The client key exchange message.
+ *
+ * <pre>
+struct {
+  select (KeyExchangeAlgorithm) {
+    case rsa: EncryptedPreMasterSecret;
+    case diffie_hellman: ClientDiffieHellmanPublic;
+  } exchange_keys;
+} ClientKeyExchange;</pre>
+ */
+public class ClientKeyExchange implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  protected ByteBuffer buffer;
+  protected final CipherSuite suite;
+  protected final ProtocolVersion version;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite,
+                            final ProtocolVersion version)
+  {
+    suite.getClass();
+    version.getClass ();
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    this.suite = suite;
+    this.version = version;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public ExchangeKeys exchangeKeys ()
+  {
+    KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm();
+    if (alg == KeyExchangeAlgorithm.RSA)
+      return new EncryptedPreMasterSecret(buffer, version);
+    else if (alg == KeyExchangeAlgorithm.DH_anon
+             || alg == KeyExchangeAlgorithm.DHE_DSS
+             || alg == KeyExchangeAlgorithm.DHE_RSA)
+      return new ClientDiffieHellmanPublic(buffer.duplicate());
+    else if (alg == KeyExchangeAlgorithm.DHE_PSK)
+      return new ClientDHE_PSKParameters(buffer.duplicate());
+    else if (alg == KeyExchangeAlgorithm.PSK)
+      return new ClientPSKParameters(buffer.duplicate());
+    else if (alg == KeyExchangeAlgorithm.RSA_PSK)
+      return new ClientRSA_PSKParameters(buffer.duplicate());
+    else if (alg == KeyExchangeAlgorithm.NONE)
+      return new EmptyExchangeKeys();
+    throw new IllegalArgumentException("unsupported key exchange: " + alg);
+  }
+
+  public int length()
+  {
+    if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+      return 0;
+    return exchangeKeys().length();
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println("struct {");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix = prefix + subprefix;
+    out.println (exchangeKeys ().toString (subprefix));
+    if (prefix != null)
+      out.print (prefix);
+    out.println("} ClientKeyExchange;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,75 @@
+/* ClientKeyExchangeBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Builder for {@link ClientKeyExchange} objects.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientKeyExchangeBuilder extends ClientKeyExchange
+  implements Builder
+{
+  public ClientKeyExchangeBuilder(CipherSuite suite, ProtocolVersion version)
+  {
+    super(ByteBuffer.allocate(512), suite, version);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+  }
+  
+  public void setExchangeKeys(ByteBuffer exchangeKeys)
+  {
+    // For SSLv3 and RSA key exchange, the message is sent without length.
+    // So we use the precise capacity of the buffer to signal the size of 
+    // the message.
+    if (buffer.capacity() < exchangeKeys.remaining()
+        || (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.RSA
+            && version == ProtocolVersion.SSL_3))
+      buffer = ByteBuffer.allocate(exchangeKeys.remaining());
+    ((ByteBuffer) buffer.duplicate().position(0)).put(exchangeKeys);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientPSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,125 @@
+/* ClientPSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. &#42;/
+              case psk:   /* NEW &#42;/
+                  opaque psk_identity&lt;0..2^16-1&gt;;
+          } exchange_keys;
+      } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientPSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+  public ClientPSKParameters(ByteBuffer buffer)
+  {
+    super(buffer);
+  }
+
+  public ClientPSKParameters(String identity)
+  {
+    super(null);
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer idBuf = utf8.encode(CharBuffer.wrap(identity));
+    buffer = ByteBuffer.allocate(idBuf.remaining() + 2);
+    buffer.putShort((short) idBuf.remaining());
+    buffer.put(idBuf);
+    buffer.rewind();
+  }
+  
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+  
+  public String identity()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+  }
+  
+  public @Override String toString()
+  {
+    return toString(null);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  identity = ");
+    out.print(identity());
+    out.println(";");
+    if (prefix != null) out.print(prefix);
+    out.print("} ClientPSKParameters;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,126 @@
+/* ClientRSA_PSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+  public ClientRSA_PSKParameters(ByteBuffer buffer)
+  {
+    super(buffer);
+  }
+
+  public ClientRSA_PSKParameters(String identity, ByteBuffer epms)
+  {
+    super(null);
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer idBuf = utf8.encode(identity);
+    buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.remaining());
+    buffer.putShort((short) idBuf.remaining());
+    buffer.put(idBuf);
+    buffer.put(epms);
+    buffer.rewind();
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+  
+  public String identity()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+                       (identityLength())).toString();
+  }
+  
+  private int identityLength()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    return identityLength() + secret().length();
+  }
+  
+  public EncryptedPreMasterSecret secret()
+  {
+    return new EncryptedPreMasterSecret
+      (((ByteBuffer) buffer.duplicate().position(identityLength())
+        .limit(buffer.capacity())).slice(), ProtocolVersion.TLS_1);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  identity = ");
+    out.print(identity());
+    if (prefix != null) out.print(prefix);
+    out.println("  encrypted_pre_master_secret =");
+    out.println(secret().toString(prefix != null ? prefix + "    " : "    "));
+    if (prefix != null) out.print(prefix);
+    out.print("} ClientRSA_PSKParameters;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CompressionMethod.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,69 @@
+/* CompressionMethod.java -- The CompressionMethod enum.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+public enum CompressionMethod
+{
+  NULL (0), ZLIB(1);
+
+  private final int value;
+
+  private CompressionMethod(int value)
+  {
+    this.value = value;
+  }
+
+  public static CompressionMethod getInstance (final int value)
+  {
+    switch (value & 0xFF)
+      {
+      case 0: return NULL;
+      case 1: return ZLIB;
+      
+      // Note: we can't throw an exception here, because we get these values
+      // over the wire, and need to just ignore ones we don't recognize.
+      default: return null; 
+      }
+  }
+
+  public int getValue()
+  {
+    return value;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/CompressionMethodList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,281 @@
+/* CompressionMethodList.java -- A list of compression methods.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A basic list interface to a list of compression methods in an SSL
+ * packet.
+ */
+public final class CompressionMethodList implements Iterable<CompressionMethod>
+{
+  private final ByteBuffer buffer;
+  private int modCount;
+
+  public CompressionMethodList (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+    modCount = 0;
+  }
+
+  /**
+   * Return the number of elements in this list.
+   *
+   * @return The size of this list.
+   */
+  public int size ()
+  {
+    return (buffer.get (0) & 0xFF);
+  }
+
+  /**
+   * Get the cipher suite at the specified index.
+   *
+   * @param index The index of the suite to get.
+   * @return The cipher suite at that index.
+   * @throws IndexOutOfBoundsException If the index is negative or is
+   * not less than {@link #size()}.
+   */
+  public CompressionMethod get (final int index)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    return CompressionMethod.getInstance (buffer.get (1 + index));
+  }
+
+  /**
+   * Set the CompressionMethod at the specified index. The list must
+   * have sufficient size to hold the element (that is, <code>index
+   * &lt;= size ()</code>).
+   *
+   * @param index The index to put the suite.
+   * @param method The CompressionMethod object.
+   * @throws IndexOutOfBoundsException If <code>index</code> is not
+   * less than @{link #size()}, or if it is negative.
+   * @throws NullPointerException If <code>suite</code> is
+   * <code>null</code>.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   */
+  public void put (final int index, final CompressionMethod method)
+  {
+    int size = size ();
+    if (index < 0 || index >= size)
+      throw new IndexOutOfBoundsException ("limit: " + size
+                                           + "; requested: " + index);
+    buffer.position (1 + index);
+    buffer.put ((byte) method.getValue ());
+    modCount++;
+  }
+
+  /**
+   * Sets the size of this list. You must call this if you are adding
+   * elements to the list; calling {@link
+   * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+   * list size (the same goes for removing elements, as there is no
+   * <code>remove</code> method).
+   *
+   * @param newSize The new size of this list.
+   * @throws IllegalArgumentException If the new size is negative or
+   * greater than 32767, or if there is insufficient space for that
+   * many elements in the underlying buffer.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   */
+  public void setSize (final int newSize)
+  {
+    if (newSize < 0 || newSize > 255)
+      throw new IllegalArgumentException ("size must be between 0 and 255");
+    if (newSize + 1 > buffer.capacity ())
+      throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+                                          + "; requested: " + newSize);
+    buffer.put (0, (byte) newSize);
+    modCount++;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("[");
+    out.print (size ());
+    out.println ("] {");
+    for (Iterator it = new Iterator (); it.hasNext (); )
+      {
+        CompressionMethod method = (CompressionMethod) it.next ();
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  ");
+        out.print (method);
+        if (it.hasNext ())
+          out.print (",");
+        out.println ();
+      }
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("};");
+    return str.toString ();
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof CompressionMethodList))
+      return false;
+    CompressionMethodList that = (CompressionMethodList) o;
+
+    if (size () != that.size ())
+      return false;
+
+    for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+         it1.hasNext () && it2.hasNext (); )
+      {
+        if (!it1.next ().equals (it2.next ()))
+          return false;
+      }
+    return true;
+  }
+
+  public java.util.Iterator<CompressionMethod> iterator ()
+  {
+    return new Iterator ();
+  }
+  
+  /**
+   * An iterator for the elements in this list. The iterator supports
+   * only the <code>set</code> method out of the optional methods,
+   * because elements in a CipherSuiteList may not be removed or
+   * added; only the size of the list can be changed, and elements at
+   * a specific index changed.
+   */
+  public class Iterator implements ListIterator<CompressionMethod>
+  {
+    private int index;
+    private final int modCount;
+
+    Iterator ()
+    {
+      index = 0;
+      modCount = CompressionMethodList.this.modCount;
+    }
+
+    public void add (CompressionMethod cm)
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public boolean hasNext ()
+    {
+      return (index < size ());
+    }
+
+    public boolean hasPrevious ()
+    {
+      return (index > 0);
+    }
+
+    public CompressionMethod next () throws NoSuchElementException
+    {
+      if (modCount != CompressionMethodList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int nextIndex ()
+    {
+      if (hasNext ())
+        return (index + 1);
+      return -1;
+    }
+
+    public CompressionMethod previous () throws NoSuchElementException
+    {
+      if (index == 0)
+        throw new NoSuchElementException ();
+      if (modCount != CompressionMethodList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (--index);
+        }
+      catch (IndexOutOfBoundsException ioobe) // on empty list
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int previousIndex ()
+    {
+      return (index - 1);
+    }
+
+    public void remove ()
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public void set (final CompressionMethod cm)
+    {
+      put (index, cm);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Constructed.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,86 @@
+/* Constructed.java -- Constructed type.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * The base interface to SSL constructed types.
+ * 
+ * <p><b>Contract for ByteBuffer-based constructed types:</b>
+ * 
+ * <p>Most implementations of this interface supported by this library
+ * take a "view" of an underlying ByteBuffer. The general contract of
+ * such classes is that they <em>will not</em> modify the position or
+ * limit of the buffer when doing read operations. That is, the position
+ * of the underlying buffer <em>should</em> remain at 0 throughout the
+ * lifetime of the object, and the limit should be either set to the
+ * capacity of the buffer, or to the size of the object (in most cases,
+ * the length of the protocol object is determined by the contents of
+ * the object, so the limit isn't useful in such cases. Of course, if the
+ * limit is set to something other than the object's length, it must be
+ * larger than the object length).
+ * 
+ * <p>Setter methods (usually in a class that implements the {@link Builder}
+ * interface) may modify the limit, but the general contract remains that
+ * the position remain at zero, and that the limit be at least as large as
+ * the object length.
+ * 
+ * <p>Thus, very often the code will use <em>absolute</em> getters and setters
+ * for primitive types, or it will use the {@link java.nio.ByteBuffer#duplicate()}
+ * method, and sometimes the {@link java.nio.ByteBuffer#slice()} method, and
+ * will change the position or limit of the duplicate buffer.
+ */
+public interface Constructed
+{
+  /**
+   * Returns the total length, in bytes, of this structure.
+   *
+   * @return The length of this structure.
+   */
+  int length();
+
+  /**
+   * Returns a printable representation of this structure, with the
+   * given prefix prepended to each line.
+   *
+   * @param prefix The prefix to prepend to each line of the
+   * output. This value may be <code>null</code>.
+   * @return A printable representation of this structure.
+   */
+  String toString(String prefix);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ContentType.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,93 @@
+/* ContentType.java -- SSL record layer content type.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * The content type enumeration, which marks packets in the record layer.
+ *
+ * <pre>
+enum { change_cipher_spec(20), alert(21), handshake(22),
+       application_data(23), (255) } ContentType;</pre>
+ *
+ * <p>There is also a "pseudo" content type, <code>client_hello_v2
+ * (1)</code>, which is used for backwards compatibility with SSLv2.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public enum ContentType
+{
+
+  CLIENT_HELLO_V2    ( 1),
+  CHANGE_CIPHER_SPEC (20),
+  ALERT              (21),
+  HANDSHAKE          (22),
+  APPLICATION_DATA   (23);
+
+  private int value;
+
+  // Constructors.
+  // ------------------------------------------------------------------------
+
+  private ContentType(int value)
+  {
+    this.value = value;
+  }
+
+  static final ContentType forInteger (final int value)
+  {
+    switch (value & 0xFF)
+      {
+      case  1: return CLIENT_HELLO_V2;
+      case 20: return CHANGE_CIPHER_SPEC;
+      case 21: return ALERT;
+      case 22: return HANDSHAKE;
+      case 23: return APPLICATION_DATA;
+      default: return null;
+      }
+  }
+
+  public int getValue()
+  {
+    return value;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Debug.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,66 @@
+/* Debug.java -- Jessie debug constants.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * Debug constants for Jessie.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class Debug
+{
+  /**
+   * Set to true to dump out traces of SSL connections to the system
+   * logger.
+   */
+  public static final boolean DEBUG = true;
+  
+  /**
+   * Set to true to dump out info about the SSL key exchange. Since this
+   * MAY contain sensitive data, it is a separate value.
+   */
+  public static final boolean DEBUG_KEY_EXCHANGE = true;
+  
+  /**
+   * Set to true to turn on dumping of decrypted packets. Since this will
+   * log potentially-sensitive information (i.e., decrypted messages), only
+   * enable this in debug scenarios.
+   */
+  public static final boolean DEBUG_DECRYPTION = false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/DelegatedTask.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,93 @@
+/* DelegatedTask.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class DelegatedTask implements Runnable
+{
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+  private boolean hasRun;
+  protected Throwable thrown;
+  
+  protected DelegatedTask()
+  {
+    hasRun = false;
+  }
+  
+  public final void run()
+  {
+    if (hasRun)
+      throw new IllegalStateException("task already ran");
+    try
+      {
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_DELEGATED_TASK,
+                      "running delegated task {0} in {1}", this,
+                      Thread.currentThread());
+        implRun();
+      }
+    catch (Throwable t)
+      {
+        if (Debug.DEBUG)
+          logger.log(Component.SSL_DELEGATED_TASK, "task threw exception", t);
+        thrown = t;
+      }
+    finally
+      {
+        hasRun = true;
+      }
+  }
+
+  public final boolean hasRun() 
+  {
+    return hasRun;
+  }
+  
+  public final Throwable thrown()
+  {
+    return thrown;
+  }
+  
+  protected abstract void implRun() throws Throwable;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/DiffieHellman.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,289 @@
+/* DiffieHellman.java -- Diffie-Hellman key exchange.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+
+/**
+ * <p>Simple implementation of two-party Diffie-Hellman key agreement.</p>
+ *
+ * <p>The primes used in this class are from the following documents:</p>
+ *
+ * <ul>
+ * <li>D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", <a
+ * href="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</a>.</li>
+ * <li>T. Kivinen and M. Kojo, "More Modular
+ * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange
+ * (IKE)", <a href="http://www.ietf.org/rfc/rfc3526.txt">RFC
+ * 3526</a>.</li>
+ * </li>
+ *
+ * <p>The generator for all these primes is 2.</p>
+ */
+final class DiffieHellman
+{
+
+  // Class method.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Get the system's Diffie-Hellman parameters, in which <i>g</i> is 2
+   * and <i>p</i> is determined by the property
+   * <code>"jessie.keypool.dh.group"</code>. The default value for <i>p</i>
+   * is 18, corresponding to {@link #GROUP_18}.
+   */
+  static GnuDHPrivateKey getParams()
+  {
+    BigInteger p = DiffieHellman.GROUP_5;
+    String group = AccessController.doPrivileged
+      (new GetSecurityPropertyAction("jessie.key.dh.group"));
+    if (group != null)
+      {
+        group = group.trim();
+        if (group.equals("1"))
+          p = DiffieHellman.GROUP_1;
+        else if (group.equals("2"))
+          p = DiffieHellman.GROUP_2;
+        else if (group.equals("5"))
+          p = DiffieHellman.GROUP_5;
+        else if (group.equals("14"))
+          p = DiffieHellman.GROUP_14;
+        else if (group.equals("15"))
+          p = DiffieHellman.GROUP_15;
+        else if (group.equals("16"))
+          p = DiffieHellman.GROUP_16;
+        else if (group.equals("17"))
+          p = DiffieHellman.GROUP_17;
+        else if (group.equals("18"))
+          p = DiffieHellman.GROUP_18;
+      }
+    return new GnuDHPrivateKey(null, p, DH_G, null);
+  }
+
+  // Constants.
+  // -------------------------------------------------------------------------
+
+  /**
+   * The generator for all Diffie Hellman groups below.
+   */
+  static final BigInteger DH_G = BigInteger.valueOf(2L);
+
+  /**
+   * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+   */
+  static final BigInteger GROUP_1 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
+   */
+  static final BigInteger GROUP_2 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
+    "FFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
+   */
+  static final BigInteger GROUP_5 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }.
+   */
+  static final BigInteger GROUP_14 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+    "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }.
+   */
+  static final BigInteger GROUP_15 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }.
+   */
+  static final BigInteger GROUP_16 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
+    "FFFFFFFFFFFFFFFF", 16);
+
+  static final BigInteger GROUP_17 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" +
+    "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" +
+    "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" +
+    "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" +
+    "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" +
+    "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" +
+    "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" +
+    "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" +
+    "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" +
+    "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" +
+    "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" +
+    "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" +
+    "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" +
+    "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" +
+    "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" +
+    "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
+    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" +
+    "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" +
+    "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" +
+    "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" +
+    "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" +
+    "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
+    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" +
+    "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" +
+    "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" +
+    "6DCC4024FFFFFFFFFFFFFFFF", 16);
+
+  /**
+   * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }.
+   *
+   * <p>This value, while quite large, is estimated to provide the equivalent
+   * cryptographic strength of a symmetric key between 190 and 320 bits.
+   */
+  static final BigInteger GROUP_18 = new BigInteger("00" +
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
+    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" +
+    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" +
+    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" +
+    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" +
+    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" +
+    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" +
+    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
+    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" +
+    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" +
+    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" +
+    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" +
+    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" +
+    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" +
+    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" +
+    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" +
+    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" +
+    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" +
+    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" +
+    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" +
+    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" +
+    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" +
+    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,77 @@
+/* EmptyExchangeKeys.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EmptyExchangeKeys
+  extends ExchangeKeys
+{
+
+  public EmptyExchangeKeys()
+  {
+    super(ByteBuffer.allocate(0));
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    return 0;
+  }
+
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    String ret = "struct { };";
+    if (prefix != null) ret = prefix + ret;
+    return ret;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,151 @@
+/* EncryptedPreMasterSecret.java -- RSA encrypted secret.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's RSA-encrypted pre-master secret.
+ *
+ * <pre>
+struct {
+  public-key-encrypted PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;</pre>
+ */
+public final class EncryptedPreMasterSecret extends ExchangeKeys implements Builder
+{
+  private final ProtocolVersion version;
+
+  public EncryptedPreMasterSecret(ByteBuffer buffer, ProtocolVersion version)
+  {
+    super(buffer);
+    version.getClass();
+    this.version = version;
+  }
+  
+  public EncryptedPreMasterSecret(byte[] encryptedSecret, ProtocolVersion version)
+  {
+    this(ByteBuffer.allocate(version == ProtocolVersion.SSL_3
+                             ? encryptedSecret.length
+                             : encryptedSecret.length + 2), version);
+    ByteBuffer b = buffer.duplicate();
+    if (version != ProtocolVersion.SSL_3)
+      b.putShort((short) encryptedSecret.length);
+    b.put(encryptedSecret);
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind();
+  }
+
+  public byte[] encryptedSecret()
+  {
+    byte[] secret;
+    if (version == ProtocolVersion.SSL_3)
+      {
+        buffer.position (0);
+        secret = new byte[buffer.limit ()];
+        buffer.get(secret);
+      }
+    else
+      {
+        int len = buffer.getShort(0) & 0xFFFF;
+        secret = new byte[len];
+        buffer.position(2);
+        buffer.get(secret);
+      }
+    return secret;
+  }
+
+  public void setEncryptedSecret(final byte[] secret, final int offset, final int length)
+  {
+    if (version == ProtocolVersion.SSL_3)
+      {
+        buffer.position(0);
+        buffer.put(secret, offset, length);
+        buffer.rewind();
+      }
+    else
+      {
+        buffer.putShort(0, (short) length);
+        buffer.position(2);
+        buffer.put(secret, offset, length);
+        buffer.rewind();
+      }
+  }
+
+  public int length ()
+  {
+    if (version == ProtocolVersion.SSL_3)
+      {
+        return buffer.capacity();
+      }
+    else
+      {
+        return (buffer.getShort(0) & 0xFFFF) + 2;
+      }
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.println("  pre_master_secret = ");
+    out.print(Util.hexDump(encryptedSecret(), prefix != null ? prefix + "    "
+                                                             : "    "));
+    if (prefix != null) out.print(prefix);
+    out.print("} EncryptedPreMasterSecret;");
+    return str.toString();
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ExchangeKeys.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,54 @@
+/* ExchangeKeys.java -- key exchange values.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public abstract class ExchangeKeys implements Constructed
+{
+
+  protected ByteBuffer buffer;
+
+  public ExchangeKeys (final ByteBuffer buffer)
+  {
+    if (buffer != null)
+      this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Extension.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,246 @@
+/* Extension.java -- A TLS hello extension.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL hello extension.
+ * 
+ * <pre>
+ * struct {
+ *   ExtensionType extension_type;
+ *   opaque extension_data<0..2^16-1>;
+ * } Extension;</pre>
+ * 
+ * @author csm@gnu.org
+ */
+public final class Extension implements Builder, Constructed
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private ByteBuffer buffer;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public Extension(final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  public Extension(final Type type, final Value value)
+  {
+    ByteBuffer valueBuffer = value.buffer();
+    int length = 2 + 2 + valueBuffer.remaining();
+    buffer = ByteBuffer.allocate(length);
+    buffer.putShort((short) type.getValue());
+    buffer.putShort((short) valueBuffer.remaining());
+    buffer.put(valueBuffer);
+    buffer.rewind();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    return (buffer.getShort (2) & 0xFFFF) + 4;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+
+  public Type type()
+  {
+    return Type.forValue (buffer.getShort (0) & 0xFFFF);
+  }
+
+  public byte[] valueBytes()
+  {
+    int len = buffer.getShort (2) & 0xFFFF;
+    byte[] value = new byte[len];
+    ((ByteBuffer) buffer.duplicate ().position (4)).get (value);
+    return value;
+  }
+  
+  public ByteBuffer valueBuffer()
+  {
+    int len = buffer.getShort(2) & 0xFFFF;
+    return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice();
+  }
+  
+  public Value value()
+  {
+    switch (type ())
+      {
+        case SERVER_NAME:
+          return new ServerNameList(valueBuffer());
+          
+        case MAX_FRAGMENT_LENGTH:
+          switch (valueBuffer().get() & 0xFF)
+            {
+              case 1: return MaxFragmentLength.LEN_2_9;
+              case 2: return MaxFragmentLength.LEN_2_10;
+              case 3: return MaxFragmentLength.LEN_2_11;
+              case 4: return MaxFragmentLength.LEN_2_12;
+              default:
+                throw new IllegalArgumentException("invalid max_fragment_len");
+            }
+          
+        case TRUNCATED_HMAC:
+          return new TruncatedHMAC();
+
+        case CLIENT_CERTIFICATE_URL:
+          return new CertificateURL(valueBuffer());
+          
+        case TRUSTED_CA_KEYS:
+          return new TrustedAuthorities(valueBuffer());
+          
+        case STATUS_REQUEST:
+          return new CertificateStatusRequest(valueBuffer());
+          
+        case SRP:
+        case CERT_TYPE:
+      }
+    return new UnresolvedExtensionValue(valueBuffer());
+  }
+  
+  public void setLength (final int newLength)
+  {
+    if (newLength < 0 || newLength > 65535)
+      throw new IllegalArgumentException ("length is out of bounds");
+    buffer.putShort (2, (short) newLength);
+  }
+  
+  public void setType (final Type type)
+  {
+    buffer.putShort(0, (short) type.getValue());
+  }
+
+  public void setValue (byte[] value)
+  {
+    setValue (value, 0, value.length);
+  }
+  
+  public void setValue (final byte[] value, final int offset, final int length)
+  {
+    if (length != length ())
+      throw new IllegalArgumentException ("length is different than claimed length");
+    ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length);
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print (prefix);
+    out.println("struct {");
+    if (prefix != null) out.print (prefix);
+    out.println("  type = " + type () + ";");
+    if (prefix != null) out.print (prefix);
+    String subprefix = "  ";
+    if (prefix != null) subprefix = prefix + subprefix;
+    out.println("  value =");
+    out.println(value().toString(subprefix));
+    if (prefix != null) out.print (prefix);
+    out.print("} Extension;");
+    return str.toString();
+  }
+
+  // Inner classes.
+  // -------------------------------------------------------------------------
+
+  public static enum Type
+  {
+    SERVER_NAME            (0),
+    MAX_FRAGMENT_LENGTH    (1),
+    CLIENT_CERTIFICATE_URL (2),
+    TRUSTED_CA_KEYS        (3),
+    TRUNCATED_HMAC         (4),
+    STATUS_REQUEST         (5),
+    SRP                    (6),
+    CERT_TYPE              (7);
+
+    private final int value;
+
+    private Type(int value)
+    {
+      this.value = value;
+    }
+
+    public static Type forValue (final int value)
+    {
+      switch (value & 0xFFFF)
+        {
+          case 0: return SERVER_NAME;
+          case 1: return MAX_FRAGMENT_LENGTH;
+          case 2: return CLIENT_CERTIFICATE_URL;
+          case 3: return TRUSTED_CA_KEYS;
+          case 4: return TRUNCATED_HMAC;
+          case 5: return STATUS_REQUEST;
+          case 6: return SRP;
+          case 7: return CERT_TYPE;
+          default: return null;
+        }
+    }
+    
+    public int getValue()
+    {
+      return value;
+    }
+  }
+  
+  public static abstract class Value implements Builder, Constructed
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ExtensionList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,290 @@
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A list of extensions, that may appear in either the {@link ClientHello} or
+ * {@link ServerHello}. The form of the extensions list is:
+ * 
+ * <tt>   Extension extensions_list&lt;1..2^16-1&gt;</tt>
+ * 
+ * @author csm
+ */
+public class ExtensionList implements Builder, Iterable<Extension>
+{
+  private final ByteBuffer buffer;
+  private int modCount;
+
+  public ExtensionList (ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    modCount = 0;
+  }
+  
+  public ExtensionList(List<Extension> extensions)
+  {
+    int length = 2;
+    for (Extension extension : extensions)
+      length += extension.length();
+    buffer = ByteBuffer.allocate(length);
+    buffer.putShort((short) (length - 2));
+    for (Extension extension : extensions)
+      buffer.put(extension.buffer());
+    buffer.rewind();
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+
+  public Extension get (final int index)
+  {
+    int length = length ();
+    int i;
+    int n = 0;
+    for (i = 2; i < length && n < index; )
+      {
+        int l = buffer.getShort (i+2) & 0xFFFF;
+        i += l + 4;
+        n++;
+      }
+    if (n < index)
+      throw new IndexOutOfBoundsException ("no elemenet at " + index);
+    int el = buffer.getShort (i+2) & 0xFFFF;
+    ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4);
+    return new Extension(b.slice());
+  }
+  
+  /**
+   * Returns the number of extensions this list contains.
+   * 
+   * @return The number of extensions.
+   */
+  public int size ()
+  {
+    int length = length ();
+    if (length == 0)
+      return 0;
+    int n = 0;
+    for (int i = 2; i < length; )
+      {
+        int len = buffer.getShort (i+2) & 0xFFFF;
+        i += len + 4;
+        n++;
+      }
+    return n;
+  }
+
+  /**
+   * Returns the length of this extension list, in bytes.
+   * 
+   * @return The length of this extension list, in bytes.
+   */
+  public int length ()
+  {
+    return (buffer.getShort (0) & 0xFFFF) + 2;
+  }
+  
+  /**
+   * Sets the extension at index <i>i</i> to <i>e</i>. Note that setting an
+   * element at an index <b>may</b> invalidate any other elements that come
+   * after element at index <i>i</i>. In other words, no attempt is made to
+   * move existing elements in this list, and since extensions are variable
+   * length, you can <em>not</em> guarantee that extensions later in the list
+   * will still be valid.
+   * 
+   * <p>Thus, elements of this list <b>must</b> be set in order of increasing
+   * index.
+   * 
+   * @param index The index to set the extension at.
+   * @param e The extension.
+   * @throws java.nio.BufferOverflowException If setting the extension overflows
+   *  the buffer.
+   * @throws IllegalArgumentException If it isn't possible to find the given index
+   *  in the current list (say, if no element index - 1 is set), or if setting
+   *  the extension will overflow the current list length (given by {@link
+   *  #length()}).
+   */
+  public void set (final int index, Extension e)
+  {
+    int length = length();
+    int n = 0;
+    int i;
+    for (i = 2; i < length && n < index; )
+      {
+        int len = buffer.getShort(i+2) & 0xFFFF;
+        i += len + 4;
+        n++;
+      }
+    if (n < index)
+      throw new IllegalArgumentException("nothing set at index " + (index-1)
+                                         + " or insufficient space");
+    if (i + e.length() + 2 > length)
+      throw new IllegalArgumentException("adding this element will exceed the "
+                                         + "list length");
+    buffer.putShort(i, (short) e.type().getValue());
+    buffer.putShort(i+2, (short) e.length());
+    ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer());
+    modCount++;
+  }
+  
+  /**
+   * Reserve space for an extension at index <i>i</i> in the list. In other
+   * words, this does the job of {@link #set(int, Extension)}, but does not
+   * copy the extension value to the underlying buffer.
+   * 
+   * @param index The index of the extension to reserve space for.
+   * @param t The type of the extension.
+   * @param eLength The number of bytes to reserve for this extension. The total
+   *  number of bytes used by this method is this length, plus four.
+   */
+  public void set (final int index, Extension.Type t, final int eLength)
+  {
+    int length = length ();
+    int n = 0;
+    int i;
+    for (i = 2; i < length && n < index; )
+      {
+        int len = buffer.getShort (i+2) & 0xFFFF;
+        i += len + 4;
+        n++;
+      }
+    if (n < index)
+      throw new IllegalArgumentException ("nothing set at index " + (index-1)
+                                          + " or insufficient space");
+    if (i + eLength + 2 > length)
+      throw new IllegalArgumentException ("adding this element will exceed the "
+                                          + "list length");
+    buffer.putShort(i, (short) t.getValue());
+    buffer.putShort(i+2, (short) eLength);
+    modCount++;
+  }
+  
+  /**
+   * Set the total length of this list, in bytes.
+   * 
+   * @param newLength The new list length.
+   */
+  public void setLength (final int newLength)
+  {
+    if (newLength < 0 || newLength > 65535)
+      throw new IllegalArgumentException ("invalid length");
+    buffer.putShort (0, (short) newLength);
+    modCount++;
+  }
+  
+  public Iterator<Extension> iterator()
+  {
+    return new ExtensionsIterator();
+  }
+
+  public String toString()
+  {
+    return toString (null);
+  }
+  
+  public String toString(final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("ExtensionList {");
+    if (prefix != null) out.print(prefix);
+    out.print("  length = ");
+    out.print(length());
+    out.println(";");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix = prefix + subprefix;
+    for (Extension e : this)
+      out.println(e.toString(subprefix));
+    if (prefix != null) out.print(prefix);
+    out.print("};");
+    return str.toString();
+  }
+
+  /**
+   * List iterator interface to an extensions list.
+   * 
+   * @author csm@gnu.org
+   */
+  public final class ExtensionsIterator implements ListIterator<Extension>
+  {
+    private final int modCount;
+    private int index;
+    private final int size;
+    
+    public ExtensionsIterator ()
+    {
+      this.modCount = ExtensionList.this.modCount;
+      index = 0;
+      size = size ();
+    }
+
+    public boolean hasNext()
+    {
+      return index < size;
+    }
+
+    public boolean hasPrevious()
+    {
+      return index > 0;
+    }
+
+    public Extension next() throws NoSuchElementException
+    {
+      if (modCount != ExtensionList.this.modCount)
+        throw new ConcurrentModificationException ();
+      if (!hasNext ())
+        throw new NoSuchElementException ();
+      return get (index++);
+    }
+
+    public Extension previous() throws NoSuchElementException
+    {
+      if (modCount != ExtensionList.this.modCount)
+        throw new ConcurrentModificationException ();
+      if (!hasPrevious ())
+        throw new NoSuchElementException ();
+      return get (--index);
+    }
+
+    public int nextIndex()
+    {
+      if (hasNext ())
+        return index + 1;
+      return index;
+    }
+
+    public int previousIndex()
+    {
+      if (hasPrevious ())
+        return index - 1;
+      return -1;
+    }
+
+    public void add(Extension e)
+    {
+      throw new UnsupportedOperationException ("cannot add items to this iterator");
+    }
+
+    public void remove()
+    {
+      throw new UnsupportedOperationException ("cannot remove items from this iterator");
+    }
+
+    public void set(Extension e)
+    {
+      ExtensionList.this.set (index, e);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Finished.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,173 @@
+/* Finished.java -- SSL Finished message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+final class Finished implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final ByteBuffer buffer;
+  private final ProtocolVersion version;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  Finished (final ByteBuffer buffer, final ProtocolVersion version)
+  {
+    buffer.getClass ();
+    version.getClass ();
+    this.buffer = buffer;
+    this.version = version;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+      return 12;
+    if (version == ProtocolVersion.SSL_3)
+      return 36;
+    throw new IllegalArgumentException ("length for this version unknown");
+  }
+
+  byte[] verifyData()
+  {
+    if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+      {
+        byte[] verify = new byte[12];
+        buffer.position (0);
+        buffer.get (verify);
+        return verify;
+      }
+    throw new IllegalArgumentException ("not TLSv1.0 or later");
+  }
+
+  byte[] md5Hash()
+  {
+    if (version == ProtocolVersion.SSL_3)
+      {
+        byte[] md5 = new byte[16];
+        buffer.position (0);
+        buffer.get (md5);
+        return md5;
+      }
+    throw new IllegalArgumentException ("not SSLv3");
+  }
+
+  byte[] shaHash()
+  {
+    if (version == ProtocolVersion.SSL_3)
+      {
+        byte[] sha = new byte[20];
+        buffer.position (16);
+        buffer.get (sha);
+        return sha;
+      }
+    throw new IllegalArgumentException ("not SSLv3");
+  }
+
+  void setVerifyData (final byte[] verifyData, final int offset)
+  {
+    if (version == ProtocolVersion.SSL_3)
+      throw new IllegalArgumentException ("not TLSv1");
+    buffer.position (0);
+    buffer.put (verifyData, offset, 12);
+  }
+
+  void setMD5Hash (final byte[] md5, final int offset)
+  {
+    if (version != ProtocolVersion.SSL_3)
+      throw new IllegalArgumentException ("not SSLv3");
+    buffer.position (0);
+    buffer.put (md5, offset, 16);
+  }
+
+  void setShaHash (final byte[] sha, final int offset)
+  {
+    if (version != ProtocolVersion.SSL_3)
+      throw new IllegalArgumentException ("not SSLv3");
+    buffer.position (16);
+    buffer.put (sha, offset, 20);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null)
+      out.print (prefix);
+    if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+      {
+        out.print ("  verifyData = ");
+        out.print (Util.toHexString (verifyData (), ':'));
+      }
+    else if (version == ProtocolVersion.SSL_3)
+      {
+        out.print ("  md5 = ");
+        out.print (Util.toHexString (md5Hash (), ':'));
+        out.println (';');
+        if (prefix != null)
+          out.print (prefix);
+        out.print ("  sha = ");
+        out.print (Util.toHexString (shaHash (), ':'));
+      }
+    out.println (';');
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("} Finished;");
+    return str.toString ();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Handshake.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,314 @@
+/* Handshake.java -- SSL Handshake message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.security.PublicKey;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.net.ssl.SSLProtocolException;
+
+/**
+ * An SSL handshake message. SSL handshake messages have the following
+ * form:
+ *
+ * <pre>
+struct
+{
+  HandshakeType msg_type;
+  uint24        length;
+  select (msg_type)
+  {
+    case hello_request:       HelloRequest;
+    case client_hello:        ClientHello;
+    case server_hello:        ServerHello;
+    case certificate:         Certificate;
+    case server_key_exchange: ServerKeyExchange;
+    case certificate_request: CertificateRequest;
+    case server_hello_done:   ServerHelloDone;
+    case certificate_verify:  CertificateVerify;
+    case client_key_exchange: ClientKeyExchange;
+    case finished:            Finished;
+  } body;
+};</pre>
+ */
+public final class Handshake implements Constructed
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final ByteBuffer buffer;
+  private final CipherSuite suite;
+  private final ProtocolVersion version;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public Handshake (final ByteBuffer buffer)
+  {
+    this (buffer, null, ProtocolVersion.TLS_1_1);
+  }
+
+  public Handshake (final ByteBuffer buffer, final CipherSuite suite,
+                    final ProtocolVersion version)
+  {
+    this.buffer = buffer;
+    this.suite = suite;
+    this.version = version;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Returns the handshake type.
+   *
+   * @return The handshake type.
+   */
+  public Type type()
+  {
+    return Type.forInteger (buffer.get (0) & 0xFF);
+  }
+
+  /**
+   * Returns the message length.
+   *
+   * @return The message length.
+   */
+  public int length ()
+  {
+    // Length is a uint24.
+    return buffer.getInt (0) & 0xFFFFFF;
+  }
+
+  /**
+   * Returns the handshake message body. Depending on the handshake
+   * type, some implementation of the Body interface is returned.
+   *
+   * @return The handshake body.
+   */
+  public Body body()
+  {
+    Type type = type ();
+    ByteBuffer bodyBuffer = bodyBuffer ();
+    switch (type)
+      {
+      case HELLO_REQUEST:
+        return new HelloRequest ();
+
+      case CLIENT_HELLO:
+        return new ClientHello (bodyBuffer);
+
+      case SERVER_HELLO:
+        return new ServerHello (bodyBuffer);
+
+      case CERTIFICATE:
+        return new Certificate (bodyBuffer, CertificateType.X509);
+
+      case SERVER_KEY_EXCHANGE:
+        return new ServerKeyExchange (bodyBuffer, suite);
+
+      case CERTIFICATE_REQUEST:
+        return new CertificateRequest (bodyBuffer);
+
+      case SERVER_HELLO_DONE:
+        return new ServerHelloDone ();
+
+      case CERTIFICATE_VERIFY:
+        return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ());
+
+      case CLIENT_KEY_EXCHANGE:
+        return new ClientKeyExchange (bodyBuffer, suite, version);
+
+      case FINISHED:
+        return new Finished (bodyBuffer, version);
+
+      case CERTIFICATE_URL:
+      case CERTIFICATE_STATUS:
+        throw new UnsupportedOperationException ("FIXME");
+      }
+    throw new IllegalArgumentException ("unknown handshake type " + type);
+  }
+
+  /**
+   * Returns a subsequence of the underlying buffer, containing only
+   * the bytes that compose the handshake body.
+   *
+   * @return The body's byte buffer.
+   */
+  public ByteBuffer bodyBuffer ()
+  {
+    int length = length ();
+    return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
+  }
+
+  /**
+   * Sets the handshake body type.
+   *
+   * @param type The handshake type.
+   */
+  public void setType (final Type type)
+  {
+    buffer.put (0, (byte) type.getValue ());
+  }
+
+  /**
+   * Sets the length of the handshake body.
+   *
+   * @param length The handshake body length.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   * @throws IllegalArgumentException of <code>length</code> is not
+   * between 0 and 16777215, inclusive.
+   */
+  public void setLength (final int length)
+  {
+    if (length < 0 || length > 0xFFFFFF)
+      throw new IllegalArgumentException ("length " + length + " out of range;"
+                                          + " must be between 0 and 16777215");
+    buffer.put (1, (byte) (length >>> 16));
+    buffer.put (2, (byte) (length >>>  8));
+    buffer.put (3, (byte)  length);
+  }
+
+  public String toString()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print (prefix);
+    out.println("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  type: ");
+    out.print (type ());
+    out.println (";");
+    Body body = body ();
+    out.println (body.toString (prefix != null ? (prefix + "  ") : "  "));
+    if (prefix != null) out.print (prefix);
+    out.print ("} Handshake;");
+    return str.toString();
+  }
+
+  // Inner class.
+  // -------------------------------------------------------------------------
+
+  public static interface Body extends Constructed
+  {
+    int length ();
+
+    String toString (String prefix);
+  }
+
+  public static enum Type
+  {
+    HELLO_REQUEST       ( 0),
+    CLIENT_HELLO        ( 1),
+    SERVER_HELLO        ( 2),
+    CERTIFICATE         (11),
+    SERVER_KEY_EXCHANGE (12),
+    CERTIFICATE_REQUEST (13),
+    SERVER_HELLO_DONE   (14),
+    CERTIFICATE_VERIFY  (15),
+    CLIENT_KEY_EXCHANGE (16),
+    FINISHED            (20),
+    CERTIFICATE_URL     (21),
+    CERTIFICATE_STATUS  (22);
+
+    private final int value;
+
+    private Type(int value)
+    {
+      this.value = value;
+    }
+
+    // Class methods.
+    // -----------------------------------------------------------------------
+
+    /**
+     * Convert a raw handshake type value to a type enum value.
+     * 
+     * @return The corresponding enum value for the raw integer value.
+     * @throws IllegalArgumentException If the value is not a known handshake
+     *  type.
+     */
+    public static Type forInteger (final int value)
+    {
+      switch (value & 0xFF)
+        {
+        case 0:  return HELLO_REQUEST;
+        case 1:  return CLIENT_HELLO;
+        case 2:  return SERVER_HELLO;
+        case 11: return CERTIFICATE;
+        case 12: return SERVER_KEY_EXCHANGE;
+        case 13: return CERTIFICATE_REQUEST;
+        case 14: return SERVER_HELLO_DONE;
+        case 15: return CERTIFICATE_VERIFY;
+        case 16: return CLIENT_KEY_EXCHANGE;
+        case 20: return FINISHED;
+        case 21: return CERTIFICATE_URL;
+        case 22: return CERTIFICATE_STATUS;
+        default: throw new IllegalArgumentException ("unsupported value type " + value);
+        }
+    }
+
+    public int getValue()
+    {
+      return value;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/HelloRequest.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,70 @@
+/* HelloRequest.java -- SSL HelloRequest handshake message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * The handshake body for a HelloRequest handshake message.
+ *
+ * <pre>struct { } HelloRequest;</pre>
+ */
+public final class HelloRequest implements Handshake.Body
+{
+  public HelloRequest ()
+  {
+  }
+
+  public String toString (final String prefix)
+  {
+    StringBuffer str = new StringBuffer ();
+    if (prefix != null)
+      str.append (prefix);
+    str.append ("HelloRequest { };");
+    return str.toString ();
+  }
+
+  public int length ()
+  {
+    return 0;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/InputSecurityParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,336 @@
+/* SecurityParameters.java -- SSL security parameters.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteArray;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+import javax.net.ssl.SSLException;
+
+public class InputSecurityParameters
+{
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+  private final Cipher cipher;
+  private final Mac mac;
+  private final Inflater inflater;
+  private SessionImpl session;
+  private final CipherSuite suite;
+  private long sequence;
+
+  public InputSecurityParameters (final Cipher cipher, final Mac mac,
+                                  final Inflater inflater,
+                                  final SessionImpl session,
+                                  final CipherSuite suite)
+  {
+    this.cipher = cipher;
+    this.mac = mac;
+    this.inflater = inflater;
+    this.session = session;
+    this.suite = suite;
+    sequence = 0;
+  }
+
+  /**
+   * Decrypt a record, storing the decrypted fragment into the given array
+   * of byte buffers.
+   * 
+   * @param record The input record.
+   * @param output The output buffers.
+   * @param offset The offset of the first buffer to use.
+   * @param length The number of buffers to use.
+   * @return The number of bytes put in the output buffers.
+   * @throws DataFormatException If decompression fails.
+   * @throws IllegalBlockSizeException If the current cipher is a block cipher,
+   *  and the input fragment is not a multiple of the block size.
+   * @throws MacException If verifying the MAC fails.
+   * @throws SSLException ???
+   * @throws ShortBufferException 
+   */
+  public int decrypt(Record record, ByteBuffer[] output, int offset, int length)
+    throws DataFormatException, IllegalBlockSizeException,
+           MacException, SSLException, ShortBufferException
+  {
+    return decrypt(record, output, offset, length, null);
+  }
+  
+  /**
+   * Decrypt a record, storing the decrypted fragment into the given growable
+   * buffer.
+   * 
+   * @param record The input record.
+   * @param outputStream The output buffer.
+   * @return The number of bytes put into the output buffer.
+   * @throws DataFormatException
+   * @throws IllegalBlockSizeException
+   * @throws MacException
+   * @throws SSLException
+   * @throws ShortBufferException
+   */
+  public int decrypt(Record record, ByteBufferOutputStream outputStream)
+    throws DataFormatException, IllegalBlockSizeException,
+           MacException, SSLException, ShortBufferException
+  {
+    return decrypt(record, null, 0, 0, outputStream);
+  }
+  
+  private int decrypt(Record record, ByteBuffer[] output, int offset, int length,
+                      ByteBufferOutputStream outputStream)
+    throws DataFormatException, IllegalBlockSizeException,
+           MacException, SSLException, ShortBufferException
+  {
+    boolean badPadding = false;
+    ByteBuffer fragment;
+    if (cipher != null)
+      {
+        ByteBuffer input = record.fragment();
+        fragment = ByteBuffer.allocate(input.remaining());
+        cipher.update(input, fragment);
+      }
+    else
+      fragment = record.fragment();
+
+    if (Debug.DEBUG_DECRYPTION)
+      logger.logv(Component.SSL_RECORD_LAYER, "decrypted fragment:\n{0}",
+                  Util.hexDump((ByteBuffer) fragment.duplicate().position(0), " >> "));
+    
+    int fragmentLength = record.length();
+    int maclen = 0;
+    if (mac != null)
+      maclen = mac.getMacLength();
+    fragmentLength -= maclen;
+
+    int padlen = 0;
+    int padRemoveLen = 0;
+    if (!suite.isStreamCipher ())
+      {
+        padlen = fragment.get(record.length() - 1) & 0xFF;
+        padRemoveLen = padlen + 1;
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "padlen:{0}", padlen);
+
+        if (record.version() == ProtocolVersion.SSL_3)
+          {
+            // In SSLv3, the padding length must not be larger than
+            // the cipher's block size.
+            if (padlen > cipher.getBlockSize ())
+              badPadding = true;
+          }
+        else if (record.version().compareTo(ProtocolVersion.TLS_1) >= 0)
+          {
+            // In TLSv1 and later, the padding must be `padlen' copies of the
+            // value `padlen'.
+            byte[] pad = new byte[padlen];
+            ((ByteBuffer) fragment.duplicate().position(record.length() - padlen - 1)).get(pad);
+            for (int i = 0; i < pad.length; i++)
+              if ((pad[i] & 0xFF) != padlen)
+                badPadding = true;
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_RECORD_LAYER, "TLSv1.x padding\n{0}",
+                          new ByteArray(pad));
+          }
+        
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "padding bad? {0}",
+                      badPadding);
+        if (!badPadding)
+          fragmentLength = fragmentLength - padRemoveLen;
+      }
+    
+    int ivlen = 0;
+    if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+        && !suite.isStreamCipher())
+      ivlen = cipher.getBlockSize();
+
+    // Compute and check the MAC.
+    if (mac != null)
+      {
+        mac.update((byte) (sequence >>> 56));
+        mac.update((byte) (sequence >>> 48));
+        mac.update((byte) (sequence >>> 40));
+        mac.update((byte) (sequence >>> 32));
+        mac.update((byte) (sequence >>> 24));
+        mac.update((byte) (sequence >>> 16));
+        mac.update((byte) (sequence >>>  8));
+        mac.update((byte)  sequence);
+        mac.update((byte) record.getContentType().getValue());
+        ProtocolVersion version = record.version();
+        if (version != ProtocolVersion.SSL_3)
+          {
+            mac.update((byte) version.major());
+            mac.update((byte) version.minor());
+          }
+        mac.update((byte) ((fragmentLength - ivlen) >>> 8));
+        mac.update((byte)  (fragmentLength - ivlen));
+        ByteBuffer content =
+          (ByteBuffer) fragment.duplicate().position(ivlen).limit(fragmentLength);
+        mac.update(content);
+        byte[] mac1 = mac.doFinal ();
+        byte[] mac2 = new byte[maclen];
+        mac.reset();
+        ((ByteBuffer) fragment.duplicate().position(fragmentLength)).get(mac2);
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "mac1:{0} mac2:{1}",
+                      Util.toHexString(mac1, ':'), Util.toHexString(mac2, ':'));
+        if (!Arrays.equals (mac1, mac2))
+          badPadding = true;
+      }
+
+    // We always say "bad MAC" and not "bad padding," because saying
+    // the latter will leak information to an attacker.
+    if (badPadding)
+      throw new MacException ();
+
+    // Inflate the compressed bytes.
+    int produced = 0;
+    if (inflater != null)
+      {
+        ByteBufferOutputStream out = new ByteBufferOutputStream(fragmentLength);
+        byte[] inbuffer = new byte[1024];
+        byte[] outbuffer = new byte[1024];
+        boolean done = false;
+        if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+            && !suite.isStreamCipher())
+          fragment.position (cipher.getBlockSize());
+        else
+          fragment.position(0);
+        fragment.limit(fragmentLength);
+        
+        while (!done)
+          {
+            int l;
+            if (inflater.needsInput())
+              {
+                l = Math.min(inbuffer.length, fragment.remaining());
+                fragment.get(inbuffer, 0, l);
+                inflater.setInput(inbuffer);
+              }
+
+            l = inflater.inflate(outbuffer);
+            out.write(outbuffer, 0, l);
+            done = !fragment.hasRemaining() && inflater.finished();
+          }
+        
+        ByteBuffer outbuf = out.buffer();
+        if (outputStream != null)
+          {
+            byte[] buf = new byte[1024];
+            while (outbuf.hasRemaining())
+              {
+                int l = Math.min(outbuf.remaining(), buf.length);
+                outbuf.get(buf, 0, l);
+                outputStream.write(buf, 0, l);
+                produced += l;
+              }
+          }
+        else
+          {
+            int i = offset;
+            while (outbuf.hasRemaining() && i < offset + length)
+              {
+                int l = Math.min(output[i].remaining(), outbuf.remaining());
+                ByteBuffer b = (ByteBuffer)
+                  outbuf.duplicate().limit(outbuf.position() + l);
+                output[i++].put(b);
+                outbuf.position(outbuf.position() + l);
+                produced += l;
+              }
+            if (outbuf.hasRemaining())
+              throw new BufferOverflowException();
+          }
+      }
+    else
+      {
+        ByteBuffer outbuf = (ByteBuffer)
+          fragment.duplicate().position(0).limit(record.length() - maclen - padRemoveLen);
+        if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+            && !suite.isStreamCipher())
+          outbuf.position(cipher.getBlockSize());
+        if (outputStream != null)
+          {
+            byte[] buf = new byte[1024];
+            while (outbuf.hasRemaining())
+              {
+                int l = Math.min(outbuf.remaining(), buf.length);
+                outbuf.get(buf, 0, l);
+                outputStream.write(buf, 0, l);
+                produced += l;
+              }
+          }
+        else
+          {
+            int i = offset;
+            while (outbuf.hasRemaining() && i < offset + length)
+              {
+                int l = Math.min(output[i].remaining(), outbuf.remaining());
+                ByteBuffer b = (ByteBuffer) outbuf.duplicate().limit(outbuf.position() + l);
+                output[i++].put(b);
+                outbuf.position(outbuf.position() + l);
+                produced += l;
+              }
+            if (outbuf.hasRemaining())
+              throw new BufferOverflowException();
+          }
+      }
+
+    sequence++;
+    
+    return produced;
+  }
+  
+  CipherSuite cipherSuite ()
+  {
+    return suite;
+  }
+}
Binary file jce/gnu/javax/net/ssl/provider/Jessie.class has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Jessie.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,102 @@
+/* Jessie.java -- JESSIE's JSSE provider.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+/**
+ * This is the security provider for Jessie. It implements the following
+ * algorithms:
+ *
+ * <pre>
+ * {@link javax.net.ssl.SSLContext}.SSLv3
+ * {@link javax.net.ssl.SSLContext}.SSL
+ * {@link javax.net.ssl.SSLContext}.TLSv1
+ * {@link javax.net.ssl.SSLContext}.TLS
+ * {@link javax.net.ssl.KeyManagerFactory}.JessieX509
+ * {@link javax.net.ssl.TrustManagerFactory}.JessieX509
+ * {@link javax.net.ssl.TrustManagerFactory}.SRP
+ * </pre>
+ *
+ */
+public class Jessie extends Provider
+{
+  private static final long serialVersionUID = -1;
+
+  public static final String VERSION = "2.0.0";
+  public static final double VERSION_DOUBLE = 2.0;
+
+  public Jessie()
+  {
+    super("Jessie", VERSION_DOUBLE,
+          "Implementing TLSv1.1, with SSLv3, TLSv1.0 compatibility modes; "
+          + "X.509 Key Manager Factory; "
+          + "X.509 Trust Manager Factory; "
+          + "SSLv3 MD5 and SHA Mac.");
+
+    AccessController.doPrivileged(new PrivilegedAction<Object>()
+      {
+        public Object run()
+        {
+          put("SSLContext.TLSv1.1", SSLContextImpl.class.getName());
+          put("Alg.Alias.SSLContext.SSLv3",   "TLSv1.1");
+          put("Alg.Alias.SSLContext.TLSv1",   "TLSv1.1");
+          put("Alg.Alias.SSLContext.TLSv1.0", "TLSv1.1");
+          put("Alg.Alias.SSLContext.TLS",     "TLSv1.1");
+          put("Alg.Alias.SSLContext.SSL",     "TLSv1.1");
+
+          put("KeyManagerFactory.JessieX509",   X509KeyManagerFactory.class.getName());
+          put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName());
+          put("KeyManagerFactory.JessiePSK",    PreSharedKeyManagerFactoryImpl.class.getName());
+          //put("TrustManagerFactory.SRP",        SRPTrustManagerFactory.class.getName());
+
+          put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName());
+          put("Mac.SSLv3HMac-SHA", SSLv3HMacSHAImpl.class.getName());
+          
+          put("Signature.TLSv1.1-RSA", SSLRSASignatureImpl.class.getName());
+          put("Alg.Alias.Signature.TLSv1-RSA", "TLSv1.1-RSA");
+          put("Alg.Alias.Signature.SSLv3-RSA", "TLSv1.1-RSA");
+          
+          return null;
+        }
+      });
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,57 @@
+/* KeyExchangeAlgorithm.java -- Key exchange algorithm enumeration.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * The enumeration of supported key exchange algorithms.
+ */
+public enum KeyExchangeAlgorithm
+{
+  NONE,
+  RSA,
+  DH_DSS,
+  DH_RSA,
+  DH_anon,
+  DHE_DSS,
+  DHE_RSA,
+//  SRP,
+  PSK,
+  DHE_PSK,
+  RSA_PSK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/MacAlgorithm.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,47 @@
+/* MacAlgorithm.java -- MAC algorithm enumeration.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * An enumeration of MAC algorithms we support.
+ */
+public enum MacAlgorithm
+{
+  NULL, MD5, SHA;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/MacException.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,53 @@
+/* MacException.java -- signals a bad record MAC.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+
+class MacException extends IOException
+{
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  MacException()
+  {
+    super();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/MaxFragmentLength.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,59 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Extension value 
+ * @author csm
+ */
+public class MaxFragmentLength extends Value
+{
+  public static final MaxFragmentLength LEN_2_9 = new MaxFragmentLength(1, 1 << 9);
+  public static final MaxFragmentLength LEN_2_10 = new MaxFragmentLength(2, 1 << 10);
+  public static final MaxFragmentLength LEN_2_11 = new MaxFragmentLength(3, 1 << 11);
+  public static final MaxFragmentLength LEN_2_12 = new MaxFragmentLength(4, 1 << 12);
+  
+  private final int value;
+  private final int length;
+  
+  private MaxFragmentLength(int value, int length)
+  {
+    this.value = value;
+    this.length = length;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return ByteBuffer.allocate(1).put(0, (byte) value);
+  }
+  
+  public int length()
+  {
+    return 1;
+  }
+
+  public int getValue()
+  {
+    return value;
+  }
+  
+  public int maxLength()
+  {
+    return length;
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  public String toString(String prefix)
+  {
+    String s = "max_fragment_length = ";
+    if (prefix != null)
+      s = prefix + s;
+    return s + maxLength() + ";";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/OutputSecurityParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,297 @@
+/* OutputSecurityParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteArray;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.ByteBuffer;
+
+import java.util.logging.Level;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+public class OutputSecurityParameters
+{
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+  private final Cipher cipher;
+  private final Mac mac;
+  private final Deflater deflater;
+  private final SessionImpl session;
+  private final CipherSuite suite;
+  private long sequence;
+
+  public OutputSecurityParameters (final Cipher cipher, final Mac mac,
+                                   final Deflater deflater, SessionImpl session,
+                                   CipherSuite suite)
+  {
+    this.cipher = cipher;
+    this.mac = mac;
+    this.deflater = deflater;
+    this.session = session;
+    this.suite = suite;
+    sequence = 0;
+  }
+
+  /**
+   * Encrypt a record, storing the result in the given output buffer.
+   *
+   * @return The number of bytes taken from the input, and the number stored
+   * into `output;' that is, the size of the encrypted fragment, plus the
+   * encoding for the record.
+   */
+  public int[] encrypt (final ByteBuffer[] input, int offset, int length,
+                        final ContentType contentType, final ByteBuffer output)
+    throws DataFormatException, IllegalBlockSizeException, ShortBufferException
+  {
+    if (offset < 0 || offset >= input.length
+        || length <= 0 || offset + length > input.length)
+      throw new IndexOutOfBoundsException();
+    
+    if (Debug.DEBUG)
+      for (int i = offset; i < offset+length; i++)
+        logger.logv(Component.SSL_RECORD_LAYER, "encrypting record [{0}]: {1}",
+                    i-offset, input[i]);
+    
+    int maclen = 0;
+    if (mac != null)
+      maclen = session.isTruncatedMac() ? 10 : mac.getMacLength ();
+
+    int ivlen = 0;
+    byte[] iv = null;
+    if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+        && !suite.isStreamCipher())
+      {
+        ivlen = cipher.getBlockSize();
+        iv = new byte[ivlen];
+        session.random().nextBytes(iv);
+      }
+        
+    int padaddlen = 0;
+    if (!suite.isStreamCipher()
+        && session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+      {
+        padaddlen = (session.random().nextInt(255 / cipher.getBlockSize())
+                     * cipher.getBlockSize());
+      }
+    
+    int fragmentLength = 0;
+    ByteBuffer[] fragments = null;
+    // Compress the content, if needed.
+    if (deflater != null)
+      {
+        ByteBufferOutputStream deflated = new ByteBufferOutputStream();
+
+        byte[] inbuf = new byte[1024];
+        byte[] outbuf = new byte[1024];
+        int written = 0;
+        
+        // Here we use the guarantee that the deflater won't increase the
+        // output size by more than 1K -- we resign ourselves to only deflate
+        // as much data as we have space for *uncompressed*, 
+        int limit = output.remaining() - (maclen + ivlen + padaddlen) - 1024;
+
+        for (int i = offset; i < length && written < limit; i++)
+          {
+            ByteBuffer in = input[i];
+            while (in.hasRemaining() && written < limit)
+              {
+                int l = Math.min(in.remaining(), inbuf.length);
+                l = Math.min(limit - written, l);
+                in.get(inbuf, 0, l);
+                deflater.setInput(inbuf, 0, l);
+                l = deflater.deflate(outbuf);
+                deflated.write(outbuf, 0, l);
+                written += l;
+              }
+          }
+        deflater.finish();
+        while (!deflater.finished())
+          {
+            int l = deflater.deflate(outbuf);
+            deflated.write(outbuf, 0, l);
+            written += l;
+          }
+        fragments = new ByteBuffer[] { deflated.buffer() };
+        fragmentLength = ((int) deflater.getBytesWritten()) + maclen + ivlen;
+        deflater.reset();
+        offset = 0;
+        length = 1;
+      }
+    else
+      {
+        int limit = output.remaining() - (maclen + ivlen + padaddlen);
+        fragments = input;
+        for (int i = offset; i < length && fragmentLength < limit; i++)
+          {
+            int l = Math.min(limit - fragmentLength, fragments[i].remaining());
+            fragmentLength += l;
+          }
+        fragmentLength += maclen + ivlen;
+      }
+
+    // Compute padding...
+    int padlen = 0;
+    byte[] pad = null;
+    if (!suite.isStreamCipher())
+      {
+        int bs = cipher.getBlockSize();
+        padlen = bs - (fragmentLength % bs);
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER,
+                      "framentLen:{0} padlen:{1} blocksize:{2}",
+                      fragmentLength, padlen, bs);
+        if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+          {
+            // TLS 1.0 and later uses a random amount of padding, up to
+            // 255 bytes. Each byte of the pad is equal to the padding
+            // length, minus one.
+            padlen += padaddlen;
+            while (padlen > 255)
+              padlen -= bs;
+            pad = new byte[padlen];
+            for (int i = 0; i < padlen; i++)
+              pad[i] = (byte) (padlen - 1);
+          }
+        else
+          {
+            // SSL 3 uses a pad only as large as the block size, but the
+            // pad may contain any values.
+            pad = new byte[padlen];
+            session.random().nextBytes(pad);
+            pad[padlen - 1] = (byte) (padlen - 1);
+          }
+        fragmentLength += pad.length;
+      }
+
+    // If there is a MAC, compute it.
+    byte[] macValue = null;
+    if (mac != null)
+      {
+        mac.update((byte) (sequence >>> 56));
+        mac.update((byte) (sequence >>> 48));
+        mac.update((byte) (sequence >>> 40));
+        mac.update((byte) (sequence >>> 32));
+        mac.update((byte) (sequence >>> 24));
+        mac.update((byte) (sequence >>> 16));
+        mac.update((byte) (sequence >>>  8));
+        mac.update((byte)  sequence);
+        mac.update((byte) contentType.getValue());
+        if (session.version != ProtocolVersion.SSL_3)
+          {
+            mac.update((byte) session.version.major ());
+            mac.update((byte) session.version.minor ());
+          }
+        int toWrite = fragmentLength - maclen - ivlen - padlen;
+        mac.update((byte) (toWrite >>> 8));
+        mac.update((byte)  toWrite);
+        int written = 0;
+        for (int i = offset; i < length && written < toWrite; i++)
+          {
+            ByteBuffer fragment = fragments[i].duplicate();
+            int l = Math.min(fragment.remaining(), toWrite - written);
+            fragment.limit(fragment.position() + l);
+            mac.update(fragment);
+          }
+        macValue = mac.doFinal();
+      }
+
+    Record outrecord = new Record(output);
+    outrecord.setContentType(contentType);
+    outrecord.setVersion(session.version);
+    outrecord.setLength(fragmentLength);
+    
+    int consumed = 0;
+    ByteBuffer outfragment = outrecord.fragment();
+
+    if (cipher != null)
+      {
+        if (iv != null)
+          cipher.update(ByteBuffer.wrap(iv), outfragment);
+        int toWrite = fragmentLength - maclen - ivlen - padlen;
+        for (int i = offset; i < offset + length && consumed < toWrite; i++)
+          {
+            ByteBuffer fragment = fragments[i].slice();
+            int l = Math.min(fragment.remaining(), toWrite - consumed);
+            fragment.limit(fragment.position() + l);
+            cipher.update(fragment, outfragment);
+            fragments[i].position(fragments[i].position() + l);
+            consumed += l;
+          }
+        if (macValue != null)
+          cipher.update(ByteBuffer.wrap(macValue), outfragment);
+        if (pad != null)
+          cipher.update(ByteBuffer.wrap(pad), outfragment);
+      }
+    else
+      {
+        // iv and pad are only used if we have a block cipher.
+        int toWrite = fragmentLength - maclen;
+        for (int i = offset; i < offset + length && consumed < toWrite; i++)
+          {
+            ByteBuffer fragment = fragments[i];
+            int l = Math.min(fragment.remaining(), toWrite - consumed);
+            fragment.limit(fragment.position() + l);
+            outfragment.put(fragment);
+            consumed += l;
+          }
+        if (macValue != null)
+          outfragment.put(macValue);
+      }
+      
+    // Advance the output buffer's position.
+    output.position(output.position() + outrecord.length() + 5);
+    sequence++;
+
+    return new int[] { consumed, fragmentLength + 5 };
+  }
+  
+  CipherSuite suite()
+  {
+    return suite;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,118 @@
+/* PreSharedKeyManagerFactory.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.PreSharedKeyManagerParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class PreSharedKeyManagerFactoryImpl
+  extends KeyManagerFactorySpi
+{
+  PreSharedKeyManagerParameters params;
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.KeyManagerFactorySpi#engineGetKeyManagers()
+   */
+  @Override protected KeyManager[] engineGetKeyManagers()
+  {
+    if (params == null)
+      throw new IllegalStateException("not initialized");
+    return new KeyManager[] { new Manager() };
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(javax.net.ssl.ManagerFactoryParameters)
+   */
+  @Override protected void engineInit(ManagerFactoryParameters params)
+    throws InvalidAlgorithmParameterException
+  {
+    if (!(params instanceof PreSharedKeyManagerParameters))
+      throw new InvalidAlgorithmParameterException("only supports gnu.javax.net.ssl.PreSharedKeyManagerParameters");
+    params = (PreSharedKeyManagerParameters) params;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(java.security.KeyStore, char[])
+   */
+  @Override protected void engineInit(KeyStore store, char[] passwd)
+    throws KeyStoreException, NoSuchAlgorithmException,
+           UnrecoverableKeyException
+  {
+    // XXX Could implement this.
+  }
+
+  class Manager implements PreSharedKeyManager
+  {
+    Manager()
+    {
+    }
+
+    /* (non-Javadoc)
+     * @see gnu.javax.net.ssl.PreSharedKeyManager#getKey(java.lang.String)
+     */
+    public SecretKey getKey(String name) throws KeyManagementException
+    {
+      return params.getKey(name);
+    }
+    
+    public String chooseIdentityHint()
+    {
+      Iterator<String> it = params.identities();
+      if (it.hasNext())
+        return it.next();
+      return null;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ProtocolVersion.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,201 @@
+/* ProtocolVersion.java -- An SSL version number.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public final class ProtocolVersion
+  implements Comparable<ProtocolVersion>, Constructed
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
+  public static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
+  public static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2);
+
+  private final int major;
+  private final int minor;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  private ProtocolVersion(int major, int minor)
+  {
+    this.major = major;
+    this.minor = minor;
+  }
+
+  // Class methods.
+  // -------------------------------------------------------------------------
+
+  public static ProtocolVersion read(InputStream in) throws IOException
+  {
+    int major = in.read() & 0xFF;
+    int minor = in.read() & 0xFF;
+    return getInstance(major, minor);
+  }
+
+  public static ProtocolVersion forName (final String name)
+  {
+    if (name.equalsIgnoreCase ("SSLv3"))
+      return SSL_3;
+    if (name.equalsIgnoreCase ("TLSv1"))
+      return TLS_1;
+    if (name.equalsIgnoreCase("TLSv1.1"))
+      return TLS_1_1;
+    throw new IllegalArgumentException ("unknown protocol name: " + name);
+  }
+
+  public static ProtocolVersion getInstance(final int major, final int minor)
+  {
+    if (major == 3)
+      {
+        switch (minor)
+          {
+          case 0: return SSL_3;
+          case 1: return TLS_1;
+          case 2: return TLS_1_1;
+          }
+      }
+    return new ProtocolVersion(major, minor);
+  }
+
+  public static ProtocolVersion getInstance (final short raw_value)
+  {
+    int major = raw_value >>> 8 & 0xFF;
+    int minor = raw_value & 0xFF;
+    return getInstance (major, minor);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    return 2;
+  }
+
+  public byte[] getEncoded()
+  {
+    return new byte[] {
+      (byte) major, (byte) minor
+    };
+  }
+
+  public int major()
+  {
+    return major;
+  }
+
+  public int minor()
+  {
+    return minor;
+  }
+
+  public int rawValue ()
+  {
+    return (major << 8) | minor;
+  }
+
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof ProtocolVersion))
+      {
+        return false;
+      }
+    return ((ProtocolVersion) o).major == this.major
+        && ((ProtocolVersion) o).minor == this.minor;
+  }
+
+  public int hashCode()
+  {
+    return major << 8 | minor;
+  }
+
+  public int compareTo(ProtocolVersion that)
+  {
+    if (major > that.major)
+      {
+        return 1;
+      }
+    else if (major < that.major)
+      {
+        return -1;
+      }
+
+    if (minor > that.minor)
+      {
+        return 1;
+      }
+    else if (minor < that.minor)
+      {
+        return -1;
+      }
+    return 0;
+  }
+
+  public String toString (String prefix)
+  {
+    return toString ();
+  }
+
+  public String toString()
+  {
+    if (this == SSL_3)
+      {
+        return "SSLv3";
+      }
+    else if (this == TLS_1)
+      {
+        return "TLSv1";
+      }
+    else if (this == TLS_1_1)
+      {
+        return "TLSv1.1";
+      }
+    else
+      {
+        return "Unsupported; major=" + major + " minor=" + minor;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Random.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,154 @@
+/* Random.java -- SSL Random structure.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL nonce.
+ *
+ * <pre>
+struct
+{
+  uint32 gmt_unix_time;
+  opaque random_bytes[28];
+} Random;
+ */
+public class Random implements Builder, Constructed
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  static final int RANDOM_LENGTH = 28;
+
+  private final ByteBuffer buffer;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public Random (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+
+  public Random copy()
+  {
+    ByteBuffer buffer = ByteBuffer.allocate(32);
+    buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
+    return new Random(buffer);
+  }
+
+  public int length()
+  {
+    return RANDOM_LENGTH + 4;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+  }
+
+  public int gmtUnixTime ()
+  {
+    return buffer.getInt(0);
+  }
+
+  public byte[] randomBytes()
+  {
+    byte[] buf = new byte[28];
+    buffer.position (4);
+    buffer.get (buf);
+    return buf;
+  }
+
+  public void setGmtUnixTime (final int gmtUnixTime)
+  {
+    buffer.putInt (0, gmtUnixTime);
+  }
+
+  public void setRandomBytes (final byte[] randomBytes)
+  {
+    setRandomBytes (randomBytes, 0);
+  }
+
+  public void setRandomBytes (final byte[] randomBytes, final int offset)
+  {
+    if (randomBytes.length - offset < RANDOM_LENGTH)
+      throw new IllegalArgumentException ("random value too short");
+    buffer.position (4);
+    buffer.put (randomBytes, offset, RANDOM_LENGTH);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println("struct {");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("  gmt_unix_time: ");
+    out.print (gmtUnixTime ());
+    out.println (";");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("  random_bytes:  ");
+    out.print (Util.toHexString (randomBytes (), ':'));
+    out.println (";");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("} Random;");
+    return str.toString();
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Record.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,198 @@
+/* Record.java -- A single SSL Record.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A SSL/TLS record structure. An SSL record is defined to be:
+ *
+ * <pre>
+struct
+{
+  {@link ContentType}     type;
+  {@link ProtocolVersion} version;
+  uint16          length;
+  opaque          fragment[TLSPlaintext.length];
+} TLSPlaintext;
+</pre>
+ */
+public class Record
+{
+  private final ByteBuffer buffer;
+
+  public Record (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+
+  // XXX remove
+  public ContentType getContentType ()
+  {
+    return contentType ();
+  }
+
+  /**
+   * Gets the content type field.
+   *
+   * @return The content type field.
+   */
+  public ContentType contentType ()
+  {
+    return ContentType.forInteger (buffer.get (0) & 0xFF);
+  }
+
+  /**
+   * Get the fragment content, storing it into <code>sink</code>.
+   *
+   * @param sink The sink for the fragment bytes.
+   * @return The number of bytes put into <code>sink</code>
+   */
+  public int fragment (final ByteBuffer sink)
+  {
+    int length = length ();
+    sink.put (((ByteBuffer) buffer.limit (5 + length).position (5)).slice ());
+    return length;
+  }
+
+  /**
+   * Returns the fragment field as a ByteBuffer. The returned buffer
+   * is shared with this object's underlying buffer, so it will share
+   * its attributes. For example, if the underlying buffer is
+   * read-only, the returned buffer will be read-only.
+   *
+   * @return The fragment buffer.
+   */
+  public ByteBuffer fragment ()
+  {
+    int length = length ();
+    return ((ByteBuffer) buffer.limit (5 + length).position (5)).slice ();
+  }
+
+  /**
+   * Gets the fragment length.
+   *
+   * @return The fragment length.
+   */
+  public int length ()
+  {
+    // XXX this is different behavior than we usually want: we return the
+    // length field, not the total length. We should consider changing this.
+    return buffer.getShort (3) & 0xFFFF;
+  }
+
+  /**
+   * Gets the protocol version field.
+   *
+   * @return The protocol version field.
+   */
+  public ProtocolVersion version ()
+  {
+    int major = buffer.get (1) & 0xFF;
+    int minor = buffer.get (2) & 0xFF;
+    return ProtocolVersion.getInstance (major, minor);
+  }
+
+  /**
+   * Sets the content type field.
+   *
+   * @param type The content type.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   * @throws NullPointerException If <i>type</i> is <code>null</code>.
+   */
+  public void setContentType (final ContentType type)
+  {
+    buffer.put (0, (byte) type.getValue ());
+  }
+
+  /**
+   * Sets the fragment length.
+   *
+   * @param length The fragment length.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   * @throws IllegalArgumentException If the length is not between 0
+   * and 16384, inclusive.
+   */
+  public void setLength (final int length)
+  {
+    if (length < 0 || length > 16384)
+      throw new IllegalArgumentException ("length " + length + " out of range; "
+                                          + "must be between 0 and 16384");
+    buffer.putShort (3, (short) length);
+  }
+
+  /**
+   * Sets the protocol version field.
+   *
+   * @param version The protocol version.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   * @throws NullPointerException If <i>version</i> is <code>null</code>.
+   */
+  public void setVersion (final ProtocolVersion version)
+  {
+    buffer.put (1, (byte) version.major ()).put (2, (byte) version.minor ());
+  }
+
+  public String toString ()
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    out.println ("struct {");
+    out.print ("  type:    ");
+    out.print (contentType ());
+    out.println (";");
+    out.print ("  version: ");
+    out.print (version ());
+    out.println (";");
+    out.print("  length: ");
+    out.print(length());
+    out.println(";");
+    out.println ("  fragment {");
+    out.print (Util.hexDump (fragment (), "    "));
+    out.println ("  };");
+    out.print ("} Record;");
+    return str.toString ();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,225 @@
+/* SRPTrustManagerFactory.java -- trust manager for SRP.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.Security;
+
+import java.util.HashMap;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator;
+import gnu.javax.crypto.sasl.srp.PasswordFile;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import gnu.javax.net.ssl.SRPManagerParameters;
+import gnu.javax.net.ssl.SRPTrustManager;
+
+/**
+ * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory}
+ * engine for the ``SRP'' algorithm. You must initialize instances of this
+ * algorithm with {@link SRPManagerParameters}.
+ */
+public class SRPTrustManagerFactory extends TrustManagerFactorySpi
+{
+
+  // Field.
+  // -------------------------------------------------------------------------
+
+  private Manager current;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public SRPTrustManagerFactory()
+  {
+    super();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected TrustManager[] engineGetTrustManagers()
+  {
+    if (current == null)
+      throw new IllegalStateException("not initialized");
+    return new TrustManager[] { current };
+  }
+
+  protected void engineInit(KeyStore ks)
+  {
+    throw new IllegalArgumentException("only accepts SRPManagerParameters");
+  }
+
+  protected void engineInit(ManagerFactoryParameters params)
+    throws InvalidAlgorithmParameterException
+  {
+    if (params == null)
+      {
+        try
+          {
+            String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file");
+            if (srpPasswd == null)
+              {
+                current = new Manager(new PasswordFile());
+                return;
+              }
+            String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2");
+            if (srpPasswd2 == null)
+              srpPasswd2 = srpPasswd + "2";
+            String srpConfig = Util.getSecurityProperty("jessie.srp.config");
+            if (srpConfig == null)
+              srpConfig = srpPasswd + ".conf";
+            current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig));
+            return;
+          }
+        catch (IOException ioe)
+          {
+            throw new InvalidAlgorithmParameterException("default initialization failed: "
+                                                         + ioe.toString());
+          }
+      }
+    if (params instanceof SRPManagerParameters)
+      {
+        current = new Manager(((SRPManagerParameters) params).getPasswordFile());
+        return;
+      }
+    throw new InvalidAlgorithmParameterException();
+  }
+
+  // Inner class.
+  // -------------------------------------------------------------------------
+
+  private class Manager implements SRPTrustManager
+  {
+
+    // Field.
+    // -----------------------------------------------------------------------
+
+    private final PasswordFile file;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    Manager(PasswordFile file)
+    {
+      this.file = file;
+    }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public boolean contains(String user)
+    {
+      try
+        {
+          return file.contains(user);
+        }
+      catch (IOException ioe) { }
+      return false;
+    }
+
+    public KeyPair getKeyPair(String user)
+    {
+      try
+        {
+          if (file.contains(user))
+            {
+              SRP srp = SRP.instance("SHA");
+              String[] ent = file.lookup(user, "SHA");
+              String[] cnf = file.lookupConfig(ent[2]);
+              BigInteger v, N, g;
+              v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0]));
+              N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0]));
+              g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1]));
+              IKeyPairGenerator kpg = new SRPKeyPairGenerator();
+              HashMap attr = new HashMap();
+              attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+              attr.put(SRPKeyPairGenerator.GENERATOR, g);
+              attr.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+              kpg.setup(attr);
+              return kpg.generate();
+            }
+        }
+      catch (IOException ioe) { }
+      return null;
+    }
+
+    public byte[] getSalt(String user)
+    {
+      try
+        {
+          if (file.contains(user))
+            {
+              return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]);
+            }
+        }
+      catch (IOException ioe) { }
+      return null;
+    }
+
+    public BigInteger getVerifier(String user)
+    {
+      try
+        {
+          if (file.contains(user))
+            {
+              return new BigInteger(1,
+                gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0]));
+            }
+        }
+      catch (IOException ioe) { }
+      return null;
+    }
+
+    public PasswordFile getPasswordFile()
+    {
+      return file;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLContextImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,315 @@
+/* SSLContextImpl.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.SRPTrustManager;
+
+import java.security.AccessController;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Our implementation of {@link SSLContextSpi}.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class SSLContextImpl extends SSLContextSpi
+{
+  AbstractSessionContext serverContext;
+  AbstractSessionContext clientContext;
+  
+  PreSharedKeyManager pskManager;
+  X509ExtendedKeyManager keyManager;
+  X509TrustManager trustManager;
+  SRPTrustManager srpTrustManager;
+  SecureRandom random;
+
+  public SSLContextImpl()
+  {
+  }
+  
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine()
+   */
+  protected @Override SSLEngine engineCreateSSLEngine()
+  {
+    return engineCreateSSLEngine(null, -1);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(java.lang.String, int)
+   */
+  protected @Override SSLEngine engineCreateSSLEngine(String host, int port)
+  {
+    return new SSLEngineImpl(this, host, port);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineGetClientSessionContext()
+   */
+  protected @Override synchronized SSLSessionContext engineGetClientSessionContext()
+  {
+    if (clientContext == null)
+      {
+        try
+          {
+            clientContext = AbstractSessionContext.newInstance();
+          }
+        catch (SSLException ssle)
+          {
+            // XXX Ignore?
+          }
+      }
+    return clientContext;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineGetServerSessionContext()
+   */
+  protected @Override synchronized SSLSessionContext engineGetServerSessionContext()
+  {
+    if (serverContext == null)
+      {
+        try
+          {
+            serverContext = AbstractSessionContext.newInstance();
+          }
+        catch (SSLException ssle)
+          {
+            // XXX Ignore?
+          }
+      }
+    return serverContext;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineGetServerSocketFactory()
+   */
+  protected @Override SSLServerSocketFactory engineGetServerSocketFactory()
+  {
+    return new SSLServerSocketFactoryImpl(this);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineGetSocketFactory()
+   */
+  protected @Override SSLSocketFactory engineGetSocketFactory()
+  {
+    return new SSLSocketFactoryImpl(this);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLContextSpi#engineInit(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)
+   */
+  protected @Override void engineInit(KeyManager[] keyManagers,
+                                      TrustManager[] trustManagers,
+                                      SecureRandom random)
+    throws KeyManagementException
+  {
+    keyManager = null;
+    trustManager = null;
+    srpTrustManager = null;
+    if (keyManagers != null)
+      {
+        for (int i = 0; i < keyManagers.length; i++)
+          {
+            if ((keyManagers[i] instanceof X509ExtendedKeyManager)
+                && keyManager == null)
+              keyManager = (X509ExtendedKeyManager) keyManagers[i];
+            if (keyManagers[i] instanceof PreSharedKeyManager
+                && pskManager == null)
+              pskManager = (PreSharedKeyManager) keyManagers[i];
+          }
+      }
+    if (keyManager == null)
+      keyManager = defaultKeyManager();
+    if (trustManagers != null)
+      {
+        for (int i = 0; i < trustManagers.length; i++)
+          {
+            if (trustManagers[i] instanceof X509TrustManager)
+              {
+                if (trustManager == null)
+                  trustManager = (X509TrustManager) trustManagers[i];
+              }
+            else if (trustManagers[i] instanceof SRPTrustManager)
+              {
+                if (srpTrustManager == null)
+                  srpTrustManager = (SRPTrustManager) trustManagers[i];
+              }
+          }
+      }
+    if (trustManager == null && srpTrustManager == null)
+      {
+        trustManager = defaultTrustManager();
+      }
+    if (random != null)
+      {
+        this.random = random;
+      }
+    else
+      {
+        this.random = defaultRandom();
+      }
+  }
+  
+  /**
+   * Create and return a default key manager. The default is the JessieX509
+   * algorithm, loaded from either the jssecerts file, or the cacerts file.
+   * 
+   * @return The default key manager instance.
+   * @throws KeyManagementException If the instance cannot be created.
+   */
+  private X509ExtendedKeyManager defaultKeyManager() throws KeyManagementException
+  {
+    KeyManagerFactory fact = null;
+    try
+      {
+        fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new KeyManagementException(nsae);
+      }
+    catch (NoSuchProviderException nspe)
+      {
+        throw new KeyManagementException(nspe);
+      }
+    try
+      {
+        fact.init(null, null);
+        return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+      }
+    catch (NoSuchAlgorithmException nsae) { }
+    catch (KeyStoreException kse) { }
+    catch (UnrecoverableKeyException uke) { }
+    catch (IllegalStateException ise) { }
+
+    try
+      {
+        fact.init(new NullManagerParameters());
+        return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+      }
+    catch (Exception shouldNotHappen)
+      {
+        throw new Error(shouldNotHappen.toString());
+      }
+  }
+
+  /**
+   * Create and return a default trust manager. The default is the JessieX509
+   * algorithm, loaded from either the jssecerts file, or the cacerts file.
+   * 
+   * @return The default trust manager instance.
+   * @throws KeyManagementException If the instance cannot be created.
+   */
+  private X509TrustManager defaultTrustManager() throws KeyManagementException
+  {
+    try
+      {
+        TrustManagerFactory fact =
+          TrustManagerFactory.getInstance("JessieX509", "Jessie");
+        fact.init((KeyStore) null);
+        return (X509TrustManager) fact.getTrustManagers()[0];
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new KeyManagementException(nsae);
+      }
+    catch (NoSuchProviderException nspe)
+      {
+        throw new KeyManagementException(nspe);
+      }
+    catch (KeyStoreException kse)
+      {
+        throw new KeyManagementException(kse);
+      }
+  }
+
+  /**
+   * Create a default secure PRNG. This is defined as either the algorithm
+   * given in the <code>gnu.javax.net.ssl.secureRandom</code> security
+   * property, or Fortuna if that property is not set. If none of these
+   * algorithms can be found, and instance created with the SecureRandom
+   * constructor is returned.
+   * 
+   * @return The default secure PRNG instance.
+   */
+  private SecureRandom defaultRandom()
+  {
+    GetSecurityPropertyAction gspa
+      = new GetSecurityPropertyAction("gnu.javax.net.ssl.secureRandom");
+    String alg = AccessController.doPrivileged(gspa);
+    if (alg == null)
+      alg = "Fortuna";
+    SecureRandom rand = null;
+    try
+      {
+        rand = SecureRandom.getInstance(alg);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        rand = new SecureRandom();
+      }
+
+    return rand;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLEngineImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,842 @@
+/* SSLEngineImpl.java -- implementation of SSLEngine.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import gnu.java.security.util.ByteBufferOutputStream;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SSLRecordHandler;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.DataFormatException;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+public final class SSLEngineImpl extends SSLEngine
+{
+  final SSLContextImpl contextImpl;
+  private SSLRecordHandler[] handlers;
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+  private SessionImpl session;
+  private InputSecurityParameters insec;
+  private OutputSecurityParameters outsec;
+  private boolean inClosed;
+  private boolean outClosed;
+  private boolean createSessions;
+  private boolean needClientAuth;
+  private boolean wantClientAuth;
+  private boolean initialHandshakeDone;
+  private AbstractHandshake handshake;
+  private Alert lastAlert;
+  private SSLEngineResult.HandshakeStatus handshakeStatus;
+  private boolean changeCipherSpec;
+
+  private String[] enabledSuites;
+  private String[] enabledProtocols;
+  
+  /**
+   * We can receive any message chunked across multiple records,
+   * including alerts, even though all alert messages are only two
+   * bytes long. Handshake messages are de-chunked in the handshake
+   * handler, change-cipher-spec messages are always empty, and we
+   * don't care about chunking of application messages.
+   *
+   * This buffer will hold the incomplete alert that we receive, if
+   * any.
+   */
+  private final ByteBuffer alertBuffer;
+
+  private Mode mode;
+
+  private enum Mode { SERVER, CLIENT }
+  
+  SSLEngineImpl (SSLContextImpl contextImpl, String host, int port)
+  {
+    super(host, port);
+    this.contextImpl = contextImpl;
+    handlers = new SSLRecordHandler[256];
+    session = new SessionImpl();
+    session.suite = CipherSuite.TLS_NULL_WITH_NULL_NULL;
+    session.version = ProtocolVersion.TLS_1_1;
+    byte[] sid = new byte[32];
+    contextImpl.random.nextBytes(sid);
+    session.setId(new Session.ID(sid));
+    session.setRandom(contextImpl.random);
+    
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_RECORD_LAYER, "generated session ID {0} with random {1}",
+                  session.id(), contextImpl.random);
+    
+    // Begin with no encryption.
+    insec = new InputSecurityParameters (null, null, null, session,
+                                         CipherSuite.TLS_NULL_WITH_NULL_NULL);
+    outsec = new OutputSecurityParameters (null, null, null, session,
+                                           CipherSuite.TLS_NULL_WITH_NULL_NULL);
+    inClosed = false;
+    outClosed = false;
+    needClientAuth = false;
+    wantClientAuth = false;
+    createSessions = true;
+    initialHandshakeDone = false;
+    alertBuffer = ByteBuffer.wrap (new byte[2]);
+    mode = null;
+    lastAlert = null;
+    handshakeStatus = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+    changeCipherSpec = false;
+    
+    // Set up default protocols and suites.
+    enabledProtocols = new String[] {
+      ProtocolVersion.TLS_1_1.toString(),
+      ProtocolVersion.TLS_1.toString(),
+      ProtocolVersion.SSL_3.toString()
+    };
+    enabledSuites = defaultSuites();
+  }
+  
+  static String[] defaultSuites()
+  {
+    return new String[] {
+      CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_RC4_128_MD5.toString(),
+      CipherSuite.TLS_RSA_WITH_RC4_128_SHA.toString(),
+      CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_DES_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+      CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5.toString(),
+      CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+      CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+      CipherSuite.TLS_RSA_WITH_NULL_MD5.toString(),
+      CipherSuite.TLS_RSA_WITH_NULL_SHA.toString()
+    };
+  }
+
+  // XXX implement?
+  /*public void registerHandler (final int contentType,
+                               SSLRecordHandler handler)
+    throws SSLException
+  {
+    if (type.equals (ContentType.CHANGE_CIPHER_SPEC)
+        || type.equals (ContentType.ALERT)
+        || type.equals (ContentType.HANDSHAKE)
+        || type.equals (ContentType.APPLICATION_DATA))
+      throw new SSLException ("can't override handler for content type " + type);
+    int i = type.getValue ();
+    if (i < 0 || i > 255)
+      throw new SSLException ("illegal content type: " + type);
+    handlers[i] = handler;
+  }*/
+
+  @Override
+  public void beginHandshake () throws SSLException
+  {
+    if (Debug.DEBUG)
+      logger.log(Component.SSL_HANDSHAKE, "{0} handshake begins", mode);
+
+    if (mode == null)
+      throw new IllegalStateException("setUseClientMode was never used");
+    
+    switch (mode)
+      {
+      case SERVER:
+        if (getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
+          throw new SSLException("handshake already in progress");
+        try
+          {
+            handshake = new ServerHandshake(initialHandshakeDone, this);
+          }
+        catch (NoSuchAlgorithmException nsae)
+          {
+            throw new SSLException(nsae);
+          }
+        break;
+        
+      case CLIENT:
+        try
+          {
+            handshake = new ClientHandshake(this);
+          }
+        catch (NoSuchAlgorithmException nsae)
+          {
+            throw new SSLException(nsae);
+          }
+        break;
+      }
+  }
+
+  @Override
+  public void closeInbound()
+  {
+    inClosed = true;
+  }
+
+  @Override
+  public void closeOutbound()
+  {
+    lastAlert = new Alert(Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
+  }
+  
+  @Override
+  public Runnable getDelegatedTask()
+  {
+    if (handshake == null)
+      return null;
+    return handshake.getTask();
+  }
+  
+  @Override
+  public String[] getEnabledCipherSuites()
+  {
+    return (String[]) enabledSuites.clone();
+  }
+  
+  @Override
+  public String[] getEnabledProtocols()
+  {
+    return (String[]) enabledProtocols.clone();
+  }
+
+  @Override
+  public boolean getEnableSessionCreation()
+  {
+    return createSessions;
+  }
+  
+  @Override
+  public HandshakeStatus getHandshakeStatus()
+  {
+    if (handshake == null)
+      return HandshakeStatus.NOT_HANDSHAKING;
+    return handshake.status();
+  }
+  
+  @Override
+  public boolean getNeedClientAuth()
+  {
+    return needClientAuth;
+  }
+  
+  @Override
+  public SSLSession getSession()
+  {
+    return session;
+  }
+  
+  @Override
+  public boolean getUseClientMode ()
+  {
+    return (mode == Mode.CLIENT);
+  }
+  
+  @Override
+  public boolean getWantClientAuth()
+  {
+    return wantClientAuth;
+  }
+  
+  @Override
+  public boolean isInboundDone()
+  {
+    return inClosed;
+  }
+  
+  @Override
+  public boolean isOutboundDone()
+  {
+    return outClosed;
+  }
+  
+  @Override
+  public void setEnableSessionCreation(final boolean createSessions)
+  {
+    this.createSessions = createSessions;
+  }
+
+  @Override
+  public void setEnabledCipherSuites(final String[] suites)
+  {
+    if (suites.length == 0)
+      throw new IllegalArgumentException("need at least one suite");
+    enabledSuites = (String[]) suites.clone();
+  }
+
+  @Override
+  public void setEnabledProtocols(final String[] protocols)
+  {
+    if (protocols.length == 0)
+      throw new IllegalArgumentException("need at least one protocol");
+    enabledProtocols = (String[]) protocols.clone();
+  }
+  
+  @Override
+  public String[] getSupportedCipherSuites()
+  {
+    // XXX if we ever want to support "pluggable" cipher suites, we'll need
+    // to figure this out.
+    
+    return CipherSuite.availableSuiteNames().toArray(new String[0]);
+  }
+  
+  @Override
+  public String[] getSupportedProtocols()
+  {
+    return new String[] { ProtocolVersion.SSL_3.toString(),
+                          ProtocolVersion.TLS_1.toString(),
+                          ProtocolVersion.TLS_1_1.toString() };
+  }
+
+  @Override
+  public void setNeedClientAuth(final boolean needClientAuth)
+  {
+    this.needClientAuth = needClientAuth;
+  }
+  
+  @Override
+  public void setUseClientMode (final boolean clientMode)
+  {
+    if (clientMode)
+      mode = Mode.CLIENT;
+    else
+      mode = Mode.SERVER;
+  }
+  
+  public @Override void setWantClientAuth(final boolean wantClientAuth)
+  {
+    this.wantClientAuth = wantClientAuth;
+  }
+
+  public @Override SSLEngineResult unwrap (final ByteBuffer source,
+                                           final ByteBuffer[] sinks,
+                                           final int offset, final int length)
+    throws SSLException
+  {
+    if (mode == null)
+      throw new IllegalStateException ("setUseClientMode was never called");
+
+    if (inClosed)
+      return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                                 handshakeStatus, 0, 0);
+    
+    if (source.remaining() < 5)
+      {
+        return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
+                                   handshakeStatus, 0, 0);
+      }
+    
+    Record record = null;
+    boolean helloV2 = false;
+
+    // XXX: messages may be chunked across multiple records; does this
+    // include the SSLv2 message? I don't think it does, but we should
+    // make sure.
+    if (!getUseClientMode() && (source.get(source.position()) & 0x80) == 0x80)
+      {
+        if (handshake == null)
+          beginHandshake();
+        int hellolen = source.getShort(source.position()) & 0x7FFF;
+        this.handshake.handleV2Hello(source.slice());
+        if (!insec.cipherSuite().equals (CipherSuite.TLS_NULL_WITH_NULL_NULL))
+          throw new SSLException ("received SSLv2 client hello in encrypted "
+                                  + "session; this is invalid.");
+        if (Debug.DEBUG)
+          logger.log (Component.SSL_RECORD_LAYER,
+                      "converting SSLv2 client hello to version 3 hello");
+        
+        source.getShort(); // skip length
+        ClientHelloV2 v2 = new ClientHelloV2(source.slice());
+        
+        if (Debug.DEBUG)
+          logger.log(Component.SSL_RECORD_LAYER, "v2 hello: {0}", v2);
+        
+        List<CipherSuite> suites = v2.cipherSpecs();
+        
+        ClientHelloBuilder hello = new ClientHelloBuilder();
+        hello.setVersion(v2.version ());
+
+        Random random = hello.random();
+        byte[] challenge = v2.challenge();
+        if (challenge.length < 32)
+          {
+            byte[] b = new byte[32];
+            System.arraycopy(challenge, 0, b, b.length - challenge.length,
+                             challenge.length);
+            challenge = b;
+          }
+        random.setGmtUnixTime((challenge[0] & 0xFF) << 24
+                              | (challenge[1] & 0xFF) << 16
+                              | (challenge[2] & 0xFF) <<  8
+                              | (challenge[3] & 0xFF));
+        random.setRandomBytes(challenge, 4);
+
+        byte[] sessionId = v2.sessionId();
+        hello.setSessionId(sessionId, 0, sessionId.length);
+        hello.setCipherSuites(suites);
+        ArrayList<CompressionMethod> comps = new ArrayList<CompressionMethod>(1);
+        comps.add(CompressionMethod.NULL);
+        hello.setCompressionMethods(comps);
+
+        record = new Record(ByteBuffer.allocate(hello.length() + 9));
+        record.setContentType(ContentType.HANDSHAKE);
+        record.setVersion(v2.version());
+        record.setLength(hello.length() + 4);
+        
+        Handshake handshake = new Handshake(record.fragment());
+        handshake.setLength(hello.length());
+        handshake.setType(Handshake.Type.CLIENT_HELLO);
+        
+        handshake.bodyBuffer().put(hello.buffer());
+        source.position(source.position() + hellolen);
+        helloV2 = true;
+      }
+    else
+      record = new Record(source);
+    
+    ContentType type = record.contentType ();
+    
+    if (Debug.DEBUG)
+      logger.log(Component.SSL_RECORD_LAYER, "input record:\n{0}", record);
+    
+    if (record.length() > session.getPacketBufferSize() - 5)
+      {
+        lastAlert = new Alert(Alert.Level.FATAL,
+                              Alert.Description.RECORD_OVERFLOW);
+        throw new AlertException(lastAlert);
+      }
+    
+    ByteBufferOutputStream sysMsg = null;    
+    ByteBuffer msg = null;
+
+    int produced = 0;
+    try
+      {
+        // Application data will get decrypted directly into the user's
+        // output buffers.
+        if (record.contentType() == ContentType.APPLICATION_DATA)
+          produced = insec.decrypt(record, sinks, offset, length);
+        else
+          {
+            if (insec.cipherSuite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+              msg = record.fragment();
+            else
+              {
+                sysMsg = new ByteBufferOutputStream();
+                insec.decrypt(record, sysMsg);
+              }
+          }
+        
+        // Advance the input buffer past the record we just read.
+        if (!helloV2)
+          source.position(source.position() + record.length() + 5);
+      }
+    catch (BufferOverflowException boe)
+      {
+        // We throw this if the output buffers are not large enough; signal
+        // the caller about this.
+        logger.log(Component.SSL_RECORD_LAYER, "buffer overflow when decrypting", boe);
+        return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
+                                   handshakeStatus, 0, 0);
+      }
+    catch (IllegalBlockSizeException ibse)
+      {
+        lastAlert = new Alert(Alert.Level.FATAL,
+                              Alert.Description.BAD_RECORD_MAC);
+        throw new AlertException(lastAlert, ibse);
+      }
+    catch (DataFormatException dfe)
+      {
+        lastAlert = new Alert(Alert.Level.FATAL,
+                              Alert.Description.DECOMPRESSION_FAILURE);
+        throw new AlertException(lastAlert, dfe);
+      }
+    catch (MacException me)
+      {
+        lastAlert = new Alert(Alert.Level.FATAL,
+                              Alert.Description.BAD_RECORD_MAC);
+        throw new AlertException(lastAlert, me);
+      }
+    catch (ShortBufferException sbe)
+      {
+        // We've messed up if this happens.
+        lastAlert = new Alert(Alert.Level.FATAL,
+                              Alert.Description.INTERNAL_ERROR);
+        throw new AlertException(lastAlert, sbe);
+      }
+
+    SSLEngineResult result = null;
+    
+    // If we need to handle the output here, do it. Otherwise, the output
+    // has been stored in the supplied output buffers.
+    if (sysMsg != null)
+      {
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "sysmessage {0}", sysMsg);
+        msg = sysMsg.buffer();
+      }
+    
+    if (type == ContentType.CHANGE_CIPHER_SPEC)
+      {
+        // We *may* get a partial message, even though the message is only
+        // one byte long.
+        if (msg.remaining() == 0)
+          {
+            result = new SSLEngineResult (SSLEngineResult.Status.OK,
+                                          handshakeStatus,
+                                          record.length() + 5, 0);
+          }
+        else
+          {
+            byte b = msg.get();
+            if (b != 1)
+              throw new SSLException ("unknown ChangeCipherSpec value: " + (b & 0xFF));
+            InputSecurityParameters params = handshake.getInputParams();
+            logger.log (Component.SSL_RECORD_LAYER,
+                        "switching to input security parameters {0}",
+                        params.cipherSuite());
+            insec = params;
+            result = new SSLEngineResult (SSLEngineResult.Status.OK,
+                                          handshakeStatus,
+                                          record.length() + 5, 0);
+          }
+      }
+    else if (type == ContentType.ALERT)
+      {
+        int len = 0;
+        if (alertBuffer.position() > 0)
+          {
+            alertBuffer.put(msg.get());
+            len = 1;
+          }
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}",
+                      Util.wrapBuffer(msg));
+        len += msg.remaining() / 2;
+        Alert[] alerts = new Alert[len];
+        int i = 0;
+        if (alertBuffer.position() > 0)
+          {
+            alertBuffer.flip();
+            alerts[0] = new Alert(alertBuffer);
+            i++;
+          }
+        while (i < alerts.length)
+          {
+            alerts[i++] = new Alert(msg.duplicate());
+            msg.position(msg.position() + 2);
+          }
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length);
+
+        for (i = 0; i < alerts.length; i++)
+          {
+            if (alerts[i].level() == Alert.Level.FATAL)
+              throw new AlertException(alerts[i], false);
+            if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY)
+              logger.log(java.util.logging.Level.WARNING,
+                         "received alert: {0}", alerts[i]);
+            if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY)
+              inClosed = true;
+          }
+
+        if (msg.hasRemaining())
+          alertBuffer.position(0).limit(2);
+
+        result = new SSLEngineResult (SSLEngineResult.Status.OK,
+                                      handshakeStatus,
+                                      record.length() + 5, 0);
+      }
+    else if (type == ContentType.HANDSHAKE)
+      {
+        if (handshake == null)
+          beginHandshake();
+        try
+          {
+            handshakeStatus = handshake.handleInput(msg);
+          }
+        catch (AlertException ae)
+          {
+            lastAlert = ae.alert();
+            return new SSLEngineResult(SSLEngineResult.Status.OK,
+                                       SSLEngineResult.HandshakeStatus.NEED_WRAP,
+                                       0, 0);
+          }
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", handshakeStatus);
+        result = new SSLEngineResult(SSLEngineResult.Status.OK,
+                                     handshakeStatus,
+                                     record.length() + 5,
+                                     0);
+        if (handshakeStatus == HandshakeStatus.FINISHED)
+          {
+            handshake = null;
+            handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+          }
+      }
+    else if (type == ContentType.APPLICATION_DATA)
+      {
+        // Do nothing more; the application data has been put into
+        // the output buffers.
+        result = new SSLEngineResult(SSLEngineResult.Status.OK,
+                                     handshakeStatus,
+                                     record.length() + 5,
+                                     produced);
+      }
+    else
+      {
+        SSLRecordHandler handler = handlers[type.getValue()];
+        if (handler != null)
+          {
+            result = new SSLEngineResult(SSLEngineResult.Status.OK,
+                                         handshakeStatus,
+                                         record.length() + 5,
+                                         0);
+          }
+        else
+          throw new SSLException ("unknown content type: " + type);
+      }
+
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_RECORD_LAYER, "return result: {0}", result);
+    
+    return result;
+  }
+
+  public @Override SSLEngineResult wrap (ByteBuffer[] sources, int offset, int length,
+                                         ByteBuffer sink)
+    throws SSLException
+  {
+    if (mode == null)
+      throw new IllegalStateException ("setUseClientMode was never called");
+
+    if (outClosed)
+      return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                                 handshakeStatus, 0, 0);
+    
+    ContentType type = null;
+    ByteBuffer sysMessage = null;
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_RECORD_LAYER, "wrap {0} {1} {2} {3} / {4}",
+                  sources, offset, length, sink, getHandshakeStatus());
+    if (lastAlert != null)
+      {
+        type = ContentType.ALERT;
+        sysMessage = ByteBuffer.allocate(2);
+        Alert alert = new Alert(sysMessage);
+        alert.setDescription(lastAlert.description());
+        alert.setLevel(lastAlert.level());
+        if (lastAlert.description() == Alert.Description.CLOSE_NOTIFY)
+          outClosed = true;
+      }
+    else if (changeCipherSpec)
+      {
+        type = ContentType.CHANGE_CIPHER_SPEC;
+        sysMessage = ByteBuffer.allocate(1);
+        sysMessage.put(0, (byte) 1);
+      }
+    else if (getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
+      {
+        // If we are not encrypting, optimize the handshake to fill
+        // the buffer directly.
+        if (outsec.suite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+          {
+            int orig = sink.position();
+            sink.order(ByteOrder.BIG_ENDIAN);
+            sink.put((byte) ContentType.HANDSHAKE.getValue());
+            sink.putShort((short) session.version.rawValue());
+            sink.putShort((short) 0);
+            handshakeStatus = handshake.handleOutput(sink);
+            int produced = sink.position() - orig;
+            sink.putShort(orig + 3, (short) (produced - 5));
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+                          new Record((ByteBuffer) sink.duplicate().position(orig)));
+            SSLEngineResult result = new SSLEngineResult(SSLEngineResult.Status.OK,
+                                                         handshakeStatus, 0, produced);
+            
+            // Note, this will only happen if we transition from
+            // TLS_NULL_WITH_NULL_NULL *to* TLS_NULL_WITH_NULL_NULL, which
+            // doesn't make a lot of sense, but we support it anyway.
+            if (handshakeStatus == HandshakeStatus.FINISHED)
+              {
+                handshake = null; // finished with it.
+                handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+              }
+            return result;
+          }
+       
+        // Rough guideline; XXX.
+        sysMessage = ByteBuffer.allocate(sink.remaining() - 2048);
+        type = ContentType.HANDSHAKE;
+        try
+          {
+            handshakeStatus = handshake.handleOutput(sysMessage);
+          }
+        catch (AlertException ae)
+          {
+            lastAlert = ae.alert();
+            return new SSLEngineResult(Status.OK,
+                                       HandshakeStatus.NEED_WRAP, 0, 0);
+          }
+        sysMessage.flip();
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}",
+                      handshakeStatus);
+      }
+
+    int produced = 0;
+    int consumed = 0;
+    
+    try
+      {
+        int orig = sink.position();
+        int[] inout = null;
+        if (sysMessage != null)
+          {
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_RECORD_LAYER, "encrypt system message {0} to {1}", sysMessage, sink);
+            inout = outsec.encrypt(new ByteBuffer[] { sysMessage }, 0, 1,
+                                   type, sink);
+            produced = inout[1];
+          }
+        else
+          {
+            inout = outsec.encrypt(sources, offset, length,
+                                   ContentType.APPLICATION_DATA, sink);
+            consumed = inout[0];
+            produced = inout[1];
+          }
+        
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+                      new Record((ByteBuffer) sink.duplicate().position(orig).limit(produced)));
+      }
+    catch (ShortBufferException sbe)
+      {
+        // We don't expect this to happen, except for bugs; signal an
+        // internal error.
+        lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+        return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+      }
+    catch (IllegalBlockSizeException ibse)
+      {
+        // We don't expect this to happen, except for bugs; signal an
+        // internal error.
+        lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+        return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+      }
+    catch (DataFormatException dfe)
+      {
+        // We don't expect this to happen; signal an internal error.
+        lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+        return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+      }
+    
+    if (lastAlert != null && lastAlert.level() == Alert.Level.FATAL)
+      {
+        AlertException ae = new AlertException(lastAlert);
+        lastAlert = null;
+        throw ae;
+      }
+    
+    if (changeCipherSpec)
+      {
+        outsec = handshake.getOutputParams();
+        changeCipherSpec = false;
+      }
+    SSLEngineResult result
+      = new SSLEngineResult(outClosed ? SSLEngineResult.Status.CLOSED
+                                      : SSLEngineResult.Status.OK,
+                            handshakeStatus, consumed, produced);
+    if (handshakeStatus == HandshakeStatus.FINISHED)
+      {
+        handshake = null; // done with it.
+        handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+      }
+    return result;
+  }
+
+  // Package-private methods.
+
+  SessionImpl session ()
+  {
+    return session;
+  }
+  
+  void setSession(SessionImpl session)
+  {
+    this.session = session;
+  }
+  
+  void changeCipherSpec()
+  {
+    changeCipherSpec = true;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLHMac.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,158 @@
+/* SSLHMac.java -- SSLv3's MAC algorithm.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.mac.IMac;
+
+/**
+ * The MAC function in SSLv3. This mac is defined as:
+ *
+ * <pre>
+ * hash(MAC_write_secret, pad_2 +
+ *      hash(MAC_write_secret + pad_1 + data));</pre>
+ *
+ * <p><tt>hash</tt> is e.g. MD5 or SHA-1, <tt>pad_1</tt> is the value
+ * 0x36 48 times for MD5 and 40 times for SHA-1, and <tt>pad_2</tt> is
+ * the value 0x5c repeated similarly.
+ */
+class SSLHMac implements IMac, Cloneable
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  static final byte PAD1 = 0x36;
+  static final byte PAD2 = 0x5c;
+
+  protected IMessageDigest md;
+  protected byte[] key;
+  protected final byte[] pad1, pad2;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  SSLHMac(String mdName)
+  {
+    super();
+    this.md = HashFactory.getInstance(mdName);
+    if (mdName.equalsIgnoreCase("MD5"))
+      {
+        pad1 = new byte[48];
+        pad2 = new byte[48];
+      }
+    else
+      {
+        pad1 = new byte[40];
+        pad2 = new byte[40];
+      }
+    Arrays.fill(pad1, PAD1);
+    Arrays.fill(pad2, PAD2);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public Object clone()
+  {
+    try
+      {
+        return super.clone();
+      }
+    catch (CloneNotSupportedException cnse)
+      {
+        throw new Error();
+      }
+  }
+
+  public String name()
+  {
+    return "SSLHMac-" + md.name();
+  }
+
+  public int macSize()
+  {
+    return md.hashSize();
+  }
+
+  public void init(Map attributes)
+  {
+    key = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+    if (key == null)
+      throw new NullPointerException();
+    reset();
+  }
+
+  public void reset()
+  {
+    md.reset();
+    md.update(key, 0, key.length);
+    md.update(pad1, 0, pad1.length);
+  }
+
+  public byte[] digest()
+  {
+    byte[] h1 = md.digest();
+    md.update(key, 0, key.length);
+    md.update(pad2, 0, pad2.length);
+    md.update(h1, 0, h1.length);
+    byte[] result = md.digest();
+    reset();
+    return result;
+  }
+
+  public void update(byte b)
+  {
+    md.update(b);
+  }
+
+  public void update(byte[] buf, int off, int len)
+  {
+    md.update(buf, off, len);
+  }
+
+  public boolean selfTest()
+  {
+    return true; // XXX
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,234 @@
+/* SSLRSASignatureImpl.java -- SSL/TLS RSA implementation.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.RSA;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+/**
+ * An implementation of of the RSA signature algorithm; this is an RSA
+ * encrypted MD5 hash followed by a SHA-1 hash.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLRSASignatureImpl extends SignatureSpi
+{
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+  private RSAPublicKey pubkey;
+  private RSAPrivateKey privkey;
+  private final MessageDigest md5, sha;
+  private boolean initSign = false;
+  private boolean initVerify = false;
+  
+  public SSLRSASignatureImpl() throws NoSuchAlgorithmException
+  {
+    md5 = MessageDigest.getInstance("MD5");
+    sha = MessageDigest.getInstance("SHA-1");
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey)
+   */
+  @Override protected void engineInitVerify(PublicKey publicKey)
+      throws InvalidKeyException
+  {
+    try
+      {
+        pubkey = (RSAPublicKey) publicKey;
+        initVerify = true;
+        initSign = false;
+        privkey = null;
+      }
+    catch (ClassCastException cce)
+      {
+        throw new InvalidKeyException(cce);
+      }
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey)
+   */
+  @Override protected void engineInitSign(PrivateKey privateKey)
+      throws InvalidKeyException
+  {
+    try
+      {
+        privkey = (RSAPrivateKey) privateKey;
+        initSign = true;
+        initVerify = false;
+        pubkey = null;
+      }
+    catch (ClassCastException cce)
+      {
+        throw new InvalidKeyException(cce);
+      }
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineUpdate(byte)
+   */
+  @Override protected void engineUpdate(byte b) throws SignatureException
+  {
+    if (!initSign && !initVerify)
+      throw new IllegalStateException("not initialized");
+    if (Debug.DEBUG)
+      logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update 0x{0}",
+                 Util.formatInt(b & 0xFF, 16, 2));
+    md5.update(b);
+    sha.update(b);
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineUpdate(byte[], int, int)
+   */
+  @Override protected void engineUpdate(byte[] b, int off, int len)
+      throws SignatureException
+  {
+    if (!initSign && !initVerify)
+      throw new IllegalStateException("not initialized");
+    if (Debug.DEBUG)
+      logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update\n{0}",
+                 Util.hexDump(b, off, len, ">> "));
+    md5.update(b, off, len);
+    sha.update(b, off, len);
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineSign()
+   */
+  @Override protected byte[] engineSign() throws SignatureException
+  {
+    // FIXME we need to add RSA blinding to this, somehow.
+    
+    if (!initSign)
+      throw new SignatureException("not initialized for signing");
+    // Pad the hash results with RSA block type 1.
+    final int k = (privkey.getModulus().bitLength() + 7) >>> 3;
+    final byte[] d = Util.concat(md5.digest(), sha.digest());
+    if (k - 11 < d.length)
+      throw new SignatureException("message too long");
+    final byte[] eb = new byte[k];
+    eb[0] = 0x00;
+    eb[1] = 0x01;
+    for (int i = 2; i < k - d.length - 1; i++)
+      eb[i] = (byte) 0xFF;
+    System.arraycopy(d, 0, eb, k - d.length, d.length);
+    BigInteger EB = new BigInteger(eb);
+
+    // Private-key encrypt the padded hashes.
+    BigInteger EM = RSA.sign(privkey, EB);
+    return Util.trim(EM);
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineVerify(byte[])
+   */
+  @Override protected boolean engineVerify(byte[] sigBytes)
+      throws SignatureException
+  {
+    if (!initVerify)
+      throw new SignatureException("not initialized for verifying");
+
+    // Public-key decrypt the signature representative.
+    BigInteger EM = new BigInteger(1, (byte[]) sigBytes);
+    BigInteger EB = RSA.verify(pubkey, EM);
+
+    // Unpad the decrypted message.
+    int i = 0;
+    final byte[] eb = EB.toByteArray();
+    if (eb[0] == 0x00)
+      {
+        for (i = 0; i < eb.length && eb[i] == 0x00; i++)
+          ;
+      }
+    else if (eb[0] == 0x01)
+      {
+        for (i = 1; i < eb.length && eb[i] != 0x00; i++)
+          {
+            if (eb[i] != (byte) 0xFF)
+              {
+                throw new SignatureException("bad padding");
+              }
+          }
+        i++;
+      }
+    else
+      {
+        throw new SignatureException("decryption failed");
+      }
+    byte[] d1 = Util.trim(eb, i, eb.length - i);
+    byte[] d2 = Util.concat(md5.digest(), sha.digest());
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "SSL/RSA d1:{0} d2:{1}",
+                  Util.toHexString(d1, ':'), Util.toHexString(d2, ':'));
+    return Arrays.equals(d1, d2);
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object)
+   */
+  @Override protected void engineSetParameter(String param, Object value)
+      throws InvalidParameterException
+  {
+    throw new InvalidParameterException("parameters not supported");
+  }
+
+  /* (non-Javadoc)
+   * @see java.security.SignatureSpi#engineGetParameter(java.lang.String)
+   */
+  @Override protected Object engineGetParameter(String param)
+      throws InvalidParameterException
+  {
+    throw new InvalidParameterException("parameters not supported");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLRandom.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,165 @@
+/* SSLRandom.java -- SSLv3 pseudo-random function.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.util.Map;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+
+class SSLRandom implements IRandom
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  static final String SECRET = "jessie.sslprng.secret";
+  static final String SEED = "jessie.sslprng.seed";
+
+  private final IMessageDigest md5, sha;
+  private byte[] secret;
+  private byte[] buffer;
+  private byte pad;
+  private byte[] seed;
+  private int idx;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  SSLRandom()
+  {
+    md5 = HashFactory.getInstance("MD5");
+    sha = HashFactory.getInstance("SHA-1");
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void init(Map attrib)
+  {
+    secret = (byte[]) attrib.get(SECRET);
+    seed = (byte[]) attrib.get(SEED);
+
+    if (secret == null || seed == null)
+      throw new NullPointerException();
+
+    pad = (byte) 'A';
+    try { buffer = nextBlock(); }
+    catch (LimitReachedException cantHappen) { }
+  }
+
+  public String name()
+  {
+    return "SSLRandom";
+  }
+
+  public Object clone()
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public byte nextByte() throws LimitReachedException
+  {
+    if (buffer == null)
+      throw new IllegalStateException();
+    if (idx >= buffer.length)
+      buffer = nextBlock();
+    return buffer[idx++];
+  }
+
+  public void nextBytes(byte[] buf, int off, int len)
+    throws LimitReachedException
+  {
+    if (buffer == null)
+      throw new IllegalStateException();
+    if (buf == null)
+      throw new NullPointerException();
+    if (off < 0 || len < 0 || off+len > buf.length)
+      throw new IndexOutOfBoundsException();
+    int count = 0;
+    while (count < len)
+      {
+        if (idx >= buffer.length)
+          buffer = nextBlock();
+        int l = Math.min(buffer.length-idx, len-count);
+        System.arraycopy(buffer, idx, buf, off+count, l);
+        count += l;
+        idx += l;
+      }
+  }
+
+  public boolean selfTest()
+  {
+    return true; // XXX
+  }
+
+  // For future versions of GNU Crypto. No-ops.
+  public void addRandomByte (byte b)
+  {
+  }
+
+  public void addRandomBytes(byte[] buffer) {
+    addRandomBytes(buffer, 0, buffer.length);
+  }
+
+  public void addRandomBytes (byte[] b, int i, int j)
+  {
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private byte[] nextBlock() throws LimitReachedException
+  {
+    int count = pad - 'A' + 1;
+    if (count > 26)
+      throw new LimitReachedException();
+    for (int i = 0; i < count; i++)
+      sha.update(pad);
+    sha.update(secret, 0, secret.length);
+    sha.update(seed, 0, seed.length);
+    byte[] b = sha.digest();
+    md5.update(secret, 0, secret.length);
+    md5.update(b, 0, b.length);
+    idx = 0;
+    pad++;
+    return md5.digest();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,108 @@
+/* SSLServerSocketFactoryImpl.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory
+{
+  private final SSLContextImpl contextImpl;
+  
+  public SSLServerSocketFactoryImpl(SSLContextImpl contextImpl)
+  {
+    this.contextImpl = contextImpl;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocketFactory#getDefaultCipherSuites()
+   */
+  @Override public String[] getDefaultCipherSuites()
+  {
+    return SSLEngineImpl.defaultSuites();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocketFactory#getSupportedCipherSuites()
+   */
+  @Override public String[] getSupportedCipherSuites()
+  {
+    return CipherSuite.availableSuiteNames().toArray(new String[0]);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ServerSocketFactory#createServerSocket(int)
+   */
+  @Override public SSLServerSocketImpl createServerSocket(int port)
+    throws IOException
+  {
+    SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+    socket.bind(new InetSocketAddress(port));
+    return socket;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ServerSocketFactory#createServerSocket(int, int)
+   */
+  @Override public SSLServerSocketImpl createServerSocket(int port, int backlog)
+    throws IOException
+  {
+    SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+    socket.bind(new InetSocketAddress(port), backlog);
+    return socket;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ServerSocketFactory#createServerSocket(int, int, java.net.InetAddress)
+   */
+  @Override public SSLServerSocketImpl createServerSocket(int port, int backlog,
+                                                          InetAddress bindAddress)
+    throws IOException
+  {
+    SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+    socket.bind(new InetSocketAddress(bindAddress, port), backlog);
+    return socket;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,199 @@
+/* SSLServerSocketImpl.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+
+import javax.net.ssl.SSLServerSocket;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketImpl extends SSLServerSocket
+{
+  private final SSLContextImpl contextImpl;
+  
+  private boolean enableSessionCreation;
+  private String[] enabledCipherSuites;
+  private String[] enabledProtocols;
+  private boolean needClientAuth;
+  private boolean wantClientAuth;
+  private boolean clientMode;
+
+  public SSLServerSocketImpl(SSLContextImpl contextImpl) throws IOException
+  {
+    super();
+    this.contextImpl = contextImpl;
+    enableSessionCreation = true;
+    enabledCipherSuites = SSLEngineImpl.defaultSuites();
+    enabledProtocols = new String[] { ProtocolVersion.SSL_3.toString(),
+                                      ProtocolVersion.TLS_1.toString(),
+                                      ProtocolVersion.TLS_1_1.toString() };
+    needClientAuth = false;
+    wantClientAuth = false;
+    clientMode = false;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getEnableSessionCreation()
+   */
+  @Override public boolean getEnableSessionCreation()
+  {
+    return enableSessionCreation;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getEnabledCipherSuites()
+   */
+  @Override public String[] getEnabledCipherSuites()
+  {
+    return (String[]) enabledCipherSuites.clone();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getEnabledProtocols()
+   */
+  @Override public String[] getEnabledProtocols()
+  {
+    return (String[]) enabledProtocols.clone();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getNeedClientAuth()
+   */
+  @Override public boolean getNeedClientAuth()
+  {
+    return needClientAuth;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getSupportedCipherSuites()
+   */
+  @Override public String[] getSupportedCipherSuites()
+  {
+    return CipherSuite.availableSuiteNames().toArray(new String[0]);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getSupportedProtocols()
+   */
+  @Override public String[] getSupportedProtocols()
+  {
+    return new String[] { ProtocolVersion.SSL_3.toString(),
+                          ProtocolVersion.TLS_1.toString(),
+                          ProtocolVersion.TLS_1_1.toString() };
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getUseClientMode()
+   */
+  @Override public boolean getUseClientMode()
+  {
+    return clientMode;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#getWantClientAuth()
+   */
+  @Override public boolean getWantClientAuth()
+  {
+    return wantClientAuth;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setEnableSessionCreation(boolean)
+   */
+  @Override public void setEnableSessionCreation(final boolean enabled)
+  {
+    enableSessionCreation = enabled;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setEnabledCipherSuites(java.lang.String[])
+   */
+  @Override public void setEnabledCipherSuites(final String[] suites)
+  {
+    enabledCipherSuites = (String[]) suites.clone();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setEnabledProtocols(java.lang.String[])
+   */
+  @Override public void setEnabledProtocols(final String[] protocols)
+  {
+    enabledProtocols = (String[]) protocols.clone();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setNeedClientAuth(boolean)
+   */
+  @Override public void setNeedClientAuth(final boolean needAuth)
+  {
+    needClientAuth = needAuth;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setUseClientMode(boolean)
+   */
+  @Override public void setUseClientMode(final boolean clientMode)
+  {
+    this.clientMode = clientMode;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLServerSocket#setWantClientAuth(boolean)
+   */
+  @Override public void setWantClientAuth(final boolean wantAuth)
+  {
+    wantClientAuth = wantAuth;
+  }
+  
+  @Override public SSLSocketImpl accept() throws IOException
+  {
+    SSLSocketImpl socketImpl = new SSLSocketImpl(contextImpl, null, -1);
+    implAccept(socketImpl);
+    socketImpl.setEnableSessionCreation(enableSessionCreation);
+    socketImpl.setEnabledCipherSuites(enabledCipherSuites);
+    socketImpl.setEnabledProtocols(enabledProtocols);
+    socketImpl.setNeedClientAuth(needClientAuth);
+    socketImpl.setUseClientMode(clientMode);
+    socketImpl.setWantClientAuth(wantClientAuth);
+    return socketImpl;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,143 @@
+/* SSLSocketFactoryImpl.java -- 
+   Copyright (C) 2006, 2007  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketFactoryImpl extends SSLSocketFactory
+{
+  /**
+   * The SSLContextImpl that created us.
+   */
+  private final SSLContextImpl contextImpl;
+  
+  public SSLSocketFactoryImpl(SSLContextImpl contextImpl)
+  {
+    this.contextImpl = contextImpl;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean)
+   */
+  @Override public Socket createSocket(Socket socket, String host, int port,
+                                       boolean autoClose)
+    throws IOException
+  {
+    return new SSLSocketImpl(contextImpl, host, port, socket, autoClose);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites()
+   */
+  @Override public String[] getDefaultCipherSuites()
+  {
+    return SSLEngineImpl.defaultSuites();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites()
+   */
+  @Override public String[] getSupportedCipherSuites()
+  {
+    return CipherSuite.availableSuiteNames().toArray(new String[0]);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.SocketFactory#createSocket(java.lang.String, int)
+   */
+  @Override public SSLSocketImpl createSocket(String host, int port)
+    throws IOException, UnknownHostException
+  {
+    return createSocket(host, port, null, 0);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
+   */
+  @Override public SSLSocketImpl createSocket(String host, int port,
+                                              InetAddress localHost, int localPort)
+    throws IOException, UnknownHostException
+  {
+    SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port);
+    InetSocketAddress endpoint = new InetSocketAddress(host, port);
+    socket.bind(new InetSocketAddress(localHost, localPort));
+    socket.connect(endpoint);
+    return socket;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
+   */
+  @Override public SSLSocketImpl createSocket(InetAddress host, int port)
+    throws IOException
+  {
+    return createSocket(host, port, null, 0);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int)
+   */
+  @Override public SSLSocketImpl createSocket(InetAddress host, int port,
+                                              InetAddress localHost, int localPort)
+    throws IOException
+  {
+    SSLSocketImpl socket = new SSLSocketImpl(contextImpl,
+                                             host.getCanonicalHostName(), port);
+    socket.bind(new InetSocketAddress(localHost, localPort));
+    socket.connect(new InetSocketAddress(host, port));
+    return socket;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.SocketFactory#createSocket()
+   */
+  @Override public Socket createSocket() throws IOException
+  {
+    return new SSLSocketImpl(contextImpl, null, -1, new Socket(), true);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLSocketImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,740 @@
+/* SSLSocketImpl.java -- implementation of an SSL client socket.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketImpl extends SSLSocket
+{
+  private class SocketOutputStream extends OutputStream
+  {
+    private final ByteBuffer buffer;
+    private final OutputStream out;
+    
+    SocketOutputStream() throws IOException
+    {
+      buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+      if (underlyingSocket != null)
+        out = underlyingSocket.getOutputStream();
+      else
+        out = SSLSocketImpl.super.getOutputStream();
+    }
+
+    @Override public void write(byte[] buf, int off, int len) throws IOException
+    {
+      if (!initialHandshakeDone
+          || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+        {
+          doHandshake();
+          if (handshakeException != null)
+            throw handshakeException;
+        }
+
+      int k = 0;
+      while (k < len)
+        {
+          synchronized (engine)
+            {
+              int l = Math.min(len-k, getSession().getApplicationBufferSize());
+              ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
+              SSLEngineResult result = engine.wrap(in, buffer);
+              if (result.getStatus() == Status.CLOSED)
+                return;
+              if (result.getStatus() != Status.OK)
+                throw new SSLException("unexpected SSL state " + result.getStatus());
+              buffer.flip();
+              out.write(buffer.array(), 0, buffer.limit());
+              k += result.bytesConsumed();
+              buffer.clear();
+            }
+        }
+    }
+    
+    @Override public void write(int b) throws IOException
+    {
+      write(new byte[] { (byte) b });
+    }
+    
+    @Override public void close() throws IOException
+    {
+      SSLSocketImpl.this.close();
+    }
+  }
+
+  private class SocketInputStream extends InputStream
+  {
+    private final ByteBuffer inBuffer;
+    private final ByteBuffer appBuffer;
+    private final DataInputStream in;
+
+    SocketInputStream() throws IOException
+    {
+      inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+      inBuffer.limit(0);
+      appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
+      appBuffer.flip();
+      if (underlyingSocket != null)
+        in = new DataInputStream(underlyingSocket.getInputStream());
+      else
+        in = new DataInputStream(SSLSocketImpl.super.getInputStream());
+    }
+
+    @Override public int read(byte[] buf, int off, int len) throws IOException
+    {
+      if (!initialHandshakeDone ||
+          engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+        {
+          doHandshake();
+          if (handshakeException != null)
+            throw handshakeException;
+        }
+
+      if (!appBuffer.hasRemaining())
+        {
+          int x = in.read();
+          if (x == -1)
+            return -1;
+          inBuffer.clear();
+          inBuffer.put((byte) x);
+          inBuffer.putInt(in.readInt());
+          int reclen = inBuffer.getShort(3) & 0xFFFF;
+          in.readFully(inBuffer.array(), 5, reclen);
+          inBuffer.position(0).limit(reclen + 5);
+          synchronized (engine)
+            {
+              appBuffer.clear();
+              SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
+              Status status = result.getStatus();
+              if (status == Status.CLOSED && result.bytesProduced() == 0)
+                return -1;
+            }
+          inBuffer.compact();
+          appBuffer.flip();
+        }
+      int l = Math.min(len, appBuffer.remaining());
+      appBuffer.get(buf, off, l);
+      return l;
+    }
+
+    @Override public int read() throws IOException
+    {
+      byte[] b = new byte[1];
+      if (read(b) == -1)
+        return -1;
+      return b[0] & 0xFF;
+    }
+  }
+
+  private static final SystemLogger logger = SystemLogger.getSystemLogger();
+
+  private SSLEngineImpl engine;
+  private Set<HandshakeCompletedListener> listeners;
+  private Socket underlyingSocket;
+  private boolean isHandshaking;
+  private IOException handshakeException;
+  private boolean initialHandshakeDone = false;
+  private final boolean autoClose;
+  
+  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
+  {
+    this(contextImpl, host, port, new Socket(), true);
+  }
+  
+  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
+                       Socket underlyingSocket, boolean autoClose)
+  {
+    engine = new SSLEngineImpl(contextImpl, host, port);
+    engine.setUseClientMode(true); // default to client mode
+    listeners = new HashSet<HandshakeCompletedListener>();
+    this.underlyingSocket = underlyingSocket;
+    this.autoClose = autoClose;
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+   */
+  @Override
+  public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
+  {
+    listeners.add(listener);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
+   */
+  @Override public boolean getEnableSessionCreation()
+  {
+    return engine.getEnableSessionCreation();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
+   */
+  @Override public String[] getEnabledCipherSuites()
+  {
+    return engine.getEnabledCipherSuites();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
+   */
+  @Override public String[] getEnabledProtocols()
+  {
+    return engine.getEnabledProtocols();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
+   */
+  @Override public boolean getNeedClientAuth()
+  {
+    return engine.getNeedClientAuth();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getSession()
+   */
+  @Override public SSLSession getSession()
+  {
+    return engine.getSession();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
+   */
+  @Override public String[] getSupportedCipherSuites()
+  {
+    return engine.getSupportedCipherSuites();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
+   */
+  @Override public String[] getSupportedProtocols()
+  {
+    return engine.getSupportedProtocols();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getUseClientMode()
+   */
+  @Override public boolean getUseClientMode()
+  {
+    return engine.getUseClientMode();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#getWantClientAuth()
+   */
+  @Override public boolean getWantClientAuth()
+  {
+    return engine.getWantClientAuth();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+   */
+  @Override
+  public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
+  {
+    listeners.remove(listener);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
+   */
+  @Override public void setEnableSessionCreation(boolean enable)
+  {
+    engine.setEnableSessionCreation(enable);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
+   */
+  @Override public void setEnabledCipherSuites(String[] suites)
+  {
+    engine.setEnabledCipherSuites(suites);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
+   */
+  @Override public void setEnabledProtocols(String[] protocols)
+  {
+    engine.setEnabledProtocols(protocols);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
+   */
+  @Override public void setNeedClientAuth(boolean needAuth)
+  {
+    engine.setNeedClientAuth(needAuth);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
+   */
+  @Override public void setUseClientMode(boolean clientMode)
+  {
+    engine.setUseClientMode(clientMode);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
+   */
+  @Override public void setWantClientAuth(boolean wantAuth)
+  {
+    engine.setWantClientAuth(wantAuth);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.net.ssl.SSLSocket#startHandshake()
+   */
+  @Override public void startHandshake() throws IOException
+  {
+    if (isHandshaking)
+      return;
+
+    if (handshakeException != null)
+      throw handshakeException;
+    
+    Thread t = new Thread(new Runnable()
+    {
+      public void run()
+      {
+        try
+          {
+            doHandshake();
+          }
+        catch (IOException ioe)
+          {
+            handshakeException = ioe;
+          }
+      }
+    }, "HandshakeThread@" + System.identityHashCode(this));
+    t.start();
+  }
+  
+  void doHandshake() throws IOException
+  {
+    synchronized (engine)
+      {
+        if (isHandshaking)
+          {
+            try
+              {
+                engine.wait();
+              }
+            catch (InterruptedException ie)
+              {
+              }
+            return;
+          }
+        isHandshaking = true;
+      }
+    
+    if (initialHandshakeDone)
+      throw new SSLException("rehandshaking not yet implemented");
+
+    long now = -System.currentTimeMillis();
+    engine.beginHandshake();
+    
+    HandshakeStatus status = engine.getHandshakeStatus();
+    assert(status != HandshakeStatus.NOT_HANDSHAKING);
+
+    ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+    inBuffer.position(inBuffer.limit());
+    ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+    ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
+    SSLEngineResult result = null;
+    
+    DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream());
+    OutputStream sockOut = underlyingSocket.getOutputStream();
+    
+    try
+      {
+        while (status != HandshakeStatus.NOT_HANDSHAKING
+               && status != HandshakeStatus.FINISHED)
+          {
+            logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
+                        status);
+
+            if (inBuffer.capacity() != getSession().getPacketBufferSize())
+              {
+                ByteBuffer b
+                  = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+                if (inBuffer.hasRemaining())
+                  b.put(inBuffer).flip();
+                inBuffer = b;
+              }
+            if (outBuffer.capacity() != getSession().getPacketBufferSize())
+              outBuffer
+              = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+
+            switch (status)
+              {
+                case NEED_UNWRAP:
+                  // Read in a single SSL record.
+                  inBuffer.clear();
+                  int i = sockIn.read();
+                  if (i == -1)
+                    throw new EOFException();
+                  if ((i & 0x80) == 0x80) // SSLv2 client hello.
+                    {
+                      inBuffer.put((byte) i);
+                      int v2len = (i & 0x7f) << 8;
+                      i = sockIn.read();
+                      v2len = v2len | (i & 0xff);
+                      inBuffer.put((byte) i);
+                      sockIn.readFully(inBuffer.array(), 2, v2len);
+                      inBuffer.position(0).limit(v2len + 2);
+                    }
+                  else
+                    {
+                      inBuffer.put((byte) i);
+                      inBuffer.putInt(sockIn.readInt());
+                      int reclen = inBuffer.getShort(3) & 0xFFFF;
+                      sockIn.readFully(inBuffer.array(), 5, reclen);
+                      inBuffer.position(0).limit(reclen + 5);
+                    }
+                  result = engine.unwrap(inBuffer, emptyBuffer);
+                  status = result.getHandshakeStatus();
+                  if (result.getStatus() != Status.OK)
+                    throw new SSLException("unexpected SSL status "
+                                           + result.getStatus());
+                  break;
+
+                case NEED_WRAP:
+                {
+                  outBuffer.clear();
+                  result = engine.wrap(emptyBuffer, outBuffer);
+                  status = result.getHandshakeStatus();
+                  if (result.getStatus() != Status.OK)
+                    throw new SSLException("unexpected SSL status "
+                                           + result.getStatus());
+                  outBuffer.flip();
+                  sockOut.write(outBuffer.array(), outBuffer.position(), 
+                                outBuffer.limit());
+                }
+                break;
+
+                case NEED_TASK:
+                {
+                  Runnable task;
+                  while ((task = engine.getDelegatedTask()) != null)
+                    task.run();
+                  status = engine.getHandshakeStatus();
+                }
+                break;
+
+                case FINISHED:
+                  break;
+              }
+          }
+
+        initialHandshakeDone = true;
+
+        HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
+        for (HandshakeCompletedListener l : listeners)
+          {
+            try
+              {
+                l.handshakeCompleted(hce);
+              }
+            catch (ThreadDeath td)
+              {
+                throw td;
+              }
+            catch (Throwable x)
+              {
+                logger.log(Component.WARNING,
+                           "HandshakeCompletedListener threw exception", x);
+              }
+          }
+
+        now += System.currentTimeMillis();
+        if (Debug.DEBUG)
+          logger.logv(Component.SSL_HANDSHAKE,
+                      "handshake completed in {0}ms in thread {1}", now,
+                      Thread.currentThread().getName());
+      }
+    catch (SSLException ssle)
+      {
+        handshakeException = ssle;
+        throw ssle;
+      }
+    finally
+      {
+        synchronized (engine)
+          {
+            isHandshaking = false;
+            engine.notifyAll();
+          }
+      }
+  }
+  
+  // Methods overriding Socket.
+
+  @Override public void bind(SocketAddress bindpoint) throws IOException
+  {
+    underlyingSocket.bind(bindpoint);
+  }
+  
+  @Override public void connect(SocketAddress endpoint) throws IOException
+  {
+    underlyingSocket.connect(endpoint);
+  }
+
+  @Override public void connect(SocketAddress endpoint, int timeout)
+    throws IOException
+  {
+    underlyingSocket.connect(endpoint, timeout);
+  }
+
+  @Override public InetAddress getInetAddress()
+  {
+    return underlyingSocket.getInetAddress();
+  }
+  
+  @Override public InetAddress getLocalAddress()
+  {
+    return underlyingSocket.getLocalAddress();
+  }
+  
+  @Override public int getPort()
+  {
+    return underlyingSocket.getPort();
+  }
+
+  @Override public int getLocalPort()
+  {
+    return underlyingSocket.getLocalPort();
+  }
+
+  @Override public SocketAddress getRemoteSocketAddress()
+  {
+    return underlyingSocket.getRemoteSocketAddress();
+  }
+
+  public SocketAddress getLocalSocketAddress()
+  {
+    return underlyingSocket.getLocalSocketAddress();
+  }
+
+  @Override public SocketChannel getChannel()
+  {
+    throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
+  }
+
+  @Override public InputStream getInputStream() throws IOException
+  {
+    return new SocketInputStream();
+  }
+
+  @Override public OutputStream getOutputStream() throws IOException
+  {
+    return new SocketOutputStream();
+  }
+
+  @Override public void setTcpNoDelay(boolean on) throws SocketException
+  {
+    underlyingSocket.setTcpNoDelay(on);
+  }
+
+  @Override public boolean getTcpNoDelay() throws SocketException
+  {
+    return underlyingSocket.getTcpNoDelay();
+  }
+
+  @Override public void setSoLinger(boolean on, int linger) throws SocketException
+  {
+    underlyingSocket.setSoLinger(on, linger);
+  }
+
+  public int getSoLinger() throws SocketException
+  {
+    return underlyingSocket.getSoLinger();
+  }
+
+  @Override public void sendUrgentData(int x) throws IOException
+  {
+    throw new UnsupportedOperationException("not supported");
+  }
+
+  @Override public void setOOBInline(boolean on) throws SocketException
+  {
+    underlyingSocket.setOOBInline(on);
+  }
+
+  @Override public boolean getOOBInline() throws SocketException
+  {
+    return underlyingSocket.getOOBInline();
+  }
+
+  @Override public void setSoTimeout(int timeout) throws SocketException
+  {
+    underlyingSocket.setSoTimeout(timeout);
+  }
+
+  @Override public int getSoTimeout() throws SocketException
+  {
+    return underlyingSocket.getSoTimeout();
+  }
+
+  @Override public void setSendBufferSize(int size) throws SocketException
+  {
+    underlyingSocket.setSendBufferSize(size);
+  }
+
+  @Override public int getSendBufferSize() throws SocketException
+  {
+    return underlyingSocket.getSendBufferSize();
+  }
+
+  @Override public void setReceiveBufferSize(int size) throws SocketException
+  {
+    underlyingSocket.setReceiveBufferSize(size);
+  }
+
+  @Override public int getReceiveBufferSize() throws SocketException
+  {
+    return underlyingSocket.getReceiveBufferSize();
+  }
+
+  @Override public void setKeepAlive(boolean on) throws SocketException
+  {
+    underlyingSocket.setKeepAlive(on);
+  }
+
+  @Override public boolean getKeepAlive() throws SocketException
+  {
+    return underlyingSocket.getKeepAlive();
+  }
+
+  @Override public void setTrafficClass(int tc) throws SocketException
+  {
+    underlyingSocket.setTrafficClass(tc);
+  }
+
+  @Override public int getTrafficClass() throws SocketException
+  {
+    return underlyingSocket.getTrafficClass();
+  }
+
+  @Override public void setReuseAddress(boolean reuseAddress)
+    throws SocketException
+  {
+    underlyingSocket.setReuseAddress(reuseAddress);
+  }
+
+  @Override public boolean getReuseAddress() throws SocketException
+  {
+    return underlyingSocket.getReuseAddress();
+  }
+
+  @Override public void close() throws IOException
+  {
+    // XXX closure alerts.
+    if (autoClose)
+      underlyingSocket.close();
+  }
+
+  @Override public void shutdownInput() throws IOException
+  {
+    underlyingSocket.shutdownInput();
+  }
+
+  @Override public void shutdownOutput() throws IOException
+  {
+    underlyingSocket.shutdownOutput();
+  }
+
+  @Override public boolean isConnected()
+  {
+    return underlyingSocket.isConnected();
+  }
+
+  @Override public boolean isBound()
+  {
+    return underlyingSocket.isBound();
+  }
+
+  @Override public boolean isClosed()
+  {
+    return underlyingSocket.isClosed();
+  }
+
+  @Override public boolean isInputShutdown()
+  {
+    return underlyingSocket.isInputShutdown();
+  }
+
+  @Override public boolean isOutputShutdown()
+  {
+    return underlyingSocket.isOutputShutdown();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,116 @@
+/* SSLv3HMacMD5.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacMD5Impl extends MacSpi
+{
+  private final SSLHMac adaptee;
+
+  public SSLv3HMacMD5Impl()
+  {
+    adaptee = new SSLHMac("MD5");
+  }
+  
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineDoFinal()
+   */
+  @Override protected byte[] engineDoFinal()
+  {
+    return adaptee.digest();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineGetMacLength()
+   */
+  @Override protected int engineGetMacLength()
+  {
+    return adaptee.macSize();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+   */
+  @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+      throws InvalidAlgorithmParameterException, InvalidKeyException
+  {
+    if (!(key instanceof SecretKey)
+        || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-MD5"))
+      throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-MD5\"");
+    Map<String,byte[]> attr =
+      Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+    adaptee.init(attr);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineReset()
+   */
+  @Override protected void engineReset()
+  {
+    adaptee.reset();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineUpdate(byte)
+   */
+  @Override protected void engineUpdate(byte input)
+  {
+    adaptee.update(input);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+   */
+  @Override protected void engineUpdate(byte[] input, int offset, int length)
+  {
+    adaptee.update(input, offset, length);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,116 @@
+/* SSLv3HMacSHA.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacSHAImpl extends MacSpi
+{
+  private final SSLHMac adaptee;
+
+  public SSLv3HMacSHAImpl()
+  {
+    adaptee = new SSLHMac("SHA-160");
+  }
+  
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineDoFinal()
+   */
+  @Override protected byte[] engineDoFinal()
+  {
+    return adaptee.digest();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineGetMacLength()
+   */
+  @Override protected int engineGetMacLength()
+  {
+    return adaptee.macSize();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+   */
+  @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+      throws InvalidAlgorithmParameterException, InvalidKeyException
+  {
+    if (!(key instanceof SecretKey)
+        || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-SHA"))
+      throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-SHA\"");
+    Map<String,byte[]> attr =
+      Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+    adaptee.init(attr);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineReset()
+   */
+  @Override protected void engineReset()
+  {
+    adaptee.reset();
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineUpdate(byte)
+   */
+  @Override protected void engineUpdate(byte input)
+  {
+    adaptee.update(input);
+  }
+
+  /* (non-Javadoc)
+   * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+   */
+  @Override protected void engineUpdate(byte[] input, int offset, int length)
+  {
+    adaptee.update(input, offset, length);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,151 @@
+/* ServerDHE_PSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. &#42;/
+              case diffie_hellman_psk:  /* NEW &#42;/
+                  opaque psk_identity_hint&lt;0..2^16-1&gt;;
+                  ServerDHParams params;
+          };
+      } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyExchangeParams
+{
+  private ByteBuffer buffer;
+  
+  public ServerDHE_PSKParameters(ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  public ServerDHE_PSKParameters(String identityHint, ServerDHParams dhParams)
+  {
+    this(identityHint, dhParams.buffer());
+  }
+
+  public ServerDHE_PSKParameters(String identityHint, ByteBuffer dhParams)
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer hintBuf = utf8.encode(identityHint);
+    buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining());
+    buffer.putShort((short) hintBuf.remaining());
+    buffer.put(hintBuf);
+    buffer.put(dhParams);    
+  }
+
+  public KeyExchangeAlgorithm algorithm()
+  {
+    return KeyExchangeAlgorithm.DHE_PSK;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2 + params().length();
+  }
+  
+  private int hintLength()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+  
+  public String identityHint()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+                       (hintLength())).toString();
+  }
+  
+  public ServerDHParams params()
+  {
+    return new ServerDHParams(((ByteBuffer) buffer.duplicate().position
+                               (hintLength()).limit(buffer.capacity())).slice());
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+  
+  public @Override String toString()
+  {
+    return toString(null);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  identity_hint = ");
+    out.print(identityHint());
+    out.println(";");
+    if (prefix != null) out.print(prefix);
+    out.println("  params =");
+    out.println(params().toString(prefix != null ? prefix + "    " : "    "));
+    if (prefix != null) out.print(prefix);
+    out.print("} ServerDHE_PSKParameters;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerDHParams.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,248 @@
+/* ServerDHParams.java -- The server's Diffie-Hellman parameters.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The server's Diffie-Hellman parameters message.
+ *
+ * <pre>
+struct
+{
+  opaque dh_p&lt;1..2^16-1&gt;;
+  opaque dh_g&lt;1..2^16-1&gt;;
+  opaque dh_Ys&lt;1..2^16-1&gt;;
+} ServerDHParams;
+</pre>
+ */
+public class ServerDHParams implements Builder, ServerKeyExchangeParams
+{
+  private final ByteBuffer buffer;
+
+  public ServerDHParams (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  public ServerDHParams (final BigInteger p, final BigInteger g,
+                         final BigInteger y)
+  {
+    byte[] p_bytes = p.toByteArray();
+    byte[] g_bytes = g.toByteArray();
+    byte[] y_bytes = y.toByteArray();
+    int len = p_bytes.length + g_bytes.length + y_bytes.length + 6;
+    
+    int p_off = 0;
+    if (p_bytes[0] == 0x00)
+      {
+        p_off = 1;
+        len--;
+      }
+    int g_off = 0;
+    if (g_bytes[0] == 0x00)
+      {
+        g_off = 1;
+        len--;
+      }
+    int y_off = 0;
+    if (y_bytes[0] == 0x00)
+      {
+        y_off = 1;
+        len--;
+      }
+    int p_len = p_bytes.length - p_off;
+    int g_len = g_bytes.length - g_off;
+    int y_len = y_bytes.length - y_off;
+    
+    buffer = ByteBuffer.allocate(len);
+    buffer.putShort((short) p_len);
+    buffer.put(p_bytes, p_off, p_len);
+    buffer.putShort((short) g_len);
+    buffer.put(g_bytes, g_off, g_len);
+    buffer.putShort((short) y_len);
+    buffer.put(y_bytes, y_off, y_len);
+  }
+
+  @Deprecated public KeyExchangeAlgorithm algorithm ()
+  {
+    return null; // XXX can't support this.
+  }
+
+  public int length ()
+  {
+    int offset1 = buffer.getShort (0) & 0xFFFF;
+    int offset2 = buffer.getShort (offset1 + 2) & 0xFFFF;
+    return ((buffer.getShort (offset1 + offset2 + 4) & 0xFFFF)
+            + offset1 + offset2 + 6);
+  }
+
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+  }
+  
+  /**
+   * Returns the server's prime modulus.
+   *
+   * @return p.
+   */
+  public BigInteger p ()
+  {
+    int len = buffer.getShort (0) & 0xFFFF;
+    byte[] buf = new byte[len];
+    buffer.position (2);
+    buffer.get (buf);
+    return new BigInteger (1, buf);
+  }
+
+  /**
+   * Returns the server's generator value.
+   *
+   * @return g.
+   */
+  public BigInteger g ()
+  {
+    int off = (buffer.getShort (0) & 0xFFFF) + 2;
+    int len = buffer.getShort (off) & 0xFFFF;
+    byte[] buf = new byte[len];
+    buffer.position (off + 2);
+    buffer.get (buf);
+    return new BigInteger (1, buf);
+  }
+
+  /**
+   * Returns the server's public value.
+   *
+   * @return Y.
+   */
+  public BigInteger y ()
+  {
+    int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+    int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+    int len = buffer.getShort (offset2) & 0xFFFF;
+    byte[] buf = new byte[len];
+    buffer.position (offset2 + 2);
+    buffer.get (buf);
+    return new BigInteger (1, buf);
+  }
+
+  /**
+   * Sets the server's prime modulus, p.
+   *
+   * @param p The p parameter.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   */
+  public void setP (final BigInteger p)
+  {
+    byte[] buf = p.toByteArray ();
+    int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+    int offset = (buf[0] == 0x00 ? 1 : 0);
+    buffer.putShort (0, (short) length);
+    buffer.position (2);
+    buffer.put (buf, offset, length);
+  }
+
+  /**
+   * Sets the server's generator value, g.
+   *
+   * @param g The g parameter.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   */
+  public void setG (final BigInteger g)
+  {
+    byte[] buf = g.toByteArray ();
+    int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+    int offset = (buf[0] == 0x00 ? 1 : 0);
+    int where = (buffer.getShort (0) & 0xFFFF) + 2;
+    buffer.putShort (where, (short) length);
+    buffer.position (where + 2);
+    buffer.put (buf, offset, length);
+  }
+
+  /**
+   * Sets the server's public value, Y.
+   *
+   * @param y The Y parameter.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   */
+  public void setY (final BigInteger y)
+  {
+    int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+    int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+    byte[] buf = y.toByteArray ();
+    int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+    int offset = (buf[0] == 0x00 ? 1 : 0);
+    buffer.putShort (offset2, (short) length);
+    buffer.position (offset2 + 2);
+    buffer.put (buf, offset, length);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  dh_p:  ");
+    out.println (p ().toString (16));
+    if (prefix != null) out.print (prefix);
+    out.print ("  dh_g:  ");
+    out.println (g ().toString (16));
+    if (prefix != null) out.print (prefix);
+    out.print ("  dh_Ys: ");
+    out.println (y ().toString (16));
+    if (prefix != null) out.print (prefix);
+    out.print ("} ServerDHParams;");
+    return str.toString ();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerHandshake.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,1377 @@
+/* ServerHandshake.java -- the server-side handshake.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.Handshake.Type.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+class ServerHandshake extends AbstractHandshake
+{  
+  /**
+   * Handshake state enumeration.
+   */
+  static enum State
+  {
+    WRITE_HELLO_REQUEST (true, false),
+    WRITE_SERVER_HELLO (true, false),
+    WRITE_CERTIFICATE (true, false),
+    WRITE_SERVER_KEY_EXCHANGE (true, false),
+    WRITE_CERTIFICATE_REQUEST (true, false),
+    WRITE_SERVER_HELLO_DONE (true, false),
+    WRITE_FINISHED (true, false),
+    READ_CLIENT_HELLO (false, true),
+    READ_CERTIFICATE (false, true),
+    READ_CLIENT_KEY_EXCHANGE (false, true),
+    READ_CERTIFICATE_VERIFY (false, true),
+    READ_FINISHED (false, true),
+    DONE (false, false);
+    
+    private final boolean isWriteState;
+    private final boolean isReadState;
+    
+    private State(final boolean isWriteState, final boolean isReadState)
+    {
+      this.isWriteState = isWriteState;
+      this.isReadState = isReadState;
+    }
+    
+    boolean isReadState()
+    {
+      return isReadState;
+    }
+    
+    boolean isWriteState()
+    {
+      return isWriteState;
+    }
+  }
+
+  private State state;
+
+  /* Handshake result fields. */
+  private ByteBuffer outBuffer;
+  private boolean clientHadExtensions = false;
+  private boolean continuedSession = false;
+  private ServerNameList requestedNames = null;
+  private String keyAlias = null;
+  private X509Certificate clientCert = null;
+  private X509Certificate localCert = null;
+  private boolean helloV2 = false;
+  private KeyPair dhPair;
+  private PrivateKey serverKey;
+  
+  // Delegated tasks we use.
+  private GenDH genDH;
+  private CertVerifier certVerifier;
+  private CertLoader certLoader;
+  private DelegatedTask keyExchangeTask;
+
+  ServerHandshake (boolean writeHelloRequest, final SSLEngineImpl engine)
+    throws NoSuchAlgorithmException
+  {
+    super(engine);
+    if (writeHelloRequest)
+      state = WRITE_HELLO_REQUEST;
+    else
+      state = READ_CLIENT_HELLO;
+    handshakeOffset = 0;
+  }
+
+  /**
+   * Choose the protocol version. Here we choose the largest protocol
+   * version we support that is not greater than the client's
+   * requested version.
+   */
+  private static ProtocolVersion chooseProtocol (final ProtocolVersion clientVersion,
+                                                 final String[] enabledVersions)
+    throws SSLException
+  {
+    ProtocolVersion version = null;
+    for (int i = 0; i < enabledVersions.length; i++)
+      {
+        ProtocolVersion v = ProtocolVersion.forName (enabledVersions[i]);
+        if (v.compareTo (clientVersion) <= 0)
+          {
+            if (version == null
+                || v.compareTo (version) > 0)
+              version = v;
+          }
+      }
+
+    // The client requested a protocol version too old, or no protocol
+    // versions are enabled.
+    if (version == null)
+      throw new SSLException ("no acceptable protocol version available");
+    return version;
+  }
+
+  /**
+   * Choose the first cipher suite in the client's requested list that
+   * we have enabled.
+   */
+  private CipherSuite chooseSuite (final CipherSuiteList clientSuites,
+                                   final String[] enabledSuites,
+                                   final ProtocolVersion version)
+    throws SSLException
+  {
+    // Figure out which SignatureAlgorithms we can support.
+    HashSet<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(8);
+
+    kexes.add(NONE);
+    X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+    if (km != null)
+      {
+        if (km.getServerAliases(DH_DSS.name(), null).length > 0)
+          kexes.add(DH_DSS);
+        if (km.getServerAliases(DH_RSA.name(), null).length > 0)
+          kexes.add(DH_RSA);
+        if (km.getServerAliases(DHE_DSS.name(), null).length > 0)
+          kexes.add(DHE_DSS);
+        if (km.getServerAliases(DHE_RSA.name(), null).length > 0)
+          kexes.add(DHE_RSA);
+        if (km.getServerAliases(RSA.name(), null).length > 0)
+          kexes.add(RSA);
+        if (km.getServerAliases(RSA_PSK.name(), null).length > 0
+            && engine.contextImpl.pskManager != null)
+          kexes.add(RSA_PSK);
+      }
+    if (engine.contextImpl.pskManager != null)
+      {
+        kexes.add(DHE_PSK);
+        kexes.add(PSK);
+      }
+    
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE,
+                  "we have certs for key exchange algorithms {0}", kexes);
+    
+    HashSet<CipherSuite> suites = new HashSet<CipherSuite>();
+    for (String s : enabledSuites)
+      {
+        CipherSuite suite = CipherSuite.forName(s);
+        if (suite == null)
+          continue;
+        if (!kexes.contains(suite.keyExchangeAlgorithm()))
+          continue;
+        suites.add(suite);
+      }
+    for (CipherSuite suite : clientSuites)
+      {
+        CipherSuite resolved = suite.resolve();
+        if (!resolved.isResolved())
+          continue;
+        if (suites.contains(resolved))
+          return resolved;
+      }
+    
+    // We didn't find a match?
+    throw new AlertException(new Alert(Alert.Level.FATAL,
+                                       Alert.Description.INSUFFICIENT_SECURITY));
+  }
+
+  /**
+   * Choose a compression method that we support, among the client's
+   * requested compression methods. We prefer ZLIB over NONE in this
+   * implementation.
+   *
+   * XXX Maybe consider implementing lzo (GNUTLS supports that).
+   */
+  private static CompressionMethod chooseCompression (final CompressionMethodList comps)
+    throws SSLException
+  {
+    GetSecurityPropertyAction gspa
+      = new GetSecurityPropertyAction("jessie.enable.compression");
+    String enable = AccessController.doPrivileged(gspa);
+    // Scan for ZLIB first.
+    if (Boolean.valueOf(enable))
+      {
+        for (CompressionMethod cm : comps)
+          {
+            if (cm.equals (CompressionMethod.ZLIB))
+              return CompressionMethod.ZLIB;
+          }
+      }
+    for (CompressionMethod cm : comps)
+      {
+        if (cm.equals (CompressionMethod.NULL))
+          return CompressionMethod.NULL;
+      }
+
+    throw new SSLException ("no supported compression method");
+  }
+  
+  protected @Override boolean doHash()
+  {
+    boolean b = helloV2;
+    helloV2 = false;
+    return (state != WRITE_HELLO_REQUEST) && !b;
+  }
+
+  public @Override HandshakeStatus implHandleInput()
+    throws SSLException
+  {
+    if (state == DONE)
+      return HandshakeStatus.FINISHED;
+
+    if (state.isWriteState()
+        || (outBuffer != null && outBuffer.hasRemaining()))
+      return HandshakeStatus.NEED_WRAP;
+
+    // Copy the current buffer, and prepare it for reading.
+    ByteBuffer buffer = handshakeBuffer.duplicate ();
+    buffer.flip();
+    buffer.position(handshakeOffset);
+    Handshake handshake = new Handshake(buffer.slice(),
+                                        engine.session().suite,
+                                        engine.session().version);
+        
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+                  state, handshake);
+
+    switch (state)
+      {
+        // Client Hello.
+        //
+        // This message is sent by the client to initiate a new handshake.
+        // On a new connection, it is the first handshake message sent.
+        //
+        // The state of the handshake, after this message is processed,
+        // will have a protocol version, cipher suite, compression method,
+        // session ID, and various extensions (that the server also
+        // supports).
+        case READ_CLIENT_HELLO:
+          if (handshake.type () != CLIENT_HELLO)
+            throw new AlertException(new Alert(Alert.Level.FATAL,
+                                               Alert.Description.UNEXPECTED_MESSAGE));
+            
+          {
+            ClientHello hello = (ClientHello) handshake.body ();
+            engine.session().version
+              = chooseProtocol (hello.version (),
+                                engine.getEnabledProtocols ());
+            engine.session().suite =
+              chooseSuite (hello.cipherSuites (),
+                           engine.getEnabledCipherSuites (),
+                           engine.session().version);
+            compression = chooseCompression (hello.compressionMethods ());
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_HANDSHAKE,
+                          "chose version:{0} suite:{1} compression:{2}",
+                          engine.session().version, engine.session().suite,
+                          compression);
+            clientRandom = hello.random().copy();
+            byte[] sessionId = hello.sessionId();
+            if (hello.hasExtensions())
+              {
+                ExtensionList exts = hello.extensions();
+                clientHadExtensions = exts.size() > 0;
+                for (Extension e : hello.extensions())
+                  {
+                    Extension.Type type = e.type();
+                    if (type == null)
+                      continue;
+                    switch (type)
+                    {
+                    case TRUNCATED_HMAC:
+                      engine.session().setTruncatedMac(true);
+                      break;
+
+                    case MAX_FRAGMENT_LENGTH:
+                      MaxFragmentLength len = (MaxFragmentLength) e.value();
+                      engine.session().maxLength = len;
+                      engine.session().setApplicationBufferSize(len.maxLength());
+                      break;
+                      
+                    case SERVER_NAME:
+                      requestedNames = (ServerNameList) e.value();
+                      List<String> names
+                        = new ArrayList<String>(requestedNames.size());
+                      for (ServerNameList.ServerName name : requestedNames)
+                        names.add(name.name());
+                      engine.session().putValue("gnu.javax.net.ssl.RequestedServerNames", names);
+                      break;
+
+                    default:
+                      logger.log(Level.INFO, "skipping unsupported extension {0}", e);
+                    }
+                  }
+              }
+            AbstractSessionContext sessions = (AbstractSessionContext)
+              engine.contextImpl.engineGetServerSessionContext();
+            SSLSession s = sessions.getSession(sessionId);
+            if (Debug.DEBUG)
+              logger.logv(Component.SSL_HANDSHAKE, "looked up saved session {0}", s);
+            if (s != null && s.isValid() && (s instanceof SessionImpl))
+              {
+                engine.setSession((SessionImpl) s);
+                continuedSession = true;
+              }
+            else
+              {
+                // We *may* wind up with a badly seeded PRNG, and emit the
+                // same session ID over and over (this did happen to me,
+                // so we add this sanity check just in case).
+                if (engine.session().id().equals(new Session.ID(sessionId)))
+                  {
+                    byte[] newId = new byte[32];
+                    engine.session().random().nextBytes(newId);
+                    engine.session().setId(new Session.ID(newId));
+                  }
+                sessions.put(engine.session());
+              }
+            state = WRITE_SERVER_HELLO;
+          }
+          break;
+
+        // Certificate.
+        //
+        // This message is sent by the client if the server had previously
+        // requested that the client authenticate itself with a certificate,
+        // and if the client has an appropriate certificate available.
+        //
+        // Processing this message will save the client's certificate,
+        // rejecting it if the certificate is not trusted, in preparation
+        // for the certificate verify message that will follow.
+        case READ_CERTIFICATE:
+          {
+            if (handshake.type() != CERTIFICATE)
+              {
+                if (engine.getNeedClientAuth()) // XXX throw better exception.
+                  throw new SSLException("client auth required");
+                state = READ_CLIENT_KEY_EXCHANGE;
+                return HandshakeStatus.NEED_UNWRAP;
+              }
+            
+            Certificate cert = (Certificate) handshake.body();
+            try
+              {
+                engine.session().setPeerVerified(false);
+                X509Certificate[] chain
+                  = cert.certificates().toArray(new X509Certificate[0]);
+                if (chain.length == 0)
+                  throw new CertificateException("no certificates in chain");
+                certVerifier = new CertVerifier(false, chain);
+                tasks.add(certVerifier);
+                engine.session().setPeerCertificates(chain);
+                clientCert = chain[0];
+                // Delay setting 'peerVerified' until CertificateVerify.
+              }
+            catch (CertificateException ce)
+              {
+                if (engine.getNeedClientAuth())
+                  {
+                    SSLPeerUnverifiedException x
+                      = new SSLPeerUnverifiedException("client certificates could not be verified");
+                    x.initCause(ce);
+                    throw x;
+                  }
+              }
+            catch (NoSuchAlgorithmException nsae)
+              {
+                throw new SSLException(nsae);
+              }
+            state = READ_CLIENT_KEY_EXCHANGE;
+          }
+          break;
+
+        // Client Key Exchange.
+        //
+        // The client's key exchange. This message is sent either following
+        // the certificate message, or if no certificate is available or
+        // requested, following the server's hello done message.
+        //
+        // After receipt of this message, the session keys for this
+        // session will have been created.
+        case READ_CLIENT_KEY_EXCHANGE:
+          {
+            if (handshake.type() != CLIENT_KEY_EXCHANGE)
+              throw new SSLException("expecting client key exchange");
+            ClientKeyExchange kex = (ClientKeyExchange) handshake.body();
+            
+            KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm();
+            switch (alg)
+              {
+                case DHE_DSS:
+                case DHE_RSA:
+                case DH_anon:
+                  {
+                    ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
+                      kex.exchangeKeys();
+                    DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
+                    DHPublicKey clientKey =
+                      new GnuDHPublicKey(null, myKey.getParams().getP(),
+                                         myKey.getParams().getG(),
+                                         pub.publicValue());
+                    keyExchangeTask = new DHPhase(clientKey);
+                    tasks.add(keyExchangeTask);
+                  }
+                  break;
+
+                case RSA:
+                  {
+                    EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
+                      kex.exchangeKeys();
+                    keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
+                    tasks.add(keyExchangeTask);
+                  }
+                  break;
+            
+                case PSK:
+                  {
+                    ClientPSKParameters params = (ClientPSKParameters)
+                      kex.exchangeKeys();
+                    generatePSKSecret(params.identity(), null, false);
+                  }
+                  break;
+                  
+                case DHE_PSK:
+                  {
+                    ClientDHE_PSKParameters params = (ClientDHE_PSKParameters)
+                      kex.exchangeKeys();
+                    DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic();
+                    DHPublicKey clientKey =
+                      new GnuDHPublicKey(null, serverKey.getParams().getP(),
+                                         serverKey.getParams().getG(),
+                                         params.params().publicValue());
+                    SecretKey psk = null;
+                    try
+                      {
+                        psk = engine.contextImpl.pskManager.getKey(params.identity());
+                      }
+                    catch (KeyManagementException kme)
+                      {
+                      }
+                    keyExchangeTask = new DHE_PSKGen(clientKey, psk, false);
+                    tasks.add(keyExchangeTask);
+                  }
+                  break;
+                  
+                case RSA_PSK:
+                  {
+                    ClientRSA_PSKParameters params = (ClientRSA_PSKParameters)
+                      kex.exchangeKeys();
+                    SecretKey psk = null;
+                    try
+                      {
+                        psk = engine.contextImpl.pskManager.getKey(params.identity());
+                      }
+                    catch (KeyManagementException kme)
+                      {
+                      }
+                    if (psk == null)
+                      {
+                        byte[] fakeKey = new byte[16];
+                        engine.session().random().nextBytes(fakeKey);
+                        psk = new SecretKeySpec(fakeKey, "DHE_PSK");
+                      }
+                    keyExchangeTask =
+                      new RSA_PSKExchange(params.secret().encryptedSecret(), psk);
+                    tasks.add(keyExchangeTask);
+                  }
+                  break;
+                  
+                case NONE:
+                  {
+                    Inflater inflater = null;
+                    Deflater deflater = null;
+                    if (compression == CompressionMethod.ZLIB)
+                      {
+                        inflater = new Inflater();
+                        deflater = new Deflater();
+                      }
+                    inParams = new InputSecurityParameters(null, null, inflater,
+                                                           engine.session(),
+                                                           engine.session().suite);
+                    outParams = new OutputSecurityParameters(null, null, deflater,
+                                                             engine.session(),
+                                                             engine.session().suite);
+                    engine.session().privateData.masterSecret = new byte[0];
+                  }
+                  break;
+              }
+            // XXX SRP
+            
+            if (clientCert != null)
+              state = READ_CERTIFICATE_VERIFY;
+            else
+              state = READ_FINISHED;
+          }
+          break;
+
+        // Certificate Verify.
+        //
+        // This message is sent following the client key exchange message,
+        // but only when the client included its certificate in a previous
+        // message.
+        //
+        // After receipt of this message, the client's certificate (and,
+        // to a degree, the client's identity) will have been verified.
+        case READ_CERTIFICATE_VERIFY:
+          {
+            if (handshake.type() != CERTIFICATE_VERIFY)
+              throw new SSLException("expecting certificate verify message");
+            
+            CertificateVerify verify = (CertificateVerify) handshake.body();
+            try
+              {
+                verifyClient(verify.signature());
+                if (certVerifier != null && certVerifier.verified())
+                  engine.session().setPeerVerified(true);
+              }
+            catch (SignatureException se)
+              {
+                if (engine.getNeedClientAuth())
+                  throw new SSLException("client auth failed", se);
+              }
+            if (continuedSession)
+              {
+                engine.changeCipherSpec();
+                state = WRITE_FINISHED;
+              }
+            else
+              state = READ_FINISHED;
+          }
+          break;
+          
+        // Finished.
+        //
+        // This message is sent immediately following the change cipher
+        // spec message (which is sent outside of the handshake layer).
+        // After receipt of this message, the session keys for the client
+        // side will have been verified (this is the first message the
+        // client sends encrypted and authenticated with the newly
+        // negotiated keys).
+        //
+        // In the case of a continued session, the client sends its
+        // finished message first. Otherwise, the server will send its
+        // finished message first.
+        case READ_FINISHED:
+          {
+            if (handshake.type() != FINISHED)
+              throw new AlertException(new Alert(Alert.Level.FATAL,
+                                                 Description.UNEXPECTED_MESSAGE));
+
+            Finished clientFinished = (Finished) handshake.body();
+            
+            MessageDigest md5copy = null;
+            MessageDigest shacopy = null;
+            try
+              {
+                md5copy = (MessageDigest) md5.clone();
+                shacopy = (MessageDigest) sha.clone();
+              }
+            catch (CloneNotSupportedException cnse)
+              {
+                // We're improperly configured to use a non-cloneable
+                // md5/sha-1, OR there's a runtime bug.
+                throw new SSLException(cnse);
+              }
+            Finished serverFinished =
+              new Finished(generateFinished(md5copy, shacopy,
+                                            true, engine.session()),
+                                            engine.session().version);
+
+            if (Debug.DEBUG)
+              logger.log(Component.SSL_HANDSHAKE, "server finished: {0}",
+                         serverFinished);
+            
+            if (engine.session().version == ProtocolVersion.SSL_3)
+              {
+                if (!Arrays.equals(clientFinished.md5Hash(),
+                                   serverFinished.md5Hash())
+                    || !Arrays.equals(clientFinished.shaHash(),
+                                      serverFinished.shaHash()))
+                  {
+                    engine.session().invalidate();
+                    throw new SSLException("session verify failed");
+                  }
+              }
+            else
+              {
+                if (!Arrays.equals(clientFinished.verifyData(),
+                                   serverFinished.verifyData()))
+                  {
+                    engine.session().invalidate();
+                    throw new SSLException("session verify failed");
+                  }
+              }
+            
+            if (continuedSession)
+              state = DONE;
+            else
+              {
+                engine.changeCipherSpec();
+                state = WRITE_FINISHED;
+              }
+          }
+          break;
+      }
+
+    handshakeOffset += handshake.length() + 4;
+
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+    if (state.isWriteState())
+      return HandshakeStatus.NEED_WRAP;
+
+    return HandshakeStatus.FINISHED;
+  }
+
+  public @Override HandshakeStatus implHandleOutput (ByteBuffer fragment)
+    throws SSLException
+  {
+    if (Debug.DEBUG)
+      logger.logv(Component.SSL_HANDSHAKE,
+                  "handle output state: {0}; output fragment: {1}",
+                  state, fragment);
+    
+    // Drain the output buffer, if it needs it.
+    if (outBuffer != null && outBuffer.hasRemaining())
+      {
+        int l = Math.min(fragment.remaining(), outBuffer.remaining());
+        fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+        outBuffer.position(outBuffer.position() + l);
+      }
+    
+    if (!fragment.hasRemaining())
+      {
+        if (state.isWriteState() || outBuffer.hasRemaining())
+          return HandshakeStatus.NEED_WRAP;
+        else
+          return HandshakeStatus.NEED_UNWRAP;
+      }
+    
+    // XXX what we need to do here is generate a "stream" of handshake
+    // messages, and insert them into fragment amounts that we have available.
+    // A handshake message can span multiple records, and we can put
+    // multiple records into a single record.
+    //
+    // So, we can have one of two states:
+    //
+    // 1) We have enough space in the record we are creating to push out
+    //    everything we need to on this round. This is easy; we just
+    //    repeatedly fill in these messages in the buffer, so we get something
+    //    that looks like this:
+    //                 ________________________________
+    //       records: |________________________________|
+    //    handshakes: |______|__|__________|
+    //
+    // 2) We can put part of one handshake message in the current record,
+    //    but we must put the rest of it in the following record, or possibly
+    //    more than one following record. So here, we'd see this:
+    //
+    //                 ________________________
+    //       records: |_______|_______|________|
+    //    handshakes: |____|_______|_________|
+    //
+    // We *could* make this a lot easier by just only ever emitting one
+    // record per call, but then we would waste potentially a lot of space
+    // and waste a lot of TCP packets by doing it the simple way. What
+    // we desire here is that we *maximize* our usage of the resources
+    // given to us, and to use as much space in the present fragment as
+    // we can.
+    //
+    // Note that we pretty much have to support this, anyway, because SSL
+    // provides no guarantees that the record size is large enough to
+    // admit *even one* handshake message. Also, callers could call on us
+    // with a short buffer, even though they aren't supposed to.
+    //
+    // This is somewhat complicated by the fact that we don't know, a priori,
+    // how large a handshake message will be until we've built it, and our
+    // design builds the message around the byte buffer.
+    //
+    // Some ways to handle this:
+    //
+    //  1. Write our outgoing handshake messages to a private buffer,
+    //     big enough per message (and, if we run out of space, resize that
+    //     buffer) and push (possibly part of) this buffer out to the
+    //     outgoing buffer. This isn't that great because we'd need to
+    //     store and copy things unnecessarily.
+    //
+    //  2. Build outgoing handshake objects “virtually,” that is, store them
+    //     as collections of objects, then compute the length, and then write
+    //     them to a buffer, instead of making the objects views on
+    //     ByteBuffers for both input and output. This would complicate the
+    //     protocol objects a bit (although, it would amount to doing
+    //     separation between client objects and server objects, which is
+    //     pretty OK), and we still need to figure out how exactly to chunk
+    //     those objects across record boundaries.
+    //
+    //  3. Try to build these objects on the buffer we’re given, but detect
+    //     when we run out of space in the output buffer, and split the
+    //     overflow message. This sounds like the best, but also probably
+    //     the hardest to code.
+output_loop:
+    while (fragment.remaining() >= 4 && state.isWriteState())
+      {
+        switch (state)
+          {
+            // Hello Request.
+            //
+            // This message is sent by the server to initiate a new
+            // handshake, to establish new session keys.
+            case WRITE_HELLO_REQUEST:
+            {
+              Handshake handshake = new Handshake(fragment);
+              handshake.setType(Handshake.Type.HELLO_REQUEST);
+              handshake.setLength(0);
+              fragment.position(fragment.position() + 4);
+              if (Debug.DEBUG)
+                logger.log(Component.SSL_HANDSHAKE, "{0}", handshake);
+              state = READ_CLIENT_HELLO;
+            }
+            break output_loop; // XXX temporary
+            
+            // Server Hello.
+            //
+            // This message is sent immediately following the client hello.
+            // It informs the client of the cipher suite, compression method,
+            // session ID (which may have been a continued session), and any
+            // supported extensions.
+            case WRITE_SERVER_HELLO:
+            {
+              ServerHelloBuilder hello = new ServerHelloBuilder();
+              hello.setVersion(engine.session().version);
+              Random r = hello.random();
+              r.setGmtUnixTime(Util.unixTime());
+              byte[] nonce = new byte[28];
+              engine.session().random().nextBytes(nonce);
+              r.setRandomBytes(nonce);
+              serverRandom = r.copy();
+              hello.setSessionId(engine.session().getId());
+              hello.setCipherSuite(engine.session().suite);
+              hello.setCompressionMethod(compression);
+              if (clientHadExtensions)
+                {
+                  // XXX figure this out.
+                }
+              else // Don't send any extensions.
+                hello.setDisableExtensions(true);
+              
+              if (Debug.DEBUG)
+                logger.log(Component.SSL_HANDSHAKE, "{0}", hello);
+
+              int typeLen = ((Handshake.Type.SERVER_HELLO.getValue() << 24)
+                  | (hello.length() & 0xFFFFFF));
+              fragment.putInt(typeLen);
+
+              outBuffer = hello.buffer();
+              int l = Math.min(fragment.remaining(), outBuffer.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              CipherSuite cs = engine.session().suite;
+              KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm();
+              if (continuedSession)
+                {
+                  byte[][] keys = generateKeys(clientRandom, serverRandom,
+                                               engine.session());
+                  setupSecurityParameters(keys, false, engine, compression);
+                  engine.changeCipherSpec();
+                  state = WRITE_FINISHED;
+                }
+              else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA
+                       || kex == RSA_PSK)
+                {
+                  certLoader = new CertLoader();
+                  tasks.add(certLoader);
+                  state = WRITE_CERTIFICATE;
+                  if (kex == DHE_DSS || kex == DHE_RSA)
+                    {
+                      genDH = new GenDH();
+                      tasks.add(genDH);
+                    }
+                  break output_loop;
+                }
+              else if (kex == PSK)
+                {
+                  state = WRITE_SERVER_KEY_EXCHANGE;
+                }
+              else if (kex == DHE_PSK || kex == DH_anon)
+                {
+                  genDH = new GenDH();
+                  tasks.add(genDH);
+                  state = WRITE_SERVER_KEY_EXCHANGE;
+                  break output_loop;
+                }
+              else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+                {
+                  state = WRITE_CERTIFICATE_REQUEST;
+                }
+              else
+                state = WRITE_SERVER_HELLO_DONE;
+            }
+            break;
+
+            // Certificate.
+            //
+            // This message is sent immediately following the server hello,
+            // IF the cipher suite chosen requires that the server identify
+            // itself (usually, servers must authenticate).
+            case WRITE_CERTIFICATE:
+            {
+              // We must have scheduled a certificate loader to run.
+              assert(certLoader != null);
+              assert(certLoader.hasRun());
+              if (certLoader.thrown() != null)
+                throw new AlertException(new Alert(Alert.Level.FATAL,
+                                                   Alert.Description.HANDSHAKE_FAILURE),
+                                         certLoader.thrown());
+              java.security.cert.Certificate[] chain
+                = engine.session().getLocalCertificates();
+              CertificateBuilder cert = new CertificateBuilder(CertificateType.X509);
+              try
+                {
+                  cert.setCertificates(Arrays.asList(chain));
+                }
+              catch (CertificateException ce)
+                {
+                  throw new SSLException(ce);
+                }
+
+              if (Debug.DEBUG)
+                {
+                  logger.logv(Component.SSL_HANDSHAKE, "my cert:\n{0}", localCert);
+                  logger.logv(Component.SSL_HANDSHAKE, "{0}", cert);
+                }
+              
+              int typeLen = ((CERTIFICATE.getValue() << 24)
+                             | (cert.length() & 0xFFFFFF));
+              fragment.putInt(typeLen);
+
+              outBuffer = cert.buffer();
+              final int l = Math.min(fragment.remaining(), outBuffer.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              CipherSuite s = engine.session().suite;
+              KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+              if (kexalg == DHE_DSS || kexalg == DHE_RSA)
+                {
+                  genDH = new GenDH();
+                  tasks.add(genDH);
+                  state = WRITE_SERVER_KEY_EXCHANGE;
+                  break output_loop;
+                }
+              else if (kexalg == RSA_PSK)
+                state = WRITE_SERVER_KEY_EXCHANGE;
+              else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+                {
+                  state = WRITE_CERTIFICATE_REQUEST;
+                }
+              else
+                state = WRITE_SERVER_HELLO_DONE;
+            }
+            break output_loop; // XXX temporary
+
+            // Server key exchange.
+            //
+            // This message is sent, following the certificate if sent,
+            // otherwise following the server hello, IF the chosen cipher
+            // suite requires that the server send explicit key exchange
+            // parameters (that is, if the key exchange parameters are not
+            // implicit in the server's certificate).
+            case WRITE_SERVER_KEY_EXCHANGE:
+            {
+              KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+              
+              ByteBuffer paramBuffer = null;
+              ByteBuffer sigBuffer = null;
+              if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon
+                  || kex == DHE_PSK)
+                {
+                  assert(genDH != null);
+                  assert(genDH.hasRun());
+                  if (genDH.thrown() != null)
+                    throw new AlertException(new Alert(Alert.Level.FATAL,
+                                                       Alert.Description.HANDSHAKE_FAILURE),
+                                             genDH.thrown());
+                  assert(dhPair != null);
+                  initDiffieHellman((DHPrivateKey) dhPair.getPrivate(),
+                                    engine.session().random());
+                  paramBuffer = genDH.paramsBuffer;
+                  sigBuffer = genDH.sigBuffer;
+                  
+                  if (kex == DHE_PSK)
+                    {
+                      String identityHint
+                        = engine.contextImpl.pskManager.chooseIdentityHint();
+                      ServerDHE_PSKParameters psk =
+                        new ServerDHE_PSKParameters(identityHint, paramBuffer);
+                      paramBuffer = psk.buffer();
+                    }
+                }
+              if (kex == RSA_PSK)
+                {
+                  String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+                  if (idHint != null)
+                    {
+                      ServerRSA_PSKParameters params
+                        = new ServerRSA_PSKParameters(idHint);
+                      paramBuffer = params.buffer();
+                    }
+                }
+              if (kex == PSK)
+                {
+                  String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+                  if (idHint != null)
+                    {
+                      ServerPSKParameters params
+                        = new ServerPSKParameters(idHint);
+                      paramBuffer = params.buffer();
+                    }
+                }
+              // XXX handle SRP
+              
+              if (paramBuffer != null)
+                {
+                  ServerKeyExchangeBuilder ske
+                    = new ServerKeyExchangeBuilder(engine.session().suite);
+                  ske.setParams(paramBuffer);
+                  if (sigBuffer != null)
+                    ske.setSignature(sigBuffer);
+                  
+                  if (Debug.DEBUG)
+                    logger.log(Component.SSL_HANDSHAKE, "{0}", ske);
+                  
+                  outBuffer = ske.buffer();
+                  int l = Math.min(fragment.remaining(), outBuffer.remaining());
+                  fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24)
+                                  | (ske.length() & 0xFFFFFF));
+                  fragment.put((ByteBuffer) outBuffer.duplicate().limit
+                               (outBuffer.position() + l));
+                  outBuffer.position(outBuffer.position() + l);
+                }
+              
+              if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+                state = WRITE_CERTIFICATE_REQUEST;
+              else
+                state = WRITE_SERVER_HELLO_DONE;
+            }
+            break;
+
+            // Certificate Request.
+            //
+            // This message is sent when the server desires or requires
+            // client authentication with a certificate; if it is sent, it
+            // will be sent just after the Certificate or Server Key
+            // Exchange messages, whichever is sent. If neither of the
+            // above are sent, it will be the message that follows the
+            // server hello.
+            case WRITE_CERTIFICATE_REQUEST:
+            {
+              CertificateRequestBuilder req = new CertificateRequestBuilder();
+              
+              List<ClientCertificateType> types
+                = new ArrayList<ClientCertificateType>(4);
+              types.add(ClientCertificateType.RSA_SIGN);
+              types.add(ClientCertificateType.RSA_FIXED_DH);
+              types.add(ClientCertificateType.DSS_SIGN);
+              types.add(ClientCertificateType.DSS_FIXED_DH);
+              req.setTypes(types);
+              
+              X509Certificate[] anchors
+                = engine.contextImpl.trustManager.getAcceptedIssuers();
+              List<X500Principal> issuers
+                = new ArrayList<X500Principal>(anchors.length);
+              for (X509Certificate cert : anchors)
+                issuers.add(cert.getIssuerX500Principal());
+              req.setAuthorities(issuers);
+              
+              if (Debug.DEBUG)
+                logger.log(Component.SSL_HANDSHAKE, "{0}", req);
+              
+              fragment.putInt((CERTIFICATE_REQUEST.getValue() << 24)
+                              | (req.length() & 0xFFFFFF));
+              
+              outBuffer = req.buffer();
+              int l = Math.min(outBuffer.remaining(), fragment.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+              
+              state = WRITE_SERVER_HELLO_DONE;
+            }
+            break;
+
+            // Server Hello Done.
+            //
+            // This message is always sent by the server, to terminate its
+            // side of the handshake. Since the server's handshake message
+            // may comprise multiple, optional messages, this sentinel
+            // message lets the client know when the server's message stream
+            // is complete.
+            case WRITE_SERVER_HELLO_DONE:
+            {
+              // ServerHelloDone is zero-length; just put in the type
+              // field.
+              fragment.putInt(SERVER_HELLO_DONE.getValue() << 24);
+              if (Debug.DEBUG)
+                logger.logv(Component.SSL_HANDSHAKE, "writing ServerHelloDone");
+              state = READ_CERTIFICATE;
+            }
+            break output_loop; // XXX temporary
+            
+            // Finished.
+            //
+            // This is always sent by the server to verify the keys that the
+            // server will use to encrypt and authenticate. In a full
+            // handshake, this message will be sent after the client's
+            // finished message; in an abbreviated handshake (with a continued
+            // session) the server sends its finished message first.
+            //
+            // This message follows the change cipher spec message, which is
+            // sent out-of-band in a different SSL content-type.
+            //
+            // This is the first message that the server will send encrypted
+            // and authenticated with the newly negotiated session keys.
+            case WRITE_FINISHED:
+            {
+              MessageDigest md5copy = null;
+              MessageDigest shacopy = null;
+              try
+                {
+                  md5copy = (MessageDigest) md5.clone();
+                  shacopy = (MessageDigest) sha.clone();
+                }
+              catch (CloneNotSupportedException cnse)
+                {
+                  // We're improperly configured to use a non-cloneable
+                  // md5/sha-1, OR there's a runtime bug.
+                  throw new SSLException(cnse);
+                }
+              outBuffer
+                = generateFinished(md5copy, shacopy, false,
+                                   engine.session());
+              
+              fragment.putInt((FINISHED.getValue() << 24)
+                              | outBuffer.remaining() & 0xFFFFFF);
+              
+              int l = Math.min(outBuffer.remaining(), fragment.remaining());
+              fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+              outBuffer.position(outBuffer.position() + l);
+
+              if (continuedSession)
+                state = READ_FINISHED;
+              else
+                state = DONE;
+            }
+            break;
+          }
+      }
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+    if (state.isWriteState() || outBuffer.hasRemaining())
+      return HandshakeStatus.NEED_WRAP;
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+    
+    return HandshakeStatus.FINISHED;
+  }
+  
+  @Override HandshakeStatus status()
+  {
+    if (!tasks.isEmpty())
+      return HandshakeStatus.NEED_TASK;
+    if (state.isReadState())
+      return HandshakeStatus.NEED_UNWRAP;
+    if (state.isWriteState())
+      return HandshakeStatus.NEED_WRAP;
+    
+    return HandshakeStatus.FINISHED;
+  }
+
+  @Override void checkKeyExchange() throws SSLException
+  {
+    if (continuedSession) // No key exchange needed.
+      return;
+    KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+    if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one.
+      return;
+    if (keyExchangeTask == null) // An error if we never created one.
+      throw new AlertException(new Alert(Alert.Level.FATAL,
+                                         Alert.Description.INTERNAL_ERROR));
+    if (!keyExchangeTask.hasRun()) // An error if the caller never ran it.
+      throw new AlertException(new Alert(Alert.Level.FATAL,
+                                         Alert.Description.INTERNAL_ERROR));
+    if (keyExchangeTask.thrown() != null) // An error was thrown.
+      throw new AlertException(new Alert(Alert.Level.FATAL,
+                                         Alert.Description.HANDSHAKE_FAILURE),
+                               keyExchangeTask.thrown());
+  }
+  
+  @Override void handleV2Hello(ByteBuffer hello)
+  {
+    int len = hello.getShort(0) & 0x7FFF;
+    md5.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+    sha.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+    helloV2 = true;
+  }
+
+  private ByteBuffer signParams(ByteBuffer serverParams)
+    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
+  {
+    SignatureAlgorithm alg = engine.session().suite.signatureAlgorithm();
+    java.security.Signature sig
+      = java.security.Signature.getInstance(alg.algorithm());
+    PrivateKey key = engine.contextImpl.keyManager.getPrivateKey(keyAlias);
+    if (Debug.DEBUG_KEY_EXCHANGE)
+      logger.logv(Component.SSL_HANDSHAKE, "server key: {0}", key);
+    sig.initSign(key);
+    sig.update(clientRandom.buffer());
+    sig.update(serverRandom.buffer());
+    sig.update(serverParams);
+    byte[] sigVal = sig.sign();
+    Signature signature = new Signature(sigVal, engine.session().suite.signatureAlgorithm());
+    return signature.buffer();
+  }
+  
+  private void verifyClient(byte[] sigValue) throws SSLException, SignatureException
+  {
+    MessageDigest md5copy = null;
+    MessageDigest shacopy = null;
+    try
+      {
+        md5copy = (MessageDigest) md5.clone();
+        shacopy = (MessageDigest) sha.clone();
+      }
+    catch (CloneNotSupportedException cnse)
+      {
+        // Mis-configured with non-cloneable digests.
+        throw new SSLException(cnse);
+      }
+    byte[] toSign = null;
+    if (engine.session().version == ProtocolVersion.SSL_3)
+      toSign = genV3CertificateVerify(md5copy, shacopy, engine.session());
+    else
+      {
+        if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+          toSign = Util.concat(md5copy.digest(), shacopy.digest());
+        else
+          toSign = shacopy.digest();
+      }
+    
+    try
+      {
+        java.security.Signature sig = java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().toString());
+        sig.initVerify(clientCert);
+        sig.update(toSign);
+        sig.verify(sigValue);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new SSLException(ike);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new SSLException(nsae);
+      }
+  }
+  
+  // Delegated tasks.
+
+  class CertLoader extends DelegatedTask
+  {
+    CertLoader()
+    {
+    }
+    
+    public void implRun() throws SSLException
+    {
+      KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm();
+      X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+      Principal[] issuers = null; // XXX use TrustedAuthorities extension.
+      keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine);
+      if (keyAlias == null)
+        throw new SSLException("no certificates available");
+      X509Certificate[] chain = km.getCertificateChain(keyAlias);
+      engine.session().setLocalCertificates(chain);
+      localCert = chain[0];
+      serverKey = km.getPrivateKey(keyAlias);
+      if (kexalg == DH_DSS || kexalg == DH_RSA)
+        dhPair = new KeyPair(localCert.getPublicKey(),
+                             km.getPrivateKey(keyAlias));
+    }
+  }
+  
+  /**
+   * Delegated task for generating Diffie-Hellman parameters.
+   */
+  private class GenDH extends DelegatedTask
+  {
+    ByteBuffer paramsBuffer;
+    ByteBuffer sigBuffer;
+
+    protected void implRun()
+      throws NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+             InvalidKeyException, SignatureException
+    {
+      KeyPairGenerator dhGen = KeyPairGenerator.getInstance("DH");
+      DHParameterSpec dhparams = DiffieHellman.getParams().getParams();
+      dhGen.initialize(dhparams, engine.session().random());
+      dhPair = dhGen.generateKeyPair();
+      DHPublicKey pub = (DHPublicKey) dhPair.getPublic();
+      
+      // Generate the parameters message.
+      ServerDHParams params = new ServerDHParams(pub.getParams().getP(),
+                                                 pub.getParams().getG(),
+                                                 pub.getY());
+      paramsBuffer = params.buffer();
+      
+      // Sign the parameters, if needed.
+      if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+        {
+          sigBuffer = signParams(paramsBuffer);
+          paramsBuffer.rewind();
+        }
+      if (Debug.DEBUG_KEY_EXCHANGE)
+        logger.logv(Component.SSL_KEY_EXCHANGE,
+                    "Diffie-Hellman public:{0} private:{1}",
+                    dhPair.getPublic(), dhPair.getPrivate());
+    }
+  }
+  
+  class RSAKeyExchange extends DelegatedTask
+  {
+    private final byte[] encryptedPreMasterSecret;
+
+    RSAKeyExchange(byte[] encryptedPreMasterSecret)
+    {
+      this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+    }
+    
+    public void implRun()
+      throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+             NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+    {
+      Cipher rsa = Cipher.getInstance("RSA");
+      rsa.init(Cipher.DECRYPT_MODE, serverKey);
+      rsa.init(Cipher.DECRYPT_MODE, localCert);
+      preMasterSecret = rsa.doFinal(encryptedPreMasterSecret);
+      generateMasterSecret(clientRandom, serverRandom, engine.session());
+      byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+      setupSecurityParameters(keys, false, engine, compression);
+    }
+  }
+  
+  class RSA_PSKExchange extends DelegatedTask
+  {
+    private final byte[] encryptedPreMasterSecret;
+    private final SecretKey psKey;
+    
+    RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)
+    {
+      this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+      this.psKey = psKey;
+    }
+    
+    public @Override void implRun()
+      throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+             NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+    {
+      Cipher rsa = Cipher.getInstance("RSA");
+      rsa.init(Cipher.DECRYPT_MODE, serverKey);
+      rsa.init(Cipher.DECRYPT_MODE, localCert);
+      byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret);
+      byte[] psSecret = psKey.getEncoded();
+      preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4];
+      preMasterSecret[0] = (byte) (rsaSecret.length >>> 8);
+      preMasterSecret[1] = (byte)  rsaSecret.length;
+      System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length);
+      preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8);
+      preMasterSecret[rsaSecret.length + 3] = (byte)  psSecret.length;
+      System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4,
+                       psSecret.length);
+      
+      generateMasterSecret(clientRandom, serverRandom, engine.session());
+      byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+      setupSecurityParameters(keys, false, engine, compression);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerHello.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,231 @@
+/* ServerHello.java -- SSL ServerHello message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The server hello message.
+ *
+ * <pre>
+struct
+{
+  ProtocolVersion server_version;
+  Random random;
+  SessionID session_id;
+  CipherSuite cipher_suite;
+  CompressionMethod compression_method;
+  Extensions server_hello_extension_list&lt;0..2^16-1&gt;
+} ServerHello;
+</pre>
+ *
+ * <p>Server hello messages may contain extra data after the
+ * <tt>compression_method</tt> field, which are interpreted as
+ * extensions to the basic handshake.
+ */
+public class ServerHello implements Handshake.Body
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  protected static final int RANDOM_OFFSET = 2;
+  protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+  protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+
+  protected ByteBuffer buffer;
+  protected boolean disableExtensions;
+  
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public ServerHello (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+    disableExtensions = false;
+  }
+
+  public int length ()
+  {
+    int sessionLen = buffer.get(SESSID_OFFSET) & 0xFF;
+    int len = SESSID_OFFSET2 + sessionLen + 3;
+    int elen = 0;
+    if (!disableExtensions && len + 1 < buffer.limit()
+        && (elen = buffer.getShort(len)) != 0)
+      len += 2 + elen;
+    return len;
+  }
+
+  /**
+   * Returns the server's protocol version. This will read two bytes
+   * from the beginning of the underlying buffer, and return an
+   * instance of the appropriate {@link ProtocolVersion}; if the
+   * version read is a supported version, this method returns a static
+   * constant instance.
+   *
+   * @return The server's protocol version.
+   */
+  public ProtocolVersion version()
+  {
+    return ProtocolVersion.getInstance (buffer.getShort (0));
+  }
+
+  /**
+   * Returns the server's random value. This method returns a
+   * lightwieght wrapper around the existing bytes; modifications to
+   * the underlying buffer will modify the returned object, and
+   * vice-versa.
+   *
+   * @return The server's random value.
+   */
+  public Random random()
+  {
+    ByteBuffer randomBuf =
+      ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+       .limit (SESSID_OFFSET)).slice ();
+    return new Random (randomBuf);
+  }
+
+  /**
+   * Returns the session ID. This method returns a new byte array with
+   * the session ID bytes.
+   *
+   * @return The session ID.
+   */
+  public byte[] sessionId()
+  {
+    int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+    byte[] sessionId = new byte[idlen];
+    buffer.position (SESSID_OFFSET2);
+    buffer.get (sessionId);
+    return sessionId;
+  }
+
+  /**
+   * Returns the server's chosen cipher suite. The returned cipher
+   * suite will be "resolved" to this structure's version.
+   *
+   * @return The server's chosen cipher suite.
+   */
+  public CipherSuite cipherSuite()
+  {
+    int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF);
+    return CipherSuite.forValue(buffer.getShort(offset)).resolve();
+  }
+
+  /**
+   * Returns the server's chosen compression method.
+   *
+   * @return The chosen compression method.
+   */
+  public CompressionMethod compressionMethod()
+  {
+    int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2;
+    return CompressionMethod.getInstance(buffer.get(offset) & 0xFF);
+  }
+
+  public int extensionsLength()
+  {
+    int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+    if (offset + 1 >= buffer.limit())
+      return 0;
+    return buffer.getShort(offset) & 0xFFFF;
+  }
+  
+  public ExtensionList extensions ()
+  {
+    int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+    if (offset + 1 >= buffer.limit())
+      return null;
+    int len = buffer.getShort(offset) & 0xFFFF;
+    if (len == 0)
+      len = buffer.limit() - offset - 2;
+    ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+                       .limit(offset + len + 2)).slice();
+    return new ExtensionList(ebuf);
+  }
+
+  public String toString()
+  {
+    return toString(null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println ("struct {");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix += prefix;
+    out.print (subprefix);
+    out.print ("version: ");
+    out.print (version ());
+    out.println (";");
+    out.print (subprefix);
+    out.println ("random:");
+    out.println (random ().toString (subprefix));
+    out.print (subprefix);
+    out.print ("sessionId:         ");
+    out.print (Util.toHexString(sessionId (), ':'));
+    out.println (";");
+    out.print (subprefix);
+    out.print ("cipherSuite:       ");
+    out.print (cipherSuite ());
+    out.println (";");
+    out.print (subprefix);
+    out.print ("compressionMethod: ");
+    out.print (compressionMethod ());
+    out.println (";");
+    ExtensionList exts = extensions ();
+    out.print (subprefix);
+    out.println ("extensions:");
+    out.println (exts != null ? exts.toString (subprefix+"  ")
+                                : subprefix + "  (nil)");
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("} ServerHello;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerHelloBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,131 @@
+/* ServerHelloBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author csm
+ *
+ */
+public class ServerHelloBuilder extends ServerHello implements Builder
+{
+  public ServerHelloBuilder()
+  {
+    // Allocate a large enough buffer to hold a hello with the maximum
+    // size session ID, and no extensions.
+    super(ByteBuffer.allocate(SESSID_OFFSET2 + 35));
+  }
+
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+  }
+  
+  // We don't reallocate the buffer in any of the following methods,
+  // because we always allocate a large enough buffer for the base
+  // object in the constructor.
+  
+  public void setVersion (final ProtocolVersion version)
+  {
+    buffer.putShort (0, (short) version.rawValue ());
+  }
+
+  public void setSessionId (final byte[] sessionId)
+  {
+    setSessionId (sessionId, 0, sessionId.length);
+  }
+
+  public void setSessionId (final byte[] sessionId, final int offset,
+                            final int length)
+  {
+    if (length < 0 || length > 32)
+      throw new IllegalArgumentException("length must be between 0 and 32");
+    buffer.put(SESSID_OFFSET, (byte) length);
+    ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2))
+      .put(sessionId, offset, length);
+  }
+
+  public void setCipherSuite (final CipherSuite suite)
+  {
+    int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 1;
+    ((ByteBuffer) buffer.duplicate().position(offset)).put(suite.id());
+  }
+
+  public void setCompressionMethod (final CompressionMethod comp)
+  {
+    int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 3;
+    buffer.put (offset, (byte) comp.getValue ());
+  }
+
+  // For extensions, we do reallocate the buffer.
+  
+  public void setDisableExtensions(boolean disable)
+  {
+    disableExtensions = disable;
+  }
+  
+  public void setExtensionsLength (final int length)
+  {
+    if (length < 0 || length > 16384)
+      throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+    int needed = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 5 + length;
+    if (buffer.capacity() < needed)
+      ensureCapacity(needed);
+    buffer.putShort (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3,
+                     (short) length);
+  }
+  
+  public void setExtensions(ByteBuffer extensions)
+  {
+    extensions = (ByteBuffer)
+      extensions.duplicate().limit(extensions.position() + extensionsLength());
+    ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2
+                                              + (buffer.get(SESSID_OFFSET) & 0xFF)
+                                              )).put(extensions);
+  }
+  
+  public void ensureCapacity(int newCapacity)
+  {
+    ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+    newBuffer.put(buffer);
+    newBuffer.position(0);
+    buffer = newBuffer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerHelloDone.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,66 @@
+/* ServerHelloDone.java -- SSL ServerHelloDone message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * An empty message that signals that the server is finished sending
+ * its handshake data.
+ *
+ * <pre>struct { } ServerHelloDone;</pre>
+ */
+public class ServerHelloDone implements Handshake.Body
+{
+  public ServerHelloDone () { }
+
+  public int length ()
+  {
+    return 0;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    return ((prefix != null ? prefix : "")
+            + "struct { } ServerHelloDone;");
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerKeyExchange.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,173 @@
+/* ServerKeyExchange.java -- SSL ServerKeyExchange message.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The server key exchange message.
+ *
+ * <pre>
+struct
+{
+  select (KeyExchangeAlgorithm)
+  {
+    case diffie_hellman:
+      ServerDHParams params;
+      Signature signed_params;
+    case rsa:
+      ServerRSAParams params;
+      Signature signed_params;
+    case srp:
+      ServerSRPParams params;
+      Signature signed_params;
+  };
+} ServerKeyExchange;
+</pre>
+ */
+public class ServerKeyExchange implements Handshake.Body
+{
+
+  protected ByteBuffer buffer;
+  protected final CipherSuite suite;
+
+  public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite)
+  {
+    suite.getClass();
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    this.suite = suite;
+  }
+
+  public int length ()
+  {
+    if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
+      return 0;
+    int len = 0;
+    ServerKeyExchangeParams params = params();
+    Signature sig = signature();
+    if (params != null)
+      len += params.length();
+    if (sig != null)
+      len += sig.length();
+    return len;
+  }
+
+  /**
+   * Returns the server's key exchange parameters. The value returned will
+   * depend on the key exchange algorithm this object was created with.
+   *
+   * @return The server's key exchange parameters.
+   */
+  public ServerKeyExchangeParams params ()
+  {
+    KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm ();
+    if (kex == KeyExchangeAlgorithm.RSA)
+      return new ServerRSAParams(buffer.duplicate ());
+    else if (kex == KeyExchangeAlgorithm.DHE_DSS
+             || kex == KeyExchangeAlgorithm.DHE_RSA
+             || kex == KeyExchangeAlgorithm.DH_anon)
+      return new ServerDHParams(buffer.duplicate());
+//     else if (kex.equals (KeyExchangeAlgorithm.SRP))
+//       return new ServerSRPParams (buffer.duplicate ());
+    else if (kex == KeyExchangeAlgorithm.NONE)
+      return null;
+    else if (kex == KeyExchangeAlgorithm.DHE_PSK)
+      return new ServerDHE_PSKParameters(buffer.duplicate());
+    else if (kex == KeyExchangeAlgorithm.PSK)
+      return new ServerPSKParameters(buffer.duplicate());
+    else if (kex == KeyExchangeAlgorithm.RSA_PSK)
+      return new ServerPSKParameters(buffer.duplicate());
+    throw new IllegalArgumentException ("unsupported key exchange: " + kex);
+  }
+
+  /**
+   * Returns the digital signature made over the key exchange parameters.
+   *
+   * @return The signature.
+   */
+  public Signature signature ()
+  {
+    KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm();
+    if (kex == KeyExchangeAlgorithm.NONE
+        || kex == KeyExchangeAlgorithm.DH_anon
+        || kex == KeyExchangeAlgorithm.DHE_PSK
+        || kex == KeyExchangeAlgorithm.PSK
+        || kex == KeyExchangeAlgorithm.RSA_PSK)
+      return null;
+    ServerKeyExchangeParams params = params();
+    ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice ();
+    return new Signature (sigbuf, suite.signatureAlgorithm ());
+  }
+
+  public String toString()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print (prefix);
+    out.println("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  algorithm: ");
+    out.print (suite.keyExchangeAlgorithm ());
+    out.println (";");
+    if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
+      {
+        if (prefix != null) out.print (prefix);
+        out.println ("  parameters:");
+        out.println (params ().toString (prefix != null ? prefix+"  " : "  "));
+      }
+    if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS))
+      {
+        if (prefix != null) out.print (prefix);
+        out.println ("  signature:");
+        out.println (signature ().toString (prefix != null ? prefix+"  " : "  "));
+      }
+    if (prefix != null) out.print (prefix);
+    out.print ("} ServerKeyExchange;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,89 @@
+/* ServerKeyExchangeBuilder.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Builder for {@link ServerKeyExchange} objects.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerKeyExchangeBuilder extends ServerKeyExchange
+    implements Builder
+{
+  public ServerKeyExchangeBuilder(final CipherSuite suite)
+  {
+    super(ByteBuffer.allocate(1024), suite);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+  }
+
+  public void setParams(ByteBuffer params)
+  {
+    if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+      throw new IllegalArgumentException("key exchange algorithm is none");
+    ensureCapacity(params.remaining());
+    buffer.duplicate().put(params);
+  }
+  
+  public void setSignature(ByteBuffer signature)
+  {
+    if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+      throw new IllegalArgumentException("key exchange algorithm is none");
+    int paramsLen = params().length();
+    ensureCapacity(paramsLen + signature.remaining());
+    ((ByteBuffer) buffer.duplicate().position(paramsLen)).put(signature);
+  }
+  
+  public void ensureCapacity(int capacity)
+  {
+    if (buffer.capacity() >= capacity)
+      return;
+    ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+    newBuffer.duplicate().put(buffer);
+    buffer = newBuffer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,50 @@
+/* ServerKeyExchangeParams.java -- Server key exchange parameters interface.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * A parameter structure sent by the server in an SSL key exchange.
+ *
+ * @see ServerRSAParams
+ * @see ServerDHParams
+ */
+interface ServerKeyExchangeParams extends Constructed
+{
+  KeyExchangeAlgorithm algorithm ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerNameList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,311 @@
+/* ServerNameList.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The ServerName extension.
+ * 
+ * <pre>
+ struct {
+   NameType name_type;
+   select (name_type) {
+     case host_name: HostName;
+   } name;
+} ServerName;
+
+enum {
+  host_name(0), (255)
+} NameType;
+
+opaque HostName<1..2^16-1>;
+
+struct {
+  ServerName server_name_list<1..2^16-1>
+} ServerNameList;</pre>
+ *
+ * <p><b>Implementation note: this class does not currently contain a
+ * <code>set</code> method. If you are modifying this list, then use the
+ * {@link #get(int)} method, and modify the returned {@link ServerName}.
+ *
+ * @author csm
+ */
+public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName>
+{
+  private ByteBuffer buffer;
+  
+  public ServerNameList (final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  public ServerNameList(List<ServerName> names)
+  {
+    int length = 2;
+    for (ServerName name : names)
+      length += name.length();
+    buffer = ByteBuffer.allocate(length);
+    buffer.putShort((short) (length - 2));
+    for (ServerName name : names)
+      buffer.put(name.buffer());
+    buffer.rewind();
+  }
+
+  public int length()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+  
+  public int size()
+  {
+    int n = 0;
+    final int len = length();
+    for (int i = 2; i < len; )
+      {
+        int l = buffer.getShort(i+1);
+        i += l + 3;
+        n++;
+      }
+    return n;
+  }
+  
+  public ServerName get (int index)
+  {
+    final int len = length();
+    if (len == 0)
+      throw new IndexOutOfBoundsException("0; " + index);
+    int n = 0;
+    int i;
+    int l = buffer.getShort(3);
+    for (i = 2; i < len && n < index; )
+      {
+        l = buffer.getShort(i+1);
+        i += l + 3;
+        n++;
+      }
+    if (n < index)
+      throw new IndexOutOfBoundsException(n + "; " + index);
+    ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice();
+    return new ServerName (buf);
+  }
+  
+  public void setLength(final int newLength)
+  {
+    if (newLength < 0 || newLength > 65535)
+      throw new IllegalArgumentException("length must be between 0 and 65535");
+    buffer.putShort(0, (short) newLength);
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println ("ServerNameList {");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix = prefix + subprefix;
+    for (ServerName name : this)
+      {
+        out.println (name.toString(subprefix));
+      }
+    if (prefix != null) out.print(prefix);
+    out.print ("};");
+    return str.toString();
+  }
+  
+  public java.util.Iterator<ServerName> iterator()
+  {
+    return new Iterator();
+  }
+
+  public class Iterator implements java.util.Iterator<ServerName>
+  {
+    private int index;
+    
+    public Iterator()
+    {
+      index = 0;
+    }
+    
+    public boolean hasNext()
+    {
+      return index < size();
+    }
+    
+    public ServerName next() throws NoSuchElementException
+    {
+      try
+        {
+          return get (index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException();
+        }
+    }
+    
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  public static class ServerName implements Constructed
+  {
+    private ByteBuffer buffer;
+    
+    public ServerName(final ByteBuffer buffer)
+    {
+      this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+    }
+    
+    public ServerName(NameType type, String name)
+    {
+      CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder();
+      ByteBuffer nameBuf = null;
+      try
+        {
+          nameBuf = utf8.encode(CharBuffer.wrap(name));
+        }
+      catch (CharacterCodingException cce)
+        {
+          // We don't expect this to happen; it's UTF-8.
+          throw new IllegalArgumentException(cce);
+        }
+      int length = 3 + nameBuf.remaining();
+      buffer = ByteBuffer.allocate(length);
+      buffer.put((byte) type.getValue());
+      buffer.putShort((short) (length - 3));
+      buffer.put(nameBuf);
+      buffer.rewind();
+    }
+    
+    public int length()
+    {
+      return (buffer.getShort(1) & 0xFFFF) + 3;
+    }
+    
+    public ByteBuffer buffer()
+    {
+      return (ByteBuffer) buffer.duplicate().limit(length());
+    }
+
+    public NameType type()
+    {
+      int v = (buffer.get(0) & 0xFF);
+      if (v == 0)
+        {
+          return NameType.HOST_NAME;
+        }
+      throw new IllegalArgumentException ("illegal name type: " + v);
+    }
+    
+    public String name()
+    {
+      int len = length();
+      Charset cs = Charset.forName ("UTF-8");
+      return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString();
+    }
+    
+    public String toString()
+    {
+      return toString (null);
+    }
+    
+    public String toString(String prefix)
+    {
+      StringWriter str = new StringWriter();
+      PrintWriter out = new PrintWriter(str);
+      if (prefix != null) out.print (prefix);
+      out.println ("struct {");
+      if (prefix != null) out.print (prefix);
+      out.print ("  name_type = ");
+      out.print (type());
+      out.println (";");
+      if (prefix != null) out.print (prefix);
+      out.print ("  server_name = ");
+      out.print (name());
+      out.println (";");
+      if (prefix != null) out.print (prefix);
+      out.print ("} ServerName;");
+      return str.toString();
+    }
+  }
+
+  public static enum NameType
+  {
+    HOST_NAME (0);
+    
+    private final int value;
+    
+    private NameType (int value)
+    {
+      this.value = value;
+    }
+    
+    public int getValue()
+    {
+      return value;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerPSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,127 @@
+/* ServerPSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. &ast;/
+              case psk:  /* NEW &ast;/
+                  opaque psk_identity_hint&lt;0..2^16-1&gt;;
+          };
+      } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerPSKParameters implements Builder, Constructed, ServerKeyExchangeParams
+{
+  private ByteBuffer buffer;
+  
+  public ServerPSKParameters(ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  public ServerPSKParameters(String identityHint)
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer identityHintBuffer = utf8.encode(identityHint);
+    buffer = ByteBuffer.allocate(2 + identityHintBuffer.remaining());
+    buffer.putShort((short) identityHintBuffer.remaining());
+    buffer.put(identityHintBuffer);
+    buffer.rewind();
+  }
+  
+  public KeyExchangeAlgorithm algorithm()
+  {
+    return KeyExchangeAlgorithm.PSK;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Builder#buffer()
+   */
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#length()
+   */
+  public int length()
+  {
+    return (buffer.getShort(0) & 0xFFFF) + 2;
+  }
+  
+  public String identityHint()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+  }
+
+  public @Override String toString()
+  {
+    return toString(null);
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+   */
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    if (prefix != null) out.print(prefix);
+    out.print("  identity_hint = ");
+    out.print(identityHint());
+    out.println(";");
+    if (prefix != null) out.print(prefix);
+    out.print("} ServerPSKParamaters;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerRSAParams.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,163 @@
+/* ServerRSAParams.java -- The server's RSA parameters.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/**
+ * The ServerRSAParams structure.
+ *
+ * <pre>
+struct
+{
+  opaque rsa_modulus&lt;1..2^16-1&gt;;
+  opaque rsa_exponent&lt;1..2^16-1&gt;;
+} ServerRSAParams;
+</pre>
+ */
+public class ServerRSAParams implements ServerKeyExchangeParams
+{
+
+  private final ByteBuffer buffer;
+
+  public ServerRSAParams (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+  }
+
+  public KeyExchangeAlgorithm algorithm ()
+  {
+    return KeyExchangeAlgorithm.RSA;
+  }
+
+  public int length ()
+  {
+    int offset = buffer.getShort (0) & 0xFFFF;
+    return (buffer.getShort (offset + 2) & 0xFFFF) + offset + 4;
+  }
+
+  /**
+   * Gets the modulus field.
+   *
+   * @return The modulus.
+   */
+  public BigInteger modulus ()
+  {
+    int len = buffer.getShort (0) & 0xFFFF;
+    byte[] buf = new byte[len];
+    buffer.position (2);
+    buffer.get (buf);
+    return new BigInteger (1, buf);
+  }
+
+  /**
+   * Returns the exponent field.
+   *
+   * @return The exponent.
+   */
+  public BigInteger exponent ()
+  {
+    int off = (buffer.getShort (0) & 0xFFFF) + 2;
+    int len = buffer.getShort (off) & 0xFFFF;
+    byte[] buf = new byte[len];
+    buffer.position (off + 2);
+    buffer.get (buf);
+    return new BigInteger (1, buf);
+  }
+
+  /**
+   * Sets the modulus.
+   *
+   * @param modulus The modulus.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writable.
+   */
+  public void setModulus (final BigInteger modulus)
+  {
+    byte[] buf = modulus.toByteArray ();
+    int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+    int offset = (buf[0] == 0x00 ? 1 : 0);
+    buffer.putShort (0, (short) length);
+    buffer.position (2);
+    buffer.put (buf, offset, length);
+  }
+
+  /**
+   * Sets the exponent.
+   *
+   * @param exponent The exponent.
+   * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+   * is not writeable.
+   */
+  public void setExponent (final BigInteger exponent)
+  {
+    byte[] buf = exponent.toByteArray ();
+    int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+    int offset = (buf[0] == 0x00 ? 1 : 0);
+    int where = (buffer.getShort (0) & 0xFFFF) + 2;
+    buffer.putShort (where, (short) length);
+    buffer.position (where + 2);
+    buffer.put (buf, offset, length);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.print ("  rsa_modulus:  ");
+    out.println (modulus ().toString (16));
+    if (prefix != null) out.print (prefix);
+    out.print ("  rsa_exponent: ");
+    out.println (exponent ());
+    if (prefix != null) out.print (prefix);
+    out.print ("} ServerRSAParams;");
+    return str.toString ();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,62 @@
+/* ServerRSA_PSKParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerRSA_PSKParameters extends ServerPSKParameters
+{
+  public ServerRSA_PSKParameters(ByteBuffer buffer)
+  {
+    super(buffer);
+  }
+
+  public ServerRSA_PSKParameters(String identityHint)
+  {
+    super(identityHint);
+  }
+
+  public @Override KeyExchangeAlgorithm algorithm()
+  {
+    return KeyExchangeAlgorithm.RSA_PSK;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SessionImpl.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,198 @@
+/* SessionImpl.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.crypto.key.GnuPBEKey;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.Session.ID;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import java.security.Certificate;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SealedObject;
+import javax.crypto.spec.PBEKeySpec;
+import javax.net.ssl.SSLException;
+
+public class SessionImpl extends Session
+{
+  static final long serialVersionUID = 8932976607588442485L;
+  CipherSuite suite;
+  ProtocolVersion version;
+  byte[] privateDataSalt;
+  SealedObject sealedPrivateData;
+  MaxFragmentLength maxLength;
+  
+  transient PrivateData privateData;
+  
+  public SessionImpl()
+  {
+    super();
+    privateData = new PrivateData();
+  }
+  
+  SecureRandom random ()
+  {
+    return random;
+  }
+  
+  public String getProtocol()
+  {
+    return version.toString();
+  }
+  
+  public void prepare(char[] passwd) throws SSLException
+  {
+    try
+      {
+        privateDataSalt = new byte[32];
+        random.nextBytes(privateDataSalt);
+        GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+        Cipher cipher = Cipher.getInstance("PBEWithHMacSHA256AndAES/OFB/PKCS7Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+        sealedPrivateData = new SealedObject(privateData, cipher);
+      }
+    catch (IllegalBlockSizeException ibse)
+      {
+        throw new SSLException(ibse);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new SSLException(ike);
+      }
+    catch (IOException ioe)
+      {
+        throw new SSLException(ioe);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new SSLException(nsae);
+      }
+    catch (NoSuchPaddingException nspe)
+      {
+        throw new SSLException(nspe);
+      }
+  }
+  
+  public void repair(char[] passwd) throws SSLException
+  {
+    try
+      {
+        GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+        privateData = (PrivateData) sealedPrivateData.getObject(key);
+      }
+    catch (ClassNotFoundException cnfe)
+      {
+        throw new SSLException(cnfe);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new SSLException(ike);
+      }
+    catch (IOException ioe)
+      {
+        throw new SSLException(ioe);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        throw new SSLException(nsae);
+      }
+  }
+  
+  public SealedObject privateData() throws SSLException
+  {
+    if (privateData == null)
+      throw new SSLException("this session has not been prepared");
+    return sealedPrivateData;
+  }
+  
+  public void setPrivateData(SealedObject so) throws SSLException
+  {
+    this.sealedPrivateData = so;
+  }
+
+  void setApplicationBufferSize(int size)
+  {
+    applicationBufferSize = size;
+  }
+  
+  void setRandom(SecureRandom random)
+  {
+    this.random = random;
+  }
+  
+  void setTruncatedMac(boolean truncatedMac)
+  {
+    this.truncatedMac = truncatedMac;
+  }
+  
+  void setId(Session.ID id)
+  {
+    this.sessionId = id;
+  }
+  
+  void setLocalCertificates(java.security.cert.Certificate[] chain)
+  {
+    this.localCerts = chain;
+  }
+  
+  void setPeerCertificates(java.security.cert.Certificate[] chain)
+  {
+    this.peerCerts = chain;
+  }
+  
+  void setPeerVerified(boolean peerVerified)
+  {
+    this.peerVerified = peerVerified;
+  }
+  
+  static class PrivateData implements Serializable
+  {
+    static final long serialVersionUID = -8040597659545984581L;
+    byte[] masterSecret;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Signature.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,172 @@
+/* Signature.java -- SSL Signature structure.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+import java.security.PublicKey;
+import java.security.interfaces.RSAKey;
+
+import java.util.Arrays;
+
+import gnu.java.security.der.*;
+
+/**
+ * The signature structure.
+ *
+ * <pre>
+select (SignatureAlgorithm)
+{
+case anonymous:
+  struct { };
+case rsa:
+  digitally-signed struct
+  {
+    opaque md5_hash[16];
+    opaque sha_hash[20];
+  };
+case dsa:
+  digitally-signed struct
+  {
+    opaque sha_hash[20];
+  };
+} Signature;</pre>
+ */
+public class Signature implements Builder, Constructed
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final ByteBuffer buffer;
+  private final SignatureAlgorithm alg;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg)
+  {
+    this.buffer = buffer;
+    this.alg = alg;
+  }
+  
+  public Signature (final byte[] sigValue, final SignatureAlgorithm alg)
+  {
+    buffer = ByteBuffer.allocate(sigValue.length + 2);
+    buffer.putShort((short) sigValue.length);
+    buffer.put(sigValue);
+    buffer.position(0);
+    this.alg = alg;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int length ()
+  {
+    if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+      return 0;
+    return (buffer.getShort (0) & 0xFFFF) + 2;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+
+  public byte[] signature ()
+  {
+    if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+      return new byte[0];
+    int length = buffer.getShort (0) & 0xFFFF;
+    byte[] buf = new byte[length];
+    ((ByteBuffer) buffer.duplicate().position(2)).get(buf);
+    return buf;
+  }
+
+  public void setSignature (final byte[] signature)
+  {
+    setSignature (signature, 0, signature.length);
+  }
+
+  public void setSignature (final byte[] signature, final int offset, final int length)
+  {
+    if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+      return;
+    buffer.putShort (0, (short) length);
+    buffer.position (2);
+    buffer.put (signature, offset, length);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null)
+      out.print (prefix);
+    out.println("struct {");
+    if (!alg.equals (SignatureAlgorithm.ANONYMOUS))
+      {
+        String subprefix = "  ";
+        if (prefix != null)
+          subprefix = prefix + subprefix;
+        out.print (Util.hexDump (signature (), subprefix));
+      }
+    if (prefix != null)
+      out.print (prefix);
+    out.print ("} Signature;");
+    return str.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SignatureAlgorithm.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,62 @@
+/* SignatureAlgorithm.java -- Signature algorithm enumeration.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+public enum SignatureAlgorithm
+{
+  ANONYMOUS, RSA, DSA;
+  
+  /**
+   * Returns the algorithm name for this signature algorithm, which can
+   * be used with the JCA API to get a {@link java.security.Signature} for
+   * that algorithm.
+   * 
+   * @return The algorithm name.
+   */
+  public String algorithm()
+  {
+    switch (this)
+      {
+        case ANONYMOUS: return null;
+        case RSA: return "TLSv1.1-RSA";
+        case DSA: return "DSS";
+      }
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/SimpleSessionContext.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,146 @@
+/* SimpleSessionContext.java -- memory-only session store.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SessionStoreException;
+import gnu.javax.net.ssl.Session.ID;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A simple, non-persistent SessionContext.
+ * 
+ * @author csm
+ */
+public final class SimpleSessionContext
+  extends AbstractSessionContext
+{
+  /**
+   * By default, sessions last for 5 minutes.
+   */
+  public static final int DEFAULT_TIMEOUT = 300;
+  
+  private final HashMap<Session.ID, Session> store;
+  private int storeLimit;
+  
+  public SimpleSessionContext()
+  {
+    super(DEFAULT_TIMEOUT);
+    storeLimit = 0;
+    store = new HashMap<Session.ID, Session>();
+  }
+  
+  @Override
+  protected Session implGet(byte[] sessionId)
+  {
+    return store.get(new Session.ID(sessionId));
+  }
+
+  @Override
+  public void load(char[] password) throws SessionStoreException
+  {
+    // Not supported. Memory-only.
+  }
+
+  @Override
+  public void put(Session session)
+  {
+    if (storeLimit > 0 && store.size() >= storeLimit)
+      {
+        Session oldest = null;
+        for (Map.Entry<Session.ID, Session> e : store.entrySet())
+          {
+            Session s = e.getValue();
+            long stamp = s.getLastAccessedTime();
+            if (oldest == null || oldest.getLastAccessedTime() > stamp)
+              oldest = s;
+          }
+        store.remove(oldest.id());
+      }
+    store.put(session.id(), session);
+  }
+
+  @Override
+  public void remove(byte[] sessionId)
+  {
+    store.remove(new Session.ID(sessionId));
+  }
+
+  @Override
+  public void store(char[] password) throws SessionStoreException
+  {
+    // Not supported. Memory-only.
+  }
+
+  public Enumeration getIds()
+  {
+    return new Enumeration()
+    {
+      Iterator<Session.ID> it = store.keySet().iterator();
+      
+      public boolean hasMoreElements()
+      {
+        return it.hasNext();
+      }
+      
+      public Object nextElement()
+      {
+        return it.next().id();
+      }
+    };
+  }
+
+  public int getSessionCacheSize()
+  {
+    return storeLimit;
+  }
+
+  public void setSessionCacheSize(int size)
+  {
+    if (size < 0)
+      throw new IllegalArgumentException("cache size must be nonnegative");
+    this.storeLimit = size;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/TLSHMac.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,138 @@
+/* TLSHMac.java -- HMAC used in TLS.
+   Copyright (C) 2001, 2002, 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.mac.HMac;
+
+/**
+ * The operation of this HMac is identical to normal HMacs, but this one
+ * allows keys with short lengths (including zero).
+ */
+class TLSHMac extends HMac
+{
+
+  // Constants.
+  // -------------------------------------------------------------------------
+
+  private static final byte IPAD_BYTE = 0x36;
+  private static final byte OPAD_BYTE = 0x5C;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  TLSHMac(IMessageDigest hash)
+  {
+    super(hash);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void init(Map attributes)
+    throws InvalidKeyException, IllegalStateException
+  {
+    Integer ts = (Integer) attributes.get(TRUNCATED_SIZE);
+    truncatedSize = (ts == null ? macSize : ts.intValue());
+    if (truncatedSize < (macSize / 2)) {
+      throw new IllegalArgumentException("Truncated size too small");
+    } else if (truncatedSize < 10) {
+      throw new IllegalArgumentException("Truncated size less than 80 bits");
+    }
+
+    // we dont use/save the key outside this method
+    byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+    if (K == null) { // take it as an indication to re-use previous key if set
+      if (ipadHash == null)
+        {
+          throw new InvalidKeyException("Null key");
+        }
+      // we already went through the motions; ie. up to step #4.  re-use
+      underlyingHash = (IMessageDigest) ipadHash.clone();
+      return;
+    }
+
+    if (K.length > blockSize)
+      {
+        // (0) replace K with HASH(K) if K is larger than the hash's
+        //     block size. Then pad with zeros until it is the correct
+        //     size (the next `if').
+        underlyingHash.update(K, 0, K.length);
+        K = underlyingHash.digest();
+      }
+    if (K.length < blockSize)
+      {
+        // (1) append zeros to the end of K to create a B byte string
+        //     (e.g., if K is of length 20 bytes and B=64, then K will be
+        //     appended with 44 zero bytes 0x00)
+        int limit = (K.length > blockSize) ? blockSize : K.length;
+        byte[] newK = new byte[blockSize];
+        System.arraycopy(K, 0, newK, 0, limit);
+        K = newK;
+      }
+
+    underlyingHash.reset();
+    opadHash = (IMessageDigest) underlyingHash.clone();
+    if (ipad == null)
+      {
+        ipad = new byte[blockSize];
+      }
+    // (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+    //     (1) with ipad
+    // (3) append the stream of data 'text' to the B byte string resulting
+    //     from step (2)
+    // (4) apply H to the stream generated in step (3)
+    for (int i = 0; i < blockSize; i++)
+      {
+        ipad[i] = (byte)(K[i] ^ IPAD_BYTE);
+      }
+    for (int i = 0; i < blockSize; i++)
+      {
+        opadHash.update((byte)(K[i] ^ OPAD_BYTE));
+      }
+
+    underlyingHash.update(ipad, 0, blockSize);
+    ipadHash = (IMessageDigest) underlyingHash.clone();
+    K = null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/TLSRandom.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,252 @@
+/* TLSRandom.java -- The TLS pseudo-random function.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.javax.crypto.mac.IMac;
+import gnu.java.security.prng.IRandom;
+
+class TLSRandom implements IRandom
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Property name for the secret that will be used to initialize the HMACs.
+   */
+  static final String SECRET = "jessie.tls.prng.secret";
+
+  /**
+   * Property name for the seed.
+   */
+  static final String SEED = "jessie.tls.prng.seed";
+
+  private final IMac hmac_sha, hmac_md5;
+  private byte[] sha_a, md5_a;
+  private byte[] seed;
+  private final byte[] buffer;
+  private int idx;
+  private boolean init;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  TLSRandom()
+  {
+    hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1"));
+    hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5"));
+    buffer = new byte[80];   // 80 == LCM of 16 and 20.
+    idx = 0;
+    init = false;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public Object clone()
+  {
+    try
+      {
+        return super.clone();
+      }
+    catch (CloneNotSupportedException shouldNotHappen)
+      {
+        throw new Error();
+      }
+  }
+
+  public void init(Map attributes)
+  {
+    HashMap sha_attr = new HashMap();
+    HashMap md5_attr = new HashMap();
+    byte[] secret = (byte[]) attributes.get(SECRET);
+    if (secret != null)
+      {
+        int l = (secret.length >>> 1) + (secret.length & 1);
+        byte[] s1 = Util.trim(secret, 0, l);
+        byte[] s2 = Util.trim(secret, secret.length - l, l);
+        md5_attr.put(IMac.MAC_KEY_MATERIAL, s1);
+        sha_attr.put(IMac.MAC_KEY_MATERIAL, s2);
+        try
+          {
+            hmac_md5.init(md5_attr);
+            hmac_sha.init(sha_attr);
+          }
+        catch (InvalidKeyException ike)
+          {
+            throw new Error(ike.toString());
+          }
+      }
+    else if (!init)
+      {
+        throw new IllegalArgumentException("no secret supplied");
+      }
+    // else re-use
+
+    byte[] seeed = (byte[]) attributes.get(SEED);
+    if (seeed != null)
+      {
+        seed = (byte[]) seeed.clone();
+      }
+    else if (!init)
+      {
+        throw new IllegalArgumentException("no seed supplied");
+      }
+    // else re-use
+
+    // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)).
+    hmac_md5.update(seed, 0, seed.length);
+    md5_a = hmac_md5.digest();
+    hmac_md5.reset();
+    hmac_sha.update(seed, 0, seed.length);
+    sha_a = hmac_sha.digest();
+    hmac_sha.reset();
+    fillBuffer();
+    init = true;
+  }
+
+  public String name()
+  {
+    return "TLSRandom";
+  }
+
+  public byte nextByte()
+  {
+    if (!init)
+      throw new IllegalStateException();
+    if (idx >= buffer.length)
+      fillBuffer();
+    return buffer[idx++];
+  }
+
+  public void nextBytes(byte[] buf, int off, int len)
+  {
+    if (!init)
+      throw new IllegalStateException();
+    if (buf == null)
+      throw new NullPointerException();
+    if (off < 0 || off > buf.length || off + len > buf.length)
+      throw new ArrayIndexOutOfBoundsException();
+    int count = 0;
+    if (idx >= buffer.length)
+      fillBuffer();
+    while (count < len)
+      {
+        int l = Math.min(buffer.length-idx, len-count);
+        System.arraycopy(buffer, idx, buf, off+count, l);
+        idx += l;
+        count += l;
+        if (count < len && idx >= buffer.length)
+          fillBuffer();
+      }
+  }
+
+  // For future versions of GNU Crypto. No-ops.
+  public void addRandomByte (byte b)
+  {
+  }
+
+  public void addRandomBytes(byte[] buffer) {
+    addRandomBytes(buffer, 0, buffer.length);
+  }
+
+  public void addRandomBytes (byte[] b, int i, int j)
+  {
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  /*
+   * The PRF is defined as:
+   *
+   *   PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+   *                              P_SHA-1(S2, label + seed);
+   *
+   * P_hash is defined as:
+   *
+   *   P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+   *                          HMAC_hash(secret, A(2) + seed) +
+   *                          HMAC_hash(secret, A(3) + seed) + ...
+   *
+   * And A() is defined as:
+   *
+   *   A(0) = seed
+   *   A(i) = HMAC_hash(secret, A(i-1))
+   *
+   * For simplicity, we compute an 80-byte block on each call, which
+   * corresponds to five iterations of MD5, and four of SHA-1.
+   */
+  private synchronized void fillBuffer()
+  {
+    int len = hmac_md5.macSize();
+    for (int i = 0; i < buffer.length; i += len)
+      {
+        hmac_md5.update(md5_a, 0, md5_a.length);
+        hmac_md5.update(seed, 0, seed.length);
+        byte[] b = hmac_md5.digest();
+        hmac_md5.reset();
+        System.arraycopy(b, 0, buffer, i, len);
+        hmac_md5.update(md5_a, 0, md5_a.length);
+        md5_a = hmac_md5.digest();
+        hmac_md5.reset();
+      }
+    len = hmac_sha.macSize();
+    for (int i = 0; i < buffer.length; i += len)
+      {
+        hmac_sha.update(sha_a, 0, sha_a.length);
+        hmac_sha.update(seed, 0, seed.length);
+        byte[] b = hmac_sha.digest();
+        hmac_sha.reset();
+        for (int j = 0; j < len; j++)
+          {
+            buffer[j + i] ^= b[j];
+          }
+        hmac_sha.update(sha_a, 0, sha_a.length);
+        sha_a = hmac_sha.digest();
+        hmac_sha.reset();
+      }
+    idx = 0;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/TruncatedHMAC.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,76 @@
+/* TruncatedHMAC.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension.
+ * This extension has an empty value; this class is thusly empty.
+ * 
+ * @author csm
+ */
+public class TruncatedHMAC extends Value
+{
+
+  public int length()
+  {
+    return 0;
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return ByteBuffer.wrap(new byte[0]);
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+
+  public String toString(String prefix)
+  {
+    String s = "TruncatedHMAC;";
+    if (prefix != null)
+      s = prefix + s;
+    return s;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/TrustedAuthorities.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,298 @@
+/* TrustedAuthorities.java
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.x509.X500DistinguishedName;
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The trusted authorities hello extension.
+ * 
+ * <pre>
+struct {
+  TrustedAuthority trusted_authorities_list&lt;0..2^16-1&gt;;
+} TrustedAuthorities;
+
+struct {
+  IdentifierType identifier_type;
+  select (identifier_type) {
+    case pre_agreed: struct {};
+    case key_sha1_hash: SHA1Hash;
+    case x509_name: DistinguishedName;
+    case cert_sha1_hash: SHA1Hash;
+  } identifier;
+} TrustedAuthority;
+
+enum {
+  pre_agreed(0), key_sha1_hash(1), x509_name(2),
+  cert_sha1_hash(3), (255)
+} IdentifierType;
+
+opaque DistinguishedName&lt;1..2^16-1&gt;;</pre>
+ * 
+ * @author csm
+ */
+public class TrustedAuthorities extends Value
+  implements Iterable<TrustedAuthorities.TrustedAuthority>
+{
+  private final ByteBuffer buffer;
+
+  public TrustedAuthorities(final ByteBuffer buffer)
+  {
+    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+  }
+  
+  // XXX really implement Builder.
+  
+  public int length()
+  {
+    return 2 + (buffer.getShort(0) & 0xFFFF);
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return (ByteBuffer) buffer.duplicate().limit(length());
+  }
+  
+  public int size()
+  {
+    int len = buffer.getShort(0) & 0xFFFF;
+    int n = 0;
+    for (int i = 2; i < len; i++)
+      {
+        TrustedAuthority auth =
+          new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+        i += auth.length();
+        n++;
+      }
+    return n;
+  }
+
+  public TrustedAuthority get(final int index)
+  {
+    int len = buffer.getShort(0) & 0xFFFF;
+    int n = 0;
+    int i = 2;
+    while (i < len && n <= index)
+      {
+        TrustedAuthority auth =
+          new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+        if (n == index)
+          return auth;
+        i += auth.length();
+        n++;
+      }
+    throw new IndexOutOfBoundsException();
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  public String toString(String prefix)
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    if (prefix != null) out.print(prefix);
+    out.println("struct {");
+    String subprefix = "  ";
+    if (prefix != null)
+      subprefix = prefix + subprefix;
+    for(TrustedAuthority ta : this)
+      out.println(ta);
+    if (prefix != null) out.print(prefix);
+    out.print("} TrustedAuthorities;");
+    return str.toString();
+  }
+  
+  public Iterator<TrustedAuthority> iterator()
+  {
+    return new AuthoritiesIterator();
+  }
+  
+  public class AuthoritiesIterator implements Iterator<TrustedAuthority>
+  {
+    private int index;
+    
+    public AuthoritiesIterator()
+    {
+      index = 0;
+    }
+    
+    public TrustedAuthority next() throws NoSuchElementException
+    {
+      try
+        {
+          return get(index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException();
+        }
+    }
+    
+    public boolean hasNext()
+    {
+      return index < size();
+    }
+    
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  public static class TrustedAuthority implements Constructed
+  {
+    private final ByteBuffer buffer;
+    
+    public TrustedAuthority(final ByteBuffer buffer)
+    {
+      this.buffer = buffer;
+    }
+    
+    public int length()
+    {
+      switch (type().getValue())
+      {
+        case 0: return 1;
+        case 1:
+        case 3: return 21;
+        case 2: return 3 + (buffer.getShort(1) & 0xFFFF);
+      }
+      throw new IllegalArgumentException("unknown authority type");
+    }
+    
+    public byte[] sha1Hash()
+    {
+      IdentifierType t = type();
+      if (t != IdentifierType.CERT_SHA1_HASH
+          && t != IdentifierType.KEY_SHA1_HASH)
+        throw new IllegalArgumentException(t + " does not have a hash value");
+      byte[] b = new byte[20];
+      ((ByteBuffer) buffer.duplicate().position(1)).get(b);
+      return b;
+    }
+    
+    public X500Principal name()
+    {
+      int len = buffer.getShort(1) & 0xFFFF;
+      byte[] b = new byte[len];
+      ((ByteBuffer) buffer.duplicate().position(3)).get(b);
+      return new X500Principal(b);
+    }
+    
+    public IdentifierType type()
+    {
+      switch (buffer.get(0))
+      {
+        case 0: return IdentifierType.PRE_AGREED;
+        case 1: return IdentifierType.KEY_SHA1_HASH;
+        case 2: return IdentifierType.X509_NAME;
+        case 3: return IdentifierType.CERT_SHA1_HASH;
+      }
+      
+      throw new IllegalArgumentException("invalid IdentifierType");
+    }
+    
+    public String toString()
+    {
+      return toString(null);
+    }
+    
+    public String toString(String prefix)
+    {
+      StringWriter str = new StringWriter();
+      PrintWriter out = new PrintWriter(str);
+      if (prefix != null) out.print(prefix);
+      out.println("struct {");
+      if (prefix != null) out.print(prefix);
+      out.print("  identifier_type = ");
+      out.print(type());
+      out.println(";");
+      switch (type().getValue())
+      {
+        case 0: break;
+        case 1:
+        case 3:
+          if (prefix != null) out.print(prefix);
+          out.print("  sha1_hash = ");
+          out.print(Util.toHexString(sha1Hash(), ':'));
+          out.println(";");
+          break;
+          
+        case 2:
+          if (prefix != null) out.print(prefix);
+          out.print("  name = ");
+          out.print(name());
+          out.println(";");
+      }
+      if (prefix != null) out.print(prefix);
+      out.print("} TrustedAuthority;");
+      return str.toString();
+    }
+  }
+  
+  public static enum IdentifierType
+  {
+    PRE_AGREED (0), KEY_SHA1_HASH (1), X509_NAME (2), CERT_SHA1_HASH (3);
+    
+    private final int value;
+    
+    private IdentifierType(final int value)
+    {
+      this.value = value;
+    }
+    
+    public int getValue()
+    {
+      return value;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,83 @@
+/* UnresolvedExtensionValue.jav --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+public class UnresolvedExtensionValue extends Value
+{
+  private final ByteBuffer buffer;
+  
+  public UnresolvedExtensionValue (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+  }
+  
+  public int length()
+  {
+    return buffer.limit();
+  }
+  
+  public ByteBuffer buffer()
+  {
+    return value();
+  }
+  
+  public ByteBuffer value()
+  {
+    return buffer.slice();
+  }
+  
+  public String toString()
+  {
+    return toString(null);
+  }
+  
+  public String toString(final String prefix)
+  {
+    String s = Util.hexDump(buffer);
+    if (prefix != null)
+      s = prefix + s;
+    return s;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/Util.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,493 @@
+/* Util.java -- Miscellaneous utility methods.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
+
+/**
+ * A collection of useful class methods.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public final class Util
+{
+
+  // Constants.
+  // -------------------------------------------------------------------------
+
+  static final String HEX = "0123456789abcdef";
+
+  // Static methods only.
+  private Util() { }
+
+  // Class methods.
+  // -------------------------------------------------------------------------
+
+  public static Object wrapBuffer(ByteBuffer buffer)
+  {
+    return wrapBuffer(buffer, "");
+  }
+  
+  public static Object wrapBuffer(ByteBuffer buffer, String prefix)
+  {
+    return new WrappedBuffer(buffer, prefix);
+  }
+  
+  private static class WrappedBuffer
+  {
+    private final ByteBuffer buffer;
+    private final String prefix;
+    
+    WrappedBuffer(ByteBuffer buffer, String prefix)
+    {
+      this.buffer = buffer;
+      this.prefix = prefix;
+    }
+    
+    public String toString()
+    {
+      return hexDump(buffer, prefix);
+    }
+  }
+  
+  /**
+   * Convert a hexadecimal string into its byte representation.
+   *
+   * @param hex The hexadecimal string.
+   * @return The converted bytes.
+   */
+  public static byte[] toByteArray(String hex)
+  {
+    hex = hex.toLowerCase();
+    byte[] buf = new byte[hex.length() / 2];
+    int j = 0;
+    for (int i = 0; i < buf.length; i++)
+      {
+        buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) |
+                          Character.digit(hex.charAt(j++), 16));
+      }
+    return buf;
+  }
+
+  /**
+   * Convert a byte array to a hexadecimal string, as though it were a
+   * big-endian arbitrarily-sized integer.
+   *
+   * @param buf The bytes to format.
+   * @param off The offset to start at.
+   * @param len The number of bytes to format.
+   * @return A hexadecimal representation of the specified bytes.
+   */
+  public static String toHexString(byte[] buf, int off, int len)
+  {
+    StringBuffer str = new StringBuffer();
+    for (int i = 0; i < len; i++)
+      {
+        str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F));
+        str.append(HEX.charAt(buf[i+off] & 0x0F));
+      }
+    return str.toString();
+  }
+
+  /**
+   * See {@link #toHexString(byte[],int,int)}.
+   */
+  public static String toHexString(byte[] buf)
+  {
+    return Util.toHexString(buf, 0, buf.length);
+  }
+
+  /**
+   * Convert a byte array to a hexadecimal string, separating octets
+   * with the given character.
+   *
+   * @param buf The bytes to format.
+   * @param off The offset to start at.
+   * @param len The number of bytes to format.
+   * @param sep The character to insert between octets.
+   * @return A hexadecimal representation of the specified bytes.
+   */
+  public static String toHexString(byte[] buf, int off, int len, char sep)
+  {
+    StringBuffer str = new StringBuffer();
+    for (int i = 0; i < len; i++)
+      {
+        str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F));
+        str.append(HEX.charAt(buf[i+off] & 0x0F));
+        if (i < len - 1)
+          str.append(sep);
+      }
+    return str.toString();
+  }
+
+  /**
+   * See {@link #toHexString(byte[],int,int,char)}.
+   */
+  public static String toHexString(byte[] buf, char sep)
+  {
+    return Util.toHexString(buf, 0, buf.length, sep);
+  }
+
+  /**
+   * Create a representation of the given byte array similar to the
+   * output of <code>`hexdump -C'</code>, which is
+   *
+   * <p><pre>OFFSET  SIXTEEN-BYTES-IN-HEX  PRINTABLE-BYTES</pre>
+   *
+   * <p>The printable bytes show up as-is if they are printable and
+   * not a newline character, otherwise showing as '.'.
+   *
+   * @param buf The bytes to format.
+   * @param off The offset to start at.
+   * @param len The number of bytes to encode.
+   * @param prefix A string to prepend to every line.
+   * @return The formatted string.
+   */
+  public static String hexDump(byte[] buf, int off, int len, String prefix)
+  {
+    String nl = getProperty("line.separator");
+    StringBuffer str = new StringBuffer();
+    int i = 0;
+    while (i < len)
+      {
+        if (prefix != null)
+          str.append(prefix);
+        str.append(Util.formatInt(i+off, 16, 8));
+        str.append("  ");
+        String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' ');
+        str.append(s);
+        for (int j = s.length(); j < 49; j++)
+          str.append(" ");
+        for (int j = 0; j < Math.min(16, len - i); j++)
+          {
+            if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E)
+              str.append('.');
+            else
+              str.append((char) (buf[i+off+j] & 0xFF));
+          }
+        str.append(nl);
+        i += 16;
+      }
+    return str.toString();
+  }
+
+  public static String hexDump (ByteBuffer buf)
+  {
+    return hexDump (buf, null);
+  }
+
+  public static String hexDump (ByteBuffer buf, String prefix)
+  {
+    buf = buf.duplicate();
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    int i = 0;
+    int len = buf.remaining();
+    byte[] line = new byte[16];
+    while (i < len)
+      {
+        if (prefix != null)
+          out.print(prefix);
+        out.print(Util.formatInt (i, 16, 8));
+        out.print("  ");
+        int l = Math.min(16, len - i);
+        buf.get(line, 0, l);
+        String s = Util.toHexString(line, 0, l, ' ');
+        out.print(s);
+        for (int j = s.length(); j < 49; j++)
+          out.print(' ');
+        for (int j = 0; j < l; j++)
+          {
+            int c = line[j] & 0xFF;
+            if (c < 0x20 || c > 0x7E)
+              out.print('.');
+            else
+              out.print((char) c);
+          }
+        out.println();
+        i += 16;
+      }
+    return str.toString();
+  }
+
+  /**
+   * See {@link #hexDump(byte[],int,int,String)}.
+   */
+  public static String hexDump(byte[] buf, int off, int len)
+  {
+    return hexDump(buf, off, len, "");
+  }
+
+  /**
+   * See {@link #hexDump(byte[],int,int,String)}.
+   */
+  public static String hexDump(byte[] buf, String prefix)
+  {
+    return hexDump(buf, 0, buf.length, prefix);
+  }
+
+  /**
+   * See {@link #hexDump(byte[],int,int,String)}.
+   */
+  public static String hexDump(byte[] buf)
+  {
+    return hexDump(buf, 0, buf.length);
+  }
+
+  /**
+   * Format an integer into the specified radix, zero-filled.
+   *
+   * @param i The integer to format.
+   * @param radix The radix to encode to.
+   * @param len The target length of the string. The string is
+   *   zero-padded to this length, but may be longer.
+   * @return The formatted integer.
+   */
+  public static String formatInt(int i, int radix, int len)
+  {
+    String s = Integer.toString(i, radix);
+    StringBuffer buf = new StringBuffer();
+    for (int j = 0; j < len - s.length(); j++)
+      buf.append("0");
+    buf.append(s);
+    return buf.toString();
+  }
+
+  /**
+   * Concatenate two byte arrays into one.
+   *
+   * @param b1 The first byte array.
+   * @param b2 The second byte array.
+   * @return The concatenation of b1 and b2.
+   */
+  public static byte[] concat(byte[] b1, byte[] b2)
+  {
+    byte[] b3 = new byte[b1.length+b2.length];
+    System.arraycopy(b1, 0, b3, 0, b1.length);
+    System.arraycopy(b2, 0, b3, b1.length, b2.length);
+    return b3;
+  }
+
+  /**
+   * See {@link #trim(byte[],int,int)}.
+   */
+  public static byte[] trim(byte[] buffer, int len)
+  {
+    return trim(buffer, 0, len);
+  }
+
+  /**
+   * Returns a portion of a byte array, possibly zero-filled.
+   *
+   * @param buffer The byte array to trim.
+   * @param off The offset to begin reading at.
+   * @param len The number of bytes to return. This value can be larger
+   *        than <i>buffer.length - off</i>, in which case the rest of the
+   *        returned byte array will be filled with zeros.
+   * @throws IndexOutOfBoundsException If <i>off</i> or <i>len</i> is
+   *         negative, or if <i>off</i> is larger than the byte array's
+   *         length.
+   * @return The trimmed byte array.
+   */
+  public static byte[] trim(byte[] buffer, int off, int len)
+  {
+    if (off < 0 || len < 0 || off > buffer.length)
+      throw new IndexOutOfBoundsException("max=" + buffer.length +
+                                          " off=" + off + " len=" + len);
+    if (off == 0 && len == buffer.length)
+      return buffer;
+    byte[] b = new byte[len];
+    System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off));
+    return b;
+  }
+
+  /**
+   * Returns the byte array representation of the given big integer with
+   * the leading zero byte (if any) trimmed off.
+   *
+   * @param bi The integer to trim.
+   * @return The byte representation of the big integer, with any leading
+   *   zero removed.
+   */
+  public static byte[] trim(BigInteger bi)
+  {
+    byte[] buf = bi.toByteArray();
+    if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO))
+      {
+        return trim(buf, 1, buf.length - 1);
+      }
+    else
+      {
+        return buf;
+      }
+  }
+
+  /**
+   * Returns the integer value of <code>{@link
+   * java.lang.System#currentTimeMillis()} / 1000</code>.
+   *
+   * @return The current time, in seconds.
+   */
+  public static int unixTime()
+  {
+    return (int) (System.currentTimeMillis() / 1000L);
+  }
+
+  /**
+   * Transform an Object array into another by calling the given method
+   * on each object. The returned object array will have the runtime
+   * type of <i>returnType</i>. For example, the following will transform
+   * array of objects into their String representations, returning a String
+   * array. For example:
+   *
+   * <blockquote><p><code>
+   * String[] strings = (String[]) Util.transform(array, String.class,
+   * "toString", null);
+   * </code></p></blockquote>
+   *
+   * <p>If any element of the given array is <tt>null</tt>, then that
+   * entry in the returned array will also be <tt>null</tt>.
+   *
+   * @param array The array to transform. It does not need to be of
+   *        uniform type.
+   * @param returnType The desired return type of the returned array.
+   *        This must by the <i>component</i> type, not the array type.
+   * @param method The name of the method to invoke from each object.
+   * @param args The arguments to pass to the method, or <tt>null</tt>
+   *        if the method takes no arguments.
+   * @throws InvocationTargetException If an exception occurs while
+   *         calling <i>method</i> of any object.
+   * @throws NoSuchMethodException If <i>method</i> is not the name of
+   *         a valid method of any component of the array.
+   * @throws ClassCastException If the returned object from the method
+   *         is not assignable to the return type.
+   * @throws IllegalArgumentException If <i>args</i> is not appropriate
+   *         for <i>method</i>
+   * @throws IllegalAccessException If <i>method</i> is not accessible.
+   * @throws SecurityException If <i>method</i> is not accessible.
+   * @return An array containing the output of <i>method</i> called on
+   *         each element of <i>array</i> with <i>args</i>. The return type
+   *         of the array will be an array of <i>returnType</i>.
+   */
+  static Object[] transform(Object[] array, Class returnType,
+                            String method, Object[] args)
+    throws InvocationTargetException, NoSuchMethodException,
+           IllegalAccessException
+  {
+    if (args == null)
+      args = new Object[0];
+    Object[] result = (Object[]) Array.newInstance(returnType, array.length);
+    Class[] argsClasses = new Class[args.length];
+    for (int i = 0; i < args.length; i++)
+      {
+        argsClasses[i] = args[i].getClass();
+      }
+    for (int i = 0; i < array.length; i++)
+      {
+        if (array[i] == null)
+          {
+            result[i] = null;
+            continue;
+          }
+        Class objClass = array[i].getClass();
+        Method objMethod = objClass.getMethod(method, argsClasses);
+        Object o = objMethod.invoke(array[i], args);
+        if (!returnType.isAssignableFrom(o.getClass()))
+          throw new ClassCastException();
+        result[i] = o;
+      }
+    return result;
+  }
+
+  /**
+   * Get a system property as a privileged action.
+   *
+   * @param name The name of the property to get.
+   * @return The property named <i>name</i>, or null if the property is
+   *   not set.
+   * @throws SecurityException If the Jessie code still does not have
+   *   permission to read the property.
+   */
+  @Deprecated static String getProperty(final String name)
+  {
+    return (String) AccessController.doPrivileged(
+      new PrivilegedAction()
+      {
+        public Object run()
+        {
+          return System.getProperty(name);
+        }
+      }
+    );
+  }
+
+  /**
+   * Get a security property as a privileged action.
+   *
+   * @param name The name of the property to get.
+   * @return The property named <i>name</i>, or null if the property is
+   *   not set.
+   * @throws SecurityException If the Jessie code still does not have
+   *   permission to read the property.
+   */
+  @Deprecated static String getSecurityProperty(final String name)
+  {
+    return (String) AccessController.doPrivileged(
+      new PrivilegedAction()
+      {
+        public Object run()
+        {
+          return Security.getProperty(name);
+        }
+      }
+    );
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/X500PrincipalList.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,272 @@
+/* X500PrincipalList.java -- A list of X.500 names.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+public final class X500PrincipalList implements Iterable<X500Principal>
+{
+  private final ByteBuffer buffer;
+  private int modCount;
+
+  public X500PrincipalList (final ByteBuffer buffer)
+  {
+    this.buffer = buffer;
+    modCount = 0;
+  }
+
+  public int size ()
+  {
+    return (buffer.getShort (0) & 0xFFFF);
+  }
+
+  public int count ()
+  {
+    int size = size ();
+    int i = 0;
+    for (int offset = 2; offset < size; i++)
+      {
+        int _size = (buffer.getShort (offset) & 0xFFFF);
+        // We don't want this going into an infinite loop if
+        // you mistakenly put a zero-length name.
+        if (_size == 0)
+          break;
+        offset += _size + 2;
+      }
+    return i;
+  }
+
+  public X500Principal get (final int index)
+  {
+    if (index < 0)
+      throw new IndexOutOfBoundsException ("negative index");
+    int size = size ();
+    int i = 0;
+    for (int offset = 2; offset < size; i++)
+      {
+        int _size = (buffer.getShort (offset) & 0xFFFF);
+        if (_size == 0)
+          throw new IndexOutOfBoundsException ("zero-length name encountered");
+        if (i == index)
+          {
+            byte[] buf = new byte[_size];
+            buffer.position (offset + 2);
+            buffer.get (buf);
+            return new X500Principal (buf);
+          }
+        offset += 2 + _size;
+      }
+    throw new IndexOutOfBoundsException ("limit: " + i + "; requested: " + index);
+  }
+
+  public void put (final int index, final X500Principal principal)
+  {
+    put (index, principal.getEncoded ());
+  }
+
+  public void put (final int index, final byte[] encoded)
+  {
+    if (index < 0)
+      throw new IndexOutOfBoundsException ("negative index");
+    int size = size ();
+    int i = 0;
+    for (int offset = 2; offset < size; i++)
+      {
+        int off = (buffer.getShort (offset) & 0xFFFF);
+        if (i == index)
+          {
+            buffer.putShort (offset, (short) encoded.length);
+            buffer.position (offset + 2);
+            buffer.put (encoded);
+            modCount++;
+            return;
+          }
+        offset += 2 + off;
+      }
+    throw new IndexOutOfBoundsException ("limit: " + (i-1) + "; requested: " + index);
+  }
+
+  public void setSize (final int numNames, final int namesSize)
+  {
+    if (numNames < 1)
+      throw new IllegalArgumentException ("must have at least one name");
+    int size = (numNames * 2) + namesSize;
+    if (size < 3 || size > buffer.capacity () || size > 0xFFFF)
+      throw new IllegalArgumentException ("size out of range; maximum: "
+                                          + Math.min (buffer.capacity (), 0xFFFF));
+    buffer.putShort (0, (short) size);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    if (prefix != null) out.print (prefix);
+    out.print ("[");
+    out.print (count ());
+    out.println ("] {");
+    for (Iterator it = new Iterator (); it.hasNext (); )
+      {
+        if (prefix != null) out.print (prefix);
+        out.print ("  ");
+        out.println (it.next ());
+      }
+    if (prefix != null) out.print (prefix);
+    out.print ("};");
+    return str.toString ();
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof X500PrincipalList))
+      return false;
+    X500PrincipalList that = (X500PrincipalList) o;
+
+    if (size () != that.size ())
+      return false;
+
+    for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+         it1.hasNext () && it2.hasNext (); )
+      {
+        if (!it1.next ().equals (it2.next ()))
+          return false;
+      }
+    return true;
+  }
+
+  public java.util.Iterator<X500Principal> iterator ()
+  {
+    return new Iterator();
+  }
+  
+  public class Iterator implements ListIterator<X500Principal>
+  {
+    private final int modCount;
+    private int index;
+    private final int count;
+
+    public Iterator ()
+    {
+      this.modCount = X500PrincipalList.this.modCount;
+      index = 0;
+      count = count ();
+    }
+
+    public void add (X500Principal o)
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public boolean hasNext ()
+    {
+      return (index < count);
+    }
+
+    public boolean hasPrevious ()
+    {
+      return (index > 0);
+    }
+
+    public X500Principal next () throws NoSuchElementException
+    {
+      if (modCount != X500PrincipalList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (index++);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int nextIndex ()
+    {
+      if (hasNext ())
+        return (index + 1);
+      return -1;
+    }
+
+    public X500Principal previous () throws NoSuchElementException
+    {
+      if (index == 0)
+        throw new NoSuchElementException ();
+      if (modCount != X500PrincipalList.this.modCount)
+        throw new ConcurrentModificationException ();
+      try
+        {
+          return get (--index);
+        }
+      catch (IndexOutOfBoundsException ioobe)
+        {
+          throw new NoSuchElementException ();
+        }
+    }
+
+    public int previousIndex ()
+    {
+      return (index - 1);
+    }
+
+    public void remove ()
+    {
+      throw new UnsupportedOperationException ();
+    }
+
+    public void set (final X500Principal o)
+    {
+      throw new UnsupportedOperationException ();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,400 @@
+/* X509KeyManagerFactory.java -- X.509 key manager factory.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Enumeration;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.List;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509KeyManager;
+
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.PrivateCredentials;
+
+/**
+ * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine
+ * for the ``JessieX509'' algorithm.
+ */
+public class X509KeyManagerFactory extends KeyManagerFactorySpi
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private Manager current;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public X509KeyManagerFactory()
+  {
+    super();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected KeyManager[] engineGetKeyManagers()
+  {
+    if (current == null)
+      {
+        throw new IllegalStateException();
+      }
+    return new KeyManager[] { current };
+  }
+
+  protected void engineInit(ManagerFactoryParameters params)
+    throws InvalidAlgorithmParameterException
+  {
+    if (params instanceof NullManagerParameters)
+      {
+        current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
+      }
+    else if (params instanceof PrivateCredentials)
+      {
+        List<X509Certificate[]> chains
+          = ((PrivateCredentials) params).getCertChains();
+        List<PrivateKey> keys
+          = ((PrivateCredentials) params).getPrivateKeys();
+        int i = 0;
+        HashMap<String, X509Certificate[]> certMap
+          = new HashMap<String, X509Certificate[]>();
+        HashMap<String, PrivateKey> keyMap
+          = new HashMap<String, PrivateKey>();
+        Iterator<X509Certificate[]> c = chains.iterator();
+        Iterator<PrivateKey> k = keys.iterator();
+        while (c.hasNext() && k.hasNext())
+          {
+            certMap.put(String.valueOf(i), c.next());
+            keyMap.put(String.valueOf(i), k.next());
+            i++;
+          }
+        current = new Manager(keyMap, certMap);
+      }
+    else
+      {
+        throw new InvalidAlgorithmParameterException();
+      }
+  }
+
+  protected void engineInit(KeyStore store, char[] passwd)
+    throws KeyStoreException, NoSuchAlgorithmException,
+           UnrecoverableKeyException
+  {
+    if (store == null)
+      {
+        String s = Util.getProperty("javax.net.ssl.keyStoreType");
+        if (s == null)
+          s = KeyStore.getDefaultType();
+        store = KeyStore.getInstance(s);
+        s = Util.getProperty("javax.net.ssl.keyStore");
+        if (s == null)
+          return;
+        String p = Util.getProperty("javax.net.ssl.keyStorePassword");
+        try
+          {
+            store.load(new FileInputStream(s), p != null ? p.toCharArray() : null);
+          }
+        catch (IOException ioe)
+          {
+            throw new KeyStoreException(ioe.toString());
+          }
+        catch (CertificateException ce)
+          {
+            throw new KeyStoreException(ce.toString());
+          }
+      }
+
+    HashMap<String, PrivateKey> p = new HashMap<String, PrivateKey>();
+    HashMap<String, X509Certificate[]> c
+      = new HashMap<String, X509Certificate[]>();
+    Enumeration aliases = store.aliases();
+    UnrecoverableKeyException exception = null;
+    while (aliases.hasMoreElements())
+      {
+        String alias = (String) aliases.nextElement();
+        if (!store.isKeyEntry(alias))
+          {
+            continue;
+          }
+        X509Certificate[] chain = null;
+        Certificate[] chain2 = store.getCertificateChain (alias);
+        if (chain2 != null && chain2.length > 0 &&
+            (chain2[0] instanceof X509Certificate))
+          {
+            chain = toX509Chain(chain2);
+          }
+        else
+          {
+            continue;
+          }
+        PrivateKey key = null;
+        try
+          {
+            key = (PrivateKey) store.getKey(alias, passwd);
+          }
+        catch (UnrecoverableKeyException uke)
+          {
+            exception = uke;
+            continue;
+          }
+        if (key == null)
+          {
+            continue;
+          }
+        p.put(alias, key);
+        c.put(alias, chain);
+      }
+    if (p.isEmpty () && c.isEmpty ())
+      {
+        if (exception != null)
+          {
+            throw exception;
+          }
+        throw new KeyStoreException ("no private credentials found");
+      }
+    current = this.new Manager(p, c);
+  }
+
+  private static X509Certificate[] toX509Chain(Certificate[] chain)
+  {
+    if (chain instanceof X509Certificate[])
+      {
+        return (X509Certificate[]) chain;
+      }
+    X509Certificate[] _chain = new X509Certificate[chain.length];
+    for (int i = 0; i < chain.length; i++)
+      _chain[i] = (X509Certificate) chain[i];
+    return _chain;
+  }
+
+  // Inner class.
+  // -------------------------------------------------------------------------
+
+  private class Manager extends X509ExtendedKeyManager
+  {
+    // Fields.
+    // -----------------------------------------------------------------------
+
+    private final Map<String, PrivateKey> privateKeys;
+    private final Map<String, X509Certificate[]> certChains;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    Manager(Map<String, PrivateKey> privateKeys,
+            Map<String, X509Certificate[]> certChains)
+    {
+      this.privateKeys = privateKeys;
+      this.certChains = certChains;
+    }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
+                                    Socket socket)
+    {
+      for (int i = 0; i < keyTypes.length; i++)
+        {
+          String[] s = getClientAliases(keyTypes[i], issuers);
+          if (s.length > 0)
+            return s[0];
+        }
+      return null;
+    }
+    
+    public @Override String chooseEngineClientAlias(String[] keyTypes,
+                                                    Principal[] issuers,
+                                                    SSLEngine engine)
+    {
+      for (String type : keyTypes)
+        {
+          String[] s = getClientAliases(type, issuers);
+          if (s.length > 0)
+            return s[0];
+        }
+      return null;
+    }
+
+    public String[] getClientAliases(String keyType, Principal[] issuers)
+    {
+      return getAliases(keyType, issuers);
+    }
+
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+                                    Socket socket)
+    {
+      String[] s = getServerAliases(keyType, issuers);
+      if (s.length > 0)
+        return s[0];
+      return null;
+    }
+    
+    public @Override String chooseEngineServerAlias(String keyType,
+                                                    Principal[] issuers,
+                                                    SSLEngine engine)
+    {
+      String[] s = getServerAliases(keyType, issuers);
+      if (s.length > 0)
+        return s[0];
+      return null;
+    }
+
+    public String[] getServerAliases(String keyType, Principal[] issuers)
+    {
+      return getAliases(keyType, issuers);
+    }
+
+    private String[] getAliases(String keyType, Principal[] issuers)
+    {
+      LinkedList<String> l = new LinkedList<String>();
+      for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
+        {
+          String alias = (String) i.next();
+          X509Certificate[] chain = getCertificateChain(alias);
+          if (chain.length == 0)
+            continue;
+          PrivateKey privKey = getPrivateKey(alias);
+          if (privKey == null)
+            continue;
+          PublicKey pubKey = chain[0].getPublicKey();
+          if (keyType.equalsIgnoreCase("RSA")
+              || keyType.equalsIgnoreCase("DHE_RSA")
+              || keyType.equalsIgnoreCase("SRP_RSA")
+              || keyType.equalsIgnoreCase("rsa_sign")
+              || keyType.equalsIgnoreCase("RSA_PSK"))
+            {
+              if (!(privKey instanceof RSAPrivateKey) ||
+                  !(pubKey instanceof RSAPublicKey))
+                continue;
+            }
+          else if (keyType.equalsIgnoreCase("DHE_DSS")
+              || keyType.equalsIgnoreCase("dss_sign")
+              || keyType.equalsIgnoreCase("SRP_DSS")
+              || keyType.equalsIgnoreCase("DSA"))
+            {
+              if (!(privKey instanceof DSAPrivateKey) ||
+                  !(pubKey instanceof DSAPublicKey))
+                continue;
+            }
+          else if (keyType.equalsIgnoreCase("DH_RSA")
+              || keyType.equalsIgnoreCase("rsa_fixed_dh"))
+            {
+              if (!(privKey instanceof DHPrivateKey) ||
+                  !(pubKey instanceof DHPublicKey))
+                continue;
+              if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
+                continue;
+            }
+          else if (keyType.equalsIgnoreCase("DH_DSS")
+              || keyType.equalsIgnoreCase("dss_fixed_dh"))
+            {
+              if (!(privKey instanceof DHPrivateKey) ||
+                  !(pubKey instanceof DHPublicKey))
+                continue;
+              if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
+                continue;
+            }
+          else // Unknown key type; ignore it.
+            continue;
+          if (issuers == null || issuers.length == 0)
+            {
+              l.add(alias);
+              continue;
+            }
+          for (Principal issuer : issuers)
+            {
+              if (chain[0].getIssuerDN().equals(issuer))
+                {
+                  l.add(alias);
+                  break;
+                }
+            }
+        }
+      return l.toArray(new String[l.size()]);
+    }
+
+    public X509Certificate[] getCertificateChain(String alias)
+    {
+      X509Certificate[] c = (X509Certificate[]) certChains.get(alias);
+      return c != null ? (X509Certificate[]) c.clone() : null;
+    }
+
+    public PrivateKey getPrivateKey(String alias)
+    {
+      return (PrivateKey) privateKeys.get(alias);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,295 @@
+/* X509TrustManagerFactory.java -- X.509 trust manager factory.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+import javax.net.ssl.X509TrustManager;
+
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.x509.X509CertPath;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.StaticTrustAnchors;
+
+/**
+ * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine
+ * for the ``JessieX509'' algorithm.
+ */
+public class X509TrustManagerFactory extends TrustManagerFactorySpi
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  private static final String sep
+    = AccessController.doPrivileged(new GetPropertyAction("file.separator"));
+  
+  /**
+   * The location of the JSSE key store.
+   */
+  private static final String JSSE_CERTS
+    = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+      + sep + "lib" + sep + "security" + sep + "jssecerts";
+
+  /**
+   * The location of the system key store, containing the CA certs.
+   */
+  private static final String CA_CERTS
+    = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+      + sep + "lib" + sep + "security" + sep + "cacerts";
+
+  private Manager current;
+
+  // Construtors.
+  // -------------------------------------------------------------------------
+
+  public X509TrustManagerFactory()
+  {
+    super();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected TrustManager[] engineGetTrustManagers()
+  {
+    if (current == null)
+      {
+        throw new IllegalStateException("not initialized");
+      }
+    return new TrustManager[] { current };
+  }
+
+  protected void engineInit(ManagerFactoryParameters params)
+    throws InvalidAlgorithmParameterException
+  {
+    if (params instanceof StaticTrustAnchors)
+      {
+        current = new Manager(((StaticTrustAnchors) params).getCertificates());
+      }
+    else if (params instanceof NullManagerParameters)
+      {
+        current = new Manager(new X509Certificate[0]);
+      }
+    else
+      {
+        throw new InvalidAlgorithmParameterException();
+      }
+  }
+
+  protected void engineInit(KeyStore store) throws KeyStoreException
+  {
+    if (store == null)
+      {
+        GetPropertyAction gpa = new GetPropertyAction("javax.net.ssl.trustStoreType");
+        String s = AccessController.doPrivileged(gpa);
+        if (s == null)
+          s = KeyStore.getDefaultType();
+        store = KeyStore.getInstance(s);
+        try
+          {
+            s = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStore"));
+            FileInputStream in = null;
+            if (s == null)
+              {
+                try
+                  {
+                    in = new FileInputStream(JSSE_CERTS);
+                  }
+                catch (IOException e)
+                  {
+                    in = new FileInputStream(CA_CERTS);
+                  }
+              }
+            else
+              {
+                in = new FileInputStream(s);
+              }
+            String p = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStorePassword"));
+            store.load(in, p != null ? p.toCharArray() : null);
+          }
+        catch (IOException ioe)
+          {
+            throw new KeyStoreException(ioe);
+          }
+        catch (CertificateException ce)
+          {
+            throw new KeyStoreException(ce);
+          }
+        catch (NoSuchAlgorithmException nsae)
+          {
+            throw new KeyStoreException(nsae);
+          }
+      }
+
+    LinkedList<X509Certificate> l = new LinkedList<X509Certificate>();
+    Enumeration aliases = store.aliases();
+    while (aliases.hasMoreElements())
+      {
+        String alias = (String) aliases.nextElement();
+        if (!store.isCertificateEntry(alias))
+          continue;
+        Certificate c = store.getCertificate(alias);
+        if (!(c instanceof X509Certificate))
+          continue;
+        l.add((X509Certificate) c);
+      }
+    current = this.new Manager(l.toArray(new X509Certificate[l.size()]));
+  }
+
+  // Inner class.
+  // -------------------------------------------------------------------------
+
+  /**
+   * The actual manager implementation returned.
+   */
+  private class Manager implements X509TrustManager
+  {
+
+    // Fields.
+    // -----------------------------------------------------------------------
+
+    private final Set<TrustAnchor> anchors;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    Manager(X509Certificate[] trusted)
+    {
+      anchors = new HashSet<TrustAnchor>();
+      if (trusted != null)
+        {
+          for (X509Certificate cert : trusted)
+            {
+              anchors.add(new TrustAnchor(cert, null));
+            }
+        }
+    }
+
+    // Instance methodns.
+    // -----------------------------------------------------------------------
+
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+      throws CertificateException
+    {
+      checkTrusted(chain, authType);
+    }
+
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+      throws CertificateException
+    {
+      checkTrusted(chain, authType);
+    }
+
+    public X509Certificate[] getAcceptedIssuers()
+    {
+      return anchors.toArray(new X509Certificate[anchors.size()]);
+    }
+
+    // Own methods.
+    // -----------------------------------------------------------------------
+
+    private void checkTrusted(X509Certificate[] chain, String authType)
+      throws CertificateException
+    {
+      CertPathValidator validator = null;
+      
+      try
+        {
+          validator = CertPathValidator.getInstance("PKIX");
+        }
+      catch (NoSuchAlgorithmException nsae)
+        {
+          throw new CertificateException(nsae);
+        }
+      
+      CertPath path = new X509CertPath(Arrays.asList(chain));
+      
+      PKIXParameters params = null;
+      try
+        {
+          params = new PKIXParameters(anchors);
+          // XXX we probably do want to enable revocation, but it's a pain
+          // in the ass.
+          params.setRevocationEnabled(false);
+        }
+      catch (InvalidAlgorithmParameterException iape)
+        {
+          throw new CertificateException(iape);
+        }
+      
+      try
+        {
+          validator.validate(path, params);
+        }
+      catch (CertPathValidatorException cpve)
+        {
+          throw new CertificateException(cpve);
+        }
+      catch (InvalidAlgorithmParameterException iape)
+        {
+          throw new CertificateException(iape);
+        }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/javax/net/VanillaServerSocketFactory.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,82 @@
+/* VanillaServerSocketFactory.java -- trivial socket factory.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.net;
+
+import java.io.IOException;
+
+import java.net.InetAddress;
+import java.net.ServerSocket;
+
+/**
+ * A trivial server socket factory.
+ */
+class VanillaServerSocketFactory extends ServerSocketFactory
+{
+
+  // Constructor.
+  // ------------------------------------------------------------------
+
+  VanillaServerSocketFactory()
+  {
+    super();
+  }
+
+  // Instance methods.
+  // ------------------------------------------------------------------
+
+  public ServerSocket createServerSocket() throws IOException
+  {
+    return new ServerSocket();
+  }
+
+  public ServerSocket createServerSocket(int port) throws IOException
+  {
+    return new ServerSocket(port);
+  }
+
+  public ServerSocket createServerSocket(int port, int backlog) throws IOException
+  {
+    return new ServerSocket(port, backlog);
+  }
+
+  public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddress) throws IOException
+  {
+    return new ServerSocket(port, backlog, bindAddress);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/javax/net/VanillaSocketFactory.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,88 @@
+/* VanillaSocketFactory.java -- trivial socket factory.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.net;
+
+import java.io.IOException;
+
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * A trivial client socket factory.
+ */
+class VanillaSocketFactory extends SocketFactory
+{
+
+  // Constructor.
+  // ------------------------------------------------------------------
+
+  VanillaSocketFactory()
+  {
+    super();
+  }
+
+  // Instance methods.
+  // ------------------------------------------------------------------
+
+  public Socket createSocket() throws IOException
+  {
+    return new Socket();
+  }
+
+  public Socket createSocket(String host, int port) throws IOException, UnknownHostException
+  {
+    return new Socket(host, port);
+  }
+
+  public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) throws IOException, UnknownHostException
+  {
+    return new Socket(host, port, localAddr, localPort);
+  }
+
+  public Socket createSocket(InetAddress address, int port) throws IOException
+  {
+    return new Socket(address, port);
+  }
+
+  public Socket createSocket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
+  {
+    return new Socket(address, port, localAddr, localPort);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/javax/net/ssl/TrivialHostnameVerifier.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,51 @@
+/* TrivialHostnameVerifier.java -- non-verifing verifier.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.net.ssl;
+
+/**
+ * A hostname verifier that always rejects mismatched hostnames.
+ */
+class TrivialHostnameVerifier implements HostnameVerifier
+{
+
+  public boolean verify(String hostname, SSLSession session)
+  {
+    return false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/gnu/java/util/Base64.java	Wed Jun 27 12:37:11 2007 -0400
@@ -0,0 +1,340 @@
+/* Base64.java -- Base64 encoding and decoding.
+   Copyright (C) 2006, 2007  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+
+--
+Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP
+follow. See http://www.isc.org/products/DHCP/.
+
+Copyright (c) 1996 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+--
+Portions Copyright (c) 1995 by International Business Machines, Inc.
+
+International Business Machines, Inc. (hereinafter called IBM) grants
+permission under its copyrights to use, copy, modify, and distribute
+this Software with or without fee, provided that the above copyright
+notice and all paragraphs of this notice appear in all copies, and
+that the name of IBM not be used in connection with the marketing of
+any product incorporating the Software or modifications thereof,
+without specific, written prior permission.
+
+To the extent it has a right to do so, IBM grants an immunity from
+suit under its patents, if any, for the use, sale or manufacture of
+products to the extent that such products are used for performing
+Domain Name System dynamic updates in TCP/IP networks by means of the
+Software.  No immunity is granted for any product per se or for any
+other function of any product.
+
+THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH
+DAMAGES.  */
+
+
+package gnu.java.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public final class Base64
+{
+
+  // No constructor.
+  private Base64() { }
+
+  // Class methods.
+  // -------------------------------------------------------------------------
+
+  /** Base-64 characters. */
+  private static final String BASE_64 =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /** Base-64 padding character. */
+  private static final char BASE_64_PAD = '=';
+
+  /**
+   * Base64 encode a byte array, with no line wrapping.
+   *
+   * @param buf The byte array to encode.
+   * @return <tt>buf</tt> encoded in Base64.
+   */
+  public static String encode(byte[] buf)
+  {
+    return encode(buf, 0);
+  }
+  
+  /**
+   * Base64 encode a byte array, returning the returning string.
+   *
+   * @param buf The byte array to encode.
+   * @param tw  The total length of any line, 0 for unlimited.
+   * @return <tt>buf</tt> encoded in Base64.
+   */
+  public static String encode(byte[] buf, int tw)
+  {
+    return encode(buf, 0, buf.length, tw);
+  }
+
+  /**
+   * Base64 encode a byte array, returning the returning string.
+   * 
+   * @param buf The byte array to encode.
+   * @param offset The offset in the byte array to start.
+   * @param length The number of bytes to encode.
+   * @param tw The total length of any line, 0 for unlimited.
+   * @return <tt>buf</tt> encoded in Base64.
+   */
+  public static String encode(byte[] buf, int offset, int length, int tw)
+  {
+    if (offset < 0 || length < 0 || offset + length > buf.length)
+      throw new ArrayIndexOutOfBoundsException(buf.length  + " "
+                                               + offset + " "
+                                               + length);
+    int srcLength = buf.length - offset;
+    byte[] input = new byte[3];
+    int[] output = new int[4];
+    StringBuffer out = new StringBuffer();
+    int i = offset;
+    int chars = 0;
+
+    while (srcLength > 2)
+      {
+        input[0] = buf[i++];
+        input[1] = buf[i++];
+        input[2] = buf[i++];
+        srcLength -= 3;
+
+        output[0] = (input[0] & 0xff) >>> 2;
+        output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4);
+        output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6);
+        output[3] = input[2] & 0x3f;
+
+        out.append(BASE_64.charAt(output[0]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        out.append(BASE_64.charAt(output[1]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        out.append(BASE_64.charAt(output[2]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        out.append(BASE_64.charAt(output[3]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+      }
+
+    if (srcLength != 0)
+      {
+        input[0] = input[1] = input[2] = 0;
+        for (int j = 0; j < srcLength; j++)
+          {
+            input[j] = buf[i+j];
+          }
+        output[0] = (input[0] & 0xff) >>> 2;
+        output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4);
+        output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6);
+
+        out.append(BASE_64.charAt(output[0]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        out.append(BASE_64.charAt(output[1]));
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        if (srcLength == 1)
+          {
+            out.append(BASE_64_PAD);
+          }
+        else
+          {
+            out.append(BASE_64.charAt(output[2]));
+          }
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+        out.append(BASE_64_PAD);
+        if (tw > 0 && ++chars % tw == 0)
+          {
+            out.append("\n");
+          }
+      }
+    if (tw > 0)
+      {
+        out.append("\n");
+      }
+
+    return out.toString();
+  }
+
+  /**
+   * Decode a Base-64 string into a byte array.
+   *
+   * @param b64 The Base-64 encoded string.
+   * @return The decoded bytes.
+   * @throws java.io.IOException If the argument is not a valid Base-64
+   *    encoding.
+   */
+  public static byte[] decode(String b64) throws IOException
+  {
+    ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3);
+    int state = 0, i;
+    byte temp = 0;
+
+    for (i = 0; i < b64.length(); i++)
+      {
+        if (Character.isWhitespace(b64.charAt(i)))
+          {
+            continue;
+          }
+        if (b64.charAt(i) == BASE_64_PAD)
+          {
+            break;
+          }
+
+        int pos = BASE_64.indexOf(b64.charAt(i));
+        if (pos < 0)
+          {
+            throw new IOException("non-Base64 character " + b64.charAt(i));
+          }
+        switch (state)
+          {
+          case 0:
+            temp = (byte) (pos - BASE_64.indexOf('A') << 2);
+            state = 1;
+            break;
+
+          case 1:
+            temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4);
+            result.write(temp);
+            temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4);
+            state = 2;
+            break;
+
+          case 2:
+            temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2);
+            result.write(temp);
+            temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6);
+            state = 3;
+            break;
+
+          case 3:
+            temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff);
+            result.write(temp);
+            state = 0;
+            break;
+
+          default:
+            throw new Error("this statement should be unreachable");
+          }
+      }
+
+    if (i < b64.length() && b64.charAt(i) == BASE_64_PAD)
+      {
+        switch (state)
+          {
+          case 0:
+          case 1:
+            throw new IOException("malformed Base64 sequence");
+
+          case 2:
+            i++;
+            for ( ; i < b64.length(); i++)
+              {
+                if (!Character.isWhitespace(b64.charAt(i)))
+                  {
+                    break;
+                  }
+              }
+            // We must see a second pad character here.
+            if (b64.charAt(i) != BASE_64_PAD)
+              {
+                throw new IOException("malformed Base64 sequence");
+              }
+            i++;
+            // Fall-through.
+
+          case 3:
+            i++;
+            for ( ; i < b64.length(); i++)
+              {
+                // We should only see whitespace after this.
+                if (!Character.isWhitespace(b64.charAt(i)))
+                  {
+                    throw new IOException("malformed Base64 sequence");
+                  }
+              }
+          }
+      }
+    else
+      {
+        if (state != 0)
+          {
+            throw new IOException("malformed Base64 sequence");
+          }
+      }
+
+    return result.toByteArray();
+  }
+}