summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Marshall <csm@gnu.org>2006-08-14 22:36:17 +0000
committerCasey Marshall <csm@gnu.org>2006-08-14 22:36:17 +0000
commit8c09ba9b0bb2b3c6768d7bf7849bf5e096efdc16 (patch)
tree2385de1ad71e083a0394a98b0865c95187cfeb76
parent32bb0e9c211961fbade190535b8041ece5df772c (diff)
downloadclasspath-8c09ba9b0bb2b3c6768d7bf7849bf5e096efdc16.tar.gz
2006-08-14 Casey Marshall <csm@gnu.org>
Merge in ssl-nio-branch work. See `ChangeLog-ssl-nio' for a record of changes made on this branch. Files modified: * gnu/classpath/debug/Component.java * gnu/classpath/debug/SystemLogger.java * gnu/java/security/action/GetPropertyAction.java * gnu/java/security/action/GetSecurityPropertyAction.java * gnu/javax/crypto/RSACipherImpl.java * gnu/javax/net/ssl/PrivateCredentials.java * gnu/javax/net/ssl/provider/Alert.java * gnu/javax/net/ssl/provider/AlertException.java * gnu/javax/net/ssl/provider/Certificate.java * gnu/javax/net/ssl/provider/CertificateRequest.java * gnu/javax/net/ssl/provider/CertificateType.java * gnu/javax/net/ssl/provider/CertificateVerify.java * gnu/javax/net/ssl/provider/CipherSuite.java * gnu/javax/net/ssl/provider/ClientHello.java * gnu/javax/net/ssl/provider/ClientKeyExchange.java * gnu/javax/net/ssl/provider/CompressionMethod.java * gnu/javax/net/ssl/provider/Constructed.java * gnu/javax/net/ssl/provider/ContentType.java * gnu/javax/net/ssl/provider/DiffieHellman.java * gnu/javax/net/ssl/provider/Extension.java * gnu/javax/net/ssl/provider/Finished.java * gnu/javax/net/ssl/provider/Handshake.java * gnu/javax/net/ssl/provider/Jessie.java * gnu/javax/net/ssl/provider/ProtocolVersion.java * gnu/javax/net/ssl/provider/Random.java * gnu/javax/net/ssl/provider/ServerHello.java * gnu/javax/net/ssl/provider/ServerKeyExchange.java * gnu/javax/net/ssl/provider/Signature.java * gnu/javax/net/ssl/provider/Util.java * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java * gnu/javax/net/ssl/provider/X509TrustManagerFactory.java * java/security/MessageDigest.java * java/security/MessageDigestSpi.java * java/security/Signature.java * java/security/SignatureSpi.java * javax/crypto/Mac.java * javax/crypto/MacSpi.java * javax/net/ssl/HandshakeCompletedEvent.java * javax/net/ssl/HttpsURLConnection.java * javax/net/ssl/SSLContext.java * javax/net/ssl/SSLContextSpi.java * javax/net/ssl/SSLSession.java Files added: * gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java * gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java * gnu/javax/net/ssl/provider/SimpleSessionContext.java * gnu/javax/net/ssl/provider/ServerRSAParams.java * gnu/javax/net/ssl/provider/SSLContextImpl.java * gnu/javax/net/ssl/provider/ServerDHParams.java * gnu/javax/net/ssl/provider/ClientHelloBuilder.java * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java * gnu/javax/net/ssl/provider/SignatureAlgorithm.java * gnu/javax/net/ssl/provider/CipherSuiteList.java * gnu/javax/net/ssl/provider/ServerNameList.java * gnu/javax/net/ssl/provider/SSLServerSocketImpl.java * gnu/javax/net/ssl/provider/CompressionMethodList.java * gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java * gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java * gnu/javax/net/ssl/provider/TrustedAuthorities.java * gnu/javax/net/ssl/provider/CertificateStatusRequest.java * gnu/javax/net/ssl/provider/ServerHelloDone.java * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java * gnu/javax/net/ssl/provider/SSLSocketImpl.java * gnu/javax/net/ssl/provider/ServerHelloBuilder.java * gnu/javax/net/ssl/provider/Record.java * gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java * gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java * gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java * gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java * gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java * gnu/javax/net/ssl/provider/CertificateBuilder.java * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java * gnu/javax/net/ssl/provider/CertificateStatusType.java * gnu/javax/net/ssl/provider/ExtensionList.java * gnu/javax/net/ssl/provider/ClientCertificateTypeList.java * gnu/javax/net/ssl/provider/ClientPSKParameters.java * gnu/javax/net/ssl/provider/X500PrincipalList.java * gnu/javax/net/ssl/provider/ServerHandshake.java * gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java * gnu/javax/net/ssl/provider/SessionImpl.java * gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java * gnu/javax/net/ssl/provider/ServerPSKParameters.java * gnu/javax/net/ssl/provider/TruncatedHMAC.java * gnu/javax/net/ssl/provider/MaxFragmentLength.java * gnu/javax/net/ssl/provider/HelloRequest.java * gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java * gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java * gnu/javax/net/ssl/provider/CipherAlgorithm.java * gnu/javax/net/ssl/provider/ClientHandshake.java * gnu/javax/net/ssl/provider/ExchangeKeys.java * gnu/javax/net/ssl/provider/CertificateURL.java * gnu/javax/net/ssl/provider/EmptyExchangeKeys.java * gnu/javax/net/ssl/provider/CertificateRequestBuilder.java * gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java * gnu/javax/net/ssl/provider/Builder.java * gnu/javax/net/ssl/provider/Debug.java * gnu/javax/net/ssl/provider/SSLEngineImpl.java * gnu/javax/net/ssl/provider/MacAlgorithm.java * gnu/javax/net/ssl/provider/DelegatedTask.java * gnu/javax/net/ssl/provider/InputSecurityParameters.java * gnu/javax/net/ssl/provider/ClientHelloV2.java * gnu/javax/net/ssl/provider/OutputSecurityParameters.java * gnu/javax/net/ssl/provider/AbstractHandshake.java * javax/net/ssl/SSLEngine.java * javax/net/ssl/CertPathTrustManagerParameters.java * javax/net/ssl/KeyStoreBuilderParameters.java * javax/net/ssl/X509ExtendedKeyManager.java * javax/net/ssl/SSLEngineResult.java * gnu/javax/net/ssl/PreSharedKeyManager.java * gnu/javax/net/ssl/Session.java * gnu/javax/net/ssl/PreSharedKeyManagerParameters.java * gnu/javax/net/ssl/SSLCipherSuite.java * gnu/javax/net/ssl/AbstractSessionContext.java * gnu/javax/net/ssl/SessionStoreException.java * gnu/javax/net/ssl/SSLRecordHandler.java * gnu/javax/net/ssl/SSLProtocolVersion.java * gnu/javax/crypto/key/GnuPBEKey.java * gnu/java/security/util/ByteBufferOutputStream.java * gnu/java/security/Requires.java * gnu/javax/security/auth/callback/CertificateCallback.java Files removed: * gnu/javax/net/ssl/provider/Context.java * gnu/javax/net/ssl/provider/DigestInputStream.java * gnu/javax/net/ssl/provider/DigestOutputStream.java * gnu/javax/net/ssl/provider/Enumerated.java * gnu/javax/net/ssl/provider/Extensions.java * gnu/javax/net/ssl/provider/GNUSecurityParameters.java * gnu/javax/net/ssl/provider/JCESecurityParameters.java * gnu/javax/net/ssl/provider/JDBCSessionContext.java * gnu/javax/net/ssl/provider/JessieDHPrivateKey.java * gnu/javax/net/ssl/provider/JessieDHPublicKey.java * gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java * gnu/javax/net/ssl/provider/JessieRSAPublicKey.java * gnu/javax/net/ssl/provider/KeyPool.java * gnu/javax/net/ssl/provider/OverflowException.java * gnu/javax/net/ssl/provider/RecordInput.java * gnu/javax/net/ssl/provider/RecordInputStream.java * gnu/javax/net/ssl/provider/RecordOutputStream.java * gnu/javax/net/ssl/provider/RecordingInputStream.java * gnu/javax/net/ssl/provider/SSLRSASignature.java * gnu/javax/net/ssl/provider/SSLServerSocket.java * gnu/javax/net/ssl/provider/SSLServerSocketFactory.java * gnu/javax/net/ssl/provider/SSLSocket.java * gnu/javax/net/ssl/provider/SSLSocketFactory.java * gnu/javax/net/ssl/provider/SSLSocketInputStream.java * gnu/javax/net/ssl/provider/SSLSocketOutputStream.java * gnu/javax/net/ssl/provider/SecurityParameters.java * gnu/javax/net/ssl/provider/Session.java * gnu/javax/net/ssl/provider/SessionContext.java * gnu/javax/net/ssl/provider/SynchronizedRandom.java * gnu/javax/net/ssl/provider/XMLSessionContext.java
-rw-r--r--ChangeLog80
-rw-r--r--ChangeLog-ssl-nio642
-rw-r--r--gnu/classpath/debug/Component.java7
-rw-r--r--gnu/classpath/debug/SystemLogger.java41
-rw-r--r--gnu/java/security/Requires.java59
-rw-r--r--gnu/java/security/action/GetPropertyAction.java4
-rw-r--r--gnu/java/security/action/GetSecurityPropertyAction.java4
-rw-r--r--gnu/java/security/util/ByteBufferOutputStream.java118
-rw-r--r--gnu/javax/crypto/RSACipherImpl.java67
-rw-r--r--gnu/javax/crypto/key/GnuPBEKey.java95
-rw-r--r--gnu/javax/net/ssl/AbstractSessionContext.java288
-rw-r--r--gnu/javax/net/ssl/PreSharedKeyManager.java54
-rw-r--r--gnu/javax/net/ssl/PreSharedKeyManagerParameters.java83
-rw-r--r--gnu/javax/net/ssl/PrivateCredentials.java16
-rw-r--r--gnu/javax/net/ssl/SSLCipherSuite.java142
-rw-r--r--gnu/javax/net/ssl/SSLProtocolVersion.java54
-rw-r--r--gnu/javax/net/ssl/SSLRecordHandler.java101
-rw-r--r--gnu/javax/net/ssl/Session.java364
-rw-r--r--gnu/javax/net/ssl/SessionStoreException.java59
-rw-r--r--gnu/javax/net/ssl/provider/AbstractHandshake.java1205
-rw-r--r--gnu/javax/net/ssl/provider/Alert.java422
-rw-r--r--gnu/javax/net/ssl/provider/AlertException.java37
-rw-r--r--gnu/javax/net/ssl/provider/Builder.java66
-rw-r--r--gnu/javax/net/ssl/provider/Certificate.java205
-rw-r--r--gnu/javax/net/ssl/provider/CertificateBuilder.java (renamed from gnu/javax/net/ssl/provider/DigestInputStream.java)95
-rw-r--r--gnu/javax/net/ssl/provider/CertificateRequest.java226
-rw-r--r--gnu/javax/net/ssl/provider/CertificateRequestBuilder.java113
-rw-r--r--gnu/javax/net/ssl/provider/CertificateStatusRequest.java272
-rw-r--r--gnu/javax/net/ssl/provider/CertificateStatusType.java13
-rw-r--r--gnu/javax/net/ssl/provider/CertificateType.java56
-rw-r--r--gnu/javax/net/ssl/provider/CertificateURL.java388
-rw-r--r--gnu/javax/net/ssl/provider/CertificateVerify.java54
-rw-r--r--gnu/javax/net/ssl/provider/CipherAlgorithm.java (renamed from gnu/javax/net/ssl/provider/OverflowException.java)22
-rw-r--r--gnu/javax/net/ssl/provider/CipherSuite.java1193
-rw-r--r--gnu/javax/net/ssl/provider/CipherSuiteList.java283
-rw-r--r--gnu/javax/net/ssl/provider/ClientCertificateTypeList.java227
-rw-r--r--gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java122
-rw-r--r--gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java129
-rw-r--r--gnu/javax/net/ssl/provider/ClientHandshake.java1150
-rw-r--r--gnu/javax/net/ssl/provider/ClientHello.java315
-rw-r--r--gnu/javax/net/ssl/provider/ClientHelloBuilder.java137
-rw-r--r--gnu/javax/net/ssl/provider/ClientHelloV2.java158
-rw-r--r--gnu/javax/net/ssl/provider/ClientKeyExchange.java163
-rw-r--r--gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java75
-rw-r--r--gnu/javax/net/ssl/provider/ClientPSKParameters.java125
-rw-r--r--gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java126
-rw-r--r--gnu/javax/net/ssl/provider/CompressionMethod.java51
-rw-r--r--gnu/javax/net/ssl/provider/CompressionMethodList.java281
-rw-r--r--gnu/javax/net/ssl/provider/Constructed.java47
-rw-r--r--gnu/javax/net/ssl/provider/ContentType.java72
-rw-r--r--gnu/javax/net/ssl/provider/Context.java334
-rw-r--r--gnu/javax/net/ssl/provider/Debug.java66
-rw-r--r--gnu/javax/net/ssl/provider/DelegatedTask.java93
-rw-r--r--gnu/javax/net/ssl/provider/DiffieHellman.java6
-rw-r--r--gnu/javax/net/ssl/provider/DigestOutputStream.java107
-rw-r--r--gnu/javax/net/ssl/provider/EmptyExchangeKeys.java77
-rw-r--r--gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java151
-rw-r--r--gnu/javax/net/ssl/provider/ExchangeKeys.java54
-rw-r--r--gnu/javax/net/ssl/provider/Extension.java260
-rw-r--r--gnu/javax/net/ssl/provider/ExtensionList.java290
-rw-r--r--gnu/javax/net/ssl/provider/Extensions.java159
-rw-r--r--gnu/javax/net/ssl/provider/Finished.java146
-rw-r--r--gnu/javax/net/ssl/provider/GNUSecurityParameters.java490
-rw-r--r--gnu/javax/net/ssl/provider/Handshake.java472
-rw-r--r--gnu/javax/net/ssl/provider/HelloRequest.java (renamed from gnu/javax/net/ssl/provider/Enumerated.java)55
-rw-r--r--gnu/javax/net/ssl/provider/InputSecurityParameters.java336
-rw-r--r--gnu/javax/net/ssl/provider/JCESecurityParameters.java307
-rw-r--r--gnu/javax/net/ssl/provider/JDBCSessionContext.java356
-rw-r--r--gnu/javax/net/ssl/provider/Jessie.java35
-rw-r--r--gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java57
-rw-r--r--gnu/javax/net/ssl/provider/KeyPool.java110
-rw-r--r--gnu/javax/net/ssl/provider/MacAlgorithm.java47
-rw-r--r--gnu/javax/net/ssl/provider/MaxFragmentLength.java59
-rw-r--r--gnu/javax/net/ssl/provider/OutputSecurityParameters.java297
-rw-r--r--gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java118
-rw-r--r--gnu/javax/net/ssl/provider/ProtocolVersion.java73
-rw-r--r--gnu/javax/net/ssl/provider/Random.java112
-rw-r--r--gnu/javax/net/ssl/provider/Record.java198
-rw-r--r--gnu/javax/net/ssl/provider/RecordInput.java232
-rw-r--r--gnu/javax/net/ssl/provider/RecordOutputStream.java189
-rw-r--r--gnu/javax/net/ssl/provider/RecordingInputStream.java131
-rw-r--r--gnu/javax/net/ssl/provider/SSLContextImpl.java315
-rw-r--r--gnu/javax/net/ssl/provider/SSLEngineImpl.java842
-rw-r--r--gnu/javax/net/ssl/provider/SSLRSASignature.java235
-rw-r--r--gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java233
-rw-r--r--gnu/javax/net/ssl/provider/SSLServerSocket.java283
-rw-r--r--gnu/javax/net/ssl/provider/SSLServerSocketFactory.java136
-rw-r--r--gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java108
-rw-r--r--gnu/javax/net/ssl/provider/SSLServerSocketImpl.java199
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocket.java3530
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocketFactory.java133
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java137
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocketImpl.java833
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocketInputStream.java181
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocketOutputStream.java115
-rw-r--r--gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java116
-rw-r--r--gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java116
-rw-r--r--gnu/javax/net/ssl/provider/SecurityParameters.java178
-rw-r--r--gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java151
-rw-r--r--gnu/javax/net/ssl/provider/ServerDHParams.java248
-rw-r--r--gnu/javax/net/ssl/provider/ServerHandshake.java1377
-rw-r--r--gnu/javax/net/ssl/provider/ServerHello.java271
-rw-r--r--gnu/javax/net/ssl/provider/ServerHelloBuilder.java131
-rw-r--r--gnu/javax/net/ssl/provider/ServerHelloDone.java66
-rw-r--r--gnu/javax/net/ssl/provider/ServerKeyExchange.java311
-rw-r--r--gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java (renamed from gnu/javax/net/ssl/provider/RecordInputStream.java)89
-rw-r--r--gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java50
-rw-r--r--gnu/javax/net/ssl/provider/ServerNameList.java311
-rw-r--r--gnu/javax/net/ssl/provider/ServerPSKParameters.java127
-rw-r--r--gnu/javax/net/ssl/provider/ServerRSAParams.java163
-rw-r--r--gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java62
-rw-r--r--gnu/javax/net/ssl/provider/Session.java381
-rw-r--r--gnu/javax/net/ssl/provider/SessionContext.java250
-rw-r--r--gnu/javax/net/ssl/provider/SessionImpl.java198
-rw-r--r--gnu/javax/net/ssl/provider/Signature.java140
-rw-r--r--gnu/javax/net/ssl/provider/SignatureAlgorithm.java62
-rw-r--r--gnu/javax/net/ssl/provider/SimpleSessionContext.java146
-rw-r--r--gnu/javax/net/ssl/provider/SynchronizedRandom.java104
-rw-r--r--gnu/javax/net/ssl/provider/TruncatedHMAC.java (renamed from gnu/javax/net/ssl/provider/JessieDHPrivateKey.java)69
-rw-r--r--gnu/javax/net/ssl/provider/TrustedAuthorities.java298
-rw-r--r--gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java (renamed from gnu/javax/net/ssl/provider/JessieDHPublicKey.java)72
-rw-r--r--gnu/javax/net/ssl/provider/Util.java109
-rw-r--r--gnu/javax/net/ssl/provider/X500PrincipalList.java272
-rw-r--r--gnu/javax/net/ssl/provider/X509KeyManagerFactory.java95
-rw-r--r--gnu/javax/net/ssl/provider/X509TrustManagerFactory.java147
-rw-r--r--gnu/javax/net/ssl/provider/XMLSessionContext.java619
-rw-r--r--gnu/javax/security/auth/callback/CertificateCallback.java (renamed from gnu/javax/net/ssl/provider/JessieRSAPublicKey.java)78
-rw-r--r--java/security/MessageDigest.java12
-rw-r--r--java/security/MessageDigestSpi.java19
-rw-r--r--java/security/Signature.java17
-rw-r--r--java/security/SignatureSpi.java19
-rw-r--r--javax/crypto/Mac.java13
-rw-r--r--javax/crypto/MacSpi.java18
-rw-r--r--javax/net/ssl/CertPathTrustManagerParameters.java71
-rw-r--r--javax/net/ssl/HandshakeCompletedEvent.java31
-rw-r--r--javax/net/ssl/HttpsURLConnection.java45
-rw-r--r--javax/net/ssl/KeyStoreBuilderParameters.java48
-rw-r--r--javax/net/ssl/SSLContext.java25
-rw-r--r--javax/net/ssl/SSLContextSpi.java22
-rw-r--r--javax/net/ssl/SSLEngine.java442
-rw-r--r--javax/net/ssl/SSLEngineResult.java194
-rw-r--r--javax/net/ssl/SSLSession.java67
-rw-r--r--javax/net/ssl/X509ExtendedKeyManager.java (renamed from gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java)92
143 files changed, 19095 insertions, 11650 deletions
diff --git a/ChangeLog b/ChangeLog
index 04c86c972..65e56db12 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,83 @@
+2006-08-14 Casey Marshall <csm@gnu.org>
+
+ Merge in ssl-nio-branch work. See `ChangeLog-ssl-nio' for a record
+ of changes made on this branch.
+ Files modified:
+ * gnu/classpath/debug/Component.java
+ * gnu/classpath/debug/SystemLogger.java
+ * gnu/java/security/action/GetPropertyAction.java
+ * gnu/java/security/action/GetSecurityPropertyAction.java
+ * gnu/javax/crypto/RSACipherImpl.java
+ * gnu/javax/net/ssl/PrivateCredentials.java
+ * gnu/javax/net/ssl/provider/Alert.java
+ * gnu/javax/net/ssl/provider/AlertException.java
+ * gnu/javax/net/ssl/provider/Certificate.java
+ * gnu/javax/net/ssl/provider/CertificateRequest.java
+ * gnu/javax/net/ssl/provider/CertificateType.java
+ * gnu/javax/net/ssl/provider/CertificateVerify.java
+ * gnu/javax/net/ssl/provider/CipherSuite.java
+ * gnu/javax/net/ssl/provider/ClientHello.java
+ * gnu/javax/net/ssl/provider/ClientKeyExchange.java
+ * gnu/javax/net/ssl/provider/CompressionMethod.java
+ * gnu/javax/net/ssl/provider/Constructed.java
+ * gnu/javax/net/ssl/provider/ContentType.java
+ * gnu/javax/net/ssl/provider/DiffieHellman.java
+ * gnu/javax/net/ssl/provider/Extension.java
+ * gnu/javax/net/ssl/provider/Finished.java
+ * gnu/javax/net/ssl/provider/Handshake.java
+ * gnu/javax/net/ssl/provider/Jessie.java
+ * gnu/javax/net/ssl/provider/ProtocolVersion.java
+ * gnu/javax/net/ssl/provider/Random.java
+ * gnu/javax/net/ssl/provider/ServerHello.java
+ * gnu/javax/net/ssl/provider/ServerKeyExchange.java
+ * gnu/javax/net/ssl/provider/Signature.java
+ * gnu/javax/net/ssl/provider/Util.java
+ * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
+ * gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
+ * java/security/MessageDigest.java
+ * java/security/MessageDigestSpi.java
+ * java/security/Signature.java
+ * java/security/SignatureSpi.java
+ * javax/crypto/Mac.java
+ * javax/crypto/MacSpi.java
+ * javax/net/ssl/HandshakeCompletedEvent.java
+ * javax/net/ssl/HttpsURLConnection.java
+ * javax/net/ssl/SSLContext.java
+ * javax/net/ssl/SSLContextSpi.java
+ * javax/net/ssl/SSLSession.java
+ Files added:
+ Files removed:
+ * gnu/javax/net/ssl/provider/Context.java
+ * gnu/javax/net/ssl/provider/DigestInputStream.java
+ * gnu/javax/net/ssl/provider/DigestOutputStream.java
+ * gnu/javax/net/ssl/provider/Enumerated.java
+ * gnu/javax/net/ssl/provider/Extensions.java
+ * gnu/javax/net/ssl/provider/GNUSecurityParameters.java
+ * gnu/javax/net/ssl/provider/JCESecurityParameters.java
+ * gnu/javax/net/ssl/provider/JDBCSessionContext.java
+ * gnu/javax/net/ssl/provider/JessieDHPrivateKey.java
+ * gnu/javax/net/ssl/provider/JessieDHPublicKey.java
+ * gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
+ * gnu/javax/net/ssl/provider/JessieRSAPublicKey.java
+ * gnu/javax/net/ssl/provider/KeyPool.java
+ * gnu/javax/net/ssl/provider/OverflowException.java
+ * gnu/javax/net/ssl/provider/RecordInput.java
+ * gnu/javax/net/ssl/provider/RecordInputStream.java
+ * gnu/javax/net/ssl/provider/RecordOutputStream.java
+ * gnu/javax/net/ssl/provider/RecordingInputStream.java
+ * gnu/javax/net/ssl/provider/SSLRSASignature.java
+ * gnu/javax/net/ssl/provider/SSLServerSocket.java
+ * gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
+ * gnu/javax/net/ssl/provider/SSLSocket.java
+ * gnu/javax/net/ssl/provider/SSLSocketFactory.java
+ * gnu/javax/net/ssl/provider/SSLSocketInputStream.java
+ * gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
+ * gnu/javax/net/ssl/provider/SecurityParameters.java
+ * gnu/javax/net/ssl/provider/Session.java
+ * gnu/javax/net/ssl/provider/SessionContext.java
+ * gnu/javax/net/ssl/provider/SynchronizedRandom.java
+ * gnu/javax/net/ssl/provider/XMLSessionContext.java
+
2006-08-11 Andrew John Hughes <gnu_andrew@member.fsf.org>
* vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java:
diff --git a/ChangeLog-ssl-nio b/ChangeLog-ssl-nio
new file mode 100644
index 000000000..f15d93cac
--- /dev/null
+++ b/ChangeLog-ssl-nio
@@ -0,0 +1,642 @@
+2006-07-18 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/ClientHandshake.java
+ (implHandleInput, implHandleOutput): fix PSK exchange handling.
+ (ClientDHGen.full): new field.
+ (ClientDHGen.implRun): run full key exchange if `full' is true.
+ (ClientDHGen.serverKey): new method.
+ (RSAGen.full): new field.
+ (RSAGen.implRun): run full key exchange if `full' is true.
+ * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
+ (params): slice the buffer.
+ * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
+ (<init>): use `dhParams,' not `buffer.'
+ (params): slice the buffer.
+ * gnu/javax/net/ssl/provider/ServerKeyExchange.java (length):
+ handle case where parameters or signature are null.
+ * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
+ (version): removed.
+ (<init>): don't take version argument.
+ (<init>): don't take version argument; take buffer argument.
+ (secret): pass TLS_1 to EncryptedPreMasterSecret constructor.
+ * gnu/javax/net/ssl/provider/CipherSuite.java (isResolved): new
+ field.
+ (<init>, <init>): set `isResolved.'
+ (resolve): add PSK cipher suite detection.
+ (isResolved): new method.
+ * gnu/javax/net/ssl/provider/ServerHandshake.java (serverKey): new
+ field.
+ (chooseSuites): choose NONE key exchanges, too; omit unresolved
+ cipher suites.
+ (implHandleInput, implHandleOutput): fix PSK handling.
+ (checkKeyExchange): update for NONE and PSK exchanges.
+ (CertLoader.implRun): grab our private key here.
+ (RSAKeyExchange.implRun): initialize RSA cipher with our private
+ key.
+ (RSA_PSKExchange.implRun): likewise.
+ * gnu/javax/net/ssl/provider/ExchangeKeys.java (<init>): duplicate
+ and order the buffer; handle null argument.
+ * gnu/javax/net/ssl/provider/ClientKeyExchange.java
+ (exchangeKeys): handle NONE exchange.
+ * gnu/javax/net/ssl/provider/SSLContextImpl.java (engineInit):
+ handle PSK key managers properly.
+ * gnu/javax/net/ssl/provider/SSLEngineImpl.java (<init>): remove
+ debug logging.
+ * gnu/javax/net/ssl/provider/ServerDHParams.java (<init>):
+ duplicate and order the buffer.
+ * gnu/javax/crypto/RSACipherImpl.java (doFinal): allow short
+ input.
+ (rsaDecrypt): ensure there's a leading zero.
+ * gnu/javax/net/ssl/provider/EmptyExchangeKeys.java: new file.
+
+2006-07-14 Casey Marshall <csm@gnu.org>
+
+ * gnu/java/net/protocol/http/HTTPConnection.java (getSocket):
+ enable TLSv1.1.
+ * gnu/java/security/action/GetPropertyAction.java: implement
+ PrivilegedAction<String>.
+ (run): return String.
+
+2006-07-14 Casey Marshall <csm@gnu.org>
+
+ * gnu/classpath/debug/Component.java (SSL_DELEGATED_TASK): new
+ constant.
+ * gnu/classpath/debug/SystemLogger.java (getSystemLogger): new
+ class method.
+ * gnu/javax/crypto/RSACipherImpl.java (logger): make instance of
+ SystemLogger.
+ (doFinal): use `EME_PKCS1_V1_5' to pad/unpad.
+ * gnu/javax/net/ssl/AbstractSessionContext.java (getSession): new
+ method.
+ * gnu/javax/net/ssl/PreSharedKeyManager.java: new file.
+ * gnu/javax/net/ssl/PreSharedKeyManagerParameters.java: new file.
+ * gnu/javax/net/ssl/provider/AbstractHandshake.java: move
+ delegated task classes to the end.
+ (handleInput): don't stop processing current input if tasks are
+ scheduled.
+ (DHE_PSKGen): new class.
+ * gnu/javax/net/ssl/provider/CertificateStatusRequest.java
+ (buffer): make non-final.
+ (<init>): new "builder" constructor.
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/CertificateURL.java (buffer): make
+ non-final.
+ (<init>): new "builder" constructor.
+ (buffer): new method.
+ (URLAndOptionalHash): implement Builder.
+ (URLAndOptionalHash.<init>): set buffer order to BIG_ENDIAN.
+ (URLAndOptionalHash.<init>, URLAndOptionalHash.<init>): new
+ "builder" constructors.
+ (URLAndOptionalHash.buffer): new method.
+ * gnu/javax/net/ssl/provider/CipherSuite.java: replace
+ DIFFIE_HELLMAN with qualified algorithm.
+ (TLS_PSK_WITH_RC4_128_SHA, TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ TLS_PSK_WITH_AES_128_CBC_SHA, TLS_PSK_WITH_AES_256_CBC_SHA,
+ TLS_DHE_PSK_WITH_RC4_128_SHA, TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ TLS_RSA_PSK_WITH_RC4_128_SHA, TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ TLS_RSA_PSK_WITH_AES_256_CBC_SHA): new constants.
+ * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java: new
+ file.
+ * gnu/javax/net/ssl/provider/ClientHandshake.java
+ (maxFragmentLengthSent, truncatedHMacSent, sentVersion): new
+ fields.
+ (implHandleInput): handle hello extensions; handle PSK key
+ exchange.
+ (implHandleOutput): send extensions if configured; handle PSK key
+ exchange.
+ (enableExtensions, maxFragmentLength, truncatedHMac,
+ getPSKIdentity): new methods.
+ (RSAGen.implRun): use the protocol version we sent in the
+ generated secret, not the agreed version.
+ * gnu/javax/net/ssl/provider/ClientHello.java: remove unused
+ imports.
+ (disableExtensions): new field.
+ (length): use `disableExtensions' field.
+ (extensions): fix telling if there are extensions.
+ * gnu/javax/net/ssl/provider/ClientHelloBuilder.java
+ (setExtensions): fix.
+ (setDisableExtensions): new method.
+ * gnu/javax/net/ssl/provider/ClientKeyExchange.java
+ (exchangeKeys): handle PSK exchange.
+ * gnu/javax/net/ssl/provider/ClientPSKParameters.java: new file.
+ * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java: new
+ file.
+ * gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
+ (toString): include hexdump output.
+ * gnu/javax/net/ssl/provider/Extension.java: implement Builder.
+ (buffer): mark non-final.
+ (<init>): make public.
+ (<init>): new "builder" constructor.
+ (length): include length of the extension type.
+ (buffer): new method.
+ (Value): implement Builder.
+ * gnu/javax/net/ssl/provider/ExtensionList.java: implement
+ Builder.
+ (<init>): new "builder" constructor.
+ (get): fix.
+ (length): return total length, including length field.
+ * gnu/javax/net/ssl/provider/InputSecurityParameters.java
+ (decrypt): handle stream ciphers (with no padding) properly.
+ * gnu/javax/net/ssl/provider/Jessie.java (<init>): add JessiePSK
+ key manager factory.
+ * gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
+ (DIFFIE_HELLMAN): removed.
+ (DH_DSS, DH_RSA, DH_anon, DHE_DSS, DHE_RSA, PSK, DHE_PSK,
+ RSA_PSK): new enum constants.
+ * gnu/javax/net/ssl/provider/MaxFragmentLength.java (buffer): new
+ method.
+ * gnu/javax/net/ssl/provider/OutputSecurityParameters.java
+ (encrypt): don't use `doFinal.'
+ * gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java:
+ new file.
+ * gnu/javax/net/ssl/provider/SSLContextImpl.java (pskManager): new
+ field.
+ (engineInit): initialize PSK manager, if specified.
+ * gnu/javax/net/ssl/provider/SSLEngineImpl.java (unwrap): debug
+ logging; don't log warnings on closure alerts.
+ * gnu/javax/net/ssl/provider/SSLSocketImpl.java
+ (SocketOutputStream.write): throw an exception if the handshake
+ threw one in another thread; clear the output buffer after writing
+ the record.
+ (doHandshake): fix this; capture exceptions thrown here, for other
+ threads.
+ * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java: new
+ file.
+ * gnu/javax/net/ssl/provider/ServerDHParams.java (algorithm): mark
+ deprecated (it's difficult to support this properly).
+ * gnu/javax/net/ssl/provider/ServerHandshake.java
+ (chooseSuites): select suites based on key exchange algorithm.
+ (implHandleInput): handle key exchange better; handle PSK
+ exchange.
+ (implHandleOutput): likewise.
+ (CertLoader.implRun): just use key exchange name directly.
+ (RSA_PSKExchange): new class.
+ * gnu/javax/net/ssl/provider/ServerKeyExchange.java (params):
+ handle PSK exchange algorithms.
+ (signature): likewise.
+ * gnu/javax/net/ssl/provider/ServerNameList.java
+ (buffer): make non-final.
+ (<init>): new "builder" constructor.
+ (buffer): new method.
+ (ServerName.buffer): make non-final.
+ (ServerName.<init>): new "builder" constructor.
+ (ServerName.length): return total length, including type and
+ length fields.
+ (ServerName.buffer): new method.
+ * gnu/javax/net/ssl/provider/ServerPSKParameters.java: new file.
+ * gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java: new
+ file.
+ * gnu/javax/net/ssl/provider/TruncatedHMAC.java (buffer): new
+ method.
+ * gnu/javax/net/ssl/provider/TrustedAuthorities.java (<init>): set
+ buffer order to BIG_ENDIAN.
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/Util.java (wrapBuffer, wrapBuffer):
+ new methods.
+ (WrappedBuffer): new class.
+ * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
+ (getAliases): add RSA_PSK.
+
+2006-07-12 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/security/auth/callback/CertificateCallback.java: new
+ file.
+
+2006-07-12 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/AbstractHandshake.java
+ (engine, inParams, outParams, tasks, serverRandom, clientRandom,
+ compression): new fields.
+ (<init>): take an SSLEngineImpl parameter; init `tasks.'
+ (handleInput): return NEED_TASK if we have tasks.
+ (getInputParams, getOutputParams): implement here; mark final.
+ (getTask): new method.
+ (checkKeyExchange): new method.
+ (reallocateBuffer): use `compact.'
+ (diffieHellmanPhase1, diffieHellmanPhase2): removed.
+ (DHPhase, CertVerifier): new classes.
+ (generateMasterSecret): add asserts.
+ (setupSecurityParameters): new method.
+ * gnu/javax/net/ssl/provider/Certificate.java (certificates): fix
+ reading multiple certificates.
+ * gnu/javax/net/ssl/provider/ClientCertificateTypeList.java:
+ implement Iterable<ClientCertificateType>.
+ (iterator): new method.
+ * gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java: make
+ public; implement Builder.
+ (<init>): make public.
+ (<init>): new constructor.
+ (wrap): new method.
+ (buffer): new method.
+ (publicValue): make public; use `rewind.'
+ (setPublicValue): use `Util.trim;' use `rewind.'
+ (length): return proper length.
+ * gnu/javax/net/ssl/provider/ClientHandshake.java: new file.
+ * gnu/javax/net/ssl/provider/ClientKeyExchange.java: remove unused
+ imports; make public, non-final.
+ (buffer): make protected, non-final.
+ (suite, version): make protected.
+ (<init>): make public.
+ (length): return 0 for NONE key exchange algorithm.
+ * gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java: new
+ file.
+ * gnu/javax/net/ssl/provider/DelegatedTask.java: new file.
+ * gnu/javax/net/ssl/provider/DiffieHellman.java (getParams): use
+ AccessController instead of Util.
+ * gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java: make
+ public; implement Builder.
+ (<init>): make public.
+ (<init>): new constructor.
+ (buffer): new method.
+ (encryptedSecret): make public; fix SSLv3 handling.
+ (setEncryptedSecret): make public; rewind the buffer after putting
+ the value.
+ (length): fix length computation.
+ * gnu/javax/net/ssl/provider/ExchangeKeys.java: make public.
+ (buffer): make protected, non-final.
+ (<init>): made public; don't check null.
+ * gnu/javax/net/ssl/provider/Jessie.java (<init>): add "SSL" alias.
+ * gnu/javax/net/ssl/provider/ServerHandshake.java: clean up unused
+ imports.
+ (engine, compression, clientRandom, serverRandom, clientSessionID,
+ inParams, outParams, keyAgreement): moved to superclass.
+ (genDH, certVerifier, certLoader, keyExchangeTask): new fields.
+ (<init>): pass engine to superclass constructor.
+ (implHandleInput): throw `AlertException' when it makes sense; run
+ long-running tasks as delegated tasks; return NEED_TASK if we
+ scheduled a delegated task.
+ (implHandleOutput): generate keys for continued sessions; run
+ long-running tasks as delegated tasks; return NEED_TASK if we
+ scheduled a delegated task.
+ (status): also return NEED_TASK as appropriate.
+ (getInputParams, getOutputParams): removed.
+ (checkKeyExchange): new method.
+ (genDiffieHellman): removed.
+ (signParams): throw exceptions.
+ (CertLoader, GenDH, RSAKeyExchange): new classes.
+ * gnu/javax/net/ssl/provider/SSLContextImpl.java
+ (engineGetServerSocketFactory): implement.
+ (engineGetSocketFactory): implement.
+ (defaultRandom): use AccessController instead of Util.
+ * gnu/javax/net/ssl/provider/SSLEngineImpl.java (<init>): use
+ `defaultSuites.'
+ (defaultSuites): new method.
+ (startHandshake): start client handshake in client mode.
+ (getDelegatedTask): implement.
+ (unwrap, wrap): send alert if we catch an AlertException during
+ handshaking.
+ * gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java: new
+ file.
+ * gnu/javax/net/ssl/provider/SSLServerSocketImpl.java: new file.
+ * gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java: new file.
+ * gnu/javax/net/ssl/provider/SSLSocketImpl.java: new file.
+ * gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
+ (sep, JSSE_CERTS, CA_CERTS, engineInit): use AccessController, not
+ Util.
+ (checkTrusted): don't require revocation checking.
+ * java/util/Collections.java (CheckedMap.entrySet): casting hack.
+ * java/util/concurrent/CopyOnWriteArrayList.java: new file.
+
+2006-07-09 Casey Marshall <csm@gnu.org>
+
+ * gnu/java/io/ByteBufferOutputStream.java (write): new method.
+ (buffer): use flip() and slice() to get the buffer.
+ (toString): new method.
+ * gnu/java/security/Engine.java: merge mwringe's case-insensitive
+ algorithm name patch.
+ * gnu/javax/crypto/jce/GnuCrypto.java (<init>): qualify
+ PrivilegedAction.
+ * gnu/javax/crypto/key/dh/GnuDHPrivateKey.java (toString): new
+ method.
+ * gnu/javax/crypto/key/dh/GnuDHPublicKey.java (toString): new
+ method.
+ * java/security/Security.java: qualify generic types.
+
+2006-07-09 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/AbstractSessionContext.java (newInstance):
+ return `AbstractSessionContext.'
+ (getSession): check if the session is null.
+ * gnu/javax/net/ssl/Session.java (packetBufferSize): removed.
+ (<init>): initialize `applicationBufferSize.'
+ (getPacketBufferSize): return application buffer size, plus 2048.
+ * gnu/javax/net/ssl/provider/AbstractHandshake.java (PAD1, PAD2):
+ new constants.
+ (handleInput): implement; call `implHandleOutput,' and hash
+ messages as they are consumed.
+ (implHandleInput): new abstract method.
+ (handleOutput): fix hashing of produced bytes.
+ (status, handleV2Hello): new abstract methods.
+ (pollHandshake): don't hash the input here; add logging.
+ (hasMessage): add logging.
+ (reallocateBuffer): shift the existing contents down in the
+ buffer, if it is, on the whole, large enough for new input.
+ (genV2CertificateVerify): renamed...
+ (genV3CertificateVerify): to this, which is correct.
+ (generateKeys): fix PRF setup; generate an IV for 1.1; add
+ logging.
+ (generateFinished): add logging; update with correct padding.
+ (generateMasterSecret): add logging; fix PRF initialization.
+ * gnu/javax/net/ssl/provider/CipherSuite.java (mac): use mac
+ algorithm name "HMac-SHA1".
+ * gnu/javax/net/ssl/provider/ClientHello.java: make extendable.
+ * gnu/javax/net/ssl/provider/ClientHelloBuilder.java: new file.
+ * gnu/javax/net/ssl/provider/ClientHelloV2.java (<init>): order
+ the input buffer BIG_ENDIAN.
+ (cipherSpecs): made public; use qualified return type.
+ * gnu/javax/net/ssl/provider/Debug.java: new file.
+ * gnu/javax/net/ssl/provider/Extension.java (<init>): order the
+ input buffer BIG_ENDIAN.
+ (length): return the total length, including the length field.
+ (toString): add prefix to value.
+ * gnu/javax/net/ssl/provider/ExtensionList.java (<init>): order
+ the input buffer BIG_ENDIAN.
+ * gnu/javax/net/ssl/provider/InputSecurityParameters.java
+ (logger): new constant.
+ (suite): new field.
+ (<init>): also take a `CipherSuite' argument.
+ (decrypt): use `update,' not `doFinal' for decryption; add debug
+ logging; fix mac computation; fix copying fragment to output.
+ (cipherSuite): return `suite' field.
+ * gnu/javax/net/ssl/provider/Jessie.java (<init>): add
+ "TLSv1.1-RSA" signature.
+ * gnu/javax/net/ssl/provider/OutputSecurityParameters.java
+ (logger): new constant.
+ (suite): new field.
+ (<init>): take additional `CipherSuite' argument.
+ (encrypt): add debug logging; fix mac computation; various little
+ fixes.
+ (suite): new method.
+ * gnu/javax/net/ssl/provider/ProtocolVersion.java (forName): also
+ recognize "TLSv1.1".
+ * gnu/javax/net/ssl/provider/Random.java (copy): fix copying the
+ internal buffer.
+ * gnu/javax/net/ssl/provider/Record.java (<init>): order the input
+ buffer BIG_ENDIAN.
+ (toString): include length in output.
+ * gnu/javax/net/ssl/provider/SSLContextImpl.java (serverContext,
+ clientContext): declare both as `AbstractSessionContext.'
+ * gnu/javax/net/ssl/provider/SSLEngineImpl.java (logger): make an
+ instance of `SystemLogger.'
+ (mode): declare as a Mode.
+ (Mode): new enum.
+ (<init>): add logging; initialize `enabledProtocols' and
+ `enabledSuites.'
+ (beginHandshake): debug logging; handle Mode enum.
+ (closeOutbound): prepare `lastAlert' to carry the close alert.
+ (isInboundDone, isOutboundDone): implement.
+ (setUseClientMode): use Mode enum.
+ (unwrap): fix V2 hello handling; optimize calls when the cipher
+ suite is TLS_NULL_WITH_NULL_NULL; add debug logging; handle closue
+ alerts properly; fix record length reporting.
+ (wrap): set `outClosed' if we are sending a closure alert here;
+ delay changing output security params until we emit the change
+ notification; optimize initial handshake; fix input buffer
+ consumption; handle end of handshake.
+ * gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java: new file.
+ * gnu/javax/net/ssl/provider/ServerDHParams.java (buffer): set
+ position to 0 in the buffer we return.
+ * gnu/javax/net/ssl/provider/ServerHandshake.java (version,
+ suite): removed.
+ (chooseSuite): make non-static; only choose a cipher suite that we
+ have a compatible certificate for.
+ (chooseCompression): use properties to enable/disable zlib.
+ (doHash): say no if we are handling a V2 hello.
+ (handleInput): rename to...
+ (implHandleInput): this; only handle a single handshake message in
+ this method (handleInput from the superclass will call us
+ repeatedly to drain the input buffer); various other fixes.
+ (implHandleOutput): debug logging; temporarily disable packing
+ more than one handshake per record; various little fixes.
+ (status, handleV2Hello): new methods.
+ (genDiffieHellman): use static parameters from the DiffieHellman
+ class.
+ (signParams): use correct signature algorithm.
+ * gnu/javax/net/ssl/provider/ServerHello.java (totalLength):
+ removed.
+ (disableExtensions): new field.
+ (length): don't query extensions if `disableExtensions' is true.
+ * gnu/javax/net/ssl/provider/ServerHelloBuilder.java
+ (setDisableExtensions): new method.
+ * gnu/javax/net/ssl/provider/ServerNameList.java: various parsing
+ fixes.
+ * gnu/javax/net/ssl/provider/SessionImpl.java (<init>): new
+ constructor.
+ (setApplicationBufferSize): new method.
+ (setPacketBufferSize): new method.
+ * gnu/javax/net/ssl/provider/SignatureAlgorithm.java
+ (getAlgorithm): new method.
+ * gnu/javax/net/ssl/provider/Util.java: make public; mark
+ security-sensitive methods deprecated.
+ * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
+ (chooseAliases): handle DSA; handle unrecognized signature
+ algorithms.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * jessie-tests/testCertificate.java: update for Builder
+ interface and API changes.
+ * jesasie-tests/testServerHello.java: likewise.
+ * jessie-tests/testServerKeyExchange.java: likewise.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/crypto/key/GnuPBEKey.java: new file.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/AbstractHandshake.java: implement
+ numerous "common" methods in server and client handshakes.
+ * gnu/javax/net/ssl/provider/AlertException.java: made public; add
+ cause constructors.
+ * gnu/javax/net/ssl/provider/Builder.java: new file.
+ * gnu/javax/net/ssl/provider/Certificate.java: make subclassable.
+ * gnu/javax/net/ssl/provider/CertificateBuilder.java: new file.
+ * gnu/javax/net/ssl/provider/CertificateRequest.java: make
+ subclassable.
+ * gnu/javax/net/ssl/provider/CertificateRequestBuilder.java: new
+ file.
+ * gnu/javax/net/ssl/provider/CipherSuite.java: remove dependence
+ on protocol version.
+ * gnu/javax/net/ssl/provider/ClientHello.java (hasExtensions): new
+ method.
+ * gnu/javax/net/ssl/provider/ClientHelloV2.java (cipherSpecs):
+ genericize collections.
+ * gnu/javax/net/ssl/provider/ClientKeyExchange.java: make version
+ argument explicit, instead of implied by the cipher suite.
+ * gnu/javax/net/ssl/provider/Constructed.java: expand JavaDocs.
+ * gnu/javax/net/ssl/provider/Finished.java: accept TLS 1.1 version
+ numbers, too.
+ * gnu/javax/net/ssl/provider/Handshake.java: make version
+ explicit, instead of implied by the cipher suite.
+ * gnu/javax/net/ssl/provider/InputSecurityParameters.java: made
+ public.
+ (suite): removed.
+ (session): new field (replaces/encapsulates `suite').
+ (<init>): made public; take a SessionImpl, not a CipherSuite.
+ (decrypt, decrypt, decrypt): add support for growable buffers AND
+ a fixed-size array of buffers (we use the former internally; the
+ latter is used to implement the scatter/gather model of
+ SSLEngine.
+ * gnu/javax/net/ssl/provider/Jessie.java: update algorithms.
+ * gnu/javax/net/ssl/provider/MacAlgorithm.java: just specify
+ NULL/MD5/SHA, not version-specific algorithms.
+ * gnu/javax/net/ssl/provider/OutputSecurityParameters.java:
+ replace suite with session; support scatter/gather operation.
+ * gnu/javax/net/ssl/provider/ProtocolVersion.java: implement
+ Comparable<ProtocolVersion>.
+ * gnu/javax/net/ssl/provider/Random.java: implement Builder.
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/SSLContextImpl.java: new file.
+ * gnu/javax/net/ssl/provider/SSLEngineImpl.java: numerous changes;
+ largely implemented now.
+ * gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java: new file.
+ * gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java: new file.
+ * gnu/javax/net/ssl/provider/ServerDHParams.java: implement
+ Builder.
+ (<init>): new constructor that takes known parameters.
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/ServerHandshake.java: numerous
+ changes; largely implemented now.
+ * gnu/javax/net/ssl/provider/ServerHello.java: make subclassable.
+ * gnu/javax/net/ssl/provider/ServerHelloBuilder.java: new file.
+ * gnu/javax/net/ssl/provider/ServerKeyExchange.java: make
+ subclassable.
+ * gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java: new
+ file.
+ * gnu/javax/net/ssl/provider/SessionImpl.java: expanded.
+ * gnu/javax/net/ssl/provider/Signature.java: implement Builder.
+ (<init>): new method, that takes a pre-computed signature.
+ (buffer): new method.
+ * gnu/javax/net/ssl/provider/SimpleSessionContext.java: new file.
+ * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java:
+ genericize Collections usage.
+ (Manager): extend X509ExtendedKeyManager; genericize fields.
+ (Manager.chooseEngineClientAlias): new method.
+ (Manager.chooseEngineServerAlias): new method.
+ * gnu/javax/net/ssl/provider/X509TrustManagerFactory.java (sep):
+ new constant; use it instead of constantly calling getProperty.
+ (init): genericize lists.
+ (Manager.trusted): removed.
+ (Manager.anchors): new field (replacement for above).
+ (<init>): handle changes to fields.
+ (getAcceptedIssuers): use `anchors.toArray().'
+ (checkTrusted): use a PKIX CertPathVerifier.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/AbstractSessionContext.java: renamed from
+ `SessionStore.' Implement SessionContext.
+ * gnu/javax/net/ssl/PrivateCredentials.java: genericize
+ collections.
+ * gnu/javax/net/ssl/Session.java (packetBufferSize): new field.
+ (values): genericize.
+ (random): make transient.
+ (truncatedMac, context): new fields.
+ (getLocalPrincipal, getPacketBufferSize, getPeerPrincipal)
+ (getSessionContext): implement.
+ (isTruncatedMac): new method.
+ (repair, privateData, setPrivateData): new abstract methods.
+ (PrivateData.serialVersionUID): new constant.
+ * gnu/javax/net/ssl/SessionStore.java: renamed to
+ `AbstractSessionContext.'
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/java/security/Requires.java: new annotation.
+ * gnu/java/security/action/GetSecurityPropertyAction.java:
+ implement PrivilegedAction<String>.
+ (run): return String.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/java/io/ByteBufferOutputStream.java: new file.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * gnu/classpath/debug/SystemLogger.java: extend Logger.
+ (SYSTEM): declare as instance of SystemLogger; set it to such an
+ instance.
+ (<clinit>): removed debug lines.
+ (<init>): new method.
+ (logv): new method.
+
+2006-06-28 Casey Marshall <csm@gnu.org>
+
+ * java/security/Signature.java (update): new method.
+ * java/security/SignatureSpi.java (engineUpdate): new method.
+
+2006-06-10 Casey Marshall <csm@gnu.org>
+
+ * jessie-tests/testClientHello.java: update for extensions
+ changes.
+ * jessie-tests/testExtensionList.java: likewise.
+ * jessie-tests/testServerHello.java: likewise.
+
+2006-06-10 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/ServerHello.java (extensions): return
+ an ExtensionList.
+ (setExtensionsLength): set the length in the buffer.
+ (toString): print out individual extensions.
+ * gnu/javax/net/ssl/provider/Extension.java (valueBytes): new
+ method.
+ (valueBuffer): new method.
+ (value): return an Extenion.Value.
+ (toString): print out extension value.
+ (Value): new abstract inner class.
+ * gnu/javax/net/ssl/provider/ClientHello.java (extensions): return
+ an ExtensionList.
+ (setExtensionListLength): set the length in the buffer.
+ (toString): print out extensions.
+ * gnu/javax/net/ssl/provider/ServerHandshake.java
+ (chooseSuite, chooseCompression): use generics and foreach loops.
+ * gnu/javax/net/ssl/provider/ExtensionList.java: new class.
+ * gnu/javax/net/ssl/provider/MaxFragmentLength.java: new class.
+ * gnu/javax/net/ssl/provider/CertificateURL.java: new class.
+ * gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java: new
+ class.
+ * gnu/javax/net/ssl/provider/TruncatedHMAC.java: new class.
+ * gnu/javax/net/ssl/provider/ServerNameList.java: new class.
+ * gnu/javax/net/ssl/provider/TrustedAuthorities.java: new class.
+ * gnu/javax/net/ssl/provider/CertificateStatusType.java: new
+ class.
+ * gnu/javax/net/ssl/provider/CertificateStatusRequest.java: new
+ class.
+
+2006-06-05 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/Extension.java: add Javadoc.
+ (length): return the length of the extension value.
+ (setLength, setType, setValue, setValue): new methods.
+ * gnu/javax/net/ssl/provider/ExtensionList.java: new file.
+ * jessie-tests/run-tests.sh: add testExtensionList.
+ * jessie-tests/testExtensionList.java: new file.
+
+2006-06-05 Casey Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/CipherSuiteList.java: implement
+ Iterable<CipherSuite>.
+ (iterator): new method.
+ * gnu/javax/net/ssl/provider/CompressionMethodList.java: implement
+ Iterable<CompressionMethod>.
+ (iterator): new method.
+ * gnu/javax/net/ssl/provider/X500PrincipalList.java: implement
+ Iterable<X500Principal>.
+ (iterator): new method.
+
+2006-06-05 C. Scott Marshall <csm@gnu.org>
+
+ * java/security/MessageDigest.java (update): new method.
+ * java/security/MessageDigestSpi.java (engineUpdate): new method.
+
+2006-06-03 C. Scott Marshall <csm@gnu.org>
+
+ * gnu/javax/net/ssl/provider/ServerHelloDone.java: made public.
+ * jessie-tests/run-tests.sh: add `testServerHelloDone.'
+ * jessie-tests/testServerHelloDone.java: new test.
diff --git a/gnu/classpath/debug/Component.java b/gnu/classpath/debug/Component.java
index 0cc38d709..dce257502 100644
--- a/gnu/classpath/debug/Component.java
+++ b/gnu/classpath/debug/Component.java
@@ -97,8 +97,13 @@ public final class Component extends Level
* Trace details about the SSL key exchange.
*/
public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2);
+
+ /**
+ * Trace running of delegated tasks.
+ */
+ public static final Component SSL_DELEGATED_TASK = new Component ("SSL DELEGATED TASK", 3);
- /* Indices 3 and 4 reserved for future use by SSL components. */
+ /* Index 4 reserved for future use by SSL components. */
/**
* Trace the operation of cryptographic primitives.
diff --git a/gnu/classpath/debug/SystemLogger.java b/gnu/classpath/debug/SystemLogger.java
index 502b48870..8919e80c7 100644
--- a/gnu/classpath/debug/SystemLogger.java
+++ b/gnu/classpath/debug/SystemLogger.java
@@ -42,11 +42,12 @@ import gnu.java.security.action.GetPropertyAction;
import java.security.AccessController;
import java.util.StringTokenizer;
+import java.util.logging.Level;
import java.util.logging.Logger;
-public final class SystemLogger
+public final class SystemLogger extends Logger
{
- public static final Logger SYSTEM = Logger.getLogger ("gnu.classpath");
+ public static final SystemLogger SYSTEM = new SystemLogger();
static
{
@@ -62,12 +63,40 @@ public final class SystemLogger
Component c = Component.forName (tok.nextToken ());
if (c != null)
PreciseFilter.GLOBAL.enable (c);
- SYSTEM.log (java.util.logging.Level.INFO, "enabled: {0}", c);
+ SYSTEM.log (Level.INFO, "enabled: {0}", c);
}
}
+ }
- java.util.logging.Handler[] h = SYSTEM.getHandlers ();
- for (int i = 0; i < h.length; i++)
- System.out.println (h[i]);
+ /**
+ * Fetch the system logger instance. The logger returned is meant for debug
+ * and diagnostic logging for Classpath internals.
+ *
+ * @return The system logger.
+ */
+ public static SystemLogger getSystemLogger()
+ {
+ // XXX Check some permission here?
+ return SYSTEM;
+ }
+
+ /**
+ * Keep only one instance of the system logger.
+ */
+ private SystemLogger()
+ {
+ super("gnu.classpath", null);
+ }
+
+ /**
+ * Variable-arguments log method.
+ *
+ * @param level The level to log to.
+ * @param format The format string.
+ * @param args The arguments.
+ */
+ public void logv(Level level, String format, Object... args)
+ {
+ log(level, format, args);
}
}
diff --git a/gnu/java/security/Requires.java b/gnu/java/security/Requires.java
new file mode 100644
index 000000000..c820336c0
--- /dev/null
+++ b/gnu/java/security/Requires.java
@@ -0,0 +1,59 @@
+/* Requires.java -- mark methods as requiring permission.
+ 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.java.security;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+import java.security.Permission;
+
+/**
+ *
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+@Documented @Retention(CLASS) @Target(METHOD)
+public @interface Requires
+{
+ Class<? extends Permission> permissionClass();
+ String target();
+ String action();
+}
diff --git a/gnu/java/security/action/GetPropertyAction.java b/gnu/java/security/action/GetPropertyAction.java
index 2886deb34..0c8141a4d 100644
--- a/gnu/java/security/action/GetPropertyAction.java
+++ b/gnu/java/security/action/GetPropertyAction.java
@@ -49,7 +49,7 @@ import java.security.PrivilegedAction;
* String port = AccessController.doPrivileged(action);
* </code>
*/
-public class GetPropertyAction implements PrivilegedAction
+public class GetPropertyAction implements PrivilegedAction<String>
{
String name;
String value = null;
@@ -68,7 +68,7 @@ public class GetPropertyAction implements PrivilegedAction
setParameters(propName, defaultValue);
}
- public Object run()
+ public String run()
{
return System.getProperty(name, value);
}
diff --git a/gnu/java/security/action/GetSecurityPropertyAction.java b/gnu/java/security/action/GetSecurityPropertyAction.java
index 97fa15d03..ac928ca33 100644
--- a/gnu/java/security/action/GetSecurityPropertyAction.java
+++ b/gnu/java/security/action/GetSecurityPropertyAction.java
@@ -50,7 +50,7 @@ import java.security.Security;
* String passwd = AccessController.doPrivileged(action);
* </code>
*/
-public class GetSecurityPropertyAction implements PrivilegedAction
+public class GetSecurityPropertyAction implements PrivilegedAction<String>
{
private String name;
private String value;
@@ -83,7 +83,7 @@ public class GetSecurityPropertyAction implements PrivilegedAction
return this;
}
- public Object run()
+ public String run()
{
String val = Security.getProperty(name);
if (val == null)
diff --git a/gnu/java/security/util/ByteBufferOutputStream.java b/gnu/java/security/util/ByteBufferOutputStream.java
new file mode 100644
index 000000000..be4d0a98d
--- /dev/null
+++ b/gnu/java/security/util/ByteBufferOutputStream.java
@@ -0,0 +1,118 @@
+/* ByteBufferOutputStream.java -- output stream with a growable underlying
+ byte buffer.
+ 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.java.security.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An output stream that writes bytes to a ByteBuffer, which will be resized
+ * if more space is needed.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ByteBufferOutputStream extends OutputStream
+{
+ private ByteBuffer buffer;
+
+ public ByteBufferOutputStream()
+ {
+ this(256);
+ }
+
+ public ByteBufferOutputStream(int initialCapacity)
+ {
+ buffer = ByteBuffer.allocate(initialCapacity);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#write(int)
+ */
+ public @Override synchronized void write(int b) throws IOException
+ {
+ if (!buffer.hasRemaining())
+ growBuffer();
+ buffer.put((byte) b);
+ }
+
+ public @Override synchronized void write(byte[] b, int offset, int length)
+ {
+ if (buffer.remaining() < length)
+ growBuffer();
+ buffer.put(b, offset, length);
+ }
+
+ public @Override void write(byte[] b)
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Get the current state of the buffer. The returned buffer will have
+ * its position set to zero, its capacity set to the current limit,
+ * and its limit set to its capacity.
+ *
+ * @return The buffer.
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().flip()).slice();
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [ buffer: " + buffer + " ]";
+ }
+
+ private void growBuffer()
+ {
+ int newCapacity = buffer.capacity();
+ if (newCapacity < 16384) // If the buffer isn't huge yet, double its size
+ newCapacity = newCapacity << 1;
+ else // Otherwize, increment by a bit.
+ newCapacity += 4096;
+ ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+ buffer.flip();
+ newBuffer.put(buffer);
+ buffer = newBuffer;
+ }
+}
diff --git a/gnu/javax/crypto/RSACipherImpl.java b/gnu/javax/crypto/RSACipherImpl.java
index 60504ecce..a4adff007 100644
--- a/gnu/javax/crypto/RSACipherImpl.java
+++ b/gnu/javax/crypto/RSACipherImpl.java
@@ -40,6 +40,7 @@ package gnu.javax.crypto;
import gnu.classpath.debug.Component;
import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
import gnu.java.security.util.ByteArray;
import java.math.BigInteger;
@@ -53,7 +54,6 @@ import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -65,7 +65,8 @@ import javax.crypto.ShortBufferException;
public class RSACipherImpl
extends CipherSpi
{
- private static final Logger logger = SystemLogger.SYSTEM;
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+
private static final byte[] EMPTY = new byte[0];
private int opmode = -1;
private RSAPrivateKey decipherKey = null;
@@ -199,22 +200,12 @@ public class RSACipherImpl
engineUpdate(in, offset, length);
if (opmode == Cipher.DECRYPT_MODE)
{
- if (pos < dataBuffer.length)
- throw new IllegalBlockSizeException("expecting exactly "
- + dataBuffer.length + " bytes");
- BigInteger enc = new BigInteger(1, dataBuffer);
- byte[] dec = rsaDecrypt(enc);
- logger.log(Component.CRYPTO, "RSA: decryption produced\n{0}",
- new ByteArray(dec));
- if (dec[0] != 0x02)
- throw new BadPaddingException("expected padding type 2");
- int i;
- for (i = 1; i < dec.length && dec[i] != 0x00; i++)
- ; // keep incrementing i
- int len = dec.length - i - 1; // skip the 0x00 byte
- byte[] result = new byte[len];
- System.arraycopy(dec, i + 1, result, 0, len);
- pos = 0;
+ BigInteger enc = new BigInteger (1, dataBuffer);
+ byte[] dec = rsaDecrypt (enc);
+ logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}",
+ new ByteArray (dec));
+ EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey);
+ byte[] result = pkcs.decode(dec);
return result;
}
else
@@ -222,24 +213,18 @@ public class RSACipherImpl
offset = dataBuffer.length - pos;
if (offset < 3)
throw new IllegalBlockSizeException("input is too large to encrypt");
- byte[] dec = new byte[dataBuffer.length];
- dec[0] = 0x02;
+ EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey);
if (random == null)
random = new SecureRandom();
- byte[] pad = new byte[offset - 2];
- random.nextBytes(pad);
- for (int i = 0; i < pad.length; i++)
- if (pad[i] == 0)
- pad[i] = 1;
- System.arraycopy(pad, 0, dec, 1, pad.length);
- dec[dec.length - pos] = 0x00;
- System.arraycopy(dataBuffer, 0, dec, offset, pos);
- logger.log(Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
- new ByteArray(dec));
- BigInteger x = new BigInteger(1, dec);
- BigInteger y = x.modPow(encipherKey.getPublicExponent(),
- encipherKey.getModulus());
- byte[] enc = y.toByteArray();
+ byte[] em = new byte[pos];
+ System.arraycopy(dataBuffer, 0, em, 0, pos);
+ byte[] dec = pkcs.encode(em, random);
+ logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
+ new ByteArray (dec));
+ BigInteger x = new BigInteger (1, dec);
+ BigInteger y = x.modPow (encipherKey.getPublicExponent (),
+ encipherKey.getModulus ());
+ byte[] enc = y.toByteArray ();
if (enc[0] == 0x00)
{
byte[] tmp = new byte[enc.length - 1];
@@ -298,7 +283,17 @@ public class RSACipherImpl
}
BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n);
if (pubExp != null)
- dec = dec.multiply(r.modInverse(n)).mod(n);
- return dec.toByteArray();
+ {
+ dec = dec.multiply (r.modInverse (n)).mod (n);
+ }
+
+ byte[] decb = dec.toByteArray();
+ if (decb[0] != 0x00)
+ {
+ byte[] b = new byte[decb.length + 1];
+ System.arraycopy(decb, 0, b, 1, decb.length);
+ decb = b;
+ }
+ return decb;
}
}
diff --git a/gnu/javax/crypto/key/GnuPBEKey.java b/gnu/javax/crypto/key/GnuPBEKey.java
new file mode 100644
index 000000000..6f4bcb1b3
--- /dev/null
+++ b/gnu/javax/crypto/key/GnuPBEKey.java
@@ -0,0 +1,95 @@
+/* GnuPBEKey.java -- A password-based encryption key.
+ 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.crypto.key;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * An implementation of a password-based encryption key.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GnuPBEKey
+ implements PBEKey
+{
+ private final PBEKeySpec spec;
+
+ public GnuPBEKey (final PBEKeySpec spec)
+ {
+ if (spec == null)
+ throw new NullPointerException ();
+ this.spec = spec;
+ }
+
+ public GnuPBEKey (char[] password, byte[] salt, int iterationCount)
+ {
+ this (new PBEKeySpec (password, salt, iterationCount));
+ }
+
+ public int getIterationCount ()
+ {
+ return spec.getIterationCount ();
+ }
+
+ public char[] getPassword ()
+ {
+ return spec.getPassword ();
+ }
+
+ public byte[] getSalt ()
+ {
+ return spec.getSalt ();
+ }
+
+ public String getAlgorithm ()
+ {
+ return "PBE";
+ }
+
+ public String getFormat ()
+ {
+ return "NONE"; // FIXME?
+ }
+
+ public byte[] getEncoded ()
+ {
+ return null; // FIXME?
+ }
+}
diff --git a/gnu/javax/net/ssl/AbstractSessionContext.java b/gnu/javax/net/ssl/AbstractSessionContext.java
new file mode 100644
index 000000000..bdd7f274e
--- /dev/null
+++ b/gnu/javax/net/ssl/AbstractSessionContext.java
@@ -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
diff --git a/gnu/javax/net/ssl/PreSharedKeyManager.java b/gnu/javax/net/ssl/PreSharedKeyManager.java
new file mode 100644
index 000000000..ba6500a27
--- /dev/null
+++ b/gnu/javax/net/ssl/PreSharedKeyManager.java
@@ -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
diff --git a/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java b/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java
new file mode 100644
index 000000000..1b1d492b1
--- /dev/null
+++ b/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java
@@ -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();
+ }
+}
diff --git a/gnu/javax/net/ssl/PrivateCredentials.java b/gnu/javax/net/ssl/PrivateCredentials.java
index f602f98ae..442629309 100644
--- a/gnu/javax/net/ssl/PrivateCredentials.java
+++ b/gnu/javax/net/ssl/PrivateCredentials.java
@@ -51,6 +51,7 @@ 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;
@@ -95,16 +96,16 @@ public class PrivateCredentials implements ManagerFactoryParameters
public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY";
public static final String END_RSA = "-----END RSA PRIVATE KEY";
- private List privateKeys;
- private List certChains;
+ private List<PrivateKey> privateKeys;
+ private List<X509Certificate[]> certChains;
// Constructor.
// -------------------------------------------------------------------------
public PrivateCredentials()
{
- privateKeys = new LinkedList();
- certChains = new LinkedList();
+ privateKeys = new LinkedList<PrivateKey>();
+ certChains = new LinkedList<X509Certificate[]>();
}
// Instance methods.
@@ -115,7 +116,7 @@ public class PrivateCredentials implements ManagerFactoryParameters
IOException, NoSuchAlgorithmException, WrongPaddingException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
- Collection certs = cf.generateCertificates(certChain);
+ Collection<? extends Certificate> certs = cf.generateCertificates(certChain);
X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]);
String alg = null;
@@ -199,11 +200,12 @@ public class PrivateCredentials implements ManagerFactoryParameters
(BigInteger) der.read().getValue(), // d mod (q-1)
(BigInteger) der.read().getValue()); // coefficient
}
+
privateKeys.add(kf.generatePrivate(spec));
certChains.add(chain);
}
- public List getPrivateKeys()
+ public List<PrivateKey> getPrivateKeys()
{
if (isDestroyed())
{
@@ -212,7 +214,7 @@ public class PrivateCredentials implements ManagerFactoryParameters
return privateKeys;
}
- public List getCertChains()
+ public List<X509Certificate[]> getCertChains()
{
return certChains;
}
diff --git a/gnu/javax/net/ssl/SSLCipherSuite.java b/gnu/javax/net/ssl/SSLCipherSuite.java
new file mode 100644
index 000000000..a3ab87713
--- /dev/null
+++ b/gnu/javax/net/ssl/SSLCipherSuite.java
@@ -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);
+}
diff --git a/gnu/javax/net/ssl/SSLProtocolVersion.java b/gnu/javax/net/ssl/SSLProtocolVersion.java
new file mode 100644
index 000000000..3998f936a
--- /dev/null
+++ b/gnu/javax/net/ssl/SSLProtocolVersion.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/SSLRecordHandler.java b/gnu/javax/net/ssl/SSLRecordHandler.java
new file mode 100644
index 000000000..3147415fe
--- /dev/null
+++ b/gnu/javax/net/ssl/SSLRecordHandler.java
@@ -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
diff --git a/gnu/javax/net/ssl/Session.java b/gnu/javax/net/ssl/Session.java
new file mode 100644
index 000000000..e2b21aa1e
--- /dev/null
+++ b/gnu/javax/net/ssl/Session.java
@@ -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
diff --git a/gnu/javax/net/ssl/SessionStoreException.java b/gnu/javax/net/ssl/SessionStoreException.java
new file mode 100644
index 000000000..5dcf3d028
--- /dev/null
+++ b/gnu/javax/net/ssl/SessionStoreException.java
@@ -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);
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/AbstractHandshake.java b/gnu/javax/net/ssl/provider/AbstractHandshake.java
new file mode 100644
index 000000000..d80a5bb78
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/AbstractHandshake.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/Alert.java b/gnu/javax/net/ssl/provider/Alert.java
index c31e1bef5..12c86b0a4 100644
--- a/gnu/javax/net/ssl/provider/Alert.java
+++ b/gnu/javax/net/ssl/provider/Alert.java
@@ -38,10 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
+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
@@ -52,211 +52,112 @@ import java.io.OutputStream;
*
* <pre>
* struct {
- * AlertLevel level;
+ * AlertLevel level;
* AlertDescription description;
* }
* </pre>
*/
-final class Alert implements Constructed
+public final class Alert implements Constructed
{
// Fields.
// -------------------------------------------------------------------------
- /** The alert level enumerated. */
- private final Level level;
-
- /** The alert description enumerated. */
- private final Description description;
+ /** The underlying byte buffer. */
+ private final ByteBuffer buffer;
// Constructor.
// -------------------------------------------------------------------------
- Alert(Level level, Description description)
+ public Alert (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public Alert (final Level level, final Description description)
{
- this.level = level;
- this.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 ();
}
- // Class method.
+ // Instance methods.
// -------------------------------------------------------------------------
- static Alert read(InputStream in) throws IOException
+ public int length ()
{
- Level level = Level.read(in);
- Description desc = Description.read(in);
- return new Alert(level, desc);
+ return 2;
}
- static Alert forName(String name)
+ byte[] getEncoded()
{
- if (name == null)
- {
- return new Alert(Level.FATAL, Description.INTERNAL_ERROR);
- }
- Description desc = Description.INTERNAL_ERROR;
- if (name.equals("close_notify"))
- {
- desc = Description.CLOSE_NOTIFY;
- }
- else if (name.equals("unexpected_message"))
- {
- desc = Description.UNEXPECTED_MESSAGE;
- }
- else if (name.equals("bad_record_mac"))
- {
- desc = Description.BAD_RECORD_MAC;
- }
- else if (name.equals("DECRYPTION_FAILED"))
- {
- desc = Description.DECRYPTION_FAILED;
- }
- else if (name.equals("record_overflow"))
- {
- desc = Description.RECORD_OVERFLOW;
- }
- else if (name.equals("decompression_failure"))
- {
- desc = Description.DECOMPRESSION_FAILURE;
- }
- else if (name.equals("handshake_failure"))
- {
- desc = Description.HANDSHAKE_FAILURE;
- }
- else if (name.equals("no_certificate"))
- {
- desc = Description.NO_CERTIFICATE;
- }
- else if (name.equals("bad_certificate"))
- {
- desc = Description.BAD_CERTIFICATE;
- }
- else if (name.equals("unsupported_certificate"))
- {
- desc = Description.UNSUPPORTED_CERTIFICATE;
- }
- else if (name.equals("certificate_revoked"))
- {
- desc = Description.CERTIFICATE_REVOKED;
- }
- else if (name.equals("certificate_expired"))
- {
- desc = Description.CERTIFICATE_EXPIRED;
- }
- else if (name.equals("certificate_unknown"))
- {
- desc = Description.CERTIFICATE_UNKNOWN;
- }
- else if (name.equals("illegal_parameter"))
- {
- desc = Description.ILLEGAL_PARAMETER;
- }
- else if (name.equals("unknown_ca"))
- {
- desc = Description.UNKNOWN_CA;
- }
- else if (name.equals("access_denied"))
- {
- desc = Description.ACCESS_DENIED;
- }
- else if (name.equals("decode_error"))
- {
- desc = Description.DECODE_ERROR;
- }
- else if (name.equals("decrypt_error"))
- {
- desc = Description.DECRYPT_ERROR;
- }
- else if (name.equals("export_restriction"))
- {
- desc = Description.EXPORT_RESTRICTION;
- }
- else if (name.equals("protocol_version"))
- {
- desc = Description.PROTOCOL_VERSION;
- }
- else if (name.equals("insufficient_security"))
- {
- desc = Description.INSUFFICIENT_SECURITY;
- }
- else if (name.equals("internal_error"))
- {
- desc = Description.INTERNAL_ERROR;
- }
- else if (name.equals("user_canceled"))
- {
- desc = Description.USER_CANCELED;
- }
- else if (name.equals("no_renegotiation"))
- {
- desc = Description.NO_RENEGOTIATION;
- }
- else if (name.equals("unsupported_extension"))
- {
- desc = Description.UNSUPPORTED_EXTENSION;
- }
- else if (name.equals("certificate_unobtainable"))
- {
- desc = Description.CERTIFICATE_UNOBTAINABLE;
- }
- else if (name.equals("unrecognized_name"))
- {
- desc = Description.UNRECOGNIZED_NAME;
- }
- else if (name.equals("bad_certificate_status_response"))
- {
- desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE;
- }
- else if (name.equals("bad_certificate_hash_value"))
- {
- desc = Description.BAD_CERTIFICATE_HASH_VALUE;
- }
- else if (name.equals("unknown_srp_username"))
- {
- desc = Description.UNKNOWN_SRP_USERNAME;
- }
- else if (name.equals("missing_srp_username"))
- {
- desc = Description.MISSING_SRP_USERNAME;
- }
- return new Alert(Level.FATAL, desc);
+ byte[] buf = new byte[2];
+ buffer.position (0);
+ buffer.get (buf);
+ return buf;
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ public Level level()
+ {
+ return Level.forInteger (buffer.get (0) & 0xFF);
+ }
- public void write(OutputStream out) throws IOException
+ public Description description()
{
- out.write((byte) level.getValue());
- out.write((byte) description.getValue());
+ return Description.forInteger (buffer.get (1) & 0xFF);
}
- byte[] getEncoded()
+ public void setLevel (final Level level)
+ {
+ buffer.put (0, (byte) level.getValue ());
+ }
+
+ public void setDescription (final Description description)
{
- return new byte[] { (byte) level.getValue(),
- (byte) description.getValue() };
+ buffer.put (1, (byte) description.getValue ());
}
- Level getLevel()
+ public boolean equals (Object o)
{
- return level;
+ if (!(o instanceof Alert))
+ return false;
+ Alert that = (Alert) o;
+ return that.buffer.position (0).equals (buffer.position (0));
}
- Description getDescription()
+ public int hashCode ()
{
- return description;
+ return buffer.getShort (0) & 0xFFFF;
}
public String toString()
{
- String nl = System.getProperty("line.separator");
- return "struct {" + nl +
- " level = " + level + ";" + nl +
- " description = " + description + ";" + nl +
- "} Alert;" + nl;
+ 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 ();
}
- // Inner classes.
+ // Enumerations.
// -------------------------------------------------------------------------
/**
@@ -266,129 +167,88 @@ final class Alert implements Constructed
* enum { warning(1), fatal(2), (255) } AlertLevel;
* </pre>
*/
- static final class Level implements Enumerated
+ public static enum Level
{
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Level WARNING = new Level(1), FATAL = new Level(2);
-
+ WARNING (1), FATAL (2);
+
private final int value;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Level(int value)
{
this.value = value;
}
- // Class method.
- // -----------------------------------------------------------------------
-
- static Level read(InputStream in) throws IOException
+ public static Level forInteger (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of stream");
- }
- switch (i & 0xFF)
+ switch (value & 0xFF)
{
case 1: return WARNING;
case 2: return FATAL;
- default: return new Level(i);
+ default: throw new IllegalArgumentException ("invalid alert level: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 1: return "warning";
- case 2: return "fatal";
- default: return "unknown(" + value + ")";
- }
- }
}
/**
* The description enumeration.
*/
- static final class Description implements Enumerated
+ public static enum Description
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Description
- CLOSE_NOTIFY = new Description( 0),
- UNEXPECTED_MESSAGE = new Description( 10),
- BAD_RECORD_MAC = new Description( 20),
- DECRYPTION_FAILED = new Description( 21),
- RECORD_OVERFLOW = new Description( 22),
- DECOMPRESSION_FAILURE = new Description( 30),
- HANDSHAKE_FAILURE = new Description( 40),
- NO_CERTIFICATE = new Description( 41),
- BAD_CERTIFICATE = new Description( 42),
- UNSUPPORTED_CERTIFICATE = new Description( 43),
- CERTIFICATE_REVOKED = new Description( 44),
- CERTIFICATE_EXPIRED = new Description( 45),
- CERTIFICATE_UNKNOWN = new Description( 46),
- ILLEGAL_PARAMETER = new Description( 47),
- UNKNOWN_CA = new Description( 48),
- ACCESS_DENIED = new Description( 49),
- DECODE_ERROR = new Description( 50),
- DECRYPT_ERROR = new Description( 51),
- EXPORT_RESTRICTION = new Description( 60),
- PROTOCOL_VERSION = new Description( 70),
- INSUFFICIENT_SECURITY = new Description( 71),
- INTERNAL_ERROR = new Description( 80),
- USER_CANCELED = new Description( 90),
- NO_RENEGOTIATION = new Description(100),
- UNSUPPORTED_EXTENSION = new Description(110),
- CERTIFICATE_UNOBTAINABLE = new Description(111),
- UNRECOGNIZED_NAME = new Description(112),
- BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113),
- BAD_CERTIFICATE_HASH_VALUE = new Description(114),
- UNKNOWN_SRP_USERNAME = new Description(120),
- MISSING_SRP_USERNAME = new Description(121);
-
+ 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;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Description(int value)
{
this.value = value;
}
- // Class method.
- // -----------------------------------------------------------------------
-
- static Description read(InputStream in) throws IOException
+ /**
+ * 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)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (i)
+ switch (value & 0xFF)
{
case 0: return CLOSE_NOTIFY;
case 10: return UNEXPECTED_MESSAGE;
@@ -416,59 +276,13 @@ final class Alert implements Constructed
case 100: return NO_RENEGOTIATION;
case 120: return UNKNOWN_SRP_USERNAME;
case 121: return MISSING_SRP_USERNAME;
- default: return new Description(i);
+ default: throw new IllegalArgumentException("unknown alert description: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- 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 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 110: return "unsupported_extension";
- case 111: return "certificate_unobtainable";
- case 112: return "unrecognized_name";
- case 113: return "bad_certificate_status_response";
- case 114: return "bad_certificate_hash_value";
- case 120: return "unknown_srp_username";
- case 121: return "missing_srp_username";
- default: return "unknown(" + value + ")";
- }
- }
}
}
diff --git a/gnu/javax/net/ssl/provider/AlertException.java b/gnu/javax/net/ssl/provider/AlertException.java
index 666efe5ac..291de2700 100644
--- a/gnu/javax/net/ssl/provider/AlertException.java
+++ b/gnu/javax/net/ssl/provider/AlertException.java
@@ -40,7 +40,10 @@ package gnu.javax.net.ssl.provider;
import javax.net.ssl.SSLException;
-class AlertException extends SSLException
+/**
+ * An exception generated by an SSL alert.
+ */
+public class AlertException extends SSLException
{
// Fields.
@@ -52,25 +55,47 @@ class AlertException extends SSLException
// Constructor.
// -------------------------------------------------------------------------
- AlertException(Alert alert, boolean isLocal)
+ public AlertException(Alert alert, boolean isLocal)
{
- super(alert.getDescription().toString());
+ 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.getDescription() + ": " +
+ return alert.description() + ": " +
(isLocal ? "locally generated; " : "remotely generated; ") +
- alert.getLevel();
+ alert.level();
}
- public Alert getAlert ()
+ public Alert alert ()
{
return alert;
}
+
+ public boolean isLocal()
+ {
+ return isLocal;
+ }
}
diff --git a/gnu/javax/net/ssl/provider/Builder.java b/gnu/javax/net/ssl/provider/Builder.java
new file mode 100644
index 000000000..baaba8aec
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/Builder.java
@@ -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();
+}
diff --git a/gnu/javax/net/ssl/provider/Certificate.java b/gnu/javax/net/ssl/provider/Certificate.java
index b1d6b2a01..8ff91e557 100644
--- a/gnu/javax/net/ssl/provider/Certificate.java
+++ b/gnu/javax/net/ssl/provider/Certificate.java
@@ -1,4 +1,4 @@
-/* Certificate.java -- SSL Certificate message.
+/* Certificate.java -- SSL certificate message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,157 +38,140 @@ 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.security.cert.CertificateEncodingException;
+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 javax.net.ssl.SSLProtocolException;
-
-final class Certificate implements Handshake.Body
+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.
// -------------------------------------------------------------------------
- private final X509Certificate[] certs;
+ protected ByteBuffer buffer;
+ protected final CertificateType type;
// Constructors.
// -------------------------------------------------------------------------
- Certificate(X509Certificate[] certs)
+ public Certificate (final ByteBuffer buffer, final CertificateType type)
{
- if (certs == null)
- {
- throw new NullPointerException();
- }
- this.certs = certs;
+ buffer.getClass ();
+ type.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.type = type;
}
- // Class methods.
+ // Instance methods.
// -------------------------------------------------------------------------
- static Certificate read(InputStream in, CertificateType type)
- throws IOException
+ public int length ()
{
- if (type == CertificateType.X509)
- {
- int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8
- | (in.read() & 0xFF);
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of stream");
- }
- count += l;
- }
- try
- {
- LinkedList certs = new LinkedList();
- CertificateFactory fact = CertificateFactory.getInstance("X.509");
- ByteArrayInputStream bin = new ByteArrayInputStream(buf);
- count = 0;
- while (count < len)
- {
- int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8
- | (bin.read() & 0xFF);
- certs.add(fact.generateCertificate(bin));
- count += len2 + 3;
- }
- return new Certificate((X509Certificate[])
- certs.toArray(new X509Certificate[certs.size()]));
- }
- catch (CertificateException ce)
- {
- SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage());
- sslpe.initCause (ce);
- throw sslpe;
- }
- }
- else if (type == CertificateType.OPEN_PGP)
- {
- throw new UnsupportedOperationException("not yet implemented");
- }
- else
- throw new Error("unsupported certificate type "+type);
+ return (((buffer.get (0) & 0xFF) << 24)
+ | buffer.getShort (1)) + 3;
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ public List<java.security.cert.Certificate> certificates ()
+ throws CertificateException, NoSuchAlgorithmException
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try
- {
- for (int i = 0; i < certs.length; i++)
- {
- byte[] enc = certs[i].getEncoded();
- bout.write((enc.length >>> 16) & 0xFF);
- bout.write((enc.length >>> 8) & 0xFF);
- bout.write( enc.length & 0xFF);
- bout.write(enc);
- }
- }
- catch (CertificateEncodingException cee)
- {
- throw new Error("cannot encode certificates");
- }
- catch (IOException ignored)
+ 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);
}
- out.write(bout.size() >>> 16 & 0xFF);
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
+ return list;
}
- X509Certificate[] getCertificates()
+ public String toString ()
{
- return certs;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" certificateList =");
- for (int i = 0; i < certs.length; i++)
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ try
{
- BufferedReader r =
- new BufferedReader(new StringReader(certs[i].toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
+ 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.println("} Certificate;");
+ out.print ("} Certificate;");
return str.toString();
}
}
diff --git a/gnu/javax/net/ssl/provider/DigestInputStream.java b/gnu/javax/net/ssl/provider/CertificateBuilder.java
index dd138b436..b60ad556a 100644
--- a/gnu/javax/net/ssl/provider/DigestInputStream.java
+++ b/gnu/javax/net/ssl/provider/CertificateBuilder.java
@@ -1,4 +1,4 @@
-/* DigestInputStream.java -- digesting input stream.
+/* CertificateBuilder.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,71 +33,62 @@ 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. */
+exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.FilterInputStream;
-import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
-
-import gnu.java.security.hash.IMessageDigest;
-
-final class DigestInputStream extends FilterInputStream
+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
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private IMessageDigest md5, sha;
- private boolean digesting;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha)
+ public CertificateBuilder(final CertificateType certType)
{
- super(in);
- if (md5 == null || sha == null)
- throw new NullPointerException();
- this.md5 = md5;
- this.sha = sha;
- digesting = true;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- void setDigesting(boolean digesting)
- {
- this.digesting = digesting;
- }
-
- public int read() throws IOException
- {
- int i = in.read();
- if (digesting && i != -1)
- {
- md5.update((byte) i);
- sha.update((byte) i);
- }
- return i;
+ super(ByteBuffer.allocate(1024), certType);
}
- public int read(byte[] buf) throws IOException
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
{
- return read(buf, 0, buf.length);
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- public int read(byte[] buf, int off, int len) throws IOException
+ public void setCertificates (final List<? extends java.security.cert.Certificate> certificates)
+ throws CertificateException
{
- int ret = in.read(buf, off, len);
- if (digesting && ret != -1)
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ for (java.security.cert.Certificate cert : certificates)
{
- md5.update(buf, off, ret);
- sha.update(buf, off, ret);
+ 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.
+ }
}
- return ret;
+ 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);
}
}
diff --git a/gnu/javax/net/ssl/provider/CertificateRequest.java b/gnu/javax/net/ssl/provider/CertificateRequest.java
index 0f788039b..b7a22b204 100644
--- a/gnu/javax/net/ssl/provider/CertificateRequest.java
+++ b/gnu/javax/net/ssl/provider/CertificateRequest.java
@@ -38,201 +38,96 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import java.util.LinkedList;
-import java.security.Principal;
-
-final class CertificateRequest implements Handshake.Body
+/**
+ * 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.
// -------------------------------------------------------------------------
- private final ClientType[] types;
- private final Principal[] authorities;
-
+ protected ByteBuffer buffer;
+
// Constructor.
// -------------------------------------------------------------------------
- CertificateRequest(ClientType[] types, Principal[] authorities)
- {
- if (types == null)
- {
- throw new NullPointerException();
- }
- this.types = types;
- if (authorities == null)
- {
- throw new NullPointerException();
- }
- this.authorities = authorities;
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static CertificateRequest read(InputStream in) throws IOException
+ public CertificateRequest(final ByteBuffer buffer)
{
- DataInputStream din = new DataInputStream(in);
- ClientType[] types = new ClientType[din.readUnsignedByte()];
- for (int i = 0; i < types.length; i++)
- {
- types[i] = ClientType.read(din);
- }
-
- LinkedList authorities = new LinkedList();
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- ByteArrayInputStream bin = new ByteArrayInputStream(buf);
- try
- {
- String x500name = Util.getSecurityProperty("jessie.x500.class");
- if (x500name == null)
- {
- x500name = "org.metastatic.jessie.pki.X500Name";
- }
- Class x500class = null;
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- if (cl != null)
- {
- x500class = cl.loadClass(x500name);
- }
- else
- {
- x500class = Class.forName(x500name);
- }
- Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() });
- while (bin.available() > 0)
- {
- buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)];
- bin.read(buf);
- authorities.add(c.newInstance(new Object[] { buf }));
- }
- }
- catch (IOException ioe)
- {
- throw ioe;
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- return new CertificateRequest(types,
- (Principal[]) authorities.toArray(new Principal[authorities.size()]));
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public int length ()
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- out.write(types.length);
- for (int i = 0; i < types.length; i++)
- {
- out.write(types[i].getValue());
- }
-
- try
- {
- Class x500class = authorities[0].getClass();
- Method m = x500class.getMethod("getEncoded", null);
- for (int i = 0; i < authorities.length; i++)
- {
- byte[] buf = (byte[]) m.invoke(authorities[i], null);
- bout.write(buf.length >>> 8 & 0xFF);
- bout.write(buf.length & 0xFF);
- bout.write(buf, 0, buf.length);
- }
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
+ int o1 = (buffer.get (0) & 0xFF) + 1;
+ return o1 + (buffer.getShort (o1) & 0xFFFF) + 2;
}
- ClientType[] getTypes()
+ public ClientCertificateTypeList types ()
{
- return types;
+ return new ClientCertificateTypeList(buffer.duplicate());
}
- String[] getTypeStrings()
+ public X500PrincipalList authorities ()
{
- try
- {
- return (String[]) Util.transform(types, String.class, "toString", null);
- }
- catch (Exception x)
- {
- return null;
- }
+ int offset = (buffer.get (0) & 0xFF) + 1;
+ return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice());
}
- Principal[] getAuthorities()
+ public String toString()
{
- return authorities;
+ return toString (null);
}
- public String toString()
+ 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 {");
- out.print(" types = ");
- for (int i = 0; i < types.length; i++)
- {
- out.print(types[i]);
- if (i != types.length - 1)
- out.print(", ");
- }
- out.println(";");
+ if (prefix != null) out.print (prefix);
+ out.println (" types =");
+ out.println (types ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
out.println(" authorities =");
- for (int i = 0; i < authorities.length; i++)
- {
- out.print(" ");
- out.print(authorities[i].getName());
- if (i != types.length - 1)
- out.println(",");
- }
- out.println(";");
- out.println("} CertificateRequest;");
+ out.println (authorities ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print ("} CertificateRequest;");
return str.toString();
}
- // Inner class.
- // -------------------------------------------------------------------------
-
- static final class ClientType implements Enumerated
+ public static enum ClientCertificateType
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final ClientType
- RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2),
- RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4);
+ RSA_SIGN (1),
+ DSS_SIGN (2),
+ RSA_FIXED_DH (3),
+ DSS_FIXED_DH (4);
private final int value;
// Constructor.
// -----------------------------------------------------------------------
- private ClientType(int value)
+ private ClientCertificateType (final int value)
{
this.value = value;
}
@@ -240,46 +135,21 @@ final class CertificateRequest implements Handshake.Body
// Class method.
// -----------------------------------------------------------------------
- static ClientType read(InputStream in) throws IOException
+ static ClientCertificateType forValue (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (i & 0xFF)
+ 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: return new ClientType(i);
+ default: throw new IllegalArgumentException("unknown client certificate type: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- 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: return "unknown(" + value + ")";
- }
- }
}
}
diff --git a/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java b/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
new file mode 100644
index 000000000..9beab473c
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
new file mode 100644
index 000000000..059c6ec47
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
@@ -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();
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateStatusType.java b/gnu/javax/net/ssl/provider/CertificateStatusType.java
new file mode 100644
index 000000000..7cddf168f
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateStatusType.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateType.java b/gnu/javax/net/ssl/provider/CertificateType.java
index c5705939f..ecba21b63 100644
--- a/gnu/javax/net/ssl/provider/CertificateType.java
+++ b/gnu/javax/net/ssl/provider/CertificateType.java
@@ -38,67 +38,25 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-
-final class CertificateType implements Enumerated
+public enum CertificateType
{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- static final CertificateType X509 = new CertificateType(0);
- static final CertificateType OPEN_PGP = new CertificateType(1);
+ X509 (0),
+ OPEN_PGP (1);
private final int value;
- // Constructor.
- // -------------------------------------------------------------------------
-
private CertificateType(int value)
{
this.value = value;
}
- // Class method.
- // -------------------------------------------------------------------------
-
- static CertificateType read(InputStream in) throws IOException
- {
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (value & 0xFF)
- {
- case 0: return X509;
- case 1: return OPEN_PGP;
- default: return new CertificateType(value);
- }
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
- public int getValue()
- {
- return value;
- }
-
- public String toString()
+ public static CertificateType forValue (final int value)
{
switch (value)
{
- case 0: return "X.509";
- case 1: return "OpenPGP";
- default: return "unknown(" + value + ")";
+ case 0: return X509;
+ case 1: return OPEN_PGP;
+ default: throw new IllegalArgumentException ("unknown certificate type: " + value);
}
}
}
diff --git a/gnu/javax/net/ssl/provider/CertificateURL.java b/gnu/javax/net/ssl/provider/CertificateURL.java
new file mode 100644
index 000000000..0bc1c428b
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateURL.java
@@ -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();
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateVerify.java b/gnu/javax/net/ssl/provider/CertificateVerify.java
index e0bf130f1..b63f5e4ef 100644
--- a/gnu/javax/net/ssl/provider/CertificateVerify.java
+++ b/gnu/javax/net/ssl/provider/CertificateVerify.java
@@ -38,34 +38,24 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-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.security.PublicKey;
+import java.nio.ByteBuffer;
-final class CertificateVerify extends Signature implements Handshake.Body
+public class CertificateVerify extends Signature implements Handshake.Body
{
// Contstructor.
// -------------------------------------------------------------------------
- CertificateVerify(Object sigValue, String sigAlg)
+ public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg)
{
- super(sigValue, sigAlg);
+ super(buffer, sigAlg);
}
-
- // Class method.
- // --------------------------------------------------------------------------
-
- static Signature read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+
+ public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg)
{
- Signature sig = Signature.read(in, suite, key);
- return new CertificateVerify(sig.getSigValue(), sig.getSigAlg());
+ super(sigVal, sigAlg);
}
// Instance method.
@@ -73,23 +63,21 @@ final class CertificateVerify extends Signature implements Handshake.Body
public String toString()
{
- StringWriter str = new StringWriter();
- PrintWriter out = new PrintWriter(str);
+ 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 {");
- BufferedReader r = new BufferedReader(new StringReader(super.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println("} CertificateVerify;");
+ 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();
}
}
diff --git a/gnu/javax/net/ssl/provider/OverflowException.java b/gnu/javax/net/ssl/provider/CipherAlgorithm.java
index 93bdcaec5..98e05af31 100644
--- a/gnu/javax/net/ssl/provider/OverflowException.java
+++ b/gnu/javax/net/ssl/provider/CipherAlgorithm.java
@@ -1,4 +1,4 @@
-/* OverflowException.java -- signals an input overflow.
+/* CipherAlgorithm.java -- Cipher algorithm enumeration.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,20 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-
-class OverflowException extends IOException
+/**
+ * The set of cipher algorithms we support.
+ */
+public enum CipherAlgorithm
{
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- OverflowException()
- {
- }
-
- OverflowException(String msg)
- {
- super(msg);
- }
+ NULL, RC4, DES, DESede, CAST5, AES
}
diff --git a/gnu/javax/net/ssl/provider/CipherSuite.java b/gnu/javax/net/ssl/provider/CipherSuite.java
index de916817b..af3041e94 100644
--- a/gnu/javax/net/ssl/provider/CipherSuite.java
+++ b/gnu/javax/net/ssl/provider/CipherSuite.java
@@ -38,407 +38,521 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.DataInputStream;
-import java.io.InputStream;
+import gnu.java.security.action.GetSecurityPropertyAction;
+
import java.io.IOException;
import java.io.OutputStream;
-import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.security.Security;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
+import javax.crypto.NullCipher;
-import gnu.javax.crypto.cipher.CipherFactory;
-import gnu.javax.crypto.cipher.IBlockCipher;
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mac.MacFactory;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.mode.ModeFactory;
-
-final class CipherSuite implements Constructed
+public final class CipherSuite implements Constructed
{
// Constants and fields.
// -------------------------------------------------------------------------
- private static final List tlsSuiteNames = new LinkedList();
- private static final HashMap namesToSuites = new HashMap();
-
- // SSL CipherSuites.
- static final CipherSuite SSL_NULL_WITH_NULL_NULL =
- new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
- "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_NULL_MD5 =
- new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01,
- "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_NULL_SHA =
- new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02,
- "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03,
- "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04,
- "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_RC4_128_SHA =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05,
- "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08,
- "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09,
- "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A,
- "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B,
- "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C,
- "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D,
- "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E,
- "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F,
- "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10,
- "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11,
- "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12,
- "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13,
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14,
- "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15,
- "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16,
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ 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.
- static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F,
- "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30,
- "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31,
- "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32,
- "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33,
- "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35,
- "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36,
- "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37,
- "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38,
- "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39,
- "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
-
- // Ciphersuites from the OpenPGP extension draft.
- static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
- "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
- "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
- "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
- "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
- "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
- "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
- "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
- "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
- "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
- "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
- "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
- "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
- "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
-
- static final CipherSuite TLS_NULL_WITH_NULL_NULL =
- new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
- "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
- new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01,
- "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_NULL_SHA =
- new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02,
- "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03,
- "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04,
- "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05,
- "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08,
- "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09,
- "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A,
- "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B,
- "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C,
- "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D,
- "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E,
- "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F,
- "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10,
- "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11,
- "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12,
- "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13,
- "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14,
- "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15,
- "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16,
- "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
-
- // AES CipherSuites.
- static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F,
- "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30,
- "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31,
- "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32,
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33,
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35,
- "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36,
- "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37,
- "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38,
- "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39,
- "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ 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
- static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50,
- "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51,
- "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52,
- "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53,
- "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54,
- "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55,
- "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56,
- "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57,
- "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58,
- "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ // 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.
- static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
- "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
- "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
- "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
- "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
- "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
- "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
- "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
- "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
- "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
- "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
- "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
- "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
- "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
- "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
- "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
-
- private final String cipherName;
- private final String kexName;
- private final String sigName;
- private final String macName;
+ // 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 ProtocolVersion version;
+ private final boolean isResolved;
// Constructors.
// -------------------------------------------------------------------------
- private CipherSuite(String cipherName, String kexName, String sigName,
- String macName, int keyLength, int id1, int id2,
- String name, ProtocolVersion version)
+ 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.cipherName = cipherName.intern();
- this.kexName = kexName.intern();
- this.sigName = sigName.intern();
- this.macName = macName.intern();
+ this.cipherAlgorithm = cipherAlgorithm;
+ this.keyExchangeAlgorithm = keyExchangeAlgorithm;
+ this.ephemeralDH = ephemeralDH;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.macAlgorithm = macAlgorithm;
this.exportable = keyLength <= 5;
- this.isStream = cipherName.equals("null") || cipherName.equals("RC4");
+ this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL
+ || cipherAlgorithm == CipherAlgorithm.RC4);
this.keyLength = keyLength;
this.id = new byte[] { (byte) id1, (byte) id2 };
this.name = name.intern();
- this.version = version;
namesToSuites.put(name, this);
if (name.startsWith("TLS"))
{
tlsSuiteNames.add(name);
}
+ isResolved = true;
}
private CipherSuite(byte[] id)
{
- cipherName = null;
- kexName = null;
- sigName = null;
- macName = null;
+ cipherAlgorithm = null;
+ keyExchangeAlgorithm = null;
+ signatureAlgorithm = null;
+ macAlgorithm = null;
+ ephemeralDH = false;
exportable = false;
isStream = false;
keyLength = 0;
this.id = id;
name = null;
- version = null;
+ isResolved = false;
}
// Class methods.
@@ -450,274 +564,243 @@ final class CipherSuite implements Constructed
*
* @return The named cipher suite.
*/
- static CipherSuite forName(String name)
+ public static CipherSuite forName(String name)
{
- return (CipherSuite) namesToSuites.get(name);
+ if (name.startsWith("SSL_"))
+ name = "TLS_" + name.substring(4);
+ return namesToSuites.get(name);
}
- static List availableSuiteNames()
+ public static CipherSuite forValue(final short raw_value)
{
- return tlsSuiteNames;
+ byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value };
+ return new CipherSuite(b).resolve();
}
- static CipherSuite read(InputStream in) throws IOException
+ public static List<String> availableSuiteNames()
{
- DataInputStream din = new DataInputStream(in);
- byte[] id = new byte[2];
- din.readFully(id);
- return new CipherSuite(id);
+ return tlsSuiteNames;
}
- static IMode getCipher(String cbcCipherName)
+ // Intance methods.
+ // -------------------------------------------------------------------------
+
+ public CipherAlgorithm cipherAlgorithm ()
{
- IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName);
- if (cipher == null)
- {
- return null;
- }
- return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize());
+ return cipherAlgorithm;
}
- static Cipher getJCECipher (final String name)
- throws NoSuchAlgorithmException, NoSuchPaddingException
+ public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException
{
- final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
- if (name.equals ("RC4"))
+ 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)
{
- if (provider != null)
+ try
{
- try
- {
- return Cipher.getInstance (name, provider);
- }
- catch (NoSuchProviderException nsae)
- {
- // Fall through. Try any available provider.
- }
+ return Cipher.getInstance (alg, provider);
}
-
- return Cipher.getInstance (name);
- }
- else
- {
- // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding
- // is different than TLSv1 in subtle, but important, ways. But they
- // sorta look the same, so why not make them equivalent?
- //
- // There should be a seperate padding "TLS1Padding".
- if (provider != null)
+ catch (NoSuchProviderException nspe)
{
- try
- {
- return Cipher.getInstance (name + "/CBC/SSL3Padding", provider);
- }
- catch (NoSuchProviderException nspe)
- {
- // Fall through. Try any available provider.
- }
}
- return Cipher.getInstance (name + "/CBC/SSL3Padding");
}
+ return Cipher.getInstance (alg);
+ }
+
+ public MacAlgorithm macAlgorithm ()
+ {
+ return macAlgorithm;
}
- static IMac getMac(String macName)
+ public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException
{
- if (macName.startsWith("SSLMAC-"))
+ if (macAlgorithm == null)
+ throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite");
+ if (macAlgorithm == MacAlgorithm.NULL)
+ return null;
+
+ String macAlg = null;
+ if (version == ProtocolVersion.SSL_3)
{
- return new SSLHMac(macName.substring(7));
+ macAlg = "SSLv3HMac-" + macAlgorithm;
}
else
{
- return MacFactory.getInstance(macName);
+ if (macAlgorithm == MacAlgorithm.MD5)
+ macAlg = "HMac-MD5";
+ if (macAlgorithm == MacAlgorithm.SHA)
+ macAlg = "HMac-SHA1";
}
- }
-
- static Mac getJCEMac (final String name)
- throws NoSuchAlgorithmException
- {
- final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
+
+ GetSecurityPropertyAction gspa =
+ new GetSecurityPropertyAction ("jessie.jce.provider");
+ final String provider = AccessController.doPrivileged (gspa);
if (provider != null)
{
try
{
- return Mac.getInstance (name, provider);
+ return Mac.getInstance(macAlg, provider);
}
catch (NoSuchProviderException nspe)
{
- // Fall through. Try any available provider.
+ // Ignore; try any installed provider.
}
}
- return Mac.getInstance (name);
+ return Mac.getInstance(macAlg);
}
- // Intance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ public SignatureAlgorithm signatureAlgorithm ()
{
- out.write(id);
+ return signatureAlgorithm;
}
- CipherSuite resolve(ProtocolVersion version)
+ public KeyExchangeAlgorithm keyExchangeAlgorithm ()
{
- if (version == ProtocolVersion.SSL_3)
- {
- if (id[0] == 0x00) switch (id[1])
- {
- case 0x00: return SSL_NULL_WITH_NULL_NULL;
- case 0x01: return SSL_RSA_WITH_NULL_MD5;
- case 0x02: return SSL_RSA_WITH_NULL_SHA;
- case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5;
- case 0x04: return SSL_RSA_WITH_RC4_128_MD5;
- case 0x05: return SSL_RSA_WITH_RC4_128_SHA;
- case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x09: return SSL_RSA_WITH_DES_CBC_SHA;
- case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA;
- case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA;
- case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA;
- case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA;
- case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA;
- case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA;
- case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA;
- case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA;
- case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA;
- case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA;
- case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA;
- case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA;
- case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA;
- case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA;
- }
- }
- else if (version == ProtocolVersion.TLS_1 ||
- version == ProtocolVersion.TLS_1_1)
- {
- if (id[0] == 0x00) switch (id[1])
- {
- 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;
- }
- }
- return this;
+ return keyExchangeAlgorithm;
}
- String getCipher()
+ public boolean isEphemeralDH ()
{
- return cipherName;
+ return ephemeralDH;
}
- int getKeyLength()
+ public int length ()
{
- return keyLength;
+ return 2;
}
- String getKeyExchange()
+ public void write(OutputStream out) throws IOException
{
- return kexName;
+ out.write(id);
}
- String getSignature()
+ public void put (final ByteBuffer buf)
{
- return sigName;
+ buf.put (id);
}
-
- String getMac()
+
+ public CipherSuite resolve()
{
- return macName;
+ 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;
}
-
- boolean isExportable()
+
+ public boolean isResolved()
{
- return exportable;
+ return isResolved;
}
- boolean isStreamCipher()
+ public int keyLength()
{
- return isStream;
+ return keyLength;
}
- String getAuthType()
+ public boolean isExportable()
{
- if (kexName.equals("RSA"))
- {
- if (isExportable())
- {
- return "RSA_EXPORT";
- }
- return "RSA";
- }
- return kexName + "_" + sigName;
+ return exportable;
}
- byte[] getId()
+ public boolean isStreamCipher()
{
- return id;
+ return isStream;
}
- ProtocolVersion getVersion()
+// String getAuthType()
+// {
+// if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA)
+// {
+// if (isExportable())
+// {
+// return "RSA_EXPORT";
+// }
+// return "RSA";
+// }
+// return kexName + "_" + sigName;
+// }
+
+ public byte[] id()
{
- return version;
+ return id;
}
public boolean equals(Object o)
@@ -728,26 +811,26 @@ final class CipherSuite implements Constructed
}
if (o == this)
return true;
- byte[] id = ((CipherSuite) o).getId();
- return id[0] == this.id[0] &&
- id[1] == this.id[1];
+ byte[] id = ((CipherSuite) o).id();
+ return (id[0] == this.id[0] &&
+ id[1] == this.id[1]);
}
public int hashCode()
{
- if (version == null)
- {
- return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
- }
- return version.getMajor() << 24 | version.getMinor() << 16
- | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ }
+
+ public String toString (String prefix)
+ {
+ return toString ();
}
public String toString()
{
if (name == null)
{
- return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
+ return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
}
return name;
}
diff --git a/gnu/javax/net/ssl/provider/CipherSuiteList.java b/gnu/javax/net/ssl/provider/CipherSuiteList.java
new file mode 100644
index 000000000..0e96b3144
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CipherSuiteList.java
@@ -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);
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java b/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
new file mode 100644
index 000000000..1a1886b88
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
new file mode 100644
index 000000000..e63e03c0a
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
@@ -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;
+ }
+
+}
diff --git a/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java b/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
new file mode 100644
index 000000000..8af8b850b
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
@@ -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 ();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientHandshake.java b/gnu/javax/net/ssl/provider/ClientHandshake.java
new file mode 100644
index 000000000..059b165a6
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientHandshake.java
@@ -0,0 +1,1150 @@
+/* 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];
+ rsa.init(Cipher.ENCRYPT_MODE, cert);
+ 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;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientHello.java b/gnu/javax/net/ssl/provider/ClientHello.java
index 259051df1..54d7f8b4d 100644
--- a/gnu/javax/net/ssl/provider/ClientHello.java
+++ b/gnu/javax/net/ssl/provider/ClientHello.java
@@ -38,216 +38,203 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-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.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import javax.net.ssl.SSLProtocolException;
-
-final class ClientHello implements Handshake.Body
+/**
+ * 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.
// -------------------------------------------------------------------------
- private ProtocolVersion version;
- private Random random;
- private byte[] sessionId;
- private List suites;
- private List comp;
- private List extensions;
+ // 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.
// -------------------------------------------------------------------------
- ClientHello(ProtocolVersion version, Random random,
- byte[] sessionId, List suites, List comp)
+ public ClientHello (final ByteBuffer buffer)
{
- this(version, random, sessionId, suites, comp, null);
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ disableExtensions = false;
}
- ClientHello(ProtocolVersion version, Random random,
- byte[] sessionId, List suites, List comp, List extensions)
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length()
{
- this.version = version;
- this.random = random;
- this.sessionId = sessionId;
- this.suites = suites;
- this.comp = comp;
- this.extensions = extensions;
+ 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;
}
- // Class methods.
- // -------------------------------------------------------------------------
+ /**
+ * Gets the protocol version field.
+ *
+ * @return The protocol version field.
+ */
+ public ProtocolVersion version()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (0));
+ }
- static ClientHello read(InputStream in) throws IOException
+ /**
+ * Gets the SSL nonce.
+ *
+ * @return The nonce.
+ */
+ public Random random()
{
- ProtocolVersion vers = ProtocolVersion.read(in);
- Random rand = Random.read(in);
- byte[] id = new byte[in.read() & 0xFF];
- in.read(id);
- int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- ArrayList suites = new ArrayList(len / 2);
- for (int i = 0; i < len; i += 2)
- {
- suites.add(CipherSuite.read(in).resolve(vers));
- }
- len = in.read() & 0xFF;
- ArrayList comp = new ArrayList(len);
- for (int i = 0; i < len; i++)
- {
- comp.add(CompressionMethod.read(in));
- }
-
- List ext = null;
- // Since parsing MAY need to continue into the extensions fields, or it
- // may end here, the specified input stream MUST be a ByteArrayInputStream
- // over all the data this hello contains. Otherwise this will mess up
- // the data stream.
- if (in.available() > 0) // then we have extensions.
- {
- ext = new LinkedList();
- len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- Extension e = Extension.read(in);
- ext.add(e);
- count += e.getValue().length + 4;
- }
- }
- return new ClientHello(vers, rand, id, suites, comp, ext);
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ 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 void write(OutputStream out) throws IOException
+ public CipherSuiteList cipherSuites()
{
- version.write(out);
- random.write(out);
- out.write(sessionId.length);
- out.write(sessionId);
- out.write((suites.size() << 1) >>> 8 & 0xFF);
- out.write((suites.size() << 1) & 0xFF);
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- ((CipherSuite) i.next()).write(out);
- }
- out.write(comp.size());
- for (Iterator i = comp.iterator(); i.hasNext(); )
- {
- out.write(((CompressionMethod) i.next()).getValue());
- }
- if (extensions != null)
- {
- ByteArrayOutputStream out2 = new ByteArrayOutputStream();
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- ((Extension) i.next()).write(out2);
- }
- out.write(out2.size() >>> 8 & 0xFF);
- out.write(out2.size() & 0xFF);
- out2.writeTo(out);
- }
+ 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 ());
}
- ProtocolVersion getVersion()
+ public CompressionMethodList compressionMethods()
{
- return version;
+ 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());
}
- Random getRandom()
+ 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()
{
- return random;
+ if (hasExtensions())
+ return 0;
+ return buffer.getShort(getExtensionsOffset()) & 0xFFFF;
}
- byte[] getSessionId()
+ protected int getCipherSuitesOffset ()
{
- return sessionId;
+ return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF));
}
- List getCipherSuites()
+ protected int getCompressionMethodsOffset ()
{
- return suites;
+ int csOffset = getCipherSuitesOffset ();
+ int csLen = buffer.getShort (csOffset) & 0xFFFF;
+ return csOffset + csLen + 2;
}
- List getCompressionMethods()
+ protected int getExtensionsOffset ()
{
- return comp;
+ int cmOffset = getCompressionMethodsOffset ();
+ return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1;
}
- List getExtensions()
+ public String toString ()
{
- return extensions;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
- StringWriter str = new StringWriter();
- PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" version = " + version + ";");
- BufferedReader r = new BufferedReader(new StringReader(random.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
- out.println(" cipherSuites = {");
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- out.print(" ");
- out.println(i.next());
- }
- out.println(" };");
- out.print(" compressionMethods = { ");
- for (Iterator i = comp.iterator(); i.hasNext(); )
- {
- out.print(i.next());
- if (i.hasNext())
- out.print(", ");
- }
- out.println(" };");
- if (extensions != null)
- {
- out.println(" extensions = {");
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- r = new BufferedReader(new StringReader(i.next().toString()));
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println(" };");
- }
- out.println("} ClientHello;");
+ 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();
}
}
diff --git a/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
new file mode 100644
index 000000000..81e3dd72f
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientHelloV2.java b/gnu/javax/net/ssl/provider/ClientHelloV2.java
new file mode 100644
index 000000000..a514d9ad3
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientHelloV2.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/gnu/javax/net/ssl/provider/ClientKeyExchange.java
index 828aa8d5e..2006e7385 100644
--- a/gnu/javax/net/ssl/provider/ClientKeyExchange.java
+++ b/gnu/javax/net/ssl/provider/ClientKeyExchange.java
@@ -38,143 +38,94 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-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.math.BigInteger;
-
-import java.security.PublicKey;
-import java.security.interfaces.RSAKey;
-import javax.crypto.interfaces.DHPublicKey;
-
-final class ClientKeyExchange implements Handshake.Body
+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.
// -------------------------------------------------------------------------
- private final Object exObject;
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
+ protected final ProtocolVersion version;
// Constructors.
// -------------------------------------------------------------------------
- ClientKeyExchange(byte[] encryptedSecret)
- {
- exObject = encryptedSecret;
- }
-
- ClientKeyExchange(BigInteger bigint)
- {
- exObject = bigint;
- }
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static ClientKeyExchange read(InputStream in, CipherSuite suite,
- PublicKey key)
- throws IOException
+ public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
{
- DataInputStream din = new DataInputStream(in);
- if (suite.getKeyExchange().equals("RSA"))
- {
- int len = 0;
- if (suite.getVersion() == ProtocolVersion.SSL_3)
- {
- len = (((RSAKey) key).getModulus().bitLength()+7) / 8;
- }
- else
- {
- len = din.readUnsignedShort();
- }
- byte[] buf = new byte[len];
- din.readFully(buf);
- return new ClientKeyExchange(buf);
- }
- else if (suite.getKeyExchange().equals("SRP"))
- {
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- return new ClientKeyExchange(new BigInteger(1, buf));
- }
- else if (key == null || !(key instanceof DHPublicKey)) // explicit.
- {
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- return new ClientKeyExchange(new BigInteger(1, buf));
- }
- else
- {
- return new ClientKeyExchange(new byte[0]);
- }
+ suite.getClass();
+ version.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
+ this.version = version;
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public ExchangeKeys exchangeKeys ()
{
- throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead");
+ 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 void write(OutputStream out, ProtocolVersion version) throws IOException
+ public int length()
{
- if (exObject instanceof byte[])
- {
- byte[] b = (byte[]) exObject;
- if (b.length > 0)
- {
- if (version != ProtocolVersion.SSL_3)
- {
- out.write(b.length >>> 8 & 0xFF);
- out.write(b.length & 0xFF);
- }
- out.write(b);
- }
- }
- else
- {
- byte[] bigint = ((BigInteger) exObject).toByteArray();
- if (bigint[0] == 0x00)
- {
- out.write(bigint.length - 1 >>> 8 & 0xFF);
- out.write(bigint.length - 1 & 0xFF);
- out.write(bigint, 1, bigint.length - 1);
- }
- else
- {
- out.write(bigint.length >>> 8 & 0xFF);
- out.write(bigint.length & 0xFF);
- out.write(bigint);
- }
- }
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ return 0;
+ return exchangeKeys().length();
}
- Object getExchangeObject()
+ public String toString ()
{
- return exObject;
+ return toString (null);
}
- public String toString()
+ 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 (exObject instanceof byte[] && ((byte[]) exObject).length > 0)
- {
- out.println(" encryptedPreMasterSecret =");
- out.print(Util.hexDump((byte[]) exObject, " "));
- }
- else if (exObject instanceof BigInteger)
- {
- out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";");
- }
+ 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();
}
diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java b/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
new file mode 100644
index 000000000..ebebdcc0e
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
@@ -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);
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/gnu/javax/net/ssl/provider/ClientPSKParameters.java
new file mode 100644
index 000000000..676a872f9
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientPSKParameters.java
@@ -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();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
new file mode 100644
index 000000000..f7483a94c
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
@@ -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();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CompressionMethod.java b/gnu/javax/net/ssl/provider/CompressionMethod.java
index c2fdf05f9..6c57e840c 100644
--- a/gnu/javax/net/ssl/provider/CompressionMethod.java
+++ b/gnu/javax/net/ssl/provider/CompressionMethod.java
@@ -1,4 +1,4 @@
-/* CompressionMethod.java -- the compression method enum.
+/* CompressionMethod.java -- The CompressionMethod enum.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,67 +38,32 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-
-final class CompressionMethod implements Enumerated
+public enum CompressionMethod
{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- static final CompressionMethod NULL = new CompressionMethod(0),
- ZLIB = new CompressionMethod(1);
+ NULL (0), ZLIB(1);
private final int value;
- // Constructor.
- // -------------------------------------------------------------------------
-
private CompressionMethod(int value)
{
this.value = value;
}
- // Class method.
- // -------------------------------------------------------------------------
-
- static CompressionMethod read(InputStream in) throws IOException
+ public static CompressionMethod getInstance (final int value)
{
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
switch (value & 0xFF)
{
case 0: return NULL;
case 1: return ZLIB;
- default: return new CompressionMethod(value);
+
+ // 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;
}
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 0: return "null";
- case 1: return "zlib";
- default: return "unknown(" + value + ")";
- }
- }
}
diff --git a/gnu/javax/net/ssl/provider/CompressionMethodList.java b/gnu/javax/net/ssl/provider/CompressionMethodList.java
new file mode 100644
index 000000000..47ba5484c
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CompressionMethodList.java
@@ -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);
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/Constructed.java b/gnu/javax/net/ssl/provider/Constructed.java
index ee3f56a7f..3a3545b22 100644
--- a/gnu/javax/net/ssl/provider/Constructed.java
+++ b/gnu/javax/net/ssl/provider/Constructed.java
@@ -1,4 +1,4 @@
-/* Constructed.java -- constructed type.
+/* Constructed.java -- Constructed type.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,20 +38,49 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-import java.io.OutputStream;
-
/**
* 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.
*/
-interface Constructed
+public interface Constructed
{
+ /**
+ * Returns the total length, in bytes, of this structure.
+ *
+ * @return The length of this structure.
+ */
+ int length();
/**
- * Writes this structure's encoded form to the given output stream.
+ * Returns a printable representation of this structure, with the
+ * given prefix prepended to each line.
*
- * @param out The output stream.
- * @throws IOException If an I/O error occurs.
+ * @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.
*/
- void write(OutputStream out) throws IOException;
+ String toString(String prefix);
}
diff --git a/gnu/javax/net/ssl/provider/ContentType.java b/gnu/javax/net/ssl/provider/ContentType.java
index 336809467..f7165a2d7 100644
--- a/gnu/javax/net/ssl/provider/ContentType.java
+++ b/gnu/javax/net/ssl/provider/ContentType.java
@@ -1,4 +1,4 @@
-/* ContentType.java -- record layer content type.
+/* ContentType.java -- SSL record layer content type.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -45,22 +45,23 @@ 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>
+ * <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)
*/
-final class ContentType implements Enumerated
+public enum ContentType
{
- // Constants and fields.
- // ------------------------------------------------------------------------
-
- static final ContentType CLIENT_HELLO_V2 = new ContentType( 1);
- static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20);
- static final ContentType ALERT = new ContentType(21);
- static final ContentType HANDSHAKE = new ContentType(22);
- static final ContentType APPLICATION_DATA = new ContentType(23);
+ CLIENT_HELLO_V2 ( 1),
+ CHANGE_CIPHER_SPEC (20),
+ ALERT (21),
+ HANDSHAKE (22),
+ APPLICATION_DATA (23);
private int value;
@@ -72,16 +73,8 @@ final class ContentType implements Enumerated
this.value = value;
}
- // Class methods.
- // ------------------------------------------------------------------------
-
- static final ContentType read(InputStream in) throws IOException
+ static final ContentType forInteger (final int value)
{
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
switch (value & 0xFF)
{
case 1: return CLIENT_HELLO_V2;
@@ -89,47 +82,12 @@ final class ContentType implements Enumerated
case 21: return ALERT;
case 22: return HANDSHAKE;
case 23: return APPLICATION_DATA;
- default: return new ContentType(value);
+ default: return null;
}
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public boolean equals(Object o)
- {
- if (o == null || !(o instanceof ContentType))
- {
- return false;
- }
- return ((ContentType) o).value == value;
- }
-
- public int hashCode()
- {
- return getValue();
- }
-
- public String toString()
- {
- switch (value)
- {
- case 1: return "v2_client_hello";
- case 20: return "change_cipher_spec";
- case 21: return "alert";
- case 22: return "handshake";
- case 23: return "application_data";
- default: return "unknown(" + value + ")";
- }
- }
}
diff --git a/gnu/javax/net/ssl/provider/Context.java b/gnu/javax/net/ssl/provider/Context.java
deleted file mode 100644
index 2bd7193f2..000000000
--- a/gnu/javax/net/ssl/provider/Context.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/* Context.java -- SSLContext 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 java.io.File;
-import java.io.InputStream;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStoreException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.UnrecoverableKeyException;
-import java.sql.SQLException;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContextSpi;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.NullManagerParameters;
-import gnu.javax.net.ssl.SRPTrustManager;
-import gnu.javax.net.ssl.StaticTrustAnchors;
-
-/**
- * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext}
- * engine, and is available under the algorithm names ``SSLv3'', ``SSL'',
- * ``TLSv1'', and ``TLS''.
- */
-public final class Context extends SSLContextSpi
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private SessionContext clientSessions;
- private SessionContext serverSessions;
- private X509KeyManager keyManager;
- private X509TrustManager trustManager;
- private SRPTrustManager srpTrustManager;
- private SecureRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- public Context()
- {
- String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec");
- String codecClass = null;
- if (codec == null)
- {
- codec = "null";
- }
- if (codec.equalsIgnoreCase("xml"))
- {
- codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
- }
- else if (codec.equalsIgnoreCase("jdbc"))
- {
- codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
- }
- else if (codec.equalsIgnoreCase("null"))
- {
- codecClass = "gnu.javax.net.ssl.provider.SessionContext";
- }
- else
- {
- throw new IllegalArgumentException("no such codec: " + codec);
- }
- try
- {
- ClassLoader cl = Context.class.getClassLoader();
- if (cl == null)
- {
- cl = ClassLoader.getSystemClassLoader();
- }
- clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- throw new IllegalArgumentException(ex.toString());
- }
-
- codec = Util.getSecurityProperty("jessie.serverSessionContext.codec");
- if (codec == null)
- {
- codec = "null";
- }
- if (codec.equalsIgnoreCase("xml"))
- {
- codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
- }
- else if (codec.equalsIgnoreCase("jdbc"))
- {
- codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
- }
- else if (codec.equalsIgnoreCase("null"))
- {
- codecClass = "gnu.javax.net.ssl.provider.SessionContext";
- }
- else
- {
- throw new IllegalArgumentException("no such codec: " + codec);
- }
- try
- {
- ClassLoader cl = Context.class.getClassLoader();
- if (cl == null)
- {
- cl = ClassLoader.getSystemClassLoader();
- }
- serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- throw new IllegalArgumentException(ex.toString());
- }
- }
-
- // Engine methods.
- // -------------------------------------------------------------------------
-
- protected SSLSessionContext engineGetClientSessionContext()
- {
- return clientSessions;
- }
-
- protected SSLSessionContext engineGetServerSessionContext()
- {
- return serverSessions;
- }
-
- protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory()
- {
- if (keyManager == null || (trustManager == null && srpTrustManager == null)
- || random == null)
- {
- throw new IllegalStateException();
- }
- return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager,
- random, serverSessions);
- }
-
- protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory()
- {
- if (keyManager == null || trustManager == null || random == null)
- {
- throw new IllegalStateException();
- }
- return new SSLSocketFactory(trustManager, keyManager, random, clientSessions);
- }
-
- protected 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 X509KeyManager)
- {
- keyManager = (X509KeyManager) keyManagers[i];
- break;
- }
- }
- }
- 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();
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private X509KeyManager defaultKeyManager() throws KeyManagementException
- {
- KeyManagerFactory fact = null;
- try
- {
- fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException();
- }
- catch (NoSuchProviderException nspe)
- {
- throw new KeyManagementException();
- }
- try
- {
- fact.init(null, null);
- return (X509KeyManager) fact.getKeyManagers()[0];
- }
- catch (NoSuchAlgorithmException nsae) { }
- catch (KeyStoreException kse) { }
- catch (UnrecoverableKeyException uke) { }
- catch (IllegalStateException ise) { }
-
- try
- {
- fact.init(new NullManagerParameters());
- return (X509KeyManager) fact.getKeyManagers()[0];
- }
- catch (Exception shouldNotHappen)
- {
- throw new Error(shouldNotHappen.toString());
- }
- }
-
- private X509TrustManager defaultTrustManager() throws KeyManagementException
- {
- try
- {
- TrustManagerFactory fact =
- TrustManagerFactory.getInstance("JessieX509", "Jessie");
- fact.init(StaticTrustAnchors.CA_CERTS);
- return (X509TrustManager) fact.getTrustManagers()[0];
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException(nsae.toString());
- }
- catch (NoSuchProviderException nspe)
- {
- throw new KeyManagementException(nspe.toString());
- }
- catch (InvalidAlgorithmParameterException kse)
- {
- throw new KeyManagementException(kse.toString());
- }
- }
-
- private SecureRandom defaultRandom() throws KeyManagementException
- {
- String alg = Util.getSecurityProperty("jessie.secure.random");
- if (alg == null)
- {
- alg = "Fortuna";
- }
- SecureRandom rand = null;
- try
- {
- rand = SecureRandom.getInstance(alg);
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException(nsae.toString());
- }
-
- return rand;
- }
-}
diff --git a/gnu/javax/net/ssl/provider/Debug.java b/gnu/javax/net/ssl/provider/Debug.java
new file mode 100644
index 000000000..6d0f7c3a5
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/Debug.java
@@ -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;
+}
diff --git a/gnu/javax/net/ssl/provider/DelegatedTask.java b/gnu/javax/net/ssl/provider/DelegatedTask.java
new file mode 100644
index 000000000..200d4d457
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/DelegatedTask.java
@@ -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;
+}
diff --git a/gnu/javax/net/ssl/provider/DiffieHellman.java b/gnu/javax/net/ssl/provider/DiffieHellman.java
index ad48c7959..5a5275712 100644
--- a/gnu/javax/net/ssl/provider/DiffieHellman.java
+++ b/gnu/javax/net/ssl/provider/DiffieHellman.java
@@ -39,6 +39,9 @@ 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;
/**
@@ -72,7 +75,8 @@ final class DiffieHellman
static GnuDHPrivateKey getParams()
{
BigInteger p = DiffieHellman.GROUP_5;
- String group = Util.getSecurityProperty("jessie.key.dh.group");
+ String group = AccessController.doPrivileged
+ (new GetSecurityPropertyAction("jessie.key.dh.group"));
if (group != null)
{
group = group.trim();
diff --git a/gnu/javax/net/ssl/provider/DigestOutputStream.java b/gnu/javax/net/ssl/provider/DigestOutputStream.java
deleted file mode 100644
index f1548459e..000000000
--- a/gnu/javax/net/ssl/provider/DigestOutputStream.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/* DigestOutputStream.java -- digesting output stream.
- 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.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import gnu.java.security.hash.IMessageDigest;
-
-final class DigestOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private IMessageDigest md5, sha;
- private boolean digesting;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha)
- {
- super(out);
- this.md5 = md5;
- this.sha = sha;
- digesting = true;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- void setDigesting(boolean digesting)
- {
- this.digesting = digesting;
- }
-
- public void write(int b) throws IOException
- {
- if (digesting)
- {
- md5.update((byte) b);
- sha.update((byte) b);
- }
- out.write(b);
- }
-
- public void write(byte[] buf) throws IOException
- {
- write(buf, 0, buf.length);
- }
-
- public void write(byte[] buf, int off, int len) throws IOException
- {
- if (buf == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off+len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
- if (digesting)
- {
- md5.update(buf, off, len);
- sha.update(buf, off, len);
- }
- out.write(buf, off, len);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
new file mode 100644
index 000000000..acf4cfa03
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
new file mode 100644
index 000000000..ea7439bd2
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/ExchangeKeys.java b/gnu/javax/net/ssl/provider/ExchangeKeys.java
new file mode 100644
index 000000000..f161f484a
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ExchangeKeys.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/Extension.java b/gnu/javax/net/ssl/provider/Extension.java
index 1c79dd5cb..c79e58832 100644
--- a/gnu/javax/net/ssl/provider/Extension.java
+++ b/gnu/javax/net/ssl/provider/Extension.java
@@ -38,177 +38,209 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-final class Extension implements Constructed
+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 final Type type;
- private final byte[] value;
+ private ByteBuffer buffer;
// Constructor.
// -------------------------------------------------------------------------
- Extension(Type type, byte[] value)
+ public Extension(final ByteBuffer buffer)
{
- if (type == null || value == null)
- {
- throw new NullPointerException();
- }
- this.type = type;
- this.value = value;
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static Extension read(InputStream in) throws IOException
+
+ public Extension(final Type type, final Value value)
{
- Type t = Type.read(in);
- int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- byte[] v = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(v, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of extension");
- }
- count += l;
- }
- return new Extension(t, v);
+ 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 void write(OutputStream out) throws IOException
+ public int length ()
+ {
+ return (buffer.getShort (2) & 0xFFFF) + 4;
+ }
+
+ public ByteBuffer buffer()
{
- out.write(type.getEncoded());
- out.write(value.length >>> 8 & 0xFF);
- out.write(value.length & 0xFF);
- out.write(value);
+ return (ByteBuffer) buffer.duplicate().limit(length());
}
- Type getType()
+ public Type type()
{
- return type;
+ return Type.forValue (buffer.getShort (0) & 0xFFFF);
}
- byte[] getValue()
+ 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 {");
- out.println(" type = " + type + ";");
+ 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(Util.hexDump(value, " "));
- out.println("} Extension;");
+ out.println(value().toString(subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print("} Extension;");
return str.toString();
}
- // Inner class.
+ // Inner classes.
// -------------------------------------------------------------------------
- static final class Type implements Enumerated
+ public static enum Type
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Type SERVER_NAME = new Type(0);
- static final Type MAX_FRAGMENT_LENGTH = new Type(1);
- static final Type CLIENT_CERTIFICATE_URL = new Type(2);
- static final Type TRUSTED_CA_KEYS = new Type(3);
- static final Type TRUNCATED_HMAC = new Type(4);
- static final Type STATUS_REQUEST = new Type(5);
- static final Type SRP = new Type(6);
- static final Type CERT_TYPE = new Type(7);
+ 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;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Type(int value)
{
this.value = value;
}
- // Class methods.
- // -----------------------------------------------------------------------
-
- static Type read(InputStream in) throws IOException
+ public static Type forValue (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- int value = (i & 0xFF) << 8;
- i = in.read();
- if (i == -1)
+ switch (value & 0xFFFF)
{
- throw new EOFException("unexpected end of input stream");
- }
- value |= i & 0xFF;
- switch (value)
- {
- 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 new Type(value);
+ 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;
}
}
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] {
- (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF)
- };
- }
-
+
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- 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 "unknown(" + value + ")";
- }
- }
+ }
+
+ public static abstract class Value implements Builder, Constructed
+ {
}
}
diff --git a/gnu/javax/net/ssl/provider/ExtensionList.java b/gnu/javax/net/ssl/provider/ExtensionList.java
new file mode 100644
index 000000000..d5aaad621
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ExtensionList.java
@@ -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);
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/Extensions.java b/gnu/javax/net/ssl/provider/Extensions.java
deleted file mode 100644
index 9ed9619f0..000000000
--- a/gnu/javax/net/ssl/provider/Extensions.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Extensions.java -- various static extension utilities.
- 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.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.security.auth.x500.X500Principal;
-
-import gnu.java.security.x509.X500DistinguishedName;
-
-final class Extensions
-{
-
- // Constants.
- // -------------------------------------------------------------------------
-
- private static final Integer _512 = new Integer(512),
- _1024 = new Integer(1024), _2048 = new Integer(2048),
- _4096 = new Integer(4096);
-
- // Class methods only.
- private Extensions() { }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static List getServerName(Extension ex)
- {
- LinkedList l = new LinkedList();
- byte[] buf = ex.getValue();
- int pos = 0;
- try
- {
- while (pos < buf.length)
- {
- if (buf[pos++] != 0)
- break;
- int len = (buf[pos++] & 0xFF) << 8;
- len |= buf[pos++] & 0xFF;
- l.add(new String(buf, pos, len, "UTF-8"));
- pos += len;
- }
- }
- catch (Exception x)
- {
- }
- return Collections.unmodifiableList(l);
- }
-
- static List getClientCertTypes(Extension ex) throws IOException
- {
- List l = new LinkedList();
- ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue());
- final int len = in.read() & 0xFF;
- for (int i = 0; i < len; i++)
- {
- l.add(CertificateType.read(in));
- }
- return Collections.unmodifiableList(l);
- }
-
- static CertificateType getServerCertType(Extension ex) throws IOException
- {
- return CertificateType.read(new ByteArrayInputStream(ex.getValue()));
- }
-
- static Integer getMaxFragmentLength(Extension ex)
- {
- switch (ex.getValue()[0] & 0xFF)
- {
- case 1: return _512;
- case 2: return _1024;
- case 3: return _2048;
- case 4: return _4096;
- }
- throw new IllegalArgumentException();
- }
-
- static Object[] getTrustedCA(Extension ex)
- {
- byte[] buf = ex.getValue();
- int type = buf[0] & 0xFF;
- try
- {
- switch (type)
- {
- case 0:
- return new Object[] { new Integer(type), null };
- case 1:
- case 3:
- return new Object[] { new Integer(type),
- Util.trim(buf, 1, 20) };
- case 2:
- return new Object[] { new Integer(type),
- new X500Principal(Util.trim(buf, 1, 20)) };
- }
- }
- catch (Exception x)
- {
- }
- throw new IllegalArgumentException();
- }
-
- static String getSRPUsername(Extension ex)
- {
- int len = ex.getValue()[0] & 0xFF;
- if (len > ex.getValue().length - 1)
- throw new IllegalArgumentException();
- try
- {
- return new String(ex.getValue(), 1, len, "UTF-8");
- }
- catch (UnsupportedEncodingException uee)
- {
- throw new Error(uee.toString());
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/Finished.java b/gnu/javax/net/ssl/provider/Finished.java
index 8b9c220a5..9a2a4707a 100644
--- a/gnu/javax/net/ssl/provider/Finished.java
+++ b/gnu/javax/net/ssl/provider/Finished.java
@@ -38,10 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-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.nio.ByteBuffer;
final class Finished implements Handshake.Body
{
@@ -49,95 +49,125 @@ final class Finished implements Handshake.Body
// Fields.
// -------------------------------------------------------------------------
- /** TLSv1.x verify data. */
- private final byte[] verifyData;
-
- /** SSLv3 message digest pair. */
- private final byte[] md5, sha;
+ private final ByteBuffer buffer;
+ private final ProtocolVersion version;
// Constructor.
// -------------------------------------------------------------------------
- Finished(byte[] verifyData)
+ Finished (final ByteBuffer buffer, final ProtocolVersion version)
{
- this.verifyData = verifyData;
- md5 = sha = null;
+ buffer.getClass ();
+ version.getClass ();
+ this.buffer = buffer;
+ this.version = version;
}
- Finished(byte[] md5, byte[] sha)
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
{
- this.md5 = md5;
- this.sha = sha;
- verifyData = null;
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ return 12;
+ if (version == ProtocolVersion.SSL_3)
+ return 36;
+ throw new IllegalArgumentException ("length for this version unknown");
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static Finished read(InputStream in, CipherSuite suite)
- throws IOException
+ byte[] verifyData()
{
- DataInputStream din = new DataInputStream(in);
- if (suite.getVersion().equals(ProtocolVersion.SSL_3))
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
{
- byte[] md5 = new byte[16];
- byte[] sha = new byte[20];
- din.readFully(md5);
- din.readFully(sha);
- return new Finished(md5, sha);
+ byte[] verify = new byte[12];
+ buffer.position (0);
+ buffer.get (verify);
+ return verify;
}
- else
+ throw new IllegalArgumentException ("not TLSv1.0 or later");
+ }
+
+ byte[] md5Hash()
+ {
+ if (version == ProtocolVersion.SSL_3)
{
- byte[] buf = new byte[12];
- din.readFully(buf);
- return new Finished(buf);
+ byte[] md5 = new byte[16];
+ buffer.position (0);
+ buffer.get (md5);
+ return md5;
}
+ throw new IllegalArgumentException ("not SSLv3");
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ byte[] shaHash()
{
- if (verifyData != null)
- out.write(verifyData);
- else
+ if (version == ProtocolVersion.SSL_3)
{
- out.write(md5);
- out.write(sha);
+ 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);
}
- byte[] getVerifyData()
+ void setMD5Hash (final byte[] md5, final int offset)
{
- return verifyData;
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (0);
+ buffer.put (md5, offset, 16);
}
- byte[] getMD5Hash()
+ void setShaHash (final byte[] sha, final int offset)
{
- return md5;
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (16);
+ buffer.put (sha, offset, 20);
}
- byte[] getSHAHash()
+ public String toString ()
{
- return sha;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
- String nl = System.getProperty("line.separator");
- if (verifyData != null)
+ 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)
{
- return "struct {" + nl +
- " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl +
- "} Finished;" + nl;
+ out.print (" verifyData = ");
+ out.print (Util.toHexString (verifyData (), ':'));
}
- else
+ else if (version == ProtocolVersion.SSL_3)
{
- return "struct {" + nl +
- " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl +
- " shaHash = " + Util.toHexString(sha, ':') + ";" + nl +
- "} Finished;" + nl;
+ 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 ();
}
}
diff --git a/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
deleted file mode 100644
index a04c3fd5c..000000000
--- a/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
+++ /dev/null
@@ -1,490 +0,0 @@
-/* GNUSecurityParameters.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 java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import java.security.SecureRandom;
-import java.security.Security;
-import java.util.Arrays;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.SSLException;
-
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mode.IMode;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-
-/**
- * This class implements the {@link SecurityParameters} interface, using the
- * GNU Crypto interface for ciphers and macs, and the JZlib package for
- * record compression.
- */
-class GNUSecurityParameters implements SecurityParameters
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = false;
- private static final PrintWriter debug = new PrintWriter (System.err, true);
-
- /**
- * The CBC block cipher, if any.
- */
- IMode inCipher, outCipher;
-
- /**
- * The RC4 PRNG, if any.
- */
- IRandom inRandom, outRandom;
-
- /**
- * The MAC algorithm.
- */
- IMac inMac, outMac;
-
- long inSequence, outSequence;
- Session session;
- ProtocolVersion version;
- int fragmentLength;
- private Inflater inflater;
- private Deflater deflater;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- GNUSecurityParameters (Session session)
- {
- inSequence = 0;
- outSequence = 0;
- this.session = session;
- fragmentLength = 16384;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void reset()
- {
- inSequence = 0L;
- outSequence = 0L;
- inCipher = null;
- outCipher = null;
- inMac = null;
- outMac = null;
- inRandom = null;
- outRandom = null;
- deflater = null;
- inflater = null;
- }
-
- public ProtocolVersion getVersion()
- {
- return version;
- }
-
- public void setVersion(ProtocolVersion version)
- {
- this.version = version;
- }
-
- public void setInCipher(Object inCipher)
- {
- if (inCipher instanceof IMode)
- {
- this.inCipher = (IMode) inCipher;
- inRandom = null;
- }
- else
- {
- inRandom = (IRandom) inCipher;
- this.inCipher = null;
- }
- }
-
- public void setOutCipher(Object outCipher)
- {
- if (outCipher instanceof IMode)
- {
- this.outCipher = (IMode) outCipher;
- outRandom = null;
- }
- else
- {
- outRandom = (IRandom) outCipher;
- this.outCipher = null;
- }
- }
-
- public void setInMac(Object inMac)
- {
- this.inMac = (IMac) inMac;
- inSequence = 0L;
- }
-
- public void setOutMac(Object outMac)
- {
- this.outMac = (IMac) outMac;
- outSequence = 0L;
- }
-
- public void setDeflating (boolean deflate)
- {
- if (deflate)
- {
- if (deflater == null)
- deflater = new Deflater();
- }
- else
- deflater = null;
- }
-
- public void setInflating (boolean inflate)
- {
- if (inflate)
- {
- if (inflater == null)
- inflater = new Inflater();
- }
- else
- inflater = null;
- }
-
- public int getFragmentLength()
- {
- return fragmentLength;
- }
-
- public void setFragmentLength (int fragmentLength)
- {
- this.fragmentLength = fragmentLength;
- }
-
- /**
- * Decrypt, verify, and decompress a fragment, returning the transformed
- * fragment.
- *
- * @param fragment The fragment to decrypt.
- * @param version The protocol version of the fragment's record.
- * @param type The content type of the record.
- * @return The decrypted fragment.
- * @throws MacException If the MAC could not be verified.
- * @throws OverflowException If the inflated data is too large.
- * @throws SSLException If decompressing fails.
- */
- public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
- ContentType type)
- throws MacException, OverflowException, SSLException
- {
- boolean badPadding = false;
-
- // Decrypt the ciphertext, if it is encrypted.
- if (inCipher != null)
- {
- int bs = inCipher.currentBlockSize ();
- for (int i = 0; i < fragment.length; i += bs)
- {
- inCipher.update (fragment, i, fragment, i);
- }
- int padLen = fragment[fragment.length-1] & 0xFF;
- int len = fragment.length - padLen - 1;
- if (version == ProtocolVersion.SSL_3)
- {
- // SSLv3 requires that the padding length not exceed the
- // cipher's block size.
- if (padLen >= bs)
- {
- badPadding = true;
- }
- }
- else
- {
- for (int i = len; i < fragment.length; i++)
- {
- // If the TLS padding is wrong, throw a MAC exception below.
- if ((fragment[i] & 0xFF) != padLen)
- {
- badPadding = true;
- }
- }
- }
- fragment = Util.trim (fragment, len);
- }
- else if (inRandom != null)
- {
- transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom);
- }
-
- // Check the MAC.
- if (inMac != null)
- {
- inMac.update ((byte) (inSequence >>> 56));
- inMac.update ((byte) (inSequence >>> 48));
- inMac.update ((byte) (inSequence >>> 40));
- inMac.update ((byte) (inSequence >>> 32));
- inMac.update ((byte) (inSequence >>> 24));
- inMac.update ((byte) (inSequence >>> 16));
- inMac.update ((byte) (inSequence >>> 8));
- inMac.update ((byte) inSequence);
- inMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- inMac.update ((byte) version.getMajor());
- inMac.update ((byte) version.getMinor());
- }
- int macLen = inMac.macSize ();
- int fragLen = fragment.length - macLen;
- inMac.update ((byte) (fragLen >>> 8));
- inMac.update ((byte) fragLen);
- inMac.update (fragment, 0, fragLen);
- byte[] mac = inMac.digest ();
- inMac.reset ();
- for (int i = 0; i < macLen; i++)
- {
- if (fragment[i + fragLen] != mac[i])
- {
- throw new MacException();
- }
- }
- if (badPadding)
- {
- throw new MacException();
- }
- fragment = Util.trim (fragment, fragLen);
- }
-
- if (inflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
- inflater.setInput (fragment);
- int len;
- try
- {
- while ((len = inflater.inflate (buf)) > 0)
- {
- bout.write (buf, 0, len);
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("inflated data too large");
- }
- }
- catch (DataFormatException dfe)
- {
- throw new SSLException (String.valueOf (dfe));
- }
- fragment = bout.toByteArray();
- inflater.reset();
- }
-
- inSequence++;
- return fragment;
- }
-
- /**
- * Compress, MAC, encrypt, and write a record. The fragment of the
- * record is taken from <i>buf</i> as <i>len</i> bytes starting at
- * <i>offset</i>. <i>len</i> <b>must</b> be smaller than or equal to
- * the configured fragment length.
- *
- * @param buf The fragment bytes.
- * @param off The offset from whence to read.
- * @param len The size of the fragment.
- * @param type The content-type for this record.
- * @param out The output stream to write the record to.
- * @throws IOException If an I/O error occurs.
- * @throws SSLException If compression fails.
- * @throws OverflowException If compression inflates the data beyond
- * the fragment length plus 1024 bytes.
- */
- public synchronized byte[] encrypt (byte[] buf, int off, int len,
- ContentType type)
- throws SSLException, OverflowException
- {
- // If we are compressing, do it.
- if (deflater != null)
- {
- byte[] buf2 = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
- deflater.setInput (buf, off, len);
- deflater.finish();
- len = 0;
- while ((len = deflater.deflate (buf2)) > 0)
- bout.write (buf2, 0, len);
- // This should technically never happen for zlib.
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("deflated data too large");
- buf = bout.toByteArray();
- off = 0;
- len = buf.length;
- deflater.reset();
- }
-
- // If there is a MAC, compute it.
- byte[] mac = new byte[0];
- if (outMac != null)
- {
- outMac.update((byte) (outSequence >>> 56));
- outMac.update((byte) (outSequence >>> 48));
- outMac.update((byte) (outSequence >>> 40));
- outMac.update((byte) (outSequence >>> 32));
- outMac.update((byte) (outSequence >>> 24));
- outMac.update((byte) (outSequence >>> 16));
- outMac.update((byte) (outSequence >>> 8));
- outMac.update((byte) outSequence);
- outMac.update((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- outMac.update((byte) version.getMajor());
- outMac.update((byte) version.getMinor());
- }
- outMac.update((byte) (len >>> 8));
- outMac.update((byte) len);
- outMac.update(buf, off, len);
- mac = outMac.digest();
- outMac.reset();
- }
- outSequence++;
-
- // Compute padding if needed.
- byte[] pad = new byte[0];
- if (outCipher != null)
- {
- int padLen = outCipher.currentBlockSize() -
- ((len + mac.length + 1) % outCipher.currentBlockSize());
- // Use a random amount of padding if the protocol is TLS.
- if (version != ProtocolVersion.SSL_3 && session.random != null)
- {
- padLen += (Math.abs(session.random.nextInt ()) & 7) *
- outCipher.currentBlockSize();
- while (padLen > 255)
- {
- padLen -= outCipher.currentBlockSize();
- }
- }
- pad = new byte[padLen+1];
- Arrays.fill (pad, (byte) padLen);
- }
-
- // Write the record header.
- final int fraglen = len + mac.length + pad.length;
-
- // Encrypt and write the fragment.
- if (outCipher != null)
- {
- byte[] buf2 = new byte[fraglen];
- System.arraycopy (buf, off, buf2, 0, len);
- System.arraycopy (mac, 0, buf2, len, mac.length);
- System.arraycopy (pad, 0, buf2, len + mac.length, pad.length);
- int bs = outCipher.currentBlockSize ();
- for (int i = 0; i < fraglen; i += bs)
- {
- outCipher.update (buf2, i, buf2, i);
- }
- return buf2;
- }
- else if (outRandom != null)
- {
- byte[] buf2 = new byte[fraglen];
- transformRC4 (buf, off, len, buf2, 0, outRandom);
- transformRC4 (mac, 0, mac.length, buf2, len, outRandom);
- return buf2;
- }
- else
- {
- if (mac.length == 0)
- {
- return Util.trim (buf, off, len);
- }
- else
- {
- return Util.concat (Util.trim (buf, off, len), mac);
- }
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- /**
- * Encrypt/decrypt a byte array with the RC4 stream cipher.
- *
- * @param in The input data.
- * @param off The input offset.
- * @param len The number of bytes to transform.
- * @param out The output buffer.
- * @param outOffset The offest into the output buffer.
- * @param random The ARCFOUR PRNG.
- */
- private static void transformRC4(byte[] in, int off, int len,
- byte[] out, int outOffset, IRandom random)
- {
- if (random == null)
- {
- throw new IllegalStateException();
- }
- if (in == null || out == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || off + len > in.length ||
- outOffset < 0 || outOffset + len > out.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- try
- {
- for (int i = 0; i < len; i++)
- {
- out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte());
- }
- }
- catch (LimitReachedException cannotHappen)
- {
- throw new Error(cannotHappen.toString());
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/Handshake.java b/gnu/javax/net/ssl/provider/Handshake.java
index ef9e72381..52f61424e 100644
--- a/gnu/javax/net/ssl/provider/Handshake.java
+++ b/gnu/javax/net/ssl/provider/Handshake.java
@@ -1,4 +1,4 @@
-/* Handshake.java -- SSL handshake message.
+/* Handshake.java -- SSL Handshake message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -49,6 +49,8 @@ import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
import java.security.PublicKey;
import java.util.ArrayList;
@@ -56,306 +58,219 @@ import java.util.Collections;
import javax.net.ssl.SSLProtocolException;
-final class Handshake implements Constructed
+/**
+ * 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 static final buffer BUF = new buffer();
-
- private final Type type;
- private final Body body;
+ private final ByteBuffer buffer;
+ private final CipherSuite suite;
+ private final ProtocolVersion version;
// Constructors.
// -------------------------------------------------------------------------
- Handshake(Type type, Body body)
+ public Handshake (final ByteBuffer buffer)
{
- this.type = type;
- this.body = body;
+ this (buffer, null, ProtocolVersion.TLS_1_1);
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static Handshake read(byte[] buffer) throws IOException
+ public Handshake (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
{
- return read(new ByteArrayInputStream(buffer));
+ this.buffer = buffer;
+ this.suite = suite;
+ this.version = version;
}
- static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key)
- throws IOException
- {
- return read(new ByteArrayInputStream(buffer), suite, key);
- }
-
- static Handshake read(InputStream in) throws IOException
- {
- return read(in, null, null);
- }
+ // Instance methods.
+ // -------------------------------------------------------------------------
- static Handshake read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+ /**
+ * Returns the handshake type.
+ *
+ * @return The handshake type.
+ */
+ public Type type()
{
- return read(in, suite, key, null);
+ return Type.forInteger (buffer.get (0) & 0xFF);
}
- static Handshake read(InputStream in, CertificateType certType)
- throws IOException
+ /**
+ * Returns the message length.
+ *
+ * @return The message length.
+ */
+ public int length ()
{
- return read(in, null, null, certType);
+ // Length is a uint24.
+ return buffer.getInt (0) & 0xFFFFFF;
}
- static Handshake read(InputStream in, CipherSuite suite, PublicKey key,
- CertificateType certType)
- throws IOException
+ /**
+ * 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.read(in);
- byte[] lenbuf = new byte[3];
- in.read(lenbuf);
- int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8
- | (lenbuf[2] & 0xFF);
- Body body = null;
- if (type == Type.HELLO_REQUEST)
- {
- body = null;
- }
- else if (type == Type.CLIENT_HELLO)
- {
- // Most likely a V2 hello. If the first byte is 0x30, and if this
- // is not a V2 client hello, then it is a V3 client hello with
- // at least 1.5 million cipher specs, which is unlikely.
- if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2))
- {
- ProtocolVersion vers = null;
- switch (lenbuf[1])
- {
- case 0:
- vers = ProtocolVersion.SSL_3;
- break;
- case 1:
- vers = ProtocolVersion.TLS_1;
- break;
- case 2:
- vers = ProtocolVersion.TLS_1_1;
- break;
- }
- int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF);
- int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
-
- ArrayList suites = new ArrayList(specLen / 3);
- for (int i = 0; i < specLen; i += 3)
- {
- if (in.read() == 0)
- {
- suites.add(CipherSuite.read(in).resolve(vers));
- }
- else
- {
- in.read();
- in.read();
- }
- }
- byte[] id = new byte[idLen];
- in.read(id);
- byte[] challenge = new byte[chalLen];
- in.read(challenge);
- if (challenge.length > 32)
- challenge = Util.trim(challenge, 32);
- else if (challenge.length < 32)
- {
- byte[] b = new byte[32];
- System.arraycopy(challenge, 0, b, b.length - challenge.length,
- challenge.length);
- challenge = b;
- }
- int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16
- | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF);
- Random rand = new Random(time, Util.trim(challenge, 4, 28));
- return new Handshake(Handshake.Type.CLIENT_HELLO,
- new ClientHello(vers, rand, id, suites,
- Collections.singletonList(CompressionMethod.NULL)));
- }
- // Since hello messages may contain extensions, we read the whole
- // thing here.
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- count += l;
- }
- body = ClientHello.read(new ByteArrayInputStream(buf));
- }
- else if (type == Type.SERVER_HELLO)
- {
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- count += l;
- }
- body = ServerHello.read(new ByteArrayInputStream(buf));
- }
- else if (type == Type.CERTIFICATE)
- {
- body = Certificate.read(in, certType);
- }
- else if (type == Type.SERVER_KEY_EXCHANGE)
+ Type type = type ();
+ ByteBuffer bodyBuffer = bodyBuffer ();
+ switch (type)
{
- body = ServerKeyExchange.read(in, suite, key);
- }
- else if (type == Type.CERTIFICATE_REQUEST)
- {
- body = CertificateRequest.read(in);
- }
- else if (type == Type.CERTIFICATE_VERIFY)
- {
- body = (CertificateVerify) CertificateVerify.read(in, suite, key);
- }
- else if (type == Type.CLIENT_KEY_EXCHANGE)
- {
- body = ClientKeyExchange.read(in, suite, key);
- }
- else if (type == Type.SERVER_HELLO_DONE)
- {
- body = null;
- }
- else if (type == Type.FINISHED)
- {
- body = Finished.read(in, suite);
- }
- else
- {
- throw new SSLProtocolException("unknown HandshakeType: " +
- type.getValue());
- }
+ case HELLO_REQUEST:
+ return new HelloRequest ();
- return new Handshake(type, body);
- }
+ case CLIENT_HELLO:
+ return new ClientHello (bodyBuffer);
- // Instance methods.
- // -------------------------------------------------------------------------
+ case SERVER_HELLO:
+ return new ServerHello (bodyBuffer);
- public void write(OutputStream out)
- {
- throw new UnsupportedOperationException();
+ 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);
}
- public int write(OutputStream out, ProtocolVersion version)
- throws IOException
+ /**
+ * 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 ()
{
- out.write(type.getValue());
- if (body == null)
- {
- out.write(0);
- out.write(0);
- out.write(0);
- return 4;
- }
- else
- {
- ByteArrayOutputStream bout = BUF.getBuffer();
- bout.reset();
- if (body instanceof ServerKeyExchange)
- {
- ((ServerKeyExchange) body).write(bout, version);
- }
- else if (body instanceof ClientKeyExchange)
- {
- ((ClientKeyExchange) body).write(bout, version);
- }
- else if (body instanceof CertificateVerify)
- {
- ((CertificateVerify) body).write(bout, version);
- }
- else
- {
- body.write(bout);
- }
- out.write(bout.size() >>> 16 & 0xFF);
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
- return 4 + bout.size();
- }
+ int length = length ();
+ return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
}
- Type getType()
+ /**
+ * Sets the handshake body type.
+ *
+ * @param type The handshake type.
+ */
+ public void setType (final Type type)
{
- return type;
+ buffer.put (0, (byte) type.getValue ());
}
- Body getBody()
+ /**
+ * 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)
{
- return body;
+ 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);
- String nl = System.getProperty("line.separator");
- StringBuffer buf = new StringBuffer();
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.println(" type = " + type + ";");
- if (body != null)
- {
- BufferedReader r = new BufferedReader(new StringReader(body.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println("} Handshake;");
+ 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.
// -------------------------------------------------------------------------
- static interface Body extends Constructed
+ public static interface Body extends Constructed
{
+ int length ();
+
+ String toString (String prefix);
}
- static class Type implements Enumerated
+ public static enum Type
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- public static final Type
- HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1),
- SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11),
- SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13),
- SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15),
- CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20),
- CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22);
+ 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;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Type(int value)
{
this.value = value;
@@ -364,18 +279,20 @@ final class Handshake implements Constructed
// Class methods.
// -----------------------------------------------------------------------
- public static Type read(InputStream in) throws IOException
+ /**
+ * 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)
{
- int i = in.read();
- if (i == -1)
+ switch (value & 0xFF)
{
- throw new EOFException("unexpected end of input stream");
- }
- switch (i & 0xFF)
- {
- case 0: return HELLO_REQUEST;
- case 1: return CLIENT_HELLO;
- case 2: return SERVER_HELLO;
+ 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;
@@ -385,56 +302,13 @@ final class Handshake implements Constructed
case 20: return FINISHED;
case 21: return CERTIFICATE_URL;
case 22: return CERTIFICATE_STATUS;
- default: return new Type(i);
+ default: throw new IllegalArgumentException ("unsupported value type " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- 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: return "unknown(" + value + ")";
- }
- }
- }
-
- private static class buffer extends ThreadLocal
- {
- static final int SIZE = 2048;
-
- protected Object initialValue()
- {
- return new ByteArrayOutputStream(SIZE);
- }
-
- ByteArrayOutputStream getBuffer()
- {
- return (ByteArrayOutputStream) get();
- }
}
}
diff --git a/gnu/javax/net/ssl/provider/Enumerated.java b/gnu/javax/net/ssl/provider/HelloRequest.java
index 8875addab..0ffc26c2b 100644
--- a/gnu/javax/net/ssl/provider/Enumerated.java
+++ b/gnu/javax/net/ssl/provider/HelloRequest.java
@@ -1,4 +1,4 @@
-/* Enumerated.java -- Interface to enumerated types.
+/* HelloRequest.java -- SSL HelloRequest handshake message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -39,41 +39,32 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
/**
- * An enumerated type in the SSL protocols. Enumerated values take on
- * one of a set of possible numeric values, which are not specifically
- * ordered, and may be extensible to a maximum value.
+ * The handshake body for a HelloRequest handshake message.
*
- * <pre>enum { e1(v1), e2(v2), ... [[, (n) ]] }</pre>
- *
- * <p>Enumerated types are encoded as big-endian multibyte integers,
- * which take up the least possible number of bytes. Thus, an
- * enumeration with up to 255 values will be encoded in a single byte,
- * and so on.
- *
- * @author Casey Marshall (rsdio@metastatic.org)
+ * <pre>struct { } HelloRequest;</pre>
*/
-interface Enumerated
+public final class HelloRequest implements Handshake.Body
{
+ public HelloRequest ()
+ {
+ }
- /**
- * Returns the encoded value of this enumerated value, which is
- * appropriate to send over-the-wire.
- *
- * @return The encoded value.
- */
- byte[] getEncoded();
+ public String toString (final String prefix)
+ {
+ StringBuffer str = new StringBuffer ();
+ if (prefix != null)
+ str.append (prefix);
+ str.append ("HelloRequest { };");
+ return str.toString ();
+ }
- /**
- * Returns the numeric value of this enumerated value.
- *
- * @return The numeric value.
- */
- int getValue();
+ public int length ()
+ {
+ return 0;
+ }
- /**
- * Returns a string representation of this enumerated value.
- *
- * @return The string.
- */
- String toString();
+ public String toString ()
+ {
+ return toString (null);
+ }
}
diff --git a/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/gnu/javax/net/ssl/provider/InputSecurityParameters.java
new file mode 100644
index 000000000..13a3ef814
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/InputSecurityParameters.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/gnu/javax/net/ssl/provider/JCESecurityParameters.java
deleted file mode 100644
index 6663c97b5..000000000
--- a/gnu/javax/net/ssl/provider/JCESecurityParameters.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/* JCESecurityParameters.java -- JCE-based 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 java.io.ByteArrayOutputStream;
-
-import java.util.Arrays;
-import java.util.zip.DataFormatException;
-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.Mac;
-
-import javax.net.ssl.SSLException;
-
-class JCESecurityParameters implements SecurityParameters
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private Cipher inCipher, outCipher;
- private Mac inMac, outMac;
- private Inflater inflater;
- private Deflater deflater;
- private int fragmentLength;
- private long inSequence, outSequence;
- private ProtocolVersion version;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- JCESecurityParameters ()
- {
- fragmentLength = 16384;
- inSequence = 0L;
- outSequence = 0L;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void reset()
- {
- inCipher = null;
- outCipher = null;
- inMac = null;
- outMac = null;
- deflater = null;
- inflater = null;
- }
-
- public void setInCipher (Object inCipher)
- {
- this.inCipher = (Cipher) inCipher;
- }
-
- public void setOutCipher (Object outCipher)
- {
- this.outCipher = (Cipher) outCipher;
- }
-
- public void setInMac (Object inMac)
- {
- this.inMac = (Mac) inMac;
- inSequence = 0L;
- }
-
- public void setOutMac (Object outMac)
- {
- this.outMac = (Mac) outMac;
- outSequence = 0L;
- }
-
- public void setDeflating (boolean deflate)
- {
- if (deflate)
- {
- if (deflater == null)
- deflater = new Deflater();
- }
- else
- deflater = null;
- }
-
- public void setInflating (boolean inflate)
- {
- if (inflate)
- {
- if (inflater == null)
- inflater = new Inflater();
- }
- else
- inflater = null;
- }
-
- public int getFragmentLength()
- {
- return fragmentLength;
- }
-
- public void setFragmentLength (int fragmentLength)
- {
- this.fragmentLength = fragmentLength;
- }
-
- public ProtocolVersion getVersion()
- {
- return version;
- }
-
- public void setVersion (ProtocolVersion version)
- {
- this.version = version;
- }
-
- public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
- ContentType type)
- throws MacException, OverflowException, SSLException
- {
- boolean badpad = false;
- if (inCipher != null)
- {
- // We imagine that the JCE would be used in cases where hardware
- // acceleration is available, since it isn't really that useful for
- // pure Java crypto. We decrypt (and encrypt, below) in one go
- // to minimize (potential) calls to native methods.
- try
- {
- fragment = inCipher.doFinal (fragment);
- }
- catch (BadPaddingException bpe)
- {
- badpad = true;
- }
- catch (IllegalBlockSizeException ibse)
- {
- badpad = true;
- }
- }
-
- if (inMac != null)
- {
- int macLen = inMac.getMacLength();
- int fragLen = fragment.length - macLen;
- byte[] mac = Util.trim (fragment, fragLen, macLen);
- fragment = Util.trim (fragment, fragLen);
- inMac.update ((byte) (inSequence >>> 56));
- inMac.update ((byte) (inSequence >>> 48));
- inMac.update ((byte) (inSequence >>> 40));
- inMac.update ((byte) (inSequence >>> 32));
- inMac.update ((byte) (inSequence >>> 24));
- inMac.update ((byte) (inSequence >>> 16));
- inMac.update ((byte) (inSequence >>> 8));
- inMac.update ((byte) inSequence);
- inMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- inMac.update ((byte) version.getMajor());
- inMac.update ((byte) version.getMinor());
- }
- inMac.update ((byte) (fragLen >>> 8));
- inMac.update ((byte) fragLen);
- inMac.update (fragment);
- if (!Arrays.equals (mac, inMac.doFinal()) || badpad)
- throw new MacException();
- }
-
- if (inflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
- inflater.setInput (fragment);
- int len;
- try
- {
- while ((len = inflater.inflate (buf)) > 0)
- {
- bout.write (buf, 0, len);
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("inflated data too large");
- }
- }
- catch (DataFormatException dfe)
- {
- throw new SSLException (String.valueOf (dfe));
- }
- fragment = bout.toByteArray();
- inflater.reset();
- }
-
- inSequence++;
- return fragment;
- }
-
- public synchronized byte[] encrypt (byte[] fragment, int off, int len,
- ContentType type)
- throws OverflowException, SSLException
- {
- if (deflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
- deflater.setInput (fragment, off, len);
- deflater.finish();
- len = 0;
- while ((len = deflater.deflate (buf)) > 0)
- bout.write (buf, 0, len);
- // This should technically never happen for zlib.
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("deflated data too large");
- fragment = bout.toByteArray();
- off = 0;
- len = fragment.length;
- deflater.reset();
- }
-
- if (outMac != null)
- {
- outMac.update ((byte) (inSequence >>> 56));
- outMac.update ((byte) (inSequence >>> 48));
- outMac.update ((byte) (inSequence >>> 40));
- outMac.update ((byte) (inSequence >>> 32));
- outMac.update ((byte) (inSequence >>> 24));
- outMac.update ((byte) (inSequence >>> 16));
- outMac.update ((byte) (inSequence >>> 8));
- outMac.update ((byte) inSequence);
- outMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- outMac.update ((byte) version.getMajor());
- outMac.update ((byte) version.getMinor());
- }
- outMac.update ((byte) (len >>> 8));
- outMac.update ((byte) len);
- outMac.update (fragment, off, len);
- fragment = Util.concat (fragment, outMac.doFinal());
- off = 0;
- len = fragment.length;
- }
-
- if (outCipher != null)
- {
- try
- {
- fragment = outCipher.doFinal (fragment, off, len);
- }
- catch (BadPaddingException shouldNeverHappen)
- {
- // This is nonsensical. Don't even pretend that we can handle this.
- throw new RuntimeException ("bad padding thrown while encrypting");
- }
- catch (IllegalBlockSizeException ibse)
- {
- // Ditto.
- throw new RuntimeException ("illegal block size thrown while encrypting");
- }
- off = 0;
- len = fragment.length;
- }
-
- outSequence++;
- if (off == 0 && len == fragment.length)
- return fragment;
- else
- return Util.trim (fragment, off, len);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/gnu/javax/net/ssl/provider/JDBCSessionContext.java
deleted file mode 100644
index 2b9b14034..000000000
--- a/gnu/javax/net/ssl/provider/JDBCSessionContext.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/* JDBCSessionContext.java -- database persistent sessions.
- 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.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Timestamp;
-import java.sql.Types;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Enumeration;
-import java.util.TreeSet;
-import java.util.Vector;
-
-import javax.net.ssl.SSLSession;
-
-/**
- * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>,
- * looks like this:
- *
- * <blockquote><pre>
- * TABLE SESSIONS (
- * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL,
- * CREATED TIMESTAMP NOT NULL,
- * LAST_ACCESSED TIMESTAMP NOT NULL,
- * PROTOCOL VARCHAR(7) NOT NULL,
- * SUITE VARCHAR(255) NOT NULL,
- * PEER_HOST TEXT NOT NULL,
- * PEER_CERT_TYPE VARCHAR(32),
- * PEER_CERTS BLOB,
- * CERT_TYPE VARCHAR(32),
- * CERTS BLOB,
- * SECRET VARBINARY(48) NOT NULL
- * )
- * </pre></blockquote>
- *
- * <p>Note that the master secret for sessions is not protected before
- * being inserted into the database; it is up to the system to protect
- * the stored data from unauthorized access.
- */
-class JDBCSessionContext extends SessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- protected Connection connection;
- protected PreparedStatement selectById;
- protected PreparedStatement insert;
- protected PreparedStatement selectTimestamp;
- protected PreparedStatement updateTimestamp;
- protected PreparedStatement deleteSession;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JDBCSessionContext() throws SQLException
- {
- String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url");
- String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user");
- String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password");
- if (url == null)
- {
- throw new IllegalArgumentException("no JDBC URL");
- }
- if (user == null || passwd == null)
- {
- connection = DriverManager.getConnection(url);
- }
- else
- {
- connection = DriverManager.getConnection(url, user, passwd);
- }
- selectById =
- connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?");
- insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
- selectTimestamp =
- connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?");
- updateTimestamp =
- connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?");
- deleteSession =
- connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?");
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized Enumeration getIds()
- {
- Vector ids = new Vector();
- try
- {
- Statement stmt = connection.createStatement();
- ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS");
- while (rs.next())
- {
- byte[] id = rs.getBytes("ID");
- ids.add(id);
- }
- }
- catch (SQLException sqle)
- {
- }
- return ids.elements();
- }
-
- public synchronized SSLSession getSession(byte[] sessionId)
- {
- Session session = (Session) super.getSession(sessionId);
- if (session == null)
- {
- try
- {
- selectById.setBytes(1, sessionId);
- ResultSet rs = selectById.executeQuery();
- if (rs.next())
- {
- session = new Session(rs.getTimestamp("CREATED").getTime());
- session.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- session.random = new SecureRandom();
- session.context = this;
- session.sessionId = new Session.ID(rs.getBytes("ID"));
- session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime());
- long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
- if ((int) (elapsed / 1000L) > timeout)
- {
- removeSession(session.sessionId);
- return null;
- }
- session.peerHost = rs.getString("PEER_HOST");
- String protocol = rs.getString("PROTOCOL");
- if (protocol.equals("SSLv3"))
- {
- session.protocol = ProtocolVersion.SSL_3;
- }
- else if (protocol.equals("TLSv1"))
- {
- session.protocol = ProtocolVersion.TLS_1;
- }
- else if (protocol.equals("TLSv1.1"))
- {
- session.protocol = ProtocolVersion.TLS_1_1;
- }
- else
- {
- return null;
- }
- session.cipherSuite = CipherSuite.forName(rs.getString("SUITE"));
- String type = rs.getString("PEER_CERT_TYPE");
- boolean wasNull = rs.wasNull();
- InputStream certs = null;
- if (!wasNull)
- {
- certs = rs.getBinaryStream("PEER_CERTS");
- wasNull = rs.wasNull();
- }
- if (!wasNull)
- {
- CertificateFactory cf = CertificateFactory.getInstance(type);
- session.peerCerts = (Certificate[])
- cf.generateCertificates(certs).toArray(new Certificate[0]);
- session.peerVerified = true;
- }
- type = rs.getString("CERT_TYPE");
- wasNull = rs.wasNull();
- if (!wasNull)
- {
- certs = rs.getBinaryStream("CERTS");
- wasNull = rs.wasNull();
- }
- if (!wasNull)
- {
- CertificateFactory cf = CertificateFactory.getInstance(type);
- session.localCerts = (Certificate[])
- cf.generateCertificates(certs).toArray(new Certificate[0]);
- }
- session.masterSecret = rs.getBytes("SECRET");
- if (cacheSize == 0 || sessions.size() < cacheSize)
- {
- sessions.put(session.sessionId, session);
- }
- }
- }
- catch (Exception ex)
- {
- }
- }
- return session;
- }
-
- synchronized boolean addSession(Session.ID id, Session s)
- {
- if (containsSessionID(id))
- {
- return false;
- }
- try
- {
- insert.setBytes(1, id.getId());
- insert.setTimestamp(2, new Timestamp(s.getCreationTime()));
- insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime()));
- insert.setString(4, s.getProtocol());
- insert.setString(5, s.getCipherSuite());
- insert.setString(6, s.peerHost);
- if (s.peerCerts != null && s.peerCerts.length > 0)
- {
- insert.setString(7, s.peerCerts[0].getType());
- insert.setBytes(8, certs(s.peerCerts));
- }
- else
- {
- insert.setNull(7, Types.VARCHAR);
- insert.setNull(8, Types.LONGVARBINARY);
- }
- if (s.localCerts != null && s.localCerts.length > 0)
- {
- insert.setString(9, s.localCerts[0].getType());
- insert.setBytes(10, certs(s.localCerts));
- }
- else
- {
- insert.setNull(9, Types.VARCHAR);
- insert.setNull(10, Types.LONGVARBINARY);
- }
- insert.setBytes(11, s.masterSecret);
- insert.executeUpdate();
- super.addSession(id, s);
- }
- catch (SQLException sqle)
- {
- return false;
- }
- return true;
- }
-
- synchronized boolean containsSessionID(Session.ID sessionId)
- {
- try
- {
- selectTimestamp.setBytes(1, sessionId.getId());
- ResultSet rs = selectTimestamp.executeQuery();
- if (!rs.next())
- {
- return false;
- }
- Timestamp ts = rs.getTimestamp("CREATED");
- if (rs.wasNull())
- {
- return false;
- }
- long elapsed = System.currentTimeMillis() - ts.getTime();
- if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(sessionId);
- return false;
- }
- return true;
- }
- catch (SQLException sqle)
- {
- return false;
- }
- }
-
- protected boolean removeSession(Session.ID sessionId)
- {
- super.removeSession(sessionId);
- try
- {
- deleteSession.setBytes(1, sessionId.getId());
- return deleteSession.executeUpdate() > 0;
- }
- catch (SQLException sqle)
- {
- }
- return false;
- }
-
- synchronized void notifyAccess(Session session)
- {
- try
- {
- updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime()));
- updateTimestamp.setBytes(2, session.getId());
- updateTimestamp.executeUpdate();
- }
- catch (SQLException sqle)
- {
- }
- }
-
- private byte[] certs(Certificate[] certs)
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
- for (int i = 0; i < certs.length; i++)
- {
- try
- {
- out.write(certs[i].getEncoded());
- }
- catch (Exception x)
- {
- }
- }
- return out.toByteArray();
- }
-}
diff --git a/gnu/javax/net/ssl/provider/Jessie.java b/gnu/javax/net/ssl/provider/Jessie.java
index 14b671d02..6bd68b385 100644
--- a/gnu/javax/net/ssl/provider/Jessie.java
+++ b/gnu/javax/net/ssl/provider/Jessie.java
@@ -59,31 +59,42 @@ import java.security.Provider;
*/
public class Jessie extends Provider
{
+ private static final long serialVersionUID = -1;
- public static final String VERSION = "1.0.0";
- public static final double VERSION_DOUBLE = 1.0;
+ public static final String VERSION = "2.0.0";
+ public static final double VERSION_DOUBLE = 2.0;
public Jessie()
{
super("Jessie", VERSION_DOUBLE,
- "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" +
- System.getProperty("line.separator") +
- "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." );
+ "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()
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
{
public Object run()
{
- put("SSLContext.SSLv3", Context.class.getName());
- put("Alg.Alias.SSLContext.SSL", "SSLv3");
- put("Alg.Alias.SSLContext.TLSv1", "SSLv3");
- put("Alg.Alias.SSLContext.TLS", "SSLv3");
- //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3");
+ 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("TrustManagerFactory.SRP", SRPTrustManagerFactory.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;
}
});
diff --git a/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
new file mode 100644
index 000000000..04416c5a5
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
@@ -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;
+}
diff --git a/gnu/javax/net/ssl/provider/KeyPool.java b/gnu/javax/net/ssl/provider/KeyPool.java
deleted file mode 100644
index 18d9dc281..000000000
--- a/gnu/javax/net/ssl/provider/KeyPool.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/* KeyPool.java -- A set of ephemeral key pairs.
- 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.math.BigInteger;
-import java.security.KeyPair;
-import java.security.SecureRandom;
-
-final class KeyPool
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final BigInteger ONE = BigInteger.ONE;
- private static final BigInteger TWO = BigInteger.valueOf(2L);
- private static final BigInteger E = BigInteger.valueOf(65537L);
- private static final SecureRandom RANDOM = new SecureRandom ();
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- private KeyPool()
- {
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- /**
- * Generate an export-class (512 bit) RSA key pair.
- *
- * @return The new key pair.
- */
- static KeyPair generateRSAKeyPair()
- {
- BigInteger p, q, n, d;
-
- // Simplified version of GNU Crypto's RSAKeyPairGenerator.
-
- int M = 256;
- BigInteger lower = TWO.pow(255);
- BigInteger upper = TWO.pow(256).subtract(ONE);
- byte[] kb = new byte[32];
- while (true)
- {
- nextBytes(kb);
- p = new BigInteger(1, kb).setBit(0);
- if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 &&
- p.isProbablePrime(80) && p.gcd(E).equals(ONE))
- break;
- }
-
- while (true)
- {
- nextBytes(kb);
- q = new BigInteger(1, kb).setBit(0);
- n = q.multiply(p);
- if (n.bitLength() == 512 && q.isProbablePrime(80) &&
- q.gcd(E).equals(ONE))
- break;
- }
-
- d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE)));
-
- return new KeyPair(new JessieRSAPublicKey(n, E),
- new JessieRSAPrivateKey(n, d));
- }
-
- private static void nextBytes(byte[] buf)
- {
- RANDOM.nextBytes (buf);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/MacAlgorithm.java b/gnu/javax/net/ssl/provider/MacAlgorithm.java
new file mode 100644
index 000000000..cae0efbfa
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/MacAlgorithm.java
@@ -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;
+}
diff --git a/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/gnu/javax/net/ssl/provider/MaxFragmentLength.java
new file mode 100644
index 000000000..eb63958b8
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/MaxFragmentLength.java
@@ -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() + ";";
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
new file mode 100644
index 000000000..6da0d0667
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
new file mode 100644
index 000000000..aa1f97853
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
@@ -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;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ProtocolVersion.java b/gnu/javax/net/ssl/provider/ProtocolVersion.java
index 5f5d1d979..ca62054a8 100644
--- a/gnu/javax/net/ssl/provider/ProtocolVersion.java
+++ b/gnu/javax/net/ssl/provider/ProtocolVersion.java
@@ -42,15 +42,16 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
-final class ProtocolVersion implements Comparable, Constructed
+public final class ProtocolVersion
+ implements Comparable<ProtocolVersion>, Constructed
{
// Constants and fields.
// -------------------------------------------------------------------------
- static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
- static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
- static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2);
+ 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;
@@ -67,14 +68,25 @@ final class ProtocolVersion implements Comparable, Constructed
// Class methods.
// -------------------------------------------------------------------------
- static ProtocolVersion read(InputStream in) throws IOException
+ public static ProtocolVersion read(InputStream in) throws IOException
{
int major = in.read() & 0xFF;
int minor = in.read() & 0xFF;
return getInstance(major, minor);
}
- static ProtocolVersion getInstance(int major, int 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)
{
@@ -88,35 +100,46 @@ final class ProtocolVersion implements Comparable, Constructed
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 void write(OutputStream out) throws IOException
+ public int length ()
{
- out.write(major);
- out.write(minor);
+ return 2;
}
- byte[] getEncoded()
+ public byte[] getEncoded()
{
return new byte[] {
(byte) major, (byte) minor
};
}
- int getMajor()
+ public int major()
{
return major;
}
- int getMinor()
+ public int minor()
{
return minor;
}
+ public int rawValue ()
+ {
+ return (major << 8) | minor;
+ }
+
public boolean equals(Object o)
{
- if (o == null || !(o instanceof ProtocolVersion))
+ if (!(o instanceof ProtocolVersion))
{
return false;
}
@@ -129,35 +152,33 @@ final class ProtocolVersion implements Comparable, Constructed
return major << 8 | minor;
}
- public int compareTo(Object o)
+ public int compareTo(ProtocolVersion that)
{
- if (o == null || !(o instanceof ProtocolVersion))
+ if (major > that.major)
{
return 1;
}
- if (this.equals(o))
- {
- return 0;
- }
- if (major > ((ProtocolVersion) o).major)
- {
- return 1;
- }
- else if (major < ((ProtocolVersion) o).major)
+ else if (major < that.major)
{
return -1;
}
- if (minor > ((ProtocolVersion) o).minor)
+
+ if (minor > that.minor)
{
return 1;
}
- else if (minor < ((ProtocolVersion) o).minor)
+ else if (minor < that.minor)
{
return -1;
}
return 0;
}
+ public String toString (String prefix)
+ {
+ return toString ();
+ }
+
public String toString()
{
if (this == SSL_3)
diff --git a/gnu/javax/net/ssl/provider/Random.java b/gnu/javax/net/ssl/provider/Random.java
index c42592b14..e68159309 100644
--- a/gnu/javax/net/ssl/provider/Random.java
+++ b/gnu/javax/net/ssl/provider/Random.java
@@ -45,80 +45,110 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-class Random implements Constructed
+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.
// -------------------------------------------------------------------------
- private final int gmtUnixTime;
- private final byte[] randomBytes;
+ static final int RANDOM_LENGTH = 28;
+
+ private final ByteBuffer buffer;
// Constructors.
// -------------------------------------------------------------------------
- Random(int gmtUnixTime, byte[] randomBytes)
+ public Random (final ByteBuffer buffer)
{
- this.gmtUnixTime = gmtUnixTime;
- this.randomBytes = (byte[]) randomBytes.clone();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
- // Class methods.
- // -------------------------------------------------------------------------
+ public Random copy()
+ {
+ ByteBuffer buffer = ByteBuffer.allocate(32);
+ buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
+ return new Random(buffer);
+ }
- static Random read(InputStream in) throws IOException
+ public int length()
{
- int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16
- | (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- byte[] buf = new byte[28];
- in.read(buf);
- return new Random(time, buf);
+ return RANDOM_LENGTH + 4;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ public int gmtUnixTime ()
+ {
+ return buffer.getInt(0);
+ }
- public void write(OutputStream out) throws IOException
+ public byte[] randomBytes()
{
- out.write((gmtUnixTime >>> 24) & 0xFF);
- out.write((gmtUnixTime >>> 16) & 0xFF);
- out.write((gmtUnixTime >>> 8) & 0xFF);
- out.write(gmtUnixTime & 0xFF);
- out.write(randomBytes);
+ byte[] buf = new byte[28];
+ buffer.position (4);
+ buffer.get (buf);
+ return buf;
}
- byte[] getEncoded()
+ public void setGmtUnixTime (final int gmtUnixTime)
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream(32);
- try
- {
- write(bout);
- }
- catch (IOException cantHappen)
- {
- throw new Error(cantHappen.toString());
- }
- return bout.toByteArray();
+ buffer.putInt (0, gmtUnixTime);
}
- int getTime()
+ public void setRandomBytes (final byte[] randomBytes)
{
- return gmtUnixTime;
+ setRandomBytes (randomBytes, 0);
}
- byte[] getRandomBytes()
+ public void setRandomBytes (final byte[] randomBytes, final int offset)
{
- return randomBytes;
+ 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()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
out.println("struct {");
- out.println(" gmt_unix_time = " + gmtUnixTime + ";");
- out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";");
- out.println("} Random;");
+ 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);
+ }
}
diff --git a/gnu/javax/net/ssl/provider/Record.java b/gnu/javax/net/ssl/provider/Record.java
new file mode 100644
index 000000000..6f5a23ef4
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/Record.java
@@ -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 ();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/RecordInput.java b/gnu/javax/net/ssl/provider/RecordInput.java
deleted file mode 100644
index d4ba5b596..000000000
--- a/gnu/javax/net/ssl/provider/RecordInput.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/* RecordInput.java -- record layer input.
- 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.SystemProperties;
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import java.util.logging.Logger;
-
-import javax.net.ssl.SSLProtocolException;
-
-class RecordInput
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = true;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- private byte[] fragment;
- private int index;
- private ContentType type;
-
- private final DataInputStream in;
- private Session session;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordInput (final InputStream in, final Session session)
- {
- this.in = new DataInputStream (in);
- this.session = session;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- synchronized int available (ContentType type) throws IOException
- {
- if (fragment == null)
- {
- readRecord ();
- }
- if (type != this.type)
- {
- return 0;
- }
- return fragment.length - index;
- }
-
- void setSession (Session session)
- {
- this.session = session;
- }
-
- synchronized int read (byte[] buf, int off, int len, ContentType type)
- throws IOException
- {
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
- " off=" + off + " len=" + len);
- }
- if (fragment == null || index >= fragment.length)
- {
- readRecord ();
- }
- if (type != this.type)
- {
- return 0;
- }
- len = Math.min (len, fragment.length - index);
- System.arraycopy (fragment, index, buf, off, len);
- index += len;
- return len;
- }
-
- boolean pollClose () throws IOException
- {
- if (fragment == null || index >= fragment.length)
- {
- try
- {
- readRecord();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert();
- if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY)
- {
- return true;
- }
- throw ae;
- }
- }
- return false;
- }
-
- private void readRecord() throws IOException
- {
- type = ContentType.read (in);
- if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0)
- {
- in.read();
- if ((type.getValue() & 0x40) != 0)
- {
- in.read();
- }
- type = ContentType.read(in);
- if (type != ContentType.CLIENT_HELLO_V2)
- {
- throw new SSLProtocolException("unsupported V2 message");
- }
- type = ContentType.HANDSHAKE;
- // Record this message, and re-present it as a normal handshake
- // layer message. ClientHello will handle the real parsing.
- ByteArrayOutputStream buffer = new ByteArrayOutputStream (256);
- buffer.write(1); // The type we just read.
- RecordingInputStream in2 = new RecordingInputStream (in, buffer);
- ProtocolVersion version = ProtocolVersion.read (in2);
- if (version.compareTo (ProtocolVersion.SSL_3) < 0)
- {
- throw new SSLProtocolException("unsupported client version");
- }
- int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- int l = (int) in2.skip(len - count);
- if (l > 0)
- {
- count += l;
- }
- }
- fragment = buffer.toByteArray ();
- index = 0;
-
- // We can't be encrypted/MACed/compressed here, since a V2 message
- // will only be sent as the first message, and only by the client.
- return;
- }
- ProtocolVersion v = ProtocolVersion.read (in);
- int len = in.readUnsignedShort ();
- if (len > session.params.getFragmentLength() + 2048)
- {
- throw new OverflowException();
- }
- fragment = new byte [len];
- in.readFully (fragment);
-
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> READ RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, v, new Integer (len),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
-
- fragment = session.params.decrypt (fragment, v, type);
- index = 0;
-
- if (session.random != null)
- session.random.setSeed (fragment);
-
- if (type == ContentType.ALERT)
- {
- Alert alert = Alert.read (new ByteArrayInputStream (fragment));
- session.currentAlert = alert;
- }
- if (session.currentAlert != null)
- {
- throw new AlertException (session.currentAlert, false);
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/RecordOutputStream.java b/gnu/javax/net/ssl/provider/RecordOutputStream.java
deleted file mode 100644
index 3bf228f2d..000000000
--- a/gnu/javax/net/ssl/provider/RecordOutputStream.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/* RecordOutputStream.java -- record layer output.
- 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.SystemProperties;
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import java.util.logging.Logger;
-
-/**
- * An output stream for writing data to the record layer. All data written
- * to this stream (through any of the write methods) is immediately sent
- * as a full record, so it is advisable to write large arrays to the stream
- * instead of one byte at a time (alternatively, a {@link
- * java.io.BufferedOutputStream} can be used).
- */
-class RecordOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = true;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- /**
- * The content type of this output stream.
- */
- private final ContentType type;
-
- /**
- * The security parameters.
- */
- private final SecurityParameters params;
-
- private final boolean emitEmpty;
-
- private static final byte[] ZERO = new byte[0];
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordOutputStream (final OutputStream out, final ContentType type,
- final SecurityParameters params)
- {
- super (out);
- this.type = type;
- this.params = params;
- String empty = Util.getSecurityProperty ("jessie.emit.empty.records");
- if (empty == null)
- {
- // IE panics if it gets an empty record; so, leave this false
- // for the default.
- empty = "false";
- }
- emitEmpty = Boolean.valueOf (empty).booleanValue () &&
- type == ContentType.APPLICATION_DATA;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write (int b) throws IOException
- {
- write (new byte[] { (byte) b });
- }
-
- public void write (byte[] buf) throws IOException
- {
- write (buf, 0, buf.length);
- }
-
- public void write (byte[] buf, int off, int len) throws IOException
- {
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
- " off=" + off + " len=" + len);
- }
-
- int count = 0;
- int len2 = 0;
- do
- {
- if (emitEmpty)
- {
- byte[] fragment = params.encrypt (ZERO, 0, 0, type);
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> WRITING RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, params.getVersion (), new Integer (fragment.length),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
- out.write (type.getValue());
- params.getVersion().write (out);
- out.write ((fragment.length >>> 8) & 0xFF);
- out.write ( fragment.length & 0xFF);
- out.write (fragment);
- out.flush ();
- }
- len2 = Math.min (len - count, params.getFragmentLength());
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- "writing chunk size={0}", new Integer (len2));
- }
- synchronized (out)
- {
- byte[] fragment = params.encrypt (buf, off + count, len2, type);
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> WRITING RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, params.getVersion (), new Integer (fragment.length),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
- out.write (type.getValue());
- params.getVersion().write (out);
- out.write ((fragment.length >>> 8) & 0xFF);
- out.write ( fragment.length & 0xFF);
- out.write (fragment);
- out.flush ();
- }
- count += len2;
- }
- while (count < len);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/RecordingInputStream.java b/gnu/javax/net/ssl/provider/RecordingInputStream.java
deleted file mode 100644
index d81b652d5..000000000
--- a/gnu/javax/net/ssl/provider/RecordingInputStream.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* RecordingInputStream.java -- Input stream that records data.
- 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.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * A filter input stream that records every byte read from the underlying
- * input stream. This class is useful for protocols that require portions
- * of the communication to be saved, such as the handshake and key
- * derivation in SSL.
- *
- * @author Casey Marshall (rsdio@metastatic.org)
- */
-class RecordingInputStream extends FilterInputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- protected ByteArrayOutputStream sink;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- RecordingInputStream(InputStream in)
- {
- this(in, new ByteArrayOutputStream());
- }
-
- RecordingInputStream(InputStream in, ByteArrayOutputStream sink)
- {
- super(in);
- this.sink = sink;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized int read() throws IOException
- {
- int i = in.read();
- sink.write(i);
- return i;
- }
-
- public synchronized int read(byte[] buf, int off, int len) throws IOException
- {
- int l = in.read(buf, off, len);
- sink.write(buf, off, l);
- return l;
- }
-
- public synchronized int read(byte[] buf) throws IOException
- {
- return read(buf, 0, buf.length);
- }
-
- public synchronized long skip(long len) throws IOException
- {
- long l = 0;
- int i = 0;
- byte[] buf = new byte[1024];
- while (l < len)
- {
- i = read(buf, 0, (int) Math.min((long) buf.length, len - l));
- if (i == -1)
- break;
- l += i;
- }
- return l;
- }
-
- /**
- * Returns all bytes recorded after this instance was created, or the last
- * call to {@link resetSink()}.
- *
- * @return The recorded bytes.
- */
- byte[] getBytes()
- {
- return sink.toByteArray();
- }
-
- /**
- * Clears the recording buffer off all previously-recorded bytes.
- */
- void resetSink()
- {
- sink.reset();
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLContextImpl.java b/gnu/javax/net/ssl/provider/SSLContextImpl.java
new file mode 100644
index 000000000..cf7c8e4e3
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLContextImpl.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/gnu/javax/net/ssl/provider/SSLEngineImpl.java
new file mode 100644
index 000000000..22c488d68
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLEngineImpl.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/SSLRSASignature.java b/gnu/javax/net/ssl/provider/SSLRSASignature.java
deleted file mode 100644
index 2f8c6cfe6..000000000
--- a/gnu/javax/net/ssl/provider/SSLRSASignature.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/* SSLRSASignature.java -- SSL's RSA signature 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.math.BigInteger;
-
-import java.security.InvalidKeyException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import gnu.java.security.hash.HashFactory;
-import gnu.java.security.hash.IMessageDigest;
-import gnu.java.security.sig.ISignature;
-import gnu.java.security.sig.rsa.RSA;
-
-/**
- * The RSA signature algorithm as used in the SSL protocol. Note that this
- * is different from the RSA signature used to verify certificates.
- *
- * <p>This signature scheme works as follows:</p>
- *
- * <blockquote><p><pre>digitally-signed struct {
- * opaque md5_hash[16];
- * opaque sha_hash[20];
- * }</pre></p></blockquote>
- *
- * <p>Where a <code>digitally-signed struct</code> is RSA-encrypted with
- * block type 0 or 1 according to PKCS #1, version 1.5.</p>
- */
-final class SSLRSASignature implements ISignature
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private RSAPublicKey pubkey;
- private RSAPrivateKey privkey;
- private final IMessageDigest md5, sha;
- private boolean initVerify = false, initSign = false;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLRSASignature()
- {
- this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1"));
- }
-
- SSLRSASignature(IMessageDigest md5, IMessageDigest sha)
- {
- this.md5 = md5;
- this.sha = sha;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String name()
- {
- return "RSA/SSL";
- }
-
- public void setupVerify(Map attrib)
- {
- PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY);
- if (key == null)
- {
- if (initSign)
- {
- return; // re-use.
- }
- throw new IllegalArgumentException("no key supplied");
- }
- if (!(key instanceof RSAPublicKey))
- {
- throw new IllegalArgumentException("not an RSA key");
- }
- pubkey = (RSAPublicKey) key;
- privkey = null;
- initSign = false;
- initVerify = true;
- }
-
- public void setupSign(Map attrib)
- {
- PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY);
- if (key == null)
- {
- if (initVerify)
- {
- return; // re-use.
- }
- throw new IllegalArgumentException("no key supplied");
- }
- if (!(key instanceof RSAPrivateKey))
- {
- throw new IllegalArgumentException("not an RSA key");
- }
- privkey = (RSAPrivateKey) key;
- pubkey = null;
- initVerify = false;
- initSign = true;
- }
-
- public void update(byte b)
- {
- if (!initVerify && !initSign)
- {
- throw new IllegalStateException();
- }
- md5.update(b);
- sha.update(b);
- }
-
- public void update(byte[] buf, int off, int len)
- {
- if (!initVerify && !initSign)
- {
- throw new IllegalStateException();
- }
- md5.update(buf, off, len);
- sha.update(buf, off, len);
- }
-
- public Object sign()
- {
- if (!initSign)
- {
- throw new IllegalStateException();
- }
- // 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 IllegalArgumentException("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);
- }
-
- public boolean verify(Object signature)
- {
- if (!initVerify)
- {
- throw new IllegalStateException();
- }
- // Public-key decrypt the signature representative.
- BigInteger EM = new BigInteger(1, (byte[]) signature);
- 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 IllegalArgumentException("bad padding");
- }
- }
- i++;
- }
- else
- {
- throw new IllegalArgumentException("decryption failed");
- }
- byte[] d1 = Util.trim(eb, i, eb.length - i);
- byte[] d2 = Util.concat(md5.digest(), sha.digest());
- return Arrays.equals(d1, d2);
- }
-
- public Object clone()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java b/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
new file mode 100644
index 000000000..415efc6f5
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
@@ -0,0 +1,233 @@
+/* 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");
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLServerSocket.java b/gnu/javax/net/ssl/provider/SSLServerSocket.java
deleted file mode 100644
index ee96b8d1b..000000000
--- a/gnu/javax/net/ssl/provider/SSLServerSocket.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SSLServerSocket.java -- SSL server 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 java.io.IOException;
-
-import java.net.InetAddress;
-import java.net.Socket;
-
-import java.security.SecureRandom;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-class SSLServerSocket extends javax.net.ssl.SSLServerSocket
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private SessionContext sessions;
- private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- private List enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- private boolean clientMode = false;
- private boolean needClientAuth = false;
- private boolean wantClientAuth = false;
- private boolean createSessions = true;
- private SRPTrustManager srpTrustManager;
- private X509TrustManager trustManager;
- private X509KeyManager keyManager;
- private SecureRandom random;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLServerSocket() throws IOException
- {
- super();
- }
-
- SSLServerSocket(int port) throws IOException
- {
- super(port);
- }
-
- SSLServerSocket(int port, int backlog) throws IOException
- {
- super(port, backlog);
- }
-
- SSLServerSocket(int port, int backlog, InetAddress address)
- throws IOException
- {
- super(port, backlog, address);
- }
-
- // SSL methods.
- // -------------------------------------------------------------------------
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public String[] getEnabledCipherSuites()
- {
- synchronized (enabledSuites)
- {
- String[] s = new String[enabledSuites.size()];
- int i = 0;
- for (Iterator it = enabledSuites.iterator(); it.hasNext(); )
- s[i++] = it.next().toString();
- return s;
- }
- }
-
- public void setEnabledCipherSuites(String[] suites)
- {
- if (suites == null || suites.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < suites.length; i++)
- if (CipherSuite.forName(suites[i]) == null)
- throw new IllegalArgumentException("unsupported suite: " +
- suites[i]);
- synchronized (enabledSuites)
- {
- enabledSuites.clear();
- for (int i = 0; i < suites.length; i++)
- {
- CipherSuite suite = CipherSuite.forName(suites[i]);
- if (!enabledSuites.contains(suite))
- enabledSuites.add(suite);
- }
- }
- }
-
- public String[] getSupportedProtocols()
- {
- return new String[] { "SSLv3", "TLSv1", "TLSv1.1" };
- }
-
- public String[] getEnabledProtocols()
- {
- synchronized (enabledProtocols)
- {
- String[] s = new String[enabledProtocols.size()];
- int i = 0;
- for (Iterator it = enabledProtocols.iterator(); it.hasNext(); )
- s[i++] = it.next().toString();
- return s;
- }
- }
-
- public void setEnabledProtocols(String[] protocols)
- {
- if (protocols == null || protocols.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < protocols.length; i++)
- {
- if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
- protocols[i].equalsIgnoreCase("TLSv1") ||
- protocols[i].equalsIgnoreCase("TLSv1.1")))
- {
- throw new
- IllegalArgumentException("unsupported protocol: " +
- protocols[i]);
- }
- }
- synchronized (enabledProtocols)
- {
- enabledProtocols.clear();
- for (int i = 0; i < protocols.length; i++)
- {
- if (protocols[i].equalsIgnoreCase("SSLv3"))
- enabledProtocols.add(ProtocolVersion.SSL_3);
- else if (protocols[i].equalsIgnoreCase("TLSv1"))
- enabledProtocols.add(ProtocolVersion.TLS_1);
- else
- enabledProtocols.add(ProtocolVersion.TLS_1_1);
- }
- }
- }
-
- public void setUseClientMode(boolean clientMode)
- {
- this.clientMode = clientMode;
- }
-
- public boolean getUseClientMode()
- {
- return clientMode;
- }
-
- public void setNeedClientAuth(boolean needClientAuth)
- {
- this.needClientAuth = needClientAuth;
- }
-
- public boolean getNeedClientAuth()
- {
- return needClientAuth;
- }
-
- public void setWantClientAuth(boolean wantClientAuth)
- {
- this.wantClientAuth = wantClientAuth;
- }
-
- public boolean getWantClientAuth()
- {
- return wantClientAuth;
- }
-
- // I misspelled this method in javax.net.SSLServerSocket, and that version
- // made it into kaffe 1.1.4.
- public void setEnabledSessionCreation(boolean createSessions)
- {
- setEnableSessionCreation(createSessions);
- }
-
- public void setEnableSessionCreation(boolean createSessions)
- {
- this.createSessions = createSessions;
- }
-
- public boolean getEnableSessionCreation()
- {
- return createSessions;
- }
-
- // Socket methods.
- // -------------------------------------------------------------------------
-
- public Socket accept() throws IOException
- {
- SSLSocket socket = new SSLSocket();
- implAccept(socket);
- socket.setUseClientMode(clientMode);
- socket.setNeedClientAuth(needClientAuth);
- socket.setWantClientAuth(wantClientAuth);
- socket.setEnableSessionCreation(createSessions);
- socket.setSessionContext(sessions);
- socket.setEnabledCipherSuites(new ArrayList(enabledSuites));
- socket.setEnabledProtocols(new TreeSet(enabledProtocols));
- socket.setSRPTrustManager(srpTrustManager);
- socket.setTrustManager(trustManager);
- socket.setKeyManager(keyManager);
- socket.setRandom(random);
- return socket;
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- void setSessionContext(SessionContext sessions)
- {
- this.sessions = sessions;
- }
-
- void setKeyManager(X509KeyManager keyManager)
- {
- this.keyManager = keyManager;
- }
-
- void setTrustManager(X509TrustManager trustManager)
- {
- this.trustManager = trustManager;
- }
-
- void setSRPTrustManager(SRPTrustManager srpTrustManager)
- {
- this.srpTrustManager = srpTrustManager;
- }
-
- void setRandom(SecureRandom random)
- {
- this.random = random;
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
deleted file mode 100644
index 72fb512c5..000000000
--- a/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/* SSLServerSocketFactory.java -- factory for SSL server sockets.
- 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.ServerSocket;
-
-import java.security.SecureRandom;
-
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SessionContext sessions;
- private final X509KeyManager keyManager;
- private final X509TrustManager trustManager;
- private final SRPTrustManager srpTrustManager;
- private final SecureRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLServerSocketFactory(X509TrustManager trustManager,
- SRPTrustManager srpTrustManager,
- X509KeyManager keyManager,
- SecureRandom random,
- SessionContext sessions)
- {
- super();
- this.trustManager = trustManager;
- this.srpTrustManager = srpTrustManager;
- this.keyManager = keyManager;
- this.random = random;
- this.sessions = sessions;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String[] getDefaultCipherSuites()
- {
- return getSupportedCipherSuites();
- }
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public ServerSocket createServerSocket() throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket();
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port) throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port);
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port, int backlog)
- throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port, backlog);
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port, int backlog, InetAddress addr)
- throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port, backlog, addr);
- setup(socket);
- return socket;
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private void setup(SSLServerSocket socket)
- {
- socket.setSessionContext(sessions);
- socket.setKeyManager(keyManager);
- socket.setTrustManager(trustManager);
- socket.setSRPTrustManager(srpTrustManager);
- socket.setRandom(random);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java b/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
new file mode 100644
index 000000000..dc80dc782
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java b/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
new file mode 100644
index 000000000..41ef5f1cf
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLSocket.java b/gnu/javax/net/ssl/provider/SSLSocket.java
deleted file mode 100644
index a564659c0..000000000
--- a/gnu/javax/net/ssl/provider/SSLSocket.java
+++ /dev/null
@@ -1,3530 +0,0 @@
-/* SSLSocket.java -- the SSL socket class.
- 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.BufferedOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import java.math.BigInteger;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-
-import java.nio.channels.SocketChannel;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SecureRandom;
-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.Arrays;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import java.util.logging.Logger;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import javax.net.ssl.HandshakeCompletedEvent;
-import javax.net.ssl.HandshakeCompletedListener;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLProtocolException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.ConfirmationCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextInputCallback;
-
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import gnu.java.security.Registry;
-import gnu.javax.security.auth.callback.DefaultCallbackHandler;
-import gnu.java.security.hash.HashFactory;
-import gnu.java.security.hash.IMessageDigest;
-import gnu.javax.crypto.key.IKeyAgreementParty;
-import gnu.javax.crypto.key.KeyAgreementFactory;
-import gnu.javax.crypto.key.KeyAgreementException;
-import gnu.javax.crypto.key.OutgoingMessage;
-import gnu.javax.crypto.key.IncomingMessage;
-import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement;
-import gnu.javax.crypto.key.dh.ElGamalKeyAgreement;
-import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
-import gnu.javax.crypto.key.dh.GnuDHPublicKey;
-import gnu.javax.crypto.key.srp6.SRPPrivateKey;
-import gnu.javax.crypto.key.srp6.SRPPublicKey;
-import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.prng.ARCFour;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
-import gnu.javax.crypto.sasl.srp.SRPRegistry;
-import gnu.java.security.sig.ISignature;
-import gnu.java.security.sig.SignatureFactory;
-import gnu.java.security.sig.dss.DSSSignature;
-import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
-import gnu.java.security.sig.rsa.RSA;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-/**
- * This is the core of the Jessie SSL implementation; it implements the {@link
- * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all
- * protocols implemented by this library.
- */
-final class SSLSocket extends javax.net.ssl.SSLSocket
-{
-
- // This class is almost unbearably large and complex, but is laid out
- // as follows:
- //
- // 1. Fields.
- // 2. Constructors.
- // 3. SSLSocket methods. These are the public methods defined in
- // javax.net.ssl.SSLSocket.
- // 4. Socket methods. These override the public methods of java.net.Socket,
- // and delegate the method call to either the underlying socket if this is
- // a wrapped socket, or to the superclass.
- // 5. Package-private methods that various pieces of Jessie use.
- // 6. Private methods. These compose the SSL handshake.
- //
- // Each part is preceeded by a form feed.
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- // Debuggery.
- private static final boolean DEBUG_HANDSHAKE_LAYER = true;
- private static final boolean DEBUG_KEY_EXCHANGE = false;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- // Fields for using this class as a wrapped socket.
- private Socket underlyingSocket;
- private int underlyingPort;
- private boolean autoClose;
-
- // Cryptography fields.
- SessionContext sessionContext;
- Session session;
- LinkedList handshakeListeners;
- private boolean clientMode, wantClientAuth, needClientAuth, createSessions;
- private boolean handshakeDone;
-
- // I/O fields.
- private String remoteHost;
- private InputStream socketIn;
- private OutputStream socketOut;
- private InputStream applicationIn;
- private OutputStream applicationOut;
- private InputStream handshakeIn;
- private OutputStream handshakeOut;
-// private ThreadGroup recordLayer;
- RecordInput recordInput;
-// RecordOutput recordOutput;
- private long handshakeTime;
-
- private SocketChannel channel;
-
- static SortedSet supportedProtocols = new TreeSet();
- static List supportedSuites = new ArrayList(30);
-
- // Static initializer.
- // -------------------------------------------------------------------------
-
- static
- {
- //supportedProtocols.add(ProtocolVersion.TLS_1_1);
- supportedProtocols.add(ProtocolVersion.TLS_1);
- supportedProtocols.add(ProtocolVersion.SSL_3);
-
- // These are in preference order. It's my preference order, but I'm not
- // a total idiot.
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA);
- }
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLSocket(Socket socket, String host, int port, boolean autoClose)
- throws IOException
- {
- underlyingSocket = socket;
- remoteHost = host;
- underlyingPort = port;
- this.autoClose = autoClose;
- initialize();
- }
-
- SSLSocket (Socket socket, SocketChannel channel) throws IOException
- {
- underlyingSocket = socket;
- this.channel = channel;
- initialize ();
- }
-
- SSLSocket() throws IOException
- {
- super();
- initialize();
- }
-
- SSLSocket(InetAddress addr, int port) throws IOException
- {
- super(addr, port);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- {
- remoteHost = addr.getHostAddress();
- }
- }
-
- SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(addr, port, laddr, lport);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- remoteHost = addr.getHostAddress();
- }
-
- SSLSocket(String host, int port) throws IOException
- {
- super(host, port);
- initialize();
- remoteHost = host;
- }
-
- SSLSocket(String host, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(host, port, laddr, lport);
- initialize();
- remoteHost = host;
- }
-
- private void initialize()
- {
- session = new Session();
- session.enabledSuites = new ArrayList(supportedSuites);
- session.enabledProtocols = new TreeSet(supportedProtocols);
- session.protocol = ProtocolVersion.TLS_1;
- session.params.setVersion (ProtocolVersion.TLS_1);
- handshakeListeners = new LinkedList();
- handshakeDone = false;
- }
-
- // SSL methods.
- // -------------------------------------------------------------------------
-
- public void addHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- if (l == null)
- throw new NullPointerException();
- if (!handshakeListeners.contains(l))
- handshakeListeners.add(l);
- }
- }
-
- public void removeHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- handshakeListeners.remove(l);
- }
- }
-
- public String[] getEnabledProtocols()
- {
- synchronized (session.enabledProtocols)
- {
- try
- {
- return (String[]) Util.transform(session.enabledProtocols.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledProtocols(String[] protocols)
- {
- if (protocols == null || protocols.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < protocols.length; i++)
- {
- if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
- protocols[i].equalsIgnoreCase("TLSv1") ||
- protocols[i].equalsIgnoreCase("TLSv1.1")))
- {
- throw new
- IllegalArgumentException("unsupported protocol: " +
- protocols[i]);
- }
- }
- synchronized (session.enabledProtocols)
- {
- session.enabledProtocols.clear();
- for (int i = 0; i < protocols.length; i++)
- {
- if (protocols[i].equalsIgnoreCase("SSLv3"))
- {
- session.enabledProtocols.add(ProtocolVersion.SSL_3);
- }
- else if (protocols[i].equalsIgnoreCase("TLSv1"))
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1);
- }
- else
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1_1);
- }
- }
- }
- }
-
- public String[] getSupportedProtocols()
- {
- return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" };
- }
-
- public String[] getEnabledCipherSuites()
- {
- synchronized (session.enabledSuites)
- {
- try
- {
- return (String[]) Util.transform(session.enabledSuites.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledCipherSuites(String[] suites)
- {
- if (suites == null || suites.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < suites.length; i++)
- if (CipherSuite.forName(suites[i]) == null)
- throw new IllegalArgumentException("unsupported suite: " +
- suites[i]);
- synchronized (session.enabledSuites)
- {
- session.enabledSuites.clear();
- for (int i = 0; i < suites.length; i++)
- {
- CipherSuite suite = CipherSuite.forName(suites[i]);
- if (!session.enabledSuites.contains(suite))
- {
- session.enabledSuites.add(suite);
- }
- }
- }
- }
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]);
- }
-
- public SSLSession getSession()
- {
- return session;
- }
-
- public boolean getEnableSessionCreation()
- {
- return createSessions;
- }
-
- public void setEnableSessionCreation(boolean flag)
- {
- createSessions = flag;
- }
-
- public boolean getNeedClientAuth()
- {
- return needClientAuth;
- }
-
- public void setNeedClientAuth(boolean flag)
- {
- needClientAuth = flag;
- }
-
- public boolean getWantClientAuth()
- {
- return wantClientAuth;
- }
-
- public void setWantClientAuth(boolean flag)
- {
- wantClientAuth = flag;
- }
-
- public boolean getUseClientMode()
- {
- return clientMode;
- }
-
- public void setUseClientMode(boolean flag)
- {
- this.clientMode = flag;
- }
-
- public synchronized void startHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis();
- }
- if (handshakeDone)
- {
- if (clientMode)
- {
- handshakeDone = false;
- doClientHandshake();
- }
- else
- {
- Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null);
- req.write (handshakeOut, session.protocol);
- handshakeOut.flush();
-// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol));
- }
- return;
- }
- if (recordInput == null)
- {
- setupIO();
- }
- if (clientMode)
- {
- doClientHandshake();
- }
- else
- {
- doServerHandshake();
- }
- }
-
- // Socket methods.
- // -------------------------------------------------------------------------
-
- public InetAddress getInetAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getInetAddress();
- }
- else
- {
- return super.getInetAddress();
- }
- }
-
- public InetAddress getLocalAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalAddress();
- }
- else
- {
- return super.getLocalAddress();
- }
- }
-
- public int getPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getPort();
- }
- else
- {
- return super.getPort();
- }
- }
-
- public int getLocalPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalPort();
- }
- else
- {
- return super.getLocalPort();
- }
- }
-
- public InputStream getInputStream() throws IOException
- {
- if (applicationIn == null)
- {
- setupIO();
- }
- return applicationIn;
- }
-
- public OutputStream getOutputStream() throws IOException
- {
- if (applicationOut == null)
- {
- setupIO();
- }
- return applicationOut;
- }
-
- public void setTcpNoDelay(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setTcpNoDelay(flag);
- }
- else
- {
- super.setTcpNoDelay(flag);
- }
- }
-
- public boolean getTcpNoDelay() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getTcpNoDelay();
- }
- else
- {
- return super.getTcpNoDelay();
- }
- }
-
- public void setSoLinger(boolean flag, int linger) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoLinger(flag, linger);
- }
- else
- {
- super.setSoLinger(flag, linger);
- }
- }
-
- public int getSoLinger() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoLinger();
- }
- else
- {
- return super.getSoLinger();
- }
- }
-
- public void sendUrgentData(int data) throws IOException
- {
- throw new UnsupportedOperationException("not implemented");
- }
-
- public void setSoTimeout(int timeout) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoTimeout(timeout);
- }
- else
- {
- super.setSoTimeout(timeout);
- }
- }
-
- public int getSoTimeout() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoTimeout();
- }
- else
- {
- return super.getSoTimeout();
- }
- }
-
- public void setSendBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSendBufferSize(size);
- }
- else
- {
- super.setSendBufferSize(size);
- }
- }
-
- public int getSendBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSendBufferSize();
- }
- else
- {
- return super.getSendBufferSize();
- }
- }
-
- public void setReceiveBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setReceiveBufferSize(size);
- }
- else
- {
- super.setReceiveBufferSize(size);
- }
- }
-
- public int getReceiveBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getReceiveBufferSize();
- }
- else
- {
- return super.getReceiveBufferSize();
- }
- }
-
- public synchronized void close() throws IOException
- {
- if (recordInput == null)
- {
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- return;
- }
-// while (recordOutput.applicationDataPending()) Thread.yield();
- Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
- sendAlert (close);
- long wait = System.currentTimeMillis() + 60000L;
- while (session.currentAlert == null && !recordInput.pollClose())
- {
-
- Thread.yield();
- if (wait <= System.currentTimeMillis())
- {
- break;
- }
- }
- boolean gotClose = session.currentAlert != null &&
- session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY;
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
-// recordLayer.interrupt();
- recordInput = null;
-// recordOutput = null;
-// recordLayer = null;
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- if (!gotClose)
- {
- session.invalidate();
- throw new SSLException("did not receive close notify");
- }
- }
-
- public String toString()
- {
- if (underlyingSocket != null)
- {
- return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]";
- }
- else
- {
- return SSLSocket.class.getName() + " [ " + super.toString() + " ]";
- }
- }
-
- // Configuration insanity begins here.
-
- public void connect(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr);
- }
- else
- {
- super.connect(saddr);
- }
- }
-
- public void connect(SocketAddress saddr, int timeout) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr, timeout);
- }
- else
- {
- super.connect(saddr, timeout);
- }
- }
-
- public void bind(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.bind(saddr);
- }
- else
- {
- super.bind(saddr);
- }
- }
-
- public SocketAddress getLocalSocketAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalSocketAddress();
- }
- else
- {
- return super.getLocalSocketAddress();
- }
- }
-
- public SocketChannel getChannel()
- {
- return channel;
- }
-
- public boolean isBound()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isBound();
- }
- else
- {
- return super.isBound();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isClosed()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isClosed();
- }
- else
- {
- return super.isClosed();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- //public SocketAddress getRemoteSocketAddress()
- //{
- // if (underlyingSocket != null)
- // {
- // return underlyingSocket.getRemoteSocketAddress();
- // }
- // else
- // {
- // return super.getRemoteSocketAddress();
- // }
- //}
-
- public void setOOBInline(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setOOBInline(flag);
- // }
- //else
- // {
- // super.setOOBInline(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getOOBInline() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getOOBInline();
- // }
- //else
- // {
- // return super.getOOBInline();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setKeepAlive(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setKeepAlive(flag);
- // }
- //else
- // {
- // super.setKeepAlive(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getKeepAlive() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getKeepAlive();
- // }
- //else
- // {
- // return super.getKeepAlive();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setTrafficClass(int clazz) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setTrafficClass(clazz);
- // }
- //else
- // {
- // super.setTrafficClass(clazz);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public int getTrafficClass() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getTrafficClass();
- // }
- //else
- // {
- // return super.getTrafficClass();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setReuseAddress(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setReuseAddress(flag);
- // }
- //else
- // {
- // super.setReuseAddress(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getReuseAddress() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getReuseAddress();
- // }
- //else
- // {
- // return super.getReuseAddress();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void shutdownInput() throws IOException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.shutdownInput();
- // }
- //else
- // {
- // super.shutdownInput();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void shutdownOutput() throws IOException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.shutdownOutput();
- // }
- //else
- // {
- // super.shutdownOutput();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isConnected()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isConnected();
- }
- else
- {
- return super.isConnected();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isInputShutdown()
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.isInputShutdown();
- // }
- //else
- // {
- // return super.isInputShutdown();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isOutputShutdown()
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.isOutputShutdown();
- // }
- //else
- // {
- // return super.isOutputShutdown();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- protected void finalize()
- {
- if (session.currentAlert == null)
- {
- try
- {
- close();
- }
- catch (Exception ignore) { }
- }
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- void setSessionContext(SessionContext sessionContext)
- {
- this.sessionContext = sessionContext;
- }
-
- void setEnabledCipherSuites(List suites)
- {
- session.enabledSuites = suites;
- }
-
- void setEnabledProtocols(SortedSet protocols)
- {
- session.enabledProtocols = protocols;
- }
-
- void setSRPTrustManager(SRPTrustManager srpTrustManager)
- {
- session.srpTrustManager = srpTrustManager;
- }
-
- void setTrustManager(X509TrustManager trustManager)
- {
- session.trustManager = trustManager;
- }
-
- void setKeyManager(X509KeyManager keyManager)
- {
- session.keyManager = keyManager;
- }
-
- void setRandom(SecureRandom random)
- {
- session.random = random;
- }
-
- void sendAlert (Alert alert) throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.ALERT, session.params);
- out.write (alert.getEncoded ());
- }
-
- /**
- * Gets the most-recently-received alert message.
- *
- * @return The alert message.
- */
- Alert checkAlert()
- {
- return session.currentAlert;
- }
-
- synchronized void checkHandshakeDone() throws IOException
- {
- if (!handshakeDone)
- {
- startHandshake();
- }
- Alert alert = session.currentAlert;
- if (alert != null && alert.getLevel() == Alert.Level.FATAL)
- {
- throw new AlertException(alert, false);
- }
- if (handshakeIn.available() > 0 && !clientMode)
- {
- handshakeDone = false;
- startHandshake();
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private static final byte[] SENDER_CLIENT =
- new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
- private static final byte[] SENDER_SERVER =
- new byte[] { 0x53, 0x52, 0x56, 0x52 };
-
- private void changeCipherSpec () throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params);
- out.write (1);
- }
-
- private void readChangeCipherSpec () throws IOException
- {
- RecordInputStream in =
- new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC);
- if (in.read() != 1)
- {
- throw new SSLProtocolException ("bad change cipher spec message");
- }
- }
-
- /**
- * Initializes the application data streams and starts the record layer
- * threads.
- */
- private synchronized void setupIO() throws IOException
- {
- if (recordInput != null)
- {
- return;
- }
- if (underlyingSocket != null)
- {
- socketIn = underlyingSocket.getInputStream();
- socketOut = underlyingSocket.getOutputStream();
- }
- else
- {
- socketIn = super.getInputStream();
- socketOut = super.getOutputStream();
- }
-// recordLayer = new ThreadGroup("record_layer");
-// recordInput = new RecordInput(in, session, recordLayer);
-// recordOutput = new RecordOutput(out, session, recordLayer);
-// recordInput.setRecordOutput(recordOutput);
-// recordLayer.setDaemon(true);
-// recordInput.start();
-// recordOutput.start();
- recordInput = new RecordInput (socketIn, session);
- applicationIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this);
- applicationOut = new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this);
- handshakeIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false);
- handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096);
- }
-
- private void handshakeCompleted ()
- {
- handshakeDone = true;
- HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session);
- for (Iterator it = handshakeListeners.iterator (); it.hasNext (); )
- {
- try
- {
- ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event);
- }
- catch (Throwable t) { }
- }
- if (createSessions)
- {
- synchronized (session)
- {
- sessionContext.addSession (session.sessionId, session);
- session.access ();
- }
- }
-
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis() - handshakeTime;
- logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s",
- new Long (handshakeTime / 1000));
- }
- }
-
- /*
- * Perform the client handshake. The process looks like this:
- *
- * ClientHello -->
- * ServerHello <--
- * Certificate* <--
- * ServerKeyExchange* <--
- * CertificateRequest* <--
- * ServerHelloDone* <--
- * Certificate* -->
- * ClientKeyExchange -->
- * CertificateVerify* -->
- * [ChangeCipherSpec] -->
- * Finished -->
- * [ChangeCipherSpec] <--
- * Finished <--
- *
- * With --> denoting output and <-- denoting input. * denotes optional
- * messages.
- *
- * Alternatively, this may be an abbreviated handshake if we are resuming
- * a session:
- *
- * ClientHello -->
- * ServerHello <--
- * [ChangeCipherSpec] <--
- * Finished <--
- * [ChangeCipherSpec] -->
- * Finished -->
- */
- private void doClientHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}",
- Thread.currentThread());
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
- Session continuedSession = null;
- byte[] sessionId = new byte[0];
- List extensions = null;
- String user = null;
- CertificateType certType = CertificateType.X509;
-
- // Look through the available sessions to see if an appropriate one is
- // available.
- for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); )
- {
- byte[] id = (byte[]) e.nextElement();
- continuedSession = (Session) sessionContext.getSession(id);
- if (continuedSession == null)
- {
- continue;
- }
- if (!session.enabledProtocols.contains(continuedSession.protocol))
- {
- continue;
- }
- if (continuedSession.getPeerHost().equals(remoteHost))
- {
- sessionId = id;
- break;
- }
- }
-
- // If a SRP suite is enabled, ask for a username so we can include it
- // with our extensions list.
- for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); )
- {
- CipherSuite s = (CipherSuite) i.next();
- if (s.getKeyExchange() == "SRP")
- {
- extensions = new LinkedList();
- user = askUserName(remoteHost);
- byte[] b = user.getBytes("UTF-8");
- if (b.length > 255)
- {
- handshakeFailure();
- throw new SSLException("SRP username too long");
- }
- extensions.add(new Extension(Extension.Type.SRP,
- Util.concat(new byte[] { (byte) b.length }, b)));
-
- break;
- }
- }
-
- // If the jessie.fragment.length property is set, add the appropriate
- // extension to the list. The fragment length is only actually set if
- // the server responds with the same extension.
- try
- {
- int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length"));
- byte[] ext = new byte[1];
- if (flen == 512)
- ext[0] = 1;
- else if (flen == 1024)
- ext[0] = 2;
- else if (flen == 2048)
- ext[0] = 3;
- else if (flen == 4096)
- ext[0] = 4;
- else
- throw new NumberFormatException();
- if (extensions == null)
- extensions = new LinkedList();
- extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext));
- }
- catch (NumberFormatException nfe) { }
-
- // FIXME: set certificate types.
-
- // Send the client hello.
- ProtocolVersion version = session.protocol;
- Random clientRandom =
- new Random(Util.unixTime(), session.random.generateSeed(28));
- session.protocol = (ProtocolVersion) session.enabledProtocols.last();
- List comp = new ArrayList(2);
- comp.add(CompressionMethod.ZLIB);
- comp.add(CompressionMethod.NULL);
- ClientHello clientHello =
- new ClientHello(session.protocol, clientRandom, sessionId,
- session.enabledSuites, comp, extensions);
- Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-// try
-// {
-// Thread.sleep(150);
-// }
-// catch (InterruptedException ie)
-// {
-// }
-
- // Receive the server hello.
- msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.SERVER_HELLO)
- {
- throwUnexpectedMessage();
- }
- ServerHello serverHello = (ServerHello) msg.getBody();
- Random serverRandom = serverHello.getRandom();
- version = serverHello.getVersion();
-
- // If we don't directly support the server's protocol version, choose
- // the highest one we support that is less than the server's version.
- if (!session.enabledProtocols.contains(version))
- {
- ProtocolVersion v1 = null, v2 = null;
- for (Iterator it = session.enabledProtocols.iterator();
- it.hasNext(); )
- {
- v1 = (ProtocolVersion) it.next();
- if (v1.compareTo(version) > 0)
- break;
- v2 = v1;
- }
- version = v1;
- }
-
- // The server's version is either unsupported by us (unlikely) or the user
- // has only enabled incompatible versions.
- if (version == null)
- {
- Alert.Description desc = null;
- if (serverHello.getVersion() == ProtocolVersion.SSL_3)
- {
- desc = Alert.Description.HANDSHAKE_FAILURE;
- }
- else
- {
- desc = Alert.Description.PROTOCOL_VERSION;
- }
- Alert alert = new Alert(Alert.Level.FATAL, desc);
- sendAlert(alert);
- session.currentAlert = alert;
- fatal();
- throw new AlertException(alert, true);
- }
-
- if (serverHello.getExtensions() != null)
- {
- for (Iterator it = serverHello.getExtensions().iterator();
- it.hasNext(); )
- {
- Extension e = (Extension) it.next();
- if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int len = Extensions.getMaxFragmentLength(e).intValue();
- session.params.setFragmentLength(len);
-// recordOutput.setFragmentLength(len);
-// recordInput.setFragmentLength(len);
- }
- else if (e.getType() == Extension.Type.CERT_TYPE)
- {
- certType = Extensions.getServerCertType(e);
- }
- }
- }
-
- CipherSuite suite = serverHello.getCipherSuite().resolve(version);
- boolean newSession = true;
- if (sessionId.length > 0 &&
- Arrays.equals(sessionId, serverHello.getSessionId()))
- {
- SecurityParameters params = session.params;
- SecureRandom random = session.random;
- session = (Session) continuedSession.clone();
- session.params = params;
- session.random = random;
- recordInput.setSession(session);
-// recordOutput.setSession(session);
- suite = session.cipherSuite;
- newSession = false;
- }
- else
- {
- sessionContext.removeSession(new Session.ID(sessionId));
- }
- if (newSession)
- {
- session.peerHost = remoteHost;
- session.sessionId = new Session.ID(serverHello.getSessionId());
- session.cipherSuite = suite;
- }
- session.params.reset();
-// session.params.setInMac(null);
-// session.params.setOutMac(null);
-// session.params.setInRandom(null);
-// session.params.setOutRandom(null);
-// session.params.setInCipher(null);
-// session.params.setOutCipher(null);
- session.currentAlert = null;
- session.valid = true;
- session.protocol = version;
-
- // If the server responded with the same session id that we sent, we
- // assume that the session will be continued, and skip the bulk of the
- // handshake.
- if (newSession)
- {
- PublicKey serverKey = null, serverKex = null;
- KeyPair clientKeys = null, clientKex = null;
- CertificateRequest certReq;
- boolean sendKeyExchange = false;
- BigInteger srp_x = null;
- IKeyAgreementParty clientKA = null;
- IncomingMessage in; // used for key agreement protocol exchange
- OutgoingMessage out = null;
-
- if (suite.getKeyExchange() == "SRP")
- {
- String password = askPassword(user);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE,
- "SRP: password read is ''{0}''", password);
- }
- byte[] userSrpPassword = password.getBytes("UTF-8");
-
- // instantiate and setup client-side key agreement party
- clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA);
- Map clientAttributes = new HashMap();
- clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user);
- clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword);
- try
- {
- clientKA.init(clientAttributes);
- // initiate the exchange
- out = clientKA.processMessage(null);
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
-
- if (suite.getSignature() != "anon")
- {
- msg = Handshake.read(din, certType);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CERTIFICATE)
- {
- throwUnexpectedMessage();
- }
- Certificate serverCertificate = (Certificate) msg.getBody();
- X509Certificate[] peerCerts = serverCertificate.getCertificates();
- try
- {
- session.trustManager.checkServerTrusted(peerCerts,
- suite.getAuthType());
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DH" &&
- !(peerCerts[0].getPublicKey() instanceof DHPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DHE")
- {
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getSignature() == "DSS" &&
- !(peerCerts[0].getPublicKey() instanceof DSAPublicKey))
- throw new InvalidKeyException("improper public key");
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- catch (InvalidKeyException ike)
- {
- throwHandshakeFailure();
- }
- catch (Exception x)
- {
- if (!checkCertificates(peerCerts))
- {
- peerUnverified(peerCerts);
- SSLPeerUnverifiedException e =
- new SSLPeerUnverifiedException ("could not verify peer certificate: "+
- peerCerts[0].getSubjectDN());
- e.initCause (x);
- throw e;
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- serverKey = peerCerts[0].getPublicKey();
- serverKex = serverKey;
- }
-
- msg = Handshake.read(din, suite, serverKey);
-
- // Receive the server's key exchange.
- if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ServerKeyExchange skex = (ServerKeyExchange) msg.getBody();
- serverKex = skex.getPublicKey();
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else if (suite.getSignature() == "DSS")
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupVerify(Collections.singletonMap(
- ISignature.VERIFIER_KEY, serverKey));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- if (suite.getKeyExchange() == "RSA")
- {
- updateSig(sig, ((RSAPublicKey) serverKex).getModulus());
- updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent());
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getP());
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getG());
- updateSig(sig, ((DHPublicKey) serverKex).getY());
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- updateSig(sig, ((SRPPublicKey) serverKex).getN());
- updateSig(sig, ((SRPPublicKey) serverKex).getG());
- byte[] srpSalt = skex.getSRPSalt();
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, ((SRPPublicKey) serverKex).getY());
- }
- if (!sig.verify(skex.getSignature().getSigValue()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (suite.getKeyExchange() == "SRP")
- {
- // use server's key exchange data to continue
- // agreement protocol by faking a received incoming
- // message. again the following code can be broken
- // into multiple blocks for more accurate exception
- // handling
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(((SRPPublicKey) serverKex).getN());
- out.writeMPI(((SRPPublicKey) serverKex).getG());
- out.writeMPI(new BigInteger(1, skex.getSRPSalt()));
- out.writeMPI(((SRPPublicKey) serverKex).getY());
-
- in = new IncomingMessage(out.toByteArray());
-
- out = clientKA.processMessage(in);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}",
- Boolean.valueOf (clientKA.isComplete()));
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
- msg = Handshake.read(din, suite, serverKey);
- }
-
- // See if the server wants us to send our certificates.
- certReq = null;
- if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST)
- {
- if (suite.getSignature() == "anon")
- {
- throwHandshakeFailure();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- certReq = (CertificateRequest) msg.getBody();
- msg = Handshake.read(din);
- }
-
- // Read ServerHelloDone.
- if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
-
- // Send our certificate chain if the server asked for it.
- if (certReq != null)
- {
- String alias = session.keyManager.chooseClientAlias(
- certReq.getTypeStrings(), certReq.getAuthorities(), null);
- if (alias == null && version == ProtocolVersion.SSL_3)
- {
- Alert alert =
- new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE);
- sendAlert(alert);
- }
- else
- {
- X509Certificate[] chain =
- session.keyManager.getCertificateChain(alias);
- PrivateKey key = session.keyManager.getPrivateKey(alias);
- if (chain == null)
- {
- chain = new X509Certificate[0];
- }
- Certificate cert = new Certificate(chain);
- msg = new Handshake(Handshake.Type.CERTIFICATE, cert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- if (chain.length > 0)
- {
- session.localCerts = chain;
- clientKeys = new KeyPair(chain[0].getPublicKey(), key);
- }
- }
- }
-
- // Send our key exchange.
- byte[] preMasterSecret = null;
- ClientKeyExchange ckex = null;
- if (suite.getKeyExchange() == "RSA")
- {
- ProtocolVersion v =
- (ProtocolVersion) session.enabledProtocols.last();
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(v.getEncoded(), b);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex);
- BigInteger bi = new BigInteger(1,
- pkcs1.encode(preMasterSecret, session.random));
- bi = RSA.encrypt((RSAPublicKey) serverKex, bi);
- ckex = new ClientKeyExchange(Util.trim(bi));
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- if (clientKeys == null ||
- !(clientKeys.getPublic() instanceof DHPublicKey))
- {
- GnuDHPrivateKey tmpKey =
- new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(),
- ((DHPublicKey) serverKex).getParams().getG(), null);
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA);
- Map attr = new HashMap();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- tmpKey);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- try
- {
- clientKA.init(attr);
- out = new OutgoingMessage();
- out.writeMPI(((DHPublicKey) serverKex).getY());
- in = new IncomingMessage(out.toByteArray());
- out = clientKA.processMessage(in);
- in = new IncomingMessage(out.toByteArray());
- ckex = new ClientKeyExchange(in.readMPI());
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else
- {
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- clientKeys.getPrivate());
- try
- {
- // The key exchange is already complete here; our public
- // value was sent with our certificate.
- clientKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- ckex = new ClientKeyExchange(new byte[0]);
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- // at this point, out --the outgoing message-- already contains
- // what we want. so...
- BigInteger A = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- A = in.readMPI();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A);
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- ckex = new ClientKeyExchange(A);
- }
- msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
-
- // Generate the master secret.
- if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- clientKA = null;
- }
- }
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString (preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED,
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException (shouldNotHappen.getMessage());
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Send our certificate verify message.
- if (certReq != null && clientKeys != null)
- {
- IMessageDigest vMD5 = (IMessageDigest) md5.clone();
- IMessageDigest vSHA = (IMessageDigest) sha.clone();
- PrivateKey key = clientKeys.getPrivate();
- Object sig = null;
- String sigAlg = null;
- try
- {
- if (key instanceof DSAPrivateKey)
- {
- sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(),
- session.random);
- sigAlg = "DSS";
- }
- else if (key instanceof RSAPrivateKey)
- {
- SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA);
- rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key));
- sig = rsa.sign();
- sigAlg = "RSA";
- }
- else
- {
- throw new InvalidKeyException("no appropriate key");
- }
- }
- catch (Exception x)
- {
- throwHandshakeFailure();
- }
- CertificateVerify verify = new CertificateVerify(sig, sigAlg);
- msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- }
- dout.flush();
- }
-
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- session.params.setVersion (version);
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause(ike);
- throw re;
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nsae);
- throw x;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nspe);
- throw x;
- }
-
- Finished finis = null;
-
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
-
- msg = Handshake.read(din, suite, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Perform the server handshake.
- */
- private void doServerHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}",
- Thread.currentThread());
- }
-
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostName();
- }
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostAddress();
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
-
- // Read the client hello.
- Handshake msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CLIENT_HELLO)
- {
- throwUnexpectedMessage();
- }
- ClientHello clientHello = (ClientHello) msg.getBody();
- Random clientRandom = clientHello.getRandom();
- ProtocolVersion version = clientHello.getVersion();
- ProtocolVersion server =
- (ProtocolVersion) session.enabledProtocols.last();
- CompressionMethod comp;
- if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB))
- comp = CompressionMethod.ZLIB;
- else
- comp = CompressionMethod.NULL;
- if (!session.enabledProtocols.contains(version)
- && version.compareTo(server) < 0)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.PROTOCOL_VERSION);
- sendAlert(alert);
- session.currentAlert = alert;
- throw new AlertException(alert, true);
- }
-
- // Look through the extensions sent by the client (if any), and react to
- // them appropriately.
- List extensions = null;
- String remoteUser = null;
- if (clientHello.getExtensions() != null)
- {
- for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();)
- {
- Extension ex = (Extension) it.next();
- if (ex.getType() == Extension.Type.SERVER_NAME)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int maxLen = Extensions.getMaxFragmentLength(ex).intValue();
-// recordInput.setFragmentLength(maxLen);
-// recordOutput.setFragmentLength(maxLen);
- session.params.setFragmentLength(maxLen);
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.SRP)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- byte[] b = ex.getValue();
- remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8");
- session.putValue("srp-username", remoteUser);
- }
- }
- }
-
- CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version);
- if (suite == null)
- {
- return;
- }
-
- // If the selected suite turns out to be SRP, set up the key exchange
- // objects.
- IKeyAgreementParty serverKA = null;
- IncomingMessage in;
- OutgoingMessage out = null;
- if (suite.getKeyExchange() == "SRP")
- {
- // FIXME
- // Uhm, I don't think this can happen, because if remoteUser is null
- // we cannot choose an SRP ciphersuite...
- if (remoteUser == null)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider();
- Map dbAttributes = new HashMap();
- dbAttributes.put(SRPRegistry.PASSWORD_DB,
- session.srpTrustManager.getPasswordFile());
- srpDB.activate(dbAttributes);
-
- // FIXME
- // We can also fake that the user exists, and generate a dummy (and
- // invalid) master secret, and let the handshake fail at the Finished
- // message. This is better than letting the connecting side know that
- // the username they sent isn't valid.
- //
- // But how to implement this?
- if (!srpDB.contains(remoteUser))
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNKNOWN_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA);
- Map serverAttributes = new HashMap();
- serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB);
-
- try
- {
- serverKA.init(serverAttributes);
- out = new OutgoingMessage();
- out.writeString(remoteUser);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- }
- catch (KeyAgreementException x)
- {
- throwHandshakeFailure();
- }
- }
-
- // Check if the session specified by the client's ID corresponds
- // to a saved session, and if so, continue it.
- boolean newSession = true;
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext);
- }
- if (sessionContext.containsSessionID(
- new Session.ID(clientHello.getSessionId())))
- {
- Session old = session;
- session = (Session) sessionContext.getSession(clientHello.getSessionId());
- if (!clientHello.getCipherSuites().contains(session.cipherSuite))
- {
- throwHandshakeFailure();
- }
- if (session.getPeerHost().equals(remoteHost) &&
- old.enabledProtocols.contains(session.protocol))
- {
- session = (Session) session.clone();
- suite = session.cipherSuite;
- newSession = false;
- recordInput.setSession(session);
- session.currentAlert = null;
- session.params = old.params;
- session.random = old.random;
- }
- else
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}",
- new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)),
- Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) });
- }
- session = old;
- session.peerHost = remoteHost;
- newSession = true;
- }
- }
- else if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}",
- new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))),
- sessionContext });
- }
- if (newSession)
- {
- byte[] buf = new byte[32];
- Session.ID sid = null;
- do
- {
- session.random.nextBytes(buf);
- sid = new Session.ID(buf);
- }
- while (sessionContext.containsSessionID(sid));
- session.sessionId = sid;
- }
- session.valid = true;
- session.peerHost = remoteHost;
- session.cipherSuite = suite;
- session.protocol = version;
- session.params.setVersion (version);
-
- // Send the server hello.
- Random serverRandom = new Random(Util.unixTime(),
- session.random.generateSeed(28));
- ServerHello serverHello = new ServerHello(version, serverRandom,
- session.getId(), suite,
- comp, extensions);
- msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-
- if (newSession)
- {
- X509Certificate[] certs = null;
- PrivateKey serverKey = null;
- if (suite.getSignature() != "anon")
- {
- // Send our CA-issued certificate to the client.
- String alias = session.keyManager.chooseServerAlias(suite.getAuthType(),
- null, null);
- certs = session.keyManager.getCertificateChain(alias);
- serverKey = session.keyManager.getPrivateKey(alias);
- if (certs == null || serverKey == null)
- {
- throwHandshakeFailure();
- }
- session.localCerts = certs;
- Certificate serverCert = new Certificate(certs);
- msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If the certificate we sent does not contain enough information to
- // do the key exchange (in the case of ephemeral Diffie-Hellman,
- // export RSA, and SRP) we send a signed public key to be used for the
- // key exchange.
- KeyPair signPair = null;
- if (certs != null)
- {
- signPair = new KeyPair(certs[0].getPublicKey(), serverKey);
- }
- KeyPair kexPair = signPair;
- ServerKeyExchange skex = null;
-
- // Set up our key exchange, and/or prepare our ServerKeyExchange
- // message.
- if ((suite.getKeyExchange() == "RSA" && suite.isExportable() &&
- ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512))
- {
- kexPair = KeyPool.generateRSAKeyPair();
- RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic();
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- SSLRSASignature sig = new SSLRSASignature();
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getModulus());
- updateSig(sig, pubkey.getPublicExponent());
- s = new Signature(sig.sign(), "RSA");
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "DH")
- {
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- serverKey);
- try
- {
- serverKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- // We don't send a ServerKeyExchange for this suite.
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA);
- Map attr = new HashMap();
- GnuDHPrivateKey servParams = DiffieHellman.getParams();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- servParams);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- BigInteger serv_y = null;
- try
- {
- serverKA.init(attr);
- out = serverKA.processMessage(null);
- in = new IncomingMessage(out.toByteArray());
- serv_y = in.readMPI();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- GnuDHPublicKey pubkey =
- new GnuDHPublicKey(null, servParams.getParams().getP(),
- servParams.getParams().getG(), serv_y);
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getParams().getP());
- updateSig(sig, pubkey.getParams().getG());
- updateSig(sig, pubkey.getY());
- s = new Signature(sig.sign(), suite.getSignature());
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger N = null;
- BigInteger g = null;
- BigInteger salt = null;
- BigInteger B = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- N = in.readMPI();
- g = in.readMPI();
- salt = in.readMPI();
- B = in.readMPI();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- Signature s = null;
- final byte[] srpSalt = Util.trim(salt);
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, N);
- updateSig(sig, g);
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, B);
- s = new Signature(sig.sign(), suite.getSignature());
- }
- final SRPPublicKey pubkey = new SRPPublicKey(N, g, B);
- skex = new ServerKeyExchange(pubkey, s, srpSalt);
- }
- if (skex != null)
- {
- msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If we are configured to want or need client authentication, then
- // ask for it.
- if (wantClientAuth || needClientAuth)
- {
- Principal[] auths = null;
- CertificateRequest.ClientType[] types =
- new CertificateRequest.ClientType[] {
- CertificateRequest.ClientType.RSA_SIGN,
- CertificateRequest.ClientType.DSS_SIGN,
- CertificateRequest.ClientType.RSA_FIXED_DH,
- CertificateRequest.ClientType.DSS_FIXED_DH
- };
- try
- {
- auths = (Principal[])
- Util.transform(session.trustManager.getAcceptedIssuers(),
- Principal.class, "getSubjectDN", null);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- CertificateRequest req = new CertificateRequest(types, auths);
- msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req);
- msg.write(dout, version);
- dout.flush();
- }
-
- // Send our server hello done.
- msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
-
- if (suite.getKeyExchange() == "RSA")
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- else
- {
- msg = Handshake.read(din, suite, null);
- }
- boolean clientCertOk = false;
- boolean clientCanSign = false;
- X509Certificate[] clientChain = null;
- PublicKey clientKey = null;
-
- // Read the client's certificate, if sent.
- if (msg.getType() == Handshake.Type.CERTIFICATE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- Certificate cliCert = (Certificate) msg.getBody();
- clientChain = cliCert.getCertificates();
- try
- {
- session.trustManager.checkClientTrusted(clientChain,
- suite.getAuthType());
- session.peerCerts = clientChain;
- session.peerVerified = true;
- clientKey = clientChain[0].getPublicKey();
- }
- catch (Exception x)
- {
- }
- clientCanSign = ((clientKey instanceof DSAPublicKey) ||
- (clientKey instanceof RSAPublicKey));
- if (suite.getKeyExchange().startsWith("DH"))
- {
- msg = Handshake.read(din, suite, clientKey);
- }
- else
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- }
-
- // If we require client authentication, and the client sent an
- // unverifiable certificate or no certificate at all, drop the
- // connection.
- if (!session.peerVerified && needClientAuth)
- {
- throwHandshakeFailure();
- }
-
- // Read the client key exchange.
- if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody();
- byte[] preMasterSecret = null;
- if (suite.getKeyExchange() == "RSA")
- {
- byte[] enc = (byte[]) ckex.getExchangeObject();
- BigInteger bi = new BigInteger(1, enc);
- try
- {
- bi = RSA.decrypt(kexPair.getPrivate(), bi);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance(
- (RSAPrivateKey) kexPair.getPrivate());
- preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray()));
- //rsa.init(kexPair);
- //preMasterSecret = rsa.decrypt(enc);
- }
- catch (Exception x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x);
- }
- // Generate a fake pre-master secret if the RSA decryption
- // fails.
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(version.getEncoded(), b);
- }
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- out = new OutgoingMessage();
- if (clientKey == null)
- out.writeMPI((BigInteger) ckex.getExchangeObject());
- else
- out.writeMPI(((DHPublicKey) clientKey).getY());
- in = new IncomingMessage(out.toByteArray());
- serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger A = (BigInteger) ckex.getExchangeObject();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A);
- }
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(A);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- serverKA = null;
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString(preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
-
- // Generate the master secret.
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException();
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Read the client's certificate verify message, if needed.
- if (clientCanSign && (wantClientAuth || needClientAuth))
- {
- msg = Handshake.read(din);
- if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY)
- {
- throwUnexpectedMessage();
- }
- CertificateVerify verify = (CertificateVerify) msg.getBody();
- if (clientChain != null && clientChain.length > 0)
- {
- IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
- IMessageDigest cvSHA = (IMessageDigest) sha.clone();
- clientKey = clientChain[0].getPublicKey();
- if (clientKey instanceof RSAPublicKey)
- {
- SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA);
- sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey));
- if (!sig.verify(verify.getSigValue()))
- {
- handshakeFailure();
- throw new SSLHandshakeException("client certificate verify failed");
- }
- }
- else if (clientKey instanceof DSAPublicKey)
- {
- try
- {
- if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(),
- (BigInteger[]) verify.getSigValue()))
- {
- throw new Exception("client's certificate could not be verified");
- }
- }
- catch (Exception x)
- {
- handshakeFailure();
- SSLHandshakeException e = new SSLHandshakeException (x.getMessage());
- e.initCause (x);
- throw e;
- }
- }
- }
- }
- }
-
- // Generate the session keys.
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause (ike);
- throw new RuntimeException (String.valueOf (ike));
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nsae);
- throw e;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nspe);
- throw e;
- }
-
- Finished finis = null;
- // If we are continuing a session, we send our Finished message first.
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- // Wait until we receive a ChangeCipherSpec, then change the crypto
- // algorithms for the incoming side.
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(comp == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- // Receive and verify the client's finished message.
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = Handshake.read(din, suite, null);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- // Send our Finished message last for new sessions.
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Generate the keys from the master secret.
- *
- * @param server The server's random value.
- * @param client The client's random value.
- * @param activeVersion The negotiated protocol version.
- * @return The generated keys.
- */
- private byte[][] generateKeys(byte[] server, byte[] client,
- ProtocolVersion activeVersion)
- throws LimitReachedException, IOException
- {
- CipherSuite suite = session.cipherSuite;
- int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20;
- int keyLen = suite.getKeyLength();
- int ivLen = 0;
- if (suite.getCipher().indexOf("DES") >= 0)
- {
- ivLen = 8;
- }
- else if (suite.getCipher() == "AES")
- {
- ivLen = 16;
- }
- byte[][] keyMaterial = new byte[6][];
- keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret
- keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret
- keyMaterial[2] = new byte[keyLen]; // client_write_key
- keyMaterial[3] = new byte[keyLen]; // server_write_key
- keyMaterial[4] = new byte[ivLen]; // client_write_IV
- keyMaterial[5] = new byte[ivLen]; // server_write_IV
- IRandom prf = null;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- prf = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, session.masterSecret);
- attr.put(SSLRandom.SEED, Util.concat(server, client));
- prf.init(attr);
- }
- else
- {
- prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"),
- Util.concat(server, client)));
- prf.init(attr);
- }
- for (int i = 0; i < keyMaterial.length; i++)
- {
- prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length);
- }
-
- // Exportable ciphers transform their keys once more, and use a
- // nonsecret IV for block ciphers.
- if (suite.isExportable())
- {
- int finalLen = suite.getCipher() == "DES" ? 8 : 16;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- md5.update(keyMaterial[2], 0, keyMaterial[2].length);
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[2] = Util.trim(md5.digest(), finalLen);
- md5.update(keyMaterial[3], 0, keyMaterial[3].length);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[3] = Util.trim(md5.digest(), finalLen);
- if (!suite.isStreamCipher())
- {
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[4] = Util.trim(md5.digest(), ivLen);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[5] = Util.trim(md5.digest(), ivLen);
- }
- }
- else
- {
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, keyMaterial[2]);
- attr.put(TLSRandom.SEED,
- Util.concat("client write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[2] = new byte[finalLen];
- prf.nextBytes(keyMaterial[2], 0, finalLen);
- attr.put(TLSRandom.SECRET, keyMaterial[3]);
- attr.put(TLSRandom.SEED,
- Util.concat("server write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[3] = new byte[finalLen];
- prf.nextBytes(keyMaterial[3], 0, finalLen);
- if (!suite.isStreamCipher())
- {
- attr.put(TLSRandom.SECRET, new byte[0]);
- attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length);
- prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length);
- }
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:");
- for (int i = 0; i < keyMaterial.length; i++)
- logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}",
- new Object[] { new Integer (i),
- Util.toHexString(keyMaterial[i], ':') });
- }
-
- return keyMaterial;
- }
-
- /**
- * Generate a "finished" message, based on the hashes of the handshake
- * messages, the agreed version, and a label.
- *
- * @param version The agreed version.
- * @param md5 The current state of the handshake MD5 hash.
- * @param sha The current state of the handshake SHA hash.
- * @param client Should be true if the message is generated by the client.
- */
- private Finished generateFinished(ProtocolVersion version, IMessageDigest md5,
- IMessageDigest sha, boolean client)
- {
- if (version == ProtocolVersion.SSL_3)
- {
- if (client)
- {
- md5.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- md5.update(SENDER_SERVER, 0, 4);
- }
- byte[] ms = session.masterSecret;
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD1);
- }
- byte[] b = md5.digest();
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD2);
- }
- md5.update(b, 0, b.length);
-
- if (client)
- {
- sha.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- sha.update(SENDER_SERVER, 0, 4);
- }
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD1);
- }
- b = sha.digest();
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD2);
- }
- sha.update(b, 0, b.length);
- return new Finished(md5.digest(), sha.digest());
- }
- else
- {
- byte[] h1 = md5.digest();
- byte[] h2 = sha.digest();
- String label = client ? "client finished" : "server finished";
- byte[] seed = null;
- try
- {
- seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2));
- }
- catch (java.io.UnsupportedEncodingException uee)
- {
- RuntimeException re = new RuntimeException (uee.getMessage());
- re.initCause (uee);
- throw re;
- }
- IRandom prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, seed);
- prf.init(attr);
- byte[] finishedValue = new byte[12];
- try
- {
- prf.nextBytes(finishedValue, 0, 12);
- }
- catch (LimitReachedException lre)
- {
- RuntimeException re = new RuntimeException (lre.getMessage());
- re.initCause (lre);
- throw re;
- }
- return new Finished(finishedValue);
- }
- }
-
- /**
- * Send a fatal unexpected_message alert.
- */
- private Alert unexpectedMessage() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNEXPECTED_MESSAGE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwUnexpectedMessage() throws IOException
- {
- throw new AlertException(unexpectedMessage(), true);
- }
-
- /**
- * Send a fatal handshake_failure alert.
- */
- private Alert handshakeFailure() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwHandshakeFailure() throws IOException
- {
- throw new AlertException(handshakeFailure(), true);
- }
-
- /**
- * Send an internal_error alert.
- */
- private Alert internalError() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INTERNAL_ERROR);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwInternalError() throws IOException
- {
- throw new AlertException(internalError(), true);
- }
-
- private Alert peerUnverified(X509Certificate[] chain) throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwPeerUnverified(X509Certificate[] chain) throws IOException
- {
- peerUnverified (chain);
- throw new SSLPeerUnverifiedException("could not verify: "+
- chain[0].getSubjectDN());
- }
-
- /**
- * Grab the first suite that is both in the client's requested suites
- * and in our enabled suites, and for which we have the proper
- * credentials.
- *
- * @param suites The client's requested suites.
- * @param version The version being negotiated.
- * @return The selected cipher suite.
- * @throws SSLException If no appropriate suite can be selected.
- */
- private CipherSuite selectSuite(List suites, ProtocolVersion version)
- throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}",
- new Object[] { suites, session.enabledSuites });
- boolean srpSuiteNoUser = false;
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- CipherSuite herSuite = (CipherSuite) i.next();
- for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); )
- {
- CipherSuite mySuite = (CipherSuite) j.next();
- if (!mySuite.equals(herSuite))
- {
- continue;
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0} == {1}",
- new Object[] { mySuite, herSuite });
- if (mySuite.getSignature() != "anon" && session.keyManager != null &&
- session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key",
- mySuite);
- continue;
- }
- if (mySuite.getKeyExchange() == "SRP")
- {
- if (session.getValue("srp-username") == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP username");
- srpSuiteNoUser = true;
- continue;
- }
- if (session.srpTrustManager == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP password file");
- continue;
- }
- }
- return mySuite.resolve(version);
- }
- }
- Alert alert = null;
- if (srpSuiteNoUser)
- {
- alert = new Alert(Alert.Level.WARNING,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- return null;
- }
- else
- alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INSUFFICIENT_SECURITY);
- sendAlert(alert);
- fatal();
- throw new AlertException(alert, true);
- }
-
- /**
- * Ask the user for their user name.
- *
- * @param remoteHost The remote host being connected to.
- * @return The user name.
- */
- private String askUserName(String remoteHost)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- TextInputCallback user =
- new TextInputCallback("User name for " + remoteHost + ": ",
- Util.getProperty("user.name"));
- try
- {
- handler.handle(new Callback[] { user });
- }
- catch (Exception x) { }
- return user.getText();
- }
-
- /**
- * Ask the user for a password.
- *
- * @param user The user name.
- * @return The password.
- */
- private String askPassword(String user)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false);
- try
- {
- handler.handle(new Callback[] { passwd });
- }
- catch (Exception x) { }
- return new String(passwd.getPassword());
- }
-
- /**
- * Ask the user (via a callback) if they will accept a certificate that
- * could not be verified.
- *
- * @param chain The certificate chain in question.
- * @return true if the user accepts the certificate chain.
- */
- private boolean checkCertificates(X509Certificate[] chain)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x)
- {
- }
- String nl = Util.getProperty("line.separator");
- ConfirmationCallback confirm = new ConfirmationCallback(
- "The server's certificate could not be verified. There is no proof" + nl +
- "that this server is who it claims to be, or that their certificate" + nl +
- "is valid. Do you wish to continue connecting?",
- ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION,
- ConfirmationCallback.NO);
- try
- {
- handler.handle(new Callback[] { confirm });
- }
- catch (Exception x)
- {
- return false;
- }
- return confirm.getSelectedIndex() == ConfirmationCallback.YES;
- }
-
- /**
- * Update a signature object with a BigInteger, trimming the leading
- * "00" octet if present.
- *
- * @param sig The signature being updated.
- * @param bi The integer to feed into the signature.
- */
- private void updateSig(ISignature sig, BigInteger bi)
- {
- byte[] buf = Util.trim(bi);
- sig.update((byte) (buf.length >>> 8));
- sig.update((byte) buf.length);
- sig.update(buf, 0, buf.length);
- }
-
- /**
- * Teardown everything on fatal errors.
- */
- private void fatal() throws IOException
- {
- if (session != null)
- {
- session.invalidate();
- }
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
- if (underlyingSocket != null)
- {
- underlyingSocket.close();
- }
- else
- {
- super.close();
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/gnu/javax/net/ssl/provider/SSLSocketFactory.java
deleted file mode 100644
index 24a8389c1..000000000
--- a/gnu/javax/net/ssl/provider/SSLSocketFactory.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/* SSLSocketFactory.java -- factory for SSL sockets.
- 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.Socket;
-import java.net.UnknownHostException;
-import java.security.SecureRandom;
-
-import javax.net.ssl.X509TrustManager;
-import javax.net.ssl.X509KeyManager;
-
-class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final X509TrustManager trustManager;
- private final X509KeyManager keyManager;
- private final SecureRandom random;
- private final SessionContext sessionContext;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager,
- SecureRandom random, SessionContext sessionContext)
- {
- this.trustManager = trustManager;
- this.keyManager = keyManager;
- this.random = random;
- this.sessionContext = sessionContext;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String[] getDefaultCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public String[] getSupportedCipherSuites()
- {
- return getDefaultCipherSuites();
- }
-
- public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
- throws IOException
- {
- return setup(new SSLSocket(socket, host, port, autoClose));
- }
-
- public Socket createSocket() throws IOException
- {
- return setup(new SSLSocket());
- }
-
- public Socket createSocket(String host, int port)
- throws IOException, UnknownHostException
- {
- return setup(new SSLSocket(host, port));
- }
-
- public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
- throws IOException, UnknownHostException
- {
- return setup(new SSLSocket(host, port, localAddr, localPort));
- }
-
- public Socket createSocket(InetAddress address, int port) throws IOException
- {
- return setup(new SSLSocket(address, port));
- }
-
- public Socket createSocket(InetAddress address, int port,
- InetAddress localAddr, int localPort)
- throws IOException
- {
- return setup(new SSLSocket(address, port, localAddr, localPort));
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private SSLSocket setup(SSLSocket s)
- {
- s.setTrustManager(trustManager);
- s.setKeyManager(keyManager);
- s.setRandom(random);
- s.setSessionContext(sessionContext);
- s.setUseClientMode(true);
- return s;
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java b/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
new file mode 100644
index 000000000..6c804f9c6
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
@@ -0,0 +1,137 @@
+/* SSLSocketFactoryImpl.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 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
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port);
+ InetSocketAddress endpoint = new InetSocketAddress(host, port);
+ socket.connect(endpoint);
+ return socket;
+ }
+
+ /* (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 = createSocket(host, port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(InetAddress host, int port)
+ throws IOException
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl,
+ host.getCanonicalHostName(), port);
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ /* (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 = createSocket(host, port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ return socket;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/gnu/javax/net/ssl/provider/SSLSocketImpl.java
new file mode 100644
index 000000000..0181b66d8
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLSocketImpl.java
@@ -0,0 +1,833 @@
+/* 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, null, false);
+ }
+
+ 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 = null;
+ if (underlyingSocket != null)
+ sockIn = new DataInputStream(underlyingSocket.getInputStream());
+ else
+ sockIn = new DataInputStream(super.getInputStream());
+
+ OutputStream sockOut = null;
+ if (underlyingSocket != null)
+ sockOut = underlyingSocket.getOutputStream();
+ else
+ sockOut = super.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
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.bind(bindpoint);
+ else
+ super.bind(bindpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint) throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.connect(endpoint);
+ else
+ super.connect(endpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint, int timeout)
+ throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.connect(endpoint, timeout);
+ else
+ super.connect(endpoint, timeout);
+ }
+
+ @Override public InetAddress getInetAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getInetAddress();
+ return super.getInetAddress();
+ }
+
+ @Override public InetAddress getLocalAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalAddress();
+ return super.getLocalAddress();
+ }
+
+ @Override public int getPort()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getPort();
+ return super.getPort();
+ }
+
+ @Override public int getLocalPort()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalPort();
+ return super.getLocalPort();
+ }
+
+ @Override public SocketAddress getRemoteSocketAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getRemoteSocketAddress();
+ return super.getRemoteSocketAddress();
+ }
+
+ public SocketAddress getLocalSocketAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalSocketAddress();
+ return super.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
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setTcpNoDelay(on);
+ else
+ super.setTcpNoDelay(on);
+ }
+
+ @Override public boolean getTcpNoDelay() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getTcpNoDelay();
+ return super.getTcpNoDelay();
+ }
+
+ @Override public void setSoLinger(boolean on, int linger) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSoLinger(on, linger);
+ else
+ super.setSoLinger(on, linger);
+ }
+
+ public int getSoLinger() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSoLinger();
+ return super.getSoLinger();
+ }
+
+ @Override public void sendUrgentData(int x) throws IOException
+ {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ @Override public void setOOBInline(boolean on) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setOOBInline(on);
+ else
+ super.setOOBInline(on);
+ }
+
+ @Override public boolean getOOBInline() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getOOBInline();
+ return super.getOOBInline();
+ }
+
+ @Override public void setSoTimeout(int timeout) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSoTimeout(timeout);
+ else
+ super.setSoTimeout(timeout);
+ }
+
+ @Override public int getSoTimeout() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSoTimeout();
+ return super.getSoTimeout();
+ }
+
+ @Override public void setSendBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSendBufferSize(size);
+ else
+ super.setSendBufferSize(size);
+ }
+
+ @Override public int getSendBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSendBufferSize();
+ return super.getSendBufferSize();
+ }
+
+ @Override public void setReceiveBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setReceiveBufferSize(size);
+ else
+ underlyingSocket.setReceiveBufferSize(size);
+ }
+
+ @Override public int getReceiveBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getReceiveBufferSize();
+ return super.getReceiveBufferSize();
+ }
+
+ @Override public void setKeepAlive(boolean on) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setKeepAlive(on);
+ else
+ super.setKeepAlive(on);
+ }
+
+ @Override public boolean getKeepAlive() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getKeepAlive();
+ return super.getKeepAlive();
+ }
+
+ @Override public void setTrafficClass(int tc) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setTrafficClass(tc);
+ else
+ super.setTrafficClass(tc);
+ }
+
+ @Override public int getTrafficClass() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getTrafficClass();
+ return super.getTrafficClass();
+ }
+
+ @Override public void setReuseAddress(boolean reuseAddress)
+ throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setReuseAddress(reuseAddress);
+ else
+ super.setReuseAddress(reuseAddress);
+ }
+
+ @Override public boolean getReuseAddress() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getReuseAddress();
+ return super.getReuseAddress();
+ }
+
+ @Override public void close() throws IOException
+ {
+ // XXX closure alerts.
+ if (underlyingSocket != null && autoClose)
+ underlyingSocket.close();
+ else
+ super.close();
+ }
+
+ @Override public void shutdownInput() throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.shutdownInput();
+ else
+ super.shutdownInput();
+ }
+
+ @Override public void shutdownOutput() throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.shutdownOutput();
+ else
+ super.shutdownOutput();
+ }
+
+ @Override public boolean isConnected()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isConnected();
+ return super.isConnected();
+ }
+
+ @Override public boolean isBound()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isBound();
+ return super.isBound();
+ }
+
+ @Override public boolean isClosed()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isClosed();
+ return super.isClosed();
+ }
+
+ @Override public boolean isInputShutdown()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isInputShutdown();
+ return super.isInputShutdown();
+ }
+
+ @Override public boolean isOutputShutdown()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isOutputShutdown();
+ return super.isOutputShutdown();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
deleted file mode 100644
index 69202ca33..000000000
--- a/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/* SSLSocketInputStream.java -- InputStream for SSL sockets.
- 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.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import javax.net.ssl.SSLException;
-
-class SSLSocketInputStream extends FilterInputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SSLSocket socket;
- private final boolean checkHandshake;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLSocketInputStream(InputStream in, SSLSocket socket)
- {
- this(in, socket, true);
- }
-
- SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake)
- {
- super(in);
- this.socket = socket;
- this.checkHandshake = checkHandshake;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public int available() throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- int ret = 0;
- try
- {
- ret = super.available();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- public int read() throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- int ret = 0;
- try
- {
- ret = in.read();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- public int read(byte[] buf) throws IOException
- {
- return read(buf, 0, buf.length);
- }
-
- public int read(byte[] buf, int off, int len) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- if (buf == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
- int ret = 0;
- try
- {
- ret = in.read(buf, off, len);
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private boolean checkAlert() throws IOException
- {
- Alert alert = socket.checkAlert();
- if (alert == null) return false;
- if (alert.getLevel().equals(Alert.Level.FATAL))
- throw new AlertException(alert, false);
- if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY))
- {
- try { return (in.available() <= 0); }
- catch (IOException ioe) { }
- }
- return false;
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
deleted file mode 100644
index fe769a85f..000000000
--- a/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/* SSLSocketOutputStream.java -- output stream for SSL sockets.
- 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.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import javax.net.ssl.SSLException;
-
-class SSLSocketOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SSLSocket socket;
- private final boolean checkHandshake;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLSocketOutputStream(OutputStream out, SSLSocket socket)
- {
- this(out, socket, true);
- }
-
- SSLSocketOutputStream(OutputStream out, SSLSocket socket,
- boolean checkHandshake)
- {
- super(out);
- this.socket = socket;
- this.checkHandshake = checkHandshake;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(int b) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- checkAlert();
- out.write(b);
- checkAlert();
- }
-
- public void write(byte[] buf) throws IOException
- {
- write(buf, 0, buf.length);
- }
-
- public void write(byte[] buf, int off, int len) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- if (buf == null)
- throw new NullPointerException();
- if (off < 0 || len < 0 || off + len > buf.length)
- throw new ArrayIndexOutOfBoundsException();
- checkAlert();
- out.write(buf, off, len);
- checkAlert();
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private synchronized void checkAlert() throws SSLException
- {
- Alert alert = socket.checkAlert();
- if (alert == null) return;
- if (alert.getLevel().equals(Alert.Level.FATAL))
- throw new AlertException(alert, false);
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java b/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
new file mode 100644
index 000000000..763bbaf3b
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
@@ -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);
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java b/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
new file mode 100644
index 000000000..008a21c04
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
@@ -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);
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SecurityParameters.java b/gnu/javax/net/ssl/provider/SecurityParameters.java
deleted file mode 100644
index aa06680e2..000000000
--- a/gnu/javax/net/ssl/provider/SecurityParameters.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/* 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 javax.net.ssl.SSLException;
-
-/**
- * The interface that all security parameters used by Jessie must implement.
- * Security parameters handle all transforming of data, including encryption,
- * authentication, and compression.
- */
-interface SecurityParameters
-{
-
- // Methods.
- // -------------------------------------------------------------------------
-
- /**
- * Decrypts, verifies, and inflates a fragment received. The fragment is
- * just the data field of a text object, without the version, type, and
- * length fields. An exception is thrown if any step fails.
- *
- * @param fragment The fragment being decrypted.
- * @param version The version field of the received text.
- * @param type The type field of the received text.
- * @return The decrypted fragment.
- * @throws MacException If the MAC could not be verified, or if the padding
- * on the decrypted fragment is incorrect.
- * @throws OverflowException If the processed text overflows the configured
- * maximum fragment size.
- * @throws SSLException If any other error occurs.
- */
- byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type)
- throws MacException, OverflowException, SSLException;
-
- /**
- * Deflates, authenticates, and encrypts a fragment to be sent.
- *
- * @param buf The fragment being encrypted.
- * @param off The offset into the buffer to start at.
- * @param len The number of bytes in this fragment.
- * @param type The content type of this text.
- * @return The encrypted fragment.
- * @throws OverflowException If deflating increases the size of the fragment
- * too much.
- * @throws SSLException If any other error occurs.
- */
- byte[] encrypt (byte[] buf, int off, int len, ContentType type)
- throws OverflowException, SSLException;
-
- /**
- * Set all crypto primitives to <code>null</code>, meaning that any calls
- * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or
- * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType})
- * will perform the identity transformation.
- */
- void reset();
-
- /**
- * Returns the version of texts being sent.
- *
- * @return The version.
- */
- ProtocolVersion getVersion();
-
- /**
- * Sets the version of texts being sent. This affects the {@link
- * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)}
- * method.
- *
- * @param version The version to set.
- */
- void setVersion (ProtocolVersion version);
-
- /**
- * Turns zlib deflating on or off.
- *
- * @param deflate Whether or not to deflate outgoing fragments.
- */
- void setDeflating (boolean deflate);
-
- /**
- * Turns zlib inflating on or off.
- *
- * @param inflate Whether or not to inflate incoming fragments.
- */
- void setInflating (boolean inflate);
-
- /**
- * Returns the maximum size that plaintext fragments may be.
- *
- * @return The fragment length.
- */
- int getFragmentLength();
-
- /**
- * Sets the maximum size that plaintext fragments may be.
- *
- * @param fragmentLength The new fragment length.
- */
- void setFragmentLength (int fragmentLength);
-
- /**
- * Set the cipher used to decrypt incoming fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param cipher The cipher.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setInCipher (Object cipher);
-
- /**
- * Set the cipher used to encrypt outgoing fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param cipher The cipher.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setOutCipher (Object cipher);
-
- /**
- * Set the MAC used to verify incoming fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param mac The MAC.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setInMac (Object mac);
-
- /**
- * Set the MAC used to authenticating outgoinging fragments. The parameter
- * must be appropriate for the implementation.
- *
- * @param mac The MAC.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setOutMac (Object mac);
-}
diff --git a/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
new file mode 100644
index 000000000..edc3ac259
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
@@ -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();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerDHParams.java b/gnu/javax/net/ssl/provider/ServerDHParams.java
new file mode 100644
index 000000000..55d4a41da
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerDHParams.java
@@ -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 ();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerHandshake.java b/gnu/javax/net/ssl/provider/ServerHandshake.java
new file mode 100644
index 000000000..300012a4b
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerHandshake.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/ServerHello.java b/gnu/javax/net/ssl/provider/ServerHello.java
index 8b7853c7f..2bbce37fb 100644
--- a/gnu/javax/net/ssl/provider/ServerHello.java
+++ b/gnu/javax/net/ssl/provider/ServerHello.java
@@ -38,179 +38,194 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-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.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.nio.ByteBuffer;
-import javax.net.ssl.SSLProtocolException;
-
-class ServerHello implements Handshake.Body
+/**
+ * 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.
// -------------------------------------------------------------------------
- private final ProtocolVersion version;
- private final Random random;
- private final byte[] sessionId;
- private final CipherSuite suite;
- private final CompressionMethod comp;
- private final List extensions;
+ 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.
// -------------------------------------------------------------------------
- ServerHello(ProtocolVersion version, Random random,
- byte[] sessionId, CipherSuite suite,
- CompressionMethod comp)
+ public ServerHello (final ByteBuffer buffer)
{
- this(version, random, sessionId, suite, comp, null);
+ this.buffer = buffer;
+ disableExtensions = false;
}
- ServerHello(ProtocolVersion version, Random random,
- byte[] sessionId, CipherSuite suite,
- CompressionMethod comp, List extensions)
+ public int length ()
{
- this.version = version;
- this.random = random;
- this.sessionId = sessionId;
- this.suite = suite;
- this.comp = comp;
- this.extensions = extensions;
+ 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;
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static ServerHello read(InputStream in) throws IOException
+ /**
+ * 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()
{
- ProtocolVersion vers = ProtocolVersion.read(in);
- Random rand = Random.read(in);
- byte[] id = new byte[in.read() & 0xFF];
- in.read(id);
- CipherSuite suite = CipherSuite.read(in).resolve(vers);
- CompressionMethod comp = CompressionMethod.read(in);
- List ext = null;
- if (in.available() > 0)
- {
- ext = new LinkedList();
- int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- Extension e = Extension.read(in);
- ext.add(e);
- count += e.getValue().length + 4;
- }
- }
- return new ServerHello(vers, rand, id, suite, comp, ext);
+ return ProtocolVersion.getInstance (buffer.getShort (0));
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ /**
+ * 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()
{
- version.write(out);
- random.write(out);
- out.write(sessionId.length);
- out.write(sessionId);
- suite.write(out);
- out.write(comp.getValue());
- if (extensions != null)
- {
- ByteArrayOutputStream out2 = new ByteArrayOutputStream();
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- ((Extension) i.next()).write(out2);
- out.write(out2.size() >>> 8 & 0xFF);
- out.write(out2.size() & 0xFF);
- out2.writeTo(out);
- }
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
}
- ProtocolVersion getVersion()
+ /**
+ * Returns the session ID. This method returns a new byte array with
+ * the session ID bytes.
+ *
+ * @return The session ID.
+ */
+ public byte[] sessionId()
{
- return version;
+ int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+ byte[] sessionId = new byte[idlen];
+ buffer.position (SESSID_OFFSET2);
+ buffer.get (sessionId);
+ return sessionId;
}
- Random getRandom()
+ /**
+ * 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()
{
- return random;
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF);
+ return CipherSuite.forValue(buffer.getShort(offset)).resolve();
}
- byte[] getSessionId()
+ /**
+ * Returns the server's chosen compression method.
+ *
+ * @return The chosen compression method.
+ */
+ public CompressionMethod compressionMethod()
{
- return (byte[]) sessionId.clone();
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2;
+ return CompressionMethod.getInstance(buffer.get(offset) & 0xFF);
}
- CipherSuite getCipherSuite()
+ public int extensionsLength()
{
- return suite;
+ int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+ if (offset + 1 >= buffer.limit())
+ return 0;
+ return buffer.getShort(offset) & 0xFFFF;
}
-
- CompressionMethod getCompressionMethod()
+
+ public ExtensionList extensions ()
{
- return comp;
+ 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);
}
- List getExtensions()
+ public String toString()
{
- return extensions;
+ return toString(null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" version = " + version + ";");
- BufferedReader r = new BufferedReader(new StringReader(random.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
- out.println(" cipherSuite = " + suite + ";");
- out.println(" compressionMethod = " + comp + ";");
- if (extensions != null)
- {
- out.println(" extensions = {");
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- r = new BufferedReader(new StringReader(i.next().toString()));
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println(" };");
- }
- out.println("} ServerHello;");
+ 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();
}
}
diff --git a/gnu/javax/net/ssl/provider/ServerHelloBuilder.java b/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
new file mode 100644
index 000000000..09ad1d9e8
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerHelloDone.java b/gnu/javax/net/ssl/provider/ServerHelloDone.java
new file mode 100644
index 000000000..e09772250
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerHelloDone.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/gnu/javax/net/ssl/provider/ServerKeyExchange.java
index 583041593..1206ae6b2 100644
--- a/gnu/javax/net/ssl/provider/ServerKeyExchange.java
+++ b/gnu/javax/net/ssl/provider/ServerKeyExchange.java
@@ -38,249 +38,136 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-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.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPublicKey;
-
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHParameterSpec;
-
-import javax.net.ssl.SSLProtocolException;
-
-import gnu.javax.crypto.key.dh.GnuDHPublicKey;
-import gnu.javax.crypto.key.srp6.SRPPublicKey;
-
-class ServerKeyExchange implements Handshake.Body
+/**
+ * The server key exchange message.
+ *
+ * <pre>
+struct
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private PublicKey publicKey;
- private Signature signature;
- private byte[] srpSalt;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- ServerKeyExchange(PublicKey publicKey, Signature signature)
- {
- this(publicKey, signature, null);
- }
-
- ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt)
+ select (KeyExchangeAlgorithm)
{
- this.publicKey = publicKey;
- this.signature = signature;
- this.srpSalt = srpSalt;
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static ServerKeyExchange read(InputStream in, CipherSuite suite,
- PublicKey serverKey)
- throws IOException
- {
- DataInputStream din = new DataInputStream(in);
- PublicKey key = null;
- byte[] salt = null;
- String kex = suite.getKeyExchange();
- if (kex.equals("DHE"))
- {
- BigInteger p, g, y;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- p = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- g = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- y = new BigInteger(1, buf);
- key = new GnuDHPublicKey(null, p, g, y);
- }
- else if (kex.equals("RSA"))
- {
- BigInteger n, e;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- n = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- e = new BigInteger(1, buf);
- key = new JessieRSAPublicKey(n, e);
- }
- else if (kex.equals("SRP"))
- {
- BigInteger N, g, B;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- N = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- g = new BigInteger(1, buf);
- salt = new byte[din.readUnsignedByte()];
- din.readFully(salt);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- B = new BigInteger(1, buf);
- try
- {
- key = new SRPPublicKey(N, g, B);
- }
- catch (IllegalArgumentException iae)
- {
- throw new SSLProtocolException(iae.getMessage());
- }
- }
- else
- {
- throw new SSLProtocolException("invalid kex algorithm");
- }
-
- Signature sig = null;
- if (!suite.getSignature().equals("anon"))
- {
- sig = Signature.read(in, suite, serverKey);
- }
- return new ServerKeyExchange(key, sig, salt);
- }
+ 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
+{
- // Instance methods.
- // -------------------------------------------------------------------------
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
- public void write(OutputStream out) throws IOException
+ public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite)
{
- write(out, ProtocolVersion.TLS_1);
+ suite.getClass();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
}
- public void write(OutputStream out, ProtocolVersion version)
- throws IOException
+ public int length ()
{
- if (publicKey instanceof DHPublicKey)
- {
- writeBigint(out, ((DHPublicKey) publicKey).getParams().getP());
- writeBigint(out, ((DHPublicKey) publicKey).getParams().getG());
- writeBigint(out, ((DHPublicKey) publicKey).getY());
- }
- else if (publicKey instanceof RSAPublicKey)
- {
- writeBigint(out, ((RSAPublicKey) publicKey).getModulus());
- writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent());
- }
- else if (publicKey instanceof SRPPublicKey)
- {
- writeBigint(out, ((SRPPublicKey) publicKey).getN());
- writeBigint(out, ((SRPPublicKey) publicKey).getG());
- out.write(srpSalt.length);
- out.write(srpSalt);
- writeBigint(out, ((SRPPublicKey) publicKey).getY());
- }
- if (signature != null)
- {
- signature.write(out, version);
- }
+ 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;
}
- PublicKey getPublicKey()
+ /**
+ * 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 ()
{
- return publicKey;
+ 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);
}
- Signature getSignature()
+ /**
+ * Returns the digital signature made over the key exchange parameters.
+ *
+ * @return The signature.
+ */
+ public Signature signature ()
{
- return 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 ());
}
- byte[] getSRPSalt()
+ public String toString()
{
- return srpSalt;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.println(" publicKey = struct {");
- if (publicKey instanceof DHPublicKey)
- {
- out.println(" p = " +
- ((DHPublicKey) publicKey).getParams().getP().toString(16) +
- ";");
- out.println(" g = " +
- ((DHPublicKey) publicKey).getParams().getG().toString(16) +
- ";");
- out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) +
- ";");
- out.println(" } DHPublicKey;");
- }
- else if (publicKey instanceof RSAPublicKey)
+ if (prefix != null) out.print (prefix);
+ out.print (" algorithm: ");
+ out.print (suite.keyExchangeAlgorithm ());
+ out.println (";");
+ if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
{
- out.println(" modulus = " +
- ((RSAPublicKey) publicKey).getModulus().toString(16) +
- ";");
- out.println(" exponent = " +
- ((RSAPublicKey) publicKey).getPublicExponent().toString(16) +
- ";");
- out.println(" } RSAPublicKey;");
+ if (prefix != null) out.print (prefix);
+ out.println (" parameters:");
+ out.println (params ().toString (prefix != null ? prefix+" " : " "));
}
- else if (publicKey instanceof SRPPublicKey)
+ if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS))
{
- out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";");
- out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";");
- out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";");
- out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";");
- out.println(" } SRPPublicKey;");
+ if (prefix != null) out.print (prefix);
+ out.println (" signature:");
+ out.println (signature ().toString (prefix != null ? prefix+" " : " "));
}
- if (signature != null)
- {
- out.println(" signature =");
- BufferedReader r = new BufferedReader(new StringReader(signature.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println("} ServerKeyExchange;");
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerKeyExchange;");
return str.toString();
}
-
- private void writeBigint(OutputStream out, BigInteger bigint)
- throws IOException
- {
- byte[] b = bigint.toByteArray();
- if (b[0] == 0x00)
- {
- out.write((b.length - 1) >>> 8 & 0xFF);
- out.write((b.length - 1) & 0xFF);
- out.write(b, 1, b.length - 1);
- }
- else
- {
- out.write(b.length >>> 8 & 0xFF);
- out.write(b.length & 0xFF);
- out.write(b);
- }
- }
}
diff --git a/gnu/javax/net/ssl/provider/RecordInputStream.java b/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
index 14cf829ac..d4b6fa397 100644
--- a/gnu/javax/net/ssl/provider/RecordInputStream.java
+++ b/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
@@ -1,4 +1,4 @@
-/* RecordInputStream.java -- record layer input stream interface.
+/* ServerKeyExchangeBuilder.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,74 +33,57 @@ 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. */
+exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-import java.io.InputStream;
+import java.nio.ByteBuffer;
-class RecordInputStream extends InputStream
+/**
+ * Builder for {@link ServerKeyExchange} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerKeyExchangeBuilder extends ServerKeyExchange
+ implements Builder
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- /**
- * The record input instance.
- */
- private final RecordInput in;
-
- /**
- * The content type this stream is reading.
- */
- private final ContentType type;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordInputStream (RecordInput in, ContentType type)
+ public ServerKeyExchangeBuilder(final CipherSuite suite)
{
- this.in = in;
- this.type = type;
+ super(ByteBuffer.allocate(1024), suite);
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public int available () throws IOException
- {
- return in.available (type);
- }
-
- public int read () throws IOException
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
{
- byte[] b = new byte[1];
- int ret;
- while ((ret = read (b)) != 1)
- {
- if (ret == -1)
- {
- return -1;
- }
- Thread.yield ();
- }
- return b[0] & 0xFF;
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- public int read (byte[] buf) throws IOException
+ public void setParams(ByteBuffer params)
{
- return read (buf, 0, buf.length);
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ throw new IllegalArgumentException("key exchange algorithm is none");
+ ensureCapacity(params.remaining());
+ buffer.duplicate().put(params);
}
-
- public int read (byte[] buf, int off, int len) throws IOException
+
+ public void setSignature(ByteBuffer signature)
{
- return in.read (buf, off, len, type);
+ 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 String toString ()
+
+ public void ensureCapacity(int capacity)
{
- return RecordInputStream.class.getName () + " [ type=" + type + " ]";
+ if (buffer.capacity() >= capacity)
+ return;
+ ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+ newBuffer.duplicate().put(buffer);
+ buffer = newBuffer;
}
}
diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java b/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
new file mode 100644
index 000000000..cb523650f
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
@@ -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 ();
+}
diff --git a/gnu/javax/net/ssl/provider/ServerNameList.java b/gnu/javax/net/ssl/provider/ServerNameList.java
new file mode 100644
index 000000000..5a268f542
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerNameList.java
@@ -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;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/gnu/javax/net/ssl/provider/ServerPSKParameters.java
new file mode 100644
index 000000000..8acce6dde
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerPSKParameters.java
@@ -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();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerRSAParams.java b/gnu/javax/net/ssl/provider/ServerRSAParams.java
new file mode 100644
index 000000000..ff265ce8a
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerRSAParams.java
@@ -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 ();
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
new file mode 100644
index 000000000..0d7b590d2
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/Session.java b/gnu/javax/net/ssl/provider/Session.java
deleted file mode 100644
index e13758b03..000000000
--- a/gnu/javax/net/ssl/provider/Session.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/* Session.java -- SSL and TLS session data.
- 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.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLPermission;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-import javax.security.cert.X509Certificate;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-/**
- * A generic SSL session implementation for SSL and TLS.
- */
-final class Session implements SSLSession
-{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION =
- new SSLPermission("getSSLSessionContext");
-
- private final long creationTime;
- private Date lastAccessedTime;
- ID sessionId;
- Certificate[] localCerts;
- Certificate[] peerCerts;
- X509Certificate[] peerCertChain;
- String peerHost;
- boolean peerVerified;
- SessionContext context;
- HashMap values;
- boolean valid;
- List enabledSuites;
- CipherSuite cipherSuite;
- SortedSet enabledProtocols;
- ProtocolVersion protocol;
- byte[] masterSecret;
- SRPTrustManager srpTrustManager;
- X509TrustManager trustManager;
- X509KeyManager keyManager;
- SecureRandom random;
- SecurityParameters params;
- Alert currentAlert;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- Session()
- {
- this(System.currentTimeMillis());
- }
-
- Session(long creationTime)
- {
- peerVerified = false;
- valid = true;
- this.creationTime = creationTime;
- lastAccessedTime = new Date(0L);
- values = new HashMap();
- if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce")))
- params = new JCESecurityParameters();
- else
- params = new GNUSecurityParameters (this);
- }
-
- // Public instance methods.
- // -------------------------------------------------------------------------
-
- protected Object clone()
- {
- Session result = new Session(creationTime);
- result.lastAccessedTime = lastAccessedTime;
- result.sessionId = sessionId;
- result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null);
- result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null);
- result.peerHost = peerHost;
- result.peerVerified = peerVerified;
- result.context = context;
- result.values = values;
- result.enabledSuites = new ArrayList(enabledSuites);
- result.cipherSuite = cipherSuite;
- result.enabledProtocols = new TreeSet(enabledProtocols);
- result.protocol = protocol;
- result.masterSecret = masterSecret;
- result.keyManager = keyManager;
- result.srpTrustManager = srpTrustManager;
- result.trustManager = trustManager;
- result.random = random;
- return result;
- }
-
- public String getCipherSuite()
- {
- return cipherSuite.toString();
- }
-
- public long getCreationTime()
- {
- return creationTime;
- }
-
- public byte[] getId()
- {
- return (sessionId != null ? sessionId.getId() : null);
- }
-
- public long getLastAccessedTime()
- {
- return lastAccessedTime.getTime();
- }
-
- public Certificate[] getLocalCertificates()
- {
- return (Certificate[]) (localCerts != null ? localCerts.clone() : null);
- }
-
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
- {
- if (!peerVerified)
- {
- throw new SSLPeerUnverifiedException("peer not verified");
- }
- return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null);
- }
-
- public X509Certificate[] getPeerCertificateChain()
- throws SSLPeerUnverifiedException
- {
- if (!peerVerified)
- {
- throw new SSLPeerUnverifiedException("peer not verified");
- }
- if (peerCerts == null)
- {
- return null;
- }
- if (peerCertChain != null)
- {
- return (X509Certificate[]) peerCertChain.clone();
- }
- try
- {
- peerCertChain = new X509Certificate[peerCerts.length];
- for (int i = 0; i < peerCerts.length; i++)
- {
- peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded());
- }
- return (X509Certificate[]) peerCertChain.clone();
- }
- catch (javax.security.cert.CertificateException ce)
- {
- return null;
- }
- catch (CertificateException ce2)
- {
- return null;
- }
- }
-
- public String getPeerHost()
- {
- return peerHost;
- }
-
- public String getProtocol()
- {
- return protocol.toString();
- }
-
- public SSLSessionContext getSessionContext()
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- {
- sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION);
- }
- return context;
- }
-
- public String[] getValueNames()
- {
- Set names = values.keySet();
- return (String[]) names.toArray(new String[names.size()]);
- }
-
- public Object getValue(String name)
- {
- return values.get(name);
- }
-
- public void putValue(String name, Object value)
- {
- values.put(name, value);
- if (value instanceof SSLSessionBindingListener)
- {
- ((SSLSessionBindingListener) value).valueBound(
- new SSLSessionBindingEvent(this, name));
- }
- }
-
- public void removeValue(String name)
- {
- Object value = values.remove(name);
- if (value != null && (value instanceof SSLSessionBindingListener))
- {
- ((SSLSessionBindingListener) value).valueUnbound(
- new SSLSessionBindingEvent(this, name));
- }
- }
-
- public void invalidate()
- {
- if (masterSecret != null)
- {
- for (int i = 0; i < masterSecret.length; i++)
- {
- masterSecret[i] = 0;
- }
- masterSecret = null;
- }
- valid = false;
- }
-
- synchronized void access()
- {
- lastAccessedTime.setTime(System.currentTimeMillis());
- context.notifyAccess(this);
- }
-
- void setLastAccessedTime(long lastAccessedTime)
- {
- this.lastAccessedTime.setTime(lastAccessedTime);
- }
-
- // Inner classes.
- // -------------------------------------------------------------------------
-
- /**
- * A byte array with appropriate <code>equals()</code>,
- * <code>hashCode()</code>, and <code>compareTo()</code> semantics.
- */
- static final class ID implements Comparable
- {
-
- // Fields.
- // -----------------------------------------------------------------------
-
- /** The ID itself. */
- private final byte[] id;
-
- // Constructor.
- // -----------------------------------------------------------------------
-
- /**
- * Creates a new ID.
- *
- * @param id The ID. The array is not cloned.
- */
- ID(byte[] id)
- {
- if (id == null)
- {
- throw new IllegalArgumentException();
- }
- this.id = id;
- }
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getId()
- {
- return (byte[]) id.clone();
- }
-
- public boolean equals(Object other)
- {
- if (other == null || !(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)
- {
- if (other == null || !(other instanceof ID))
- {
- return 1;
- }
- 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] < id2[i])
- {
- return -1;
- }
- else if (id[i] > id2[i])
- {
- return 1;
- }
- }
- return 0;
- }
-
- public String toString()
- {
- return Util.toHexString(id, ':');
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SessionContext.java b/gnu/javax/net/ssl/provider/SessionContext.java
deleted file mode 100644
index 9e265429a..000000000
--- a/gnu/javax/net/ssl/provider/SessionContext.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/* SessionContext.java -- Implementation of a session context.
- 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.Security;
-
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Vector;
-
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-
-/**
- * A collection of SSL sessions. This implementation is a memory-only
- * store; subclasses may implement persistent storage.
- */
-class SessionContext implements SSLSessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- /** The map of Session.ID objects to Sessions. */
- protected final HashMap sessions;
-
- /** The number of sessions to cache. */
- protected int cacheSize;
-
- /** The session timeout, in seconds. */
- protected int timeout;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SessionContext()
- {
- sessions = new HashMap();
- cacheSize = 0;
- try
- {
- timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout"));
- }
- catch (Exception x)
- {
- // Default 24-hour timeout.
- timeout = 86400;
- }
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized Enumeration getIds()
- {
- Vector ids = new Vector();
- for(Iterator i = sessions.keySet().iterator(); i.hasNext(); )
- {
- Session.ID id = (Session.ID) i.next();
- ids.add(id.getId());
- }
- return ids.elements();
- }
-
- public synchronized SSLSession getSession(byte[] sessionId)
- {
- Session session = (Session) sessions.get(new Session.ID(sessionId));
- if (session == null)
- return null;
- long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
- if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(session.sessionId);
- session.invalidate();
- return null;
- }
- if (!session.valid)
- {
- removeSession(session.sessionId);
- session.invalidate();
- return null;
- }
- return session;
- }
-
- public int getSessionCacheSize()
- {
- return cacheSize;
- }
-
- public void setSessionCacheSize(int cacheSize)
- {
- if (cacheSize < 0)
- throw new IllegalArgumentException();
- this.cacheSize = cacheSize;
- }
-
- public int getSessionTimeout()
- {
- return timeout;
- }
-
- public void setSessionTimeout(int timeout)
- {
- if (timeout <= 0)
- throw new IllegalArgumentException();
- this.timeout = timeout;
- }
-
- public String toString()
- {
- return sessions.keySet().toString();
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- /**
- * Adds a session to this context. This method:
- *
- * <ol>
- * <li>Will do nothing if the cache already contains the given ID.</li>
- * <li>Will do nothing if the cache limit has been reached (and is
- * not zero).</li>
- * <li>Will remove any invalid sessions in the cache before trying to insert
- * the new one.</li>
- * <li>Will remove any expired sessions before trying to insert the new
- * one.</li>
- * </ol>
- *
- * @param sessionId This session's ID.
- * @param session The session to add.
- * @return True if the session was added, false otherwise.
- */
- synchronized boolean addSession(Session.ID sessionId, Session session)
- {
- if (sessions.containsKey(sessionId))
- return false;
- if (cacheSize > 0 && sessions.size() > cacheSize)
- {
- boolean removed = false;
- for (Iterator i = sessions.values().iterator(); i.hasNext(); )
- {
- Session s = (Session) i.next();
- long elapsed = System.currentTimeMillis() - s.getCreationTime();
- if (!s.valid)
- {
- removeSession(session.sessionId);
- removed = true;
- }
- else if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(session.sessionId);
- removed = true;
- }
- }
- if (removed)
- {
- sessions.put(sessionId, session);
- session.context = this;
- session.sessionId = sessionId;
- return true;
- }
- return false;
- }
- else
- {
- sessions.put(sessionId, session);
- session.context = this;
- session.sessionId = sessionId;
- return true;
- }
- }
-
- /**
- * Returns whether or not a session with the given ID is cached by this
- * context.
- */
- synchronized boolean containsSessionID(Session.ID sessionId)
- {
- Session s = (Session) sessions.get(sessionId);
- if (s == null)
- {
- return false;
- }
- long elapsed = System.currentTimeMillis() - s.getCreationTime();
- if (!s.valid || (int) (elapsed / 1000) > timeout)
- {
- removeSession(sessionId);
- return false;
- }
- return true;
- }
-
- /**
- * Removes a session from this context.
- *
- * @param sessionId The ID of the session to remove.
- */
- synchronized boolean removeSession(Session.ID sessionId)
- {
- return sessions.remove(sessionId) != null;
- }
-
- /**
- * Notifies this context of an access event on a session.
- *
- * @param session The session that was accessed.
- */
- void notifyAccess(Session session)
- {
- }
-}
diff --git a/gnu/javax/net/ssl/provider/SessionImpl.java b/gnu/javax/net/ssl/provider/SessionImpl.java
new file mode 100644
index 000000000..86dcb4915
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SessionImpl.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/Signature.java b/gnu/javax/net/ssl/provider/Signature.java
index c9be64143..8c6cfadc7 100644
--- a/gnu/javax/net/ssl/provider/Signature.java
+++ b/gnu/javax/net/ssl/provider/Signature.java
@@ -1,4 +1,4 @@
-/* Signature.java -- SSL signature message.
+/* Signature.java -- SSL Signature structure.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -49,6 +49,8 @@ import java.io.StringWriter;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
import java.security.PublicKey;
import java.security.interfaces.RSAKey;
@@ -56,103 +58,115 @@ import java.util.Arrays;
import gnu.java.security.der.*;
-class Signature implements Constructed
+/**
+ * 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 Object sigValue;
- private final String sigAlg;
+ private final ByteBuffer buffer;
+ private final SignatureAlgorithm alg;
// Constructor.
// -------------------------------------------------------------------------
- Signature(Object sigValue, String sigAlg)
+ public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg)
{
- this.sigValue = sigValue;
- this.sigAlg = sigAlg;
+ this.buffer = buffer;
+ this.alg = alg;
}
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static Signature read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+
+ public Signature (final byte[] sigValue, final SignatureAlgorithm alg)
{
- Object sigValue = null;
- DataInputStream din = new DataInputStream(in);
- int len = din.readUnsignedShort();
- sigValue = new byte[len];
- din.readFully((byte[]) sigValue);
- if (suite.getSignature() == "DSS")
- {
- DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue));
- if (der.read().getTag() != DER.SEQUENCE)
- {
- throw new IOException("expecting DER SEQUENCE");
- }
- BigInteger r = (BigInteger) der.read().getValue();
- BigInteger s = (BigInteger) der.read().getValue();
- sigValue = new BigInteger[] { r, s };
- }
- return new Signature(sigValue, suite.getSignature());
+ buffer = ByteBuffer.allocate(sigValue.length + 2);
+ buffer.putShort((short) sigValue.length);
+ buffer.put(sigValue);
+ buffer.position(0);
+ this.alg = alg;
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ 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 ()
{
- write(out, ProtocolVersion.TLS_1);
+ 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 write(OutputStream out, ProtocolVersion version)
- throws IOException
+ public void setSignature (final byte[] signature)
{
- byte[] result = null;
- if (sigValue instanceof byte[])
- {
- result = (byte[]) sigValue;
- }
- else
- {
- DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]);
- DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]);
- DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED,
- Arrays.asList(new Object[] { r, s }));
- result = sig.getEncoded();
- }
- out.write(result.length >>> 8 & 0xFF);
- out.write(result.length & 0xFF);
- out.write(result);
+ setSignature (signature, 0, signature.length);
}
- Object getSigValue()
+ public void setSignature (final byte[] signature, final int offset, final int length)
{
- return sigValue;
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return;
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (signature, offset, length);
}
- String getSigAlg()
+ public String toString ()
{
- return sigAlg;
+ return toString (null);
}
- public String toString()
+ 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 (sigAlg.equals("RSA"))
- {
- out.print(Util.hexDump((byte[]) sigValue, " "));
- }
- else
+ if (!alg.equals (SignatureAlgorithm.ANONYMOUS))
{
- out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";");
- out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.print (Util.hexDump (signature (), subprefix));
}
- out.println("} Signature;");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Signature;");
return str.toString();
}
}
diff --git a/gnu/javax/net/ssl/provider/SignatureAlgorithm.java b/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
new file mode 100644
index 000000000..a789576db
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
@@ -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;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/SimpleSessionContext.java b/gnu/javax/net/ssl/provider/SimpleSessionContext.java
new file mode 100644
index 000000000..b9d0f9551
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/SimpleSessionContext.java
@@ -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;
+ }
+
+}
diff --git a/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/gnu/javax/net/ssl/provider/SynchronizedRandom.java
deleted file mode 100644
index 4e22f08be..000000000
--- a/gnu/javax/net/ssl/provider/SynchronizedRandom.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/* SynchronizedRandom.java -- Thread-safe IRandom wrapper.
- 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.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-
-class SynchronizedRandom implements IRandom
-{
-
- // Field.
- // -------------------------------------------------------------------------
-
- private final IRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SynchronizedRandom(IRandom random)
- {
- this.random = random;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String name()
- {
- return random.name();
- }
-
- public synchronized void init(Map attrib)
- {
- random.init(attrib);
- }
-
- public synchronized byte nextByte()
- throws IllegalStateException, LimitReachedException
- {
- return random.nextByte();
- }
-
- public synchronized void nextBytes(byte[] buf, int off, int len)
- throws IllegalStateException, LimitReachedException
- {
- random.nextBytes(buf, off, len);
- }
-
- public synchronized Object clone()
- throws CloneNotSupportedException
- {
- return new SynchronizedRandom((IRandom) random.clone());
- }
-
- // 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)
- {
- }
-}
diff --git a/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/gnu/javax/net/ssl/provider/TruncatedHMAC.java
index 1997458dd..0595f87a7 100644
--- a/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java
+++ b/gnu/javax/net/ssl/provider/TruncatedHMAC.java
@@ -1,4 +1,4 @@
-/* JessieDHPrivateKey.java -- simple DH private key.
+/* TruncatedHMAC.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,62 +38,39 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.math.BigInteger;
+import gnu.javax.net.ssl.provider.Extension.Value;
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.spec.DHParameterSpec;
+import java.nio.ByteBuffer;
-class JessieDHPrivateKey implements DHPrivateKey
+/**
+ * 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
{
- // Fields.
- // -------------------------------------------------------------------------
-
- private final DHParameterSpec params;
- private final BigInteger x;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieDHPrivateKey(DHParameterSpec params, BigInteger x)
+ public int length()
{
- this.params = params;
- this.x = x;
+ return 0;
}
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
+
+ public ByteBuffer buffer()
{
- return "Diffie-Hellman";
+ return ByteBuffer.wrap(new byte[0]);
}
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
- {
- return null;
- }
-
- public DHParameterSpec getParams()
- {
- return params;
- }
-
- public BigInteger getX()
+
+ public String toString()
{
- return x;
+ return toString(null);
}
- public String toString()
+ public String toString(String prefix)
{
- String nl = System.getProperty("line.separator");
- return "P: " + params.getP() + nl +
- "G: " + params.getG() + nl +
- "X: " + x;
+ String s = "TruncatedHMAC;";
+ if (prefix != null)
+ s = prefix + s;
+ return s;
}
}
diff --git a/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/gnu/javax/net/ssl/provider/TrustedAuthorities.java
new file mode 100644
index 000000000..1e4b17359
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/TrustedAuthorities.java
@@ -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;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
index dc6587288..2094daf90 100644
--- a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java
+++ b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
@@ -1,4 +1,4 @@
-/* JessieDHPublicKey.java -- simple DH public key.
+/* UnresolvedExtensionValue.jav --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,62 +38,46 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.math.BigInteger;
+import gnu.javax.net.ssl.provider.Extension.Value;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHParameterSpec;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
-class JessieDHPublicKey implements DHPublicKey
+public class UnresolvedExtensionValue extends Value
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final DHParameterSpec params;
- private final BigInteger y;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieDHPublicKey(DHParameterSpec params, BigInteger y)
+ private final ByteBuffer buffer;
+
+ public UnresolvedExtensionValue (final ByteBuffer buffer)
{
- this.params = params;
- this.y = y;
+ this.buffer = buffer;
}
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
+
+ public int length()
{
- return "Diffie-Hellman";
+ return buffer.limit();
}
-
- public String getFormat()
+
+ public ByteBuffer buffer()
{
- return "NONE";
+ return value();
}
-
- public byte[] getEncoded()
+
+ public ByteBuffer value()
{
- return null;
+ return buffer.slice();
}
-
- public DHParameterSpec getParams()
- {
- return params;
- }
-
- public BigInteger getY()
+
+ public String toString()
{
- return y;
+ return toString(null);
}
-
- public String toString()
+
+ public String toString(final String prefix)
{
- String nl = System.getProperty("line.separator");
- return "P: " + params.getP() + nl +
- "G: " + params.getG() + nl +
- "Y: " + y;
+ String s = Util.hexDump(buffer);
+ if (prefix != null)
+ s = prefix + s;
+ return s;
}
}
diff --git a/gnu/javax/net/ssl/provider/Util.java b/gnu/javax/net/ssl/provider/Util.java
index 15790dd26..ba8ea7db7 100644
--- a/gnu/javax/net/ssl/provider/Util.java
+++ b/gnu/javax/net/ssl/provider/Util.java
@@ -38,11 +38,16 @@ 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;
@@ -52,7 +57,7 @@ import java.security.Security;
*
* @author Casey Marshall (rsdio@metastatic.org)
*/
-final class Util
+public final class Util
{
// Constants.
@@ -66,13 +71,40 @@ final class 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.
*/
- static byte[] toByteArray(String hex)
+ public static byte[] toByteArray(String hex)
{
hex = hex.toLowerCase();
byte[] buf = new byte[hex.length() / 2];
@@ -94,7 +126,7 @@ final class Util
* @param len The number of bytes to format.
* @return A hexadecimal representation of the specified bytes.
*/
- static String toHexString(byte[] buf, int off, int len)
+ public static String toHexString(byte[] buf, int off, int len)
{
StringBuffer str = new StringBuffer();
for (int i = 0; i < len; i++)
@@ -108,7 +140,7 @@ final class Util
/**
* See {@link #toHexString(byte[],int,int)}.
*/
- static String toHexString(byte[] buf)
+ public static String toHexString(byte[] buf)
{
return Util.toHexString(buf, 0, buf.length);
}
@@ -123,7 +155,7 @@ final class Util
* @param sep The character to insert between octets.
* @return A hexadecimal representation of the specified bytes.
*/
- static String toHexString(byte[] buf, int off, int len, char sep)
+ public static String toHexString(byte[] buf, int off, int len, char sep)
{
StringBuffer str = new StringBuffer();
for (int i = 0; i < len; i++)
@@ -139,7 +171,7 @@ final class Util
/**
* See {@link #toHexString(byte[],int,int,char)}.
*/
- static String toHexString(byte[] buf, char sep)
+ public static String toHexString(byte[] buf, char sep)
{
return Util.toHexString(buf, 0, buf.length, sep);
}
@@ -159,7 +191,7 @@ final class Util
* @param prefix A string to prepend to every line.
* @return The formatted string.
*/
- static String hexDump(byte[] buf, int off, int len, String prefix)
+ public static String hexDump(byte[] buf, int off, int len, String prefix)
{
String nl = getProperty("line.separator");
StringBuffer str = new StringBuffer();
@@ -172,7 +204,7 @@ final class Util
str.append(" ");
String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' ');
str.append(s);
- for (int j = 56 - (56 - s.length()); j < 56; j++)
+ for (int j = s.length(); j < 49; j++)
str.append(" ");
for (int j = 0; j < Math.min(16, len - i); j++)
{
@@ -187,10 +219,49 @@ final class Util
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)}.
*/
- static String hexDump(byte[] buf, int off, int len)
+ public static String hexDump(byte[] buf, int off, int len)
{
return hexDump(buf, off, len, "");
}
@@ -198,7 +269,7 @@ final class Util
/**
* See {@link #hexDump(byte[],int,int,String)}.
*/
- static String hexDump(byte[] buf, String prefix)
+ public static String hexDump(byte[] buf, String prefix)
{
return hexDump(buf, 0, buf.length, prefix);
}
@@ -206,7 +277,7 @@ final class Util
/**
* See {@link #hexDump(byte[],int,int,String)}.
*/
- static String hexDump(byte[] buf)
+ public static String hexDump(byte[] buf)
{
return hexDump(buf, 0, buf.length);
}
@@ -220,7 +291,7 @@ final class Util
* zero-padded to this length, but may be longer.
* @return The formatted integer.
*/
- static String formatInt(int i, int radix, int len)
+ public static String formatInt(int i, int radix, int len)
{
String s = Integer.toString(i, radix);
StringBuffer buf = new StringBuffer();
@@ -237,7 +308,7 @@ final class Util
* @param b2 The second byte array.
* @return The concatenation of b1 and b2.
*/
- static byte[] concat(byte[] b1, byte[] 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);
@@ -248,7 +319,7 @@ final class Util
/**
* See {@link #trim(byte[],int,int)}.
*/
- static byte[] trim(byte[] buffer, int len)
+ public static byte[] trim(byte[] buffer, int len)
{
return trim(buffer, 0, len);
}
@@ -266,7 +337,7 @@ final class Util
* length.
* @return The trimmed byte array.
*/
- static byte[] trim(byte[] buffer, int off, int len)
+ public static byte[] trim(byte[] buffer, int off, int len)
{
if (off < 0 || len < 0 || off > buffer.length)
throw new IndexOutOfBoundsException("max=" + buffer.length +
@@ -286,7 +357,7 @@ final class Util
* @return The byte representation of the big integer, with any leading
* zero removed.
*/
- static byte[] trim(BigInteger bi)
+ public static byte[] trim(BigInteger bi)
{
byte[] buf = bi.toByteArray();
if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO))
@@ -305,7 +376,7 @@ final class Util
*
* @return The current time, in seconds.
*/
- static int unixTime()
+ public static int unixTime()
{
return (int) (System.currentTimeMillis() / 1000L);
}
@@ -385,7 +456,7 @@ final class Util
* @throws SecurityException If the Jessie code still does not have
* permission to read the property.
*/
- static String getProperty(final String name)
+ @Deprecated static String getProperty(final String name)
{
return (String) AccessController.doPrivileged(
new PrivilegedAction()
@@ -407,7 +478,7 @@ final class Util
* @throws SecurityException If the Jessie code still does not have
* permission to read the property.
*/
- static String getSecurityProperty(final String name)
+ @Deprecated static String getSecurityProperty(final String name)
{
return (String) AccessController.doPrivileged(
new PrivilegedAction()
diff --git a/gnu/javax/net/ssl/provider/X500PrincipalList.java b/gnu/javax/net/ssl/provider/X500PrincipalList.java
new file mode 100644
index 000000000..1c88479cb
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/X500PrincipalList.java
@@ -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
diff --git a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
index 476655c45..dc7728866 100644
--- a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
+++ b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
@@ -54,7 +54,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
-import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -76,6 +75,8 @@ 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;
@@ -122,13 +123,17 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
else if (params instanceof PrivateCredentials)
{
- List chains = ((PrivateCredentials) params).getCertChains();
- List keys = ((PrivateCredentials) params).getPrivateKeys();
+ List<X509Certificate[]> chains
+ = ((PrivateCredentials) params).getCertChains();
+ List<PrivateKey> keys
+ = ((PrivateCredentials) params).getPrivateKeys();
int i = 0;
- HashMap certMap = new HashMap();
- HashMap keyMap = new HashMap();
- Iterator c = chains.iterator();
- Iterator k = keys.iterator();
+ 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());
@@ -171,8 +176,9 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
}
- HashMap p = new HashMap();
- HashMap c = new HashMap();
+ 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())
@@ -236,18 +242,19 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
// Inner class.
// -------------------------------------------------------------------------
- private class Manager implements X509KeyManager
+ private class Manager extends X509ExtendedKeyManager
{
// Fields.
// -----------------------------------------------------------------------
- private final Map privateKeys;
- private final Map certChains;
+ private final Map<String, PrivateKey> privateKeys;
+ private final Map<String, X509Certificate[]> certChains;
// Constructor.
// -----------------------------------------------------------------------
- Manager(Map privateKeys, Map certChains)
+ Manager(Map<String, PrivateKey> privateKeys,
+ Map<String, X509Certificate[]> certChains)
{
this.privateKeys = privateKeys;
this.certChains = certChains;
@@ -267,6 +274,19 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
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)
{
@@ -281,6 +301,16 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
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)
{
@@ -289,7 +319,7 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
private String[] getAliases(String keyType, Principal[] issuers)
{
- LinkedList l = new LinkedList();
+ LinkedList<String> l = new LinkedList<String>();
for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
{
String alias = (String) i.next();
@@ -300,21 +330,27 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
if (privKey == null)
continue;
PublicKey pubKey = chain[0].getPublicKey();
- if (keyType.equals("RSA") || keyType.equals("DHE_RSA") ||
- keyType.equals("SRP_RSA") || keyType.equals("rsa_sign"))
+ 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;
}
- if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") ||
- keyType.equals("SRP_DSS"))
+ 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;
}
- if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh"))
+ else if (keyType.equalsIgnoreCase("DH_RSA")
+ || keyType.equalsIgnoreCase("rsa_fixed_dh"))
{
if (!(privKey instanceof DHPrivateKey) ||
!(pubKey instanceof DHPublicKey))
@@ -322,7 +358,8 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
continue;
}
- if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh"))
+ else if (keyType.equalsIgnoreCase("DH_DSS")
+ || keyType.equalsIgnoreCase("dss_fixed_dh"))
{
if (!(privKey instanceof DHPrivateKey) ||
!(pubKey instanceof DHPublicKey))
@@ -330,19 +367,23 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
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 (int j = 0; j < issuers.length; j++)
- if (chain[0].getIssuerDN().equals(issuers[j]))
- {
- l.add(alias);
- break;
- }
+ for (Principal issuer : issuers)
+ {
+ if (chain[0].getIssuerDN().equals(issuer))
+ {
+ l.add(alias);
+ break;
+ }
+ }
}
- return (String[]) l.toArray(new String[l.size()]);
+ return l.toArray(new String[l.size()]);
}
public X509Certificate[] getCertificateChain(String alias)
diff --git a/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
index 4f049e916..1a0591284 100644
--- a/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
+++ b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
@@ -45,17 +45,20 @@ 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.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Security;
-import java.security.SignatureException;
+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;
@@ -63,6 +66,8 @@ 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;
@@ -76,21 +81,22 @@ 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 = Util.getProperty("java.home")
- + Util.getProperty("file.separator") + "lib"
- + Util.getProperty("file.separator") + "security"
- + Util.getProperty("file.separator") + "jssecerts";
+ 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 = Util.getProperty("java.home")
- + Util.getProperty("file.separator") + "lib"
- + Util.getProperty("file.separator") + "security"
- + Util.getProperty("file.separator") + "cacerts";
+ private static final String CA_CERTS
+ = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+ + sep + "lib" + sep + "security" + sep + "cacerts";
private Manager current;
@@ -135,13 +141,14 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
{
if (store == null)
{
- String s = Util.getProperty("javax.net.ssl.trustStoreType");
+ 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 = Util.getProperty("javax.net.ssl.trustStore");
+ s = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStore"));
FileInputStream in = null;
if (s == null)
{
@@ -158,24 +165,24 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
{
in = new FileInputStream(s);
}
- String p = Util.getProperty("javax.net.ssl.trustStorePassword");
+ 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.toString());
+ throw new KeyStoreException(ioe);
}
catch (CertificateException ce)
{
- throw new KeyStoreException(ce.toString());
+ throw new KeyStoreException(ce);
}
catch (NoSuchAlgorithmException nsae)
{
- throw new KeyStoreException(nsae.toString());
+ throw new KeyStoreException(nsae);
}
}
- LinkedList l = new LinkedList();
+ LinkedList<X509Certificate> l = new LinkedList<X509Certificate>();
Enumeration aliases = store.aliases();
while (aliases.hasMoreElements())
{
@@ -185,10 +192,9 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
Certificate c = store.getCertificate(alias);
if (!(c instanceof X509Certificate))
continue;
- l.add(c);
+ l.add((X509Certificate) c);
}
- current = this.new Manager((X509Certificate[])
- l.toArray(new X509Certificate[l.size()]));
+ current = this.new Manager(l.toArray(new X509Certificate[l.size()]));
}
// Inner class.
@@ -203,14 +209,21 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
// Fields.
// -----------------------------------------------------------------------
- private final X509Certificate[] trusted;
+ private final Set<TrustAnchor> anchors;
// Constructor.
// -----------------------------------------------------------------------
Manager(X509Certificate[] trusted)
{
- this.trusted = trusted;
+ anchors = new HashSet<TrustAnchor>();
+ if (trusted != null)
+ {
+ for (X509Certificate cert : trusted)
+ {
+ anchors.add(new TrustAnchor(cert, null));
+ }
+ }
}
// Instance methodns.
@@ -230,9 +243,7 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
public X509Certificate[] getAcceptedIssuers()
{
- if (trusted == null)
- return new X509Certificate[0];
- return (X509Certificate[]) trusted.clone();
+ return anchors.toArray(new X509Certificate[anchors.size()]);
}
// Own methods.
@@ -241,58 +252,44 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
private void checkTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
- // NOTE: this is not a full-featured path validation algorithm.
- //
- // Step 0: check if the target is valid now.
- chain[0].checkValidity();
-
- // Step 1: verify that the chain is complete and valid.
- for (int i = 1; i < chain.length; i++)
+ CertPathValidator validator = null;
+
+ try
{
- chain[i].checkValidity();
- try
- {
- chain[i-1].verify(chain[i].getPublicKey());
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new CertificateException(nsae.toString());
- }
- catch (NoSuchProviderException nspe)
- {
- throw new CertificateException(nspe.toString());
- }
- catch (InvalidKeyException ike)
- {
- throw new CertificateException(ike.toString());
- }
- catch (SignatureException se)
- {
- throw new CertificateException(se.toString());
- }
+ validator = CertPathValidator.getInstance("PKIX");
}
-
- // Step 2: verify that the root of the chain was issued by a trust anchor.
- if (trusted == null || trusted.length == 0)
- throw new CertificateException("no trust anchors");
- for (int i = 0; i < trusted.length; i++)
+ catch (NoSuchAlgorithmException nsae)
{
- try
- {
- trusted[i].checkValidity();
- chain[chain.length-1].verify(trusted[i].getPublicKey());
- return;
- }
- catch (Exception e)
- {
- }
- //catch (CertificateException ce) { }
- //catch (NoSuchAlgorithmException nsae) { }
- //catch (NoSuchProviderException nspe) { }
- //catch (InvalidKeyException ike) { }
- //catch (SignatureException se) { }
+ 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);
}
- throw new CertificateException();
}
}
}
diff --git a/gnu/javax/net/ssl/provider/XMLSessionContext.java b/gnu/javax/net/ssl/provider/XMLSessionContext.java
deleted file mode 100644
index dcfa9d4ad..000000000
--- a/gnu/javax/net/ssl/provider/XMLSessionContext.java
+++ /dev/null
@@ -1,619 +0,0 @@
-/* XMLSessionContext.java -- XML-encoded persistent SSL sessions.
- 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.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateFactory;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mac.MacFactory;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.mode.ModeFactory;
-import gnu.javax.crypto.prng.IPBE;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.PRNGFactory;
-
-import gnu.javax.net.ssl.Base64;
-
-/**
- * An implementation of session contexts that stores session data on the
- * filesystem in a simple XML-encoded file.
- */
-class XMLSessionContext extends SessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final File file;
- private final IRandom pbekdf;
- private final boolean compress;
- private final SecureRandom random;
- private boolean encoding;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- XMLSessionContext() throws IOException, SAXException
- {
- file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file"));
- String password = Util.getSecurityProperty("jessie.SessionContext.xml.password");
- compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue();
- if (password == null)
- {
- password = "";
- }
- pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1");
- HashMap kdfattr = new HashMap();
- kdfattr.put(IPBE.PASSWORD, password.toCharArray());
- // Dummy salt. This is replaced by a real salt when encoding.
- kdfattr.put(IPBE.SALT, new byte[8]);
- kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000));
- pbekdf.init(kdfattr);
- encoding = false;
- if (file.exists())
- {
- decode();
- }
- encoding = true;
- random = new SecureRandom ();
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- synchronized boolean addSession(Session.ID sessionId, Session session)
- {
- boolean ret = super.addSession(sessionId, session);
- if (ret && encoding)
- {
- try
- {
- encode();
- }
- catch (IOException ioe)
- {
- }
- }
- return ret;
- }
-
- synchronized void notifyAccess(Session session)
- {
- try
- {
- encode();
- }
- catch (IOException ioe)
- {
- }
- }
-
- synchronized boolean removeSession(Session.ID sessionId)
- {
- if (super.removeSession(sessionId))
- {
- try
- {
- encode();
- }
- catch (Exception x)
- {
- }
- return true;
- }
- return false;
- }
-
- private void decode() throws IOException, SAXException
- {
- SAXParser parser = null;
- try
- {
- parser = SAXParserFactory.newInstance().newSAXParser();
- }
- catch (Exception x)
- {
- throw new Error(x.toString());
- }
- SAXHandler handler = new SAXHandler(this, pbekdf);
- InputStream in = null;
- if (compress)
- in = new GZIPInputStream(new FileInputStream(file));
- else
- in = new FileInputStream(file);
- parser.parse(in, handler);
- }
-
- private void encode() throws IOException
- {
- IMode cipher = ModeFactory.getInstance("CBC", "AES", 16);
- HashMap cipherAttr = new HashMap();
- IMac mac = MacFactory.getInstance("HMAC-SHA1");
- HashMap macAttr = new HashMap();
- byte[] key = new byte[32];
- byte[] iv = new byte[16];
- byte[] mackey = new byte[20];
- byte[] salt = new byte[8];
- byte[] encryptedSecret = new byte[48];
- cipherAttr.put(IMode.KEY_MATERIAL, key);
- cipherAttr.put(IMode.IV, iv);
- cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
- PrintStream out = null;
- if (compress)
- {
- out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file)));
- }
- else
- {
- out = new PrintStream(new FileOutputStream(file));
- }
- out.println("<?xml version=\"1.0\"?>");
- out.println("<!DOCTYPE sessions [");
- out.println(" <!ELEMENT sessions (session*)>");
- out.println(" <!ATTLIST sessions size CDATA \"0\">");
- out.println(" <!ATTLIST sessions timeout CDATA \"86400\">");
- out.println(" <!ELEMENT session (peer, certificates?, secret)>");
- out.println(" <!ATTLIST session id CDATA #REQUIRED>");
- out.println(" <!ATTLIST session protocol (SSLv3|TLSv1|TLSv1.1) #REQUIRED>");
- out.println(" <!ATTLIST session suite CDATA #REQUIRED>");
- out.println(" <!ATTLIST session created CDATA #REQUIRED>");
- out.println(" <!ATTLIST session timestamp CDATA #REQUIRED>");
- out.println(" <!ELEMENT peer (certificates?)>");
- out.println(" <!ATTLIST peer host CDATA #REQUIRED>");
- out.println(" <!ELEMENT certificates (#PCDATA)>");
- out.println(" <!ATTLIST certificates type CDATA \"X.509\">");
- out.println(" <!ELEMENT secret (#PCDATA)>");
- out.println(" <!ATTLIST secret salt CDATA #REQUIRED>");
- out.println("]>");
- out.println();
- out.print("<sessions size=\"");
- out.print(cacheSize);
- out.print("\" timeout=\"");
- out.print(timeout);
- out.println("\">");
- for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) it.next();
- Session.ID id = (Session.ID) entry.getKey();
- Session session = (Session) entry.getValue();
- if (!session.valid)
- {
- continue;
- }
- out.print("<session id=\"");
- out.print(Base64.encode(id.getId(), 0));
- out.print("\" suite=\"");
- out.print(session.getCipherSuite());
- out.print("\" protocol=\"");
- out.print(session.getProtocol());
- out.print("\" created=\"");
- out.print(session.getCreationTime());
- out.print("\" timestamp=\"");
- out.print(session.getLastAccessedTime());
- out.println("\">");
- out.print("<peer host=\"");
- out.print(session.getPeerHost());
- out.println("\">");
- Certificate[] certs = session.getPeerCertificates();
- if (certs != null && certs.length > 0)
- {
- out.print("<certificates type=\"");
- out.print(certs[0].getType());
- out.println("\">");
- for (int i = 0; i < certs.length; i++)
- {
- out.println("-----BEGIN CERTIFICATE-----");
- try
- {
- out.print(Base64.encode(certs[i].getEncoded(), 70));
- }
- catch (CertificateEncodingException cee)
- {
- throw new IOException(cee.toString());
- }
- out.println("-----END CERTIFICATE-----");
- }
- out.println("</certificates>");
- }
- out.println("</peer>");
- certs = session.getLocalCertificates();
- if (certs != null && certs.length > 0)
- {
- out.print("<certificates type=\"");
- out.print(certs[0].getType());
- out.println("\">");
- for (int i = 0; i < certs.length; i++)
- {
- out.println("-----BEGIN CERTIFICATE-----");
- try
- {
- out.print(Base64.encode(certs[i].getEncoded(), 70));
- }
- catch (CertificateEncodingException cee)
- {
- throw new IOException(cee.toString());
- }
- out.println("-----END CERTIFICATE-----");
- }
- out.println("</certificates>");
- }
- random.nextBytes (salt);
- pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
- try
- {
- pbekdf.nextBytes(key, 0, key.length);
- pbekdf.nextBytes(iv, 0, iv.length);
- pbekdf.nextBytes(mackey, 0, mackey.length);
- cipher.reset();
- cipher.init(cipherAttr);
- mac.init(macAttr);
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- for (int i = 0; i < session.masterSecret.length; i += 16)
- {
- cipher.update(session.masterSecret, i, encryptedSecret, i);
- }
- mac.update(encryptedSecret, 0, encryptedSecret.length);
- byte[] macValue = mac.digest();
- out.print("<secret salt=\"");
- out.print(Base64.encode(salt, 0));
- out.println("\">");
- out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70));
- out.println("</secret>");
- out.println("</session>");
- }
- out.println("</sessions>");
- out.close();
- }
-
- // Inner class.
- // -------------------------------------------------------------------------
-
- private class SAXHandler extends DefaultHandler
- {
-
- // Field.
- // -----------------------------------------------------------------------
-
- private SessionContext context;
- private Session current;
- private IRandom pbekdf;
- private StringBuffer buf;
- private String certType;
- private int state;
- private IMode cipher;
- private HashMap cipherAttr;
- private IMac mac;
- private HashMap macAttr;
- private byte[] key;
- private byte[] iv;
- private byte[] mackey;
-
- private static final int START = 0;
- private static final int SESSIONS = 1;
- private static final int SESSION = 2;
- private static final int PEER = 3;
- private static final int PEER_CERTS = 4;
- private static final int CERTS = 5;
- private static final int SECRET = 6;
-
- // Constructor.
- // -----------------------------------------------------------------------
-
- SAXHandler(SessionContext context, IRandom pbekdf)
- {
- this.context = context;
- this.pbekdf = pbekdf;
- buf = new StringBuffer();
- state = START;
- cipher = ModeFactory.getInstance("CBC", "AES", 16);
- cipherAttr = new HashMap();
- mac = MacFactory.getInstance("HMAC-SHA1");
- macAttr = new HashMap();
- key = new byte[32];
- iv = new byte[16];
- mackey = new byte[20];
- cipherAttr.put(IMode.KEY_MATERIAL, key);
- cipherAttr.put(IMode.IV, iv);
- cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
- }
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public void startElement(String u, String n, String qname, Attributes attr)
- throws SAXException
- {
- qname = qname.toLowerCase();
- switch (state)
- {
- case START:
- if (qname.equals("sessions"))
- {
- try
- {
- timeout = Integer.parseInt(attr.getValue("timeout"));
- cacheSize = Integer.parseInt(attr.getValue("size"));
- if (timeout <= 0 || cacheSize < 0)
- throw new SAXException("timeout or cache size out of range");
- }
- catch (NumberFormatException nfe)
- {
- throw new SAXException(nfe);
- }
- state = SESSIONS;
- }
- else
- throw new SAXException("expecting sessions");
- break;
-
- case SESSIONS:
- if (qname.equals("session"))
- {
- try
- {
- current = new Session(Long.parseLong(attr.getValue("created")));
- current.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- current.context = context;
- current.sessionId = new Session.ID(Base64.decode(attr.getValue("id")));
- current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp")));
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- String prot = attr.getValue("protocol");
- if (prot.equals("SSLv3"))
- current.protocol = ProtocolVersion.SSL_3;
- else if (prot.equals("TLSv1"))
- current.protocol = ProtocolVersion.TLS_1;
- else if (prot.equals("TLSv1.1"))
- current.protocol = ProtocolVersion.TLS_1_1;
- else
- throw new SAXException("bad protocol: " + prot);
- current.cipherSuite = CipherSuite.forName(attr.getValue("suite"));
- state = SESSION;
- }
- else
- throw new SAXException("expecting session");
- break;
-
- case SESSION:
- if (qname.equals("peer"))
- {
- current.peerHost = attr.getValue("host");
- state = PEER;
- }
- else if (qname.equals("certificates"))
- {
- certType = attr.getValue("type");
- state = CERTS;
- }
- else if (qname.equals("secret"))
- {
- byte[] salt = null;
- try
- {
- salt = Base64.decode(attr.getValue("salt"));
- }
- catch (IOException ioe)
- {
- throw new SAXException(ioe);
- }
- pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
- state = SECRET;
- }
- else
- throw new SAXException("bad element: " + qname);
- break;
-
- case PEER:
- if (qname.equals("certificates"))
- {
- certType = attr.getValue("type");
- state = PEER_CERTS;
- }
- else
- throw new SAXException("bad element: " + qname);
- break;
-
- default:
- throw new SAXException("bad element: " + qname);
- }
- }
-
- public void endElement(String uri, String name, String qname)
- throws SAXException
- {
- qname = qname.toLowerCase();
- switch (state)
- {
- case SESSIONS:
- if (qname.equals("sessions"))
- state = START;
- else
- throw new SAXException("expecting sessions");
- break;
-
- case SESSION:
- if (qname.equals("session"))
- {
- current.valid = true;
- context.addSession(current.sessionId, current);
- state = SESSIONS;
- }
- else
- throw new SAXException("expecting session");
- break;
-
- case PEER:
- if (qname.equals("peer"))
- state = SESSION;
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case PEER_CERTS:
- if (qname.equals("certificates"))
- {
- try
- {
- CertificateFactory fact = CertificateFactory.getInstance(certType);
- current.peerCerts = (Certificate[])
- fact.generateCertificates(new ByteArrayInputStream(
- buf.toString().getBytes())).toArray(new Certificate[0]);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- current.peerVerified = true;
- state = PEER;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case CERTS:
- if (qname.equals("certificates"))
- {
- try
- {
- CertificateFactory fact = CertificateFactory.getInstance(certType);
- current.localCerts = (Certificate[])
- fact.generateCertificates(new ByteArrayInputStream(
- buf.toString().getBytes())).toArray(new Certificate[0]);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- state = SESSION;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case SECRET:
- if (qname.equals("secret"))
- {
- byte[] encrypted = null;
- try
- {
- encrypted = Base64.decode(buf.toString());
- if (encrypted.length != 68)
- throw new IOException("encrypted secret not 68 bytes long");
- pbekdf.nextBytes(key, 0, key.length);
- pbekdf.nextBytes(iv, 0, iv.length);
- pbekdf.nextBytes(mackey, 0, mackey.length);
- cipher.reset();
- cipher.init(cipherAttr);
- mac.init(macAttr);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- mac.update(encrypted, 0, 48);
- byte[] macValue = mac.digest();
- for (int i = 0; i < macValue.length; i++)
- {
- if (macValue[i] != encrypted[48+i])
- throw new SAXException("MAC mismatch");
- }
- current.masterSecret = new byte[48];
- for (int i = 0; i < current.masterSecret.length; i += 16)
- {
- cipher.update(encrypted, i, current.masterSecret, i);
- }
- state = SESSION;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- default:
- throw new SAXException("unexpected element: " + qname);
- }
- buf.setLength(0);
- }
-
- public void characters(char[] ch, int off, int len) throws SAXException
- {
- if (state != CERTS && state != PEER_CERTS && state != SECRET)
- {
- throw new SAXException("illegal character data");
- }
- buf.append(ch, off, len);
- }
- }
-}
diff --git a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/gnu/javax/security/auth/callback/CertificateCallback.java
index 19921d98c..fcec11962 100644
--- a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java
+++ b/gnu/javax/security/auth/callback/CertificateCallback.java
@@ -1,4 +1,4 @@
-/* JessieRSAPublicKey.java -- simple RSA public key.
+/* CertificateCallback.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,66 +33,32 @@ 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. */
+exception statement from your version. */
-package gnu.javax.net.ssl.provider;
+package gnu.javax.security.auth.callback;
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
+import java.security.cert.Certificate;
-class JessieRSAPublicKey implements RSAPublicKey
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final BigInteger modulus;
- private final BigInteger exponent;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieRSAPublicKey(BigInteger modulus, BigInteger exponent)
- {
- this.modulus = modulus;
- this.exponent = exponent;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
- {
- return "RSA";
- }
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
- {
- return null;
- }
-
- public BigInteger getModulus()
- {
- return modulus;
- }
-
- public BigInteger getPublicExponent()
- {
- return exponent;
- }
+import javax.security.auth.callback.ConfirmationCallback;
- public String toString()
+/**
+ * A {@link javax.security.auth.callback.Callback} for confirming whether or
+ * not a certificate may be used. This works similarly to
+ * {@link ConfirmationCallback}, but additionally contains the certificate
+ * being verified. Thus, handlers may present the certificate to the user, when
+ * handling this callback.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateCallback extends ConfirmationCallback
+{
+ static final long serialVersionUID = 8343869651419225634L;
+ public final Certificate certificate;
+
+ public CertificateCallback(Certificate cert, String prompt)
{
- String nl = System.getProperty("line.separator");
- return "RSAPublicKey {" + nl +
- " modulus = " + modulus.toString(16) + ";" + nl +
- " exponent = " + exponent.toString(16) + ";" + nl +
- "};";
+ super(prompt, ERROR, YES_NO_OPTION, NO);
+ this.certificate = cert;
}
}
diff --git a/java/security/MessageDigest.java b/java/security/MessageDigest.java
index b817759f5..8a5de92df 100644
--- a/java/security/MessageDigest.java
+++ b/java/security/MessageDigest.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package java.security;
import gnu.java.security.Engine;
+import java.nio.ByteBuffer;
/**
* Message digests are secure one-way hash functions that take arbitrary-sized
@@ -224,6 +225,17 @@ public abstract class MessageDigest extends MessageDigestSpi
}
/**
+ * Updates the digest with the remaining bytes of a buffer.
+ *
+ * @param input The input byte buffer.
+ * @since 1.5
+ */
+ public void update (ByteBuffer input)
+ {
+ engineUpdate (input);
+ }
+
+ /**
* Computes the final digest of the stored data.
*
* @return a byte array representing the message digest.
diff --git a/java/security/MessageDigestSpi.java b/java/security/MessageDigestSpi.java
index df3bd3ead..6615b1d93 100644
--- a/java/security/MessageDigestSpi.java
+++ b/java/security/MessageDigestSpi.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package java.security;
+import java.nio.ByteBuffer;
+
/**
This is the Service Provider Interface (SPI) for MessageDigest
class in java.security. It provides the back end functionality
@@ -98,6 +100,23 @@ public abstract class MessageDigestSpi
protected abstract void engineUpdate(byte[]input, int offset, int len);
/**
+ * Updates this digest with the remaining bytes of a byte buffer.
+ *
+ * @param input The input buffer.
+ * @since 1.5
+ */
+ protected void engineUpdate (ByteBuffer input)
+ {
+ byte[] buf = new byte[1024];
+ while (input.hasRemaining())
+ {
+ int n = Math.min(input.remaining(), buf.length);
+ input.get (buf, 0, n);
+ engineUpdate (buf, 0, n);
+ }
+ }
+
+ /**
Computes the final digest of the stored bytes and returns
them. It performs any necessary padding. The message digest
should reset sensitive data after performing the digest.
diff --git a/java/security/Signature.java b/java/security/Signature.java
index 845a77a8b..68ae99d42 100644
--- a/java/security/Signature.java
+++ b/java/security/Signature.java
@@ -40,6 +40,7 @@ package java.security;
import gnu.java.security.Engine;
+import java.nio.ByteBuffer;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
@@ -467,6 +468,22 @@ public abstract class Signature extends SignatureSpi
else
throw new SignatureException();
}
+
+ /**
+ * Update this signature with the {@link java.nio.Buffer#remaining()}
+ * bytes of the input buffer.
+ *
+ * @param input The input buffer.
+ * @throws SignatureException If this instance was not properly
+ * initialized.
+ */
+ public final void update(ByteBuffer input) throws SignatureException
+ {
+ if (state != UNINITIALIZED)
+ engineUpdate(input);
+ else
+ throw new SignatureException("not initialized");
+ }
/**
* Returns the name of the algorithm currently used. The names of algorithms
diff --git a/java/security/SignatureSpi.java b/java/security/SignatureSpi.java
index 25d49dedd..3b46815ec 100644
--- a/java/security/SignatureSpi.java
+++ b/java/security/SignatureSpi.java
@@ -37,6 +37,7 @@ exception statement from your version. */
package java.security;
+import java.nio.ByteBuffer;
import java.security.spec.AlgorithmParameterSpec;
/**
@@ -131,6 +132,24 @@ public abstract class SignatureSpi
throws SignatureException;
/**
+ * Update this signature with the {@link java.nio.Buffer#remaining()}
+ * bytes of the given buffer.
+ *
+ * @param input The input buffer.
+ * @throws SignatureException
+ */
+ protected void engineUpdate(ByteBuffer input) throws SignatureException
+ {
+ byte[] buf = new byte[4096];
+ while (input.hasRemaining())
+ {
+ int l = Math.min(input.remaining(), buf.length);
+ input.get(buf, 0, l);
+ engineUpdate(buf, 0, l);
+ }
+ }
+
+ /**
* Returns the signature bytes of all the data fed to this instance. The
* format of the output depends on the underlying signature algorithm.
*
diff --git a/javax/crypto/Mac.java b/javax/crypto/Mac.java
index abbff8b23..055b20a4f 100644
--- a/javax/crypto/Mac.java
+++ b/javax/crypto/Mac.java
@@ -41,6 +41,7 @@ package javax.crypto;
import gnu.java.security.Engine;
import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -398,6 +399,18 @@ public class Mac implements Cloneable
}
/**
+ * Update this MAC with the remaining bytes in the given buffer
+ * @param buffer The input buffer.
+ * @since 1.5
+ */
+ public final void update (final ByteBuffer buffer)
+ {
+ if (virgin)
+ throw new IllegalStateException ("not initialized");
+ macSpi.engineUpdate(buffer);
+ }
+
+ /**
* Clone this instance, if the underlying implementation supports it.
*
* @return A clone of this instance.
diff --git a/javax/crypto/MacSpi.java b/javax/crypto/MacSpi.java
index b0f96bff3..853bd66aa 100644
--- a/javax/crypto/MacSpi.java
+++ b/javax/crypto/MacSpi.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.crypto;
+import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -142,4 +143,21 @@ public abstract class MacSpi
* @param length The number of bytes to update.
*/
protected abstract void engineUpdate(byte[] input, int offset, int length);
+
+ /**
+ * Update this MAC with the remaining bytes of a buffer.
+ *
+ * @param buffer The input buffer.
+ * @since 1.5
+ */
+ protected void engineUpdate (final ByteBuffer buffer)
+ {
+ byte[] buf = new byte[1024];
+ while (buffer.hasRemaining ())
+ {
+ int n = Math.min (buffer.remaining (), buf.length);
+ buffer.get (buf, 0, n);
+ engineUpdate (buf, 0, n);
+ }
+ }
}
diff --git a/javax/net/ssl/CertPathTrustManagerParameters.java b/javax/net/ssl/CertPathTrustManagerParameters.java
new file mode 100644
index 000000000..b6dc135e1
--- /dev/null
+++ b/javax/net/ssl/CertPathTrustManagerParameters.java
@@ -0,0 +1,71 @@
+/* CertPathTrustManagerParameters.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 javax.net.ssl;
+
+import java.security.cert.CertPathParameters;
+
+/**
+ * Trust manager parameters for certification paths.
+ */
+public class CertPathTrustManagerParameters implements ManagerFactoryParameters
+{
+ private final CertPathParameters params;
+
+ /**
+ * Creates a new trust manager parameter instance. The argument is
+ * cloned to prevent modification of this instance.
+ *
+ * @param params The certificate path parameters.
+ * @throws NullPointerException If params is null.
+ */
+ public CertPathTrustManagerParameters (final CertPathParameters params)
+ {
+ this.params = (CertPathParameters) params.clone ();
+ }
+
+ /**
+ * Returns a copy of the certificate path parameters.
+ *
+ * @return A copy of the certificate path parameters.
+ */
+ public CertPathParameters getParameters ()
+ {
+ return (CertPathParameters) params.clone ();
+ }
+}
diff --git a/javax/net/ssl/HandshakeCompletedEvent.java b/javax/net/ssl/HandshakeCompletedEvent.java
index 743f13726..b65dff06c 100644
--- a/javax/net/ssl/HandshakeCompletedEvent.java
+++ b/javax/net/ssl/HandshakeCompletedEvent.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.net.ssl;
+import java.security.Principal;
import java.security.cert.Certificate;
import javax.security.cert.X509Certificate;
@@ -108,6 +109,20 @@ public class HandshakeCompletedEvent extends java.util.EventObject
}
/**
+ * Returns the local identity used in this connection, or
+ * <code>null</code> if there is none.
+ *
+ * @return The local identity.
+ * @since 1.5
+ */
+ public Principal getLocalPrincipal ()
+ {
+ if (session != null)
+ return session.getLocalPrincipal ();
+ return null;
+ }
+
+ /**
* Returns the peer's certificates being used in this connection.
*
* @return The peer's certificates.
@@ -129,6 +144,22 @@ public class HandshakeCompletedEvent extends java.util.EventObject
}
/**
+ * Returns the peer's identity, or <code>null</code> if there is
+ * none.
+ *
+ * @return The peer's identity.
+ * @throws SSLPeerUnverifiedException If the remote peer's identity
+ * could not be verified.
+ * @since 1.5
+ */
+ public Principal getPeerPrincipal () throws SSLPeerUnverifiedException
+ {
+ if (session != null)
+ return session.getPeerPrincipal ();
+ return null;
+ }
+
+ /**
* Returns the SSL session object associated with this connection.
*
* @return The session object.
diff --git a/javax/net/ssl/HttpsURLConnection.java b/javax/net/ssl/HttpsURLConnection.java
index 3f30dc1b8..7d68162c9 100644
--- a/javax/net/ssl/HttpsURLConnection.java
+++ b/javax/net/ssl/HttpsURLConnection.java
@@ -38,9 +38,12 @@ exception statement from your version. */
package javax.net.ssl;
+import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.security.Principal;
import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
/**
* A URL connection that connects via the <i>Secure Socket Layer</i>
@@ -245,6 +248,48 @@ public abstract class HttpsURLConnection extends HttpURLConnection
this.factory = factory;
}
+ /**
+ * Returns the local principal for this connection.
+ *
+ * <p>The default implementation will return the {@link
+ * javax.security.x500.X500Principal} for the end entity certificate
+ * in the local certificate chain if those certificates are of type
+ * {@link java.security.cert.X509Certificate}. Otherwise, this
+ * method returns <code>null</code>.
+ *
+ * @return The local principal.
+ * @since 1.5
+ */
+ public Principal getLocalPrincipal ()
+ {
+ Certificate[] c = getLocalCertificates ();
+ if (c != null && c.length > 0 && (c[0] instanceof X509Certificate))
+ return ((X509Certificate) c[0]).getSubjectX500Principal ();
+ return null;
+ }
+
+ /**
+ * Returns the remote peer's principal for this connection.
+ *
+ * <p>The default implementation will return the {@link
+ * javax.security.x500.X500Principal} for the end entity certificate
+ * in the remote peer's certificate chain if those certificates are
+ * of type {@link java.security.cert.X509Certificate}. Otherwise,
+ * this method returns <code>null</code>.
+ *
+ * @return The remote principal.
+ * @throws SSLPeerUnverifiedException If the remote peer has not
+ * been verified.
+ * @since 1.5
+ */
+ public Principal getPeerPrincipal () throws SSLPeerUnverifiedException
+ {
+ Certificate[] c = getServerCertificates ();
+ if (c != null && c.length > 0 && (c[0] instanceof X509Certificate))
+ return ((X509Certificate) c[0]).getSubjectX500Principal ();
+ return null;
+ }
+
// Abstract methods.
// -------------------------------------------------------------------
diff --git a/javax/net/ssl/KeyStoreBuilderParameters.java b/javax/net/ssl/KeyStoreBuilderParameters.java
new file mode 100644
index 000000000..2aa665ed5
--- /dev/null
+++ b/javax/net/ssl/KeyStoreBuilderParameters.java
@@ -0,0 +1,48 @@
+/* KeyStoreBuilderParameters.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 javax.net.ssl;
+
+/**
+ * <p style="color: red;"><b>FIXME</b> this class is currently a stub;
+ * it depends on an implementation of {@link
+ * java.security.KeyStore.Builder}</p>.
+ */
+public class KeyStoreBuilderParameters implements ManagerFactoryParameters
+{
+}
diff --git a/javax/net/ssl/SSLContext.java b/javax/net/ssl/SSLContext.java
index eaf3e3638..3f284ab1a 100644
--- a/javax/net/ssl/SSLContext.java
+++ b/javax/net/ssl/SSLContext.java
@@ -188,6 +188,31 @@ public class SSLContext
// -----------------------------------------------------------------
/**
+ * Creates a new {@link SSLEngine} for this context.
+ *
+ * @return The new SSLEngine.
+ * @since 1.5
+ */
+ public final SSLEngine createSSLEngine ()
+ {
+ return ctxSpi.engineCreateSSLEngine ();
+ }
+
+ /**
+ * Creates a new {@link SSLEngine} for this context, with a given
+ * host name and port number.
+ *
+ * @param host The local host name.
+ * @param port The local port number.
+ * @return The new SSLEngine.
+ * @since 1.5
+ */
+ public final SSLEngine createSSLEngine (final String host, final int port)
+ {
+ return ctxSpi.engineCreateSSLEngine (host, port);
+ }
+
+ /**
* Returns the set of SSL contexts available for client connections.
*
* @return The set of SSL contexts available for client connections.
diff --git a/javax/net/ssl/SSLContextSpi.java b/javax/net/ssl/SSLContextSpi.java
index a6b0c7581..03c44f85e 100644
--- a/javax/net/ssl/SSLContextSpi.java
+++ b/javax/net/ssl/SSLContextSpi.java
@@ -64,6 +64,28 @@ public abstract class SSLContextSpi
// Abstract methods.
// -------------------------------------------------------------------
+ // Sun, you've broken existing applications by introducing new
+ // abstract methods! Goodjob!!!
+
+ /**
+ * Returns a new {@link SSLEngine} for this context.
+ *
+ * @return A new SSLEngine.
+ * @since 1.5
+ */
+ protected abstract SSLEngine engineCreateSSLEngine ();
+
+ /**
+ * Returns a new {@link SSLEngine} for this context, for the given
+ * host name and port number.
+ *
+ * @param host The local host name.
+ * @param port The local port number.
+ * @return A new SSLEngine.
+ * @since 1.5
+ */
+ protected abstract SSLEngine engineCreateSSLEngine (String host, int port);
+
/**
* Returns the set of SSL sessions available for client connections.
*
diff --git a/javax/net/ssl/SSLEngine.java b/javax/net/ssl/SSLEngine.java
new file mode 100644
index 000000000..efab9725b
--- /dev/null
+++ b/javax/net/ssl/SSLEngine.java
@@ -0,0 +1,442 @@
+/* SSLEngine.java -- advanced, generic utility for manipulating SSL 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 javax.net.ssl;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A class for low-level message wrapping and unwrapping of SSL
+ * messages.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ * @since 1.5
+ */
+public abstract class SSLEngine
+{
+ private final String peerHost;
+ private final int peerPort;
+
+ /**
+ * Creates a new SSLEngine with no peer host name or port number.
+ */
+ protected SSLEngine ()
+ {
+ this (null, -1);
+ }
+
+ /**
+ * Creates a new SSLEngine with the specified peer host name and
+ * port number.
+ *
+ * @param peerHost The peer's host name.
+ * @param peerPort The peer's port number.
+ */
+ protected SSLEngine (String peerHost, int peerPort)
+ {
+ this.peerHost = peerHost;
+ this.peerPort = peerPort;
+ }
+
+
+
+ /**
+ * Begin, or restart, the SSL handshake.
+ *
+ * @throws SSLException
+ */
+ public abstract void beginHandshake () throws SSLException;
+
+ /**
+ * Close the inbound state.
+ *
+ * @throws SSLException
+ */
+ public abstract void closeInbound () throws SSLException;
+
+ /**
+ * Close the outbound state.
+ */
+ public abstract void closeOutbound ();
+
+ /**
+ *
+ */
+ public abstract Runnable getDelegatedTask ();
+
+ /**
+ * Returns the peer host name this SSL session is connected to, or
+ * <code>null</code> if this value was not set.
+ *
+ * @return The peer host's name.
+ */
+ public String getPeerHost ()
+ {
+ return peerHost;
+ }
+
+ /**
+ * Returns the peer IP port number this SSL session in communicating
+ * on, or -1 if this value was not set.
+ *
+ * @return The peer's port number.
+ */
+ public int getPeerPort ()
+ {
+ return peerPort;
+ }
+
+ /**
+ * Returns a list of SSL cipher suite names this SSLEngine is
+ * configured to use.
+ *
+ * @return The list of enabled cipher suite names.
+ */
+ public abstract String[] getEnabledCipherSuites();
+
+ /**
+ * Returns a list of SSL protocol version names this SSLEngine is
+ * configured to use.
+ *
+ * @return The list of enabled protocol names.
+ */
+ public abstract String[] getEnabledProtocols ();
+
+ /**
+ * Tells if sessions will be created by this engine, and therefore
+ * may be resumed at a later time.
+ *
+ * @return True if sessions will be created.
+ */
+ public abstract boolean getEnableSessionCreation();
+
+ /**
+ * Return the current handshake status.
+ *
+ * @return The current handshake status.
+ */
+ public abstract SSLEngineResult.HandshakeStatus getHandshakeStatus ();
+
+ /**
+ * Tells if this SSLEngine is configured to require client
+ * authentication when in server mode.
+ *
+ * @return True iff client authentication is required.
+ */
+ public abstract boolean getNeedClientAuth ();
+
+ /**
+ * Return the {@link SSLSession} object this connection represents.
+ *
+ * @return The SSL session.
+ */
+ public abstract SSLSession getSession ();
+
+ /**
+ * Returns a list of SSL cipher suite names this SSLEngine
+ * implementation supports.
+ *
+ * @return The list of cipher suite names supported by this
+ * implementation.
+ */
+ public abstract String[] getSupportedCipherSuites ();
+
+ /**
+ * Returns a list of SSL protocol version names this SSLEngine
+ * implementation supports. SSL protocol names include things like
+ * "SSLv3" or "TLSv1".
+ *
+ * @return The list of SSL protocol names
+ */
+ public abstract String[] getSupportedProtocols ();
+
+ /**
+ * Tells if this SSLEngine is a "client" session.
+ *
+ * @return True iff this session is configured for client mode.
+ */
+ public abstract boolean getUseClientMode ();
+
+ /**
+ * Tells if client authentication is requested, but not required,
+ * for sessions in server mode. If true, a server session will
+ * request an authentication message from connecting clients, but
+ * will still allow clients to connect if they cannot be
+ * authenticated.
+ *
+ * @return True iff client authentication is requested.
+ */
+ public abstract boolean getWantClientAuth ();
+
+ /**
+ * Tells if the incoming data stream is finished, and thus if no
+ * more data will be available to be unwrapped.
+ *
+ * @return True if no more data is to be unwrapped.
+ */
+ public abstract boolean isInboundDone ();
+
+ /**
+ * Tells if the outgoing data stream is finished, and thus if no
+ * more data may be wrapped.
+ *
+ * @return True if no more data may be wrapped.
+ */
+ public abstract boolean isOutboundDone ();
+
+ /**
+ * Sets the list of enabled cipher suites. The argument is an array
+ * of strings of the canonical suite names.
+ *
+ * @param suites The cipher suites to enable.
+ * @throws IllegalArgumentException If any of the specified suite
+ * strings is not supported by this implementation, or if the
+ * argument is null.
+ */
+ public abstract void setEnabledCipherSuites (String[] suites);
+
+ /**
+ * Sets the list of enabled protocol versions. The argument is an
+ * array of strings of the canonical protocol version names, such as
+ * "TLSv1".
+ *
+ * @param protocols The protocol versions to enable.
+ * @throws IllegalArgumentException If any of the specified
+ * protocols are not supported, or if the argument is null.
+ */
+ public abstract void setEnabledProtocols (String[] protocols);
+
+ /**
+ * Enables or disables session creation. If enabled, each connection
+ * will create session that may be resumed by another connection.
+ *
+ * @param create Whether or not to enable session creation.
+ */
+ public abstract void setEnableSessionCreation (boolean create);
+
+ /**
+ * Enables client or server mode. If the argument is true, this
+ * engine will run in client mode; if false, server mode.
+ *
+ * @param clientMode Whether or not to use client mode.
+ */
+ public abstract void setUseClientMode (boolean clientMode);
+
+ /**
+ * Enables or disables required client authentication. If enabled,
+ * clients may only connect if they provide proper identification.
+ *
+ * <p>This parameter is only used in server mode.
+ *
+ * @param needAuth Whether or not client authentication is required.
+ */
+ public abstract void setNeedClientAuth (boolean needAuth);
+
+ /**
+ * Enables or disables requested client authentication. If enabled,
+ * clients will be asked to provide proper identification, but will
+ * still be allowed to connect if they do not provide it.
+ *
+ * <p>This parameter is only used in server mode.
+ *
+ * @param wantAuth Whether or not client authentication will be
+ * requested, but not required.
+ */
+ public abstract void setWantClientAuth (boolean wantAuth);
+
+ /**
+ * Unwraps a byte buffer recieved from the network, storing the
+ * decrypted, unwrapped bytes into the given buffer.
+ *
+ * <p>This call is exactly equivalent to <code>unwrap (source, new
+ * ByteBuffer[] { sink }, 0, 1)</code>.
+ *
+ * @param source The source bytes, coming from the network.
+ * @param sink The buffer to hold the unwrapped message.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL message parsing error occurs.
+ * @throws java.nio.ReadOnlyBufferException If 'sink' is not
+ * writable.
+ * @throws IllegalArgumentException If either 'source' or 'sink' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ */
+ public SSLEngineResult unwrap (ByteBuffer source, ByteBuffer sink)
+ throws SSLException
+ {
+ return unwrap (source, new ByteBuffer[] { sink }, 0, 1);
+ }
+
+ /**
+ * Unwraps a byte buffer recieved from the network, storing the
+ * decrypted, unwrapped bytes into the given buffers.
+ *
+ * <p>This call is exactly equivalent to <code>unwrap (source,
+ * sinks, 0, sinks.length)</code>.
+ *
+ * @param source The source bytes, coming from the network.
+ * @param sinks The buffers to hold the unwrapped message.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL message parsing error occurs.
+ * @throws java.nio.ReadOnlyBufferException If any buffer in 'sinks'
+ * is not writable.
+ * @throws IllegalArgumentException If either 'source' or 'sinks' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ */
+ public SSLEngineResult unwrap (ByteBuffer source, ByteBuffer[] sinks)
+ throws SSLException
+ {
+ return unwrap (source, sinks, 0, sinks.length);
+ }
+
+ /**
+ * Unwraps a byte buffer received from the network, storing the
+ * decrypted, unwrapped bytes into the given buffers. After
+ * unwrapping, the bytes placed into the sink buffers are ready for
+ * consumption by the application.
+ *
+ * <p>This method may place no bytes in the destination buffer; for
+ * example, if this engine is still performing the SSL handshake,
+ * only handshake data will be consumed, and no application data.
+ *
+ * <p>It is stated that this method may modify the source buffer,
+ * and that it must not be passed to another SSLEngine (SSL
+ * connections are independent, so another SSLEngine will not have
+ * the parameters or state to handle messages meant for this
+ * engine).
+ *
+ * @param source The source bytes, coming from the network.
+ * @param sinks The buffers to hold the unwrapped message.
+ * @param offset The index of the first buffer in 'sinks' to use.
+ * @param length The number of buffers in 'sinks' to use.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL message parsing error occurs.
+ * @throws java.nio.ReadOnlyBufferException If any buffer in 'sinks'
+ * is not writable.
+ * @throws IllegalArgumentException If either 'source' or 'sinks' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ * @throws IndexOutOfBoundsException If 'offset' or 'length' is
+ * negative, or if 'length+offset' is greater than 'sinks.length'.
+ */
+ public abstract SSLEngineResult unwrap (ByteBuffer source,
+ ByteBuffer[] sinks, int offset,
+ int length)
+ throws javax.net.ssl.SSLException;
+
+ /**
+ * Wraps a byte buffer into an SSL message, for preparation to send
+ * it over the network.
+ *
+ * <p>This method is exactly equivalent to <code>wrap (new
+ * ByteBuffer[] { source }, 0, 1, sink)</code>.
+ *
+ * @param source The source buffer with application data.
+ * @param sink The buffer to hold the wrapped data.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL error occurs.
+ * @throws java.nio.ReadOnlyBufferException If 'sink' is read-only.
+ * @throws IllegalArgumentException If either 'source' or 'sink' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ */
+ public SSLEngineResult wrap (ByteBuffer source, ByteBuffer sink)
+ throws SSLException
+ {
+ return wrap (new ByteBuffer[] { source }, 0, 1, sink);
+ }
+
+ /**
+ * Wraps byte buffers into an SSL message, for preparation to send
+ * them over the network.
+ *
+ * <p>This method is exactly equivalent to <code>wrap (sources, 0,
+ * 1, sink)</code>.
+ *
+ * @param sources The source buffers with application data.
+ * @param sink The buffer to hold the wrapped data.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL error occurs.
+ * @throws java.nio.ReadOnlyBufferException If 'sink' is read-only.
+ * @throws IllegalArgumentException If either 'sources' or 'sink' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ */
+ public SSLEngineResult wrap (ByteBuffer[] sources, ByteBuffer sink)
+ throws SSLException
+ {
+ return wrap (sources, 0, sources.length, sink);
+ }
+
+ /**
+ * Wraps byte buffers into an SSL message, for preparation to send
+ * them over the network. After wrapping, the data in the sink
+ * buffer is ready to be sent over the transport layer.
+ *
+ * <p>This method may consume no data from the source buffers, and
+ * yet still produce output that should be sent accross the wire;
+ * for example if this engine has not yet completed the SSL
+ * handshake, the sink buffer will be filled with handshake
+ * messages.
+ *
+ * @param sources The source buffers with application data.
+ * @param offset The offset into the source buffers to start reading
+ * application data.
+ * @param length The number of buffers to read from 'sources'.
+ * @param sink The buffer to hold the wrapped data.
+ * @return An engine result object for the operation.
+ * @throws SSLException If an SSL error occurs.
+ * @throws java.nio.ReadOnlyBufferException If 'sink' is read-only.
+ * @throws IllegalArgumentException If either 'sources' or 'sink' is
+ * null.
+ * @throws IllegalStateException If this engine has not been put
+ * into client or server mode.
+ * @throws IndexOutOfBoundsException If 'offset' or 'length' is
+ * negative, or if 'length+offset' is greater than 'sources.length'.
+ */
+ public abstract SSLEngineResult wrap (ByteBuffer[] sources, int offset,
+ int length, ByteBuffer sink)
+ throws SSLException;
+
+}
diff --git a/javax/net/ssl/SSLEngineResult.java b/javax/net/ssl/SSLEngineResult.java
new file mode 100644
index 000000000..0d6a435dd
--- /dev/null
+++ b/javax/net/ssl/SSLEngineResult.java
@@ -0,0 +1,194 @@
+/* SSLEngineResult.java --
+ Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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 result from an {@link SSLEngine} <code>wrap</code> or
+ * <code>unwrap</code> operation. This class conveys a possibly
+ * intermediate result, and may ask for more input data or request
+ * that output data be sent over a connection.
+ */
+public class SSLEngineResult
+{
+ private final HandshakeStatus handshakeStatus;
+ private final Status status;
+ private final int bytesConsumed;
+ private final int bytesProduced;
+
+ /**
+ * Creates a new SSL engine result.
+ *
+ * @param status The status of the SSL connection.
+ * @param handshakeStatus The status of the SSL handshake.
+ * @param bytesConsumed The number of bytes consumed by the previous
+ * operation.
+ * @param bytesProduced The number of bytes produced by the previous
+ * operation.
+ * @throws IllegalArgumentException If either enum value is
+ * <code>null</code>, or if either integer is negative.
+ */
+ public SSLEngineResult (Status status, HandshakeStatus handshakeStatus,
+ int bytesConsumed, int bytesProduced)
+ {
+ if (status == null)
+ throw new IllegalArgumentException ("'status' may not be null");
+ if (handshakeStatus == null)
+ throw new IllegalArgumentException ("'handshakeStatus' may not be null");
+ if (bytesConsumed < 0)
+ throw new IllegalArgumentException ("'bytesConumed' must be nonnegative");
+ if (bytesProduced < 0)
+ throw new IllegalArgumentException ("'bytesProduced' must be nonnegative");
+ this.status = status;
+ this.handshakeStatus = handshakeStatus;
+ this.bytesConsumed = bytesConsumed;
+ this.bytesProduced = bytesProduced;
+ }
+
+
+
+ /**
+ * An enumeration of possible general states.
+ */
+ public static enum Status
+ {
+
+ /**
+ * There were not enough input bytes available to complete the
+ * operation.
+ */
+ BUFFER_UNDERFLOW,
+
+ /**
+ * There was not enough space for the output message.
+ */
+ BUFFER_OVERFLOW,
+
+ /**
+ * Okay. No error.
+ */
+ OK,
+
+ /**
+ * The connection is closed.
+ */
+ CLOSED
+ }
+
+ /**
+ * An enumeration of possible handshake status states.
+ */
+ public static enum HandshakeStatus
+ {
+
+ /**
+ * Not currently handshaking.
+ */
+ NOT_HANDSHAKING,
+
+ /**
+ * The handshake is finished.
+ */
+ FINISHED,
+
+ /**
+ * Needs the status of one or more delegated tasks.
+ */
+ NEED_TASK,
+
+ /**
+ * Has data prepared for output, and needs a new call to
+ * <code>wrap</code>.
+ */
+ NEED_WRAP,
+
+ /**
+ * Is waiting for more input.
+ */
+ NEED_UNWRAP
+ }
+
+
+
+ /**
+ * Returns the number of bytes consumed by the previous operation.
+ *
+ * @return The number of bytes consumed.
+ */
+ public int bytesConsumed ()
+ {
+ return bytesConsumed;
+ }
+
+ /**
+ * Returns the number of bytes produced by the previous operation.
+ *
+ * @return The number of bytes produced.
+ */
+ public int bytesProduced ()
+ {
+ return bytesProduced;
+ }
+
+ /**
+ * Returns the handshake status.
+ *
+ * @return The handshake status.
+ */
+ public HandshakeStatus getHandshakeStatus ()
+ {
+ return handshakeStatus;
+ }
+
+ /**
+ * Returns the connection status.
+ *
+ * @return The connection status.
+ */
+ public Status getStatus ()
+ {
+ return status;
+ }
+
+ public String toString ()
+ {
+ return (super.toString () + " [ status: " + status + "; handshakeStatus: "
+ + handshakeStatus + "; bytesConsumed: " + bytesConsumed
+ + "; bytesProduced: " + bytesProduced + " ]");
+ }
+}
diff --git a/javax/net/ssl/SSLSession.java b/javax/net/ssl/SSLSession.java
index 9400a1a51..c8a4785f9 100644
--- a/javax/net/ssl/SSLSession.java
+++ b/javax/net/ssl/SSLSession.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.net.ssl;
+import java.security.Principal;
import java.security.cert.Certificate;
import javax.security.cert.X509Certificate;
@@ -48,6 +49,20 @@ import javax.security.cert.X509Certificate;
*/
public interface SSLSession
{
+
+ /**
+ * Returns the size of the largest application data buffer that can
+ * occur in this session.
+ *
+ * <p>Buffers passed to handle the incoming data for the
+ * <code>unwrap</code> method of SSLEngine must be at least this
+ * large.
+ *
+ * @return The size of application buffers.
+ * @since 1.5
+ */
+ int getApplicationBufferSize ();
+
/**
* Returns this session's cihper suite.
*
@@ -87,6 +102,28 @@ public interface SSLSession
Certificate[] getLocalCertificates();
/**
+ * Returns the {@link Principal} representing the local identity
+ * used in this session, or <code>null</code> if there is no local
+ * identity.
+ *
+ * @return The local principal.
+ */
+ Principal getLocalPrincipal ();
+
+ /**
+ * Returns the size of the largest SSL message that will be
+ * generated by this session.
+ *
+ * <p>Callers of <code>wrap</code> and <code>unwrap</code> should
+ * use this value to determine the size of buffers for data coming
+ * into, or going out over, the network.
+ *
+ * @returns The maximum network packet size.
+ * @since 1.5
+ */
+ int getPacketBufferSize ();
+
+ /**
* Returns the chain of certificates that the remote side used in
* the handshake, or null if none were used.
*
@@ -115,6 +152,27 @@ public interface SSLSession
String getPeerHost();
/**
+ * Returns the port number the remote peer is using for this
+ * session.
+ *
+ * @return The peer's port number.
+ * @since 1.5
+ */
+ int getPeerPort ();
+
+ /**
+ * Returns the {@link Principal} representing the identity of the
+ * remote peer, or <code>null</code> if the remote peer has no known
+ * identity.
+ *
+ * @return The remote peer's principal.
+ * @throws SSLPeerUnverifiedException If the remote peer's identity
+ * could not be verified.
+ * @since 1.5
+ */
+ Principal getPeerPrincipal () throws SSLPeerUnverifiedException;
+
+ /**
* Returns the protocol this session uses.
*
* @return The protocol.
@@ -152,6 +210,15 @@ public interface SSLSession
void invalidate();
/**
+ * Tells if this session is currently valid, and may be resumed.
+ *
+ * @return True if this session is valid.
+ * @since 1.5
+ * @see #invalidate()
+ */
+ boolean isValid ();
+
+ /**
* Binds a value to this session, with the given name.
*
* @param name The name to bind the object with.
diff --git a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/javax/net/ssl/X509ExtendedKeyManager.java
index 4ec71a7aa..ccd146f82 100644
--- a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
+++ b/javax/net/ssl/X509ExtendedKeyManager.java
@@ -1,4 +1,4 @@
-/* JessieRSAPrivateKey.java -- simple RSA private key.
+/* X509ExtendedKeyManager.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -36,63 +36,61 @@ 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;
+package javax.net.ssl;
-import java.math.BigInteger;
-import java.security.interfaces.RSAPrivateKey;
+import java.security.Principal;
-class JessieRSAPrivateKey implements RSAPrivateKey
+/**
+ * An extended {@link X509KeyManager} for use with {@link SSLEngine}.
+ *
+ * @since 1.5
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class X509ExtendedKeyManager implements X509KeyManager
{
- // Fields.
- // -------------------------------------------------------------------------
-
- private final BigInteger modulus;
- private final BigInteger exponent;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent)
+ /**
+ * Default constructor.
+ */
+ protected X509ExtendedKeyManager ()
{
- this.modulus = modulus;
- this.exponent = exponent;
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
- {
- return "RSA";
- }
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
+ /**
+ * Return a client alias given a list of key types, a list of
+ * allowable issuers, and the SSLEngine being used.
+ *
+ * <p>This implementation always returns <code>null</code>.
+ *
+ * @param keyTypes The list of desired key types.
+ * @param issuers The list of desired key issuers.
+ * @param engine This client's SSLEngine.
+ * @return A key alias that matches the given parameters, or
+ * <code>null</code> if the parameters were not matched.
+ */
+ public String chooseEngineClientAlias (final String[] keyTypes,
+ final Principal[] issuers,
+ final SSLEngine engine)
{
return null;
}
- public BigInteger getModulus()
- {
- return modulus;
- }
-
- public BigInteger getPrivateExponent()
+ /**
+ * Return a server alias given a key type, a list of allowable
+ * issuers, and the SSLEngine being used.
+ *
+ * <p>This implementation always returns <code>null</code>.
+ *
+ * @param keyType The desired key type.
+ * @param issuers The list of desired key issuers.
+ * @param engine The server's SSLEngine.
+ * @return A key alias that matches the given parameters, or
+ * <code>null</code> if the parameters were not matched.
+ */
+ public String chooseEngineServerAlias (final String keyType,
+ final Principal[] issuers,
+ final SSLEngine engine)
{
- return exponent;
- }
-
- public String toString()
- {
- String nl = System.getProperty("line.separator");
- return "RSAPrivateKey {" + nl +
- " modulus = " + modulus.toString(16) + ";" + nl +
- " exponent = " + exponent.toString(16) + ";" + nl +
- "};";
+ return null;
}
}