From 8c09ba9b0bb2b3c6768d7bf7849bf5e096efdc16 Mon Sep 17 00:00:00 2001 From: Casey Marshall Date: Mon, 14 Aug 2006 22:36:17 +0000 Subject: 2006-08-14 Casey Marshall 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 --- ChangeLog | 80 + ChangeLog-ssl-nio | 642 ++++ gnu/classpath/debug/Component.java | 7 +- gnu/classpath/debug/SystemLogger.java | 41 +- gnu/java/security/Requires.java | 59 + gnu/java/security/action/GetPropertyAction.java | 4 +- .../security/action/GetSecurityPropertyAction.java | 4 +- gnu/java/security/util/ByteBufferOutputStream.java | 118 + gnu/javax/crypto/RSACipherImpl.java | 67 +- gnu/javax/crypto/key/GnuPBEKey.java | 95 + gnu/javax/net/ssl/AbstractSessionContext.java | 288 ++ gnu/javax/net/ssl/PreSharedKeyManager.java | 54 + .../net/ssl/PreSharedKeyManagerParameters.java | 83 + gnu/javax/net/ssl/PrivateCredentials.java | 16 +- gnu/javax/net/ssl/SSLCipherSuite.java | 142 + gnu/javax/net/ssl/SSLProtocolVersion.java | 54 + gnu/javax/net/ssl/SSLRecordHandler.java | 101 + gnu/javax/net/ssl/Session.java | 364 ++ gnu/javax/net/ssl/SessionStoreException.java | 59 + gnu/javax/net/ssl/provider/AbstractHandshake.java | 1205 +++++++ gnu/javax/net/ssl/provider/Alert.java | 422 +-- gnu/javax/net/ssl/provider/AlertException.java | 37 +- gnu/javax/net/ssl/provider/Builder.java | 66 + gnu/javax/net/ssl/provider/Certificate.java | 205 +- gnu/javax/net/ssl/provider/CertificateBuilder.java | 94 + gnu/javax/net/ssl/provider/CertificateRequest.java | 226 +- .../ssl/provider/CertificateRequestBuilder.java | 113 + .../net/ssl/provider/CertificateStatusRequest.java | 272 ++ .../net/ssl/provider/CertificateStatusType.java | 13 + gnu/javax/net/ssl/provider/CertificateType.java | 56 +- gnu/javax/net/ssl/provider/CertificateURL.java | 388 +++ gnu/javax/net/ssl/provider/CertificateVerify.java | 54 +- gnu/javax/net/ssl/provider/CipherAlgorithm.java | 47 + gnu/javax/net/ssl/provider/CipherSuite.java | 1193 ++++--- gnu/javax/net/ssl/provider/CipherSuiteList.java | 283 ++ .../ssl/provider/ClientCertificateTypeList.java | 227 ++ .../net/ssl/provider/ClientDHE_PSKParameters.java | 122 + .../ssl/provider/ClientDiffieHellmanPublic.java | 129 + gnu/javax/net/ssl/provider/ClientHandshake.java | 1150 +++++++ gnu/javax/net/ssl/provider/ClientHello.java | 315 +- gnu/javax/net/ssl/provider/ClientHelloBuilder.java | 137 + gnu/javax/net/ssl/provider/ClientHelloV2.java | 158 + gnu/javax/net/ssl/provider/ClientKeyExchange.java | 163 +- .../net/ssl/provider/ClientKeyExchangeBuilder.java | 75 + .../net/ssl/provider/ClientPSKParameters.java | 125 + .../net/ssl/provider/ClientRSA_PSKParameters.java | 126 + gnu/javax/net/ssl/provider/CompressionMethod.java | 51 +- .../net/ssl/provider/CompressionMethodList.java | 281 ++ gnu/javax/net/ssl/provider/Constructed.java | 47 +- gnu/javax/net/ssl/provider/ContentType.java | 72 +- gnu/javax/net/ssl/provider/Context.java | 334 -- gnu/javax/net/ssl/provider/Debug.java | 66 + gnu/javax/net/ssl/provider/DelegatedTask.java | 93 + gnu/javax/net/ssl/provider/DiffieHellman.java | 6 +- gnu/javax/net/ssl/provider/DigestInputStream.java | 103 - gnu/javax/net/ssl/provider/DigestOutputStream.java | 107 - gnu/javax/net/ssl/provider/EmptyExchangeKeys.java | 77 + .../net/ssl/provider/EncryptedPreMasterSecret.java | 151 + gnu/javax/net/ssl/provider/Enumerated.java | 79 - gnu/javax/net/ssl/provider/ExchangeKeys.java | 54 + gnu/javax/net/ssl/provider/Extension.java | 260 +- gnu/javax/net/ssl/provider/ExtensionList.java | 290 ++ gnu/javax/net/ssl/provider/Extensions.java | 159 - gnu/javax/net/ssl/provider/Finished.java | 146 +- .../net/ssl/provider/GNUSecurityParameters.java | 490 --- gnu/javax/net/ssl/provider/Handshake.java | 472 +-- gnu/javax/net/ssl/provider/HelloRequest.java | 70 + .../net/ssl/provider/InputSecurityParameters.java | 336 ++ .../net/ssl/provider/JCESecurityParameters.java | 307 -- gnu/javax/net/ssl/provider/JDBCSessionContext.java | 356 -- gnu/javax/net/ssl/provider/Jessie.java | 35 +- gnu/javax/net/ssl/provider/JessieDHPrivateKey.java | 99 - gnu/javax/net/ssl/provider/JessieDHPublicKey.java | 99 - .../net/ssl/provider/JessieRSAPrivateKey.java | 98 - gnu/javax/net/ssl/provider/JessieRSAPublicKey.java | 98 - .../net/ssl/provider/KeyExchangeAlgorithm.java | 57 + gnu/javax/net/ssl/provider/KeyPool.java | 110 - gnu/javax/net/ssl/provider/MacAlgorithm.java | 47 + gnu/javax/net/ssl/provider/MaxFragmentLength.java | 59 + .../net/ssl/provider/OutputSecurityParameters.java | 297 ++ gnu/javax/net/ssl/provider/OverflowException.java | 57 - .../provider/PreSharedKeyManagerFactoryImpl.java | 118 + gnu/javax/net/ssl/provider/ProtocolVersion.java | 73 +- gnu/javax/net/ssl/provider/Random.java | 112 +- gnu/javax/net/ssl/provider/Record.java | 198 ++ gnu/javax/net/ssl/provider/RecordInput.java | 232 -- gnu/javax/net/ssl/provider/RecordInputStream.java | 106 - gnu/javax/net/ssl/provider/RecordOutputStream.java | 189 -- .../net/ssl/provider/RecordingInputStream.java | 131 - gnu/javax/net/ssl/provider/SSLContextImpl.java | 315 ++ gnu/javax/net/ssl/provider/SSLEngineImpl.java | 842 +++++ gnu/javax/net/ssl/provider/SSLRSASignature.java | 235 -- .../net/ssl/provider/SSLRSASignatureImpl.java | 233 ++ gnu/javax/net/ssl/provider/SSLServerSocket.java | 283 -- .../net/ssl/provider/SSLServerSocketFactory.java | 136 - .../ssl/provider/SSLServerSocketFactoryImpl.java | 108 + .../net/ssl/provider/SSLServerSocketImpl.java | 199 ++ gnu/javax/net/ssl/provider/SSLSocket.java | 3530 -------------------- gnu/javax/net/ssl/provider/SSLSocketFactory.java | 133 - .../net/ssl/provider/SSLSocketFactoryImpl.java | 137 + gnu/javax/net/ssl/provider/SSLSocketImpl.java | 833 +++++ .../net/ssl/provider/SSLSocketInputStream.java | 181 - .../net/ssl/provider/SSLSocketOutputStream.java | 115 - gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java | 116 + gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java | 116 + gnu/javax/net/ssl/provider/SecurityParameters.java | 178 - .../net/ssl/provider/ServerDHE_PSKParameters.java | 151 + gnu/javax/net/ssl/provider/ServerDHParams.java | 248 ++ gnu/javax/net/ssl/provider/ServerHandshake.java | 1377 ++++++++ gnu/javax/net/ssl/provider/ServerHello.java | 271 +- gnu/javax/net/ssl/provider/ServerHelloBuilder.java | 131 + gnu/javax/net/ssl/provider/ServerHelloDone.java | 66 + gnu/javax/net/ssl/provider/ServerKeyExchange.java | 311 +- .../net/ssl/provider/ServerKeyExchangeBuilder.java | 89 + .../net/ssl/provider/ServerKeyExchangeParams.java | 50 + gnu/javax/net/ssl/provider/ServerNameList.java | 311 ++ .../net/ssl/provider/ServerPSKParameters.java | 127 + gnu/javax/net/ssl/provider/ServerRSAParams.java | 163 + .../net/ssl/provider/ServerRSA_PSKParameters.java | 62 + gnu/javax/net/ssl/provider/Session.java | 381 --- gnu/javax/net/ssl/provider/SessionContext.java | 250 -- gnu/javax/net/ssl/provider/SessionImpl.java | 198 ++ gnu/javax/net/ssl/provider/Signature.java | 140 +- gnu/javax/net/ssl/provider/SignatureAlgorithm.java | 62 + .../net/ssl/provider/SimpleSessionContext.java | 146 + gnu/javax/net/ssl/provider/SynchronizedRandom.java | 104 - gnu/javax/net/ssl/provider/TruncatedHMAC.java | 76 + gnu/javax/net/ssl/provider/TrustedAuthorities.java | 298 ++ .../net/ssl/provider/UnresolvedExtensionValue.java | 83 + gnu/javax/net/ssl/provider/Util.java | 109 +- gnu/javax/net/ssl/provider/X500PrincipalList.java | 272 ++ .../net/ssl/provider/X509KeyManagerFactory.java | 95 +- .../net/ssl/provider/X509TrustManagerFactory.java | 147 +- gnu/javax/net/ssl/provider/XMLSessionContext.java | 619 ---- .../auth/callback/CertificateCallback.java | 64 + java/security/MessageDigest.java | 12 + java/security/MessageDigestSpi.java | 19 + java/security/Signature.java | 17 + java/security/SignatureSpi.java | 19 + javax/crypto/Mac.java | 13 + javax/crypto/MacSpi.java | 18 + javax/net/ssl/CertPathTrustManagerParameters.java | 71 + javax/net/ssl/HandshakeCompletedEvent.java | 31 + javax/net/ssl/HttpsURLConnection.java | 45 + javax/net/ssl/KeyStoreBuilderParameters.java | 48 + javax/net/ssl/SSLContext.java | 25 + javax/net/ssl/SSLContextSpi.java | 22 + javax/net/ssl/SSLEngine.java | 442 +++ javax/net/ssl/SSLEngineResult.java | 194 ++ javax/net/ssl/SSLSession.java | 67 + javax/net/ssl/X509ExtendedKeyManager.java | 96 + 151 files changed, 19488 insertions(+), 12043 deletions(-) create mode 100644 ChangeLog-ssl-nio create mode 100644 gnu/java/security/Requires.java create mode 100644 gnu/java/security/util/ByteBufferOutputStream.java create mode 100644 gnu/javax/crypto/key/GnuPBEKey.java create mode 100644 gnu/javax/net/ssl/AbstractSessionContext.java create mode 100644 gnu/javax/net/ssl/PreSharedKeyManager.java create mode 100644 gnu/javax/net/ssl/PreSharedKeyManagerParameters.java create mode 100644 gnu/javax/net/ssl/SSLCipherSuite.java create mode 100644 gnu/javax/net/ssl/SSLProtocolVersion.java create mode 100644 gnu/javax/net/ssl/SSLRecordHandler.java create mode 100644 gnu/javax/net/ssl/Session.java create mode 100644 gnu/javax/net/ssl/SessionStoreException.java create mode 100644 gnu/javax/net/ssl/provider/AbstractHandshake.java create mode 100644 gnu/javax/net/ssl/provider/Builder.java create mode 100644 gnu/javax/net/ssl/provider/CertificateBuilder.java create mode 100644 gnu/javax/net/ssl/provider/CertificateRequestBuilder.java create mode 100644 gnu/javax/net/ssl/provider/CertificateStatusRequest.java create mode 100644 gnu/javax/net/ssl/provider/CertificateStatusType.java create mode 100644 gnu/javax/net/ssl/provider/CertificateURL.java create mode 100644 gnu/javax/net/ssl/provider/CipherAlgorithm.java create mode 100644 gnu/javax/net/ssl/provider/CipherSuiteList.java create mode 100644 gnu/javax/net/ssl/provider/ClientCertificateTypeList.java create mode 100644 gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java create mode 100644 gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java create mode 100644 gnu/javax/net/ssl/provider/ClientHandshake.java create mode 100644 gnu/javax/net/ssl/provider/ClientHelloBuilder.java create mode 100644 gnu/javax/net/ssl/provider/ClientHelloV2.java create mode 100644 gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java create mode 100644 gnu/javax/net/ssl/provider/ClientPSKParameters.java create mode 100644 gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java create mode 100644 gnu/javax/net/ssl/provider/CompressionMethodList.java delete mode 100644 gnu/javax/net/ssl/provider/Context.java create mode 100644 gnu/javax/net/ssl/provider/Debug.java create mode 100644 gnu/javax/net/ssl/provider/DelegatedTask.java delete mode 100644 gnu/javax/net/ssl/provider/DigestInputStream.java delete mode 100644 gnu/javax/net/ssl/provider/DigestOutputStream.java create mode 100644 gnu/javax/net/ssl/provider/EmptyExchangeKeys.java create mode 100644 gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java delete mode 100644 gnu/javax/net/ssl/provider/Enumerated.java create mode 100644 gnu/javax/net/ssl/provider/ExchangeKeys.java create mode 100644 gnu/javax/net/ssl/provider/ExtensionList.java delete mode 100644 gnu/javax/net/ssl/provider/Extensions.java delete mode 100644 gnu/javax/net/ssl/provider/GNUSecurityParameters.java create mode 100644 gnu/javax/net/ssl/provider/HelloRequest.java create mode 100644 gnu/javax/net/ssl/provider/InputSecurityParameters.java delete mode 100644 gnu/javax/net/ssl/provider/JCESecurityParameters.java delete mode 100644 gnu/javax/net/ssl/provider/JDBCSessionContext.java delete mode 100644 gnu/javax/net/ssl/provider/JessieDHPrivateKey.java delete mode 100644 gnu/javax/net/ssl/provider/JessieDHPublicKey.java delete mode 100644 gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java delete mode 100644 gnu/javax/net/ssl/provider/JessieRSAPublicKey.java create mode 100644 gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java delete mode 100644 gnu/javax/net/ssl/provider/KeyPool.java create mode 100644 gnu/javax/net/ssl/provider/MacAlgorithm.java create mode 100644 gnu/javax/net/ssl/provider/MaxFragmentLength.java create mode 100644 gnu/javax/net/ssl/provider/OutputSecurityParameters.java delete mode 100644 gnu/javax/net/ssl/provider/OverflowException.java create mode 100644 gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java create mode 100644 gnu/javax/net/ssl/provider/Record.java delete mode 100644 gnu/javax/net/ssl/provider/RecordInput.java delete mode 100644 gnu/javax/net/ssl/provider/RecordInputStream.java delete mode 100644 gnu/javax/net/ssl/provider/RecordOutputStream.java delete mode 100644 gnu/javax/net/ssl/provider/RecordingInputStream.java create mode 100644 gnu/javax/net/ssl/provider/SSLContextImpl.java create mode 100644 gnu/javax/net/ssl/provider/SSLEngineImpl.java delete mode 100644 gnu/javax/net/ssl/provider/SSLRSASignature.java create mode 100644 gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java delete mode 100644 gnu/javax/net/ssl/provider/SSLServerSocket.java delete mode 100644 gnu/javax/net/ssl/provider/SSLServerSocketFactory.java create mode 100644 gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java create mode 100644 gnu/javax/net/ssl/provider/SSLServerSocketImpl.java delete mode 100644 gnu/javax/net/ssl/provider/SSLSocket.java delete mode 100644 gnu/javax/net/ssl/provider/SSLSocketFactory.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocketImpl.java delete mode 100644 gnu/javax/net/ssl/provider/SSLSocketInputStream.java delete mode 100644 gnu/javax/net/ssl/provider/SSLSocketOutputStream.java create mode 100644 gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java create mode 100644 gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java delete mode 100644 gnu/javax/net/ssl/provider/SecurityParameters.java create mode 100644 gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java create mode 100644 gnu/javax/net/ssl/provider/ServerDHParams.java create mode 100644 gnu/javax/net/ssl/provider/ServerHandshake.java create mode 100644 gnu/javax/net/ssl/provider/ServerHelloBuilder.java create mode 100644 gnu/javax/net/ssl/provider/ServerHelloDone.java create mode 100644 gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java create mode 100644 gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java create mode 100644 gnu/javax/net/ssl/provider/ServerNameList.java create mode 100644 gnu/javax/net/ssl/provider/ServerPSKParameters.java create mode 100644 gnu/javax/net/ssl/provider/ServerRSAParams.java create mode 100644 gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java delete mode 100644 gnu/javax/net/ssl/provider/Session.java delete mode 100644 gnu/javax/net/ssl/provider/SessionContext.java create mode 100644 gnu/javax/net/ssl/provider/SessionImpl.java create mode 100644 gnu/javax/net/ssl/provider/SignatureAlgorithm.java create mode 100644 gnu/javax/net/ssl/provider/SimpleSessionContext.java delete mode 100644 gnu/javax/net/ssl/provider/SynchronizedRandom.java create mode 100644 gnu/javax/net/ssl/provider/TruncatedHMAC.java create mode 100644 gnu/javax/net/ssl/provider/TrustedAuthorities.java create mode 100644 gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java create mode 100644 gnu/javax/net/ssl/provider/X500PrincipalList.java delete mode 100644 gnu/javax/net/ssl/provider/XMLSessionContext.java create mode 100644 gnu/javax/security/auth/callback/CertificateCallback.java create mode 100644 javax/net/ssl/CertPathTrustManagerParameters.java create mode 100644 javax/net/ssl/KeyStoreBuilderParameters.java create mode 100644 javax/net/ssl/SSLEngine.java create mode 100644 javax/net/ssl/SSLEngineResult.java create mode 100644 javax/net/ssl/X509ExtendedKeyManager.java diff --git a/ChangeLog b/ChangeLog index 04c86c972..65e56db12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,83 @@ +2006-08-14 Casey Marshall + + 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 * 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 + + * 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 + (): 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. + (): don't take version argument. + (): 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. + (, ): 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 (): 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 (): remove + debug logging. + * gnu/javax/net/ssl/provider/ServerDHParams.java (): + 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 + + * gnu/java/net/protocol/http/HTTPConnection.java (getSocket): + enable TLSv1.1. + * gnu/java/security/action/GetPropertyAction.java: implement + PrivilegedAction. + (run): return String. + +2006-07-14 Casey Marshall + + * 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. + (): new "builder" constructor. + (buffer): new method. + * gnu/javax/net/ssl/provider/CertificateURL.java (buffer): make + non-final. + (): new "builder" constructor. + (buffer): new method. + (URLAndOptionalHash): implement Builder. + (URLAndOptionalHash.): set buffer order to BIG_ENDIAN. + (URLAndOptionalHash., URLAndOptionalHash.): 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. + (): make public. + (): 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. + (): 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 (): 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. + (): new "builder" constructor. + (buffer): new method. + (ServerName.buffer): make non-final. + (ServerName.): 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 (): 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 + + * gnu/javax/security/auth/callback/CertificateCallback.java: new + file. + +2006-07-12 Casey Marshall + + * gnu/javax/net/ssl/provider/AbstractHandshake.java + (engine, inParams, outParams, tasks, serverRandom, clientRandom, + compression): new fields. + (): 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. + (iterator): new method. + * gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java: make + public; implement Builder. + (): make public. + (): 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. + (): 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. + (): make public. + (): 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. + (): made public; don't check null. + * gnu/javax/net/ssl/provider/Jessie.java (): 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. + (): 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 (): 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 + + * 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 (): 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 + + * gnu/javax/net/ssl/AbstractSessionContext.java (newInstance): + return `AbstractSessionContext.' + (getSession): check if the session is null. + * gnu/javax/net/ssl/Session.java (packetBufferSize): removed. + (): 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 (): 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 (): 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 (): order + the input buffer BIG_ENDIAN. + * gnu/javax/net/ssl/provider/InputSecurityParameters.java + (logger): new constant. + (suite): new field. + (): 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 (): add + "TLSv1.1-RSA" signature. + * gnu/javax/net/ssl/provider/OutputSecurityParameters.java + (logger): new constant. + (suite): new field. + (): 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 (): 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. + (): 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 (): 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 + + * 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 + + * gnu/javax/crypto/key/GnuPBEKey.java: new file. + +2006-06-28 Casey Marshall + + * 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'). + (): 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. + * 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. + (): 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. + (): 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). + (): handle changes to fields. + (getAcceptedIssuers): use `anchors.toArray().' + (checkTrusted): use a PKIX CertPathVerifier. + +2006-06-28 Casey Marshall + + * 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 + + * gnu/java/security/Requires.java: new annotation. + * gnu/java/security/action/GetSecurityPropertyAction.java: + implement PrivilegedAction. + (run): return String. + +2006-06-28 Casey Marshall + + * gnu/java/io/ByteBufferOutputStream.java: new file. + +2006-06-28 Casey Marshall + + * gnu/classpath/debug/SystemLogger.java: extend Logger. + (SYSTEM): declare as instance of SystemLogger; set it to such an + instance. + (): removed debug lines. + (): new method. + (logv): new method. + +2006-06-28 Casey Marshall + + * java/security/Signature.java (update): new method. + * java/security/SignatureSpi.java (engineUpdate): new method. + +2006-06-10 Casey Marshall + + * jessie-tests/testClientHello.java: update for extensions + changes. + * jessie-tests/testExtensionList.java: likewise. + * jessie-tests/testServerHello.java: likewise. + +2006-06-10 Casey Marshall + + * 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 + + * 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 + + * gnu/javax/net/ssl/provider/CipherSuiteList.java: implement + Iterable. + (iterator): new method. + * gnu/javax/net/ssl/provider/CompressionMethodList.java: implement + Iterable. + (iterator): new method. + * gnu/javax/net/ssl/provider/X500PrincipalList.java: implement + Iterable. + (iterator): new method. + +2006-06-05 C. Scott Marshall + + * java/security/MessageDigest.java (update): new method. + * java/security/MessageDigestSpi.java (engineUpdate): new method. + +2006-06-03 C. Scott Marshall + + * 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 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); * */ -public class GetPropertyAction implements PrivilegedAction +public class GetPropertyAction implements PrivilegedAction { 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); * */ -public class GetSecurityPropertyAction implements PrivilegedAction +public class GetSecurityPropertyAction implements PrivilegedAction { 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. + * + *

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. + * + *

As a simple example, that writes sessions to some object output + * stream: + * + *

+  char[] password = ...;
+  ObjectOutputStream out = ...;
+  ...
+  for (Session s : this)
+    {
+      s.prepare(password);
+      out.writeObject(s);
+    }
+ * + *

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: + * + *

+  char[] password = ...;
+  ObjectInputStream in = ...;
+  ...
+  while (hasMoreSessions(in))
+    {
+      Session s = (Session) in.readObject();
+      s.repair(password);
+      addToThisStore(s);
+    }
+ * + * @author Casey Marshall (csm@gnu.org) + */ +public abstract class AbstractSessionContext implements SSLSessionContext +{ + protected long timeout; + private static Class + 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. + * + *

Note: this method requires that the caller have + * {@link SSLPermission} with target + * gnu.javax.net.ssl.AbstractSessionContext and action + * setImplClass. + * + * @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 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. + * + *

Subclasses implementing this class must not + * 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 null 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. + * + *

Subclasses implementing this class must not + * 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. + * + *

Subclasses implementing this class must not + * 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 keys; + + public PreSharedKeyManagerParameters() + { + keys = new LinkedHashMap(); + } + + 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 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 privateKeys; + private List certChains; // Constructor. // ------------------------------------------------------------------------- public PrivateCredentials() { - privateKeys = new LinkedList(); - certChains = new LinkedList(); + privateKeys = new LinkedList(); + certChains = new LinkedList(); } // 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 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 getPrivateKeys() { if (isDestroyed()) { @@ -212,7 +214,7 @@ public class PrivateCredentials implements ManagerFactoryParameters return privateKeys; } - public List getCertChains() + public List 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 fragment of the record layer message + * — 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. + * + *

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 values; + protected boolean valid; + protected boolean truncatedMac = false; + transient protected SecureRandom random; + transient protected SSLSessionContext context; + + protected Session() + { + creationTime = System.currentTimeMillis(); + values = new HashMap(); + 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 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 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(); + } + + /** + * 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 + * fragment, 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. + * + *

In the presence of a well-behaving peer, this should be called once + * the ChangeCipherSpec 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 + * ChangeCipherSpec 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 should 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. + * + *

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. + * + *

SSLv3 uses the algorithm: + * + *

+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));
+ * + * @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 attr = new HashMap(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 attr = new HashMap(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 attr = new HashMap(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 params = new HashMap(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 attr = new HashMap(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() + { + 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; * *
  * struct {
- *   AlertLevel level;
+ *   AlertLevel       level;
  *   AlertDescription description;
  * }
  * 
*/ -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; * */ - 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. + * + *

Once the object is built, through various setters 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. + * + *

opaque ASN.1Cert<1..2^24-1>;
+
+struct {
+  ASN.1Cert certificate_list<0..2^24-1>;
+} Certificate;
+ * + * @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 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 list + = new LinkedList(); + 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/CertificateBuilder.java b/gnu/javax/net/ssl/provider/CertificateBuilder.java new file mode 100644 index 000000000..b60ad556a --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateBuilder.java @@ -0,0 +1,94 @@ +/* CertificateBuilder.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.security.cert.CertificateException; + +/** + * Builder for {@link Certificate} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class CertificateBuilder extends Certificate implements Builder +{ + public CertificateBuilder(final CertificateType certType) + { + super(ByteBuffer.allocate(1024), certType); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + public void setCertificates (final List certificates) + throws CertificateException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + for (java.security.cert.Certificate cert : certificates) + { + byte[] encoded = cert.getEncoded(); + out.write((encoded.length >>> 16) & 0xFF); + out.write((encoded.length >>> 8) & 0xFF); + out.write( encoded.length & 0xFF); + try + { + out.write(encoded); + } + catch (IOException shouldNotHappen) + { + // ignore; this is a ByteArrayOutputStream. + } + } + byte[] certs = out.toByteArray(); + // There is only one field in Certificate; so it is easy to reallocate. + if (buffer.capacity() < certs.length + 3) + buffer = ByteBuffer.allocate(certs.length + 3); + buffer.put(0, (byte) (certs.length >>> 16)); + buffer.putShort(1, (short) certs.length); + ((ByteBuffer) buffer.duplicate().position(3)).put(certs); + } +} 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. + * + *
+struct
+{
+  ClientCertificateType certificate_types<1..2^8-1>;
+  DistinguishedName certificate_authorities<3..2^16-1>;
+} CertificateRequest;
+
+ */ +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 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 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; + +/** + *
+struct {
+  CertificateStatusType status_type;
+  select (status_type) {
+    case ocsp: OCSPStatusRequest;
+  } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+  ResponderID responder_id_list<0..2^16-1>;
+  Extensions  request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID<1..2^16-1>;
+opaque Extensions<0..2^16-1>;
+ * + * @author csm + */ +public class CertificateStatusRequest extends Value implements Iterable +{ + private ByteBuffer buffer; + + public CertificateStatusRequest(final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public CertificateStatusRequest(CertificateStatusType type, + List 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 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 + { + 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. + * + *
+enum {
+  individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+  false(0), true(1)
+} Boolean;
+
+struct {
+  CertChainType type;
+  URLAndOptionalHash url_and_hash_list<1..2^16-1>;
+} CertificateURL;
+
+struct {
+  opaque url<1..2^16-1>;
+  Boolean hash_present;
+  select (hash_present) {
+    case false: struct {};
+    case true: SHA1Hash;
+  } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];
+ * + * @author csm + * + */ +public class CertificateURL extends Value implements Iterable +{ + private ByteBuffer buffer; + + public CertificateURL(final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public CertificateURL(CertChainType type, List 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 iterator() + { + return new Iterator(); + } + + public class Iterator implements java.util.Iterator + { + 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/CipherAlgorithm.java b/gnu/javax/net/ssl/provider/CipherAlgorithm.java new file mode 100644 index 000000000..98e05af31 --- /dev/null +++ b/gnu/javax/net/ssl/provider/CipherAlgorithm.java @@ -0,0 +1,47 @@ +/* CipherAlgorithm.java -- Cipher algorithm enumeration. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +/** + * The set of cipher algorithms we support. + */ +public enum CipherAlgorithm +{ + NULL, RC4, DES, DESede, CAST5, AES +} 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 tlsSuiteNames = new LinkedList(); + private static final HashMap namesToSuites = new HashMap(); + + // 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 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 +{ + 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, index <= + * size ()). + * + * @param index The index to put the suite. + * @param suite The CipherSuite object. + * @throws IndexOutOfBoundsException If index is not + * less than @{link #size()}, or if it is negative. + * @throws NullPointerException If suite is + * null. + * @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 + * remove 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 iterator () + { + return new Iterator (); + } + + /** + * An iterator for the elements in this list. The iterator supports + * only the set 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 + { + 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 +{ + 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 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 + { + 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; + +/** + *
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. */
+              case diffie_hellman_psk:   /* NEW */
+                  opaque psk_identity<0..2^16-1>;
+                  ClientDiffieHellmanPublic public;
+          } exchange_keys;
+      } ClientKeyExchange;
+ * + * @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. + * + *
+struct {
+  select (PublicValueEncoding) {
+    case implicit: struct { };
+    case explicit: opaque dh_Yc<1..2^16-1>;
+  } dh_public;
+} ClientDiffieHellmanPublic;
+ */ +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 typeList = new LinkedList(); + for (ClientCertificateType t : types) + typeList.add(t.name()); + + X500PrincipalList issuers = req.authorities(); + LinkedList issuerList = new LinkedList(); + 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 extensions = new LinkedList(); + 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 getSuites() throws SSLException + { + List suites = new LinkedList(); + 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 getCompressionMethods() + { + List methods = new LinkedList(); + 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 keyTypes; + private final List issuers; + + CertLoader(List keyTypes, List 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. + * + *
+struct
+{
+  ProtocolVersion   client_version;                // 2
+  Random            random;                        // 32
+  SessionID         session_id;                    // 1 + 0..32
+  CipherSuite       cipher_suites<2..2^16-1>
+  CompressionMethod compression_methods<1..2^8-1>
+  Extension         client_hello_extension_list<0..2^16-1>
+} ClientHello;
+
+ */ +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 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 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. + * + *

The format of a version 2 client hello is: + * + *

+    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<<8)|LSB]
+    char SESSION-ID-DATA[(MSB<<8)|LSB]
+    char CHALLENGE-DATA[(MSB<<8)|LSB]
+ */ +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 cipherSpecs () + { + int n = cipherSpecsLength (); + List l = new ArrayList(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. + * + *
+struct {
+  select (KeyExchangeAlgorithm) {
+    case rsa: EncryptedPreMasterSecret;
+    case diffie_hellman: ClientDiffieHellmanPublic;
+  } exchange_keys;
+} ClientKeyExchange;
+ */ +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; + +/** + *
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. */
+              case psk:   /* NEW */
+                  opaque psk_identity<0..2^16-1>;
+          } exchange_keys;
+      } ClientKeyExchange;
+ * + * @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 +{ + 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, index + * <= size ()). + * + * @param index The index to put the suite. + * @param method The CompressionMethod object. + * @throws IndexOutOfBoundsException If index is not + * less than @{link #size()}, or if it is negative. + * @throws NullPointerException If suite is + * null. + * @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 + * remove 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 iterator () + { + return new Iterator (); + } + + /** + * An iterator for the elements in this list. The iterator supports + * only the set 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 + { + 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. + * + *

Contract for ByteBuffer-based constructed types: + * + *

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 will not modify the position or + * limit of the buffer when doing read operations. That is, the position + * of the underlying buffer should 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). + * + *

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. + * + *

Thus, very often the code will use absolute 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 null. + * @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. * - *

enum { change_cipher_spec(20), alert(21), handshake(22),
- *             application_data(23), (255) } ContentType;
+ *
+enum { change_cipher_spec(20), alert(21), handshake(22),
+       application_data(23), (255) } ContentType;
+ * + *

There is also a "pseudo" content type, client_hello_v2 + * (1), 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/DigestInputStream.java b/gnu/javax/net/ssl/provider/DigestInputStream.java deleted file mode 100644 index dd138b436..000000000 --- a/gnu/javax/net/ssl/provider/DigestInputStream.java +++ /dev/null @@ -1,103 +0,0 @@ -/* DigestInputStream.java -- digesting input 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.FilterInputStream; -import java.io.InputStream; -import java.io.IOException; - -import gnu.java.security.hash.IMessageDigest; - -final class DigestInputStream extends FilterInputStream -{ - - // Fields. - // ------------------------------------------------------------------------- - - private IMessageDigest md5, sha; - private boolean digesting; - - // Constructor. - // ------------------------------------------------------------------------- - - DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha) - { - 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; - } - - public int read(byte[] buf) throws IOException - { - return read(buf, 0, buf.length); - } - - public int read(byte[] buf, int off, int len) throws IOException - { - int ret = in.read(buf, off, len); - if (digesting && ret != -1) - { - md5.update(buf, off, ret); - sha.update(buf, off, ret); - } - return ret; - } -} 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. + * + *

+struct {
+  public-key-encrypted PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;
+ */ +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/Enumerated.java b/gnu/javax/net/ssl/provider/Enumerated.java deleted file mode 100644 index 8875addab..000000000 --- a/gnu/javax/net/ssl/provider/Enumerated.java +++ /dev/null @@ -1,79 +0,0 @@ -/* Enumerated.java -- Interface to enumerated 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; - -/** - * 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. - * - *
enum { e1(v1), e2(v2), ... [[, (n) ]] }
- * - *

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) - */ -interface Enumerated -{ - - /** - * Returns the encoded value of this enumerated value, which is - * appropriate to send over-the-wire. - * - * @return The encoded value. - */ - byte[] getEncoded(); - - /** - * Returns the numeric value of this enumerated value. - * - * @return The numeric value. - */ - int getValue(); - - /** - * Returns a string representation of this enumerated value. - * - * @return The string. - */ - String toString(); -} 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. + * + *

+ * struct {
+ *   ExtensionType extension_type;
+ *   opaque extension_data<0..2^16-1>;
+ * } Extension;
+ * + * @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: + * + * Extension extensions_list<1..2^16-1> + * + * @author csm + */ +public class ExtensionList implements Builder, Iterable +{ + private final ByteBuffer buffer; + private int modCount; + + public ExtensionList (ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + modCount = 0; + } + + public ExtensionList(List 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 to e. Note that setting an + * element at an index may invalidate any other elements that come + * after element at index i. In other words, no attempt is made to + * move existing elements in this list, and since extensions are variable + * length, you can not guarantee that extensions later in the list + * will still be valid. + * + *

Thus, elements of this list must 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 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 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 + { + 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 buf as len bytes starting at - * offset. len must 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: + * + *

+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;
+};
+ */ +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 length 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/HelloRequest.java b/gnu/javax/net/ssl/provider/HelloRequest.java new file mode 100644 index 000000000..0ffc26c2b --- /dev/null +++ b/gnu/javax/net/ssl/provider/HelloRequest.java @@ -0,0 +1,70 @@ +/* HelloRequest.java -- SSL HelloRequest handshake message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +/** + * The handshake body for a HelloRequest handshake message. + * + *
struct { } HelloRequest;
+ */ +public final class HelloRequest implements Handshake.Body +{ + public HelloRequest () + { + } + + public String toString (final String prefix) + { + StringBuffer str = new StringBuffer (); + if (prefix != null) + str.append (prefix); + str.append ("HelloRequest { };"); + return str.toString (); + } + + public int length () + { + return 0; + } + + public String toString () + { + return toString (null); + } +} 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 SESSIONS, - * looks like this: - * - *
- * 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
- * )
- * 
- * - *

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() { 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/JessieDHPrivateKey.java b/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java deleted file mode 100644 index 1997458dd..000000000 --- a/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java +++ /dev/null @@ -1,99 +0,0 @@ -/* JessieDHPrivateKey.java -- simple DH private 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.net.ssl.provider; - -import java.math.BigInteger; - -import javax.crypto.interfaces.DHPrivateKey; -import javax.crypto.spec.DHParameterSpec; - -class JessieDHPrivateKey implements DHPrivateKey -{ - - // Fields. - // ------------------------------------------------------------------------- - - private final DHParameterSpec params; - private final BigInteger x; - - // Constructor. - // ------------------------------------------------------------------------- - - JessieDHPrivateKey(DHParameterSpec params, BigInteger x) - { - this.params = params; - this.x = x; - } - - // Instance methods. - // ------------------------------------------------------------------------- - - public String getAlgorithm() - { - return "Diffie-Hellman"; - } - - public String getFormat() - { - return "NONE"; - } - - public byte[] getEncoded() - { - return null; - } - - public DHParameterSpec getParams() - { - return params; - } - - public BigInteger getX() - { - return x; - } - - public String toString() - { - String nl = System.getProperty("line.separator"); - return "P: " + params.getP() + nl + - "G: " + params.getG() + nl + - "X: " + x; - } -} diff --git a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/gnu/javax/net/ssl/provider/JessieDHPublicKey.java deleted file mode 100644 index dc6587288..000000000 --- a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java +++ /dev/null @@ -1,99 +0,0 @@ -/* JessieDHPublicKey.java -- simple DH public 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.net.ssl.provider; - -import java.math.BigInteger; - -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHParameterSpec; - -class JessieDHPublicKey implements DHPublicKey -{ - - // Fields. - // ------------------------------------------------------------------------- - - private final DHParameterSpec params; - private final BigInteger y; - - // Constructor. - // ------------------------------------------------------------------------- - - JessieDHPublicKey(DHParameterSpec params, BigInteger y) - { - this.params = params; - this.y = y; - } - - // Instance methods. - // ------------------------------------------------------------------------- - - public String getAlgorithm() - { - return "Diffie-Hellman"; - } - - public String getFormat() - { - return "NONE"; - } - - public byte[] getEncoded() - { - return null; - } - - public DHParameterSpec getParams() - { - return params; - } - - public BigInteger getY() - { - return y; - } - - public String toString() - { - String nl = System.getProperty("line.separator"); - return "P: " + params.getP() + nl + - "G: " + params.getG() + nl + - "Y: " + y; - } -} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java deleted file mode 100644 index 4ec71a7aa..000000000 --- a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java +++ /dev/null @@ -1,98 +0,0 @@ -/* JessieRSAPrivateKey.java -- simple RSA private 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.net.ssl.provider; - -import java.math.BigInteger; -import java.security.interfaces.RSAPrivateKey; - -class JessieRSAPrivateKey implements RSAPrivateKey -{ - - // Fields. - // ------------------------------------------------------------------------- - - private final BigInteger modulus; - private final BigInteger exponent; - - // Constructor. - // ------------------------------------------------------------------------- - - JessieRSAPrivateKey(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 getPrivateExponent() - { - return exponent; - } - - public String toString() - { - String nl = System.getProperty("line.separator"); - return "RSAPrivateKey {" + nl + - " modulus = " + modulus.toString(16) + ";" + nl + - " exponent = " + exponent.toString(16) + ";" + nl + - "};"; - } -} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java deleted file mode 100644 index 19921d98c..000000000 --- a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java +++ /dev/null @@ -1,98 +0,0 @@ -/* JessieRSAPublicKey.java -- simple RSA public 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.net.ssl.provider; - -import java.math.BigInteger; -import java.security.interfaces.RSAPublicKey; - -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; - } - - public String toString() - { - String nl = System.getProperty("line.separator"); - return "RSAPublicKey {" + nl + - " modulus = " + modulus.toString(16) + ";" + nl + - " exponent = " + exponent.toString(16) + ";" + nl + - "};"; - } -} 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/OverflowException.java b/gnu/javax/net/ssl/provider/OverflowException.java deleted file mode 100644 index 93bdcaec5..000000000 --- a/gnu/javax/net/ssl/provider/OverflowException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* OverflowException.java -- signals an input overflow. - Copyright (C) 2006 Free Software Foundation, Inc. - -This file is a part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 -USA - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.javax.net.ssl.provider; - -import java.io.IOException; - -class OverflowException extends IOException -{ - - // Constructors. - // ------------------------------------------------------------------------- - - OverflowException() - { - } - - OverflowException(String msg) - { - super(msg); - } -} 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 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, 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. + * + *
+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:
+ *
+ * 
+struct
+{
+  {@link ContentType}     type;
+  {@link ProtocolVersion} version;
+  uint16          length;
+  opaque          fragment[TLSPlaintext.length];
+} TLSPlaintext;
+
+ */ +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 sink. + * + * @param sink The sink for the fragment bytes. + * @return The number of bytes put into sink + */ + 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 type is null. + */ + 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 version is null. + */ + 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/RecordInputStream.java b/gnu/javax/net/ssl/provider/RecordInputStream.java deleted file mode 100644 index 14cf829ac..000000000 --- a/gnu/javax/net/ssl/provider/RecordInputStream.java +++ /dev/null @@ -1,106 +0,0 @@ -/* RecordInputStream.java -- record layer input stream 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; - -import java.io.IOException; -import java.io.InputStream; - -class RecordInputStream extends InputStream -{ - - // 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) - { - this.in = in; - this.type = type; - } - - // Instance methods. - // ------------------------------------------------------------------------- - - public int available () throws IOException - { - return in.available (type); - } - - public int read () throws IOException - { - byte[] b = new byte[1]; - int ret; - while ((ret = read (b)) != 1) - { - if (ret == -1) - { - return -1; - } - Thread.yield (); - } - return b[0] & 0xFF; - } - - public int read (byte[] buf) throws IOException - { - return read (buf, 0, buf.length); - } - - public int read (byte[] buf, int off, int len) throws IOException - { - return in.read (buf, off, len, type); - } - - public String toString () - { - return RecordInputStream.class.getName () + " [ type=" + type + " ]"; - } -} 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 gnu.javax.net.ssl.secureRandom 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 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 comps = new ArrayList(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. - * - *

This signature scheme works as follows:

- * - *

digitally-signed struct {
- *     opaque md5_hash[16];
- *     opaque sha_hash[20];
- * }

- * - *

Where a digitally-signed struct is RSA-encrypted with - * block type 0 or 1 according to PKCS #1, version 1.5.

- */ -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 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(); + 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 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 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 null, 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; + +/** + *
+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. */
+              case diffie_hellman_psk:  /* NEW */
+                  opaque psk_identity_hint<0..2^16-1>;
+                  ServerDHParams params;
+          };
+      } ServerKeyExchange;
+ * + * @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. + * + *
+struct
+{
+  opaque dh_p<1..2^16-1>;
+  opaque dh_g<1..2^16-1>;
+  opaque dh_Ys<1..2^16-1>;
+} ServerDHParams;
+
+ */ +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 kexes = new HashSet(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 suites = new HashSet(); + 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 names + = new ArrayList(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 types + = new ArrayList(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 issuers + = new ArrayList(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. + * + *
+struct
+{
+  ProtocolVersion server_version;
+  Random random;
+  SessionID session_id;
+  CipherSuite cipher_suite;
+  CompressionMethod compression_method;
+  Extensions server_hello_extension_list<0..2^16-1>
+} ServerHello;
+
+ * + *

Server hello messages may contain extra data after the + * compression_method 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. + * + *

struct { } ServerHelloDone;
+ */ +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. + * + *
+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;
+
+ */ +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/ServerKeyExchangeBuilder.java b/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java new file mode 100644 index 000000000..d4b6fa397 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java @@ -0,0 +1,89 @@ +/* ServerKeyExchangeBuilder.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * Builder for {@link ServerKeyExchange} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerKeyExchangeBuilder extends ServerKeyExchange + implements Builder +{ + public ServerKeyExchangeBuilder(final CipherSuite suite) + { + super(ByteBuffer.allocate(1024), suite); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + public void setParams(ByteBuffer params) + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + throw new IllegalArgumentException("key exchange algorithm is none"); + ensureCapacity(params.remaining()); + buffer.duplicate().put(params); + } + + public void setSignature(ByteBuffer signature) + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + throw new IllegalArgumentException("key exchange algorithm is none"); + int paramsLen = params().length(); + ensureCapacity(paramsLen + signature.remaining()); + ((ByteBuffer) buffer.duplicate().position(paramsLen)).put(signature); + } + + public void ensureCapacity(int capacity) + { + if (buffer.capacity() >= capacity) + return; + ByteBuffer newBuffer = ByteBuffer.allocate(capacity); + newBuffer.duplicate().put(buffer); + buffer = newBuffer; + } +} 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. + * + *
+ 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;
+ * + *

Implementation note: this class does not currently contain a + * set 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 +{ + private ByteBuffer buffer; + + public ServerNameList (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerNameList(List 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 iterator() + { + return new Iterator(); + } + + public class Iterator implements java.util.Iterator + { + 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; + +/** + *

+      struct {
+          select (KeyExchangeAlgorithm) {
+              /* other cases for rsa, diffie_hellman, etc. */
+              case psk:  /* NEW */
+                  opaque psk_identity_hint<0..2^16-1>;
+          };
+      } ServerKeyExchange;
+ * + * @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. + * + *
+struct
+{
+  opaque rsa_modulus<1..2^16-1>;
+  opaque rsa_exponent<1..2^16-1>;
+} ServerRSAParams;
+
+ */ +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 equals(), - * hashCode(), and compareTo() 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: - * - *
    - *
  1. Will do nothing if the cache already contains the given ID.
  2. - *
  3. Will do nothing if the cache limit has been reached (and is - * not zero).
  4. - *
  5. Will remove any invalid sessions in the cache before trying to insert - * the new one.
  6. - *
  7. Will remove any expired sessions before trying to insert the new - * one.
  8. - *
- * - * @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. + * + *
+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;
+ */ +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 store; + private int storeLimit; + + public SimpleSessionContext() + { + super(DEFAULT_TIMEOUT); + storeLimit = 0; + store = new HashMap(); + } + + @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 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 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/TruncatedHMAC.java b/gnu/javax/net/ssl/provider/TruncatedHMAC.java new file mode 100644 index 000000000..0595f87a7 --- /dev/null +++ b/gnu/javax/net/ssl/provider/TruncatedHMAC.java @@ -0,0 +1,76 @@ +/* TruncatedHMAC.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.nio.ByteBuffer; + +/** + * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension. + * This extension has an empty value; this class is thusly empty. + * + * @author csm + */ +public class TruncatedHMAC extends Value +{ + + public int length() + { + return 0; + } + + public ByteBuffer buffer() + { + return ByteBuffer.wrap(new byte[0]); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + String s = "TruncatedHMAC;"; + if (prefix != null) + s = prefix + s; + return s; + } +} 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. + * + *
+struct {
+  TrustedAuthority trusted_authorities_list<0..2^16-1>;
+} 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<1..2^16-1>;
+ * + * @author csm + */ +public class TrustedAuthorities extends Value + implements Iterable +{ + 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 iterator() + { + return new AuthoritiesIterator(); + } + + public class AuthoritiesIterator implements Iterator + { + 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/UnresolvedExtensionValue.java b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java new file mode 100644 index 000000000..2094daf90 --- /dev/null +++ b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java @@ -0,0 +1,83 @@ +/* UnresolvedExtensionValue.jav -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; + +public class UnresolvedExtensionValue extends Value +{ + private final ByteBuffer buffer; + + public UnresolvedExtensionValue (final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public int length() + { + return buffer.limit(); + } + + public ByteBuffer buffer() + { + return value(); + } + + public ByteBuffer value() + { + return buffer.slice(); + } + + public String toString() + { + return toString(null); + } + + public String toString(final String prefix) + { + String s = Util.hexDump(buffer); + if (prefix != null) + s = prefix + s; + return s; + } +} 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 +{ + 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 iterator () + { + return new Iterator(); + } + + public class Iterator implements ListIterator + { + 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 chains + = ((PrivateCredentials) params).getCertChains(); + List keys + = ((PrivateCredentials) params).getPrivateKeys(); int i = 0; - HashMap certMap = new HashMap(); - HashMap keyMap = new HashMap(); - Iterator c = chains.iterator(); - Iterator k = keys.iterator(); + HashMap certMap + = new HashMap(); + HashMap keyMap + = new HashMap(); + Iterator c = chains.iterator(); + Iterator 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 p = new HashMap(); + HashMap c + = new HashMap(); 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 privateKeys; + private final Map certChains; // Constructor. // ----------------------------------------------------------------------- - Manager(Map privateKeys, Map certChains) + Manager(Map privateKeys, + Map 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 l = new LinkedList(); 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 l = new LinkedList(); 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 anchors; // Constructor. // ----------------------------------------------------------------------- Manager(X509Certificate[] trusted) { - this.trusted = trusted; + anchors = new HashSet(); + 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(""); - out.println(""); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println(" "); - out.println("]>"); - out.println(); - out.print(""); - 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(""); - out.print(""); - Certificate[] certs = session.getPeerCertificates(); - if (certs != null && certs.length > 0) - { - out.print(""); - 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(""); - } - out.println(""); - certs = session.getLocalCertificates(); - if (certs != null && certs.length > 0) - { - out.print(""); - 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(""); - } - 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(""); - out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70)); - out.println(""); - out.println(""); - } - out.println(""); - 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/security/auth/callback/CertificateCallback.java b/gnu/javax/security/auth/callback/CertificateCallback.java new file mode 100644 index 000000000..fcec11962 --- /dev/null +++ b/gnu/javax/security/auth/callback/CertificateCallback.java @@ -0,0 +1,64 @@ +/* CertificateCallback.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.security.auth.callback; + +import java.security.cert.Certificate; + +import javax.security.auth.callback.ConfirmationCallback; + +/** + * 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) + { + 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 @@ -223,6 +224,17 @@ public abstract class MessageDigest extends MessageDigestSpi engineUpdate(input, 0, input.length); } + /** + * 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. * 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 @@ -97,6 +99,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 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; /** @@ -130,6 +131,24 @@ public abstract class SignatureSpi protected abstract void engineUpdate(byte[] b, int off, int len) 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; @@ -397,6 +398,18 @@ public class Mac implements Cloneable macSpi.engineUpdate(input, offset, length); } + /** + * 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. * 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; @@ -107,6 +108,20 @@ public class HandshakeCompletedEvent extends java.util.EventObject return null; } + /** + * Returns the local identity used in this connection, or + * null 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. * @@ -128,6 +143,22 @@ public class HandshakeCompletedEvent extends java.util.EventObject return null; } + /** + * Returns the peer's identity, or null 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. * 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 Secure Socket Layer @@ -245,6 +248,48 @@ public abstract class HttpsURLConnection extends HttpURLConnection this.factory = factory; } + /** + * Returns the local principal for this connection. + * + *

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 null. + * + * @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. + * + *

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 null. + * + * @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; + +/** + *

FIXME this class is currently a stub; + * it depends on an implementation of {@link + * java.security.KeyStore.Builder}

. + */ +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 @@ -187,6 +187,31 @@ public class SSLContext // Instance methods. // ----------------------------------------------------------------- + /** + * 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. * 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 + * null 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. + * + *

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. + * + *

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. + * + *

This call is exactly equivalent to unwrap (source, new + * ByteBuffer[] { sink }, 0, 1). + * + * @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. + * + *

This call is exactly equivalent to unwrap (source, + * sinks, 0, sinks.length). + * + * @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. + * + *

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. + * + *

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. + * + *

This method is exactly equivalent to wrap (new + * ByteBuffer[] { source }, 0, 1, sink). + * + * @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. + * + *

This method is exactly equivalent to wrap (sources, 0, + * 1, sink). + * + * @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. + * + *

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} wrap or + * unwrap 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 + * null, 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 + * wrap. + */ + 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. + * + *

Buffers passed to handle the incoming data for the + * unwrap 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. * @@ -86,6 +101,28 @@ public interface SSLSession */ Certificate[] getLocalCertificates(); + /** + * Returns the {@link Principal} representing the local identity + * used in this session, or null 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. + * + *

Callers of wrap and unwrap 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. @@ -114,6 +151,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 null 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. * @@ -151,6 +209,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. * diff --git a/javax/net/ssl/X509ExtendedKeyManager.java b/javax/net/ssl/X509ExtendedKeyManager.java new file mode 100644 index 000000000..ccd146f82 --- /dev/null +++ b/javax/net/ssl/X509ExtendedKeyManager.java @@ -0,0 +1,96 @@ +/* X509ExtendedKeyManager.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.Principal; + +/** + * An extended {@link X509KeyManager} for use with {@link SSLEngine}. + * + * @since 1.5 + * @author Casey Marshall (csm@gnu.org) + */ +public abstract class X509ExtendedKeyManager implements X509KeyManager +{ + + /** + * Default constructor. + */ + protected X509ExtendedKeyManager () + { + } + + /** + * Return a client alias given a list of key types, a list of + * allowable issuers, and the SSLEngine being used. + * + *

This implementation always returns null. + * + * @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 + * null if the parameters were not matched. + */ + public String chooseEngineClientAlias (final String[] keyTypes, + final Principal[] issuers, + final SSLEngine engine) + { + return null; + } + + /** + * Return a server alias given a key type, a list of allowable + * issuers, and the SSLEngine being used. + * + *

This implementation always returns null. + * + * @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 + * null if the parameters were not matched. + */ + public String chooseEngineServerAlias (final String keyType, + final Principal[] issuers, + final SSLEngine engine) + { + return null; + } +} -- cgit v1.2.1